#!/usr/bin/env php
<?php
Phar::mapPhar();

require_once 'phar://codecept.phar/autoload.php';

require_once 'phar://codecept.phar/codecept';

__HALT_COMPILER(); ?>
          codecept.phar       src/Codeception/Events.php  YW  m%7      -   src/Codeception/TestCase/Interfaces/Plain.phpr   YWr   ;      6   src/Codeception/TestCase/Interfaces/ScenarioDriven.phpE  YWE  c      3   src/Codeception/TestCase/Interfaces/Descriptive.php   YW   [@?      0   src/Codeception/TestCase/Interfaces/Reported.php   YW   %ж      4   src/Codeception/TestCase/Interfaces/Configurable.php  YW  ń      )   src/Codeception/TestCase/Shared/Actor.php  YW  X-      1   src/Codeception/TestCase/Shared/Configuration.php  YW  *CE      0   src/Codeception/TestCase/Shared/Dependencies.php'  YW'  iͶJ      1   src/Codeception/TestCase/Shared/ScenarioPrint.php  YW  >T      !   src/Codeception/TestCase/Test.phpG	  YWG	  9      !   src/Codeception/TestCase/Cept.php  YW  4F      !   src/Codeception/TestCase/Cest.php  YW  @e         src/Codeception/Extension.php  YW  TY      )   src/Codeception/PHPUnit/ResultPrinter.php  YW  +[      %   src/Codeception/PHPUnit/Log/JUnit.php%  YW%  Ll      0   src/Codeception/PHPUnit/Constraint/WebDriver.php	  YW	  V*      1   src/Codeception/PHPUnit/Constraint/CrawlerNot.phpB  YWB  uPٶ      3   src/Codeception/PHPUnit/Constraint/WebDriverNot.php  YW  Ӷ	      .   src/Codeception/PHPUnit/Constraint/Crawler.php>  YW>  &      +   src/Codeception/PHPUnit/Constraint/Page.php  YW  W      *   src/Codeception/PHPUnit/ConsolePrinter.phpp  YWp  XҶ      $   src/Codeception/PHPUnit/Listener.php  YW  1AV      0   src/Codeception/PHPUnit/ResultPrinter/Report.php  YW  `p      H   src/Codeception/PHPUnit/ResultPrinter/template/scenario_header.html.dist3   YW3   ʤ      =   src/Codeception/PHPUnit/ResultPrinter/template/step.html.distJ   YWJ   wGֶ      >   src/Codeception/PHPUnit/ResultPrinter/template/suite.html.dist3   YW3   |      =   src/Codeception/PHPUnit/ResultPrinter/template/fail.html.dist;   YW;   ˟      A   src/Codeception/PHPUnit/ResultPrinter/template/scenario.html.dist  YW  +      B   src/Codeception/PHPUnit/ResultPrinter/template/scenarios.html.dist  YW  Do      A   src/Codeception/PHPUnit/ResultPrinter/template/substeps.html.dist  YW  yC'      .   src/Codeception/PHPUnit/ResultPrinter/HTML.php  YW  b\      ,   src/Codeception/PHPUnit/ResultPrinter/UI.phpE
  YWE
  {H      "   src/Codeception/PHPUnit/Runner.php$  YW$  ?      ,   src/Codeception/PHPUnit/Overrides/Filter.php(	  YW(	  ^ƶ          src/Codeception/SuiteManager.php  YW  +ն      *   src/Codeception/Subscriber/AutoRebuild.php3  YW3  )      2   src/Codeception/Subscriber/Shared/StaticEvents.php   YW   $c      &   src/Codeception/Subscriber/Console.phpCJ  YWCJ        %   src/Codeception/Subscriber/Module.phpv	  YWv	  dX      (   src/Codeception/Subscriber/Bootstrap.php^  YW^        '   src/Codeception/Subscriber/FailFast.php  YW  ިr      2   src/Codeception/Subscriber/GracefulTermination.php  YW  1      +   src/Codeception/Subscriber/ErrorHandler.phps  YWs  |N      .   src/Codeception/Subscriber/BeforeAfterTest.php  YW  yZ         src/Codeception/TestCase.php*  YW*  P0|m      !   src/Codeception/Lib/Framework.php  YW  E      /   src/Codeception/Lib/Interfaces/MultiSession.php  YW  {2      /   src/Codeception/Lib/Interfaces/PartedModule.php  YW  T:V      1   src/Codeception/Lib/Interfaces/ElementLocator.php  YW  ;#      )   src/Codeception/Lib/Interfaces/Remote.php  YW  bW      /   src/Codeception/Lib/Interfaces/ActiveRecord.php5  YW5  [      2   src/Codeception/Lib/Interfaces/PageSourceSaver.phpU  YWU  *`      2   src/Codeception/Lib/Interfaces/SessionSnapshot.php  YW  	Q      3   src/Codeception/Lib/Interfaces/DoctrineProvider.phpv   YWv   p.q      &   src/Codeception/Lib/Interfaces/Web.php;j  YW;j  Ƕ      2   src/Codeception/Lib/Interfaces/DependsOnModule.php_  YW_  Ī      2   src/Codeception/Lib/Interfaces/ScreenshotSaver.phph  YWh  h      %   src/Codeception/Lib/Interfaces/Db.php3  YW3  Og6      (   src/Codeception/Lib/Interfaces/Queue.php^  YW^  ^=      6   src/Codeception/Lib/Interfaces/ConflictsWithModule.php   YW   0:         src/Codeception/Lib/Di.phpt  YWt  e7T      2   src/Codeception/Lib/Generator/Shared/Classname.php  YW  /!      &   src/Codeception/Lib/Generator/Test.phpB  YWB        '   src/Codeception/Lib/Generator/Group.phpB  YWB  +b      ,   src/Codeception/Lib/Generator/PageObject.phpt  YWt  }G      ,   src/Codeception/Lib/Generator/StepObject.php  YW  )      &   src/Codeception/Lib/Generator/Cept.php  YW  0rg      )   src/Codeception/Lib/Generator/PhpUnit.php  YW  b-o      '   src/Codeception/Lib/Generator/Actor.php  YW  ӧv      &   src/Codeception/Lib/Generator/Cest.php  YW  h6      )   src/Codeception/Lib/Generator/Actions.php
  YW
  *0z      (   src/Codeception/Lib/Generator/Helper.php  YW  i4      $   src/Codeception/Lib/Notification.php  YW  2~8      '   src/Codeception/Lib/ModuleContainer.php  YW        ,   src/Codeception/Lib/Actor/Shared/Comment.php  YW  Ya+      +   src/Codeception/Lib/Actor/Shared/Friend.php  YW  Dc         src/Codeception/Lib/Parser.php^  YW^  #x      &   src/Codeception/Lib/Console/Output.php!  YW!  f _      '   src/Codeception/Lib/Console/Message.php_
  YW_
        $   src/Codeception/Lib/InnerBrowser.phpL  YWL  dS         src/Codeception/Lib/Friend.php  YW  p      "   src/Codeception/Lib/TestLoader.php  YW  w+z      $   src/Codeception/Lib/GroupManager.php  YW  bo      *   src/Codeception/Lib/Connector/Symfony2.php	  YW	  F}      )   src/Codeception/Lib/Connector/Guzzle6.php(  YW(  I𕵶      A   src/Codeception/Lib/Connector/Shared/PhpSuperGlobalsConverter.phpj  YWj  Ż      *   src/Codeception/Lib/Connector/Laravel4.php  YW  Cڸ      %   src/Codeception/Lib/Connector/ZF2.php  YW        B   src/Codeception/Lib/Connector/ZendExpressive/ResponseCollector.php  YW  1Ķ      )   src/Codeception/Lib/Connector/Phalcon.php(  YW(  z{}      (   src/Codeception/Lib/Connector/Guzzle.phpP"  YWP"  n      &   src/Codeception/Lib/Connector/Yii2.php  YW  4      D   src/Codeception/Lib/Connector/Laravel5/ExceptionHandlerDecorator.phpL  YWL  &      *   src/Codeception/Lib/Connector/Laravel5.php  YW  &      &   src/Codeception/Lib/Connector/Yii1.phpe  YWe  q*      '   src/Codeception/Lib/Connector/Lumen.php  YW  h      %   src/Codeception/Lib/Connector/ZF1.phpt  YWt  ;p      +   src/Codeception/Lib/Connector/Universal.php  YW        0   src/Codeception/Lib/Connector/ZendExpressive.phpK  YWK  c=      "   src/Codeception/Lib/Driver/Oci.php  YW  Ao      &   src/Codeception/Lib/Driver/MongoDb.phpg  YWg  -b      %   src/Codeception/Lib/Driver/Sqlite.php  YW  3శ      )   src/Codeception/Lib/Driver/PostgreSql.phpJ  YWJ  y)93      $   src/Codeception/Lib/Driver/MySql.phpd  YWd   Mⅶ      $   src/Codeception/Lib/Driver/Redis.phpxf  YWxf  	@      (   src/Codeception/Lib/Driver/AmazonSQS.phpr  YWr  Nr      (   src/Codeception/Lib/Driver/Beanstalk.php-  YW-  BS      !   src/Codeception/Lib/Driver/Db.php%  YW%  2X      #   src/Codeception/Lib/Driver/Iron.php	  YW	  Xot      %   src/Codeception/Lib/Driver/SqlSrv.php  YW  F	      '   src/Codeception/Lib/Driver/Facebook.php  YW            src/Codeception/Lib/Suite.php  YW        .   src/Codeception/Coverage/DummyCodeCoverage.php   YW   0Զ      #   src/Codeception/Coverage/Filter.php  YW  Y ɶ      -   src/Codeception/Coverage/Subscriber/Local.phpk  YWk  S       4   src/Codeception/Coverage/Subscriber/RemoteServer.phpu  YWu        /   src/Codeception/Coverage/Subscriber/Printer.php  YW  uL      3   src/Codeception/Coverage/Subscriber/LocalServer.php  YW  )s      ,   src/Codeception/Coverage/SuiteSubscriber.php	  YW	  ۶         src/Codeception/GroupObject.php  YW  Bk      '   src/Codeception/Util/PropertyAccess.php  YW  JS         src/Codeception/Util/sq.php_  YW_  j^g         src/Codeception/Util/Maybe.phpX  YWX  3I>      *   src/Codeception/Util/Shared/Namespaces.php  YW  t$      '   src/Codeception/Util/Shared/Asserts.php'  YW'  *'      )   src/Codeception/Util/ReflectionHelper.php  YW  @      #   src/Codeception/Util/XmlBuilder.phpB  YWB  J0         src/Codeception/Util/Xml.php{  YW{  9         src/Codeception/Util/Uri.php  YW  Bgj      !   src/Codeception/Util/Template.php  YW  w+         src/Codeception/Util/Debug.php  YW  :/      !   src/Codeception/Util/Autoload.php  YW  .      !   src/Codeception/Util/JsonType.php  YW  דU      !   src/Codeception/Util/Fixtures.php  YW  ,߶          src/Codeception/Util/Locator.php|  YW|        #   src/Codeception/Util/FileSystem.phpG	  YWG	        %   src/Codeception/Util/XmlStructure.phpR	  YWR	   	N      #   src/Codeception/Util/Annotation.php;  YW;  [      "   src/Codeception/Util/JsonArray.php#  YW#  J+N         src/Codeception/Util/Stub.php&\  YW&\           src/Codeception/Util/Soap.phpn  YWn  4uK         src/Codeception/Util/sqs.phpp  YWp           src/Codeception/Actor.php  YW  l#Lƶ         src/Codeception/Module.php  YW  mS         src/Codeception/Step/Skip.php|  YW|  ^yG         src/Codeception/Step/Action.phpX   YWX   yM      -   src/Codeception/Step/ConditionalAssertion.php  YW  :K      "   src/Codeception/Step/Condition.phpy   YWy   k         src/Codeception/Step/Meta.php  YW  ݃          src/Codeception/Step/Comment.php  YW        "   src/Codeception/Step/Assertion.phpy   YWy   ֝?      #   src/Codeception/Step/Incomplete.php  YW  O3Ӷ      !   src/Codeception/Step/Executor.php  YW  z;#      !   src/Codeception/Configuration.phpF  YWF  Xn      &   src/Codeception/Platform/Extension.php   YW   [j      "   src/Codeception/Platform/Group.php   YW   Yܶ      0   src/Codeception/Exception/InjectionException.phpY   YWY   g@      -   src/Codeception/Exception/RemoteException.php   YW   I~      7   src/Codeception/Exception/MalformedLocatorException.php  YW  -m      2   src/Codeception/Exception/TestRuntimeException.php|   YW|         4   src/Codeception/Exception/ConfigurationException.php]   YW]   ˏ.      5   src/Codeception/Exception/ModuleConflictException.php  YW  
      3   src/Codeception/Exception/ModuleConfigException.php  YW  4      -   src/Codeception/Exception/ElementNotFound.phph  YWh  7      -   src/Codeception/Exception/ContentNotFound.phps   YWs   B($.      8   src/Codeception/Exception/ConditionalAssertionFailed.php}   YW}   bN      0   src/Codeception/Exception/TestParseException.php'  YW'  Kv      -   src/Codeception/Exception/ModuleException.php  YW  J      0   src/Codeception/Exception/ExtensionException.php  YW  <)      1   src/Codeception/Exception/ConnectionException.phpb   YWb         4   src/Codeception/Exception/ModuleRequireException.php  YW  1      2   src/Codeception/Exception/ExternalUrlException.php\   YW\   Ux¶         src/Codeception/Scenario.php-  YW-  !cB      $   src/Codeception/Event/SuiteEvent.php  YW  Ίv      *   src/Codeception/Event/PrintResultEvent.php  YW  )_ζ      #   src/Codeception/Event/TestEvent.phpy  YWy  Ňb      #   src/Codeception/Event/StepEvent.php{  YW{  ItF+      #   src/Codeception/Event/FailEvent.php
  YW
  He      )   src/Codeception/Command/GenerateSuite.php  YW  t      (   src/Codeception/Command/Shared/Style.phpy  YWy  g˶      -   src/Codeception/Command/Shared/FileSystem.php  YW  QS      )   src/Codeception/Command/Shared/Config.php  YW  6      #   src/Codeception/Command/Console.php   YW   S      )   src/Codeception/Command/GenerateGroup.php  YW  ꠇR      (   src/Codeception/Command/GenerateCept.phpY  YWY  ld         src/Codeception/Command/Run.php4  YW4  91      &   src/Codeception/Command/SelfUpdate.php  YW  wo      (   src/Codeception/Command/GenerateTest.php  YW  R      !   src/Codeception/Command/Build.php  YW  <      *   src/Codeception/Command/GenerateHelper.php.  YW.  ]ܘ      %   src/Codeception/Command/Bootstrap.php{"  YW{"  f_      /   src/Codeception/Command/GenerateEnvironment.php  YW  M"4      +   src/Codeception/Command/GeneratePhpUnit.php}  YW}  t`B      -   src/Codeception/Command/GenerateScenarios.php  YW  )Y      .   src/Codeception/Command/GenerateStepObject.php
  YW
  c      !   src/Codeception/Command/Clean.phpk  YWk  )H      (   src/Codeception/Command/GenerateCest.php=  YW=   I6      .   src/Codeception/Command/GeneratePageObject.php	  YW	            src/Codeception/Step.php  YW  b5         src/Codeception/Module/Dbh.phpx  YWx           src/Codeception/Module/FTP.phpZ  YWZ  ?}      #   src/Codeception/Module/Symfony2.php@  YW@  Gw#      !   src/Codeception/Module/XMLRPC.php=  YW=        #   src/Codeception/Module/Laravel4.phphH  YWhH         #   src/Codeception/Module/Memcache.php  YW  +      "   src/Codeception/Module/MongoDb.phpW)  YWW)  (         src/Codeception/Module/ZF2.phpZ  YWZ  I=      #   src/Codeception/Module/Phalcon2.php?  YW?  gv         src/Codeception/Module/AMQP.php  YW  ߡ      #   src/Codeception/Module/Phalcon1.phpB  YWB  㾶      "   src/Codeception/Module/Asserts.php$)  YW$)  ¶      $   src/Codeception/Module/WebDriver.phpLA YWLA ep         src/Codeception/Module/SOAP.php7  YW7  Ǵ      %   src/Codeception/Module/PhpBrowser.php   YW   {C      $   src/Codeception/Module/Doctrine2.phpz5  YWz5           src/Codeception/Module/Yii2.phpd  YWd  r}         src/Codeception/Module/REST.php  YW  Q׶         src/Codeception/Module/Cli.php1  YW1  )      #   src/Codeception/Module/Laravel5.phpg  YWg  D'j          src/Codeception/Module/Redis.php  YW  5         src/Codeception/Module/Yii1.php  YW  ݦX          src/Codeception/Module/Lumen.phps,  YWs,  	y         src/Codeception/Module/ZF1.phpK   YWK   )      %   src/Codeception/Module/Filesystem.php|  YW|  fy       )   src/Codeception/Module/ZendExpressive.phpg	  YWg	  P3          src/Codeception/Module/Silex.phpU  YWU  ~}Ƕ         src/Codeception/Module/Db.php0-  YW0-            src/Codeception/Module/Queue.php]+  YW]+  Au      #   src/Codeception/Module/Sequence.php	  YW	        #   src/Codeception/Module/Facebook.php&  YW&  [         src/Codeception/Codecept.phpj  YWj  !,         ext/SimpleOutput.phpW  YWW  3         ext/RunFailed.php  YW  ];	         ext/Logger.php  YW  V         ext/Recorder.phpt'  YWt'  _h1Ӷ      :   vendor/facebook/php-sdk-v4/src/Facebook/FacebookClient.php  YW  5Y      G   vendor/facebook/php-sdk-v4/src/Facebook/GraphNodes/GraphApplication.php   YW   Kj~      @   vendor/facebook/php-sdk-v4/src/Facebook/GraphNodes/GraphUser.php+  YW+  }wq      A   vendor/facebook/php-sdk-v4/src/Facebook/GraphNodes/GraphAlbum.php  YW  :      @   vendor/facebook/php-sdk-v4/src/Facebook/GraphNodes/GraphList.phpj   YWj   1F      @   vendor/facebook/php-sdk-v4/src/Facebook/GraphNodes/GraphPage.php  YW  O4ʶ      A   vendor/facebook/php-sdk-v4/src/Facebook/GraphNodes/Collection.php  YW  ѻ      G   vendor/facebook/php-sdk-v4/src/Facebook/GraphNodes/GraphNodeFactory.phpq  YWq  EG      D   vendor/facebook/php-sdk-v4/src/Facebook/GraphNodes/GraphLocation.phpb  YWb  @`      @   vendor/facebook/php-sdk-v4/src/Facebook/GraphNodes/GraphEdge.php  YW  &      A   vendor/facebook/php-sdk-v4/src/Facebook/GraphNodes/GraphGroup.php  YW  ĺV      G   vendor/facebook/php-sdk-v4/src/Facebook/GraphNodes/GraphSessionInfo.php~  YW~  <T      C   vendor/facebook/php-sdk-v4/src/Facebook/GraphNodes/GraphPicture.php  YW  i(      I   vendor/facebook/php-sdk-v4/src/Facebook/GraphNodes/GraphObjectFactory.php  YW  ,qƶ      A   vendor/facebook/php-sdk-v4/src/Facebook/GraphNodes/GraphEvent.phpn  YWn        G   vendor/facebook/php-sdk-v4/src/Facebook/GraphNodes/GraphAchievement.php  YW  )      F   vendor/facebook/php-sdk-v4/src/Facebook/GraphNodes/GraphCoverPhoto.php  YW  {
}ж      B   vendor/facebook/php-sdk-v4/src/Facebook/GraphNodes/GraphObject.phpl   YWl   !k      @   vendor/facebook/php-sdk-v4/src/Facebook/GraphNodes/GraphNode.php$  YW$  %      I   vendor/facebook/php-sdk-v4/src/Facebook/Helpers/FacebookPageTabHelper.php  YW  29      X   vendor/facebook/php-sdk-v4/src/Facebook/Helpers/FacebookSignedRequestFromInputHelper.php  YW  7h      O   vendor/facebook/php-sdk-v4/src/Facebook/Helpers/FacebookRedirectLoginHelper.php~  YW~  !ZO      H   vendor/facebook/php-sdk-v4/src/Facebook/Helpers/FacebookCanvasHelper.phpa  YWa  .      L   vendor/facebook/php-sdk-v4/src/Facebook/Helpers/FacebookJavaScriptHelper.php   YW   oC      4   vendor/facebook/php-sdk-v4/src/Facebook/autoload.php  YW  ;K      E   vendor/facebook/php-sdk-v4/src/Facebook/Http/RequestBodyMultipart.phpx  YWx        A   vendor/facebook/php-sdk-v4/src/Facebook/Http/GraphRawResponse.php*  YW*  Ga1      E   vendor/facebook/php-sdk-v4/src/Facebook/Http/RequestBodyInterface.php~   YW~   o$0      F   vendor/facebook/php-sdk-v4/src/Facebook/Http/RequestBodyUrlEncoded.php9  YW9  茿      <   vendor/facebook/php-sdk-v4/src/Facebook/FacebookResponse.phpG  YWG  2n      L   vendor/facebook/php-sdk-v4/src/Facebook/FileUpload/FacebookTransferChunk.php  YW        @   vendor/facebook/php-sdk-v4/src/Facebook/FileUpload/Mimetypes.php  YW  pI듶      C   vendor/facebook/php-sdk-v4/src/Facebook/FileUpload/FacebookFile.php  YW  Wu      D   vendor/facebook/php-sdk-v4/src/Facebook/FileUpload/FacebookVideo.phpn   YWn   
G      P   vendor/facebook/php-sdk-v4/src/Facebook/FileUpload/FacebookResumableUploader.php  YW  
7      G   vendor/facebook/php-sdk-v4/src/Facebook/Authentication/OAuth2Client.php~  YW~  J\      N   vendor/facebook/php-sdk-v4/src/Facebook/Authentication/AccessTokenMetadata.php  YW  vӶ      F   vendor/facebook/php-sdk-v4/src/Facebook/Authentication/AccessToken.php  YW  t̙      9   vendor/facebook/php-sdk-v4/src/Facebook/SignedRequest.phpu  YWu  u%      A   vendor/facebook/php-sdk-v4/src/Facebook/FacebookBatchResponse.php  YW  YIf      ;   vendor/facebook/php-sdk-v4/src/Facebook/FacebookRequest.php  YW  Y3      D   vendor/facebook/php-sdk-v4/src/Facebook/HttpClients/FacebookCurl.php  YW  ]ʊm      J   vendor/facebook/php-sdk-v4/src/Facebook/HttpClients/HttpClientsFactory.php  YW  d      F   vendor/facebook/php-sdk-v4/src/Facebook/HttpClients/FacebookStream.php  YW  dҶ      P   vendor/facebook/php-sdk-v4/src/Facebook/HttpClients/FacebookStreamHttpClient.phpI  YWI  NA      S   vendor/facebook/php-sdk-v4/src/Facebook/HttpClients/FacebookHttpClientInterface.php   YW   2$7      N   vendor/facebook/php-sdk-v4/src/Facebook/HttpClients/FacebookCurlHttpClient.php2  YW2  5Lw      P   vendor/facebook/php-sdk-v4/src/Facebook/HttpClients/FacebookGuzzleHttpClient.phpE  YWE  6߄      F   vendor/facebook/php-sdk-v4/src/Facebook/Url/FacebookUrlManipulator.php  YW  Ħ2      E   vendor/facebook/php-sdk-v4/src/Facebook/Url/UrlDetectionInterface.php   YW   d&      K   vendor/facebook/php-sdk-v4/src/Facebook/Url/FacebookUrlDetectionHandler.php  YW  h      _   vendor/facebook/php-sdk-v4/src/Facebook/PersistentData/FacebookSessionPersistentDataHandler.php  YW  6[      R   vendor/facebook/php-sdk-v4/src/Facebook/PersistentData/PersistentDataInterface.php   YW   YҶ      ^   vendor/facebook/php-sdk-v4/src/Facebook/PersistentData/FacebookMemoryPersistentDataHandler.phpo  YWo  a      P   vendor/facebook/php-sdk-v4/src/Facebook/PersistentData/PersistentDataFactory.php$  YW$  m      V   vendor/facebook/php-sdk-v4/src/Facebook/Exceptions/FacebookAuthenticationException.php   YW   +Ҷ      N   vendor/facebook/php-sdk-v4/src/Facebook/Exceptions/FacebookClientException.php   YW         K   vendor/facebook/php-sdk-v4/src/Facebook/Exceptions/FacebookSDKException.phps   YWs   8      M   vendor/facebook/php-sdk-v4/src/Facebook/Exceptions/FacebookOtherException.php   YW   x$2      W   vendor/facebook/php-sdk-v4/src/Facebook/Exceptions/FacebookResumableUploadException.php   YW   f{      N   vendor/facebook/php-sdk-v4/src/Facebook/Exceptions/FacebookServerException.php   YW   M۶      P   vendor/facebook/php-sdk-v4/src/Facebook/Exceptions/FacebookResponseException.php  YW  1P      U   vendor/facebook/php-sdk-v4/src/Facebook/Exceptions/FacebookAuthorizationException.php   YW   X$      P   vendor/facebook/php-sdk-v4/src/Facebook/Exceptions/FacebookThrottleException.php   YW         7   vendor/facebook/php-sdk-v4/src/Facebook/FacebookApp.php  YW  [      @   vendor/facebook/php-sdk-v4/src/Facebook/FacebookBatchRequest.php  YW  M      _   vendor/facebook/php-sdk-v4/src/Facebook/PseudoRandomString/PseudoRandomStringGeneratorTrait.php  YW        a   vendor/facebook/php-sdk-v4/src/Facebook/PseudoRandomString/PseudoRandomStringGeneratorFactory.php  YW  AI      `   vendor/facebook/php-sdk-v4/src/Facebook/PseudoRandomString/McryptPseudoRandomStringGenerator.php}  YW}  am      a   vendor/facebook/php-sdk-v4/src/Facebook/PseudoRandomString/UrandomPseudoRandomStringGenerator.php  YW  ^      a   vendor/facebook/php-sdk-v4/src/Facebook/PseudoRandomString/OpenSslPseudoRandomStringGenerator.php  YW  )      c   vendor/facebook/php-sdk-v4/src/Facebook/PseudoRandomString/PseudoRandomStringGeneratorInterface.php   YW   ]F      4   vendor/facebook/php-sdk-v4/src/Facebook/Facebook.php!  YW!  ok      %   vendor/facebook/webdriver/example.php  YW  H']      /   vendor/facebook/webdriver/lib/WebDriverWait.phpC  YWC  v      <   vendor/facebook/webdriver/lib/WebDriverExpectedCondition.phpc  YWc  ,      3   vendor/facebook/webdriver/lib/WebDriverKeyboard.php   YW   %      /   vendor/facebook/webdriver/lib/WebDriverKeys.php8	  YW8	  vk      1   vendor/facebook/webdriver/lib/WebDriverAction.phps   YWs   <ض      0   vendor/facebook/webdriver/lib/WebDriverPoint.phpa  YWa  z      8   vendor/facebook/webdriver/lib/WebDriverTargetLocator.php  YW  ̶      3   vendor/facebook/webdriver/lib/WebDriverUpAction.php   YW   o	      4   vendor/facebook/webdriver/lib/Remote/RemoteMouse.php  YW  }@      6   vendor/facebook/webdriver/lib/Remote/DriverCommand.php
  YW
  v;      <   vendor/facebook/webdriver/lib/Remote/DesiredCapabilities.php  YW  s9      6   vendor/facebook/webdriver/lib/Remote/ExecuteMethod.php   YW   0C      <   vendor/facebook/webdriver/lib/Remote/RemoteTargetLocator.phpS  YWS  s$      8   vendor/facebook/webdriver/lib/Remote/RemoteWebDriver.php  YW        @   vendor/facebook/webdriver/lib/Remote/WebDriverCapabilityType.php3  YW3  =PҶ      <   vendor/facebook/webdriver/lib/Remote/RemoteExecuteMethod.phpd  YWd  χٶ      >   vendor/facebook/webdriver/lib/Remote/Service/DriverService.php  YW  Tz˶      F   vendor/facebook/webdriver/lib/Remote/Service/DriverCommandExecutor.php  YW  \6Ӷ      <   vendor/facebook/webdriver/lib/Remote/HttpCommandExecutor.php.  YW.  
s      <   vendor/facebook/webdriver/lib/Remote/UselessFileDetector.php   YW   X=1      :   vendor/facebook/webdriver/lib/Remote/WebDriverResponse.php  YW  %ڴ      7   vendor/facebook/webdriver/lib/Remote/RemoteKeyboard.php@  YW@  Mg'      9   vendor/facebook/webdriver/lib/Remote/WebDriverCommand.php  YW  E      5   vendor/facebook/webdriver/lib/Remote/FileDetector.php   YW    ~ն      9   vendor/facebook/webdriver/lib/Remote/RemoteWebElement.php  YW  ض      :   vendor/facebook/webdriver/lib/Remote/RemoteTouchScreen.php  YW  r_
      :   vendor/facebook/webdriver/lib/Remote/LocalFileDetector.php   YW   	      =   vendor/facebook/webdriver/lib/Remote/WebDriverBrowserType.php  YW  h1      6   vendor/facebook/webdriver/lib/Chrome/ChromeOptions.php  YW  ΐ*      <   vendor/facebook/webdriver/lib/Chrome/ChromeDriverService.php  YW  
侶      5   vendor/facebook/webdriver/lib/Chrome/ChromeDriver.phpq  YWq  7      8   vendor/facebook/webdriver/lib/Firefox/FirefoxProfile.php~  YW~  tc      7   vendor/facebook/webdriver/lib/Firefox/FirefoxDriver.php   YW   ݾ      <   vendor/facebook/webdriver/lib/Firefox/FirefoxPreferences.php>  YW>  <Rж      E   vendor/facebook/webdriver/lib/Support/Events/EventFiringWebDriver.phpr  YWr  9      F   vendor/facebook/webdriver/lib/Support/Events/EventFiringWebElement.php  YW  -7g      O   vendor/facebook/webdriver/lib/Support/Events/EventFiringWebDriverNavigation.php3  YW3  Ʒ      +   vendor/facebook/webdriver/lib/WebDriver.php  YW        0   vendor/facebook/webdriver/lib/WebDriverAlert.php  YW  L      8   vendor/facebook/webdriver/lib/WebDriverEventListener.php  YW  b      :   vendor/facebook/webdriver/lib/WebDriverHasInputDevices.php   YW   0      3   vendor/facebook/webdriver/lib/WebDriverTimeouts.php  YW  e      0   vendor/facebook/webdriver/lib/WebDriverMouse.php*  YW*  &B      7   vendor/facebook/webdriver/lib/WebDriverCapabilities.phpC  YWC  lOֶ      4   vendor/facebook/webdriver/lib/JavaScriptExecutor.php   YW   ?ζ      5   vendor/facebook/webdriver/lib/WebDriverNavigation.php  YW  kS      1   vendor/facebook/webdriver/lib/WebDriverWindow.phpK  YWK  a)      2   vendor/facebook/webdriver/lib/WebDriverOptions.php  YW  R      8   vendor/facebook/webdriver/lib/WebDriverSearchContext.php   YW         1   vendor/facebook/webdriver/lib/WebDriverSelect.phpp  YWp  HM      3   vendor/facebook/webdriver/lib/WebDriverPlatform.php&  YW&  Q\      @   vendor/facebook/webdriver/lib/Exception/NoSuchFrameException.phpw   YWw   kA      C   vendor/facebook/webdriver/lib/Exception/NoScriptResultException.phpz   YWz   ~'ɂ      F   vendor/facebook/webdriver/lib/Exception/SessionNotCreatedException.php~   YW~   ]F      J   vendor/facebook/webdriver/lib/Exception/MoveTargetOutOfBoundsException.php   YW   ו=      G   vendor/facebook/webdriver/lib/Exception/InvalidCoordinatesException.php   YW   +M̶      I   vendor/facebook/webdriver/lib/Exception/ElementNotSelectableException.php   YW   2      F   vendor/facebook/webdriver/lib/Exception/UnexpectedTagNameException.phpB  YWB  wT.K      E   vendor/facebook/webdriver/lib/Exception/NoSuchCollectionException.php|   YW|   [      D   vendor/facebook/webdriver/lib/Exception/NoStringWrapperException.php{   YW{   m
;      B   vendor/facebook/webdriver/lib/Exception/NoSuchElementException.phpy   YWy   zö      =   vendor/facebook/webdriver/lib/Exception/NoStringException.phpg   YWg   H      B   vendor/facebook/webdriver/lib/Exception/UnknownServerException.phpy   YWy   4      C   vendor/facebook/webdriver/lib/Exception/NoSuchDocumentException.php{   YW{   ׶      A   vendor/facebook/webdriver/lib/Exception/NoSuchWindowException.phpx   YWx   '>x      D   vendor/facebook/webdriver/lib/Exception/IMENotAvailableException.php|   YW|   w}Hh      =   vendor/facebook/webdriver/lib/Exception/ExpectedException.phpu   YWu    >)      H   vendor/facebook/webdriver/lib/Exception/InvalidCookieDomainException.php   YW   "B      @   vendor/facebook/webdriver/lib/Exception/NullPointerException.phpx   YWx   Q      C   vendor/facebook/webdriver/lib/Exception/NoStringLengthException.phpz   YWz   zlrk      B   vendor/facebook/webdriver/lib/Exception/WebDriverCurlException.phpz   YWz   2      C   vendor/facebook/webdriver/lib/Exception/UnknownCommandException.phpz   YWz   E      H   vendor/facebook/webdriver/lib/Exception/UnexpectedAlertOpenException.php   YW   ꃊw      <   vendor/facebook/webdriver/lib/Exception/TimeOutException.phps   YWs   Z3      J   vendor/facebook/webdriver/lib/Exception/StaleElementReferenceException.php   YW   Eʶ      H   vendor/facebook/webdriver/lib/Exception/InvalidElementStateException.php   YW   3      J   vendor/facebook/webdriver/lib/Exception/UnrecognizedExceptionException.php   YW   An¶      @   vendor/facebook/webdriver/lib/Exception/XPathLookupException.phpw   YWw         I   vendor/facebook/webdriver/lib/Exception/UnexpectedJavascriptException.php   YW   KD      N   vendor/facebook/webdriver/lib/Exception/IMEEngineActivationFailedException.php   YW          A   vendor/facebook/webdriver/lib/Exception/NoSuchDriverException.phpx   YWx   ?"o      F   vendor/facebook/webdriver/lib/Exception/UnableToSetCookieException.php}   YW}   0̶      >   vendor/facebook/webdriver/lib/Exception/WebDriverException.php
  YW
  ^      @   vendor/facebook/webdriver/lib/Exception/NoAlertOpenException.phpw   YWw   X      F   vendor/facebook/webdriver/lib/Exception/ElementNotVisibleException.php}   YW}   .      D   vendor/facebook/webdriver/lib/Exception/InvalidSelectorException.php|   YW|   L      I   vendor/facebook/webdriver/lib/Exception/UnsupportedOperationException.php   YW         A   vendor/facebook/webdriver/lib/Exception/NoCollectionException.phpk   YWk   Q      B   vendor/facebook/webdriver/lib/Exception/ScriptTimeoutException.phpz   YWz   h^	      E   vendor/facebook/webdriver/lib/Exception/IndexOutOfBoundsException.phpo   YWo   s      :   vendor/facebook/webdriver/lib/WebDriverCommandExecutor.php   YW         -   vendor/facebook/webdriver/lib/WebDriverBy.php  YW  @N      G   vendor/facebook/webdriver/lib/Interactions/WebDriverCompositeAction.php  YW  |Q      ?   vendor/facebook/webdriver/lib/Interactions/WebDriverActions.php  YW  %      D   vendor/facebook/webdriver/lib/Interactions/WebDriverTouchActions.phpD
  YWD
  iV      H   vendor/facebook/webdriver/lib/Interactions/Touch/WebDriverDownAction.php  YW  C5      H   vendor/facebook/webdriver/lib/Interactions/Touch/WebDriverMoveAction.php  YW  eN      M   vendor/facebook/webdriver/lib/Interactions/Touch/WebDriverLongPressAction.php!  YW!  ۙz      I   vendor/facebook/webdriver/lib/Interactions/Touch/WebDriverTouchScreen.php  YW  4E      I   vendor/facebook/webdriver/lib/Interactions/Touch/WebDriverFlickAction.php  YW  Ӡ      I   vendor/facebook/webdriver/lib/Interactions/Touch/WebDriverTouchAction.php}  YW}  v/d      J   vendor/facebook/webdriver/lib/Interactions/Touch/WebDriverScrollAction.php  YW  ohN      G   vendor/facebook/webdriver/lib/Interactions/Touch/WebDriverTapAction.php  YW  r>$Ҷ      M   vendor/facebook/webdriver/lib/Interactions/Touch/WebDriverDoubleTapAction.php!  YW!  +      T   vendor/facebook/webdriver/lib/Interactions/Touch/WebDriverFlickFromElementAction.php  YW  <B(      U   vendor/facebook/webdriver/lib/Interactions/Touch/WebDriverScrollFromElementAction.phpE  YWE  1      S   vendor/facebook/webdriver/lib/Interactions/Internal/WebDriverClickAndHoldAction.php'  YW'  2      P   vendor/facebook/webdriver/lib/Interactions/Internal/WebDriverSingleKeyAction.phpR  YWR  Sֶ      O   vendor/facebook/webdriver/lib/Interactions/Internal/WebDriverSendKeysAction.php  YW        S   vendor/facebook/webdriver/lib/Interactions/Internal/WebDriverMoveToOffsetAction.php  YW  mҶ      P   vendor/facebook/webdriver/lib/Interactions/Internal/WebDriverMouseMoveAction.php!  YW!  ܶ      T   vendor/facebook/webdriver/lib/Interactions/Internal/WebDriverButtonReleaseAction.php&  YW&  ޶      S   vendor/facebook/webdriver/lib/Interactions/Internal/WebDriverContextClickAction.php*  YW*  >癦      N   vendor/facebook/webdriver/lib/Interactions/Internal/WebDriverKeyDownAction.php.  YW.  1"GQ      L   vendor/facebook/webdriver/lib/Interactions/Internal/WebDriverMouseAction.php  YW        L   vendor/facebook/webdriver/lib/Interactions/Internal/WebDriverKeyUpAction.php.  YW.  Y      R   vendor/facebook/webdriver/lib/Interactions/Internal/WebDriverDoubleClickAction.php%  YW%  2Y      L   vendor/facebook/webdriver/lib/Interactions/Internal/WebDriverClickAction.php  YW  Y#      R   vendor/facebook/webdriver/lib/Interactions/Internal/WebDriverKeysRelatedAction.php  YW  {      L   vendor/facebook/webdriver/lib/Interactions/Internal/WebDriverCoordinates.phpR  YWR  尋I      0   vendor/facebook/webdriver/lib/Net/URLChecker.php  YW  _o      5   vendor/facebook/webdriver/lib/WebDriverDispatcher.phph  YWh  ʶ      2   vendor/facebook/webdriver/lib/WebDriverElement.php  YW  s      =   vendor/facebook/webdriver/lib/Internal/WebDriverLocatable.php   YW   {      4   vendor/facebook/webdriver/lib/WebDriverDimension.php  YW        '   vendor/phpunit/phpunit/src/Util/PHP.php  YW  ca      *   vendor/phpunit/phpunit/src/Util/Getopt.php
  YW
  "M      /   vendor/phpunit/phpunit/src/Util/PHP/Default.php  YW  -m繶      D   vendor/phpunit/phpunit/src/Util/PHP/Template/TestCaseMethod.tpl.dist  YW  B      /   vendor/phpunit/phpunit/src/Util/PHP/Windows.php  YW  r;d      2   vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php6   YW6   G      *   vendor/phpunit/phpunit/src/Util/String.php  YW  \      9   vendor/phpunit/phpunit/src/Util/InvalidArgumentHelper.php  YW  |A`      (   vendor/phpunit/phpunit/src/Util/Test.phpL  YWL        /   vendor/phpunit/phpunit/src/Util/GlobalState.php  YW  cc      ,   vendor/phpunit/phpunit/src/Util/Log/JSON.phpq  YWq  [ö      +   vendor/phpunit/phpunit/src/Util/Log/TAP.php  YW  lŶ      -   vendor/phpunit/phpunit/src/Util/Log/JUnit.php=  YW=  h8      *   vendor/phpunit/phpunit/src/Util/Filter.php  YW  fʶ      (   vendor/phpunit/phpunit/src/Util/Type.php   YW   cڶ      5   vendor/phpunit/phpunit/src/Util/TestSuiteIterator.php  YW  aw      '   vendor/phpunit/phpunit/src/Util/XML.php:  YW:  {Xy      .   vendor/phpunit/phpunit/src/Util/Fileloader.php8  YW8  ՝      +   vendor/phpunit/phpunit/src/Util/Printer.php  YW  J{4      )   vendor/phpunit/phpunit/src/Util/Regex.phpQ  YWQ  2      9   vendor/phpunit/phpunit/src/Util/TestDox/ResultPrinter.php  YW  Q6      >   vendor/phpunit/phpunit/src/Util/TestDox/ResultPrinter/Text.php  YW  !m      >   vendor/phpunit/phpunit/src/Util/TestDox/ResultPrinter/HTML.php  YW        :   vendor/phpunit/phpunit/src/Util/TestDox/NamePrettifier.phpg  YWg  P˶      1   vendor/phpunit/phpunit/src/Util/Configuration.php_J  YW_J  .%      .   vendor/phpunit/phpunit/src/Util/Filesystem.php   YW   )      -   vendor/phpunit/phpunit/src/Util/Blacklist.php  YW  >rݶ      0   vendor/phpunit/phpunit/src/Util/ErrorHandler.php  YW  uPu      7   vendor/phpunit/phpunit/src/Extensions/PhptTestSuite.php  YW  I0b      8   vendor/phpunit/phpunit/src/Extensions/GroupTestSuite.phpB  YWB  MԶ      7   vendor/phpunit/phpunit/src/Extensions/TestDecorator.phpH  YWH  H/      6   vendor/phpunit/phpunit/src/Extensions/PhptTestCase.php  YW  tLb.      8   vendor/phpunit/phpunit/src/Extensions/TicketListener.php

  YW

  r      6   vendor/phpunit/phpunit/src/Extensions/RepeatedTest.php  YW  C      5   vendor/phpunit/phpunit/src/Runner/TestSuiteLoader.php   YW   ԭ#      /   vendor/phpunit/phpunit/src/Runner/Exception.phpk   YWk         =   vendor/phpunit/phpunit/src/Runner/StandardTestSuiteLoader.php  YW  ;      4   vendor/phpunit/phpunit/src/Runner/Filter/Factory.phpe  YWe  k_      1   vendor/phpunit/phpunit/src/Runner/Filter/Test.php  YW  L8      2   vendor/phpunit/phpunit/src/Runner/Filter/Group.php  YW        :   vendor/phpunit/phpunit/src/Runner/Filter/Group/Include.php   YW   1fB      :   vendor/phpunit/phpunit/src/Runner/Filter/Group/Exclude.php   YW   T      4   vendor/phpunit/phpunit/src/Runner/BaseTestRunner.php  YW  zW̶      -   vendor/phpunit/phpunit/src/Runner/Version.php  YW  /J/      2   vendor/phpunit/phpunit/src/Framework/TestSuite.php48  YW48  t      A   vendor/phpunit/phpunit/src/Framework/InvalidCoversTargetError.php   YW   'qն      <   vendor/phpunit/phpunit/src/Framework/IncompleteTestError.php   YW   Ѷ      -   vendor/phpunit/phpunit/src/Framework/Test.php   YW   þ      2   vendor/phpunit/phpunit/src/Framework/RiskyTest.php?   YW?   ,홶      7   vendor/phpunit/phpunit/src/Framework/SyntheticError.php  YW  wk      7   vendor/phpunit/phpunit/src/Framework/IncompleteTest.phpD   YWD    	      9   vendor/phpunit/phpunit/src/Framework/ExceptionWrapper.php  YW  a4      H   vendor/phpunit/phpunit/src/Framework/UnintentionallyCoveredCodeError.phpz   YWz   ܜ      E   vendor/phpunit/phpunit/src/Framework/InvalidCoversTargetException.php{   YW{   +      /   vendor/phpunit/phpunit/src/Framework/Assert.phpa  YWa  =/      1   vendor/phpunit/phpunit/src/Framework/TestCase.phpVw  YWVw  |ĝ      >   vendor/phpunit/phpunit/src/Framework/SkippedTestSuiteError.php   YW   `ʶ      >   vendor/phpunit/phpunit/src/Framework/CodeCoverageException.phph   YWh   ׄ      9   vendor/phpunit/phpunit/src/Framework/Assert/Functions.phpdc  YWdc        K   vendor/phpunit/phpunit/src/Framework/Constraint/ClassHasStaticAttribute.php  YW  1F      :   vendor/phpunit/phpunit/src/Framework/Constraint/IsNull.php   YW   p      7   vendor/phpunit/phpunit/src/Framework/Constraint/Xor.php  YW  ݺ      7   vendor/phpunit/phpunit/src/Framework/Constraint/Not.php  YW  '1R      ;   vendor/phpunit/phpunit/src/Framework/Constraint/IsEmpty.php  YW  3!t      B   vendor/phpunit/phpunit/src/Framework/Constraint/StringContains.php  YW  9U׶      ;   vendor/phpunit/phpunit/src/Framework/Constraint/IsFalse.php   YW   s~)      B   vendor/phpunit/phpunit/src/Framework/Constraint/StringEndsWith.php  YW  <_      @   vendor/phpunit/phpunit/src/Framework/Constraint/IsInstanceOf.phpG  YWG  2AUɶ      G   vendor/phpunit/phpunit/src/Framework/Constraint/TraversableContains.php  YW  D      9   vendor/phpunit/phpunit/src/Framework/Constraint/Count.phpG  YWG  睍      <   vendor/phpunit/phpunit/src/Framework/Constraint/SameSize.php   YW   gSAH      >   vendor/phpunit/phpunit/src/Framework/Constraint/FileExists.php^  YW^  =r      K   vendor/phpunit/phpunit/src/Framework/Constraint/TraversableContainsOnly.phpl  YWl   r      ;   vendor/phpunit/phpunit/src/Framework/Constraint/IsEqual.php  YW  l(      7   vendor/phpunit/phpunit/src/Framework/Constraint/And.php  YW  ʔ      >   vendor/phpunit/phpunit/src/Framework/Constraint/IsAnything.phpY  YWY  ;@      ?   vendor/phpunit/phpunit/src/Framework/Constraint/ArrayHasKey.phpv  YWv  Z      ?   vendor/phpunit/phpunit/src/Framework/Constraint/ArraySubset.php  YW  9"      A   vendor/phpunit/phpunit/src/Framework/Constraint/ExceptionCode.phpx  YWx  [      <   vendor/phpunit/phpunit/src/Framework/Constraint/Callback.php  YW  X`l      =   vendor/phpunit/phpunit/src/Framework/Constraint/Attribute.php  YW  }G      ?   vendor/phpunit/phpunit/src/Framework/Constraint/JsonMatches.php;  YW;  [A      T   vendor/phpunit/phpunit/src/Framework/Constraint/JsonMatches/ErrorMessageProvider.php  YW  7Զ      D   vendor/phpunit/phpunit/src/Framework/Constraint/ExceptionMessage.php]  YW]  wk      <   vendor/phpunit/phpunit/src/Framework/Constraint/LessThan.php  YW  s4      ?   vendor/phpunit/phpunit/src/Framework/Constraint/GreaterThan.php  YW  6      :   vendor/phpunit/phpunit/src/Framework/Constraint/IsTrue.php   YW   S      J   vendor/phpunit/phpunit/src/Framework/Constraint/ExceptionMessageRegExp.php:  YW:  )PH      ?   vendor/phpunit/phpunit/src/Framework/Constraint/IsIdentical.php  YW  3//      :   vendor/phpunit/phpunit/src/Framework/Constraint/IsType.php  YW  ;6      E   vendor/phpunit/phpunit/src/Framework/Constraint/ClassHasAttribute.php  YW  mP      =   vendor/phpunit/phpunit/src/Framework/Constraint/PCREMatch.php  YW  _Y      =   vendor/phpunit/phpunit/src/Framework/Constraint/Exception.phpY  YWY  A׶      D   vendor/phpunit/phpunit/src/Framework/Constraint/StringStartsWith.php  YW  6̶      F   vendor/phpunit/phpunit/src/Framework/Constraint/ObjectHasAttribute.php  YW  |~$߶      =   vendor/phpunit/phpunit/src/Framework/Constraint/Composite.php  YW  ē6      A   vendor/phpunit/phpunit/src/Framework/Constraint/StringMatches.php[  YW[  f<Ƕ      :   vendor/phpunit/phpunit/src/Framework/Constraint/IsJson.php@  YW@  eq      6   vendor/phpunit/phpunit/src/Framework/Constraint/Or.phpr  YWr  >      4   vendor/phpunit/phpunit/src/Framework/OutputError.phpl   YWl   t4      =   vendor/phpunit/phpunit/src/Framework/AssertionFailedError.php   YW   @.      5   vendor/phpunit/phpunit/src/Framework/TestListener.php9  YW9  B      C   vendor/phpunit/phpunit/src/Framework/ExpectationFailedException.php  YW  7<¶      0   vendor/phpunit/phpunit/src/Framework/Warning.phpL  YWL  ,      7   vendor/phpunit/phpunit/src/Framework/RiskyTestError.php   YW   MҶ      9   vendor/phpunit/phpunit/src/Framework/Error/Deprecated.php   YW   rCr      5   vendor/phpunit/phpunit/src/Framework/Error/Notice.php   YW   "?      6   vendor/phpunit/phpunit/src/Framework/Error/Warning.php   YW   A~      9   vendor/phpunit/phpunit/src/Framework/SkippedTestError.php   YW   MJq      9   vendor/phpunit/phpunit/src/Framework/BaseTestListener.phpI  YWI  ^[      4   vendor/phpunit/phpunit/src/Framework/TestFailure.php`  YW`  ӆ      8   vendor/phpunit/phpunit/src/Framework/SkippedTestCase.php  YW  :      2   vendor/phpunit/phpunit/src/Framework/Exception.php/  YW/  P      4   vendor/phpunit/phpunit/src/Framework/SkippedTest.php@   YW@   7w      3   vendor/phpunit/phpunit/src/Framework/Constraint.php  YW  E      3   vendor/phpunit/phpunit/src/Framework/TestResult.php7  YW7  _W      7   vendor/phpunit/phpunit/src/Framework/SelfDescribing.phpd   YWd   c!      ;   vendor/phpunit/phpunit/src/Framework/IncompleteTestCase.php  YW  g3      .   vendor/phpunit/phpunit/src/Framework/Error.php  YW  S      ?   vendor/phpunit/phpunit/src/Framework/TestSuite/DataProvider.php   YW   Dݶ      (   vendor/phpunit/phpunit/src/Exception.php4   YW4   +      3   vendor/phpunit/phpunit/src/TextUI/ResultPrinter.php2&  YW2&  oJȐ      0   vendor/phpunit/phpunit/src/TextUI/TestRunner.phpp  YWp  ⡸      -   vendor/phpunit/phpunit/src/TextUI/Command.phpU  YWU  о      -   vendor/phpunit/phpunit/build/phar-version.php  YW        .   vendor/phpunit/phpunit/build/phar-manifest.php  YW  ,      0   vendor/phpunit/php-file-iterator/src/Factory.phpd  YWd  mp      /   vendor/phpunit/php-file-iterator/src/Facade.php  YW  ?-ɶ      1   vendor/phpunit/php-file-iterator/src/Iterator.php  YW  N      &   vendor/phpunit/php-timer/src/Timer.php  YW  i>      <   vendor/phpunit/php-code-coverage/src/CodeCoverage/Driver.php   YW   u      <   vendor/phpunit/php-code-coverage/src/CodeCoverage/Filter.phph  YWh  ˍ      P   vendor/phpunit/php-code-coverage/src/CodeCoverage/Util/InvalidArgumentHelper.php  YW  dҔ      @   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/PHP.php  YW  \X      D   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/Factory.php	  YW	  aO      K   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/Node/Directory.php  YW  bu/      J   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/Node/Iterator.php6  YW6  Ƕ      F   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/Node/File.php(  YW(  VH      T   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Directory.php  YW  o      T   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Dashboard.php  YW  (^      ]   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Template/css/style.css+  YW+  Y`g      a   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Template/css/nv.d3.min.cssX%  YWX%  0,      e   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Template/css/bootstrap.min.css9 YW9 ܛ2      \   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Template/js/d3.min.jsUN YWUN ;1      c   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Template/js/bootstrap.min.jso  YWo  ;      _   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Template/js/nv.d3.min.js] YW] ']4      c   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Template/js/html5shiv.min.jsL
  YWL
  F      a   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Template/js/respond.min.js  YW  {      `   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Template/js/holder.min.jsm  YWm  JsѶ      `   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Template/js/jquery.min.jsv YWv e      c   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Template/file_item.html.distg  YWg  VP      f   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Template/coverage_bar.html.dist1  YW1  itL      e   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Template/method_item.html.distx  YWx  *      h   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Template/directory_item.html.dist5  YW5  Z]      c   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Template/directory.html.diste  YWe  ǐ      w   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Template/fonts/glyphicons-halflings-regular.woff[  YW[  {      v   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Template/fonts/glyphicons-halflings-regular.svg¨ YW¨ |ɶ      v   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Template/fonts/glyphicons-halflings-regular.eotN  YWN  XǱ      x   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Template/fonts/glyphicons-halflings-regular.woff2lF  YWlF  va      v   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Template/fonts/glyphicons-halflings-regular.ttf\  YW\  <      ^   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Template/file.html.dist
  YW
  D      c   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Template/dashboard.html.dist  YW  {      O   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/File.phpU&  YWU&  `}J      J   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer.php  YW        A   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/Node.php  YW  "      A   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/Text.phpo  YWo  @      C   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/Clover.php5  YW5  s`׶      J   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/XML/Directory.phpk   YWk   SO޶      L   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/XML/File/Report.php  YW  aZ̶      J   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/XML/File/Unit.php  YW  ǲ$      N   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/XML/File/Coverage.php  YW  :2      L   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/XML/File/Method.php  YW  L<      E   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/XML/Node.phpc  YWc  wM      H   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/XML/Project.php  YW  |l      G   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/XML/Totals.php$
  YW$
  U      F   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/XML/Tests.php  YW  l>ƶ      E   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/XML/File.php  YW  ^kB      A   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML.php  YW  v      @   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/XML.phpa  YWa  b$]      C   vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/Crap4j.php  YW  çp      :   vendor/phpunit/php-code-coverage/src/CodeCoverage/Util.php  YW  [      Z   vendor/phpunit/php-code-coverage/src/CodeCoverage/Exception/UnintentionallyCoveredCode.phpw   YWw   .
      ?   vendor/phpunit/php-code-coverage/src/CodeCoverage/Exception.phpR   YWR   ?d      C   vendor/phpunit/php-code-coverage/src/CodeCoverage/Driver/Xdebug.php  YW        C   vendor/phpunit/php-code-coverage/src/CodeCoverage/Driver/PHPDBG.php|  YW|  HFb      A   vendor/phpunit/php-code-coverage/src/CodeCoverage/Driver/HHVM.php   YW   <      5   vendor/phpunit/php-code-coverage/src/CodeCoverage.php5  YW5  Ze      8   vendor/phpunit/php-code-coverage/scripts/auto_append.phpt   YWt   s      9   vendor/phpunit/php-code-coverage/scripts/auto_prepend.php  YW  %      ^   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Generator/proxied_method.tpl.dist  YW  ?a      [   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Generator/trait_class.tpl.dist7   YW7   [$~      d   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Generator/mocked_static_method.tpl.dist   YW   +F      \   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Generator/mocked_clone.tpl.dist   YW   aT      \   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Generator/mocked_class.tpl.dist  YW  FZ      c   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Generator/mocked_class_method.tpl.dist   YW   4޶      ]   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Generator/mocked_method.tpl.dist  YW  bV      [   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Generator/wsdl_method.tpl.dist<   YW<   i      Z   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Generator/wsdl_class.tpl.dist   YW   w&S      ^   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Generator/unmocked_clone.tpl.dist   YW   8W}ض      R   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Builder/Namespace.php   YW   ϑ~      Y   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Builder/InvocationMocker.php  YW  c'f      N   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Builder/Match.php   YW   }̦      Q   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Builder/Identity.phpt   YWt         X   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Builder/MethodNameMatch.php   YW   gwj      M   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Builder/Stub.php   YW   s      X   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Builder/ParametersMatch.php   YW   >@F:      H   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher.php  YW  ~7Ҷ      Q   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/InvocationMocker.php  YW  7e      K   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/MockObject.phpJ  YWJ  $      X   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/AnyInvokedCount.php   YW   p      \   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/InvokedAtLeastCount.php  YW  A߶      U   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/InvokedCount.php!  YW!  ZH'      \   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/StatelessInvocation.php)  YW)  %      S   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/MethodName.php  YW  <6      X   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/InvokedRecorder.php~  YW~  I0g      [   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/InvokedAtMostCount.php  YW  =      ^   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/ConsecutiveParameters.php   YW   ~O      S   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/Invocation.php\  YW\  (	A      [   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/InvokedAtLeastOnce.php  YW        S   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/Parameters.php  YW  Qt      V   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/AnyParameters.php5  YW5  v      W   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/InvokedAtIndex.phpq  YWq        K   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Invocation.phpJ   YWJ   qЀg      L   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/MockBuilder.php
  YW
  p(1      J   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Generator.phpQ  YWQ        K   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Verifiable.phpj   YWj          [   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Exception/RuntimeException.php   YW   ˹}      T   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Exception/Exception.phpI   YWI   ;      a   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Exception/BadMethodCallException.php   YW   ˥      T   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Stub/ReturnCallback.php8  YW8  ?'F      L   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Stub/Return.php  YW  jPy@      T   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Stub/ReturnArgument.php%  YW%  0]      P   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Stub/ReturnSelf.php  YW  pɶ      T   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Stub/ReturnValueMap.phpt  YWt  eJL      V   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Stub/ConsecutiveCalls.php  YW  $鬶      W   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Stub/MatcherCollection.php   YW   åc      O   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Stub/Exception.php  YW  kBD      R   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Invocation/Static.php  YW  `pr>      R   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Invocation/Object.phpn  YWn  ^J      J   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Invokable.php'  YW'  ɶ      E   vendor/phpunit/phpunit-mock-objects/src/Framework/MockObject/Stub.php   YW   l      -   vendor/phpunit/php-token-stream/src/Token.php[H  YW[H  g˨      4   vendor/phpunit/php-token-stream/src/Token/Stream.php"  YW"  {{      C   vendor/phpunit/php-token-stream/src/Token/Stream/CachingFactory.php  YW  |c      1   vendor/phpunit/php-text-template/src/Template.php  YW  I      .   vendor/php-amqplib/php-amqplib/spec/parser.phph*  YWh*  /q      ?   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Helper/MiscHelper.php  YW  o]ڶ      @   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Helper/DebugHelper.php  YW  
B      E   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Protocol/Wait080.php
  YW
  lw      E   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Protocol/Wait091.php  YW  UG      I   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Protocol/Protocol091.php5  YW5  	zF      I   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Protocol/Protocol080.phpM  YWM  #e$      J   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Protocol/MethodMap080.php  YW  P6ж      J   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Helper/Protocol/MethodMap091.php  YW  vqF      =   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AMQPReader.php  YW  Ӫr      I   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AMQPAbstractCollection.phpI  YWI  K      =   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AMQPWriter.phpr  YWr  ir2      <   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AMQPTable.php  YW  #G      <   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AMQPArray.phpl  YWl  ]&      A   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AbstractClient.php{  YW{  {{¶      ?   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/Constants091.phpz	  YWz	  W      A   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/GenericContent.php@
  YW@
  XN      ?   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/Constants080.phpW  YWW  K,      >   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/AMQPDecimal.php  YW  ۶      >   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/IO/SocketIO.php  YW  췆K      >   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/IO/StreamIO.php  YW  Qp*      @   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/IO/AbstractIO.phpl  YWl  )2      E   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Channel/AbstractChannel.php|$  YW|$  ~1      A   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Channel/AMQPChannel.php8S  YW8S  ݑY      A   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Message/AMQPMessage.php  YW  Fnƶ      O   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPOutOfRangeException.php   YW   Y      T   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPProtocolChannelException.phpl   YWl   ϯ      K   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPIOWaitException.phpb   YWb         O   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPConnectionException.phpb   YWb   &⭶      L   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPRuntimeException.php   YW   )      L   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPChannelException.php_   YW_   N=      N   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPExceptionInterface.phpL   YWL   ;f[ܶ      L   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPTimeoutException.php   YW   	      P   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPOutOfBoundsException.php   YW   Ϳ,      W   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPProtocolConnectionException.phpo   YWo   u#]      G   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPIOException.phpv   YWv   ^      J   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPLogicException.php   YW   $dL      T   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPInvalidArgumentException.php   YW   kfm      P   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPBasicCancelException.php   YW   D      M   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPProtocolException.php5  YW5  	      E   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Exception/AMQPException.php  YW  H~      Q   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AMQPLazySocketConnection.php  YW        G   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AMQPConnection.phpe   YWe   rӶ      M   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AMQPSocketConnection.php  YW  :O      K   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AMQPLazyConnection.php  YW        J   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AMQPSSLConnection.phpj  YWj  ZŶ      M   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AMQPStreamConnection.php  YW  "T      K   vendor/php-amqplib/php-amqplib/PhpAmqpLib/Connection/AbstractConnection.php8  YW8           vendor/autoload.php   YW         #   vendor/sebastian/diff/src/Chunk.php#  YW#  h      W   vendor/sebastian/diff/src/LCS/MemoryEfficientLongestCommonSubsequenceImplementation.php  YW  Z      :   vendor/sebastian/diff/src/LCS/LongestCommonSubsequence.php   YW   (U      U   vendor/sebastian/diff/src/LCS/TimeEfficientLongestCommonSubsequenceImplementation.php  YW  I      "   vendor/sebastian/diff/src/Line.php  YW  64/F      $   vendor/sebastian/diff/src/Differ.php  YW  38<̶      $   vendor/sebastian/diff/src/Parser.php  YW  $      "   vendor/sebastian/diff/src/Diff.php  YW  n@      +   vendor/sebastian/comparator/src/Factory.php'  YW'  KW      8   vendor/sebastian/comparator/src/MockObjectComparator.php  YW  m4      5   vendor/sebastian/comparator/src/NumericComparator.phpP  YWP  ˋV      2   vendor/sebastian/comparator/src/TypeComparator.php  YW  e]      4   vendor/sebastian/comparator/src/DoubleComparator.php+  YW+        .   vendor/sebastian/comparator/src/Comparator.php	  YW	  2      3   vendor/sebastian/comparator/src/ArrayComparator.php  YW  W6      4   vendor/sebastian/comparator/src/ScalarComparator.phpf  YWf  9ۊ      4   vendor/sebastian/comparator/src/ObjectComparator.php|  YW|  NC      5   vendor/sebastian/comparator/src/ComparisonFailure.php  YW  e      6   vendor/sebastian/comparator/src/DateTimeComparator.php  YW  yI      6   vendor/sebastian/comparator/src/ResourceComparator.php  YW  \      >   vendor/sebastian/comparator/src/SplObjectStorageComparator.phpq  YWq  y#      7   vendor/sebastian/comparator/src/ExceptionComparator.php  YW  `.cG      5   vendor/sebastian/comparator/src/DOMNodeComparator.phpJ  YWJ  \g      2   vendor/sebastian/recursion-context/src/Context.php4  YW4  Y5      4   vendor/sebastian/recursion-context/src/Exception.phpX   YWX   N3      C   vendor/sebastian/recursion-context/src/InvalidArgumentException.php   YW   >_F      ,   vendor/sebastian/environment/src/Console.php  YW  衶      ,   vendor/sebastian/environment/src/Runtime.php	  YW	  .      *   vendor/sebastian/exporter/src/Exporter.php  YW        6   vendor/sebastian/global-state/src/RuntimeException.php   YW   5~      .   vendor/sebastian/global-state/src/Snapshot.phpU  YWU  X      2   vendor/sebastian/global-state/src/CodeExporter.php  YW  4R=      .   vendor/sebastian/global-state/src/Restorer.php?
  YW?
  n̦      /   vendor/sebastian/global-state/src/Blacklist.php  YW  n|      /   vendor/sebastian/global-state/src/Exception.phpS   YWS   C)      (   vendor/sebastian/version/src/Version.php  YW  [/      P   vendor/doctrine/instantiator/src/Doctrine/Instantiator/InstantiatorInterface.php   YW   ,A¶      G   vendor/doctrine/instantiator/src/Doctrine/Instantiator/Instantiator.php  YW  yG      W   vendor/doctrine/instantiator/src/Doctrine/Instantiator/Exception/ExceptionInterface.phpj   YWj   ζ      ]   vendor/doctrine/instantiator/src/Doctrine/Instantiator/Exception/UnexpectedValueException.php  YW  xi      ]   vendor/doctrine/instantiator/src/Doctrine/Instantiator/Exception/InvalidArgumentException.php  YW  p      E   vendor/myclabs/deep-copy/src/DeepCopy/Reflection/ReflectionHelper.php  YW        A   vendor/myclabs/deep-copy/src/DeepCopy/TypeMatcher/TypeMatcher.php  YW  @PG      E   vendor/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyNameMatcher.php  YW        9   vendor/myclabs/deep-copy/src/DeepCopy/Matcher/Matcher.phpo   YWo   ,eն      A   vendor/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyMatcher.phpj  YWj  oL      E   vendor/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyTypeMatcher.php  YW  31      B   vendor/myclabs/deep-copy/src/DeepCopy/Exception/CloneException.php`   YW`   .ڝ      B   vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/ReplaceFilter.php  YW  'w%      ?   vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/TypeFilter.phpe   YWe   S<_      F   vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/ShallowCopyFilter.php   YW         ;   vendor/myclabs/deep-copy/src/DeepCopy/Filter/KeepFilter.php   YW   ;      7   vendor/myclabs/deep-copy/src/DeepCopy/Filter/Filter.php{   YW{   U겶      W   vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineEmptyCollectionFilter.php  YW        R   vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineCollectionFilter.php(  YW(        >   vendor/myclabs/deep-copy/src/DeepCopy/Filter/ReplaceFilter.php  YW  /      >   vendor/myclabs/deep-copy/src/DeepCopy/Filter/SetNullFilter.phpD  YWD  vދ      2   vendor/myclabs/deep-copy/src/DeepCopy/DeepCopy.php8  YW8  ݶ      *   vendor/myclabs/deep-copy/doc/deep-copy.png*  YW*  i9      +   vendor/myclabs/deep-copy/doc/deep-clone.png6  YW6  JŨ      &   vendor/myclabs/deep-copy/doc/graph.png$  YW$  P϶      &   vendor/myclabs/deep-copy/doc/clone.png\0  YW\0        ,   vendor/guzzlehttp/psr7/src/ServerRequest.php`  YW`  qq      -   vendor/guzzlehttp/psr7/src/DroppingStream.php/  YW/  FE;      3   vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php8  YW8  b      +   vendor/guzzlehttp/psr7/src/UploadedFile.php  YW  >#      *   vendor/guzzlehttp/psr7/src/LimitStream.php  YW  0      '   vendor/guzzlehttp/psr7/src/Response.phpW
  YWW
  w      0   vendor/guzzlehttp/psr7/src/functions_include.php]   YW]   ɶ      "   vendor/guzzlehttp/psr7/src/Uri.php#  YW#  {c      %   vendor/guzzlehttp/psr7/src/Stream.php  YW        .   vendor/guzzlehttp/psr7/src/MultipartStream.php*
  YW*
        ,   vendor/guzzlehttp/psr7/src/StreamWrapper.php  YW  z      ,   vendor/guzzlehttp/psr7/src/InflateStream.phpb  YWb  L('      )   vendor/guzzlehttp/psr7/src/PumpStream.php_  YW_  !IU      +   vendor/guzzlehttp/psr7/src/MessageTrait.php	  YW	        &   vendor/guzzlehttp/psr7/src/Request.php	  YW	  '      -   vendor/guzzlehttp/psr7/src/LazyOpenStream.php  YW  bE      ,   vendor/guzzlehttp/psr7/src/CachingStream.phpx  YWx  à      (   vendor/guzzlehttp/psr7/src/functions.phpm3  YWm3   F      +   vendor/guzzlehttp/psr7/src/NoSeekStream.php:  YW:  R!      +   vendor/guzzlehttp/psr7/src/AppendStream.php  YW  ƶ      +   vendor/guzzlehttp/psr7/src/BufferStream.php)  YW)  1      '   vendor/guzzlehttp/psr7/src/FnStream.phpn  YWn  o      8   vendor/guzzlehttp/ringphp/src/Future/BaseFutureTrait.php  YW  ٶ      =   vendor/guzzlehttp/ringphp/src/Future/FutureArrayInterface.php   YW         4   vendor/guzzlehttp/ringphp/src/Future/FutureValue.phpt   YWt   ԄV      4   vendor/guzzlehttp/ringphp/src/Future/FutureArray.php1  YW1  ۆE      =   vendor/guzzlehttp/ringphp/src/Future/CompletedFutureValue.php]  YW]  +y      9   vendor/guzzlehttp/ringphp/src/Future/MagicFutureTrait.php  YW  U      =   vendor/guzzlehttp/ringphp/src/Future/CompletedFutureArray.php  YW  P6      8   vendor/guzzlehttp/ringphp/src/Future/FutureInterface.php  YW  2u      4   vendor/guzzlehttp/ringphp/src/Client/MockHandler.phpE  YWE  Ũ      4   vendor/guzzlehttp/ringphp/src/Client/CurlFactory.php,  YW,  !0      4   vendor/guzzlehttp/ringphp/src/Client/ClientUtils.php2  YW2  iM      3   vendor/guzzlehttp/ringphp/src/Client/Middleware.php*  YW*  [z      6   vendor/guzzlehttp/ringphp/src/Client/StreamHandler.php!  YW!  0KL      4   vendor/guzzlehttp/ringphp/src/Client/CurlHandler.phpu  YWu  ./      9   vendor/guzzlehttp/ringphp/src/Client/CurlMultiHandler.php`  YW`  5      &   vendor/guzzlehttp/ringphp/src/Core.php  YW  ^)      9   vendor/guzzlehttp/ringphp/src/Exception/RingException.php^   YW^   2x      >   vendor/guzzlehttp/ringphp/src/Exception/CancelledException.phpO   YWO         <   vendor/guzzlehttp/ringphp/src/Exception/ConnectException.php_   YW_   ڊU      J   vendor/guzzlehttp/ringphp/src/Exception/CancelledFutureAccessException.php   YW   kR      1   vendor/guzzlehttp/streams/src/AsyncReadStream.php	  YW	        0   vendor/guzzlehttp/streams/src/DroppingStream.php  YW  ;      6   vendor/guzzlehttp/streams/src/StreamDecoratorTrait.phpz  YWz  m      -   vendor/guzzlehttp/streams/src/LimitStream.php_  YW_  ç      1   vendor/guzzlehttp/streams/src/StreamInterface.php  YW  M`;      (   vendor/guzzlehttp/streams/src/Stream.php  YW  -bUW      /   vendor/guzzlehttp/streams/src/InflateStream.php  YW  saW      ,   vendor/guzzlehttp/streams/src/PumpStream.php
  YW
  y%&      '   vendor/guzzlehttp/streams/src/Utils.phpE  YWE  ]      0   vendor/guzzlehttp/streams/src/LazyOpenStream.phpt  YWt   ?      /   vendor/guzzlehttp/streams/src/CachingStream.php  YW  ՟      9   vendor/guzzlehttp/streams/src/MetadataStreamInterface.phph   YWh   r      ,   vendor/guzzlehttp/streams/src/NullStream.phpf  YWf  iVvж      9   vendor/guzzlehttp/streams/src/Exception/SeekException.php  YW  )/+      A   vendor/guzzlehttp/streams/src/Exception/CannotAttachException.phpg   YWg   1<      5   vendor/guzzlehttp/streams/src/GuzzleStreamWrapper.php  YW  )'#>      .   vendor/guzzlehttp/streams/src/NoSeekStream.php-  YW-  3@߶      .   vendor/guzzlehttp/streams/src/AppendStream.php
  YW
        .   vendor/guzzlehttp/streams/src/BufferStream.php  YW  tic      *   vendor/guzzlehttp/streams/src/FnStream.phpg  YWg  k(}      *   vendor/guzzlehttp/guzzle/src/Mimetypes.phpj  YWj  3      +   vendor/guzzlehttp/guzzle/src/RingBridge.php  YW         0   vendor/guzzlehttp/guzzle/src/ClientInterface.php!  YW!  aj+      %   vendor/guzzlehttp/guzzle/src/Pool.php  YW  FO      ,   vendor/guzzlehttp/guzzle/src/Transaction.php;  YW;  ^J1      $   vendor/guzzlehttp/guzzle/src/Url.php  YW  kN      2   vendor/guzzlehttp/guzzle/src/Subscriber/Cookie.php  YW        0   vendor/guzzlehttp/guzzle/src/Subscriber/Mock.php  YW  5ݭz      5   vendor/guzzlehttp/guzzle/src/Subscriber/HttpError.php@  YW@  l6      4   vendor/guzzlehttp/guzzle/src/Subscriber/Redirect.phpN  YWN  A      3   vendor/guzzlehttp/guzzle/src/Subscriber/History.php%  YW%  ]@+      3   vendor/guzzlehttp/guzzle/src/Subscriber/Prepare.php  YW  qXM      '   vendor/guzzlehttp/guzzle/src/Client.php  YW  Om      -   vendor/guzzlehttp/guzzle/src/BatchResults.php  YW        +   vendor/guzzlehttp/guzzle/src/Collection.php  YW  l06      ,   vendor/guzzlehttp/guzzle/src/QueryParser.php  YW  ˶      +   vendor/guzzlehttp/guzzle/src/RequestFsm.php  YW  3}K      1   vendor/guzzlehttp/guzzle/src/Message/Response.php+  YW+  :oҶ      9   vendor/guzzlehttp/guzzle/src/Message/RequestInterface.php  YW  '      7   vendor/guzzlehttp/guzzle/src/Message/MessageFactory.phpH  YWH        8   vendor/guzzlehttp/guzzle/src/Message/AbstractMessage.php  YW  Re      0   vendor/guzzlehttp/guzzle/src/Message/Request.php2  YW2  k)      :   vendor/guzzlehttp/guzzle/src/Message/ResponseInterface.php  YW  7,      @   vendor/guzzlehttp/guzzle/src/Message/MessageFactoryInterface.phpB  YWB  EĎӶ      9   vendor/guzzlehttp/guzzle/src/Message/MessageInterface.php  YW  [3      @   vendor/guzzlehttp/guzzle/src/Message/AppliesHeadersInterface.php   YW         6   vendor/guzzlehttp/guzzle/src/Message/MessageParser.phpd  YWd  ֽ      7   vendor/guzzlehttp/guzzle/src/Message/FutureResponse.phpB	  YWB	  d      &   vendor/guzzlehttp/guzzle/src/Utils.php  YW  N	      ;   vendor/guzzlehttp/guzzle/src/Exception/RequestException.php  YW         <   vendor/guzzlehttp/guzzle/src/Exception/TransferException.php\   YW\   GQN      :   vendor/guzzlehttp/guzzle/src/Exception/ClientException.php`   YW`   p      9   vendor/guzzlehttp/guzzle/src/Exception/StateException.phpZ   YWZ   *BҶ      H   vendor/guzzlehttp/guzzle/src/Exception/CouldNotRewindStreamException.phpg   YWg    Y      :   vendor/guzzlehttp/guzzle/src/Exception/ServerException.php`   YW`          9   vendor/guzzlehttp/guzzle/src/Exception/ParseException.php  YW  #7      ;   vendor/guzzlehttp/guzzle/src/Exception/ConnectException.phpZ   YWZ   dB"m      <   vendor/guzzlehttp/guzzle/src/Exception/XmlParseException.php  YW  8d      D   vendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.phpc   YWc   ߶      ?   vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.phpa   YWa   ]I      -   vendor/guzzlehttp/guzzle/src/HasDataTrait.php  YW  *      1   vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php  YW  ܫ      1   vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php  YW  )      5   vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php6  YW6  :e      8   vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.phpF  YWF  fɶ      :   vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php(  YW(  O      :   vendor/guzzlehttp/guzzle/src/Event/SubscriberInterface.php}   YW}   _N      2   vendor/guzzlehttp/guzzle/src/Event/BeforeEvent.php2  YW2  )F      4   vendor/guzzlehttp/guzzle/src/Event/ProgressEvent.php  YW  )ia      :   vendor/guzzlehttp/guzzle/src/Event/HasEmitterInterface.phpk   YWk   
K      /   vendor/guzzlehttp/guzzle/src/Event/EndEvent.php   YW   6^      <   vendor/guzzlehttp/guzzle/src/Event/AbstractTransferEvent.php!  YW!  8lɶ      4   vendor/guzzlehttp/guzzle/src/Event/AbstractEvent.php  YW  ]      1   vendor/guzzlehttp/guzzle/src/Event/ErrorEvent.php   YW   Il      .   vendor/guzzlehttp/guzzle/src/Event/Emitter.php
  YW
  z|      4   vendor/guzzlehttp/guzzle/src/Event/CompleteEvent.phpc   YWc   N      6   vendor/guzzlehttp/guzzle/src/Event/HasEmitterTrait.php   YW   lv      =   vendor/guzzlehttp/guzzle/src/Event/AbstractRetryableEvent.phpB  YWB  -      4   vendor/guzzlehttp/guzzle/src/Event/RequestEvents.php  YW  M6      ;   vendor/guzzlehttp/guzzle/src/Event/AbstractRequestEvent.phpj  YWj  (_m      7   vendor/guzzlehttp/guzzle/src/Event/EmitterInterface.php_  YW_  ->      <   vendor/guzzlehttp/guzzle/src/Event/ListenerAttacherTrait.phpx  YWx  v.      5   vendor/guzzlehttp/guzzle/src/Event/EventInterface.php   YW   5      1   vendor/guzzlehttp/guzzle/src/ToArrayInterface.php_   YW_    B(      &   vendor/guzzlehttp/guzzle/src/Query.php0	  YW0	  =      ,   vendor/guzzlehttp/guzzle/src/UriTemplate.php  YW  y      .   vendor/guzzlehttp/guzzle/src/Post/PostBody.php  YW  :]Ƕ      3   vendor/guzzlehttp/guzzle/src/Post/MultipartBody.php  YW  !E      7   vendor/guzzlehttp/guzzle/src/Post/PostBodyInterface.php	  YW	  Sú      .   vendor/guzzlehttp/guzzle/src/Post/PostFile.php   YW   ٧i      7   vendor/guzzlehttp/guzzle/src/Post/PostFileInterface.php   YW   U      +   vendor/guzzlehttp/guzzle/build/packager.php  YW  UWu       5   vendor/guzzlehttp/guzzle/docs/_static/guzzle-icon.png#  YW#  xƶ      .   vendor/guzzlehttp/guzzle/docs/_static/logo.png~ YW~ +8K      0   vendor/psr/http-message/src/RequestInterface.php  YW  V      /   vendor/psr/http-message/src/StreamInterface.php  YW  h\l      1   vendor/psr/http-message/src/ResponseInterface.php  YW        0   vendor/psr/http-message/src/MessageInterface.php  YW  )t      5   vendor/psr/http-message/src/UploadedFileInterface.phpz  YWz  9b      ,   vendor/psr/http-message/src/UriInterface.php|  YW|  k      6   vendor/psr/http-message/src/ServerRequestInterface.phpo  YWo  
$h      )   vendor/psr/log/Psr/Log/AbstractLogger.php3  YW3  s K      #   vendor/psr/log/Psr/Log/LogLevel.php   YW   j8      &   vendor/psr/log/Psr/Log/LoggerTrait.php`  YW`  C      *   vendor/psr/log/Psr/Log/LoggerInterface.php  YW  
}      3   vendor/psr/log/Psr/Log/Test/LoggerInterfaceTest.php
  YW
        %   vendor/psr/log/Psr/Log/NullLogger.php   YW   =      +   vendor/psr/log/Psr/Log/LoggerAwareTrait.php   YW   e      3   vendor/psr/log/Psr/Log/InvalidArgumentException.php`   YW`    X1      /   vendor/psr/log/Psr/Log/LoggerAwareInterface.php{   YW{   (@      ,   vendor/react/promise/src/RejectedPromise.php  YW  bf      (   vendor/react/promise/src/LazyPromise.php!  YW!        8   vendor/react/promise/src/UnhandledRejectionException.php  YW  .V      .   vendor/react/promise/src/functions_include.php\   YW\   1^      %   vendor/react/promise/src/Deferred.php  YW  M      5   vendor/react/promise/src/ExtendedPromiseInterface.phpx  YWx  Ɉж      $   vendor/react/promise/src/Promise.php(  YW(  5?       -   vendor/react/promise/src/PromiseInterface.php   YW   \*      .   vendor/react/promise/src/CancellationQueue.php  YW  ]$      .   vendor/react/promise/src/PromisorInterface.php_   YW_   lQ)      6   vendor/react/promise/src/Exception/LengthException.php^   YW^   ?q      &   vendor/react/promise/src/functions.php  YW  s=E      8   vendor/react/promise/src/CancellablePromiseInterface.php   YW   	<      -   vendor/react/promise/src/FulfilledPromise.php  YW  d      /   vendor/symfony/css-selector/XPath/XPathExpr.php{  YW{        0   vendor/symfony/css-selector/XPath/Translator.php~  YW~  :x#      9   vendor/symfony/css-selector/XPath/TranslatorInterface.phpV  YWV  [      A   vendor/symfony/css-selector/XPath/Extension/AbstractExtension.php  YW  l      D   vendor/symfony/css-selector/XPath/Extension/PseudoClassExtension.php  YW        =   vendor/symfony/css-selector/XPath/Extension/NodeExtension.php  YW  m      J   vendor/symfony/css-selector/XPath/Extension/AttributeMatchingExtension.php	  YW	  EH      A   vendor/symfony/css-selector/XPath/Extension/FunctionExtension.php1  YW1  O      D   vendor/symfony/css-selector/XPath/Extension/CombinationExtension.phpy  YWy  f      =   vendor/symfony/css-selector/XPath/Extension/HtmlExtension.php  YW  li      B   vendor/symfony/css-selector/XPath/Extension/ExtensionInterface.php  YW  #.ɶ      +   vendor/symfony/css-selector/CssSelector.php  YW  K      .   vendor/symfony/css-selector/Node/ClassNode.phpo  YWo  60      1   vendor/symfony/css-selector/Node/SelectorNode.php  YW  ,'      0   vendor/symfony/css-selector/Node/Specificity.php  YW  #S      1   vendor/symfony/css-selector/Node/FunctionNode.php  YW        /   vendor/symfony/css-selector/Node/PseudoNode.php  YW  lɦ	      0   vendor/symfony/css-selector/Node/ElementNode.php  YW  qJ      1   vendor/symfony/css-selector/Node/NegationNode.php  YW  Źⴶ      1   vendor/symfony/css-selector/Node/AbstractNode.phpN  YWN  =      -   vendor/symfony/css-selector/Node/HashNode.php`  YW`  L;N      9   vendor/symfony/css-selector/Node/CombinedSelectorNode.php  YW  '      2   vendor/symfony/css-selector/Node/NodeInterface.php   YW   .y      2   vendor/symfony/css-selector/Node/AttributeNode.php  YW  9W      :   vendor/symfony/css-selector/Parser/Handler/HashHandler.php  YW  Z_R      @   vendor/symfony/css-selector/Parser/Handler/WhitespaceHandler.phpN  YWN  sE      ?   vendor/symfony/css-selector/Parser/Handler/HandlerInterface.php  YW  ض      <   vendor/symfony/css-selector/Parser/Handler/NumberHandler.php
  YW
  ؾP      @   vendor/symfony/css-selector/Parser/Handler/IdentifierHandler.php  YW  "Hj      =   vendor/symfony/css-selector/Parser/Handler/CommentHandler.php  YW  !      <   vendor/symfony/css-selector/Parser/Handler/StringHandler.phpi  YWi  D      6   vendor/symfony/css-selector/Parser/ParserInterface.php   YW   y9      ,   vendor/symfony/css-selector/Parser/Token.php  YW  Ws      =   vendor/symfony/css-selector/Parser/Shortcut/ElementParser.php  YW  ]      ;   vendor/symfony/css-selector/Parser/Shortcut/ClassParser.phpz  YWz  *"2H      :   vendor/symfony/css-selector/Parser/Shortcut/HashParser.phpv  YWv        A   vendor/symfony/css-selector/Parser/Shortcut/EmptyStringParser.php  YW  ~      2   vendor/symfony/css-selector/Parser/TokenStream.php_  YW_  oٶ      -   vendor/symfony/css-selector/Parser/Parser.php  YW  L3      -   vendor/symfony/css-selector/Parser/Reader.phpQ  YWQ  #      B   vendor/symfony/css-selector/Parser/Tokenizer/TokenizerPatterns.php  YW        B   vendor/symfony/css-selector/Parser/Tokenizer/TokenizerEscaping.php  YW  ZL      :   vendor/symfony/css-selector/Parser/Tokenizer/Tokenizer.php  YW   `8      <   vendor/symfony/css-selector/Exception/ExceptionInterface.phpm   YWm   Y~      B   vendor/symfony/css-selector/Exception/ExpressionErrorException.php   YW   6;      8   vendor/symfony/css-selector/Exception/ParseException.php   YW   /X      >   vendor/symfony/css-selector/Exception/SyntaxErrorException.phpo  YWo  l%      @   vendor/symfony/css-selector/Exception/InternalErrorException.php   YW   &O      4   vendor/symfony/css-selector/CssSelectorConverter.php  YW  G      .   vendor/symfony/polyfill-mbstring/bootstrap.phpo  YWo  c5      -   vendor/symfony/polyfill-mbstring/Mbstring.php50  YW50  A      -   vendor/symfony/console/Style/SymfonyStyle.phpE  YWE   72      /   vendor/symfony/console/Style/StyleInterface.php  YW  j      ,   vendor/symfony/console/Style/OutputStyle.php_  YW_        2   vendor/symfony/console/Helper/InputAwareHelper.phpc  YWc  |      +   vendor/symfony/console/Helper/TableCell.php:  YW:  7      .   vendor/symfony/console/Helper/DialogHelper.php  YW  hXö      -   vendor/symfony/console/Helper/TableHelper.php  YW  pm      +   vendor/symfony/console/Helper/HelperSet.php  YW  f!6>      '   vendor/symfony/console/Helper/Table.php{)  YW{)  |j      -   vendor/symfony/console/Helper/ProgressBar.php;'  YW;'  ڂ˶      ,   vendor/symfony/console/Helper/TableStyle.php
  YW
  P޵      0   vendor/symfony/console/Helper/ProgressHelper.phpp  YWp  ,lζ      7   vendor/symfony/console/Helper/SymfonyQuestionHelper.phpl  YWl  Co      1   vendor/symfony/console/Helper/HelperInterface.php   YW         0   vendor/symfony/console/Helper/QuestionHelper.phpV  YWV  ލ      6   vendor/symfony/console/Helper/DebugFormatterHelper.phpx  YWx  Nؼ      2   vendor/symfony/console/Helper/DescriptorHelper.phpz  YWz  f      3   vendor/symfony/console/Helper/ProgressIndicator.php  YW  eء      (   vendor/symfony/console/Helper/Helper.php  YW  z      1   vendor/symfony/console/Helper/FormatterHelper.phpc  YWc  N      /   vendor/symfony/console/Helper/ProcessHelper.php	  YW	  @ぶ      0   vendor/symfony/console/Helper/TableSeparator.php   YW   <f;      9   vendor/symfony/console/Descriptor/DescriptorInterface.php   YW   Q      3   vendor/symfony/console/Descriptor/XmlDescriptor.php  YW  P$      4   vendor/symfony/console/Descriptor/TextDescriptor.php  YW  cŶ      0   vendor/symfony/console/Descriptor/Descriptor.php  YW  ;~Ķ      8   vendor/symfony/console/Descriptor/MarkdownDescriptor.php  YW  ?wn      <   vendor/symfony/console/Descriptor/ApplicationDescription.php  YW  7      4   vendor/symfony/console/Descriptor/JsonDescriptor.php  YW  l      &   vendor/symfony/console/Application.phpU  YWU  33&      2   vendor/symfony/console/Question/ChoiceQuestion.php	  YW	  ¶      ,   vendor/symfony/console/Question/Question.php#
  YW#
  e       8   vendor/symfony/console/Question/ConfirmationQuestion.php  YW  Q@      (   vendor/symfony/console/ConsoleEvents.php   YW   H          vendor/symfony/console/Shell.php  YW  f      /   vendor/symfony/console/Tester/CommandTester.php  YW  Eٚ|      3   vendor/symfony/console/Tester/ApplicationTester.php  YW  d      9   vendor/symfony/console/Formatter/OutputFormatterStyle.phpL  YWL  8<      B   vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php  YW  Rڭ      >   vendor/symfony/console/Formatter/OutputFormatterStyleStack.phpL  YWL  .=b      4   vendor/symfony/console/Formatter/OutputFormatter.php  YW  q@      =   vendor/symfony/console/Formatter/OutputFormatterInterface.php  YW  :      (   vendor/symfony/console/Output/Output.php	  YW	  x:l      /   vendor/symfony/console/Output/ConsoleOutput.php  YW  
S\      ,   vendor/symfony/console/Output/NullOutput.php  YW  Zl      8   vendor/symfony/console/Output/ConsoleOutputInterface.php   YW   rN       1   vendor/symfony/console/Output/OutputInterface.php  YW  >      0   vendor/symfony/console/Output/BufferedOutput.php_  YW_  Bͷ      .   vendor/symfony/console/Output/StreamOutput.php7  YW7  iC      5   vendor/symfony/console/Exception/RuntimeException.php   YW   ,6      7   vendor/symfony/console/Exception/ExceptionInterface.phpf   YWf   AB      3   vendor/symfony/console/Exception/LogicException.php   YW   O\e      =   vendor/symfony/console/Exception/CommandNotFoundException.php  YW   L      ;   vendor/symfony/console/Exception/InvalidOptionException.php   YW   H      =   vendor/symfony/console/Exception/InvalidArgumentException.php   YW   ̽Z      -   vendor/symfony/console/Event/ConsoleEvent.php  YW  x\      6   vendor/symfony/console/Event/ConsoleTerminateEvent.phpz  YWz  ,L      4   vendor/symfony/console/Event/ConsoleCommandEvent.php  YW  Zk2      6   vendor/symfony/console/Event/ConsoleExceptionEvent.php  YW  2      .   vendor/symfony/console/Command/ListCommand.phpZ  YWZ  ɣ      .   vendor/symfony/console/Command/HelpCommand.php  YW  .ؙu      *   vendor/symfony/console/Command/Command.phpO   YWO   (      /   vendor/symfony/console/Logger/ConsoleLogger.php<	  YW<	  :l      /   vendor/symfony/console/Input/InputInterface.php   YW   9Ƕ      4   vendor/symfony/console/Input/InputAwareInterface.php   YW   jT      .   vendor/symfony/console/Input/InputArgument.php  YW        ,   vendor/symfony/console/Input/StringInput.php  YW   ڤ      &   vendor/symfony/console/Input/Input.php  YW        +   vendor/symfony/console/Input/ArrayInput.phpp
  YWp
        0   vendor/symfony/console/Input/InputDefinition.php  YW        *   vendor/symfony/console/Input/ArgvInput.php  YW  ~      ,   vendor/symfony/console/Input/InputOption.php  YW        /   vendor/symfony/finder/Expression/Expression.php  YW  o      )   vendor/symfony/finder/Expression/Glob.phpi  YWi  @      3   vendor/symfony/finder/Expression/ValueInterface.php  YW  ~b      *   vendor/symfony/finder/Expression/Regex.php  YW  p8 \         vendor/symfony/finder/Glob.phpK  YWK  jn      ,   vendor/symfony/finder/Adapter/PhpAdapter.php  YW  :?      5   vendor/symfony/finder/Adapter/AbstractFindAdapter.php  YW  aoȶ      0   vendor/symfony/finder/Adapter/BsdFindAdapter.php2  YW2  Q/C      2   vendor/symfony/finder/Adapter/AdapterInterface.php  YW  &      1   vendor/symfony/finder/Adapter/AbstractAdapter.php\  YW\  Ɠɀ      0   vendor/symfony/finder/Adapter/GnuFindAdapter.php  YW            vendor/symfony/finder/Finder.php-  YW-  f      %   vendor/symfony/finder/Shell/Shell.phpp  YWp  }g      '   vendor/symfony/finder/Shell/Command.phpS  YWS  cC      ;   vendor/symfony/finder/Iterator/DepthRangeFilterIterator.php  YW  0      5   vendor/symfony/finder/Iterator/PathFilterIterator.php  YW  Ƕ      7   vendor/symfony/finder/Iterator/CustomFilterIterator.php]  YW]  t౵      4   vendor/symfony/finder/Iterator/FilePathsIterator.php   YW   fQCe      =   vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php  YW  bܶ      =   vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php/  YW/  Y      3   vendor/symfony/finder/Iterator/SortableIterator.php  YW  `>c      :   vendor/symfony/finder/Iterator/SizeRangeFilterIterator.phpg  YWg  !ԗ      <   vendor/symfony/finder/Iterator/FilecontentFilterIterator.php5  YW5        :   vendor/symfony/finder/Iterator/DateRangeFilterIterator.phpz  YWz  }      9   vendor/symfony/finder/Iterator/FilenameFilterIterator.phpr  YWr  tu      A   vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php  YW  96      9   vendor/symfony/finder/Iterator/FileTypeFilterIterator.php\  YW\  p'      1   vendor/symfony/finder/Iterator/FilterIterator.php  YW  E      6   vendor/symfony/finder/Exception/ExceptionInterface.php   YW   Gz-      9   vendor/symfony/finder/Exception/AccessDeniedException.php   YW   s      @   vendor/symfony/finder/Exception/ShellCommandFailureException.php  YW  vȶ      ;   vendor/symfony/finder/Exception/AdapterFailureException.php  YW        A   vendor/symfony/finder/Exception/OperationNotPermitedException.php)  YW)  cj=      %   vendor/symfony/finder/SplFileInfo.php  YW  O      5   vendor/symfony/finder/Comparator/NumberComparator.php~  YW~   x      3   vendor/symfony/finder/Comparator/DateComparator.php%  YW%  LEǶ      /   vendor/symfony/finder/Comparator/Comparator.php  YW  wT      )   vendor/symfony/event-dispatcher/Event.php	  YW	  c      M   vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php
  YW
        B   vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php  YW  _      9   vendor/symfony/event-dispatcher/Debug/WrappedListener.php  YW  Wn      K   vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php3  YW3  [
      0   vendor/symfony/event-dispatcher/GenericEvent.php  YW  :      3   vendor/symfony/event-dispatcher/EventDispatcher.phpf  YWf  C񨡶      <   vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php{  YW{  %&      <   vendor/symfony/event-dispatcher/EventSubscriberInterface.php   YW   o;y      A   vendor/symfony/event-dispatcher/ContainerAwareEventDispatcher.php  YW        <   vendor/symfony/event-dispatcher/EventDispatcherInterface.phpJ  YWJ  5}f      #   vendor/symfony/dom-crawler/Link.php	  YW	  /&      #   vendor/symfony/dom-crawler/Form.php  YW  >Ԟ      3   vendor/symfony/dom-crawler/Field/InputFormField.php  YW  SF\      6   vendor/symfony/dom-crawler/Field/TextareaFormField.php  YW  4^      4   vendor/symfony/dom-crawler/Field/ChoiceFormField.php  YW  h      2   vendor/symfony/dom-crawler/Field/FileFormField.php  YW  S      .   vendor/symfony/dom-crawler/Field/FormField.php  YW  {Y      &   vendor/symfony/dom-crawler/Crawler.phpC  YWC        0   vendor/symfony/dom-crawler/FormFieldRegistry.php
  YW
  $7      !   vendor/symfony/yaml/Unescaper.phpB  YWB  eC         vendor/symfony/yaml/Escaper.phpR  YWR            vendor/symfony/yaml/Parser.php@  YW@  *o         vendor/symfony/yaml/Inline.php#*  YW#*  ~jD         vendor/symfony/yaml/Dumper.phpo  YWo  g      2   vendor/symfony/yaml/Exception/RuntimeException.php   YW   $      4   vendor/symfony/yaml/Exception/ExceptionInterface.phpc   YWc   ۶      0   vendor/symfony/yaml/Exception/ParseException.php  YW  d<	      /   vendor/symfony/yaml/Exception/DumpException.phps   YWs   ƶ         vendor/symfony/yaml/Yaml.php  YW  џ      (   vendor/symfony/browser-kit/CookieJar.phpq  YWq  |      '   vendor/symfony/browser-kit/Response.php3  YW3  vY~      %   vendor/symfony/browser-kit/Client.php!  YW!  "/      %   vendor/symfony/browser-kit/Cookie.phpP  YWP  [      &   vendor/symfony/browser-kit/Request.php  YW  /o      &   vendor/symfony/browser-kit/History.php  YW  J         vendor/composer/ClassLoader.phpB  YWB        !   vendor/composer/autoload_real.php  YW  4u      '   vendor/composer/autoload_namespaces.php(  YW(  Q2      %   vendor/composer/autoload_classmap.php  YW  ϫ      !   vendor/composer/autoload_psr4.php  YW  Bq-X      "   vendor/composer/autoload_files.php  YW  /\      6   vendor/codeception/specify/src/Codeception/Specify.php`  YW`        D   vendor/codeception/specify/src/Codeception/Specify/ConfigBuilder.phpW  YWW        =   vendor/codeception/specify/src/Codeception/Specify/Config.php  YW  mj6{      '   vendor/codeception/specify/RoboFile.php@  YW@  a2      ^   vendor/phpdocumentor/reflection-docblock/src/phpDocumentor/Reflection/DocBlock/Description.php	  YW	  B޶      Z   vendor/phpdocumentor/reflection-docblock/src/phpDocumentor/Reflection/DocBlock/Context.php  YW  ƶ      `   vendor/phpdocumentor/reflection-docblock/src/phpDocumentor/Reflection/DocBlock/Tag/SourceTag.phpy  YWy  5֣      `   vendor/phpdocumentor/reflection-docblock/src/phpDocumentor/Reflection/DocBlock/Tag/ThrowsTag.phpp   YWp   a      `   vendor/phpdocumentor/reflection-docblock/src/phpDocumentor/Reflection/DocBlock/Tag/CoversTag.phpm   YWm   \      ^   vendor/phpdocumentor/reflection-docblock/src/phpDocumentor/Reflection/DocBlock/Tag/LinkTag.php  YW        `   vendor/phpdocumentor/reflection-docblock/src/phpDocumentor/Reflection/DocBlock/Tag/ReturnTag.php*  YW*  1ܶ      _   vendor/phpdocumentor/reflection-docblock/src/phpDocumentor/Reflection/DocBlock/Tag/ParamTag.php@  YW@        ]   vendor/phpdocumentor/reflection-docblock/src/phpDocumentor/Reflection/DocBlock/Tag/SeeTag.php  YW  sZ      ]   vendor/phpdocumentor/reflection-docblock/src/phpDocumentor/Reflection/DocBlock/Tag/VarTag.phpl   YWl   3l      _   vendor/phpdocumentor/reflection-docblock/src/phpDocumentor/Reflection/DocBlock/Tag/SinceTag.php   YW   -pi      ^   vendor/phpdocumentor/reflection-docblock/src/phpDocumentor/Reflection/DocBlock/Tag/UsesTag.phpk   YWk   ՛      f   vendor/phpdocumentor/reflection-docblock/src/phpDocumentor/Reflection/DocBlock/Tag/PropertyReadTag.phpx   YWx   F      `   vendor/phpdocumentor/reflection-docblock/src/phpDocumentor/Reflection/DocBlock/Tag/AuthorTag.phpX  YWX  :*      b   vendor/phpdocumentor/reflection-docblock/src/phpDocumentor/Reflection/DocBlock/Tag/PropertyTag.phpq   YWq   )ɶ      a   vendor/phpdocumentor/reflection-docblock/src/phpDocumentor/Reflection/DocBlock/Tag/ExampleTag.php  YW  ʚ      `   vendor/phpdocumentor/reflection-docblock/src/phpDocumentor/Reflection/DocBlock/Tag/MethodTag.php?	  YW?	  %]r      a   vendor/phpdocumentor/reflection-docblock/src/phpDocumentor/Reflection/DocBlock/Tag/VersionTag.php  YW   *϶      d   vendor/phpdocumentor/reflection-docblock/src/phpDocumentor/Reflection/DocBlock/Tag/DeprecatedTag.php   YW   {       g   vendor/phpdocumentor/reflection-docblock/src/phpDocumentor/Reflection/DocBlock/Tag/PropertyWriteTag.phpy   YWy   2m      V   vendor/phpdocumentor/reflection-docblock/src/phpDocumentor/Reflection/DocBlock/Tag.php  YW  7+      b   vendor/phpdocumentor/reflection-docblock/src/phpDocumentor/Reflection/DocBlock/Type/Collection.phpG	  YWG	  P[	      ]   vendor/phpdocumentor/reflection-docblock/src/phpDocumentor/Reflection/DocBlock/Serializer.php  YW  _      [   vendor/phpdocumentor/reflection-docblock/src/phpDocumentor/Reflection/DocBlock/Location.php  YW  ]9      R   vendor/phpdocumentor/reflection-docblock/src/phpDocumentor/Reflection/DocBlock.phpU  YWU  [V      7   vendor/flow/jsonpath/src/Flow/JSONPath/AccessHelper.php  YW  f      8   vendor/flow/jsonpath/src/Flow/JSONPath/JSONPathLexer.php  YW  CE[      <   vendor/flow/jsonpath/src/Flow/JSONPath/JSONPathException.php_   YW_   ms>l      3   vendor/flow/jsonpath/src/Flow/JSONPath/JSONPath.php  YW  Y`      @   vendor/flow/jsonpath/src/Flow/JSONPath/Filters/IndexesFilter.php  YW  Ծ      D   vendor/flow/jsonpath/src/Flow/JSONPath/Filters/QueryResultFilter.php  YW  
ٶ      >   vendor/flow/jsonpath/src/Flow/JSONPath/Filters/SliceFilter.php  YW        C   vendor/flow/jsonpath/src/Flow/JSONPath/Filters/QueryMatchFilter.php&  YW&  ca      A   vendor/flow/jsonpath/src/Flow/JSONPath/Filters/AbstractFilter.php#  YW#  >      B   vendor/flow/jsonpath/src/Flow/JSONPath/Filters/RecursiveFilter.php,  YW,  `]      >   vendor/flow/jsonpath/src/Flow/JSONPath/Filters/IndexFilter.php  YW  j      8   vendor/flow/jsonpath/src/Flow/JSONPath/JSONPathToken.php  YW  r         autoload.phpA  YWA  7z         codecept  YW  ?      <?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\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\TestCase\Interfaces;

/**
 * TestCases that do not follow OOP
 */
interface Plain
{
}
<?php
namespace Codeception\TestCase\Interfaces;

interface ScenarioDriven
{
    public function getFeature();

    /**
     * @return \Codeception\Scenario
     */
    public function getScenario();

    public function getScenarioText($format = 'text');

    public function preload();

    public function getRawBody();
}
<?php
namespace Codeception\TestCase\Interfaces;

interface Descriptive
{
    public function getFileName();

    public function getSignature();

    public function getName($withDataSet = true);

    public function toString();
}<?php
namespace Codeception\TestCase\Interfaces;

interface Reported
{
    /**
     * @return array
     */
    public function getReportFields();
}
<?php
namespace Codeception\TestCase\Interfaces;

use Codeception\Lib\Di;
use Codeception\Lib\ModuleContainer;
use Symfony\Component\EventDispatcher\EventDispatcher;

interface Configurable
{
    public function configActor($actor);

    public function configDispatcher(EventDispatcher $dispatcher);

    public function configModules(ModuleContainer $moduleContainer);

    public function configDi(Di $di);

    public function config($name, $value);

    public function configEnv($env);

    public function initConfig();
} <?php
namespace Codeception\TestCase\Shared;

use Codeception\Event\StepEvent;
use Codeception\Event\TestEvent;
use Codeception\Events;
use Codeception\Exception\ConditionalAssertionFailed;
use Codeception\Exception\ConfigurationException;
use Codeception\Lib\Di;
use Codeception\Lib\ModuleContainer;
use Codeception\Lib\Parser;
use Codeception\Scenario;
use Codeception\Step;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventDispatcher;

trait Actor
{
    /**
     * @var EventDispatcher
     */
    protected $dispatcher;

    /**
     * @var ModuleContainer
     */
    protected $moduleContainer;

    /**
     * @var Di
     */
    protected $di;

    protected $actor;
    protected $testName;
    protected $testFile;
    protected $env;

    /**
     * @var Scenario
     */
    protected $scenario;

    /**
     * @var \Codeception\Lib\Parser
     */
    protected $parser;

    /**
     * @var \PHPUnit_Framework_TestResult
     */
    protected $testResult;


    public function initConfig()
    {
        $this->scenario = new Scenario(
            $this, [
            'env'     => $this->env,
            'modules' => $this->moduleContainer->all(),
            'name'    => $this->testName
        ]
        );
        $this->parser = new Parser($this->scenario);
        return $this;
    }

    protected function fire($event, Event $eventType)
    {
        foreach ($this->scenario->getGroups() as $group) {
            $this->dispatcher->dispatch($event . '.' . $group, $eventType);
        }
        $this->dispatcher->dispatch($event, $eventType);
    }

    /**
     * @return \Codeception\Scenario
     */
    public function getScenario()
    {
        return $this->scenario;
    }

    /**
     * @return \PHPUnit_Framework_TestResult
     */
    abstract public function getTestResultObject();

    public function prepareActorForTest()
    {
        $this->testResult = $this->getTestResultObject();
    }

    public function runStep(Step $step)
    {
        $result = null;
        $this->fire(Events::STEP_BEFORE, new StepEvent($this, $step));
        try {
            $result = $step->run($this->moduleContainer);
        } catch (ConditionalAssertionFailed $f) {
            $this->testResult->addFailure(clone($this), $f, $this->testResult->time());
        } catch (\Exception $e) {
            $this->fire(Events::STEP_AFTER, new StepEvent($this, $step));
            throw $e;
        }
        $this->fire(Events::STEP_AFTER, new StepEvent($this, $step));
        return $result;
    }

    public function getFeature()
    {
        return $this->scenario->getFeature();
    }

    public function configActor($actor)
    {
        $this->actor = $actor;
        return $this;
    }

    public function configDispatcher(EventDispatcher $dispatcher)
    {
        $this->dispatcher = $dispatcher;
        return $this;
    }

    public function configFile($file)
    {
        if (!is_file($file)) {
            throw new ConfigurationException("Test file $file not found");
        }

        $this->testFile = $file;
        return $this;
    }

    public function configName($name)
    {
        $this->testName = $name;
        return $this;
    }

    public function configEnv($env)
    {
        $this->env = $env;
        return $this;
    }

    public function configModules(ModuleContainer $moduleContainer)
    {
        $this->moduleContainer = $moduleContainer;
        return $this;
    }

    public function configDi(Di $di)
    {
        $this->di = clone($di);
        return $this;
    }

    public function config($property, $value)
    {
        $this->$property = $value;
        return $this;
    }

}
<?php
namespace Codeception\TestCase\Shared;

use Codeception\Exception\ConfigurationException;
use Symfony\Component\EventDispatcher\EventDispatcher;


trait Configuration
{
    /**
     * @var EventDispatcher
     */
    protected $dispatcher;

    protected $actor;
    protected $name;
    protected $testFile;
    protected $env;

    public function configActor($actor)
    {
        $this->actor = $actor;
        return $this;
    }

    public function configDispatcher(EventDispatcher $dispatcher)
    {
        $this->dispatcher = $dispatcher;
        return $this;
    }

    public function configFile($file)
    {
        if (!is_file($file)) {
            throw new ConfigurationException("Test file $file not found");
        }

        $this->testFile = $file;
        return $this;
    }

    public function configName($name)
    {
        $this->name = $name;
        return $this;
    }

    public function config($property, $value)
    {
        $this->$property = $value;
        return $this;
    }
}
<?php
namespace Codeception\TestCase\Shared;

use Codeception\TestCase\Cest;

trait Dependencies
{
    protected $dependencies;
    protected $dependencyInput = [];

    protected function handleDependencies()
    {
        if (empty($this->dependencies)) {
            return true;
        }

        $passed = $this->getTestResultObject()->passed();
        $passedKeys = array_map(
            function ($testname) {
                if ($this instanceof Cest) {
                    $testname = str_replace(
                        'Codeception\TestCase\Cest::',
                        get_class($this->getTestClass()) . '::',
                        $testname
                    );
                }
                return preg_replace('~with data set (.*?)~', '', $testname);
            }, array_keys($passed)
        );

        $dependencyInput = [];

        foreach ($this->dependencies as $dependency) {
            if (strpos($dependency, '::') === false) {
                $dependency = str_replace($this->getName(false), $dependency, $this->getSignature());
            }

            if (!in_array($dependency, $passedKeys)) {
                $this->getTestResultObject()->addError(
                    $this,
                    new \PHPUnit_Framework_SkippedTestError(sprintf("This test depends on '$dependency' to pass.")),
                    0
                );
                return false;
            }

            if (isset($passed[$dependency])) {
                $dependencyInput[] = $passed[$dependency]['result'];
            } else {
                $dependencyInput[] = null;
            }
        }
        $this->setDependencyInput($dependencyInput);

        return true;
    }

    public function setDependencies(array $dependencies)
    {
        $this->dependencies = $dependencies;
    }
}
<?php
namespace Codeception\TestCase\Shared;

trait ScenarioPrint
{
    public function getScenarioText($format = 'text')
    {
        $code = $this->getRawBody();
        $this->parser->parseFeature($code);
        $this->parser->parseSteps($code);
        if ($format == 'html') {
            return $this->scenario->getHtml();
        }
        return $this->scenario->getText();
    }

    abstract function getRawBody();
}
<?php
namespace Codeception\TestCase;

use Codeception\Configuration;
use Codeception\TestCase as CodeceptionTestCase;
use Codeception\Util\Annotation;
use Codeception\TestCase\Interfaces\Descriptive;
use Codeception\TestCase\Interfaces\Reported;
use Codeception\TestCase\Interfaces\Configurable;
use Codeception\TestCase\Shared\Actor;
use Codeception\TestCase\Shared\Dependencies;

class Test extends CodeceptionTestCase implements
    Descriptive,
    Configurable,
    Reported
{
    use Actor;
    use Dependencies;

    protected function setUp()
    {
        $actor = $this->actor;
        if ($actor) {
            $property = lcfirst(Configuration::config()['actor']);
            $this->$property = new $actor($this->scenario);

            // BC compatibility hook
            $actorProperty = lcfirst($actor);
            $this->$actorProperty = $this->$property;
        }
        $this->_before();
        $this->prepareActorForTest();
    }

    /**
     * Executed before each test
     */
    protected function _before()
    {
    }

    protected function tearDown()
    {
        $this->_after();
    }

    /**
     * Executed after each test
     */
    protected function _after()
    {
    }

    public function getFeature()
    {
        $text = $this->getName();
        $text = preg_replace('/([A-Z]+)([A-Z][a-z])/', '\\1 \\2', $text);
        $text = preg_replace('/([a-z\d])([A-Z])/', '\\1 \\2', $text);
        return strtolower($text);
    }

    public function getSignature()
    {
        return get_class($this) . '::' . $this->getName(false);
    }

    public function getEnvironment()
    {
        return Annotation::forMethod($this, $this->getName(false))->fetchAll('env');
    }

    public function getFileName()
    {
        return (new \ReflectionClass($this))->getFileName();
    }

    /**
     * @param $module
     *
     * @return \Codeception\Module
     * @throws \Codeception\Exception\TestRuntimeException
     */
    public function getModule($module)
    {
        return $this->moduleContainer->getModule($module);
    }

    /**
     * @return array
     */
    public function getReportFields()
    {
        return [
            'name'    => $this->getName(),
            'class'   => get_class($this),
            'file'    => $this->getFileName(),
            'feature' => $this->getFeature()
        ];
    }
}
<?php
namespace Codeception\TestCase;

use Codeception\Event\TestEvent;
use Codeception\Events;
use Codeception\Exception\TestParseException;
use Codeception\TestCase as CodeceptionTestCase;
use Codeception\TestCase\Interfaces\ScenarioDriven;
use Codeception\TestCase\Interfaces\Descriptive;
use Codeception\TestCase\Interfaces\Reported;
use Codeception\TestCase\Interfaces\Plain;
use Codeception\TestCase\Interfaces\Configurable;
use Codeception\TestCase\Shared\Actor;
use Codeception\TestCase\Shared\ScenarioPrint;

class Cept extends CodeceptionTestCase implements
    ScenarioDriven,
    Descriptive,
    Reported,
    Plain,
    Configurable
{
    use Actor;
    use ScenarioPrint;

    public function __construct(array $data = [], $dataName = '')
    {
        parent::__construct('testCodecept', $data, $dataName);
    }

    public function getSignature()
    {
        return ltrim(substr($this->testName, 0, -4), '\\/'); // cut ".php" in end; cut "/" in start
    }

    public function getName($withDataSet = true)
    {
        return $this->getFeature() ? $this->getFeature() : $this->testName;
    }

    public function getFileName()
    {
        return $this->testFile;
    }

    public function toString()
    {
        return $this->getFeature() . " (" . $this->getSignature() . ")";
    }

    public function preload()
    {
        $this->parser->prepareToRun($this->getRawBody());
        $this->fire(Events::TEST_PARSED, new TestEvent($this));
    }

    public function getRawBody()
    {
        return file_get_contents($this->testFile);
    }

    public function testCodecept()
    {
        $scenario = $this->scenario;

        $this->prepareActorForTest();

        /** @noinspection PhpIncludeInspection */
        try {
            require $this->testFile;
        } catch (\ParseError $e) {
            throw new TestParseException($this->testFile);
        }
    }

    public function getEnvironment()
    {
        return $this->scenario->getEnv();
    }

    public function getReportFields()
    {
        return [
            'name' => basename($this->getFileName(), 'Cept.php'),
            'file' => $this->getFileName(),
            'feature' => $this->getFeature()
        ];
    }
}
<?php
namespace Codeception\TestCase;

use Codeception\TestCase as CodeceptionTestCase;
use Codeception\Event\TestEvent;
use Codeception\Events;
use Codeception\Util\Annotation;
use Codeception\TestCase\Interfaces\ScenarioDriven;
use Codeception\TestCase\Interfaces\Descriptive;
use Codeception\TestCase\Interfaces\Reported;
use Codeception\TestCase\Interfaces\Configurable;
use Codeception\TestCase\Shared\Actor;
use Codeception\TestCase\Shared\Dependencies;
use Codeception\TestCase\Shared\ScenarioPrint;

class Cest extends CodeceptionTestCase implements
    ScenarioDriven,
    Descriptive,
    Reported,
    Configurable
{
    use Actor;
    use Dependencies;
    use ScenarioPrint;

    protected $testClassInstance = null;
    protected $testMethod = null;

    public function __construct(array $data = [], $dataName = '')
    {
        parent::__construct('testCodecept', $data, $dataName);
    }

    public function getName($withDataSet = true)
    {
        return $this->testMethod;
    }

    public function preload()
    {
        $this->scenario->setFeature($this->getSpecFromMethod());
        $code = $this->getRawBody();
        $this->parser->parseFeature($code);
        $this->parser->attachMetadata(Annotation::forMethod($this->testClassInstance, $this->testMethod)->raw());
        $this->di->injectDependencies($this->testClassInstance);
        $this->fire(Events::TEST_PARSED, new TestEvent($this));
    }

    public function getRawBody()
    {
        $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 testCodecept()
    {
        $I = $this->makeIObject();

        $this->prepareActorForTest();
        try {
            $this->executeHook($I, 'before');
            $this->executeBeforeMethods($this->testMethod, $I);
            $this->executeTestMethod($I);
            $this->executeAfterMethods($this->testMethod, $I);
            $this->executeHook($I, 'after');
        } catch (\Exception $e) {
            $this->executeHook($I, 'failed');
            // fails and errors are now handled by Codeception\PHPUnit\Listener
            throw $e;
        }
    }

    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 makeIObject()
    {
        $className = '\\' . $this->actor;
        $I = new $className($this->scenario);
        $spec = $this->getSpecFromMethod();

        if ($spec) {
            $I->wantTo($spec);
        }
        return $I;
    }

    protected function invoke($methodName, array $context)
    {
        foreach ($context as $class) {
            $this->di->set($class);
        }
        $this->di->injectDependencies($this->testClassInstance, $methodName, $context);
    }

    protected function executeTestMethod($I)
    {
        $testMethodSignature = [$this->testClassInstance, $this->testMethod];
        if (! is_callable($testMethodSignature)) {
            throw new \Exception("Method {$this->testMethod} can't be found in tested class");
        }
        $this->invoke($this->testMethod, [$I, $this->scenario]);
    }

    public function getTestClass()
    {
        return $this->testClassInstance;
    }

    public function getTestMethod()
    {
        return $this->testMethod;
    }

    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 configActor($actor)
    {
        foreach (['actor', 'guy'] as $annotation) {
            $definedActor = Annotation::forMethod($this->testClassInstance, $this->testMethod)->fetch($annotation);
            if ($definedActor === null) {
                $definedActor = Annotation::forClass($this->testClassInstance)->fetch($annotation);
            }
            if ($definedActor !== null) {
                $this->actor = $definedActor;
                return $this;
            }
        }

        $this->actor = $actor;
        return $this;
    }

    public function getSignature()
    {
        return get_class($this->getTestClass()) . "::" . $this->getTestMethod();
    }

    public function getFileName()
    {
        return $this->testFile;
    }

    public function toString()
    {
        return $this->getFeature() . " (" . $this->getSignature() . ")";
    }

    public function getEnvironment()
    {
        return Annotation::forMethod($this->testClassInstance, $this->testMethod)->fetchAll('env');
    }

    /**
     * @return array
     */
    public function getReportFields()
    {
        return [
            'file'    => $this->getFileName(),
            'name'    => $this->getTestMethod(),
            'class'   => get_class($this->getTestClass()),
            'feature' => $this->getFeature()
        ];
    }

    protected function executeHook($I, $hook)
    {
        if (is_callable([$this->testClassInstance, "_$hook"])) {
            $this->invoke("_$hook", [$I, $this->scenario]);
        }
    }

}
<?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;

abstract class Extension implements EventSubscriberInterface
{
    public static $events = [];

    protected $config = [];
    protected $options;
    protected $output;
    protected $globalConfig;
    private $modules = [];

    function __construct($config, $options)
    {
        $this->config = array_merge($this->config, $config);
        $this->options = $options;
        $this->output = new Output($options);
        $this->_initialize();
    }


    static function getSubscribedEvents()
    {
        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 preperations 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\PHPUnit;

use Codeception\TestCase\Interfaces\ScenarioDriven;

class ResultPrinter extends \PHPUnit_Util_TestDox_ResultPrinter
{

    /**
     * A test ended.
     *
     * @param  \PHPUnit_Framework_Test $test
     * @param  float $time
     */
    public function endTest(\PHPUnit_Framework_Test $test, $time)
    {
        $steps = [];
        $success = ($this->testStatus == \PHPUnit_Runner_BaseTestRunner::STATUS_PASSED);
        if ($success) {
            $this->successful++;
        }

        if ($test instanceof ScenarioDriven) {
            $steps = $test->getScenario()->getSteps();
        }

        $this->onTest($test->toString(), $success, $steps, $time);
    }

}
<?php
namespace Codeception\PHPUnit\Log;

use Codeception\Configuration;
use Codeception\TestCase\Interfaces\Reported;

class JUnit extends \PHPUnit_Util_Log_JUnit
{
    protected $strictAttributes = ['file', 'name', 'class'];

    public function startTest(\PHPUnit_Framework_Test $test)
    {
        if (!$test instanceof Reported) {
            return parent::startTest($test);
        }

        $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);
        }
    }
}
<?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)
    {
        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)
    {
        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))->style('debug');
        }
        $output .= "\ncontains text '" . $this->string . "'";

        throw new \PHPUnit_Framework_ExpectationFailedException(
            $output,
            $comparisonFailure
        );
    }

    protected function failureDescription($nodes)
    {
        $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("<%s> %s");
            $output .= $message->with($node->getTagName(), $node->getText())->style('info')->prepend("\n+ ");
        }
        return $output;

    }


}
<?php
namespace Codeception\PHPUnit\Constraint;

use SebastianBergmann\Comparator\ComparisonFailure;

class CrawlerNot extends Crawler
{
    protected function matches($nodes)
    {
        return !parent::matches($nodes);
    }

    protected function fail($nodes, $selector, ComparisonFailure $comparisonFailure = null)
    {
        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 .= str_replace($this->string, "<bold>{$this->string}</bold>", $this->nodesList($nodes, $this->string));
        $output .= "\ncontaining '{$this->string}'";

        throw new \PHPUnit_Framework_ExpectationFailedException(
            $output,
            $comparisonFailure
        );
    }

    public function toString()
    {
        if ($this->string) {
            return 'that contains text "' . $this->string . '"';
        }
    }
}
<?php
namespace Codeception\PHPUnit\Constraint;

use SebastianBergmann\Comparator\ComparisonFailure;
use Codeception\Util\Locator;

class WebDriverNot extends WebDriver
{
    protected function matches($nodes)
    {
        return !parent::matches($nodes);
    }

    protected function fail($nodes, $selector, ComparisonFailure $comparisonFailure = null)
    {
        $selectorString = Locator::humanReadableString($selector);
        if (!$this->string) {
            throw new \PHPUnit_Framework_ExpectationFailedException("Element $selectorString was found", $comparisonFailure);
        }

        $output = "There was $selectorString element";
        $output .= $this->uriMessage("on page");
        $output .= str_replace($this->string, "<bold>{$this->string}</bold>", $this->nodesList($nodes, $this->string));
        $output .= "\ncontaining '{$this->string}'";

        throw new \PHPUnit_Framework_ExpectationFailedException(
            $output,
            $comparisonFailure
        );
    }

    public function toString()
    {
        if ($this->string) {
            return 'that contains text "' . $this->string . '"';
        }
    }
}
<?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)
    {
        /** @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)
    {
        /** @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())->style('debug')->getMessage();
        }
        $output .= "\ncontains text '{$this->string}'";

        throw new \PHPUnit_Framework_ExpectationFailedException(
            $output,
            $comparisonFailure
        );
    }

    protected function failureDescription($other)
    {
        $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+ <info>" . $node->C14N() . "</info>";
        }
        return $output;
    }
}
<?php
namespace Codeception\PHPUnit\Constraint;

use Codeception\Lib\Console\Message;

class Page extends \PHPUnit_Framework_Constraint_StringContains
{
    protected $uri;

    public function __construct($string, $uri = '')
    {
        $this->string = (string)$string;
        $this->uri = $uri;
        $this->ignoreCase = true;
    }

    protected function failureDescription($other)
    {
        $page = substr($other, 0, 300);
        $message = new Message($page);
        $message->style('info');
        $message->prepend("\n--> ");
        $message->prepend($this->uriMessage());
        if (strlen($other) > 300) {
            $debugMessage = new Message("[Content too long to display. See complete response in '" . codecept_output_dir() . "' directory]");
            $debugMessage->style('debug')->prepend("\n");
            $message->append($debugMessage);
        }
        $message->append("\n--> ");
        return $message->getMessage() . $this->toString();
    }

    protected function uriMessage($onPage = "")
    {
        if (!$this->uri) {
            return "";
        }
        $message = new Message($this->uri);
        $message->style('bold');
        $message->prepend(" $onPage ");
        return $message;
    }
}
<?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($buffer);

    public function printResult(\PHPUnit_Framework_TestResult $result);
}
<?php
namespace Codeception\PHPUnit;

use Codeception\Event\FailEvent;
use Codeception\Event\SuiteEvent;
use Codeception\Event\TestEvent;
use Codeception\Events;
use Codeception\TestCase as CodeceptionTestCase;
use Exception;
use PHPUnit_Framework_Test;
use Symfony\Component\EventDispatcher\EventDispatcher;

class Listener implements \PHPUnit_Framework_TestListener
{
    /**
     * @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 Exception $e
     * @param float $time
     * @since  Method available since Release 4.0.0
     */
    public function addRiskyTest(PHPUnit_Framework_Test $test, Exception $e, $time)
    {
    }

    public function addFailure(\PHPUnit_Framework_Test $test, \PHPUnit_Framework_AssertionFailedError $e, $time)
    {
        $this->unsuccessfulTests[] = spl_object_hash($test);
        $this->fire(Events::TEST_FAIL, new FailEvent($test, $e));
    }

    public function addError(\PHPUnit_Framework_Test $test, \Exception $e, $time)
    {
        $this->unsuccessfulTests[] = spl_object_hash($test);
        $this->fire(Events::TEST_ERROR, new FailEvent($test, $e));
    }

    public function addIncompleteTest(\PHPUnit_Framework_Test $test, \Exception $e, $time)
    {
        if (in_array(spl_object_hash($test), $this->skippedTests)) {
            return;
        }
        $this->unsuccessfulTests[] = spl_object_hash($test);
        $this->fire(Events::TEST_INCOMPLETE, new FailEvent($test, $e));
        $this->skippedTests[] = spl_object_hash($test);
    }

    public function addSkippedTest(\PHPUnit_Framework_Test $test, \Exception $e, $time)
    {
        if (in_array(spl_object_hash($test), $this->skippedTests)) {
            return;
        }
        $this->unsuccessfulTests[] = spl_object_hash($test);
        $this->fire(Events::TEST_SKIPPED, new FailEvent($test, $e));
        $this->skippedTests[] = spl_object_hash($test);
    }

    public function startTestSuite(\PHPUnit_Framework_TestSuite $suite)
    {
        $this->dispatcher->dispatch('suite.start', new SuiteEvent($suite));
    }

    public function endTestSuite(\PHPUnit_Framework_TestSuite $suite)
    {
        $this->dispatcher->dispatch('suite.end', new SuiteEvent($suite));
    }

    public function startTest(\PHPUnit_Framework_Test $test)
    {
        $this->dispatcher->dispatch(Events::TEST_START, new TestEvent($test));
        if (!$test instanceof CodeceptionTestCase) {
            return;
        }
        try {
            $test->getScenario()->stopIfBlocked();
            $this->startedTests[] = spl_object_hash($test);
            $this->fire(Events::TEST_BEFORE, new TestEvent($test));
        } catch (\PHPUnit_Framework_IncompleteTestError $e) {
            $this->addIncompleteTest($test, $e, 0);
        } catch (\PHPUnit_Framework_SkippedTestError $e) {
            $this->addSkippedTest($test, $e, 0);
        }
    }

    public function endTest(\PHPUnit_Framework_Test $test, $time)
    {
        $hash = spl_object_hash($test);
        if (!in_array($hash, $this->unsuccessfulTests)) {
            $this->fire(Events::TEST_SUCCESS, new TestEvent($test));
        }
        if (in_array($hash, $this->startedTests) and ($test instanceof CodeceptionTestCase)) {
            $this->fire(Events::TEST_AFTER, new TestEvent($test));
        }

        $this->dispatcher->dispatch(Events::TEST_END, new TestEvent($test, $time));
    }

    protected function fire($event, TestEvent $eventType)
    {
        $test = $eventType->getTest();
        if ($test instanceof CodeceptionTestCase) {
            foreach ($test->getScenario()->getGroups() as $group) {
                $this->dispatcher->dispatch($event . '.' . $group, $eventType);
            }
        }
        $this->dispatcher->dispatch($event, $eventType);
    }
}
<?php
namespace Codeception\PHPUnit\ResultPrinter;

use Codeception\PHPUnit\ConsolePrinter;
use Codeception\PHPUnit\ResultPrinter;

class Report extends ResultPrinter implements ConsolePrinter
{

    /**
     * Handler for 'on test' event.
     *
     * @param  string $name
     * @param  boolean $success
     * @param  array $steps
     */
    protected function onTest($name, $success = true, array $steps = [], $time = 0)
    {
        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()
    {
        $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)
    {

    }
}
<h1>{name} <small>{status} ({time}s)</small></h1>

      <tr>
       <td class="stepName {error}">{action}</td>
      </tr>

<tr>
 <td>
     <h3>{suite} Tests</h3>
 </td>
</tr><tr >
    <td class="error">
        {fail}
    </td>
</tr>   <tr class="scenarioRow {scenarioStatus}">
    <td>
     <p class="{scenarioStatus}" onclick="showHide('{id}', this)">[+] {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}

     </table>
    </td>
   </tr>


<html>
 <head>
	<title>Test results</title>
	<meta charset='utf-8'>
	<link href='http://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 {
		 border: 1px solid #ccc;
		 font-family: 'Varela Round', arial;
		 -webkit-border-radius: 5px;
		 -moz-border-radius: 5px;
		 border-radius: 5px;
		 background: rgb(255,255,255); /* Old browsers */
		 background: -moz-linear-gradient(top, rgba(255,255,255,1) 0%, rgba(229,229,229,1) 100%); /* FF3.6+ */
		 background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,1)), color-stop(100%,rgba(229,229,229,1))); /* Chrome,Safari4+ */
		 background: -webkit-linear-gradient(top, rgba(255,255,255,1) 0%,rgba(229,229,229,1) 100%); /* Chrome10+,Safari5.1+ */
		 background: -o-linear-gradient(top, rgba(255,255,255,1) 0%,rgba(229,229,229,1) 100%); /* Opera11.10+ */
		 background: -ms-linear-gradient(top, rgba(255,255,255,1) 0%,rgba(229,229,229,1) 100%); /* IE10+ */
		 filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#e5e5e5',GradientType=0 ); /* IE6-9 */
		 background: linear-gradient(top, rgba(255,255,255,1) 0%,rgba(229,229,229,1) 100%); /* W3C */

		 }

         @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.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;
		 }
		 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);

    if (linkObj.innerHTML.indexOf('+')>0) {
      linkObj.innerHTML = linkObj.innerHTML.replace('+','-');
      subObj.style.display='block';
      subObj.style.width = '100%';
    } else {
      linkObj.innerHTML = linkObj.innerHTML.replace('-','+');
      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 class="stepName" ><p onclick="showHide('{id}', this)">[+] {metaStep}</p>

     </td>
</tr>
<tr>
 <td class="nostyle">
  <table border="0" width="100%" class="substeps scenarioStepsTable" id="stepContainer{id}">
    {steps}
  </table>
 </td>
</tr>
<?php
namespace Codeception\PHPUnit\ResultPrinter;

use Codeception\PHPUnit\ResultPrinter as CodeceptionResultPrinter;
use Codeception\Step;
use Codeception\Step\Meta;

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',

            dirname(__FILE__),
            DIRECTORY_SEPARATOR,
            DIRECTORY_SEPARATOR
        );
    }

    /**
     * Handler for 'start class' event.
     *
     * @param  string $name
     */
    protected function startClass($name)
    {
    }

    /**
     * Handler for 'on test' event.
     *
     * @param  string $name
     * @param  boolean $success
     * @param  array $steps
     */
    protected function onTest($name, $success = true, array $steps = [], $time = 0)
    {
        $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 = '';
        $metaStep = null;

        $subStepsBuffer = '';

        foreach ($steps as $step) {
            /** @var $step Step  **/
            if ($step->getMetaStep()) {
                $subStepsBuffer .= $this->renderStep($step);
                $metaStep = $step->getMetaStep();
                continue;
            }
            if ($step->getMetaStep() != $metaStep) {
                $stepsBuffer .= $this->renderSubsteps($metaStep, $subStepsBuffer);
                $subStepsBuffer = '';
            }
            $metaStep = $step->getMetaStep();
            $stepsBuffer .= $this->renderStep($step);
        }

        if ($subStepsBuffer and $metaStep) {
            $stepsBuffer .= $this->renderSubsteps($metaStep, $subStepsBuffer);
        }

        $scenarioTemplate = new \Text_Template(
            $this->templatePath . 'scenario.html'
        );

        $failure = '';
        if (isset($this->failures[$name])) {
            $failTemplate = new \Text_Template(
                $this->templatePath . 'fail.html'
            );
            $failTemplate->setVar(['fail' => nl2br($this->failures[$name])]);
            $failure = $failTemplate->render();
        }

        $scenarioTemplate->setVar(
            [
                'id'             => ++$this->id,
                'name'           => ucfirst($name),
                'scenarioStatus' => $scenarioStatus,
                'steps'          => $stepsBuffer,
                'failure'        => $failure,
                'time'           => round($time, 2)
            ]
        );

        $this->scenarios .= $scenarioTemplate->render();
    }

    public function startTestSuite(\PHPUnit_Framework_TestSuite $suite)
    {
        $suiteTemplate = new \Text_Template(
            $this->templatePath . 'suite.html'
        );

        $suiteTemplate->setVar(['suite' => ucfirst($suite->getName())]);

        $this->scenarios .= $suiteTemplate->render();

    }

    /**
     * Handler for 'end run' event.
     *
     */
    protected function endRun()
    {

        $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, \Exception $e, $time)
    {
        $this->failures[$test->toString()] = $e->getMessage();
        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, $time)
    {
        $this->failures[$test->toString()] = $e->getMessage();
        parent::addFailure($test, $e, $time);
    }


    /**
     * @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, 'steps' => $substepsBuffer, 'id' => uniqid()]);
        return $metaTemplate->render();
    }
}
<?php
namespace Codeception\PHPUnit\ResultPrinter;

use Codeception\Event\FailEvent;
use Codeception\Events;
use Codeception\TestCase\Test;
use Symfony\Component\EventDispatcher\EventDispatcher;

class UI extends \PHPUnit_TextUI_ResultPrinter
{
    /**
     * @var EventDispatcher
     */
    protected $dispatcher;

    public function __construct(EventDispatcher $dispatcher, $options, $out = null)
    {
        parent::__construct($out, $options['verbosity'] > 1, $options['colors'] ? 'always' : 'never');
        $this->dispatcher = $dispatcher;
    }

    protected function printDefect(\PHPUnit_Framework_TestFailure $defect, $count)
    {
        $this->write("\n---------\n");
        $this->dispatcher->dispatch(
            Events::TEST_FAIL_PRINT,
            new FailEvent($defect->failedTest(), $defect->thrownException(), $count)
        );
    }

    /**
     * @param \PHPUnit_Framework_TestFailure $defect
     */
    protected function printDefectTrace(\PHPUnit_Framework_TestFailure $defect)
    {
        $this->write($defect->getExceptionAsString());
        $this->writeNewLine();

        $stackTrace = \PHPUnit_Util_Filter::getFilteredStacktrace($defect->thrownException(), false);

        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)
    {
        if ($test instanceof Test) {
            parent::startTest($test);
        }
    }

    public function endTest(\PHPUnit_Framework_Test $test, $time)
    {
        if ($test instanceof \PHPUnit_Framework_TestCase) {
            $this->numAssertions += $test->getNumAssertions();
        }

        $this->lastTestFailed = false;
    }

    public function addError(\PHPUnit_Framework_Test $test, \Exception $e, $time)
    {
        $this->lastTestFailed = true;
    }

    public function addFailure(\PHPUnit_Framework_Test $test, \PHPUnit_Framework_AssertionFailedError $e, $time)
    {
        $this->lastTestFailed = true;
    }

    public function addIncompleteTest(\PHPUnit_Framework_Test $test, \Exception $e, $time)
    {
        $this->lastTestFailed = true;
    }

    public function addSkippedTest(\PHPUnit_Framework_Test $test, \Exception $e, $time)
    {
        $this->lastTestFailed = true;
    }
}
<?php
namespace Codeception\PHPUnit;

use Codeception\Configuration;
use Codeception\Exception\ConfigurationException;

class Runner extends \PHPUnit_TextUI_TestRunner
{
    public static $persistentListeners = [];

    protected $defaultListeners = [
        '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 doEnhancedRun(
        \PHPUnit_Framework_Test $suite,
        \PHPUnit_Framework_TestResult $result,
        array $arguments = []
    ) {
        unset($GLOBALS['app']); // hook for not to serialize globals

        $this->handleConfiguration($arguments);
        $result->convertErrorsToExceptions(false);

        if (empty(self::$persistentListeners)) {
            $this->applyReporters($result, $arguments);
        }

        $arguments['listeners'][] = $this->printer;

        // clean up listeners between suites
        foreach ($arguments['listeners'] as $listener) {
            $result->addListener($listener);
        }

        $filterFactory = new \PHPUnit_Runner_Filter_Factory();
        if ($arguments['groups']) {
            $filterFactory->addFilter(
                new \ReflectionClass('PHPUnit_Runner_Filter_Group_Include'),
                $arguments['groups']
            );
        }

        if ($arguments['excludeGroups']) {
            $filterFactory->addFilter(
                new \ReflectionClass('PHPUnit_Runner_Filter_Group_Exclude'),
                $arguments['excludeGroups']
            );
        }

        if ($arguments['filter']) {
            $filterFactory->addFilter(
                new \ReflectionClass('PHPUnit_Runner_Filter_Test'),
                $arguments['filter']
            );
        }

        $suite->injectFilter($filterFactory);

        $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']), false]);
        }
        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

class PHPUnit_Util_Filter
{
    protected static $filteredClassesPattern = [
        'Symfony\Component\Console',
        'Codeception\Command\\',
        'Codeception\TestCase\\',
    ];

    public static function getFilteredStackTrace(Exception $e, $asString = true, $filter = true)
    {
        $stackTrace = $asString ? '' : [];

        $trace = $e->getPrevious() ? $e->getPrevious()->getTrace() : $e->getTrace();
        if ($e instanceof \PHPUnit_Framework_ExceptionWrapper) {
            $trace = $e->getSerializableTrace();
        }

        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;
        }

        if (strpos($step['file'], 'src' . DIRECTORY_SEPARATOR . 'Codeception' . DIRECTORY_SEPARATOR . 'Module') !== false) {
            return false; // don`t filter modules
        }

        if (strpos($step['file'], 'src' . DIRECTORY_SEPARATOR . 'Codeception' . DIRECTORY_SEPARATOR) !== false) {
            return true;
        }

        return false;
    }
}
<?php

namespace Codeception;

use Codeception\Event\Suite;
use Codeception\Event\SuiteEvent;
use Codeception\Exception\ConfigurationException;
use Codeception\Exception\TestRuntimeException;
use Codeception\Lib\Di;
use Codeception\Lib\GroupManager;
use Codeception\Lib\ModuleContainer;
use Codeception\Lib\Notification;
use Codeception\Lib\TestLoader;
use Codeception\TestCase\Interfaces\ScenarioDriven;
use Symfony\Component\EventDispatcher\EventDispatcher;

class SuiteManager
{
    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 TestLoader
     */
    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->dispatcher->dispatch(Events::MODULE_INIT, new SuiteEvent($this->suite, null, $this->settings));
        foreach ($this->moduleContainer->all() as $module) {
            $module->_initialize();
        }
        if (!file_exists(Configuration::supportDir() . $this->settings['class_name'] . '.php')) {
            throw new Exception\ConfigurationException($this->settings['class_name'] . " class doesn't exist in suite folder.\nRun the 'build' command to generate it");
        }
        $this->dispatcher->dispatch(Events::SUITE_INIT, new 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 TestLoader($this->settings['path']);
        $path
            ? $testLoader->loadTest($path)
            : $testLoader->loadTests();

        $tests = $testLoader->getTests();
        if ($this->settings['shuffle']) {
            shuffle($tests);
        }
        foreach ($tests as $test) {
            $this->addToSuite($test);
        }
    }

    protected function addToSuite($test)
    {
        $this->configureTest($test);

        if ($test instanceof \PHPUnit_Framework_TestSuite_DataProvider) {
            foreach ($test->tests() as $t) {
                $this->configureTest($t);
            }
        }

        if ($test instanceof ScenarioDriven) {
            $test->preload();
        }
        if ($test instanceof TestCase) {
            $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 TestCase) {
            $test->getScenario()->group($groups);
        }
    }

    protected function createSuite($name)
    {
        $suite = new Lib\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);
        $suite->setModules($this->moduleContainer->all());
        return $suite;
    }


    public function run(PHPUnit\Runner $runner, \PHPUnit_Framework_TestResult $result, $options)
    {
        $this->dispatcher->dispatch(Events::SUITE_BEFORE, new Event\SuiteEvent($this->suite, $result, $this->settings));
        $runner->doEnhancedRun($this->suite, $result, $options);
        $this->dispatcher->dispatch(Events::SUITE_AFTER, new Event\SuiteEvent($this->suite, $result, $this->settings));
    }


    /**
     * @return \Codeception\Lib\Suite
     */
    public function getSuite()
    {
        return $this->suite;
    }

    /**
     * @return ModuleContainer
     */
    public function getModuleContainer()
    {
        return $this->moduleContainer;
    }

    protected function getActor()
    {
        return $this->settings['namespace']
            ? rtrim($this->settings['namespace'], '\\') . '\\' . $this->settings['class_name']
            : $this->settings['class_name'];
    }

    protected function checkEnvironmentExists(\Codeception\TestCase $test)
    {
        $envs = $test->getEnvironment();
        if (empty($envs)) {
            return;
        }
        if (!isset($this->settings['env'])) {
            Notification::warning("Environments are not configured", TestCase::getTestFullName($test));
            return;
        }
        $availableEnvironments = array_keys($this->settings['env']);
        $listedEnvironments = explode(',', implode(',', $test->getEnvironment()));
        foreach ($listedEnvironments as $env) {
            if (!in_array($env, $availableEnvironments)) {
                Notification::warning("Environment $env was not configured but used in test", TestCase::getTestFullName($test));
            }
        }
    }

    protected function isExecutedInCurrentEnvironment(\Codeception\TestCase $test)
    {
        $envs = $test->getEnvironment();
        if (empty($envs)) {
            return true;
        }
        $currentEnvironments = 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 TestCase\Interfaces\Configurable) {
            return;
        }
        $t->configDispatcher($this->dispatcher);
        $t->configActor($this->getActor());
        $t->configEnv($this->env);
        $t->configModules($this->moduleContainer);
        $t->configDi($this->di);
        $t->initConfig();
        $this->di->injectDependencies($t);
    }


}

<?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;

    static $events = [
        Events::SUITE_INIT => 'updateActor'
    ];

    public function updateActor(SuiteEvent $e)
    {
        $settings = $e->getSettings();
        $modules = $e->getSuite()->getModules();

        $actorActionsFile = Configuration::supportDir() . '_generated' . DIRECTORY_SEPARATOR
            . $settings['class_name'] . 'Actions.php';

        if (!file_exists($actorActionsFile)) {
            codecept_debug("Generating {$settings['class_name']}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['class_name']}...");
                    @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\Shared;

trait StaticEvents
{
    static function getSubscribedEvents()
    {
        return static::$events;
    }
}<?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\Lib\Console\Message;
use Codeception\Lib\Console\Output;
use Codeception\Lib\Notification;
use Codeception\Lib\Suite;
use Codeception\Step;
use Codeception\Step\Comment;
use Codeception\TestCase;
use Codeception\TestCase\Interfaces\ScenarioDriven;
use Codeception\Util\Debug;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class Console implements EventSubscriberInterface
{
    use Shared\StaticEvents;

    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_FAIL_PRINT => 'printFail',
        Events::RESULT_PRINT_AFTER => 'afterResult'
    ];

    /**
     * @var Step
     */
    protected $metaStep;

    /**
     * @var Message
     */
    protected $message = null;
    protected $steps = true;
    protected $debug = false;
    protected $color = true;
    protected $silent = false;
    protected $lastTestFailed = false;
    protected $printedTest = null;
    protected $rawStackTrace = false;
    protected $traceLength = 5;
    protected $columns = [40, 5];
    protected $output;
    protected $options;
    protected $fails = [];
    protected $reports = [];
    protected $namespace = '';

    public function __construct($options)
    {
        $this->options = $options;
        $this->debug = $options['debug'] || $options['verbosity'] >= OutputInterface::VERBOSITY_VERY_VERBOSE;
        $this->steps = $this->debug || $options['steps'];
        $this->rawStackTrace = ($options['verbosity'] === OutputInterface::VERBOSITY_DEBUG);
        $this->output = new Output($options);
        if ($this->debug) {
            Debug::setOutput($this->output);
        }

        foreach (['html', '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->buildResultsTable($e);

        $this->message("%s Tests (%d) ")
            ->with(ucfirst($e->getSuite()->getName()), count($e->getSuite()->tests()))
            ->style('bold')
            ->width(array_sum($this->columns), '-')
            ->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(array_sum($this->columns), '-')->writeln(OutputInterface::VERBOSITY_VERBOSE);
    }

    // triggered for all tests
    public function startTest(TestEvent $e)
    {
        $this->fails = [];
        $test = $e->getTest();
        $this->printedTest = $test;
        $this->message = null;
        $this->output->waitForDebugOutput = true;

        $this->writeCurrentTest($test);
        if ($this->steps && $this->isDetailed($test)) {
            $this->output->writeln("\nScenario:");
        }
    }

    public function afterStep(StepEvent $e)
    {
        $step = $e->getStep();
        if ($step->hasFailed() and $step instanceof Step\ConditionalAssertion) {
            $this->fails[] = $step;
        }
    }

    public function afterResult()
    {
        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->writeFinishedTest($e->getTest());
        $this->message('Ok')->writeln();
    }

    public function endTest(TestEvent $e)
    {
        if (!$this->output->waitForDebugOutput) {
            $this->message()->width($this->columns[0] + $this->columns[1], '^')->writeln();
        }
        $this->metaStep = null;
        $this->printedTest = null;
    }

    public function testFail(FailEvent $e)
    {
        if ($this->isDetailed($e->getTest())) {
            $this->message('FAIL')->center(' ')->style('error')->append("\n")->writeln();
            return;
        }
        $this->writeFinishedTest($e->getTest());
        $this->message('Fail')->style('error')->writeln();
    }

    public function testError(FailEvent $e)
    {
        if ($this->isDetailed($e->getTest())) {
            $this->message('ERROR')->center(' ')->style('error')->append("\n")->writeln();
            return;
        }
        $this->writeFinishedTest($e->getTest());
        $this->message('Error')->style('error')->writeln();
    }

    public function testSkipped(FailEvent $e)
    {
        if (!$this->printedTest) {
            return;
        }
        $this->writeFinishedTest($e->getTest());
        $message = $this->message('Skipped');
        if ($this->isDetailed($e->getTest())) {
            $message->apply('strtoupper')->append("\n");
        }
        $message->writeln();
    }

    public function testIncomplete(FailEvent $e)
    {
        $this->writeFinishedTest($e->getTest());
        $message = $this->message('Incomplete');
        if ($this->isDetailed($e->getTest())) {
            $message->apply('strtoupper')->append("\n");
        }
        $message->writeln();
    }

    protected function isDetailed($test)
    {
        if ($test instanceof ScenarioDriven && $this->steps) {
            return !$test->getScenario()->isBlocked();
        };
        return false;
    }

    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->output->writeln("* $metaStep");
        }
        $this->metaStep = $metaStep;
        $msg = $this->message($e->getStep()->__toString());
        $this->metaStep ? $msg->prepend('  ')->style('comment') : $msg->prepend('* ');
        $msg->writeln();
    }

    public function afterSuite(SuiteEvent $e)
    {
        $this->message()->width(array_sum($this->columns), '-')->writeln();
        $deprecationMessages = Notification::all();
        foreach ($deprecationMessages as $message) {
            $this->output->notification($message);
        }
    }

    public function printFail(FailEvent $e)
    {
        $failedTest = $e->getTest();
        $fail = $e->getFail();
        
        $this->output->write($e->getCount() . ") ");

        if ($failedTest instanceof ScenarioDriven) {
            $this->printScenarioFail($failedTest, $fail);
            return;
        }
        $this->getTestMessage($failedTest)->write();

        $this->printException($fail);
        $this->printExceptionTrace($fail);
    }

    protected function printException($e, $cause = null)
    {
        $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("%s")->with($e->getMessage());
        $isFailure = $e instanceof \PHPUnit_Framework_AssertionFailedError
            || $class == 'PHPUnit_Framework_ExpectationFailedException'
            || $class == 'PHPUnit_Framework_AssertionFailedError';
        if (!$isFailure) {
            $message->prepend("[$class] ")->block("error");
        }
        if ($isFailure && $cause) {
            $message->prepend("<error> Step </error> $cause\n<error> Fail </error> ");
        }
        if ($e instanceof \PHPUnit_Framework_ExpectationFailedException) {
            if ($e->getComparisonFailure()) {
                $message->append(trim($e->getComparisonFailure()->getDiff()));
            }
        }
        $message->writeln();

    }

    protected function printScenarioFail(ScenarioDriven $failedTest, $fail)
    {
        $feature = $failedTest->getFeature();
        $failToString = \PHPUnit_Framework_TestFailure::exceptionToString($fail);

        $failMessage = $this->message($failedTest->getSignature())
            ->style('bold')
            ->append(' (')
            ->append(codecept_relative_path($failedTest->getFileName()))
            ->append(')');

        if ($fail instanceof \PHPUnit_Framework_SkippedTest
            || $fail instanceof \PHPUnit_Framework_IncompleteTest
        ) {
            $this->printSkippedTest($feature, $failedTest->getFileName(), $failToString);
            return;
        }
        if ($feature) {
            $failMessage->prepend("Failed to $feature in ");
        }
        $failMessage->writeln();

        $failedStep = "";
        foreach ($failedTest->getScenario()->getSteps() as $step) {
            if ($step->hasFailed()) {
                $failedStep = (string)$step;
                break;
            }
        }
        $this->printException($fail,$failedStep);

        $this->printScenarioTrace($failedTest, $failToString);
        if ($this->output->getVerbosity() == OutputInterface::VERBOSITY_DEBUG) {
            $this->printExceptionTrace($fail);
            return;
        }
        if (!$fail instanceof \PHPUnit_Framework_AssertionFailedError) {
            $this->printExceptionTrace($fail);
            return;
        }
    }

    public function printExceptionTrace(\Exception $e)
    {
        static $limit = 10;

        if ($e instanceof \PHPUnit_Framework_SkippedTestError) {
            return;
        }
        if ($e instanceof \PHPUnit_Framework_IncompleteTestError) {
            return;
        }

        if ($this->rawStackTrace) {
            $this->message(\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);
        }
    }

    protected function message($text = '')
    {
        return new Message($text, $this->output);
    }

    /**
     * Sample Message: create user in CreateUserCept.php is not ready for release
     *
     * @param $feature
     * @param $fileName
     * @param $failToString
     */
    public function printSkippedTest($feature, $fileName, $failToString)
    {
        $message = $this->message();
        if ($feature) {
            $message->append($feature)->style('focus')->append(' in ');
        }
        $message->append($fileName);
        if ($failToString) {
            $message->append(": $failToString");
        }
        $message->write(OutputInterface::VERBOSITY_VERBOSE);
    }

    /**
     * @param $failedTest
     * @param $fail
     */
    public function printScenarioTrace(ScenarioDriven $failedTest)
    {
        $trace = array_reverse($failedTest->getScenario()->getSteps());
        $length = $i = count($trace);

        if (!$length) return;

        $this->message("\nScenario Steps:\n")->style('comment')->writeln();

        foreach ($trace as $step) {

            $message = $this
                ->message($i)
                ->prepend(' ')
                ->width(strlen($length))
                ->append(". " . $step->getPhpCode());

            if ($step->hasFailed()) {
                $message->append('')->style('bold');
            }

            $line = $step->getLine();
            if ($line and (!$step instanceof Comment)) {
                $message->append(" at <info>$line</info>");
            }

            $i--;
            $message->writeln();
            if (($length - $i - 1) >= $this->traceLength) {
                break;
            }
        }
        $this->output->writeln("");
    }

    /**
     * @param SuiteEvent $e
     */
    protected function buildResultsTable(SuiteEvent $e)
    {
        $this->columns = [40, 5];
        foreach ($e->getSuite()->tests() as $test) {
            if ($test instanceof TestCase) {
                $this->columns[0] = max(
                    $this->columns[0],
                    20 + strlen($test->getFeature()) + strlen($test->getFileName())
                );
                continue;
            }
            if ($test instanceof \PHPUnit_Framework_TestSuite_DataProvider) {
                $test = $test->testAt(0);
                $output_length = $test instanceof TestCase
                    ? strlen($test->getFeature()) + strlen($test->getFileName())
                    : strlen($test->toString());

                $this->columns[0] = max(
                    $this->columns[0],
                    15 + $output_length
                );
                continue;
            }
            $this->columns[0] = max($this->columns[0], 10 + strlen($test->toString()));
        }
        $cols = $this->columns[0];
        if ((strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')
            && (php_sapi_name() == "cli")
            && (getenv('TERM'))
            && (getenv('TERM') != 'unknown')
        ) {
            $cols = intval(`command -v tput >> /dev/null 2>&1 && tput cols`);
        }
        if ($cols < $this->columns[0]) {
            $this->columns[0] = $cols-$this->columns[1];
        }
    }

    /**
     * @param \PHPUnit_Framework_TestCase $test
     * @param bool $inProgress
     * @return Message
     */
    protected function getTestMessage(\PHPUnit_Framework_TestCase $test, $inProgress = false)
    {
        if (!$test instanceof TestCase) {
            $this->message = $this
                ->message('%s::%s')
                ->with($this->cutNamespace(get_class($test)), $test->getName(true))
                ->apply(function ($str) { return str_replace('with data set', "|", $str); } )
                ->cut($inProgress ? $this->columns[0] + $this->columns[1] - 16 : $this->columns[0] - 2)
                ->style('focus')
                ->prepend($inProgress ? 'Running ' : '');
            return $this->message;
        }
        $filename = $this->cutNamespace($test->getSignature());
        $feature = $test->getFeature();

        if ($feature) {
            $this->message = $this
                ->message($inProgress ? $feature : (mb_strtoupper(mb_substr($feature, 0, 1, 'utf-8'), 'utf-8') . mb_substr($feature, 1, null, 'utf-8')))
                ->apply(function ($str) { return str_replace('with data set', "|", $str); } )
                ->cut($inProgress ? $this->columns[0] + $this->columns[1] - 18 - strlen($filename) : $this->columns[0] - 5 - strlen($filename))
                ->style('focus')
                ->prepend($inProgress ? 'Trying to ' : '')
                ->append(" ($filename)");
            return $this->message;
        }
        
        $this->message = $this
            ->message("<focus>%s</focus> ")
            ->prepend($inProgress ? 'Running ' : '')
            ->with($filename);
        return $this->message;
    }

    private function cutNamespace($className)
    {
        if (!$this->namespace) {
            return $className;
        }
        if (strpos($className, $this->namespace) === 0) {
            return substr($className, strlen($this->namespace)+1);
        }
        return $className;
    }

    protected function writeCurrentTest(\PHPUnit_Framework_TestCase $test)
    {
        if (!$this->isDetailed($test) && $this->output->isInteractive()) {
            $this
                ->getTestMessage($test, true)
                ->append('... ')
                ->write();
            return;
        }
        $this->getTestMessage($test)->write();
    }

    protected function writeFinishedTest(\PHPUnit_Framework_TestCase $test)
    {
        if ($this->isDetailed($test)) {
            return;
        }

        $conditionalFails = "";
        $numFails  = count($this->fails);
        if ($numFails == 1) {
            $conditionalFails = "[F]";
        } elseif ($numFails) {
            $conditionalFails = "{$numFails}x[F]";
        }
        $conditionalLen = strlen($conditionalFails)+1;
        $conditionalFails = "<error>$conditionalFails</error> ";

        if ($this->output->isInteractive()) {
            $msg = $this->getTestMessage($test)->prepend("\x0D");
            $msg->width($this->columns[0] - $conditionalLen)->append($conditionalFails)->write();
            return;
        }
        if ($this->message) {
            $this->message('')
                ->width($this->columns[0] - $this->message->apply('strip_tags')->getLength() - $conditionalLen)
                ->append($conditionalFails)
                ->write();
        }
    }
}
<?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\Lib\Suite;
use Codeception\TestCase;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class Module implements EventSubscriberInterface
{
    use Shared\StaticEvents;

    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 TestCase) {
            return;
        }

        foreach ($this->modules as $module) {
            $module->_cleanup();
            $module->_resetConfig();
            $module->_before($event->getTest());
        }
    }

    public function after(TestEvent $e)
    {
        if (!$e->getTest() instanceof TestCase) {
            return;
        }
        foreach ($this->modules as $module) {
            $module->_after($e->getTest());
        }
    }

    public function failed(FailEvent $e)
    {
        if (!$e->getTest() instanceof TestCase) {
            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\Events;
use Codeception\Exception\ConfigurationException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class Bootstrap implements EventSubscriberInterface
{
    use Shared\StaticEvents;

    static $events = [
        Events::SUITE_INIT => 'loadBootstrap',
    ];

    public function loadBootstrap(SuiteEvent $e)
    {
        $settings = $e->getSettings();

        if (!isset($settings['bootstrap'])) {
            return;
        }

        if (!$settings['bootstrap']) {
            return;
        }

        $bootstrap = $settings['path'] . $settings['bootstrap'];
        if (!is_file($bootstrap)) {
            throw new ConfigurationException("Bootstrap file $bootstrap can't be loaded");
        }

        require_once $bootstrap;
    }
}
<?php
namespace Codeception\Subscriber;

use Codeception\Event\SuiteEvent;
use Codeception\Events;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class FailFast implements EventSubscriberInterface
{
    use Shared\StaticEvents;

    static $events = [
        Events::SUITE_BEFORE => 'stopOnFail',
    ];

    public function stopOnFail(SuiteEvent $e)
    {
        $e->getResult()->stopOnError(true);
        $e->getResult()->stopOnFailure(true);
    }
}
<?php 
namespace Codeception\Subscriber;

use Codeception\Event\SuiteEvent;
use Codeception\Events;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

declare(ticks = 1);

class GracefulTermination implements EventSubscriberInterface
{
    const SIGNAL_FUNC = 'pcntl_signal';

    /**
     * @var SuiteEvent
     */
    protected $suiteEvent;

    public function handleSuite(SuiteEvent $event)
    {
        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\SuiteEvent;
use Codeception\Events;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class ErrorHandler implements EventSubscriberInterface
{
    use Shared\StaticEvents;

    static $events = [
        Events::SUITE_BEFORE => 'handle'
    ];

    /**
     * @var bool $stopped to keep shutdownHandler from possible looping.
     */
    private static $stopped = false;

    /**
     * @var int stores bitmask for errors
     */
    private $errorLevel = 'E_ALL & ~E_STRICT & ~E_DEPRECATED';

    public function handle(SuiteEvent $e)
    {
        $settings = $e->getSettings();
        if ($settings['error_level']) {
            $this->errorLevel = $settings['error_level'];
        }
        error_reporting(eval("return {$this->errorLevel};"));
        set_error_handler([$this, 'errorHandler']);
        register_shutdown_function([$this, 'shutdownHandler']);
    }

    public function errorHandler($errno, $errstr, $errfile, $errline)
    {
        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;
        }

        throw new \PHPUnit_Framework_Exception($errstr, $errno);
    }

    public function shutdownHandler()
    {
        if (self::$stopped) {
            return;
        }
        self::$stopped = true;
        $error = error_get_last();
        if (!is_array($error)) {
            return;
        }
        if (error_reporting() === 0) {
            return;
        }
        // not fatal
        if ($error['type'] > 1) {
            return;
        }

        echo "\n\n\nFATAL ERROR. TESTS NOT FINISHED.\n";
        echo sprintf("%s \nin %s:%d\n", $error['message'], $error['file'], $error['line']);
    }
}
<?php
namespace Codeception\Subscriber;

use Codeception\Event\SuiteEvent;
use Codeception\Events;
use Codeception\TestCase;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class BeforeAfterTest implements EventSubscriberInterface
{
    use Shared\StaticEvents;

    static $events = [
        Events::SUITE_BEFORE => 'beforeClass',
        Events::SUITE_AFTER  => 'afterClass',
    ];

    protected $hooks = [];
    protected $startedTests = [];
    protected $unsuccessfulTests = [];

    public function beforeClass(SuiteEvent $e)
    {
        foreach ($e->getSuite()->tests() as $test) {
            /** @var $test \PHPUnit_Framework_Test  * */
            if ($test instanceof \PHPUnit_Framework_TestSuite_DataProvider) {
                $potentialTestClass = strstr($test->getName(), '::', true);
                $this->hooks[$potentialTestClass] = \PHPUnit_Util_Test::getHookMethods($potentialTestClass);
            }

            $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;

abstract class TestCase extends \PHPUnit_Framework_TestCase implements \PHPUnit_Framework_SelfDescribing
{
    protected $backupGlobalsBlacklist = ['app'];
    public $_hasStarted = false;

    /**
     * scenario stores steps and test settings: groups, environment, etc
     */

    /**
     * @return Scenario
     */
    abstract public function getScenario();
    abstract public function getEnvironment();

    public static function getTestSignature(\PHPUnit_Framework_TestCase $testCase)
    {
        if ($testCase instanceof TestCase\Interfaces\Descriptive) {
            return $testCase->getSignature();
        }
        return get_class($testCase) . '::' . $testCase->getName(false);
    }

    public static function getTestFileName(\PHPUnit_Framework_TestCase $testCase)
    {
        if ($testCase instanceof TestCase\Interfaces\Descriptive) {
            return $testCase->getFileName();
        }
        return (new \ReflectionClass($testCase))->getFileName();
    }

    public static function getTestFullName(\PHPUnit_Framework_TestCase $testCase)
    {
        if ($testCase instanceof TestCase\Interfaces\Plain) {
            return self::getTestFileName($testCase);
        }
        return self::getTestFileName($testCase) . ':' . $testCase->getName(false);
    }
}
<?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 [];
    }

    public function _beforeSuite($settings = [])
    {
        /**
         * reset internal domains before suite, because each suite can have a different configuration
         */
        $this->internalDomains = null;
    }

}
<?php
namespace Codeception\Lib\Interfaces;

interface MultiSession
{
    public function _initializeSession();

    public function _loadSession($session);

    public function _backupSession();

    public function _closeSession($session);

    public function _getName();
}
<?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 specifing 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 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 ActiveRecord
{
    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 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);
}
<?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 saved snapshot.
     *
     * @param $name
     * @see saveSessionSnapshot
     * @return mixed
     */
    public function loadSessionSnapshot($name);
}
<?php 
namespace Codeception\Lib\Interfaces;

interface DoctrineProvider
{
    public function _getEntityManager();
}
<?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 $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
     * ```
     * 
     * 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      $text
     * @param null $selector
     */
    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
     * ```
     * 
     * 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      $text
     * @param null $selector
     */
    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, optionally 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 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',
     *             'password' => '123456',
     *             'agree' => true
     *         ]
     *     ],
     *     'submitButton'
     * );
     * ```
     * Note that "2" will be the submitted value for the "plan" field, as it is
     * the selected option.
     * 
     * 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      $text
     * @param null $url
     */
    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 $text
     * @param null $url
     */
    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 $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 $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 $uri
     */
    public function seeCurrentUrlMatches($uri);

    /**
     * Checks that the current URI doesn't contain the given string.
     *
     * ``` php
     * <?php
     * $I->dontSeeInCurrentUrl('/users/');
     * ?>
     * ```
     *
     * @param $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 $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 $uri
     */
    public function dontSeeCurrentUrlMatches($uri);

    /**
     * Executes the given regular expression against the current URI and returns the first match.
     * If no parameters are provided, the full URI is returned.
     *
     * ``` php
     * <?php
     * $user_id = $I->grabFromCurrentUrl('~$/user/(\d+)/~');
     * $uri = $I->grabFromCurrentUrl();
     * ?>
     * ```
     *
     * @param null $uri
     *
     * @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 contains the given value.
     * For fuzzy locators, fields are matched by label text, the "name" attribute, CSS, and 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'));
     * ?>
     * ```
     *
     * @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@mail.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 :
     * - string: strict number
     * - array: range of numbers [0,10]
     */
    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.
     *
     * @param $cookie
     *
     * @param array $params
     * @return mixed
     */
    public function grabCookie($cookie, array $params = []);
}
<?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 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\Lib\Interfaces;

interface Db
{
    /**
     * Asserts that a row with the given column values exists.
     * Provide table name and column values.
     *
     * Example:
     *
     * ``` php
     * <?php
     * $I->seeInDatabase('users', array('name' => 'Davert', 'email' => 'davert@mail.com'));
     *
     * ```
     * Will generate:
     *
     * ``` sql
     * SELECT COUNT(*) FROM `users` WHERE `name` = 'Davert' AND `email` = 'davert@mail.com'
     * ```
     * Fails if no such user found.
     *
     * @param       $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.
     *
     * Example:
     *
     * ``` php
     * <?php
     * $I->dontSeeInDatabase('users', array('name' => 'Davert', 'email' => 'davert@mail.com'));
     *
     * ```
     * Will generate:
     *
     * ``` sql
     * SELECT COUNT(*) FROM `users` WHERE `name` = 'Davert' AND `email` = 'davert@mail.com'
     * ```
     * Fails if such user was found.
     *
     * @param       $table
     * @param array $criteria
     */
    public function dontSeeInDatabase($table, $criteria = []);

    /**
     * Fetches a single column value from a database.
     * Provide table name, desired column and criteria.
     *
     * Example:
     *
     * ``` php
     * <?php
     * $mail = $I->grabFromDatabase('users', 'email', array('name' => 'Davert'));
     *
     * ```
     *
     * @version 1.1
     *
     * @param       $table
     * @param       $column
     * @param array $criteria
     *
     * @return mixed
     */
    public function grabFromDatabase($table, $column, $criteria = []);
}
<?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\Interfaces;

interface ConflictsWithModule 
{
    /**
     * Returns class name or interface of module which can conflict with current.
     * @return string
     */
    public function _conflicts();
}
<?php
namespace Codeception\Lib;

use Codeception\Exception\InjectionException;

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)
    {
        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)
    {
        // get class from container
        if (isset($this->container[$className])) {
            if ($this->container[$className] instanceof $className) {
                return $this->container[$className];
            } else {
                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) {
            throw new InjectionException("Failed to inject dependencies in instance of '{$reflectedObject->name}'. " . $e->getMessage());
        }

        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 = $parameter->getClass();
            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->name);
                if (is_null($arg)) {
                    throw new InjectionException("Failed to resolve dependency '{$dependency->name}'.");
                }
                $args[] = $arg;
            }
        }
        return $args;
    }
}
<?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\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\TestCase\Test
{
    /**
     * @var \{{actorClass}}
     */
    protected \${{actor}};

    protected function _before()
    {
    }

    protected function _after()
    {
    }

    // tests
    public function testMe()
    {

    }
}
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['class_name'];
        if ($this->settings['namespace']) {
            $actor = $this->settings['namespace'] . '\\' . $actor;
        }

        $ns = $this->getNamespaceHeader($this->settings['namespace'] . '\\' . $this->name);

        return (new Template($this->template))
            ->place('namespace', $ns)
            ->place('name', $this->getShortClassName($this->name))
            ->place('actorClass', $actor)
            ->place('actor', lcfirst(Configuration::config()['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 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['class_name'])) {
            return ''; // global pageobject
        }

        $actorClass = $this->settings['class_name'];
        $actor = lcfirst($this->settings['class_name']);

        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 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['class_name'];
        $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 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['class_name'];
        $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\Util\Shared\Namespaces;
use Codeception\Util\Template;

class PhpUnit
{
    use Namespaces;
    use Shared\Classname;

    protected $template = <<<EOF
<?php
{{namespace}}
class {{name}}Test extends \PHPUnit_Framework_TestCase
{
    protected function setUp()
    {
    }

    protected function tearDown()
    {
    }

    // tests
    public function testMe()
    {
    }
}

EOF;

    protected $settings;
    protected $name;

    public function __construct($settings, $name)
    {
        $this->settings = $settings;
        $this->name = $this->removeSuffix($name, 'Test');
    }

    public function produce()
    {
        $ns = $this->getNamespaceHeader($this->settings['namespace'] . '\\' . $this->name);

        return (new Template($this->template))
            ->place('namespace', $ns)
            ->place('name', $this->getShortClassName($this->name))
            ->produce();
    }
}
<?php
namespace Codeception\Lib\Generator;

use Codeception\Configuration;
use Codeception\Lib\Di;
use Codeception\Lib\ModuleContainer;
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'], '\\');

        return (new Template($this->template))
            ->place('hasNamespace', $namespace ? "namespace $namespace;" : '')
            ->place('actor', $this->settings['class_name'])
            ->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 . ' = '.$this->getDefaultValue($param);
            } else {
                $params[] = '$' . $param->name;
            };

        }
        return implode(', ', $params);
    }

    public function getActorName()
    {
        return $this->settings['class_name'];
    }

    public function getModules()
    {
        return array_keys($this->modules);
    }

    /**
     * Infer default parameter from the reflection object and format it as PHP (code) string
     *
     * @param \ReflectionParameter $param
     *
     * @return string
     */
    private 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;
                    }
                }

                return $constName;
            }

            return $this->phpEncodeValue($param->getDefaultValue());
        }

        return 'null';
    }

    /**
     * PHP encoded a value
     *
     * @param mixed $value
     *
     * @return string
     */
    private function phpEncodeValue($value)
    {
        if (is_array($value)) {
            return $this->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
     */
    private 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([$this, 'phpEncodeValue'], $array)).']';
        }

        return '['.implode(', ', array_map(function ($key) use ($array) {
            return $this->phpEncodeValue($key).' => '.$this->phpEncodeValue($array[$key]);
        }, array_keys($array))).']';
    }
}
<?php
namespace Codeception\Lib\Generator;

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)
    {
    }

    public function _after({{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['class_name'];
        $namespace = rtrim( $this->settings['namespace'], '\\' );
        $ns = $this->getNamespaceHeader($namespace.'\\'.$this->name);
        if ($ns) {
            $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\Codecept;
use Codeception\Configuration;
use Codeception\Lib\Di;
use Codeception\Lib\ModuleContainer;
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

{{use}}

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 \$this->getScenario()->runStep(new \Codeception\Step\{{step}}('{{method}}', func_get_args()));
    }
EOF;

    protected $name;
    protected $settings;
    protected $modules = [];
    protected $actions;
    protected $numMethods = 0;

    public function __construct($settings)
    {
        $this->name = $settings['class_name'];
        $this->settings = $settings;
        $this->di = new Di();
        $modules = Configuration::modules($this->settings);
        $this->moduleContainer = new ModuleContainer($this->di, $settings);
        foreach ($modules as $moduleName) {
            $this->modules[$moduleName] = $this->moduleContainer->create($moduleName);
        }
        $this->actions = $this->moduleContainer->getActions();
    }


    public function produce()
    {
        $namespace = rtrim($this->settings['namespace'], '\\');

        $uses = [];
        foreach ($this->modules as $module) {
            $uses[] = "use " . get_class($module) . ";";
        }

        $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('use', implode("\n", $uses))
            ->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 = "*";
        }

        $conditionalDoc = $doc . "\n     * Conditional Assertion: Test won't be stopped on fail";

        $methodTemplate = (new Template($this->methodTemplate))
            ->place('module', $module)
            ->place('method', $refMethod->name)
            ->place('params', $params);

        // generate conditional assertions
        if (0 === strpos($refMethod->name, 'see')) {
            $type = 'Assertion';
            $body .= $methodTemplate
                ->place('doc', $conditionalDoc)
                ->place('action', 'can' . ucfirst($refMethod->name))
                ->place('step', 'ConditionalAssertion')
                ->produce();

            // generate negative assertion
        } elseif (0 === strpos($refMethod->name, 'dontSee')) {
            $type = 'Assertion';
            $body .= $methodTemplate
                ->place('doc', $conditionalDoc)
                ->place('action', str_replace('dont', 'cant', $refMethod->name))
                ->place('step', 'ConditionalAssertion')
                ->produce();

        } elseif (0 === strpos($refMethod->name, 'am')) {
            $type = 'Condition';
        } else {
            $type = 'Action';
        }

        $body .= $methodTemplate
            ->place('doc', $doc)
            ->place('action', $refMethod->name)
            ->place('step', $type)
            ->produce();

        return $body;
    }

    /**
     * @param \ReflectionMethod $refMethod
     * @return array
     */
    protected function getParamsString(\ReflectionMethod $refMethod)
    {
        $params = [];
        foreach ($refMethod->getParameters() as $param) {

            if ($param->isOptional()) {
                $params[] = '$' . $param->name . ' = null';
            } else {
                $params[] = '$' . $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']));
    }

    public function getNumMethods()
    {
        return $this->numMethods;
    }
} 
<?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 '\\' . $this->namespace . 'Helper\\' . $this->name;
    }
}
<?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 "<focus>$location</focus> | " . $message;
        }
        return $message;
    }

    public static function all()
    {
        $messages = self::$messages;
        self::$messages = [];
        return $messages;
    }

}<?php
namespace Codeception\Lib;

use Codeception\Configuration;
use Codeception\Exception\ConfigurationException as ConfigurationException;
use Codeception\Exception\ModuleException as ModuleException;
use Codeception\Exception\ModuleConflictException as ModuleConflictException;
use Codeception\Exception\ModuleRequireException;
use Codeception\Lib\Interfaces\ConflictsWithModule;
use Codeception\Lib\Interfaces\DependsOnModule;
use Codeception\Lib\Interfaces\PartedModule;
use Codeception\Module;
use Codeception\Util\Annotation;

class ModuleContainer
{
    const MODULE_NAMESPACE = '\\Codeception\\Module\\';

    protected $config;

    /**
     * @var Di
     */
    protected $di;

    protected $modules = [];
    protected $active = [];
    protected $actions = [];

    public function __construct(Di $di, $config)
    {
        $this->di = $di;
        $this->di->set($this);
        $this->config = $config;
    }

    /**
     * @param $moduleName
     * @param bool $active
     * @throws ConfigurationException
     * @return Module
     */
    public function create($moduleName, $active = true)
    {
        $this->active[$moduleName] = $active;
        $config = $this->getModuleConfig($moduleName);

        // skip config validation on dependent module
        if (empty($config) && !$active) {
            $config = null;
        }

        // helper
        $hasNamespace = (strpos($moduleName, '\\') !== false);
        if ($hasNamespace) {
            return $this->instantiate($moduleName, $moduleName, $config);
        }

        // standard module
        $moduleClass = self::MODULE_NAMESPACE . $moduleName;
        if (class_exists($moduleClass)) {
            return $this->instantiate($moduleName, $moduleClass, $config);
        }

        // (deprecated) try find module under namespace setting
        $namespace = isset($this->config['namespace']) ? $this->config['namespace'] : '';
        $moduleClass = $namespace . self::MODULE_NAMESPACE . $moduleName;

        if (class_exists($moduleClass)) {
            return $this->instantiate($moduleName, $moduleClass, $config);
        }

        throw new ConfigurationException("Module $moduleName could not be found and loaded");
    }

    public function hasModule($module)
    {
        return isset($this->modules[$module]);
    }

    public function getModule($module)
    {
        if (!$this->hasModule($module)) {
            throw new ModuleException(__CLASS__, "Module $module couldn't be connected");
        }
        return $this->modules[$module];
    }

    public function moduleForAction($action)
    {
        if (!isset($this->actions[$action])) {
            return null;
        }
        return $this->modules[$this->actions[$action]];
    }

    public function getActions()
    {
        return $this->actions;
    }

    public function all()
    {
        return $this->modules;
    }

    private function instantiate($name, $class, $config)
    {
        $module = $this->di->instantiate($class, [$this, $config], false);
        $this->modules[$name] = $module;

        if (!$this->active[$name]) {
            // if module is not active, its actions should not be included into actor class
            return $module;
        }
        
        if ($module instanceof DependsOnModule) {
            $this->injectDependentModule($name, $module);
        }

        $class = new \ReflectionClass($module);
        $methods = $class->getMethods(\ReflectionMethod::IS_PUBLIC);
        foreach ($methods as $method) {
            $inherit = $class->getStaticPropertyValue('includeInheritedActions');
            $only = $class->getStaticPropertyValue('onlyActions');
            $exclude = $class->getStaticPropertyValue('excludeActions');

            // exclude methods when they are listed as excluded
            if (in_array($method->name, $exclude)) {
                continue;
            }

            if (!empty($only)) {
                // skip if method is not listed
                if (!in_array($method->name, $only)) {
                    continue;
                }
            } else {
                // skip if method is inherited and inheritActions == false
                if (!$inherit && $method->getDeclaringClass() != $class) {
                    continue;
                }
            }
            // those with underscore at the beginning are considered as hidden
            if (strpos($method->name, '_') === 0) {
                continue;
            }

            if ($module instanceof PartedModule && isset($config['part'])) {
                if (!$this->moduleActionBelongsToPart($module, $method->name, $config['part'])) {
                    continue;
                }
            }

            $this->actions[$method->name] = $name;
        }
        return $module;
    }

    public function injectDependentModule($name, DependsOnModule $module)
    {
        $message = '';
        $dependency = $module->_depends();
        if (empty($dependency)) {
            return;
        }
        if (is_array($dependency)) {
            $message = reset($dependency);
            $dependency = key($dependency);
        }
        $config = $this->getModuleConfig($name);
        if (!isset($config['depends'])) {
            throw new ModuleRequireException($module,
                "\nThis module depends on $dependency\n" .
                "\n \n$message");
        }
        $dependentModule = $this->create($config['depends'], false);
        if (!method_exists($module, '_inject')) {
            throw new ModuleException($module, 'Module requires method _inject to be defined to accept dependencies');
        }
        $module->_inject($dependentModule);
        $dependentModule->_setConfig([]);
    }

    public function validateConflicts()
    {
        $moduleNames = array_keys($this->modules);
        for ($i = 0; $i < count($this->modules); $i++) {
            /** @var $currentModule Module  **/
            $currentModule = $this->modules[$moduleNames[$i]];
            if (!$currentModule instanceof ConflictsWithModule) {
                continue;
            }
            for ($j = $i; $j < count($this->modules); $j++) {
                $inspectedModule = $this->modules[$moduleNames[$j]];
                $nameAndInterfaces = array_merge([get_class($inspectedModule), $inspectedModule->_getName()], class_implements($inspectedModule));
                if (in_array(ltrim($currentModule->_conflicts(), '\\'), $nameAndInterfaces)) {
                    throw new ModuleConflictException($currentModule, $inspectedModule);
                }
            }
        }
    }

    protected function moduleActionBelongsToPart($module, $action, $part)
    {
        if (!is_array($part)) {
            $part = [strtolower($part)];
        }
        $part = array_map('strtolower', $part);
        $parts = Annotation::forMethod($module, $action)->fetchAll('part');
        $usedParts = array_intersect($parts, $part);
        return !empty($usedParts);
    }

    protected function getModuleConfig($module)
    {
        // get config for all modules
        $config = isset($this->config['modules']['config'][$module])
            ? $this->config['modules']['config'][$module]
            : [];

        if (!isset($this->config['modules']['enabled'])) {
            return $config;
        }

        if (!is_array($this->config['modules']['enabled'])) {
            return $config;
        }


        // get config for enabled modules
        foreach ($this->config['modules']['enabled'] as $enabledModuleConfig) {
            if (!is_array($enabledModuleConfig)) {
                continue;
            }
            $enabledModuleName = key($enabledModuleConfig);
            if ($enabledModuleName !== $module) {
                continue;
            }
            $config = Configuration::mergeConfigs(reset($enabledModuleConfig), $config);
        }
        return $config;
    }
}<?php
namespace Codeception\Lib\Actor\Shared;

use Codeception\Scenario;

trait Comment
{
    /**
     * @return 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;

use Codeception\Scenario;
use Codeception\Lib\Friend as LibFriend;

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;

use Codeception\Configuration;
use Codeception\Exception\TestParseException;
use Codeception\Scenario;
use Codeception\Step;
use Codeception\Util\Annotation;

class Parser
{
    protected $scenario;
    protected $code;

    public function __construct(Scenario $scenario)
    {
        $this->scenario = $scenario;
    }

    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)
    {
        $comments = $this->matchComments($code);
        $this->attachMetadata($comments);
        
        // deprecated - parsing $scenario->xxx calls
        $metaData = ['group', 'env'];
        $phpCode = $this->stripComments($code);
        $scenario = $this->scenario;
        $feature = $scenario->getFeature();
        foreach ($metaData as $call) {
            $res = preg_match_all("~\\\$scenario->$call.*?;~", $phpCode, $matches);
            if (!$res) {
                continue;
            }
            foreach ($matches[0] as $line) {
                // run $scenario->group or $scenario->env
                \Codeception\Lib\Notification::deprecate("\$scenario->$call() is deprecated in favor of annotation: // @$call",
                    $this->scenario->getFeature()
                );
                eval($line);
            }
        }
    }

    public function attachMetadata($comments)
    {
        $annotations = ['group', 'env', 'skip', 'incomplete', 'ignore'];
        foreach ($annotations as $annotation) {
            $values = Annotation::fetchAllFromComment($annotation, $comments);
            foreach ($values as $value) {
                call_user_func([$this->scenario, $annotation], $value);
            }
        }        
    }

    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;
        }
        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());
        } 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][0] === T_STRING) {
                        $namespace .= $tokens[$j][1] . '\\';
                    } else {
                        if ($tokens[$j] === '{' || $tokens[$j] === ';') {
                            break;
                        }
                    }
                }
            }

            if ($tokens[$i][0] === T_CLASS) {
                if (!isset($tokens[$i - 2])) {
                    $classes[] = $namespace . $tokens[$i + 2][1];
                    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];
            }
        }

        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\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;

    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('bold', new OutputFormatterStyle(null, null, ['bold']));
        $formatter->setStyle('focus', new OutputFormatterStyle('magenta', null, ['bold']));
        $formatter->setStyle('ok', new OutputFormatterStyle('white', 'magenta'));
        $formatter->setStyle('error', new OutputFormatterStyle('white', 'red'));
        $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);
        if ($this->waitForDebugOutput) {
            $this->writeln('');
            $this->waitForDebugOutput = false;
        }
        $this->writeln("<debug>  $message</debug>");
    }

    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\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 = mb_strlen(strip_tags($this->message), 'utf-8');

        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()
    {
        return mb_strlen($this->message, 'utf-8');
    }

    public function __toString()
    {
        return $this->message;
    }
}
<?php
namespace Codeception\Lib;

use Codeception\Configuration;
use Codeception\Exception\ElementNotFound;
use Codeception\Exception\ExternalUrlException;
use Codeception\Exception\MalformedLocatorException;
use Codeception\Exception\ModuleException;
use Codeception\Exception\TestRuntimeException;
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\TestCase;
use Codeception\Util\Locator;
use Codeception\Util\ReflectionHelper;
use Codeception\Util\Uri;
use Symfony\Component\BrowserKit\Cookie;
use Symfony\Component\DomCrawler\Link;
use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\DomCrawler\Field\ChoiceFormField;
use Symfony\Component\DomCrawler\Field\FileFormField;
use Symfony\Component\DomCrawler\Field\InputFormField;
use Symfony\Component\DomCrawler\Field\TextareaFormField;
use Symfony\Component\DomCrawler\Form;

class InnerBrowser extends Module implements Web, PageSourceSaver, ElementLocator
{
    /**
     * @var \Symfony\Component\DomCrawler\Crawler
     */
    protected $crawler;

    /**
     * @api
     * @var \Symfony\Component\BrowserKit\Client
     */
    public $client;

    /**
     * @var array|\Symfony\Component\DomCrawler\Form[]
     */
    protected $forms = [];

    protected $defaultCookieParameters = ['expires' => null, 'path' => '/', 'domain' => '', 'secure' => false];

    protected $internalDomains = null;

    public function _failed(TestCase $test, $fail)
    {
        if (!$this->client || !$this->client->getInternalResponse()) {
            return;
        }
        $this->_savePageSource(codecept_output_dir().str_replace(['::', '\\', '/'], ['.', '.', '.'], TestCase::getTestSignature($test)) . '.fail.html');
    }

    public function _after(TestCase $test)
    {
        $this->client = null;
        $this->crawler = null;
        $this->forms = [];
    }

    public function _conflicts()
    {
        return 'Codeception\Lib\Interfaces\Web';
    }

    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 $method
     * @param $uri
     * @param array $parameters
     * @param array $files
     * @param array $server
     * @param null $content
     * @return mixed|Crawler
     * @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, false);
        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->assertContains($text, $this->getModule('{{MODULE_NAME}}')->_getResponseContent(), "response contains");
     * }
     * ?>
     * ```
     *
     * @api
     * @return string
     * @throws ModuleException
     */
    public function _getResponseContent()
    {
        return (string)$this->getRunningClient()->getInternalResponse()->getContent();
    }

    protected function clientRequest($method, $uri, array $parameters = array(), array $files = array(), array $server = array(), $content = null, $changeHistory = 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 ($method !== 'GET' && $content === null && !empty($parameters)) {
                $content = http_build_query($parameters);
            }
        }

        if (!ReflectionHelper::readPrivateProperty($this->client, 'followRedirects')) {
            $result = $this->client->request($method, $uri, $parameters, $files, $server, $content, $changeHistory);
            $this->debugResponse($uri);
            return $result;
        } else {
            $maxRedirects = ReflectionHelper::readPrivateProperty($this->client, 'maxRedirects', 'Symfony\Component\BrowserKit\Client');
            $this->client->followRedirects(false);
            $result = $this->client->request($method, $uri, $parameters, $files, $server, $content, $changeHistory);
            $this->debugResponse($uri);
            return $this->redirectIfNecessary($result, $maxRedirects, 0);
        }
    }

    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 $method
     * @param $uri
     * @param array $parameters
     * @param array $files
     * @param array $server
     * @param null $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->forms = [];
    }

    /**
     * @return Crawler
     * @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()
    {
        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");
        }
        return $this->client;
    }

    public function _savePageSource($filename)
    {
        file_put_contents($filename, $this->_getResponseContent());
    }

    /**
     * Authenticates user for HTTP_AUTH
     *
     * @param $username
     * @param $password
     */
    public function amHttpAuthenticated($username, $password)
    {
        $this->client->setServerParameter('PHP_AUTH_USER', $username);
        $this->client->setServerParameter('PHP_AUTH_PW', $password);
    }


    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)) {
            $anchor = $this->getCrawler()->selectLink($link);
        }
        if (count($anchor)) {
            $this->crawler = $this->clientClick($anchor->first()->link());
            $this->forms = [];
            return;
        }

        $buttonText = str_replace('"', "'", $link);
        $button = $this->crawler->selectButton($buttonText);
        if (count($button)) {
            $buttonValue = [];
            if (strval($button->attr('name')) !== '' && $button->attr('value') !== null) {
                $buttonValue = [$button->attr('name') => $button->attr('value')];
            }
            $this->proceedSubmitForm(
                $button->parents()->filter('form')->first(),
                $buttonValue
            );
            return;
        }

        try {
            $this->clickByLocator($link);
        } catch (MalformedLocatorException $e) {
            throw new ElementNotFound("name=$link", "'$link' is invalid CSS and XPath selector and Link or Button");
        }
    }

    protected function clickByLocator($link)
    {
        $nodes = $this->match($link);
        if (!$nodes->count()) {
            throw new ElementNotFound($link, 'Link or Button by name or CSS or XPath');
        }

        foreach ($nodes as $node) {
            $tag = $node->nodeName;
            $type = $node->getAttribute('type');
            if ($tag === 'a') {
                $this->crawler = $this->clientClick($nodes->first()->link());
                $this->forms = [];
                break;
            } elseif (in_array($tag, ['input', 'button']) && in_array($type, ['submit', 'image'])) {
                $buttonValue = [];
                if (strval($nodes->first()->attr('name')) !== '' && $nodes->first()->attr('value') !== null) {
                    $buttonValue = [$nodes->first()->attr('name') => $nodes->first()->attr('value')];
                }
                $this->proceedSubmitForm(
                    $nodes->parents()->filter('form')->first(),
                    $buttonValue
                );
                break;
            }
        }
    }

    public function see($text, $selector = null)
    {
        if (!$selector) {
            $this->assertPageContains($text);
        } else {
            $nodes = $this->match($selector);
            $this->assertDomContains($nodes, $this->stringifySelector($selector), $text);
        }
    }

    public function dontSee($text, $selector = null)
    {
        if (!$selector) {
            $this->assertPageNotContains($text);
        } else {
            $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)
    {
        $links = $this->getCrawler()->selectLink($text);
        if ($url) {
            $links = $links->filterXPath(sprintf('.//a[contains(@href, %s)]', Crawler::xpathLiteral($url)));
        }
        $this->assertDomContains($links, 'a');
    }

    public function dontSeeLink($text, $url = null)
    {
        $links = $this->getCrawler()->selectLink($text);
        if ($url) {
            $links = $links->filterXPath(sprintf('.//a[contains(@href, %s)]', Crawler::xpathLiteral($url)));
        }
        $this->assertDomNotContains($links, 'a');
    }

    /**
     * @return string
     * @throws ModuleException
     */
    public function _getCurrentUri()
    {
        return Uri::retrieveUri($this->getRunningClient()->getHistory()->current()->getUri());
    }

    public function seeInCurrentUrl($uri)
    {
        $this->assertContains($uri, $this->_getCurrentUri());
    }

    public function dontSeeInCurrentUrl($uri)
    {
        $this->assertNotContains($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)
    {
        \PHPUnit_Framework_Assert::assertRegExp($uri, $this->_getCurrentUri());
    }

    public function dontSeeCurrentUrlMatches($uri)
    {
        \PHPUnit_Framework_Assert::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->getCrawler()->filter($checkbox);
        $this->assertDomContains($checkboxes->filter('input[checked=checked]'), 'checkbox');
    }

    public function dontSeeCheckboxIsChecked($checkbox)
    {
        $checkboxes = $this->getCrawler()->filter($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');
        }
        foreach ($params as $name => $values) {
            $field = $form->filterXPath(sprintf('.//*[@name=%s]', Crawler::xpathLiteral($name)));
            if ($field->count() === 0) {
                throw new ElementNotFound(
                    sprintf('//*[@name=%s]', Crawler::xpathLiteral($name)),
                    'Form'
                );
            }
            if (!is_array($values)) {
                $values = [$values];
            }
            foreach ($values as $value) {
                $ret = $this->proceedSeeInField($field, $value);
                if ($assertNot) {
                    $this->assertNot($ret);
                } else {
                    $this->assert($ret);
                }
            }
        }
    }

    protected function proceedSeeInField(Crawler $fields, $value)
    {
        $testValues = $this->proceedGetValueFromField($fields);
        if (!is_array($testValues)) {
            $testValues = [$testValues];
        }
        if (is_bool($value) && $value === true && !empty($testValues)) {
            $value = reset($testValues);
        } elseif (empty($testValues)) {
            $testValues = [''];
        }
        return [
            'Contains',
            $value,
            $testValues,
            sprintf(
                'Failed asserting that `%s` is in %s\'s value: %s',
                $value,
                $fields->getNode(0)->nodeName,
                var_export($testValues, true)
            )
        ];
    }

    /**
     * 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 Crawler $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 $box) {
            $fieldName = $this->getSubmissionFormFieldName($box->getAttribute('name'));
            $pos = (!isset($chFoundByName[$fieldName])) ? 0 : $chFoundByName[$fieldName];
            $skip = (!isset($params[$fieldName]))
                || (!is_array($params[$fieldName]) && !is_bool($params[$fieldName]))
                || ($pos >= count($params[$fieldName])
                || (is_array($params[$fieldName]) && !is_bool($params[$fieldName][$pos])));
            if ($skip) {
                continue;
            }
            $values = $params[$fieldName];
            if ($values === true) {
                $params[$fieldName] = $box->getAttribute('value');
                $chFoundByName[$fieldName] = $pos + 1;
            } elseif ($values[$pos] === true) {
                $params[$fieldName][$pos] = $box->getAttribute('value');
                $chFoundByName[$fieldName] = $pos + 1;
            } elseif (is_array($values)) {
                array_splice($params[$fieldName], $pos, 1);
            } else {
                unset($params[$fieldName]);
            }
        }
        return $params;
    }

    /**
     * Submits the form currently selected in the passed Crawler, after
     * setting any values passed in $params and setting the value of the
     * passed button name.
     *
     * @param Crawler $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)
    {
        $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]', Crawler::xpathLiteral($button)));
            if (count($btnCrawl)) {
                $requestParams[$button] = $btnCrawl->attr('value');
            }
        }

        $url = $this->getFormUrl($frmCrawl);
        if (strcasecmp($form->getMethod(), 'GET') === 0) {
            $url = Uri::mergeUrls($url, '?' . http_build_query($requestParams));
        }
        $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)) {
            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) || $uri === '#') {
            return $currentUrl;
        }
        return Uri::mergeUrls($currentUrl, $uri);
    }

    /**
     * Returns the form action's absolute URL.
     *
     * @param \Symfony\Component\DomCrawler\Crawler $form
     * @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->attr('action');
        return $this->getAbsoluteUrlFor($action);
    }

    /**
     * Returns a crawler Form object for the form pointed to by the
     * passed Crawler.
     *
     * 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 Crawler $form the form
     * @param string $action the form's absolute URL action
     * @return Form
     */
    private function getFormFromCrawler(Crawler $form, $action)
    {
        $fakeDom = new \DOMDocument();
        $fakeDom->appendChild($fakeDom->importNode($form->getNode(0), true));
        $node = $fakeDom->documentElement;
        $cloned = new Crawler($node, $action);
        $shouldDisable = $cloned->filter('input:disabled:not([disabled]),select option:disabled,select optgroup:disabled option:not([disabled])');
        foreach ($shouldDisable as $field) {
            $field->parentNode->removeChild($field);
        }
        $selectNonMulti = $cloned->filterXPath('//select[not(@multiple) and not(option[@value=""])]');
        $opt = new \DOMElement('option');
        foreach ($selectNonMulti as $field) {
            $node = $field->insertBefore($opt, $field->firstChild);
            $node->setAttribute('value', '');
        }
        return $cloned->form();
    }

    /**
     * Returns the DomCrawler\Form object for the form pointed to by
     * $node or its closes form parent.
     *
     * @param \Symfony\Component\DomCrawler\Crawler $node
     * @return \Symfony\Component\DomCrawler\Form
     */
    protected function getFormFor(Crawler $node)
    {
        if (strcasecmp($node->first()->getNode(0)->tagName, 'form') === 0) {
            $form = $node->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.');
        }
        $action = (string) $this->getFormUrl($form);
        if (!isset($this->forms[$action])) {
            $this->forms[$action] = $this->getFormFromCrawler($form, $action);
        }
        return $this->forms[$action];
    }

    /**
     * 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 \Symfony\Component\DomCrawler\Form the form
     * @return array an array of name => value pairs
     */
    protected function getFormValuesFor(Form $form)
    {
        $values = [];
        $fields = $form->all();
        foreach ($fields as $field) {
            if ($field->isDisabled() || !$field->hasValue() || $field instanceof FileFormField) {
                continue;
            }
            $fieldName = $this->getSubmissionFormFieldName($field->getName());
            if (substr($field->getName(), -2) === '[]') {
                if (!isset($values[$fieldName])) {
                    $values[$fieldName] = [];
                }
                $values[$fieldName][] = $field->getValue();
            } else {
                $values[$fieldName] = $field->getValue();
            }
        }
        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)->nodeValue = htmlspecialchars($value);
    }

    /**
     * @param $field
     *
     * @return \Symfony\Component\DomCrawler\Crawler
     */
    protected function getFieldsByLabelOrCss($field)
    {
        if (is_array($field)) {
            $input = $this->strictMatch($field);
            if (!count($input)) {
                throw new ElementNotFound($field);
            }
            return $input;
        }

        // by label
        $label = $this->strictMatch(['xpath' => sprintf('.//label[text()=%s]', Crawler::xpathLiteral($field))]);
        if (count($label)) {
            $label = $label->first();
            if ($label->attr('for')) {
                $input = $this->strictMatch(['id' => $label->attr('for')]);
            }
        }

        // by name
        if (!isset($input)) {
            $input = $this->strictMatch(['name' => $field]);
        }

        // by CSS and XPath
        if (!count($input)) {
            $input = $this->match($field);
        }

        if (!count($input)) {
            throw new ElementNotFound($field, 'Form field by Label or CSS');
        }

        return $input;
    }

    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)) {
            $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));
    }

    protected function matchOption(Crawler $field, $option)
    {
        $options = $field->filterXPath(sprintf('//option[text()=normalize-space("%s")]|//input[@type="radio" and @value=normalize-space("%s")]', $option, $option));
        if ($options->count()) {
            if ($options->getNode(0)->tagName === 'option') {
                $options->getNode(0)->setAttribute('selected', 'selected');
            } else {
                $options->getNode(0)->setAttribute('checked', 'checked');
            }
            if ($options->first()->attr('value') !== false) {
                return $options->first()->attr('value');
            }
            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));
        $path = Configuration::dataDir() . $filename;
        $name = $field->attr('name');
        if (!is_readable($path)) {
            $this->fail("file $filename not found in Codeception data path. Only files stored in data path accepted");
        }
        $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($path);
    }

    /**
     * If your page triggers an ajax request, you can perform it manually.
     * This action sends a GET ajax request with specified params.
     *
     * See ->sendAjaxPostRequest for examples.
     *
     * @param $uri
     * @param $params
     */
    public function sendAjaxGetRequest($uri, $params = [])
    {
        $this->sendAjaxRequest('GET', $uri, $params);
    }

    /**
     * If your page triggers an ajax request, you can perform it manually.
     * This action sends a POST ajax request with specified params.
     * Additional params can be passed as array.
     *
     * Example:
     *
     * Imagine that by clicking checkbox you trigger ajax request which updates user settings.
     * We emulate that click by running this ajax request manually.
     *
     * ``` php
     * <?php
     * $I->sendAjaxPostRequest('/updateSettings', array('notifications' => true)); // POST
     * $I->sendAjaxGetRequest('/updateSettings', array('notifications' => true)); // GET
     *
     * ```
     *
     * @param $uri
     * @param $params
     */
    public function sendAjaxPostRequest($uri, $params = [])
    {
        $this->sendAjaxRequest('POST', $uri, $params);
    }

    /**
     * If your page triggers an ajax request, you can perform it manually.
     * This action sends an ajax request with specified method and params.
     *
     * Example:
     *
     * You need to perform an ajax request specifying the HTTP method.
     *
     * ``` php
     * <?php
     * $I->sendAjaxRequest('PUT', '/posts/7', array('title' => 'new title'));
     *
     * ```
     *
     * @param $method
     * @param $uri
     * @param $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());
    }

    protected function getResponseStatusCode()
    {
        // depending on Symfony version
        $response = $this->getRunningClient()->getInternalResponse();
        if (method_exists($response, 'getStatus')) {
            return $response->getStatus();
        }
        if (method_exists($response, 'getStatusCode')) {
            return $response->getStatusCode();
        }
        return "N/A";
    }

    /**
     * @param $selector
     *
     * @return Crawler
     */
    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');
    }

    /**
     * @param array $by
     * @throws TestRuntimeException
     * @return Crawler
     */
    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]', Crawler::xpathLiteral($locator)));
            case 'css':
                return $this->filterByCSS($locator);
            case 'xpath':
                return $this->filterByXPath($locator);
            case 'link':
                return $this->filterByXPath(sprintf('.//a[.=%s]', Crawler::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(
                function (Crawler $node) use ($attr, $val) {
                    return $node->attr($attr) == $val;
                }
            );
        }
        return $nodes;

    }

    public function grabTextFrom($cssOrXPathOrRegex)
    {
        if (@preg_match($cssOrXPathOrRegex, $this->client->getInternalResponse()->getContent(), $matches)) {
            return $matches[1];
        }
        $nodes = $this->match($cssOrXPathOrRegex);
        if ($nodes->count()) {
            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()) {
            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) {
            if ($attribute !== null) {
                $result[] = $node->getAttribute($attribute);
            } else {
                $result[] = $node->textContent;
            }
        }
        return $result;
    }

    /**
     * @param $field
     *
     * @return array|mixed|null|string
     */
    public function grabValueFrom($field)
    {
        $nodes = $this->match($field);
        if (!$nodes->count()) {
            throw new ElementNotFound($field, 'Field');
        }
        return $this->proceedGetValueFromField($nodes);
    }

    /**
     * @param Crawler $nodes
     * @return array|mixed|string
     */
    protected function proceedGetValueFromField(Crawler $nodes)
    {
        $values = [];
        if ($nodes->filter('textarea')->count()) {
            return (new TextareaFormField($nodes->filter('textarea')->getNode(0)))->getValue();
        }

        if ($nodes->filter('input')->count()) {
            $input = $nodes->filter('input');
            if ($input->attr('type') == 'checkbox' or $input->attr('type') == 'radio') {
                $values = [];
                $input = $nodes->filter('input:checked');
                foreach ($input as $checkbox) {
                    $values[] = $checkbox->getAttribute('value');
                }
                return $values;
            }
            return (new InputFormField($nodes->filter('input')->getNode(0)))->getValue();
        }
        if ($nodes->filter('select')->count()) {
            $field = new ChoiceFormField($nodes->filter('select')->getNode(0));
            $options = $nodes->filter('option[selected]');
            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();
    }

    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($name, array $params = [])
    {
        $params = array_merge($this->defaultCookieParameters, $params);
        $this->client->getCookieJar()->expire($name, $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);
    }

    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.
     *
     * @param $code
     *
     * @return mixed
     */
    public function seeResponseCodeIs($code)
    {
        $this->assertEquals($code, $this->getResponseStatusCode());
    }

    public function seeInTitle($title)
    {
        $nodes = $this->getCrawler()->filter('title');
        if (!$nodes->count()) {
            throw new ElementNotFound("<title>", "Tag");
        }
        $this->assertContains($title, $nodes->first()->text(), "page title contains $title");
    }

    public function dontSeeInTitle($title)
    {
        $nodes = $this->getCrawler()->filter('title');
        if (!$nodes->count()) {
            $this->assertTrue(true);
            return;
        }
        $this->assertNotContains($title, $nodes->first()->text(), "page title contains $title");
    }

    protected function assertDomContains($nodes, $message, $text = '')
    {
        $constraint = new CrawlerConstraint($text, $this->_getCurrentUri());
        $this->assertThat($nodes, $constraint, $message);
    }

    protected function assertDomNotContains($nodes, $message, $text = '')
    {
        $constraint = new CrawlerNotConstraint($text, $this->_getCurrentUri());
        $this->assertThat($nodes, $constraint, $message);
    }

    protected function assertPageContains($needle, $message = '')
    {
        $constraint = new PageConstraint($needle, $this->_getCurrentUri());
        $this->assertThat(
            html_entity_decode(strip_tags($this->_getResponseContent()), ENT_QUOTES),
            $constraint,
            $message
        );
    }

    protected function assertPageNotContains($needle, $message = '')
    {
        $constraint = new PageConstraint($needle, $this->_getCurrentUri());
        $this->assertThatItsNot(
            html_entity_decode(strip_tags($this->_getResponseContent()), ENT_QUOTES),
            $constraint,
            $message
        );
    }

    protected function assertPageSourceContains($needle, $message = '')
    {
        $constraint = new PageConstraint($needle, $this->_getCurrentUri());
        $this->assertThat(
            $this->_getResponseContent(),
            $constraint,
            $message
        );
    }

    protected function assertPageSourceNotContains($needle, $message = '')
    {
        $constraint = new PageConstraint($needle, $this->_getCurrentUri());
        $this->assertThatItsNot(
            $this->_getResponseContent(),
            $constraint,
            $message
        );
    }

    /**
     * @param $name
     * @param $form
     * @param $dynamicField
     * @return FormField
     */
    protected function matchFormField($name, $form, $dynamicField)
    {
        if (substr($name, -2) != '[]') {
            return $form[$name];
        }
        $name = substr($name, 0, -2);
        /** @var $item \Symfony\Component\DomCrawler\Field\FormField */
        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 Crawler
     */
    protected function filterByCSS($locator)
    {
        if (!Locator::isCSS($locator)) {
            throw new MalformedLocatorException($locator, 'css');
        }
        return $this->getCrawler()->filter($locator);
    }

    /**
     * @param $locator
     * @return Crawler
     */
    protected function filterByXPath($locator)
    {
        if (!Locator::isXPath($locator)) {
            throw new MalformedLocatorException($locator, 'xpath');
        }
        return $this->getCrawler()->filterXPath($locator);
    }

    /**
     * @param $requestParams
     * @return array
     */
    protected function getFormPhpValues($requestParams)
    {
        foreach ($requestParams as $name => $value) {
            $qs = http_build_query([$name => $value], '', '&');
            if (!empty($qs)) {
                parse_str($qs, $expandedValue);
                $varName = substr($name, 0, strlen(key($expandedValue)));
                $requestParams = array_replace_recursive($requestParams, [$varName => current($expandedValue)]);
            }
        }
        return $requestParams;
    }

    /**
     * @param $result
     * @return mixed
     */
    protected function redirectIfNecessary($result, $maxRedirects, $redirectCount)
    {
        $locationHeader = $this->client->getInternalResponse()->getHeader('Location');
        if ($locationHeader) {
            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;
    }

    /**
     * Clicks on a given link.
     *
     * @param Link $link A Link instance
     *
     * @return Crawler
     */
    protected function clientClick(Link $link)
    {
        if ($link instanceof Form) {
            return $this->proceedSubmitForm($link);
        }

        return $this->clientRequest($link->getMethod(), $link->getUri());
    }

    /**
     * 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)) {
            $iframe = $this->match("frame[name=$name]")->first();
        }
        if (!count($iframe)) {
            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('numberOfSteps is set to ' . $numberOfSteps . ', but there are only ' . ($numberOfSteps - $i) . ' previous steps in the history');
        }
        $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 \Symfony\Component\BrowserKit\Cookie($cookie['Name'], $cookie['Value'],
                    $cookie['Expires'], $cookie['Path'], $cookie['Domain'], $cookie['Secure'], $cookie['HttpOnly']));
            }
        }
    }
}
<?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("<info>{$this->name} does --- </info>"));
        $ret = $closure($this->actor);
        $this->actor->comment(strtoupper("<info>--- {$this->name} finished</info>"));

        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 __destruct()
    {
        foreach ($this->multiSessionModules as $module) {
            if (isset($this->data[$module->_getName()])) {
                $module->_closeSession($this->data[$module->_getName()]);
            }
        }
    }
}
 <?php
namespace Codeception\Lib;

use Codeception\Exception\TestParseException;
use Codeception\TestCase\Cept;
use Codeception\TestCase\Cest;
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 TestLoader
{
    protected static $formats = ['Cest', 'Cept', 'Test'];
    protected $tests = [];
    protected $path;

    public function __construct($path)
    {
        $this->path = $path;
    }

    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(strtolower($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 (self::$formats as $format) {
            if (preg_match("~$format.php$~", $path)) {
                call_user_func([$this, "add$format"], $path);
                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()
    {
        $finder = Finder::create()->files()->sortByName()->in($this->path)->followLinks();

        foreach (self::$formats as $format) {
            $formatFinder = clone($finder);
            $testFiles = $formatFinder->name("*$format.php");
            foreach ($testFiles as $test) {
                $pathname = str_replace("//", "/", $test->getPathname());
                call_user_func([$this, "add$format"], $pathname);
            }
        }
    }

    public function addTest($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 addCept($file)
    {
        Parser::validate($file);
        $name = $this->relativeName($file);

        $cept = new Cept();
        $cept->configName($name)
            ->configFile($file);

        $this->tests[] = $cept;
    }

    public function addCest($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) {
                $test = $this->createTestFromCestMethod($unit, $method, $file);
                if (!$test) {
                    continue;
                }
                $this->tests[] = $test;
            }
        }
    }


    protected function createTestFromPhpUnitMethod(\ReflectionClass $class, \ReflectionMethod $method)
    {
        if (!\PHPUnit_Framework_TestSuite::isTestMethod($method)) {
            return;
        }
        $test = \PHPUnit_Framework_TestSuite::createTest($class, $method->name);

        if ($test instanceof \PHPUnit_Framework_TestSuite_DataProvider) {
            foreach ($test->tests() as $t) {
                $this->enhancePhpunitTest($t);
            }
            return $test;
        }

        $this->enhancePhpunitTest($test);
        return $test;
    }

    protected function enhancePhpunitTest(\PHPUnit_Framework_TestCase $test)
    {
        $className = get_class($test);
        $methodName = $test->getName(false);
        $test->setDependencies(\PHPUnit_Util_Test::getDependencies($className, $methodName));

        if (!$test instanceof \Codeception\TestCase) {
            return;
        }
    }

    protected function createTestFromCestMethod($cestInstance, $methodName, $file)
    {
        if ((strpos($methodName, '_') === 0) || ($methodName == '__construct')) {
            return null;
        }
        $testClass = get_class($cestInstance);

        $cest = new Cest();
        $cest->configName($methodName)
            ->configFile($file)
            ->config('testClassInstance', $cestInstance)
            ->config('testMethod', $methodName);

        $cest->setDependencies(\PHPUnit_Util_Test::getDependencies($testClass, $methodName));
        return $cest;
    }
}
<?php
namespace Codeception\Lib;

use Codeception\Configuration;
use Codeception\TestCase\Interfaces\Reported;
use Codeception\TestCase\Interfaces\ScenarioDriven;
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 = [];

    public function __construct(array $groups)
    {
        $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;
            }
            $files = Finder::create()->files()
                ->name(basename($pattern))
                ->path(dirname($pattern))
                ->sortByName()
                ->in(Configuration::projectDir());

            $i = 1;
            foreach ($files as $file) {
                /** @var SplFileInfo $file * */
                $this->configuredGroups[str_replace('*', $i, $group)] = $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][] = Configuration::projectDir() . $file;
                }
            } elseif (is_file(Configuration::projectDir() . $tests)) {
                $handle = @fopen(Configuration::projectDir() . $tests, "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 = trim(Configuration::projectDir() . $test);
                        $file = str_replace(['/', '\\'], [DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR], $file);
                        $this->testsInGroups[$group][] = $file;
                    }
                    fclose($handle);
                }
            } else {
                codecept_debug("Group '$group' is empty, no tests are loaded");
            }
        }
    }

    public function groupsForTest(\PHPUnit_Framework_Test $test)
    {
        $groups = [];
        if ($test instanceof ScenarioDriven) {
            $groups = $test->getScenario()->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']);
        } else {
            $groups = array_merge($groups, \PHPUnit_Util_Test::getGroups(get_class($test), $test->getName(false)));
            $filename = (new \ReflectionClass($test))->getFileName();
        }

        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;
                }
            }
        }
        return array_unique($groups);
    }
}
<?php
namespace Codeception\Lib\Connector;

class Symfony2 extends \Symfony\Component\HttpKernel\Client
{
    /**
     * @var boolean
     */
    private $rebootable = true;

    /**
     * @var boolean
     */
    private $hasPerformedRequest = false;

    /**
     * @var \Symfony\Component\DependencyInjection\ContainerInterface
     */
    private $container = null;

    /**
     * @var array
     */
    public $persistentServices = [];

    /**
     * Constructor.
     *
     * @param \Symfony\Component\HttpKernel\Kernel  $kernel     A booted HttpKernel instance
     * @param array                                 $services   An injected services
     * @param boolean                               $rebootable
     */
    public function __construct(\Symfony\Component\HttpKernel\Kernel $kernel, array $services = [], $rebootable = true)
    {
        parent::__construct($kernel);
        $this->followRedirects(true);
        $this->rebootable = (boolean)$rebootable;
        $this->persistentServices = $services;
        $this->rebootKernel();
    }

    /**
     * @param \Symfony\Component\HttpFoundation\Request $request
     */
    protected function doRequest($request)
    {
        if ($this->rebootable) {
            if ($this->hasPerformedRequest) {
                $this->rebootKernel();
            } else {
                $this->hasPerformedRequest = true;
            }
        }
        return parent::doRequest($request);
    }

    /**
     * Reboot kernel
     *
     * Services from the list of persistent services
     * are updated from service container before kernel shutdown
     * and injected into newly initialized container after kernel boot.
     */
    public function rebootKernel()
    {
        if ($this->container) {
            foreach ($this->persistentServices as $serviceName => $service) {
                if ($this->container->has($serviceName)) {
                    $this->persistentServices[$serviceName] = $this->container->get($serviceName);
                }
            }
        }

        $this->kernel->shutdown();
        $this->kernel->boot();
        $this->container = $this->kernel->getContainer();

        if ($this->container->has('profiler')) {
            $this->container->get('profiler')->enable();
        }

        foreach ($this->persistentServices as $serviceName => $service) {
            $this->container->set($serviceName, $service);
        }
    }
}
<?php
namespace Codeception\Lib\Connector;

use Codeception\Util\Uri;
use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Cookie\SetCookie;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Psr7\Request as Psr7Request;
use GuzzleHttp\Psr7\Response as Psr7Response;
use GuzzleHttp\Psr7\Uri as Psr7Uri;
use Symfony\Component\BrowserKit\Client;
use Symfony\Component\BrowserKit\Cookie;
use Symfony\Component\BrowserKit\Request as BrowserKitRequest;
use Symfony\Component\BrowserKit\Request;
use Symfony\Component\BrowserKit\Response as BrowserKitResponse;

class Guzzle6 extends Client
{
    protected $requestOptions = [
        'allow_redirects' => false,
        'headers'         => [],
    ];
    protected $refreshMaxInterval = 0;

    /** @var \GuzzleHttp\Client */
    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 equivelant
     * 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 (strval($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]);
    }

    public function setAuth($username, $password)
    {
        if (!$username) {
            unset($this->requestOptions['auth']);
            return;
        }
        $this->requestOptions['auth'] = [$username, $password];
    }

    /**
     * Taken from Mink\BrowserKitDriver
     *
     * @param Response $response
     *
     * @return \Symfony\Component\BrowserKit\Response
     */
    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="(\d*)\s*;?\s*url=(.*?)"/i',
                $body,
                $matches
            );

            if (!$matchesMeta && isset($headers['Refresh'])) {
                // match by header
                preg_match(
                    '~(\d*);?url=(.*)~',
                    (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) {
            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) and $formData) {
            $options['form_params'] = $formData;
        }

        try {
            $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 = implode('-', array_map('ucfirst', explode('-', strtolower(str_replace('_', '-', $header)))));
            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'])) {
            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(Request $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'], 'r');
                        $filename = isset($info['name']) ? $info['name'] : null;

                        $files[] = [
                            'name' => $name,
                            'contents' => $handle,
                            'filename' => $filename
                        ];
                    }
                } else {
                    $files = array_merge($files, $this->mapFiles($info, $name));
                }
            } else {
                $files[] = [
                    'name' => $name,
                    'contents' => fopen($info, 'r')
                ];
            }
        }

        return $files;
    }

    protected function extractCookies($host)
    {
        $jar = [];
        $cookies = $this->getCookieJar()->all();
        foreach ($cookies as $cookie) {
            /** @var $cookie Cookie  **/
            $setCookie = SetCookie::fromString((string)$cookie);
            if (!$setCookie->getDomain()) {
                $setCookie->setDomain($host);
            }
            $jar[] = $setCookie;
        }
        return new CookieJar(false, $jar);
    }
}
<?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\Connector;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Application;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Client;

class Laravel4 extends Client
{

    /**
     * @var \Illuminate\Foundation\Application
     */
    private $app;

    /**
     * @var \Codeception\Module\Laravel4
     */
    private $module;

    /**
     * @var bool
     */
    private $firstRequest = true;

    /**
     * Constructor.
     *
     * @param \Codeception\Module\Laravel4 $module
     */
    public function  __construct($module)
    {
        $this->module = $module;
        $this->initialize();

        $components = parse_url($this->app['config']->get('app.url', 'http://localhost'));
        $host = isset($components['host']) ? $components['host'] : 'localhost';

        parent::__construct($this->kernel, ['HTTP_HOST' => $host]);

        // Parent constructor defaults to not following redirects
        $this->followRedirects(true);
    }

    /**
     * @param Request $request
     * @return Response
     */
    protected function doRequest($request)
    {
        if (!$this->firstRequest) {
            $this->initialize($request);
        }
        $this->firstRequest = false;

        $response = $this->kernel->handle($request);
        $this->kernel->terminate($request, $response);

        return $response;
    }

    /**
     * Initialize the Laravel Framework.
     *
     * @throws ModuleConfig
     */
    private function initialize()
    {
        // Store a reference to the database object
        // so the database connection can be reused during tests
        $oldDb = null;
        if ($this->app['db'] && $this->app['db']->connection()) {
            $oldDb = $this->app['db'];
        }

        // Store the current value for the router filters
        // so it can be reset after reloading the application
        $oldFiltersEnabled = null;
        if ($router = $this->app['router']) {
            $property = new \ReflectionProperty(get_class($router), 'filtering');
            $property->setAccessible(true);
            $oldFiltersEnabled = $property->getValue($router);
        }

        $this->app = $this->loadApplication();
        $this->kernel = $this->getStackedClient();
        $this->app->boot();

        // Reset the booted flag of the Application object
        // so the app will be booted again if it receives a new Request
        $property = new \ReflectionProperty(get_class($this->app), 'booted');
        $property->setAccessible(true);
        $property->setValue($this->app, false);

        if ($oldDb) {
            $this->app['db'] = $oldDb;
            Model::setConnectionResolver($this->app['db']);
        }

        if (!is_null($oldFiltersEnabled)) {
            $oldFiltersEnabled ? $this->app['router']->enableFilters() : $this->app['router']->disableFilters();
        }

        $this->module->setApplication($this->app);
    }

    /**
     * Boot the Laravel application object.
     * @return Application
     * @throws ModuleConfig
     */
    private function loadApplication()
    {
        // The following two variables are used in the Illuminate/Foundation/start.php file
        // which is included in the bootstrap start file.
        $unitTesting = $this->module->config['unit'];
        $testEnvironment = $this->module->config['environment'];

        $app = require $this->module->config['start_file'];
        $this->setConfiguredSessionDriver($app);

        return $app;
    }

    /**
     * Get the configured session driver.
     * Laravel 4 forces the array session driver if the application is run from the console.
     * This happens in \Illuminate\Session\SessionServiceProvider::setupDefaultDriver() method.
     * This method is used to set the correct session driver that is configured in the config files.
     *
     * @param Application $app
     */
    private function setConfiguredSessionDriver(Application $app)
    {
        $configDir = $app['path'] . DIRECTORY_SEPARATOR . 'config';
        $configFiles = array(
            $configDir . DIRECTORY_SEPARATOR . $this->module->config['environment'] . DIRECTORY_SEPARATOR . 'session.php',
            $configDir . DIRECTORY_SEPARATOR . 'session.php',

        );

        foreach ($configFiles as $configFile) {
            if (file_exists($configFile)) {
                $sessionConfig = require $configFile;

                if (is_array($sessionConfig) && isset($sessionConfig['driver'])) {
                    $app['config']['session.driver'] = $sessionConfig['driver'];
                    break;
                }
            }
        }
    }

    /**
     * Use a stacked client to include middlewares.
     *
     * @see Illuminate\Foundation\Application::getStackedClient()
     * @return \Stack\StackedHttpKernel
     */
    private function getStackedClient()
    {
        $method = new \ReflectionMethod(get_class($this->app), 'getStackedClient');
        $method->setAccessible(true);

        return $method->invoke($this->app);
    }
}
<?php
namespace Codeception\Lib\Connector;

use GuzzleHttp\Psr7\Uri;
use Symfony\Component\BrowserKit\Client;
use Symfony\Component\BrowserKit\Request;
use Symfony\Component\BrowserKit\Response;
use Zend\Http\Request as HttpRequest;
use Zend\Http\Headers as HttpHeaders;
use Zend\Stdlib\Parameters;
use Zend\Uri\Http as HttpUri;
use Symfony\Component\BrowserKit\Request as BrowserKitRequest;

class ZF2 extends Client
{
    /**
     * @var \Zend\Mvc\ApplicationInterface
     */
    protected $application;

    /**
     * @var  \Zend\Http\PhpEnvironment\Request
     */
    protected $zendRequest;

    /**
     * @param \Zend\Mvc\ApplicationInterface $application
     */
    public function setApplication($application)
    {
        $this->application = $application;
    }

    /**
     * @param Request $request
     *
     * @return Response
     * @throws \Exception
     */
    public function doRequest($request)
    {
        $zendRequest = $this->application->getRequest();
        $zendResponse = $this->application->getResponse();
        
        $zendResponse->setStatusCode(200);
        $uri         = new HttpUri($request->getUri());
        $queryString = $uri->getQuery();
        $method = strtoupper($request->getMethod());

        $zendRequest->setCookies(new Parameters($request->getCookies()));

        $query = [];
        $post = [];
        $content = $request->getContent();
        if ($queryString) {
            parse_str($queryString, $query);
        }
        
        if ($method !== HttpRequest::METHOD_GET) {
            $post = $request->getParameters();
        }

        $zendRequest->setQuery(new Parameters($query));
        $zendRequest->setPost(new Parameters($post));
        $zendRequest->setContent($content);
        $zendRequest->setMethod($method);
        $zendRequest->setUri($uri);
        $requestUri = $uri->getPath();
        if (!empty($queryString)) {
            $requestUri .= '?' . $queryString;
        }

        $zendRequest->setRequestUri($requestUri);
        
        $zendRequest->setHeaders($this->extractHeaders($request));
        $this->application->run();

        $this->zendRequest = $zendRequest;

        $exception = $this->application->getMvcEvent()->getParam('exception');
        if ($exception instanceof \Exception) {
            throw $exception;
        }

        $response = new Response(
            $zendResponse->getBody(),
            $zendResponse->getStatusCode(),
            $zendResponse->getHeaders()->toArray()
        );

        return $response;
    }

    /**
     * @return \Zend\Http\PhpEnvironment\Request
     */
    public function getZendRequest()
    {
        return $this->zendRequest;
    }

    private function extractHeaders(BrowserKitRequest $request)
    {
        $headers = [];
        $server = $request->getServer();

        $contentHeaders = array('Content-Length' => true, 'Content-Md5' => true, 'Content-Type' => true);
        foreach ($server as $header => $val) {
            $header = implode('-', array_map('ucfirst', explode('-', strtolower(str_replace('_', '-', $header)))));

            if (strpos($header, 'Http-') === 0) {
                $headers[substr($header, 5)] = $val;
            } elseif (isset($contentHeaders[$header])) {
                $headers[$header] = $val;
            }
        }
        $zendHeaders = new HttpHeaders();
        $zendHeaders->addHeaders($headers);
        return $zendHeaders;
    }
}
<?php
namespace Codeception\Lib\Connector\ZendExpressive;

use Psr\Http\Message\ResponseInterface;
use Zend\Diactoros\Response\EmitterInterface;

class ResponseCollector implements EmitterInterface
{
    /**
     * @var ResponseInterface
     */
    private $response;

    public function emit(ResponseInterface $response)
    {
        $this->response = $response;
    }

    public function getResponse()
    {
        if ($this->response === null) {
            throw new \LogicException('Response wasn\'t emitted yet');
        }
        return $this->response;
    }

    public function clearResponse()
    {
        $this->response = null;
    }
}
<?php
namespace Codeception\Lib\Connector;

use Codeception\Lib\Connector\Shared\PhpSuperGlobalsConverter;
use Symfony\Component\BrowserKit\Response;
use Symfony\Component\BrowserKit\Cookie;
use Symfony\Component\BrowserKit\Client;
use Codeception\Util\Stub;
use Phalcon\Di;
use Phalcon\Mvc\Application;
use Phalcon\Mvc\Micro As MicroApplication;
use Phalcon\Http\Request;
use Phalcon\Http\RequestInterface;
use Phalcon\Session\AdapterInterface as SessionInterface;
use ReflectionProperty;
use RuntimeException;
use Closure;

class Phalcon extends Client
{
    use PhpSuperGlobalsConverter;

    /**
     * Phalcon Application
     * @var mixed
     */
    private $application;

    /**
     * Set Phalcon Application by \Phalcon\DI\Injectable, Closure or bootstrap file path
     *
     * @param mixed $application
     */
    public function setApplication($application)
    {
        $this->application = $application;
    }

    /**
     * Get Phalcon Application
     *
     * @return Application|MicroApplication
     */
    public function getApplication()
    {
        $application = $this->application;

        if ($application instanceof Closure) {
            return $application();
        } elseif (is_string($application)) {
            return require $application;
        } else {
            return $application;
        }
    }

    /**
     * Makes a request.
     *
     * @param \Symfony\Component\BrowserKit\Request $request
     *
     * @return \Symfony\Component\BrowserKit\Response
     * @throws \RuntimeException
     */
    public function doRequest($request)
    {
        $application = $this->getApplication();
        if (!$application instanceof Application && !$application instanceof MicroApplication) {
            throw new RuntimeException('Unsupported application class.');
        }

        $di = $application->getDI();
        /** @var \Phalcon\Http\Request $phRequest */
        if ($di->has('request')) {
            $phRequest = $di->get('request');
        }

        if (!$phRequest instanceof RequestInterface) {
            $phRequest = new Request;
        }

        $uri         = $request->getUri() ?: $phRequest->getURI();
        $pathString  = parse_url($uri, PHP_URL_PATH);
        $queryString = parse_url($uri, PHP_URL_QUERY);

        $_SERVER = $request->getServer();
        $_SERVER['REQUEST_METHOD'] = strtoupper($request->getMethod());
        $_SERVER['REQUEST_URI'] = null === $queryString ? $pathString : $pathString . '?' . $queryString;

        $_COOKIE  = $request->getCookies();
        $_FILES   = $this->remapFiles($request->getFiles());
        $_REQUEST = $this->remapRequestParameters($request->getParameters());
        $_POST    = [];
        $_GET     = [];

        if ($_SERVER['REQUEST_METHOD'] == 'GET') {
            $_GET = $_REQUEST;
        } else {
            $_POST = $_REQUEST;
        }

        parse_str($queryString, $output);
        foreach ($output as $k => $v) {
            $_GET[$k] = $v;
        }

        $_GET['_url']            = $pathString;
        $_SERVER['QUERY_STRING'] = http_build_query($_GET);

        Di::reset();
        Di::setDefault($di);

        $di['request'] = Stub::construct($phRequest, [], ['getRawBody' => $request->getContent()]);

        $response = $application->handle();

        $headers = $response->getHeaders();
        $status = (int) $headers->get('Status');

        $headersProperty = new ReflectionProperty($headers, '_headers');
        $headersProperty->setAccessible(true);
        $headers = $headersProperty->getValue($headers);
        if (!is_array($headers)) {
            $headers = [];
        }

        $cookiesProperty = new ReflectionProperty($di['cookies'], '_cookies');
        $cookiesProperty->setAccessible(true);
        $cookies = $cookiesProperty->getValue($di['cookies']);
        if (is_array($cookies)) {
            $restoredProperty = new ReflectionProperty('\Phalcon\Http\Cookie', '_restored');
            $restoredProperty->setAccessible(true);
            $valueProperty = new ReflectionProperty('\Phalcon\Http\Cookie', '_value');
            $valueProperty->setAccessible(true);
            foreach ($cookies as $name => $cookie) {
                if (!$restoredProperty->getValue($cookie)) {
                    $clientCookie = new Cookie(
                        $name,
                        $valueProperty->getValue($cookie),
                        $cookie->getExpiration(),
                        $cookie->getPath(),
                        $cookie->getDomain(),
                        $cookie->getSecure(),
                        $cookie->getHttpOnly()
                    );
                    $headers['Set-Cookie'][] = (string)$clientCookie;
                }
            }
        }

        return new Response(
            $response->getContent(),
            $status ? $status : 200,
            $headers
        );
    }
}

class PhalconMemorySession implements SessionInterface
{
    /**
     * @var string
     */
    protected $sessionId;

    /**
     * @var string
     */
    protected $name;

    /**
     * @var bool
     */
    protected $started = false;

    /**
     * @var array
     */
    protected $memory = [];

    /**
     * @var array
     */
    protected $options = [];

    public function __construct(array $options = null)
    {
        $this->sessionId = $this->generateId();

        if (is_array($options)) {
            $this->setOptions($options);
        }
    }

    /**
     * @inheritdoc
     */
    public function start()
    {
        if ($this->status() !== PHP_SESSION_ACTIVE) {
            $this->memory = [];
            $this->started = true;

            return true;
        }

        return false;
    }

    /**
     * @inheritdoc
     *
     * @param array $options
     */
    public function setOptions(array $options)
    {
        if (isset($options['uniqueId'])) {
            $this->sessionId = $options['uniqueId'];
        }

        $this->options = $options;
    }

    /**
     * @inheritdoc
     *
     * @return array
     */
    public function getOptions()
    {
        return $this->options;
    }

    /**
     * @inheritdoc
     *
     * @param string $index
     * @param mixed $defaultValue
     * @param bool $remove
     * @return mixed
     */
    public function get($index, $defaultValue = null, $remove = false)
    {
        $key = $this->prepareIndex($index);

        if (!isset($this->memory[$key])) {
            return $defaultValue;
        }

        $return = $this->memory[$key];

        if ($remove) {
            unset($this->memory[$key]);
        }

        return $return;
    }

    /**
     * @inheritdoc
     *
     * @param string $index
     * @param mixed $value
     */
    public function set($index, $value)
    {
        $this->memory[$this->prepareIndex($index)] = $value;
    }

    /**
     * @inheritdoc
     *
     * @param string $index
     * @return bool
     */
    public function has($index)
    {
        return isset($this->memory[$this->prepareIndex($index)]);
    }

    /**
     * @inheritdoc
     *
     * @param string $index
     */
    public function remove($index)
    {
        unset($this->memory[$this->prepareIndex($index)]);
    }

    /**
     * @inheritdoc
     *
     * @return string
     */
    public function getId()
    {
        return $this->sessionId;
    }

    /**
     * @inheritdoc
     *
     * @return bool
     */
    public function isStarted()
    {
        return $this->started;
    }

    /**
     * Returns the status of the current session
     *
     * ``` php
     * <?php
     * if ($session->status() !== PHP_SESSION_ACTIVE) {
     *     $session->start();
     * }
     * ?>
     * ```
     *
     * @return int
     */
    public function status()
    {
        if ($this->isStarted()) {
            return PHP_SESSION_ACTIVE;
        }

        return PHP_SESSION_NONE;
    }

    /**
     * @inheritdoc
     *
     * @param bool $removeData
     * @return bool
     */
    public function destroy($removeData = false)
    {
        if ($removeData) {
            if (!empty($this->sessionId)) {
                foreach ($this->memory as $key => $value) {
                    if (0 === strpos($key, $this->sessionId . '#')) {
                        unset($this->memory[$key]);
                    }
                }
            } else {
                $this->memory = [];
            }
        }

        $this->started = false;
    }

    /**
     * @inheritdoc
     *
     * @param bool $deleteOldSession
     * @return \Phalcon\Session\AdapterInterface
     */
    public function regenerateId($deleteOldSession = true)
    {
        $this->sessionId = $this->generateId();

        return $this;
    }

    /**
     * @inheritdoc
     *
     * @param string $name
     */
    public function setName($name)
    {
        $this->name = $name;
    }

    /**
     * @inheritdoc
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Dump all session
     *
     * @return array
     */
    public function toArray()
    {
        return (array) $this->memory;
    }

    /**
     * Alias: Gets a session variable from an application context
     *
     * @param string $index
     * @return mixed
     */
    public function __get($index)
    {
        return $this->get($index);
    }

    /**
     * Alias: Sets a session variable in an application context
     *
     * @param string $index
     * @param mixed $value
     */
    public function __set($index, $value)
    {
        $this->set($index, $value);
    }

    /**
     * Alias: Check whether a session variable is set in an application context
     *
     * @param  string $index
     * @return bool
     */
    public function __isset($index)
    {
        return $this->has($index);
    }

    /**
     * Alias: Removes a session variable from an application context
     *
     * @param string $index
     */
    public function __unset($index)
    {
        $this->remove($index);
    }

    private function prepareIndex($index)
    {
        if ($this->sessionId) {
            $key = $this->sessionId . '#' . $index;
        } else {
            $key = $index;
        }

        return $key;
    }

    /**
     * @return string
     */
    private function generateId()
    {
        return md5(time());
    }
}
<?php
namespace Codeception\Lib\Connector;

use Codeception\Util\Uri;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Post\PostFile;
use Symfony\Component\BrowserKit\Client;
use Symfony\Component\BrowserKit\Response as BrowserKitResponse;
use GuzzleHttp\Url;
use Symfony\Component\BrowserKit\Request as BrowserKitRequest;

class Guzzle extends Client
{
    protected $baseUri;
    protected $requestOptions = [
        'allow_redirects' => false,
        'headers' => [],
    ];
    protected $refreshMaxInterval = 0;


    /** @var \GuzzleHttp\Client */
    protected $client;

    public function setBaseUri($uri)
    {
        $this->baseUri = $uri;
    }

    /**
     * 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(\GuzzleHttp\Client $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 equivelant
     * 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 (strval($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]);
    }

    public function setAuth($username, $password)
    {
        if (!$username) {
            unset($this->requestOptions['auth']);
            return;
        }
        $this->requestOptions['auth'] = [$username, $password];
    }

    /**
     * Taken from Mink\BrowserKitDriver
     *
     * @param Response $response
     *
     * @return \Symfony\Component\BrowserKit\Response
     */
    protected function createResponse(Response $response)
    {
        $contentType = $response->getHeader('Content-Type');

        if (!$contentType) {
            $contentType = 'text/html';
        }

        if (strpos($contentType, 'charset=') === false) {
            $body = $response->getBody(true);
            if (preg_match('/\<meta[^\>]+charset *= *["\']?([a-zA-Z\-0-9]+)/i', $body, $matches)) {
                $contentType .= ';charset=' . $matches[1];
            }
            $response->setHeader('Content-Type', $contentType);
        }

        $headers = $response->getHeaders();
        $status = $response->getStatusCode();
        if ($status < 300 || $status >= 400) {
            $matches = [];

            $matchesMeta = preg_match(
                '/\<meta[^\>]+http-equiv="refresh" content="(\d*)\s*;?\s*url=(.*?)"/i',
                $response->getBody(true),
                $matches
            );

            if (!$matchesMeta) {
                // match by header
                preg_match(
                    '~(\d*);?url=(.*)~',
                    (string)$response->getHeader('Refresh'),
                    $matches
                );
            }

            if ((!empty($matches)) && (empty($matches[1]) || $matches[1] < $this->refreshMaxInterval)) {
                $uri = $this->getAbsoluteUri($matches[2]);
                $partsUri = parse_url($uri);
                $partsCur = parse_url($this->getHistory()->current()->getUri());
                foreach ($partsCur as $key => $part) {
                    if ($key === 'fragment') {
                        continue;
                    }
                    if (!isset($partsUri[$key]) || $partsUri[$key] !== $part) {
                        $status = 302;
                        $headers['Location'] = $matchesMeta ? htmlspecialchars_decode($uri) : $uri;
                        break;
                    }
                }
            }
        }

        return new BrowserKitResponse($response->getBody(), $status, $headers);
    }

    public function getAbsoluteUri($uri)
    {
        $baseUri = $this->baseUri;
        if (strpos($uri, '://') === false) {
            if (strpos($uri, '/') === 0) {
                $baseUriPath = parse_url($baseUri, PHP_URL_PATH);
                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  **/
        $requestOptions = [
            'body' => $this->extractBody($request),
            'cookies' => $this->extractCookies($request),
            'headers' => $this->extractHeaders($request)
        ];

        $requestOptions = array_replace_recursive($requestOptions, $this->requestOptions);

        $guzzleRequest = $this->client->createRequest(
            $request->getMethod(),
            $request->getUri(),
            $requestOptions
        );
        foreach ($this->extractFiles($request) as $postFile) {
            $guzzleRequest->getBody()->addFile($postFile);
        }

        // Let BrowserKit handle redirects
        try {
            $response = $this->client->send($guzzleRequest);
        } catch (RequestException $e) {
            if ($e->hasResponse()) {
                $response = $e->getResponse();
            } else {
                throw $e;
            }
        }
        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 = implode('-', array_map('ucfirst', explode('-', strtolower(str_replace('_', '-', $header)))));
            if (strpos($header, 'Http-') === 0) {
                $headers[substr($header, 5)] = $val;
            } elseif (isset($contentHeaders[$header])) {
                $headers[$header] = $val;
            }
        }
        return $headers;
    }

    protected function extractBody(BrowserKitRequest $request)
    {
        if (in_array(strtoupper($request->getMethod()), ['GET','HEAD'])) {
            return null;
        }
        if ($request->getContent() !== null) {
            return $request->getContent();
        } else {
            return $request->getParameters();
        }
}

    protected function extractFiles(BrowserKitRequest $request)
    {
        if (!in_array(strtoupper($request->getMethod()), ['POST', 'PUT'])) {
            return [];
        }

        return $this->mapFiles($request->getFiles());
    }

    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'], 'r');
                        $filename = isset($info['name']) ? $info['name'] : null;

                        $files[] = new PostFile($name, $handle, $filename);
                    }
                } else {
                    $files = array_merge($files, $this->mapFiles($info, $name));
                }
            } else {
                $files[] = new PostFile($name, fopen($info, 'r'));
            }
        }

        return $files;
    }

    protected function extractCookies(BrowserKitRequest $request)
    {
        return $this->getCookieJar()->allRawValues($request->getUri());
    }
}
<?php
namespace Codeception\Lib\Connector;

use Codeception\Util\Debug;
use Symfony\Component\BrowserKit\Client;
use Symfony\Component\BrowserKit\Cookie;
use Symfony\Component\BrowserKit\Response;
use Yii;
use yii\base\ExitException;
use yii\web\HttpException;
use yii\web\Response as YiiResponse;

class Yii2 extends Client
{
    use Shared\PhpSuperGlobalsConverter;

    /**
     * @var string application config file
     */
    public $configFile;

    /**
     * @var array
     */
    public $headers;
    public $statusCode;

    /**
     * @var \yii\web\Application
     */
    private $app;

    /**
     * @var \yii\db\Connection
     */
    public static $db; // remember the db instance

    /**
     * @return \yii\web\Application
     */
    public function getApplication()
    {
        if (!isset($this->app)) {
            $this->app = $this->startApp();
        }
        return $this->app;
    }

    public function resetApplication()
    {
        $this->app = null;
    }

    public function startApp()
    {
        $config = require($this->configFile);
        if (!isset($config['class'])) {
            $config['class'] = 'yii\web\Application';
        }
        /** @var \yii\web\Application $app */
        $app = Yii::createObject($config);
        // always use the same DB connection
        if (isset(static::$db)) {
            $app->set('db', static::$db);
        } elseif ($app->has('db')) {
            static::$db = $app->get('db');
        }
        return $app;
    }

    /**
     *
     * @param \Symfony\Component\BrowserKit\Request $request
     *
     * @return \Symfony\Component\BrowserKit\Response
     */
    public function doRequest($request)
    {
        $_COOKIE = $request->getCookies();
        $_SERVER = $request->getServer();
        $_FILES = $this->remapFiles($request->getFiles());
        $_REQUEST = $this->remapRequestParameters($request->getParameters());
        $_POST = $_GET = [];

        if (strtoupper($request->getMethod()) == 'GET') {
            $_GET = $_REQUEST;
        } else {
            $_POST = $_REQUEST;
        }

        $uri = $request->getUri();

        $pathString = parse_url($uri, PHP_URL_PATH);
        $queryString = parse_url($uri, PHP_URL_QUERY);
        $_SERVER['REQUEST_URI'] = $queryString === null ? $pathString : $pathString . '?' . $queryString;
        $_SERVER['REQUEST_METHOD'] = strtoupper($request->getMethod());

        parse_str($queryString, $params);
        foreach ($params as $k => $v) {
            $_GET[$k] = $v;
        }

        $app = $this->getApplication();

        $app->getResponse()->on(YiiResponse::EVENT_AFTER_PREPARE, [$this, 'processResponse']);

        // disabling logging. Logs are slowing test execution down
        foreach ($app->log->targets as $target) {
            $target->enabled = false;
        }

        $this->headers    = array();
        $this->statusCode = null;

        ob_start();

        $yiiRequest = $app->getRequest();
        if ($request->getContent() !== null) {
            $yiiRequest->setRawBody($request->getContent());
            $yiiRequest->setBodyParams(null);
        } else {
            $yiiRequest->setRawBody(null);
            $yiiRequest->setBodyParams($_POST);
        }
        $yiiRequest->setQueryParams($_GET);

        try {
            $app->handleRequest($yiiRequest)->send();
        } catch (\Exception $e) {
            if ($e instanceof HttpException) {
                // we shouldn't discard existing output as PHPUnit preform output level verification since PHPUnit 4.2.
                $app->errorHandler->discardExistingOutput = false;
                $app->errorHandler->handleException($e);
            } elseif ($e instanceof ExitException) {
                // nothing to do
            } else {
                // for exceptions not related to Http, we pass them to Codeception
                $this->resetApplication();
                throw $e;
            }
        }

        $content = ob_get_clean();

        // catch "location" header and display it in debug, otherwise it would be handled
        // by symfony browser-kit and not displayed.
        if (isset($this->headers['location'])) {
            Debug::debug("[Headers] " . json_encode($this->headers));
        }

        $this->resetApplication();

        return new Response($content, $this->statusCode, $this->headers);
    }

    public function processResponse($event)
    {
        /** @var \yii\web\Response $response */
        $response = $event->sender;
        $request = Yii::$app->getRequest();
        $this->headers = $response->getHeaders()->toArray();
        $response->getHeaders()->removeAll();
        $this->statusCode = $response->getStatusCode();
        $cookies = $response->getCookies();

        if ($request->enableCookieValidation) {
            $validationKey = $request->cookieValidationKey;
        }

        foreach ($cookies as $cookie) {
            /** @var \yii\web\Cookie $cookie */
            $value = $cookie->value;
            if ($cookie->expire != 1 && isset($validationKey)) {
                $data = version_compare(Yii::getVersion(), '2.0.2', '>') ? [$cookie->name, $cookie->value] : $cookie->value;
                $value = Yii::$app->security->hashData(serialize($data), $validationKey);
            }
            $c = new Cookie($cookie->name, $value, $cookie->expire, $cookie->path, $cookie->domain, $cookie->secure, $cookie->httpOnly);
            $this->getCookieJar()->set($c);
        }
        $cookies->removeAll();
    }
}
<?php
namespace Codeception\Lib\Connector\Laravel5;

use Exception;

/**
 * Class ExceptionHandlerDecorator
 *
 * @package Codeception\Lib\Connector\Laravel5
 */
class ExceptionHandlerDecorator
{
    /**
     * @var ExceptionHandlerContract
     */
    private $laravelExceptionHandler;

    /**
     * @var boolean
     */
    private $exceptionHandlingDisabled = true;

    /**
     * ExceptionHandlerDecorator constructor.
     *
     * @param object $laravelExceptionHandler
     */
    public function __construct($laravelExceptionHandler)
    {
        $this->laravelExceptionHandler = $laravelExceptionHandler;
    }

    /**
     * @param boolean $exceptionHandlingDisabled
     */
    public function exceptionHandlingDisabled($exceptionHandlingDisabled)
    {
        $this->exceptionHandlingDisabled = $exceptionHandlingDisabled;
    }

    /**
     * @param $request
     * @param Exception $e
     * @return \Symfony\Component\HttpFoundation\Response
     * @throws Exception
     */
    public function render($request, Exception $e)
    {
        $response = $this->laravelExceptionHandler->render($request, $e);

        if ($this->exceptionHandlingDisabled &&
            strpos($response->getContent(), '<div id="sf-resetcontent" class="sf-reset">') !== false
        ) {
            // If content was generated by the \Symfony\Component\Debug\ExceptionHandler class
            // the Laravel application could not handle the exception,
            // so re-throw this exception if the Codeception user disabled Laravel's exception handling.
            throw $e;
        }

        return $response;
    }

    /**
     * @param string $method
     * @param array $args
     * @return mixed
     */
    public function __call($method, $args)
    {
        return call_user_func_array(array($this->laravelExceptionHandler, $method), $args);
    }
}
<?php
namespace Codeception\Lib\Connector;

use Codeception\Lib\Connector\Laravel5\ExceptionHandlerDecorator;
use Illuminate\Foundation\Application;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Client;

class Laravel5 extends Client
{
    /**
     * @var Application
     */
    private $app;

    /**
     * @var \Codeception\Module\Laravel5
     */
    private $module;

    /**
     * @var bool
     */
    private $firstRequest = true;

    /**
     * @var array
     */
    private $triggeredEvents = [];

    /**
     * @var bool
     */
    private $exceptionHandlingDisabled;

    /**
     * @var bool
     */
    private $middlewareDisabled;

    /**
     * @var bool
     */
    private $eventsDisabled;

    /**
     * @var object
     */
    private $oldDb;

    /**
     * Constructor.
     *
     * @param \Codeception\Module\Laravel5 $module
     */
    public function __construct($module)
    {
        $this->module = $module;

        $this->exceptionHandlingDisabled = $this->module->config['disable_exception_handling'];
        $this->middlewareDisabled = $this->module->config['disable_middleware'];
        $this->eventsDisabled = $this->module->config['disable_events'];

        $this->initialize();

        $components = parse_url($this->app['config']->get('app.url', 'http://localhost'));
        if (array_key_exists('url', $this->module->config)) {
            $components = parse_url($this->module->config['url']);
        }
        $host = isset($components['host']) ? $components['host'] : 'localhost';

        parent::__construct($this->app, ['HTTP_HOST' => $host]);

        // Parent constructor defaults to not following redirects
        $this->followRedirects(true);
    }

    /**
     * Execute a request.
     *
     * @param SymfonyRequest $request
     * @return Response
     */
    protected function doRequest($request)
    {
        if (!$this->firstRequest) {
            $this->initialize($request);
        }
        $this->firstRequest = false;

        $request = Request::createFromBase($request);
        $response = $this->kernel->handle($request);
        $this->app->make('Illuminate\Contracts\Http\Kernel')->terminate($request, $response);

        return $response;
    }

    /**
     * Initialize the Laravel framework.
     *
     * @param SymfonyRequest $request
     */
    private function initialize($request = null)
    {
        // Store a reference to the database object
        // so the database connection can be reused during tests
        $this->oldDb = null;
        if ($this->app['db'] && $this->app['db']->connection()) {
            $this->oldDb = $this->app['db'];
        }

        $this->app = $this->kernel = $this->loadApplication();

        // Set the request instance for the application,
        if (is_null($request)) {
            $appConfig = require $this->module->config['project_dir'] . 'config/app.php';
            $request = SymfonyRequest::create($appConfig['url']);
        }
        $this->app->instance('request', Request::createFromBase($request));

        // Reset the old database after the DatabaseServiceProvider ran.
        // This way other service providers that rely on the $app['db'] entry
        // have the correct instance available.
        if ($this->oldDb) {
            $this->app['events']->listen('Illuminate\Database\DatabaseServiceProvider', function () {
                $this->app->singleton('db', function () {
                    return $this->oldDb;
                });
            });
        }

        $this->app->make('Illuminate\Contracts\Http\Kernel')->bootstrap();

        // Record all triggered events by adding a wildcard event listener
        $this->app['events']->listen('*', function () {
            $this->triggeredEvents[] = $this->normalizeEvent($this->app['events']->firing());
        });

        // Replace the Laravel exception handler with our decorated exception handler,
        // so exceptions can be intercepted for the disable_exception_handling functionality.
        $decorator = new ExceptionHandlerDecorator($this->app['Illuminate\Contracts\Debug\ExceptionHandler']);
        $decorator->exceptionHandlingDisabled($this->exceptionHandlingDisabled);
        $this->app->instance('Illuminate\Contracts\Debug\ExceptionHandler', $decorator);

        if ($this->module->config['disable_middleware'] || $this->middlewareDisabled) {
            $this->app->instance('middleware.disable', true);
        }

        if ($this->module->config['disable_events'] || $this->eventsDisabled) {
            $this->mockEventDispatcher();
        }

        $this->module->setApplication($this->app);
    }

    /**
     * Boot the Laravel application object.
     * @return Application
     * @throws ModuleConfig
     */
    private function loadApplication()
    {
        $app = require $this->module->config['bootstrap_file'];
        $app->loadEnvironmentFrom($this->module->config['environment_file']);
        $app->instance('request', new Request());

        return $app;
    }

    /**
     * Replace the Laravel event dispatcher with a mock.
     */
    private function mockEventDispatcher()
    {
        $mockGenerator = new \PHPUnit_Framework_MockObject_Generator;
        $mock = $mockGenerator->getMock('Illuminate\Contracts\Events\Dispatcher');

        // Even if events are disabled we still want to record the triggered events.
        // But by mocking the event dispatcher the wildcard listener registered in the initialize method is removed.
        // So to record the triggered events we have to catch the calls to the fire method of the event dispatcher mock.
        $callback = function ($event) {
            $this->triggeredEvents[] = $this->normalizeEvent($event);

            return [];
        };
        $mock->expects(new \PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount)
            ->method('fire')
            ->will(new \PHPUnit_Framework_MockObject_Stub_ReturnCallback($callback));

        $this->app->instance('events', $mock);
    }

    /**
     * Normalize events to class names.
     *
     * @param $event
     * @return string
     */
    private function normalizeEvent($event)
    {
        if (is_object($event)) {
            $event = get_class($event);
        }

        if (preg_match('/^bootstrapp(ing|ed): /', $event)) {
            return $event;
        }

        // Events can be formatted as 'event.name: parameters'
        $segments = explode(':', $event);

        return $segments[0];
    }

    //======================================================================
    // Public methods called by module
    //======================================================================

    /**
     * Did an event trigger?
     *
     * @param $event
     * @return bool
     */
    public function eventTriggered($event)
    {
        $event = $this->normalizeEvent($event);

        foreach ($this->triggeredEvents as $triggeredEvent) {
            if ($event == $triggeredEvent || is_subclass_of($event, $triggeredEvent)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Disable Laravel exception handling.
     */
    public function disableExceptionHandling()
    {
        $this->exceptionHandlingDisabled = true;
        $this->app['Illuminate\Contracts\Debug\ExceptionHandler']->exceptionHandlingDisabled(true);
    }

    /**
     * Enable Laravel exception handling.
     */
    public function enableExceptionHandling()
    {
        $this->exceptionHandlingDisabled = false;
        $this->app['Illuminate\Contracts\Debug\ExceptionHandler']->exceptionHandlingDisabled(false);
    }

    /**
     * Disable events.
     */
    public function disableEvents()
    {
        $this->eventsDisabled = true;
        $this->mockEventDispatcher();
    }

    /*
     * Disable middleware.
     */
    public function disableMiddleware()
    {
        $this->middlewareDisabled = true;
        $this->app->instance('middleware.disable', true);
    }
}
<?php
namespace Codeception\Lib\Connector;

use Symfony\Component\BrowserKit\Client;
use Symfony\Component\BrowserKit\Response;
use Yii;

class Yii1 extends Client
{
    use Shared\PhpSuperGlobalsConverter;
    /**
     * http://localhost/path/to/your/app/index.php
     * @var string url of the entry Yii script
     */
    public $url;

    /**
     * Current application settings {@see Codeception\Module\Yii1::$appSettings}
     * @var array
     */
    public $appSettings;

    /**
     * Full path to your application
     * @var string
     */
    public $appPath;

    /**
     * Current request headers
     * @var array
     */
    private $_headers;

    /**
     *
     * @param \Symfony\Component\BrowserKit\Request $request
     *
     * @return \Symfony\Component\BrowserKit\Response
     */
    public function doRequest($request)
    {
        $this->_headers = array();
        $_COOKIE        = array_merge($_COOKIE, $request->getCookies());
        $_SERVER        = array_merge($_SERVER, $request->getServer());
        $_FILES         = $this->remapFiles($request->getFiles());
        $_REQUEST       = $this->remapRequestParameters($request->getParameters());
        $_POST          = $_GET = array();

        if (strtoupper($request->getMethod()) == 'GET') {
            $_GET = $_REQUEST;
        } else {
            $_POST = $_REQUEST;
        }

        // Parse url parts
        $uriPath = trim(parse_url($request->getUri(), PHP_URL_PATH), '/');
        $uriQuery = ltrim(parse_url($request->getUri(), PHP_URL_QUERY), '?');
        $scriptName = trim(parse_url($this->url, PHP_URL_PATH), '/');
        if (!empty($uriQuery)) {

            $uriPath .= "?{$uriQuery}";

            parse_str($uriQuery, $params);
            foreach ($params as $k => $v) {
                $_GET[$k] = $v;
            }
        }

        // Add script name to request if none
        if (strpos($uriPath, $scriptName) === false) {
            $uriPath = "/{$scriptName}/{$uriPath}";
        }

        // Add forward slash if not exists
        if (strpos($uriPath, '/') !== 0) {
            $uriPath = "/{$uriPath}";
        }

        $_SERVER['REQUEST_METHOD'] = strtoupper($request->getMethod());
        $_SERVER['REQUEST_URI'] = $uriPath;

        /**
         * Hack to be sure that CHttpRequest will resolve route correctly
         */
        $_SERVER['SCRIPT_NAME'] = "/{$scriptName}";
        $_SERVER['SCRIPT_FILENAME'] = $this->appPath;

        ob_start();
        Yii::setApplication(null);
        Yii::createApplication($this->appSettings['class'], $this->appSettings['config']);

        // disabling logging. Logs slow down test execution
        if (Yii::app()->hasComponent('log')) {
            foreach (Yii::app()->getComponent('log')->routes as $route) {
                $route->enabled = false;
            }
        }
        Yii::app()->onEndRequest->add([$this, 'setHeaders']);
        Yii::app()->run();

        $content = ob_get_clean();

        $headers = $this->getHeaders();
        $statusCode = 200;
        foreach ($headers as $header => $val) {
            if ($header == 'Location') {
                $statusCode = 302;
            }
        }

        $response = new Response($content, $statusCode, $this->getHeaders());

        return $response;
    }

    /**
     * Set current client headers when terminating yii application (onEndRequest)
     */
    public function setHeaders()
    {
        $this->_headers = Yii::app()->request->getAllHeaders();
    }

    /**
     * Returns current client headers
     * @return array headers
     */
    public function getHeaders()
    {
        return $this->_headers;
    }
}
<?php
namespace Codeception\Lib\Connector;

use Illuminate\Http\Request;
use Laravel\Lumen\Application;
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Client;
use Symfony\Component\HttpKernel\HttpKernelInterface;

class Lumen extends Client implements HttpKernelInterface
{

    /**
     * @var Application
     */
    private $app;

    /**
     * Constructor.
     *
     * @param Application $app
     */
    public function __construct(Application $app)
    {
        $this->app = $app;
        parent::__construct($this);
    }

    /**
     * Handle a request.
     *
     * @param SymfonyRequest $request
     * @param int $type
     * @param bool $catch
     * @return Response
     */
    public function handle(SymfonyRequest $request, $type = self::MASTER_REQUEST, $catch = true)
    {
        $this->app['request'] = $request = Request::createFromBase($request);

        $response = $this->app->handle($request);

        $method = new \ReflectionMethod(get_class($this->app), 'callTerminableMiddleware');
        $method->setAccessible(true);
        $method->invoke($this->app, $response);

        return $response;
    }
}
<?php
namespace Codeception\Lib\Connector;

use Symfony\Component\BrowserKit\Client;
use Symfony\Component\BrowserKit\Response;
use Symfony\Component\BrowserKit\Request as BrowserKitRequest;

class ZF1 extends Client
{
    use Shared\PhpSuperGlobalsConverter;

    /**
     * @var \Zend_Controller_Front
     */
    protected $front;

    /**
     * @var \Zend_Application
     */
    protected $bootstrap;

    /**
     * @var  \Zend_Controller_Request_HttpTestCase
     */
    protected $zendRequest;

    public function setBootstrap($bootstrap)
    {
        $this->bootstrap = $bootstrap;

        $this->front = $this->bootstrap
            ->getBootstrap()
            ->getResource('frontcontroller');
        $this->front
            ->throwExceptions(true)
            ->returnResponse(false);
    }

    public function doRequest($request)
    {

        // redirector should not exit
        $redirector = \Zend_Controller_Action_HelperBroker::getStaticHelper('redirector');
        $redirector->setExit(false);

        // json helper should not exit
        $json = \Zend_Controller_Action_HelperBroker::getStaticHelper('json');
        $json->suppressExit = true;

        $zendRequest = new \Zend_Controller_Request_HttpTestCase();
        $zendRequest->setMethod($request->getMethod());
        $zendRequest->setCookies($request->getCookies());
        $zendRequest->setParams($request->getParameters());
        // Sf2's BrowserKit does not distinguish between GET, POST, PUT etc.,
        // so we set all parameters in ZF's request here to not break apps
        // relying on $request->getPost()
        $zendRequest->setPost($request->getParameters());
        $zendRequest->setRawBody($request->getContent());

        $uri = $request->getUri();
        $queryString = parse_url($uri, PHP_URL_QUERY);
        $requestUri = parse_url($uri, PHP_URL_PATH);
        if (!empty($queryString)) {
            $requestUri .= '?' . $queryString;
        }
        $zendRequest->setRequestUri($requestUri);

        $zendRequest->setHeaders($this->extractHeaders($request));
        $_FILES  = $this->remapFiles($request->getFiles());
        $_SERVER = array_merge($_SERVER, $request->getServer());

        $zendResponse = new \Zend_Controller_Response_HttpTestCase;
        $this->front->setRequest($zendRequest)->setResponse($zendResponse);

        ob_start();
        try {
            $this->bootstrap->run();
            $_GET = $_POST = [];
        } catch (\Exception $e) {
            ob_end_clean();
            $_GET = $_POST = [];
            throw $e;
        }
        ob_end_clean();

        $this->zendRequest = $zendRequest;

        $response = new Response(
            $zendResponse->getBody(),
            $zendResponse->getHttpResponseCode(),
            $this->formatResponseHeaders($zendResponse)
        );

        return $response;
    }

    /**
     * Format up the ZF1 response headers into Symfony\Component\BrowserKit\Response headers format.
     *
     * @param \Zend_Controller_Response_Abstract $response The ZF1 Response Object.
     * @return array the clean key/value headers
     */
    private function formatResponseHeaders (\Zend_Controller_Response_Abstract $response) {
        $headers = array();
        foreach ($response->getHeaders() as $header) {
            $name = $header['name'];
            if (array_key_exists($name, $headers)) {
                if ($header['replace']) {
                    $headers[$name] = $header['value'];
                }
            } else {
                $headers[$name] = $header['value'];
            }
        }
        return $headers;
    }


    /**
     * @return \Zend_Controller_Request_HttpTestCase
     */
    public function getZendRequest()
    {
        return $this->zendRequest;
    }

    private function extractHeaders(BrowserKitRequest $request)
    {
        $headers = [];
        $server = $request->getServer();

        $contentHeaders = array('Content-Length' => true, 'Content-Md5' => true, 'Content-Type' => true);
        foreach ($server as $header => $val) {
            $header = implode('-', array_map('ucfirst', explode('-', strtolower(str_replace('_', '-', $header)))));

            if (strpos($header, 'Http-') === 0) {
                $headers[substr($header, 5)] = $val;
            } elseif (isset($contentHeaders[$header])) {
                $headers[$header] = $val;
            }
        }
        return $headers;
    }
}
<?php
namespace Codeception\Lib\Connector;

use Symfony\Component\BrowserKit\Client;
use Symfony\Component\BrowserKit\Response;

class Universal extends Client
{
    use Shared\PhpSuperGlobalsConverter;

    protected $mockedResponse;
    protected $index;

    public function setIndex($index)
    {
        $this->index = $index;
    }

    public function mockResponse($response)
    {
        $this->mockedResponse = $response;
    }

    public function doRequest($request)
    {
        if ($this->mockedResponse) {
            $response = $this->mockedResponse;
            $this->mockedResponse = null;
            return $response;
        }

        $_COOKIE = $request->getCookies();
        $_SERVER = $request->getServer();
        $_FILES = $this->remapFiles($request->getFiles());

        $uri = str_replace('http://localhost', '', $request->getUri());

        $_REQUEST = $this->remapRequestParameters($request->getParameters());
        if (strtoupper($request->getMethod()) == 'GET') {
            $_GET = $_REQUEST;
        } else {
            $_POST = $_REQUEST;
        }

        $_SERVER['REQUEST_METHOD'] = strtoupper($request->getMethod());
        $_SERVER['REQUEST_URI'] = $uri;

        ob_start();
        include $this->index;

        $content = ob_get_contents();
        ob_end_clean();

        $headers = [];
        $php_headers = headers_list();
        foreach ($php_headers as $value) {
            // Get the header name
            $parts = explode(':', $value);
            if (count($parts) > 1) {
                $name = trim(array_shift($parts));
                // Build the header hash map
                $headers[$name] = trim(implode(':', $parts));
            }
        }
        $headers['Content-type'] = isset($headers['Content-type']) ? $headers['Content-type'] : "text/html; charset=UTF-8";

        $response = new Response($content, 200, $headers);
        return $response;
    }
}
<?php
namespace Codeception\Lib\Connector;

use Codeception\Lib\Connector\ZendExpressive\ResponseCollector;
use Symfony\Component\BrowserKit\Client;
use Symfony\Component\BrowserKit\Request;
use Symfony\Component\BrowserKit\Response;
use Symfony\Component\BrowserKit\Request as BrowserKitRequest;
use Zend\Diactoros\ServerRequest;
use Zend\Diactoros\Response as ZendResponse;
use Zend\Expressive\Application;

class ZendExpressive extends Client
{

    /**
     * @var Application
     */
    protected $application;

    /**
     * @var ResponseCollector
     */
    protected $responseCollector;

    /**
     * @param Application
     */
    public function setApplication(Application $application)
    {
        $this->application = $application;
    }

    /**
     * @param ResponseCollector $responseCollector
     */
    public function setResponseCollector(ResponseCollector $responseCollector)
    {
        $this->responseCollector = $responseCollector;
    }

    /**
     * @param Request $request
     *
     * @return Response
     * @throws \Exception
     */
    public function doRequest($request)
    {
        $inputStream = fopen('php://memory', 'r+');
        $content = $request->getContent();
        if ($content !== null) {
            fwrite($inputStream, $content);
            rewind($inputStream);
        }

        $queryParams = [];
        $postParams = [];
        $queryString = parse_url($request->getUri(), PHP_URL_QUERY);
        if ($queryString != '') {
            parse_str($queryString, $queryParams);
        }
        if ($request->getMethod() !== 'GET') {
            $postParams = $request->getParameters();
        }

        $serverParams = $request->getServer();
        if (!isset($serverParams['SCRIPT_NAME'])) {
            //required by WhoopsErrorHandler
            $serverParams['SCRIPT_NAME'] = 'Codeception';
        }

        $zendRequest = new ServerRequest(
            $serverParams,
            $request->getFiles(),
            $request->getUri(),
            $request->getMethod(),
            $inputStream,
            $this->extractHeaders($request)
        );

        $zendRequest = $zendRequest->withCookieParams($request->getCookies())
            ->withQueryParams($queryParams)
            ->withParsedBody($postParams);

        $cwd = getcwd();
        chdir(codecept_root_dir());
        $this->application->run($zendRequest);
        chdir($cwd);

        $this->request = $zendRequest;

        $response = $this->responseCollector->getResponse();
        $this->responseCollector->clearResponse();

        return new Response(
            $response->getBody(),
            $response->getStatusCode(),
            $response->getHeaders()
        );
    }

    private function extractHeaders(BrowserKitRequest $request)
    {
        $headers = [];
        $server = $request->getServer();

        $contentHeaders = array('Content-Length' => true, 'Content-Md5' => true, 'Content-Type' => true);
        foreach ($server as $header => $val) {
            $header = implode('-', array_map('ucfirst', explode('-', strtolower(str_replace('_', '-', $header)))));

            if (strpos($header, 'Http-') === 0) {
                $headers[substr($header, 5)] = $val;
            } elseif (isset($contentHeaders[$header])) {
                $headers[$header] = $val;
            }
        }

        return $headers;
    }
}
<?php
namespace Codeception\Lib\Driver;

class Oci extends Db
{

    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;"
        );
    }

    /**
     * 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->sqlToRun = substr($query, 0, -1 * $delimiterLength);
                $this->sqlQuery($this->sqlToRun);
                $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;

use Codeception\Exception\ModuleConfigException;
use Codeception\Exception\ModuleException;

class MongoDb
{
    private $dbh;
    private $dsn;
    private $dbName;
    private $host;
    private $user;
    private $password;
    private $client;

    public static function connect($dsn, $user, $password)
    {
        throw new \Exception(__CLASS__ . '::connect() - hm, it looked like this method had become obsolete...');
    }

    /**
     * $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)
    {
        /* defining DB name */
        $this->dbName = 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 (false !== strpos($dsn, 'mongodb://')) {
            $this->host = str_replace('mongodb://', '', $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
            ];
        }

        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()));
        }

        $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()
    {
        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()));
            }
        }
    }

    /**
     * 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)
    {
        if ($this->user && $this->password) {
            $cmd = sprintf(
                'mongo %s --username %s --password %s %s',
                $this->host . '/' . $this->dbName,
                $this->user,
                $this->password,
                escapeshellarg($dumpFile)
            );
        } else {
            $cmd = sprintf('mongo %s %s', $this->host . '/' . $this->dbName, escapeshellarg($dumpFile));
        }
        shell_exec($cmd);
    }

    public function getDbh()
    {
        return $this->dbh;
    }

    public function setDatabase($dbName)
    {
        $this->dbh = $this->client->selectDB($dbName);
    }
}
<?php
namespace Codeception\Lib\Driver;

use Codeception\Configuration;

class Sqlite extends Db
{
    protected $hasSnapshot = false;
    protected $filename = '';
    protected $con = null;

    public function __construct($dsn, $user, $password)
    {
        $this->filename = Configuration::projectDir() . substr($dsn, 7);
        $this->dsn = 'sqlite:' . $this->filename;
        parent::__construct($this->dsn, $user, $password);
    }

    public function cleanup()
    {
        $this->dbh = null;
        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;
            file_put_contents($this->filename, file_get_contents($this->filename . '_snapshot'));
            $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])) {
            $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];
    }
}
<?php
namespace Codeception\Lib\Driver;

use Codeception\Exception\ModuleException;

class PostgreSql extends Db
{
    protected $putline = false;

    protected $connection = null;

    protected $searchPath = null;

    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;
            }

            if (!preg_match('/\'.*\$\$.*\'/', $sqlLine)) { // Ignore $$ inside SQL standard string syntax such as in INSERT statements.
                $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->sqlToRun = substr($query, 0, -1 * $delimiterLength);
                $this->sqlQuery($this->sqlToRun);
                $query = "";
            }
        }
    }

    public function cleanup()
    {
        $tables = $this->dbh
            ->query("SELECT 'DROP TABLE IF EXISTS \"' || tablename || '\" cascade;' FROM pg_tables WHERE schemaname = 'public';")
            ->fetchAll();

        $sequences = $this->dbh
            ->query("SELECT 'DROP SEQUENCE IF EXISTS \"' || relname || '\" cascade;' FROM pg_class WHERE relkind = 'S';")
            ->fetchAll();

        $types = $this->dbh
            ->query("SELECT 'DROP TYPE IF EXISTS \"' || t.typname || '\" cascade;' FROM pg_catalog.pg_type t LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace WHERE (t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid) AND n.nspname <> 'pg_catalog' AND n.nspname <> 'information_schema' AND pg_catalog.pg_type_is_visible(t.oid);")
            ->fetchAll();

        $drops = array_merge($tables, $sequences, $types);
        if ($drops) {
            foreach ($drops as $drop) {
                $this->dbh->exec($drop[0]);
            }
        }
    }

    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);
        }
    }

    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');
        return $this->getDbh()->lastInsertId($sequenceName);
    }

    public function getQuotedName($name)
    {
        $name = explode('.', $name);
        $name = array_map(
            function ($data) {
                return '"' . $data . '"';
            },
            $name
        );
        return implode('.', $name);
    }

    /**
     * @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 = ?::regclass
                AND    i.indisprimary';
            $stmt = $this->executeQuery($query, [$tableName]);
            $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;

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 RedisException extends \Exception
{
}

/**
 * Redis database connection class
 *
 * @author sash
 * @license LGPL
 * @version 1.2
 */
class Redis
{
    private $port;
    private $host;
    private $_sock;
    public $debug = false;

    function __construct($host = 'localhost', $port = 6379)
    {
        $this->host = $host;
        $this->port = $port;
    }

    private function connect()
    {
        if ($this->_sock) {
            return;
        }
        if ($sock = fsockopen($this->host, $this->port, $errno, $errmsg)) {
            $this->_sock = $sock;
            $this->debug('Connected');
            return;
        }
        $msg = "Cannot open socket to {$this->host}:{$this->port}";
        if (($errno !== 0) || ($errmsg !== null)) {
            $msg .= "," . ($errno ? " error $errno" : "") . ($errmsg ? " $errmsg" : "");
        }
        throw new RedisException ("$msg.");
    }

    private function debug($msg)
    {
        if ($this->debug) {
            codecept_debug("[Redis] %s\n", $msg);
        }
    }

    private function read()
    {
        if ($s = fgets($this->_sock)) {
            $this->debug('Read: ' . $s . ' (' . strlen($s) . ' bytes)');
            return $s;
        }
        $this->disconnect();
        throw new RedisException ("Cannot read from socket.");
    }

    private function cmdResponse()
    {
        // Read the response
        $s = trim($this->read());
        switch ($s[0]) {
            case '-' : // Error message
                throw new RedisException (substr($s, 1));
                break;
            case '+' : // Single line response
                return substr($s, 1);
            case ':' : //Integer number
                return substr($s, 1) + 0;
            case '$' : //Bulk data response
                $i = ( int )(substr($s, 1));
                if ($i == -1) {
                    return null;
                }
                $buffer = '';
                if ($i == 0) {
                    $this->read();
                }
                while ($i > 0) {
                    $s = $this->read();
                    $l = strlen($s);
                    $i -= $l;
                    if ($i < 0) {
                        $s = substr($s, 0, $i);
                    }
                    $buffer .= $s;
                }
                return $buffer;
                break;
            case '*' : // Multi-bulk data (a list of values)
                $i = ( int )(substr($s, 1));
                if ($i == -1) {
                    return null;
                }
                $res = [];
                for ($c = 0; $c < $i; $c++) {
                    $res [] = $this->cmdResponse();
                }
                return $res;
                break;
            default :
                throw new RedisException ('Unknown response line: ' . $s);
                break;
        }
    }

    private $pipeline = false;
    private $pipeline_commands = 0;

    function pipeline_begin()
    {
        $this->pipeline = true;
        $this->pipeline_commands = 0;
    }

    function pipeline_responses()
    {
        $response = [];
        for ($i = 0; $i < $this->pipeline_commands; $i++) {
            $response[] = $this->cmdResponse();
        }
        $this->pipeline = false;
        return $response;
    }

    private function cmd($command)
    {
        $this->debug('Command: ' . (is_array($command) ? join(', ', $command) : $command));
        $this->connect();

        if (is_array($command)) {
            // Use unified command format

            $s = '*' . count($command) . "\r\n";
            foreach ($command as $m) {
                $s .= '$' . strlen($m) . "\r\n";
                $s .= $m . "\r\n";
            }
        } else {
            $s = $command . "\r\n";
        }
        while ($s) {
            $i = fwrite($this->_sock, $s);
            if ($i == 0) {
                break;
            }
            $s = substr($s, $i);
        }
        if ($this->pipeline) {
            $this->pipeline_commands++;
            return null;
        } else {
            return $this->cmdResponse();
        }
    }

    function disconnect()
    {
        if ($this->_sock) {
            @fclose($this->_sock);
        }
        $this->_sock = null;
    }

    ////////////////////////////////
    ///// Connection handling
    ////////////////////////////////

    /**
     * close the connection
     *
     * Ask the server to silently close the connection.
     *
     * @return void The connection is closed as soon as the QUIT command is received.
     */
    function quit()
    {
        return $this->cmd('QUIT');
    }

    /**
     * simple password authentication if enabled
     *
     * Request for authentication in a password protected Redis server. A Redis server
     * can be instructed to require a password before to allow clients to issue commands.
     * This is done using the requirepass directive in the Redis configuration file.
     *
     * If the password given by the client is correct the server replies with an
     * OK status code reply and starts accepting commands from the client. Otherwise
     * an error is returned and the clients needs to try a new password. Note that for
     * the high performance nature of Redis it is possible to try a lot of passwords in
     * parallel in very short time, so make sure to generate a strong and very long password
     * so that this attack is infeasible.
     *
     * @param $password
     *
     * @return string Status code reply
     */
    function auth($password)
    {
        return $this->cmd(['AUTH', $password]);
    }

    ////////////////////////////////
    ///// Commands operating on string values
    ////////////////////////////////
    /**
     * set a key to a string value
     *
     * Time complexity: O(1)
     *
     * Set the string value as value of the key. The string can't be longer than 1073741824 bytes (1 GB).
     *
     * @param $key
     * @param $value
     * @param $preserve USE SETNX don't perform the operation if the target key already exists.
     *
     * @return string Status code reply
     */
    function set($key, $value, $preserve = false)
    {
        return $this->cmd([($preserve ? 'SETNX' : 'SET'), $key, $value]);
    }

    /**
     * return the string value of the key
     *
     * GET
     * Get the value of the specified key. If the key does not exist the special
     * value 'nil' is returned. If the value stored at key is not a string an
     * error is returned because GET can only handle string values.
     *
     * MGET - Time complexity: O(1) for every key
     * Get the values of all the specified keys. If one or more keys dont exist
     * or is not of type String, a 'nil' value is returned instead of the value
     * of the specified key, but the operation never fails.
     *
     * USAGES:
     *  $this->get('key1')
     *  $this->get(array('key1','key2'))
     *  $this->get('key1','key2')
     *
     * @param mixed $key
     *
     * @return mixed Bulk reply | Multi bulk reply
     */
    function get($key)
    {
        $args = func_get_args();
        if (count($args) > 1) {
            $key = $args;
        }
        if (is_array($key)) {
            array_unshift($key, "MGET");
            return $this->cmd($key);
        } else {
            return $this->cmd(["GET", $key]);
        }
    }

    function __get($key)
    {
        return $this->get($key);
    }

    function __set($key, $value)
    {
        return $this->set($key, $value);
    }

    /**
     * set a key to a string returning the old value of the key
     *
     * GETSET is an atomic set this value and return the old value command. Set key
     * to the string value and return the old value stored at key. The string can't be
     * longer than 1073741824 bytes (1 GB).
     *
     * Design patterns
     * GETSET can be used together with INCR for counting with atomic reset when a
     * given condition arises. For example a process may call INCR against the key
     * mycounter every time some event occurred, but from time to time we need to get
     * the value of the counter and reset it to zero atomically using GETSET mycounter 0.
     *
     * @param $key
     * @param $value
     *
     * @return string Bulk reply
     */
    function getset($key, $value)
    {
        return $this->cmd(["GETSET", $key, $value]);
    }

    /**
     * increment the integer value of key
     *
     * Time complexity: O(1)
     *
     * Increment or decrement the number stored at key by one. If the key does not exist
     * or contains a value of a wrong type, set the key to the value of "0" before to
     * perform the increment or decrement operation.
     *
     * INCRBY and DECRBY work just like INCR and DECR but instead to increment/decrement
     * by 1 the increment/decrement is integer.
     *
     * @param $key
     * @param $amount
     *
     * @return int this commands will reply with the new value of key after the increment or decrement.
     */
    function incr($key, $amount = 1)
    {
        if ($amount == 1) {
            return $this->cmd(["INCR", $key]);
        } else {
            return $this->cmd(["INCRBY", $key, $amount]);
        }
    }

    /**
     * decrement the integer value of key
     *
     * Time complexity: O(1)
     * Increment or decrement the number stored at key by one. If the key does not exist
     * or contains a value of a wrong type, set the key to the value of "0" before to
     * perform the increment or decrement operation.
     *
     * INCRBY and DECRBY work just like INCR and DECR but instead to increment/decrement
     * by 1 the increment/decrement is integer.
     *
     * @param $key
     * @param $amount
     *
     * @return int this commands will reply with the new value of key after the increment or decrement.
     */
    function decr($key, $amount = 1)
    {
        if ($amount == 1) {
            return $this->cmd(["DECR", $key]);
        } else {
            return $this->cmd(["DECRBY", $key, $amount]);
        }
    }

    /**
     * test if a key exists
     *
     * Time complexity: O(1)
     * Test if the specified key exists. The command returns "0" if the key exists,
     * otherwise "1" is returned. Note that even keys set with an empty string as
     * value will return "1".
     *
     * @param $key
     *
     * @return int
     */
    function exists($key)
    {
        return $this->cmd(["EXISTS", $key]);
    }

    function __isset($key)
    {
        return $this->exists($key);
    }

    /**
     * delete a key
     *
     * Time complexity: O(1)
     * Remove the specified key. If the key does not exist no operation is performed.
     * The command always returns success.
     *
     * @param $key
     *
     * @return int
     */
    function delete($key)
    {
        return $this->cmd(["DEL", $key]);
    }

    function __unset($key)
    {
        return $this->delete($key);
    }

    /**
     * return the type of the value stored at key
     *
     * Time complexity: O(1)
     * Return the type of the value stored at key in form of a string. The type can
     * be one of "none", "string", "list", "set". "none" is returned if the key does not exist.
     *
     * @param $key
     *
     * @return string
     */
    function type($key)
    {
        return $this->cmd(["TYPE", $key]);
    }

    ////////////////////////////////
    ///// Commands operating on the key space
    ////////////////////////////////
    /**
     * return all the keys matching a given pattern
     *
     * @param $pattern
     *
     * @return string space separated list of keys
     */
    function keys($pattern)
    {
        return $this->cmd(["KEYS", $pattern]);
    }

    /**
     * return a random key from the key space
     *
     * @return unknown_type
     */
    function randomkey()
    {
        return $this->cmd("RANDOMKEY");
    }

    /**
     * rename the old key in the new one, destroying the newname key if it already exists if if $preserve - if the dst does not already exist
     *
     * Time complexity: O(1)
     * Atomically renames the key oldkey to newkey. If the source and destination name are the same an error is returned. If newkey already exists it is overwritten.
     *
     * @param $src
     * @param $dst
     * @param $preserve
     *
     * @return string Status code repy
     */
    function rename($src, $dst, $preserve = false)
    {
        if ($preserve) {
            return $this->cmd(["RENAMENX", $src, $dst]);
        }
        return $this->cmd(["RENAME", $src, $dst]);
    }

    /**
     * return the number of keys in the current db
     * @return int
     */
    function dbsize()
    {
        return $this->cmd("DBSIZE");
    }

    /**
     * set a time to live in seconds on a key
     *
     * @param string $key
     * @param int $ttl in seconds
     *
     * @return int 1: the timeout was set. | 0: the timeout was not set since the key already has an associated timeout, or the key does not exist.
     */
    function expire($key, $ttl)
    {
        return $this->cmd(["EXPIRE", $key, $ttl]);
    }

    /**
     * get the time to live in seconds of a key
     *
     * @param $key
     *
     * @return int
     */
    function ttl($key)
    {
        return $this->cmd(["TTL", $key]);
    }

    ////////////////////////////////
    ///// Commands operating on lists
    ////////////////////////////////

    /**
     * Append an element to the tail of the List value at key
     * if $tail == false - Append an element to the head of the List value at key
     *
     * @param $key
     * @param $value
     * @param $tail
     *
     * @return unknown_type
     */
    function push($key, $value, $tail = true)
    {
        // default is to append the element to the list
        return $this->cmd([$tail ? 'RPUSH' : 'LPUSH', $key, $value]);
    }

    /**
     * Return the length of the List value at key
     *
     * @param $key
     *
     * @return unknown_type
     */
    function llen($key)
    {
        return $this->cmd(["LLEN", $key]);
    }

    /**
     * Return a range of elements from the List at key
     *
     * @param $key
     * @param $start
     * @param $end
     *
     * @return unknown_type
     */
    function lrange($key, $start, $end)
    {
        return $this->cmd(["LRANGE", $key, $start, $end]);
    }

    /**
     * Trim the list at key to the specified range of elements
     *
     * @param $key
     * @param $start
     * @param $end
     *
     * @return unknown_type
     */
    function ltrim($key, $start, $end)
    {
        return $this->cmd(["LTRIM", $key, $start, $end]);
    }

    /**
     * Return the element at index position from the List at key
     *
     * @param $key
     * @param $index
     *
     * @return unknown_type
     */
    function lindex($key, $index)
    {
        return $this->cmd(["LINDEX", $key, $index]);
    }

    /**
     * Set a new value as the element at index position of the List at key
     *
     * @param $key
     * @param $value
     * @param $index
     *
     * @return unknown_type
     */
    function lset($key, $value, $index)
    {
        return $this->cmd(["LSET", $key, $index, $value]);
    }

    /**
     * Remove the first-N, last-N, or all the elements matching value from the List at key
     *
     * Time complexity: O(N) (with N being the length of the list)
     *
     * Remove the first count occurrences of the value element from the list.
     * If count is zero all the elements are removed. If count is negative elements
     * are removed from tail to head, instead to go from head to tail that is the
     * normal behaviour. So for example LREM with count -2 and hello as value to remove
     * against the list (a,b,c,hello,x,hello,hello) will lave the list (a,b,c,hello,x).
     * The number of removed elements is returned as an integer, see below for more
     * information about the returned value. Note that non existing keys are considered
     * like empty lists by LREM, so LREM against non existing keys will always return 0.
     *
     * @param $key
     * @param $value
     * @param $count
     *
     * @return int The number of removed elements if the operation succeeded
     */
    function lrem($key, $value, $count = 1)
    {
        return $this->cmd(["LREM", $key, $count, $value]);
    }

    /**
     * Return and remove (atomically) the last (first if not tail) element of the List at key
     *
     * @param $key
     * @param $tail
     *
     * @return string Bulk reply
     */
    function pop($key, $tail = true)
    {
        return $this->cmd([$tail ? 'RPOP' : 'LPOP', $key]);
    }


    ////////////////////////////////
    ///// Commands operating on sets
    ////////////////////////////////

    /**
     * Add the specified member to the Set value at name
     *
     * @param $key
     * @param $value
     *
     * @return unknown_type
     */
    function sadd($key, $value)
    {
        return $this->cmd(["SADD", $key, $value]);
    }

    /**
     * Remove the specified member from the Set value at name
     *
     * @param $key
     * @param $value
     *
     * @return unknown_type
     */
    function srem($key, $value)
    {
        return $this->cmd(["SREM", $key, $value]);
    }

    /**
     * Remove and return (pop) a random element from the Set value at key
     *
     * @return string
     */
    function spop($key)
    {
        return $this->cmd(["SPOP", $key]);
    }

    /**
     * Move the specified member from one Set to another atomically
     *
     * @param $srckey
     * @param $dstkey
     * @param $member
     *
     * @return int 1 if the element was moved | 0 if the element was not found on the first set and no operation was performed
     */
    function smove($srckey, $dstkey, $member)
    {
        $this->cmd(["SMOVE", $srckey, $dstkey, $member]);
    }

    /**
     * Return the number of elements (the cardinality) of the Set at key
     *
     * @param $key
     *
     * @return int
     */
    function scard($key)
    {
        return $this->cmd(["SCARD", $key]);
    }

    /**
     * Test if the specified value is a member of the Set at key
     *
     * @param $key
     * @param $value
     *
     * @return int
     */
    function sismember($key, $value)
    {
        return $this->cmd(["SISMEMBER", $key, $value]);
    }

    /**
     * Return the intersection between the Sets stored at key1, key2, ..., keyN
     *
     * @param $key1
     *
     * @return array
     */
    function sinter($key1)
    {
        if (is_array($key1)) {
            $sets = $key1;
        } else {
            $sets = func_get_args();
        }
        array_unshift($sets, 'SINTER');
        return $this->cmd($sets);
    }

    /**
     * Compute the intersection between the Sets stored at key1, key2, ..., keyN, and store the resulting
     *
     * @param $dstkey
     * @param $key1
     *
     * @return string Status code reply
     */
    function sinterstore($dstkey, $key1)
    {
        if (is_array($key1)) {
            $sets = $key1;
            array_unshift($sets, $dstkey);
        } else {
            $sets = func_get_args();
        }
        array_unshift($sets, 'SINTERSTORE');
        return $this->cmd($sets);
    }

    /**
     * Return the union between the Sets stored at key1, key2, ..., keyN
     *
     * @param $key1
     *
     * @return array
     */
    function sunion($key1)
    {
        if (is_array($key1)) {
            $sets = $key1;
        } else {
            $sets = func_get_args();
        }
        array_unshift($sets, 'SUNION');
        return $this->cmd($sets);
    }

    /**
     * Compute the union between the Sets stored at key1, key2, ..., keyN, and store the resulting Set at dstkey
     *
     * @param $dstkey
     * @param $key1
     *
     * @return string Status code reply
     */
    function sunionstore($dstkey, $key1)
    {
        if (is_array($key1)) {
            $sets = $key1;
            array_unshift($sets, $dstkey);
        } else {
            $sets = func_get_args();
        }
        array_unshift($sets, 'SUNIONSTORE');
        return $this->cmd($sets);
    }

    /**
     * Return the difference between the Set stored at key1 and all the Sets key2, ..., keyN
     *
     * @param $key1
     *
     * @return array
     */
    function sdiff($key1)
    {
        if (is_array($key1)) {
            $sets = $key1;
        } else {
            $sets = func_get_args();
        }
        array_unshift($sets, 'SDIFF');
        return $this->cmd($sets);
    }

    /**
     * Compute the difference between the Set key1 and all the Sets key2, ..., keyN, and store the resulting Set at dstkey
     *
     * @param $dstkey
     * @param $key1
     *
     * @return string Status code reply
     */
    function sdiffstore($dstkey, $key1)
    {
        if (is_array($key1)) {
            $sets = $key1;
            array_unshift($sets, $dstkey);
        } else {
            $sets = func_get_args();
        }
        array_unshift($sets, 'SDIFFSTORE');
        return $this->cmd($sets);
    }

    /**
     * Return all the members of the Set value at key
     *
     * @param $key
     *
     * @return array
     */
    function smembers($key)
    {
        return $this->cmd(["SMEMBERS", $key]);
    }


    ////////////////////////////////
    ///// Multiple databases handling commands
    ////////////////////////////////

    /**
     * Select the DB having the specified index
     *
     * @param $key
     *
     * @return string Status code reply
     */
    function select_db($key)
    {
        return $this->cmd(["SELECT", $key]);
    }

    /**
     * Move the key from the currently selected DB to the DB having as index dbindex
     *
     * @param $key
     * @param $db
     *
     * @return int 1 if the key was moved | 0 if the key was not moved because already present on the target DB or was not found in the current DB.
     */
    function move($key, $db)
    {
        return $this->cmd(["MOVE", $key, $db]);
    }

    /**
     * Remove all the keys of the currently selected DB
     * @return string Status code reply
     */
    function flushdb()
    {
        return $this->cmd("FLUSHDB");
    }

    /**
     * Remove all the keys from all the databases
     * @return string Status code reply
     */
    function flushall()
    {
        return $this->cmd("FLUSHALL");
    }


    ////////////////////////////////
    ///// Sorting
    ////////////////////////////////
    /**
     * Sort a Set or a List accordingly to the specified parameters
     *
     * @param $key
     * @param $query BY pattern LIMIT start end GET pattern ASC|DESC ALPHA
     *
     * @return array
     */
    function sort($key, $query = false)
    {
        if ($query === false) {
            return $this->cmd(["SORT", $key]);
        } else {
            return $this->cmd(["SORT", $key, $query]);
        }
    }


    ////////////////////////////////
    ///// Persistence control commands
    ////////////////////////////////

    /**
     * Synchronously save the DB on disk (if background = Asynchronously save the DB on disk)
     *
     * @param $background
     *
     * @return string Status code reply
     */
    function save($background = false)
    {
        return $this->cmd(($background ? "BGSAVE" : "SAVE"));
    }

    /**
     * Return the UNIX time stamp of the last successfully saving of the dataset on disk
     * @return int
     */
    function lastsave()
    {
        return $this->cmd("LASTSAVE");
    }

    /**
     * Synchronously save the DB on disk, then shutdown the server
     * @return string Status code reply on error. On success nothing is returned since the server quits and the connection is closed.
     */
    function shutdown()
    {
        return $this->cmd("SHUTDOWN");
    }

    ////////////////////////////////
    ///// Remote server control commands
    ////////////////////////////////
    /**
     * Provide information and statistics about the server
     *
     * @param $section
     *
     * @return unknown_type
     */
    function info($section = false)
    {
        if ($section === false) {
            return $this->cmd("INFO");
        } else {
            return $this->cmd(["INFO", $section]);
        }
    }

    /**
     * Change the replication settings
     *
     * The SLAVEOF command can change the replication settings of a slave on the fly.
     * If a Redis server is already acting as slave, the command SLAVEOF NO ONE will turn
     * off the replication turning the Redis server into a MASTER. In the proper form SLAVEOF
     * hostname port will make the server a slave of the specific server listening at the
     * specified hostname and port.
     *
     * If a server is already a slave of some master, SLAVEOF hostname port will stop
     * the replication against the old server and start the synchronization against the
     *  new one discarding the old dataset.
     *
     * The form SLAVEOF no one will stop replication turning the server into a MASTER
     * but will not discard the replication. So if the old master stop working it is
     *  possible to turn the slave into a master and set the application to use the
     *  new master in read/write. Later when the other Redis server will be fixed it
     *  can be configured in order to work as slave.
     *
     * @return string Status code reply
     */
    function slaveof($host = null, $port = 6379)
    {
        return $this->cmd(['SLAVEOF', $host ? "$host $port" : 'no one']);
    }

    ////////////////////////////////
    ///// MISC
    ////////////////////////////////
    function ping()
    {
        return $this->cmd("PING");
    }

    function do_echo($s)
    {
        return $this->cmd(["ECHO", $s]);
    }

    /**
     * Call any non-implemented function of redis using the new unified request protocol
     *
     * @param string $name
     * @param array $params
     */
    function __call($name, $params)
    {
        array_unshift($params, strtoupper($name));
        return $this->cmd($params);
    }
}
<?php
namespace Codeception\Lib\Driver;

use Codeception\Exception\TestRuntime;
use Codeception\Lib\Interfaces\Queue;
use Aws\Sqs\SqsClient;
use Aws\Common\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'];
        }

        $this->queue = SqsClient::factory($params);
        if (!$this->queue) {
            throw new TestRuntime('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 TestRuntime('queue [' . $queue . '] not found');
    }

    public function getRequiredConfig()
    {
        return ['region'];
    }

    public function getDefaultConfig()
    {
        return [];
    }
}
<?php
namespace Codeception\Lib\Driver;

use Codeception\Lib\Interfaces\Queue;

class Beanstalk implements Queue
{

    /**
     * @var \Pheanstalk_Pheanstalk
     */
    protected $queue;

    public function openConnection($config)
    {
        $this->queue = new \Pheanstalk_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 (\Pheanstalk_Exception_ServerException $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 (\Pheanstalk_Exception_ServerException $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\Lib\Driver;

class Db
{
    /**
     * @var \PDO
     */
    protected $dbh;

    /**
     * @var string
     */
    protected $dsn;

    protected $user;
    protected $password;

    /**
     * @var string
     */
    public $sqlToRun;

    /**
     * associative array with table name => primary-key
     *
     * @var array
     */
    protected $primaryKeys = [];

    public static function connect($dsn, $user, $password)
    {
        $dbh = new \PDO($dsn, $user, $password);
        $dbh->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);

        return $dbh;
    }

    /**
     * @static
     *
     * @param $dsn
     * @param $user
     * @param $password
     *
     * @return Db|SqlSrv|MySql|Oci|PostgreSql|Sqlite
     */
    public static function create($dsn, $user, $password)
    {
        $provider = self::getProvider($dsn);

        switch ($provider) {
            case 'sqlite':
                return new Sqlite($dsn, $user, $password);
            case 'mysql':
                return new MySql($dsn, $user, $password);
            case 'pgsql':
                return new PostgreSql($dsn, $user, $password);
            case 'mssql':
            case 'dblib':
            case 'sqlsrv':
                return new SqlSrv($dsn, $user, $password);
            case 'oci':
                return new Oci($dsn, $user, $password);
            default:
                return new Db($dsn, $user, $password);
        }
    }

    public static function getProvider($dsn)
    {
        return substr($dsn, 0, strpos($dsn, ':'));
    }

    public function __construct($dsn, $user, $password)
    {
        $this->dbh = new \PDO($dsn, $user, $password);
        $this->dbh->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);

        $this->dsn = $dsn;
        $this->user = $user;
        $this->password = $password;
    }

    public function getDbh()
    {
        return $this->dbh;
    }

    public function getDb()
    {
        $matches = [];
        $matched = preg_match('~dbname=(.*);~s', $this->dsn, $matches);
        if (!$matched) {
            return false;
        }

        return $matches[1];
    }

    public function cleanup()
    {
    }

    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->sqlToRun = substr($query, 0, -1 * $delimiterLength);
                $this->sqlQuery($this->sqlToRun);
                $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);
    }

    protected function generateWhereClause(array &$criteria)
    {
        if (empty($criteria)) {
            return '';
        }

        $params = [];
        foreach ($criteria as $k => $v) {
            if ($v === null) {
                $params[] = $this->getQuotedName($k) . " IS NULL ";
                unset($criteria[$k]);
            } else {
                $params[] = $this->getQuotedName($k) . " = ? ";
            }
        }

        return 'WHERE ' . implode('AND ', $params);
    }

    /**
     * @deprecated use deleteQueryByCriteria instead
     */
    public function deleteQuery($table, $id, $primaryKey = 'id')
    {
        $query = 'DELETE FROM ' . $this->getQuotedName($table) . ' WHERE ' . $this->getQuotedName($primaryKey) . ' = ?';
        $this->executeQuery($query, [$id]);
    }

    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)
    {
        $this->dbh->exec($query);
    }

    public function executeQuery($query, array $params)
    {
        $sth = $this->dbh->prepare($query);
        if (!$sth) {
            throw new \Exception("Query '$query' can't be prepared.");
        }

        $sth->execute($params);
        return $sth;
    }

    /**
     * @param string $tableName
     *
     * @return string
     * @throws \Exception
     * @deprecated use getPrimaryKey instead
     */
    public function getPrimaryColumn($tableName)
    {
        $primaryKey = $this->getPrimaryKey($tableName);
        if (empty($primaryKey)) {
            return null;
        } elseif (count($primaryKey) > 1) {
            throw new \Exception('getPrimaryColumn method does not support composite primary keys, use getPrimaryKey instead');
        }

        return $primaryKey[0];
    }

    /**
     * @param string $tableName
     *
     * @return array[string]
     */
    public function getPrimaryKey($tableName)
    {
        return [];
    }

    /**
     * @return bool
     */
    protected function flushPrimaryColumnCache()
    {
        $this->primaryKeys = [];

        return empty($this->primaryKeys);
    }
}
<?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;

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;"
        );
    }

    protected function generateWhereClause(array &$criteria)
    {
        if (empty($criteria)) {
            return '';
        }

        $params = [];
        foreach ($criteria as $k => $v) {
            $params[] = $this->getQuotedName($k) . " = ? ";        }

        return 'WHERE ' . implode('AND ', $params);
    }

    public function getQuotedName($name)
    {
        return '[' . $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
/**
 * @author tiger
 */

namespace Codeception\Lib\Driver;

use Facebook\Facebook as FacebookSDK;

class Facebook
{
    /**
     * @var callable
     */
    protected $logCallback;

    /**
     * @var FacebookSDK
     */
    protected $fb;

    /**
     * @var string
     */
    protected $appId;

    /**
     * @var string
     */
    protected $appSecret;

    /**
     * @var string
     */
    protected $appToken;

    /**
     * Facebook constructor.
     *
     * @param array         $config
     * @param callable|null $logCallback
     */
    public function __construct($config, $logCallback = null)
    {
        if (is_callable($logCallback)) {
            $this->logCallback = $logCallback;
        }

        $this->fb = new FacebookSDK(
            [
                'app_id'                => $config['app_id'],
                'app_secret'            => $config['secret'],
                'default_graph_version' => 'v2.5', //TODO add to config
            ]
        );

        $this->appId     = $config['app_id'];
        $this->appSecret = $config['secret'];
        $this->appToken  = $this->appId . '|' . $this->appSecret;
    }

    /**
     * @param string $name
     * @param array  $permissions
     *
     * @return array
     */
    public function createTestUser($name, array $permissions)
    {
        $response = $this->executeFacebookRequest(
            'POST',
            $this->appId . '/accounts/test-users',
            [
                'name'        => $name,
                'installed'   => true,
                'permissions' => $permissions
            ]
        );

        return $response->getDecodedBody();
    }

    public function deleteTestUser($testUserID)
    {
        $this->executeFacebookRequest('DELETE', '/' . $testUserID);
    }

    public function getTestUserInfo($testUserAccessToken)
    {
        $response = $this->executeFacebookRequest(
            'GET',
            '/me',
            $parameters = [],
            $testUserAccessToken
        );

        return $response->getDecodedBody();
    }

    public function getLastPostsForTestUser($testUserAccessToken)
    {
        $response = $this->executeFacebookRequest(
            'GET',
            '/me/feed',
            $parameters = [],
            $testUserAccessToken
        );

        return $response->getDecodedBody();
    }

    public function getVisitedPlaceTagForTestUser($placeId, $testUserAccessToken)
    {
        $response = $this->executeFacebookRequest(
            'GET',
            "/$placeId",
            $parameters = [],
            $testUserAccessToken
        );

        return $response->getDecodedBody();
    }

    public function sendPostToFacebook($testUserAccessToken, array $parameters)
    {
        $response = $this->executeFacebookRequest(
            'POST',
            '/me/feed',
            $parameters,
            $testUserAccessToken
        );

        return $response->getDecodedBody();
    }

    /**
     * @param string $method
     * @param string $endpoint
     * @param array  $parameters
     * @param string $token
     *
     * @return \Facebook\FacebookResponse
     */
    private function executeFacebookRequest($method, $endpoint, array $parameters = [], $token = null)
    {
        if (is_callable($this->logCallback)) {
            //used only for debugging:
            call_user_func($this->logCallback, 'Facebook API request', func_get_args());
        }

        if (!$token) {
            $token = $this->appToken;
        }

        switch ($method) {
            case 'GET':
                $response = $this->fb->get($endpoint, $token);
                break;
            case 'POST':
                $response = $this->fb->post($endpoint, $parameters, $token);
                break;
            case 'DELETE':
                $response = $this->fb->delete($endpoint, $parameters, $token);
                break;
            default:
                throw new \Exception("Facebook driver exception, please add support for method: " . $method);
                break;
        }

        if (is_callable($this->logCallback)) {
            call_user_func($this->logCallback, 'Facebook API response', $response->getDecodedBody());
        }

        return $response;
    }
}
<?php
namespace Codeception\Lib;

class Suite extends \PHPUnit_Framework_TestSuite
{
    protected $modules;
    protected $baseName;

    /**
     * @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;

class DummyCodeCoverage extends \PHP_CodeCoverage
{
    public function start($id, $clear = false)
    {

    }

    function stop($append = true, $linesToBeCovered = [], array $linesToBeUsed = [])
    {

    }
}
<?php
namespace Codeception\Coverage;

use Codeception\Configuration;
use Codeception\Exception\ModuleException;
use Symfony\Component\Finder\Finder;

class Filter
{
    /**
     * @var \PHP_CodeCoverage
     */
    protected $phpCodeCoverage = null;

    /**
     * @var Filter
     */
    protected static $c3;

    /**
     * @var \PHP_CodeCoverage_Filter
     */
    protected $filter = null;

    function __construct(\PHP_CodeCoverage $phpCoverage)
    {
        $this->phpCodeCoverage = $phpCoverage
            ? $phpCoverage
            : new \PHP_CodeCoverage;

        $this->filter = $this->phpCodeCoverage->filter();
    }

    /**
     * @param \PHP_CodeCoverage $phpCoverage
     * @return Filter
     */
    public static function setup(\PHP_CodeCoverage $phpCoverage)
    {
        self::$c3 = new self($phpCoverage);
        return self::$c3;
    }

    /**
     * @return null|\PHP_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'])) {
            foreach ($coverage['whitelist']['include'] as $fileOrDir) {
                $finder = strpos($fileOrDir, '*') === false
                    ? [$fileOrDir]
                    : $this->matchWildcardPattern($fileOrDir);

                foreach ($finder as $file) {
                    $filter->addFileToWhitelist($file);
                }
            }
        }

        if (isset($coverage['whitelist']['exclude'])) {
            foreach ($coverage['whitelist']['exclude'] as $fileOrDir) {
                $finder = strpos($fileOrDir, '*') === false
                    ? [$fileOrDir]
                    : $this->matchWildcardPattern($fileOrDir);

                foreach ($finder as $file) {
                    $filter->removeFileFromWhitelist($file);
                }
            }
        }
        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
                        ? [$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
                        ? [$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);
        $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 \PHP_CodeCoverage_Filter
     */
    public function getFilter()
    {
        return $this->filter;
    }
}
<?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
{
    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\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 = $e->getSuite()->getName();
        if ($this->options['coverage-xml']) {
            $this->retrieveAndPrintXml($suite);
        }
        if ($this->options['coverage-html']) {
            $this->retrieveAndPrintHtml($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'));
    }
}
<?php
namespace Codeception\Coverage\Subscriber;

use Codeception\Configuration;
use Codeception\Coverage\Filter;
use Codeception\Event\PrintResultEvent;
use Codeception\Events;
use Codeception\Subscriber\Shared\StaticEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class Printer implements EventSubscriberInterface
{
    use StaticEvents;

    static $events = [
        Events::RESULT_PRINT_AFTER => 'printResult'
    ];

    protected $settings = [
        'enabled'        => true,
        'low_limit'      => '35',
        'high_limit'     => '70',
        'show_uncovered' => false
    ];

    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 = new \PHP_CodeCoverage();

        // 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)
    {
        if ($this->options['steps']) {
            return;
        }
        $printer = $e->getPrinter();
        if (!$this->settings['enabled']) {
            $printer->write("\nCodeCoverage is disabled in `codeception.yml` config\n");
            return;
        }

        $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");
        }

    }

    protected function printConsole(\PHPUnit_Util_Printer $printer)
    {
        $writer = new \PHP_CodeCoverage_Report_Text(
            $this->settings['low_limit'],
            $this->settings['high_limit'],
            $this->settings['show_uncovered'],
            false
        );
        $printer->write($writer->process(self::$coverage, $this->options['colors']));
    }

    protected function printHtml()
    {
        $writer = new \PHP_CodeCoverage_Report_HTML(
            $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 \PHP_CodeCoverage_Report_Clover;
        $writer->process(self::$coverage, $this->absolutePath($this->options['coverage-xml']));
    }

    protected function printPHP()
    {
        $writer = new \PHP_CodeCoverage_Report_PHP;
        $writer->process(self::$coverage, $this->absolutePath($this->options['coverage']));
    }

    protected function printText()
    {
        $writer = new \PHP_CodeCoverage_Report_Text(
            $this->settings['low_limit'], $this->settings['high_limit'], $this->settings['show_uncovered'], false
        );
        file_put_contents($this->absolutePath($this->options['coverage-text']), $writer->process(self::$coverage, false));
    }
}
<?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\RemoteException;

/**
 * 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;

    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->mergeToPrint($coverage);
    }

    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)
    {
        $cookie = [
            'CodeCoverage'        => $testName,
            'CodeCoverage_Suite'  => $this->suiteName,
            'CodeCoverage_Config' => $this->settings['remote_config']
        ];
        $this->module->amOnPage('/');
        $this->module->setCookie(self::COVERAGE_COOKIE, json_encode($cookie));
    }

    protected function fetchErrors()
    {
        $error = $this->module->grabCookie(self::COVERAGE_COOKIE_ERROR);
        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\Coverage;

use Codeception\Configuration;
use Codeception\Coverage\Subscriber\Printer;
use Codeception\Lib\Interfaces\Remote;
use Codeception\Subscriber\Shared\StaticEvents;
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
    ];

    protected $settings = [];
    protected $filters = [];
    protected $modules = [];

    protected $coverage;
    protected $logDir;
    protected $options;
    static $events = [];

    abstract protected function isEnabled();

    function __construct($options = [])
    {
        $this->options = $options;
        $this->logDir = Configuration::outputDir();
    }

    protected function applySettings($settings)
    {
        try {
            $this->coverage = new \PHP_CodeCoverage();
        } catch (\PHP_CodeCoverage_Exception $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];
            }
        }
        $this->coverage->setProcessUncoveredFilesFromWhitelist($this->settings['show_uncovered']);
    }

    /**
     * @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)
    {
        $result->setCodeCoverage(new DummyCodeCoverage());

        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;

use Codeception\Event\TestEvent;

abstract class GroupObject extends Extension
{
    static $group;

    public function _before(TestEvent $e)
    {
    }

    public function _after(TestEvent $e)
    {
    }

    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\Util;

class PropertyAccess
{
    /**
     * @deprecated Use ReflectionHelper::readPrivateProperty()
     * @param object $object
     * @param string $property
     * @param string|null $class
     * @return mixed
     */
    public static function readPrivateProperty($object, $property, $class = null)
    {
        return ReflectionHelper::readPrivateProperty($object, $property, $class);
    }
}<?php
use Codeception\Module\Sequence;

if (!function_exists('sq')) {
    function sq($id = null)
    {
        if ($id and isset(Sequence::$hash[$id])) {
            return Sequence::$hash[$id];
        }
        $sequence = '_' . uniqid();
        if ($id) {
            Sequence::$hash[$id] = $sequence;
        }
        return $sequence;
    }

}<?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;

    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);
    }

    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;
    }

    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;
    }

    function __set($key, $val)
    {
        if ($this->val === null) {
            return;
        }

        if (is_object($this->val)) {
            $this->val->{$key} = $val;
            return;
        }

        $this->val->key = $val;
    }

    function __call($method, $args)
    {
        if ($this->val === null) {
            return new Maybe();
        }
        return call_user_func_array([$this->val, $method], $args);
    }

    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]];
        } else {
            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];
        } else {
            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]);
        } else {
            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\Shared;

trait Namespaces
{
    protected function breakParts($class)
    {
        $class      = str_replace('/', '\\', $class);
        $namespaces = explode('\\', $class);
        if (count($namespaces)) {
            $namespaces[0] = ltrim($namespaces[0], '\\');
        }
        if (!$namespaces[0]) {
            array_shift($namespaces);
        } // remove empty namespace caused of \\
        return $namespaces;
    }

    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\Shared;

trait Asserts
{
    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);
    }

    /**
     * Checks that two variables are equal.
     *
     * @param        $expected
     * @param        $actual
     * @param string $message
     *
     * @return mixed
     */
    protected function assertEquals($expected, $actual, $message = '')
    {
        \PHPUnit_Framework_Assert::assertEquals($expected, $actual, $message);
    }

    /**
     * Checks that two variables are not equal
     *
     * @param        $expected
     * @param        $actual
     * @param string $message
     */
    protected function assertNotEquals($expected, $actual, $message = '')
    {
        \PHPUnit_Framework_Assert::assertNotEquals($expected, $actual, $message);
    }

    /**
     * Checks that two variables are same
     *
     * @param        $expected
     * @param        $actual
     * @param string $message
     *
     * @return mixed
     */
    protected function assertSame($expected, $actual, $message = '')
    {
        \PHPUnit_Framework_Assert::assertSame($expected, $actual, $message);
    }

    /**
     * Checks that two variables are not same
     *
     * @param        $expected
     * @param        $actual
     * @param string $message
     */
    protected function assertNotSame($expected, $actual, $message = '')
    {
        \PHPUnit_Framework_Assert::assertNotSame($expected, $actual, $message);
    }

    /**
     * Checks that actual is greater than expected
     *
     * @param        $expected
     * @param        $actual
     * @param string $message
     */
    protected function assertGreaterThan($expected, $actual, $message = '')
    {
        \PHPUnit_Framework_Assert::assertGreaterThan($expected, $actual, $message);
    }

    /**
     * @deprecated
     */
    protected function assertGreaterThen($expected, $actual, $message = '')
    {
        \PHPUnit_Framework_Assert::assertGreaterThan($expected, $actual, $message);
    }

    /**
     * Checks that actual is greater or equal than expected
     *
     * @param        $expected
     * @param        $actual
     * @param string $message
     */
    protected function assertGreaterThanOrEqual($expected, $actual, $message = '')
    {
        \PHPUnit_Framework_Assert::assertGreaterThanOrEqual($expected, $actual, $message);
    }

    /**
     * @deprecated
     */
    protected function assertGreaterThenOrEqual($expected, $actual, $message = '')
    {
        \PHPUnit_Framework_Assert::assertGreaterThanOrEqual($expected, $actual, $message);
    }

    /**
     * Checks that actual is less than expected
     *
     * @param        $expected
     * @param        $actual
     * @param string $message
     */
    protected function assertLessThan($expected, $actual, $message = '')
    {
        \PHPUnit_Framework_Assert::assertLessThan($expected, $actual, $message);
    }

    /**
     * Checks that actual is less or equal than expected
     *
     * @param        $expected
     * @param        $actual
     * @param string $message
     */
    protected function assertLessThanOrEqual($expected, $actual, $message = '')
    {
        \PHPUnit_Framework_Assert::assertLessThanOrEqual($expected, $actual, $message);
    }


    /**
     * Checks that haystack contains needle
     *
     * @param        $needle
     * @param        $haystack
     * @param string $message
     */
    protected function assertContains($needle, $haystack, $message = '')
    {
        \PHPUnit_Framework_Assert::assertContains($needle, $haystack, $message);
    }

    /**
     * Checks that haystack doesn't contain needle.
     *
     * @param        $needle
     * @param        $haystack
     * @param string $message
     */
    protected function assertNotContains($needle, $haystack, $message = '')
    {
        \PHPUnit_Framework_Assert::assertNotContains($needle, $haystack, $message);
    }

    /**
     * Checks that string match with pattern
     *
     * @param string $pattern
     * @param string $string
     * @param string $message
     */
    protected function assertRegExp($pattern, $string, $message = '')
    {
        \PHPUnit_Framework_Assert::assertRegExp($pattern, $string, $message);
    }  
    
    /**
     * Checks that string not match with pattern
     *
     * @param string $pattern
     * @param string $string
     * @param string $message
     */
    protected function assertNotRegExp($pattern, $string, $message = '')
    {
        \PHPUnit_Framework_Assert::assertNotRegExp($pattern, $string, $message);
    }  
        
    
    /**
     * Checks that variable is empty.
     *
     * @param        $actual
     * @param string $message
     */
    protected function assertEmpty($actual, $message = '')
    {
        \PHPUnit_Framework_Assert::assertEmpty($actual, $message);
    }

    /**
     * Checks that variable is not empty.
     *
     * @param        $actual
     * @param string $message
     */
    protected function assertNotEmpty($actual, $message = '')
    {
        \PHPUnit_Framework_Assert::assertNotEmpty($actual, $message);
    }

    /**
     * Checks that variable is NULL
     *
     * @param        $actual
     * @param string $message
     */
    protected function assertNull($actual, $message = '')
    {
        \PHPUnit_Framework_Assert::assertNull($actual, $message);
    }

    /**
     * Checks that variable is not NULL
     *
     * @param        $actual
     * @param string $message
     */
    protected function assertNotNull($actual, $message = '')
    {
        \PHPUnit_Framework_Assert::assertNotNull($actual, $message);
    }

    /**
     * Checks that condition is positive.
     *
     * @param        $condition
     * @param string $message
     */
    protected function assertTrue($condition, $message = '')
    {
        \PHPUnit_Framework_Assert::assertTrue($condition, $message);
    }

    /**
     * Checks that condition is negative.
     *
     * @param        $condition
     * @param string $message
     */
    protected function assertFalse($condition, $message = '')
    {
        \PHPUnit_Framework_Assert::assertFalse($condition, $message);
    }

    /**
     * 
     * @param        $haystack
     * @param        $constraint
     * @param string $message
     */
    protected function assertThat($haystack, $constraint, $message)
    {
        \PHPUnit_Framework_Assert::assertThat($haystack, $constraint, $message);
    }

    /**
     * Checks that haystack doesn't attend
     *  
     * @param        $haystack
     * @param        $constraint
     * @param string $message
     */
    protected function assertThatItsNot($haystack, $constraint, $message)
    {
        $constraint = new \PHPUnit_Framework_Constraint_Not($constraint);
        \PHPUnit_Framework_Assert::assertThat($haystack, $constraint, $message);
    }

    
    /**
     * Checks if file exists
     *  
     * @param string $filename
     * @param string $message
     */
    protected function assertFileExists($filename, $message = '')
    {
        \PHPUnit_Framework_Assert::assertFileExists($filename, $message);
    }
    
        
    /**
     * Checks if file doesn't exist
     *  
     * @param string $filename
     * @param string $message
     */
    protected function assertFileNotExists($filename, $message = '')
    {
        \PHPUnit_Framework_Assert::assertFileNotExists($filename, $message);
    }

    /**
     * @param $expected
     * @param $actual
     * @param $description
     */
    protected function assertGreaterOrEquals($expected, $actual, $description)
    {
        \PHPUnit_Framework_Assert::assertGreaterThanOrEqual($expected, $actual, $description);
    }

    /**
     * @param $expected
     * @param $actual
     * @param $description
     */
    protected function assertLessOrEquals($expected, $actual, $description)
    {
        \PHPUnit_Framework_Assert::assertLessThanOrEqual($expected, $actual, $description);
    }

    /**
     * @param $actual
     * @param $description
     */
    protected function assertIsEmpty($actual, $description)
    {
        \PHPUnit_Framework_Assert::assertEmpty($actual, $description);
    }

    /**
     * @param $key
     * @param $actual
     * @param $description
     */
    protected function assertArrayHasKey($key, $actual, $description)
    {
        \PHPUnit_Framework_Assert::assertArrayHasKey($key, $actual, $description);
    }

    /**
     * @param $key
     * @param $actual
     * @param $description
     */
    protected function assertArrayNotHasKey($key, $actual, $description)
    {
        \PHPUnit_Framework_Assert::assertArrayNotHasKey($key, $actual, $description);
    }

    /**
     * @param $class
     * @param $actual
     * @param $description
     */
    protected function assertInstanceOf($class, $actual, $description)
    {
        \PHPUnit_Framework_Assert::assertInstanceOf($class, $actual, $description);
    }

    /**
     * @param $class
     * @param $actual
     * @param $description
     */
    protected function assertNotInstanceOf($class, $actual, $description)
    {
        \PHPUnit_Framework_Assert::assertNotInstanceOf($class, $actual, $description);
    }

    /**
     * @param $type
     * @param $actual
     * @param $description
     */
    protected function assertInternalType($type, $actual, $description)
    {
        \PHPUnit_Framework_Assert::assertInternalType($type, $actual, $description);
    }
    
    /**
     * Fails the test with message.
     *
     * @param $message
     */
    protected function fail($message)
    {
        \PHPUnit_Framework_Assert::fail($message);
    }
}
<?php
namespace Codeception\Util;

/**
 * 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
     */
    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
     */
    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);
    }
}

<?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/master/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\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 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 ($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'];
            if ($base->getPath() && (strpos($path, '/') !== 0) && !empty($path)) {
                // if it ends with a slash, relative paths are below it
                if (preg_match('~/$~', $base->getPath())) {
                    $path = $base->getPath() . $path;
                } else {
                    // remove double slashes
                    $dir = rtrim(dirname($base->getPath()), '\\/');
                    $path = $dir . '/' . $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;
        } else {
            return rtrim($cutUrl, '/') . '/'  . ltrim($path, '/');
        }
    }
}
<?php
namespace Codeception\Util;

/**
 * Basic template engine used for generating initial Cept/Cest/Test files.
 */
class Template
{
    protected $template;
    protected $vars = [];

    /**
     * Takes a template string
     *
     * @param $template
     */
    public function __construct($template)
    {
        $this->template = $template;
    }

    /**
     * Replaces {{var}} string with provided value
     *
     * @param $var
     * @param $val
     * @return $this
     */
    public function place($var, $val)
    {
        $this->vars[$var] = $val;
        return $this;
    }

    /**
     * Fills up template string with placed variables.
     *
     * @return mixed
     */
    public function produce()
    {
        $result = $this->template;
        foreach ($this->vars as $var => $value) {
            $result = str_replace('{{' . $var . '}}', $value, $result);
        }
        return $result;
    }
} 
<?php
namespace Codeception\Util;

use Codeception\Lib\Console\Output;

/**
 * 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);
    }

    /**
     * Pauses execution and waits for user input to proceed.
     */
    public static function pause()
    {
        if (!self::$output) {
            return;
        }

        self::$output->writeln("<info>The execution has been paused. Press ENTER to continue</info>");

        if (trim(fgets(STDIN)) != chr(13)) {
            return;
        }
    }
}
<?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 {
            array_push(self::$map[$prefix], $base_dir);
        }
    }

    /**
     * @deprecated Use self::addNamespace() instead.
     */
    public static function register($namespace, $suffix, $path)
    {
        self::addNamespace($namespace, $path);
    }

    /**
     * @deprecated Use self::addNamespace() instead.
     */
    public static function registerSuffix($suffix, $path)
    {
        self::addNamespace('', $path);
    }

    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 $file;
            return true;
        }
        return false;
    }
}
<?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)) {
            // sequential array
            if (array_key_exists(0, $this->jsonArray)) {
                $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;
            }
            $matchTypes = preg_split("#(?![^]\(]*\))\|#", $type);
            $matched = false;
            $currentType = strtolower(gettype($data[$key]));
            if ($currentType == 'double') {
                $currentType = 'float';
            }
            foreach ($matchTypes as $matchType) {
                $filters = preg_split("#(?![^]\(]*\))\:#", $matchType);
                $expectedType = trim(strtolower(array_shift($filters)));

                if ($expectedType != $currentType) {
                    continue;
                }
                $matched = true;

                foreach ($filters as $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/
            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);
        }
        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];
        }
    }

}
<?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');
 *
 * ?>
 * ```
 *
 */
class Fixtures
{
    protected static $fixtures = [];

    public static function add($name, $data)
    {
        self::$fixtures[$name] = $data;
    }

    public static function get($name)
    {
        if (!isset(self::$fixtures[$name])) {
            throw new \RuntimeException("$name not found in fixtures");
        }

        return self::$fixtures[$name];
    }

    public static function cleanup()
    {
        self::$fixtures = [];
    }
}
<?php
namespace Codeception\Util;

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
     *
     * @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)
     *
     * @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));
    }

    /**
     * @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
     *
     * @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;
    }

    /**
     * Checks that string and CSS selector for element by ID
     *
     */
    public static function isID($id)
    {
        return (bool)preg_match('~^#[\w\.\-\[\]\=\^\~\:]+$~', $id);
    }

    /**
     * Locates an element containing a text inside.
     * Either CSS or XPath locator can be passed, however they will be converted to XPath.
     *
     * ```php
     * 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
     * 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 $element CSS or XPath locator
     * @param $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
     * 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
     * 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 \Facebook\WebDriver\WebDriverBy) {
             $type = $selector->getMechanism();
             $locator = $selector->getValue();
             return "$type '$locator'";
          }
       }
       throw new \InvalidArgumentException("Unrecognized selector");
    }
}
<?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') {
                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;

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) {
            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;

/**
 * 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 $comment
     * @param $annotation
     * @return array
     */
    public static function fetchAllFromComment($annotation, $comment)
    {
        if (preg_match_all(sprintf(self::$regex, $annotation), $comment, $matched)) {
            return $matched[1];
        }
        return [];

    }

    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();
    }
}<?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.');
        }

        $this->jsonArray = json_decode($jsonString, true);

        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) {
            $root = key($jsonArray);
            $jsonArray = reset($jsonArray);
        }

        $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 `flow/jsonpath` to composer.json');
        }
        return (new JSONPath($this->jsonArray))->find($jsonPath)->data();
    }

    public function getXmlString()
    {
        return $this->toXml()->saveXML();
    }

    public function containsArray(array $needle)
    {
        return $needle == $this->arrayIntersectRecursive($needle, $this->jsonArray);
    }

    /**
     * @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) {
                $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 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 isEqualValue($val1, $val2)
    {
        if (is_numeric($val1)) {
            $val1 = (string) $val1;
        }

        if (is_numeric($val2)) {
            $val2 = (string) $val2;
        }

        return $val1 === $val2;
    }

    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\Util;

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', array('name' => 'davert'));
     * ?>
     * ```
     *
     * Accepts either name of class or object of that class
     *
     * ``` php
     * <?php
     * Stub::make(new User, array('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', array('save' => function () { return true; }));
     * Stub::make('User', array('save' => true }));
     * ?>
     * ```
     *
     * @param mixed $class - A class to be mocked
     * @param array $params - properties and methods to set
     * @param bool|\PHPUnit_Framework_TestCase $testCase
     *
     * @return object - mock
     * @throws \RuntimeException when class does not exist
     */
    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
     */
    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', array('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', array('isValid' => function () { return true; }));
     * Stub::makeEmptyExcept('User', 'save', array('isValid' => true }));
     * ?>
     * ```
     *
     * @param mixed $class
     * @param string $method
     * @param array $params
     * @param bool|\PHPUnit_Framework_TestCase $testCase
     *
     * @return object
     */
    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', array('name' => 'davert'));
     * ?>
     * ```
     *
     * Accepts either name of class or object of that class
     *
     * ``` php
     * <?php
     * Stub::makeEmpty(new User, array('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', array('save' => function () { return true; }));
     * Stub::makeEmpty('User', array('save' => true }));
     * ?>
     * ```
     *
     * @param mixed $class
     * @param array $params
     * @param bool|\PHPUnit_Framework_TestCase $testCase
     *
     * @return object
     */
    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
     */
    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', array('autosave' => false));
     * Stub::construct('User', array('autosave' => false), array('name' => 'davert'));
     * ?>
     * ```
     *
     * Accepts either name of class or object of that class
     *
     * ``` php
     * <?php
     * Stub::construct(new User, array('autosave' => false), array('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', array(), array('save' => function () { return true; }));
     * Stub::construct('User', array(), array('save' => true }));
     * ?>
     * ```
     *
     * @param mixed $class
     * @param array $constructorParams
     * @param array $params
     * @param bool|\PHPUnit_Framework_TestCase $testCase
     *
     * @return object
     */
    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', array('autosave' => false));
     * Stub::constructEmpty('User', array('autosave' => false), array('name' => 'davert'));
     * ?>
     * ```
     *
     * Accepts either name of class or object of that class
     *
     * ``` php
     * <?php
     * Stub::constructEmpty(new User, array('autosave' => false), array('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', array(), array('save' => function () { return true; }));
     * Stub::constructEmpty('User', array(), array('save' => true }));
     * ?>
     * ```
     *
     * @param mixed $class
     * @param array $constructorParams
     * @param array $params
     * @param bool|\PHPUnit_Framework_TestCase $testCase
     *
     * @return object
     */
    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', array('autosave' => false), array('name' => 'davert'));
     * ?>
     * ```
     *
     * Accepts either name of class or object of that class
     *
     * ``` php
     * <?php
     * Stub::constructEmptyExcept(new User, 'save', array('autosave' => false), array('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', array(), array('save' => function () { return true; }));
     * Stub::constructEmptyExcept('User', 'save', array(), array('save' => true }));
     * ?>
     * ```
     *
     * @param mixed $class
     * @param string $method
     * @param array $constructorParams
     * @param array $params
     * @param bool|\PHPUnit_Framework_TestCase $testCase
     *
     * @return object
     */
    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
     *
     * @param  string $originalClassName
     * @param  array $arguments
     * @param  string $mockClassName
     * @param  boolean $callOriginalConstructor
     * @param  boolean $callOriginalClone
     * @param  boolean $callAutoload
     * @param  array $mockedMethods
     * @param  boolean $cloneArguments
     *
     * @return object
     * @since  Method available since Release 1.0.0
     * @throws \InvalidArgumentException
     */
    private static function generateMockForAbstractClass()
    {
        return self::doGenerateMock(func_get_args(), true);
    }

    private static function doGenerateMock($args, $isAbstract = false)
    {
        $testCase = self::extractTestCaseFromArgs($args);
        $class = $testCase instanceof \PHPUnit_Framework_TestCase ? $testCase : new \PHPUnit_Framework_MockObject_Generator;
        $methodName = $isAbstract ? 'getMockForAbstractClass' : 'getMock';

        $mock = call_user_func_array([$class, $methodName], $args);

        return $mock;
    }

    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
     */
    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 \PHPUnit_Framework_MockObject_Stub_ReturnCallback($marshaler->getValue()));
                } elseif ($value instanceof \Closure) {
                    $mock->
                    expects(new \PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount)->
                    method($param)->
                    will(new \PHPUnit_Framework_MockObject_Stub_ReturnCallback($value));
                } elseif ($value instanceof ConsecutiveMap) {
                    $consecutiveMap = $value;
                    $mock->
                    expects(new \PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount)->
                    method($param)->
                    will(new \PHPUnit_Framework_MockObject_Stub_ConsecutiveCalls($consecutiveMap->getMap()));
                } else {
                    $mock->
                    expects(new \PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount)->
                    method($param)->
                    will(new \PHPUnit_Framework_MockObject_Stub_Return($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 \PHPUnit_Framework_Exception(
                            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;
    }

    /**
     * Checks if a method never has been invoked
     *
     * If method invoked, it will immediately throw an
     * exception.
     *
     * ``` php
     * <?php
     * $user = Stub::make('User', array('getName' => Stub::never(), 'someMethod' => function() {}));
     * $user->someMethod();
     * ?>
     * ```
     *
     * @param mixed $params
     *
     * @return StubMarshaler
     */
    public static function never($params = null)
    {
        return new StubMarshaler(
            new \PHPUnit_Framework_MockObject_Matcher_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
     * $user = Stub::make('User', array('getName' => Stub::once(function() { return 'Davert';}), 'someMethod' => function() {}));
     * $userName = $user->getName();
     * $this->assertEquals('Davert', $userName);
     * ?>
     * ```
     *
     * @param mixed $params
     *
     * @return StubMarshaler
     */
    public static function once($params = null)
    {
        return new StubMarshaler(
            new \PHPUnit_Framework_MockObject_Matcher_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
     * $user = Stub::make('User', array('getName' => Stub::atLeastOnce(function() { return 'Davert';}), 'someMethod' => function() {}));
     * $user->getName();
     * $user->getName();
     * ?>
     * ```
     *
     * @param mixed $params
     *
     * @return StubMarshaler
     */
    public static function atLeastOnce($params = null)
    {
        return new StubMarshaler(
            new \PHPUnit_Framework_MockObject_Matcher_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
     * $user = Stub::make('User', array('getName' => Stub::exactly(3, function() { return 'Davert';}), 'someMethod' => function() {}));
     * $user->getName();
     * $user->getName();
     * $user->getName();
     * ?>
     * ```
     *
     * @param int $count
     * @param mixed $params
     *
     * @return StubMarshaler
     */
    public static function exactly($count, $params = null)
    {
        return new StubMarshaler(
            new \PHPUnit_Framework_MockObject_Matcher_InvokedCount($count),
            self::closureIfNull($params)
        );
    }

    private static function closureIfNull($params)
    {
        if ($params == null) {
            return function () {
            };
        } else {
            return $params;
        }
    }

    /**
     * Stubbing a method call to return a list of values in the specified order.
     *
     * ``` php
     * <?php
     * $user = Stub::make('User', array('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());
    }
}

/**
 * Holds matcher and value of mocked method
 */
class StubMarshaler
{
    private $methodMatcher;

    private $methodValue;

    public function __construct(\PHPUnit_Framework_MockObject_Matcher_InvokedRecorder $matcher, $value)
    {
        $this->methodMatcher = $matcher;
        $this->methodValue = $value;
    }

    public function getMatcher()
    {
        return $this->methodMatcher;
    }

    public function getValue()
    {
        return $this->methodValue;
    }
}

/**
 * Holds the Consecutive Map for matching
 */
class ConsecutiveMap
{
    private $consecutiveMap = [];

    public function __construct(array $consecutiveMap)
    {
        $this->consecutiveMap = $consecutiveMap;
    }

    public function getMap()
    {
        return $this->consecutiveMap;
    }
}
<?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
use Codeception\Module\Sequence;

if (!function_exists('sqs')) {
    function sqs($id = null)
    {
        if ($id and isset(Sequence::$suiteHash[$id])) {
            return Sequence::$suiteHash[$id];
        }
        $sequence = '_' . uniqid();
        if ($id) {
            Sequence::$suiteHash[$id] = $sequence;
        }
        return $sequence;
    }

}<?php
namespace Codeception;

use Codeception\Lib\Actor\Shared\Comment;
use Codeception\Lib\Actor\Shared\Friend;
use Codeception\Step\Executor;

abstract class Actor
{
    use Comment;
    use Friend;

    /**
     * @var \Codeception\Scenario
     */
    protected $scenario;

    public function __construct(Scenario $scenario)
    {
        $this->scenario = $scenario;
        $this->scenario->stopIfBlocked();
    }

    /**
     * @return \Codeception\Scenario
     */
    protected function getScenario()
    {
        return $this->scenario;
    }

    public function wantToTest($text)
    {
        $this->wantTo('test ' . $text);
    }

    public function wantTo($text)
    {
        $this->scenario->setFeature(mb_strtolower($text, 'utf-8'));
    }

    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;

use Codeception\Lib\ModuleContainer;
use Codeception\Util\Shared\Asserts;

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 = [];

    public function __construct(ModuleContainer $moduleContainer, $config = null)
    {
        $this->moduleContainer = $moduleContainer;

        $this->backupConfig = $this->config;
        if (is_array($config)) {
            $this->_setConfig($config);
        }
    }

    public function _setConfig($config)
    {
        $this->config = $this->backupConfig = array_merge($this->config, $config);
        $this->validateConfig();
    }

    public function _reconfigure($config)
    {
        $this->config = array_merge($this->backupConfig, $config);
        $this->onReconfigure();
        $this->validateConfig();
    }

    protected function onReconfigure()
    {
        // update client on reconfigurations
    }

    public function _resetConfig()
    {
        $this->config = $this->backupConfig;
    }

    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"
            );
        }
    }

    public function _getName()
    {
        $moduleName = '\\'.get_class($this);

        if (strpos($moduleName, ModuleContainer::MODULE_NAMESPACE) === 0) {
            return substr($moduleName, strlen(ModuleContainer::MODULE_NAMESPACE));
        }

        return $moduleName;
    }

    public function _hasRequiredFields()
    {
        return !empty($this->requiredFields);
    }

    // HOOK: used after configuration is loaded
    public function _initialize()
    {
    }

    // HOOK: on every Guy class initialization
    public function _cleanup()
    {
    }

    // HOOK: before each suite
    public function _beforeSuite($settings = [])
    {
    }

    // HOOK: after suite
    public function _afterSuite()
    {
    }

    // HOOK: before every step
    public function _beforeStep(Step $step)
    {
    }

    // HOOK: after every  step
    public function _afterStep(Step $step)
    {
    }

    // HOOK: before scenario
    public function _before(TestCase $test)
    {
    }

    // HOOK: after scenario
    public function _after(TestCase $test)
    {
    }

    // HOOK: on fail
    public function _failed(TestCase $test, $fail)
    {
    }

    protected function debug($message)
    {
        codecept_debug($message);
    }

    protected function debugSection($title, $message)
    {
        if (is_array($message) or is_object($message)) {
            $message = stripslashes(json_encode($message));
        }
        $this->debug("[$title] $message");
    }

    protected function hasModule($name)
    {
        return $this->moduleContainer->hasModule($name);
    }

    protected function getModules()
    {
        return $this->moduleContainer->all();
    }

    protected function getModule($name)
    {
        if (!$this->hasModule($name)) {
            throw new Exception\ModuleException(__CLASS__, "Module $name couldn't be connected");
        }
        return $this->moduleContainer->getModule($name);
    }

    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\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\Step;

class Action extends Step
{
}
<?php
namespace Codeception\Step;

use Codeception\Exception\ConditionalAssertionFailed;
use Codeception\Lib\ModuleContainer;

class ConditionalAssertion extends Assertion
{
    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()
    {
        return 'can' . ucfirst($this->action);
    }

    public function getHumanizedAction()
    {
        return $this->humanize($this->action . ' ' . $this->getHumanizedArguments());
    }
}
<?php
namespace Codeception\Step;

use Codeception\Step as CodeceptionStep;

class Condition extends CodeceptionStep
{
}
<?php 
namespace Codeception\Step;

use Codeception\Lib\ModuleContainer;
use Codeception\Step as CodeceptionStep;

class Meta extends CodeceptionStep
{
    protected function storeCallerInfo()
    {
    }

    public function run(ModuleContainer $container = null)
    {
    }

    public function setTraceInfo($file, $line)
    {
        $this->file = $file;
        $this->line = $line;
    }

    public function setActor($actor)
    {
        $this->actor = $actor;
    }
}
<?php
namespace Codeception\Step;

use Codeception\Lib\ModuleContainer;
use Codeception\Step as CodeceptionStep;

class Comment extends CodeceptionStep
{
    public function __toString()
    {
        return $this->getAction();
    }

    public function getHumanizedAction()
    {
        return $this->getAction();
    }

    public function getHtml($highlightColor = '#732E81')
    {
        return '<strong>' . $this->getAction() . '</strong>';
    }

    public function getPhpCode()
    {
        return '// ' . $this->getAction();
    }

    public function run(ModuleContainer $container = null)
    {
        // don't do anything, let's rest
    }
}
<?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 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\Step as CodeceptionStep;
use Codeception\Lib\ModuleContainer;

class Executor extends CodeceptionStep
{

    protected $callable = null;

    public function __construct(\Closure $callable, $arguments = [])
    {
        // TODO: add serialization to function http://www.htmlist.com/development/extending-php-5-3-closures-with-serialization-and-reflection/
        parent::__construct('execute callable function', []);

        $this->callable = $callable;
    }

    public function run(ModuleContainer $container = null)
    {
        $callable = $this->callable;

        return $callable();
    }

}
<?php

namespace Codeception;

use Codeception\Exception\ConfigurationException as ConfigurationException;
use Codeception\Util\Autoload;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
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 Current project logs directory.
     */
    protected static $logDir = 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'      => 'Guy', ## codeception 1.x compatility
        'namespace'  => '',
        'include'    => [],
        'paths'      => [
        ],
        'modules'    => [],
        'extensions' => [
            'enabled' => [],
            'config'  => [],
        ],
        'reporters'  => [
            'xml'    => 'Codeception\PHPUnit\Log\JUnit',
            'html'   => 'Codeception\PHPUnit\ResultPrinter\HTML',
            'tap'    => 'PHPUnit_Util_Log_TAP',
            'json'   => 'PHPUnit_Util_Log_JSON',
            'report' => 'Codeception\PHPUnit\ResultPrinter\Report',
        ],
        'groups'     => [],
        'settings'   => [
            'colors'     => false,
            'log'        => false, // deprecated
            'bootstrap'  => false,
            'strict_xml' => false,
            'lint'       => true
        ],
        'coverage'   => []
    ];

    public static $defaultSuiteSettings = [
        'class_name'  => 'NoGuy',
        'modules'     => [
            'enabled' => [],
            'config'  => [],
            'depends' => []
        ],
        'namespace'   => null,
        'path'        => '',
        'groups'      => [],
        'shuffle'     => false,
        'error_level' => 'E_ALL & ~E_STRICT & ~E_DEPRECATED',
    ];

    /**
     * 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));

        $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.");
        }

        $config = self::loadConfigFile($configDistFile, self::$defaultConfig);
        $config = self::loadConfigFile($configFile, $config);

        if ($config == self::$defaultConfig) {
            throw new ConfigurationException("Configuration file is invalid");
        }

        self::$dir = $dir;
        self::$config = $config;

        if (!isset($config['paths']['log'])) {
            throw new ConfigurationException('Log path is not defined by key "paths: log"');
        }

        self::$logDir = $config['paths']['log'];

        // fill up includes with wildcard expansions
        $config['include'] = self::expandWildcardedIncludes($config['include']);

        // config without tests, for inclusion of other configs
        if (count($config['include']) and !isset($config['paths']['tests'])) {
            return self::$config = $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"');
        }

        // compatibility with 1.x, 2.0
        if (!isset($config['paths']['support']) and isset($config['paths']['helpers'])) {
            $config['paths']['support'] = $config['paths']['helpers'];
        }

        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'];
        }

        self::loadBootstrap($config['settings']['bootstrap']);
        self::autoloadHelpers();
        self::loadSuites();

        return $config;
    }

    protected static function loadBootstrap($bootstrap)
    {
        if (!$bootstrap) {
            return;
        }
        $bootstrap = self::$dir . DIRECTORY_SEPARATOR . self::$testsDir . DIRECTORY_SEPARATOR . $bootstrap;
        if (file_exists($bootstrap)) {
            include_once $bootstrap;
        }
    }

    protected static function loadConfigFile($file, $parentConfig)
    {
        $config = file_exists($file) ? Yaml::parse(file_get_contents($file)) : [];
        return self::mergeConfigs($parentConfig, $config);
    }

    protected static function autoloadHelpers()
    {
        $namespace = self::$config['namespace'];
        Autoload::addNamespace($namespace, self::supportDir());

        // deprecated
        Autoload::addNamespace($namespace . '\Codeception\Module', self::supportDir());
    }

    protected static function loadSuites()
    {
        $suites = Finder::create()->files()->name('*.{suite,suite.dist}.yml')->in(self::$dir . DIRECTORY_SEPARATOR . self::$testsDir)->depth('< 1');
        self::$suites = [];

        /** @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'] 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);
        }

        $settings['path'] = self::$dir . DIRECTORY_SEPARATOR . $config['paths']['tests'] . DIRECTORY_SEPARATOR . $suite . 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 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
     */
    protected static function getConfFromFile($filename, $nonExistentValue = [])
    {
        if (file_exists($filename)) {
            return Yaml::parse(file_get_contents($filename));
        }
        return $nonExistentValue;
    }

    /**
     * Returns all possible suite configurations according environment rules.
     * Suite configurations will contain `current_environment` key which specifies what environment used.
     *
     * @param $suite
     * @return array
     */
    public static function suiteEnvironments($suite)
    {
        $settings = self::suiteSettings($suite, self::config());

        if (!isset($settings['env']) || !is_array($settings['env'])) {
            return [];
        }

        $environments = [];

        foreach ($settings['env'] as $env => $envConfig) {
            $environments[$env] = $envConfig ? self::mergeConfigs($settings, $envConfig) : $settings;
            $environments[$env]['current_environment'] = $env;
        }

        return $environments;
    }

    public static function suites()
    {
        return self::$suites;
    }

    /**
     * Return instances of enabled modules according suite config.
     *
     * @param array $settings suite settings
     * @return array|\Codeception\Module[]
     */
    public static function modules($settings)
    {
        return array_map(
            function ($m) {
                return is_array($m) ? key($m) : $m;
            }, $settings['modules']['enabled'], array_keys($settings['modules']['enabled'])
        );
    }

    public static function isExtensionEnabled($extensionName)
    {
        return isset(self::$config['extensions'])
        && 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::$logDir) {
            throw new ConfigurationException("Path for output not specified. Please, set output path in global config");
        }

        $dir = self::$logDir . DIRECTORY_SEPARATOR;
        if (strcmp(self::$logDir[0], "/") !== 0) {
            $dir = self::$dir . DIRECTORY_SEPARATOR . $dir;
        }

        if (!is_writable($dir)) {
            @mkdir($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.");
        }

        return $dir;
    }

    /**
     * Compatibility alias to `Configuration::logDir()`
     * @return string
     */
    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 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 = [])
    {
        return self::$config = self::mergeConfigs(self::$config, $config);
    }

    public static function mergeConfigs($a1, $a2)
    {
        if (!is_array($a1) || !is_array($a2)) {
            return $a2;
        }

        $res = [];

        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
     */
    protected static function loadSuiteConfig($suite, $path, $settings)
    {
        $suiteDistConf = self::getConfFromFile(self::$dir . DIRECTORY_SEPARATOR . $path . DIRECTORY_SEPARATOR . "$suite.suite.dist.yml");
        $suiteConf = self::getConfFromFile(self::$dir . DIRECTORY_SEPARATOR . $path . DIRECTORY_SEPARATOR . "$suite.suite.yml");
        $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
     */
    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;
    }
}
<?php 
namespace Codeception\Platform;

use Codeception\Extension as BaseExtension;

/**
 * BC Compatibility
 *
 * Class Extension
 * @package Codeception\Platform
 */
abstract class Extension extends BaseExtension
{

}
<?php 
namespace Codeception\Platform;

use Codeception\GroupObject;

/**
 * BC compatibility
 *
 * Class Group
 * @package Codeception\Platform
 */
abstract class Group extends GroupObject
{
}
<?php
namespace Codeception\Exception;

class InjectionException extends \Exception
{

} <?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 MalformedLocatorException extends TestRuntimeException
{
    public function __construct($locator, $type = "CSS or XPath")
    {
        parent::__construct(ucfirst($type) . " locator is malformed: $locator");
    }
}
<?php
namespace Codeception\Exception;

use Codeception\TestCase;

class TestRuntimeException extends \RuntimeException
{
}
<?php
namespace Codeception\Exception;

class ConfigurationException extends \Exception
{

}
<?php
namespace Codeception\Exception;

class ModuleConflictException extends \Exception
{
    public function __construct($module, $conflicted)
    {
        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, Laravel4 modules in one suite,\n"
            . "as they implement similar methods but use different drivers to execute them.";
    }
}
<?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;

use Codeception\Util\Locator;

class ElementNotFound extends \PHPUnit_Framework_AssertionFailedError
{
    public function __construct($selector, $message = null)
    {
        $selector = Locator::humanReadableString($selector);
        parent::__construct($message . " element with $selector was not found.");
    }
}
<?php
namespace Codeception\Exception;

class ContentNotFound extends \PHPUnit_Framework_AssertionFailedError
{

}
<?php
namespace Codeception\Exception;

class ConditionalAssertionFailed extends \PHPUnit_Framework_AssertionFailedError
{

}<?php
namespace Codeception\Exception;

class TestParseException extends \Exception
{
    public function __construct($fileName, $errors = null)
    {
        $this->message = "Couldn't parse test '$fileName'";
        if ($errors) {
            $this->message .= "\n$errors";
        }
    }
}
<?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 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 ConnectionException extends \RuntimeException
{

}
<?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 ExternalUrlException extends \Exception
{

}<?php
namespace Codeception;

use Codeception\Exception\TestRuntimeException;

class Scenario
{
    /**
     * @var    \Codeception\TestCase
     */
    protected $test;

    /**
     * @var    array
     */
    protected $steps = [];

    /**
     * @var    string
     */
    protected $feature;
    protected $running = false;
    protected $blocker = null;
    protected $groups = [];
    protected $env = [];

    protected $currents = [];

    /**
     * Constructor.
     *
     * @param  \Codeception\TestCase $test
     */
    public function __construct(\Codeception\TestCase $test, $currents = [])
    {
        $this->test = $test;
        $this->currents = $currents;
    }

    public function group($group)
    {
        if (!is_array($group)) {
            $this->groups[] = $group;
            return;
        }
        foreach ($group as $t) {
            $this->group($t);
        }
    }

    public function env($env)
    {
        if (!is_array($env)) {
            $this->env[] = $env;
            return;
        }
        foreach ($env as $e) {
            $this->env($e);
        }
    }

    public function groups()
    {
        $this->group(func_get_args());
    }

    public function getGroups()
    {
        return $this->groups;
    }

    public function getEnv()
    {
        return $this->env;
    }

    public function setFeature($feature)
    {
        $this->feature = $feature;
    }

    public function skip($reason = "")
    {
        $this->blocker = new \Codeception\Step\Skip($reason, []);
    }

    public function incomplete($reason = "")
    {
        $this->blocker = new \Codeception\Step\Incomplete($reason, []);
    }

    protected function ignore()
    {
        $this->blocker = new \Codeception\Step\Ignore;
    }

    public function runStep(Step $step)
    {
        $this->stopIfBlocked();
        $this->steps[] = $step;
        $result = $this->test->runStep($step);
        $step->executed = true;
        return $result;
    }

    public function addStep(\Codeception\Step $step)
    {
        $this->steps[] = $step;
        return $this->test;
    }

    /**
     * Returns the steps of this scenario.
     *
     * @return array
     */
    public function getSteps()
    {
        return $this->steps;
    }

    public function getFeature()
    {
        return $this->feature;
    }

    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>" . strtoupper('I want to ' . $this->getFeature()) . "</h3>" . $text;
        return $text;

    }

    public function getText()
    {
        $text = implode("\r\n", $this->getSteps());
        $text = str_replace(array('"\'','\'"'), array("'","'"), $text);
        $text = strtoupper('I want to ' . $this->getFeature()) . str_repeat("\r\n", 2) . $text . str_repeat("\r\n", 2);
        return $text;

    }

    public function comment($comment)
    {
        $this->runStep(new \Codeception\Step\Comment($comment, []));
    }

    public function stopIfBlocked()
    {
        if ($this->isBlocked()) {
            return $this->blocker->run();
        }
    }

    public function current($key)
    {
        if (!isset($this->currents[$key])) {
            return null;
        }
        return $this->currents[$key];
    }

    public function isBlocked()
    {
        return (bool)$this->blocker;
    }

    public function preload()
    {
        \Codeception\Lib\Notification::deprecate("Scenario is never preloaded. Please remove \$scenario->preload() call.", $this->getFeature());
        return false;
    }

    public function running()
    {
        \Codeception\Lib\Notification::deprecate("Scenario is always running. Please remove \$scenario->running() call.", $this->getFeature());
        return true;
    }

}
<?php
namespace Codeception\Event;

use Codeception\Lib\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\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;

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\TestCase
     */
    public function getTest()
    {
        return $this->test;
    }
}
<?php
namespace Codeception\Event;

use Codeception\Step;
use Codeception\TestCase;

class StepEvent extends TestEvent
{
    /**
     * @var Step
     */
    protected $step;

    public function __construct(TestCase $test, Step $step)
    {
        $this->test = $test;
        $this->step = $step;
    }

    public function getStep()
    {
        return $this->step;
    }
}
<?php
namespace Codeception\Event;

class FailEvent extends TestEvent
{
    /**
     * @var \Exception
     */
    protected $fail;

    /**
     * @var int
     */
    protected $count;

    public function __construct(\PHPUnit_Framework_Test $test, \Exception $e, $count = 0)
    {
        $this->test = $test;
        $this->fail = $e;
        $this->count = $count;
    }

    public function getCount()
    {
        return $this->count;
    }

    public function getFail()
    {
        return $this->fail;
    }
}
<?php
namespace Codeception\Command;

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 Symfony\Component\Console\Input\InputOption;
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;

    protected function configure()
    {
        $this->setDefinition([
            new InputArgument('suite', InputArgument::REQUIRED, 'suite to be generated'),
            new InputArgument('actor', InputArgument::OPTIONAL, 'name of new actor class'),
            new InputOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config'),
        ]);
    }

    public function getDescription()
    {
        return 'Generates new test suite';
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        $suite = lcfirst($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;
        }

        $config = \Codeception\Configuration::config($input->getOption('config'));
        if (!$actor) {
            $actor = ucfirst($suite) . $config['actor'];
        }
        $config['class_name'] = $actor;

        $dir = \Codeception\Configuration::testsDir();
        if (file_exists($dir . $suite . '.suite.yml')) {
            throw new \Exception("Suite configuration file '$suite.suite.yml' already exists.");
        }

        $this->buildPath($dir . $suite . DIRECTORY_SEPARATOR, $config['settings']['bootstrap']);

        // generate bootstrap
        $this->save(
            $dir . $suite . DIRECTORY_SEPARATOR . $config['settings']['bootstrap'],
            "<?php\n// Here you can initialize variables that will be available to your tests\n",
            true
        );
        $actorName = $this->removeSuffix($actor, $config['actor']);

        $file = $this->buildPath(\Codeception\Configuration::supportDir() . "Helper", "$actorName.php") . "$actorName.php";

        $gen = new Helper($actorName, $config['namespace']);
        // generate helper
        $this->save(
            $file,
            $gen->produce()
        );

        $conf = <<<EOF
class_name: {{actor}}
modules:
    enabled:
        - {{helper}}
EOF;

        $this->save($dir . $suite . '.suite.yml', (new Template($conf))
            ->place('actor', $actorName . $config['actor'])
            ->place('helper', $gen->getHelperName())
            ->produce()
        );

        $output->writeln("<info>Suite $suite generated</info>");
    }

    private function containsInvalidCharacters($suite)
    {
        return preg_match('#[^A-Za-z0-9_]#', $suite) ? true : false;
    }
}
<?php
namespace Codeception\Command\Shared;

use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Symfony\Component\Console\Output\OutputInterface;

trait Style
{
    public function addStyles(OutputInterface $output)
    {
        $style = new OutputFormatterStyle('white', 'green', ['bold']);
        $output->getFormatter()->setStyle('notice', $style);
    }
}
<?php
namespace Codeception\Command\Shared;

use Codeception\Util\Shared\Namespaces;

trait FileSystem
{
    use Namespaces;

    protected function buildPath($basePath, $testName)
    {
        $basePath = rtrim($basePath, DIRECTORY_SEPARATOR);
        $testName = str_replace(['/', '\\'], [DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR], $testName);
        $path = $basePath . DIRECTORY_SEPARATOR . $testName;
        $path = pathinfo($path, PATHINFO_DIRNAME) . DIRECTORY_SEPARATOR;
        if (!file_exists($path)) {
            // Second argument should be mode. Well, umask() doesn't seem to return any if not set. Config may fix this.
            mkdir($path, 0775, true); // Third parameter commands to create directories recursively
        }
        return $path;
    }

    protected function getClassName($class)
    {
        $namespaces = $this->breakParts($class);
        return array_pop($namespaces);
    }

    protected function breakParts($class)
    {
        $class      = str_replace('/', '\\', $class);
        $namespaces = explode('\\', $class);
        if (count($namespaces)) {
            $namespaces[0] = ltrim($namespaces[0], '\\');
        }
        if (!$namespaces[0]) {
            array_shift($namespaces);
        } // remove empty namespace caused of \\
        return $namespaces;
    }

    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 save($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 Codeception\Configuration;

trait Config
{
    protected function getSuiteConfig($suite, $conf)
    {
        $config = Configuration::config($conf);
        return Configuration::suiteSettings($suite, $config);
    }

    protected function getGlobalConfig($conf)
    {
        return Configuration::config($conf);
    }

    protected function getSuites($conf)
    {
        Configuration::config($conf);
        return Configuration::suites();
    }
}
<?php
namespace Codeception\Command;

use Codeception\Codecept;
use Codeception\Configuration;
use Codeception\Event\SuiteEvent;
use Codeception\Event\TestEvent;
use Codeception\Events;
use Codeception\Lib\Console\Output;
use Codeception\Scenario;
use Codeception\SuiteManager;
use Codeception\TestCase\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
{
    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('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config'),
            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($input->getOption('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())
            ->configDispatcher($dispatcher)
            ->configModules($moduleContainer)
            ->configName('')
            ->config('file', '')
            ->initConfig();

        $scenario = new Scenario($this->test);
        if (isset($config["namespace"])) {
            $settings['class_name'] = $config["namespace"] .'\\' . $settings['class_name'];
        }
        $actor = $settings['class_name'];
        $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>");
        $output->writeln("<info>type 'exit' to leave console</info>");
        $output->writeln("<info>type 'actions' to see all available actions for this suite</info>");

        $suiteEvent = new SuiteEvent($this->suite, $this->codecept->getResult(), $settings);
        $dispatcher->dispatch(Events::SUITE_BEFORE, $suiteEvent);

        $dispatcher->dispatch(Events::TEST_PARSED, new TestEvent($this->test));
        $dispatcher->dispatch(Events::TEST_BEFORE, new TestEvent($this->test));

        $output->writeln("\n\n<comment>\$I</comment> = new {$settings['class_name']}(\$scenario);");
        $scenario->stopIfBlocked();
        $this->executeCommands($input, $output, $I, $settings['bootstrap']);

        $dispatcher->dispatch(Events::TEST_AFTER, new TestEvent($this->test));
        $dispatcher->dispatch(Events::SUITE_AFTER, new SuiteEvent($this->suite));

        $output->writeln("<info>Bye-bye!</info>");
    }

    protected function executeCommands(InputInterface $input, OutputInterface $output, $I, $bootstrap)
    {
        $dialog = new QuestionHelper();

        if (file_exists($bootstrap)) {
            require $bootstrap;
        }

        do {
            $question = new Question("<comment>\$I-></comment>");
            $question->setAutocompleterValues($this->actions);

            $command = $dialog->ask($input, $output, $question);
            if ($command == 'actions') {
                $output->writeln("<info>" . implode(' ', $this->actions));
                continue;
            }
            if ($command == 'exit') {
                return;
            }
            if ($command == '') {
                continue;
            }
            try {
                $value = eval("return \$I->$command;");
                if ($value && !is_object($value)) {
                    codecept_debug($value);
                }
            } catch (\PHPUnit_Framework_AssertionFailedError $fail) {
                $output->writeln("<error>fail</error> " . $fail->getMessage());
            } catch (\Exception $e) {
                $output->writeln("<error>error</error> " . $e->getMessage());
            }
        } while (true);
    }

    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\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\Input\InputOption;
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'),
            new InputOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config'),
        ]);
    }

    public function getDescription()
    {
        return 'Generates Group subscriber';
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        $config = $this->getGlobalConfig($input->getOption('config'));
        $group = $input->getArgument('group');

        $class = ucfirst($group);
        $path = $this->buildPath(Configuration::supportDir() . 'Group' . DIRECTORY_SEPARATOR, $class);

        $filename = $path . $class . '.php';

        $gen = new GroupGenerator($config, $group);
        $res = $this->save($filename, $gen->produce());

        if (!$res) {
            $output->writeln("<error>Group $filename already exists</error>");
            return;
        }

        $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.');
    }
}
<?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\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Generates Cept (scenario-driven test) file:
 *
 * * `codecept generate:cept suite Login`
 * * `codecept g:cept suite subdir/subdir/testnameCept.php`
 * * `codecept g:cept suite LoginCept -c path/to/project`
 *
 */
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'),
            new InputOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config'),
        ]);
    }

    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, $input->getOption('config'));
        $this->buildPath($config['path'], $filename);

        $filename = $this->completeSuffix($filename, 'Cept');
        $gen = new Cept($config);

        $full_path = rtrim( $config['path'], DIRECTORY_SEPARATOR ) . DIRECTORY_SEPARATOR . $filename;
        $res = $this->save($full_path, $gen->produce());
        if (!$res) {
            $output->writeln("<error>Test $filename already exists</error>");
            return;
        }
        $output->writeln("<info>Test was created in $full_path</info>");
    }
}
<?php
namespace Codeception\Command;

use Codeception\Codecept;
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;

/**
 * Executes tests.
 *
 * ```
 * Arguments:
 *  suite                 suite to be tested
 *  test                  test to be run
 *
 * Options:
 *  --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")
 *  --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
 *  --steps               Show steps in output
 *  --debug (-d)          Show debug and scenario output
 *  --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")
 *  --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 first failure
 *  --help (-h)           Display this help message.
 *  --quiet (-q)          Do not output any message.
 *  --verbose (-v|vv|vvv) Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for 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.
 * ```
 *
 */
class Run extends Command
{
    /**
     * @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
     */
    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('config', 'c', InputOption::VALUE_REQUIRED, 'Use custom path for config'),
            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('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('coverage', '', InputOption::VALUE_OPTIONAL, 'Run with code coverage', 'coverage.serialized'),
            new InputOption('coverage-html', '', InputOption::VALUE_OPTIONAL, 'Generate CodeCoverage HTML report in path', 'coverage'),
            new InputOption('coverage-xml', '', InputOption::VALUE_OPTIONAL, 'Generate CodeCoverage XML report in file', 'coverage.xml'),
            new InputOption('coverage-text', '', InputOption::VALUE_OPTIONAL, 'Generate CodeCoverage text report in file', 'coverage.txt'),
            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_NONE, 'Stop after first failure'),
            new InputOption('no-rebuild', '', InputOption::VALUE_NONE, 'Do not rebuild actor classes on start'),
        ]);

        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
     * @throws \RuntimeException
     */
    public function execute(InputInterface $input, OutputInterface $output)
    {
        $this->ensureCurlIsAvailable();
        $this->options = $input->getOptions();
        $this->output = $output;

        $config = Configuration::config($this->options['config']);

        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['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', 'html', 'json', 'tap', 'coverage', 'coverage-xml', 'coverage-html']));
        $userOptions['verbosity'] = $this->output->getVerbosity();
        $userOptions['interactive'] = !$input->hasParameterOption(['--no-interaction', '-n']);

        if ($this->options['no-colors']) {
            $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']) {
            $this->options['coverage'] = true;
        }


        $suite = $input->getArgument('suite');
        $test = $input->getArgument('test');

        if (! Configuration::isEmpty() && ! $test && strpos($suite, $config['paths']['tests']) === 0) {
            list(, $suite, $test) = $this->matchTestFromFilename($suite, $config['paths']['tests']);
        }

        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) {
            $filter = $this->matchFilteredTestName($test);
            $userOptions['filter'] = $filter;
        }

        $this->codecept = new Codecept($userOptions);

        if ($suite and $test) {
            $this->codecept->run($suite, $test);
        }

        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);
            }
        }
    }

    /**
     * Runs included suites recursively
     *
     * @param array $suites
     * @param string $parent_dir
     */
    protected function runIncludedSuites($suites, $parent_dir)
    {
        foreach ($suites as $relativePath) {
            $current_dir = rtrim($parent_dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $relativePath;
            $config = Configuration::config($current_dir);
            $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, $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;
    }

    private function matchFilteredTestName(&$path)
    {
        $test_parts = explode(':', $path);
        if (count($test_parts) > 1) {
            list($path, $filter) = $test_parts;
            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 (strpos($token, '--') === 0 && $token !== '--') {
                $options[] = substr($token, 2);
                continue;
            }
            if (strpos($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) {
            if (strpos($request, "--$option")) {
                $values[$option] = $input->hasParameterOption($option)
                    ? $input->getParameterOption($option)
                    : $input->getOption($option);
            } else {
                $values[$option] = false;
            }
        }
        return $values;
    }

    private function ensureCurlIsAvailable()
    {
        if (!extension_loaded('curl')) {
            throw new \Exception(
                "Codeception requires CURL extension installed to make tests run\n"
                . "If you are not sure, how to install CURL, 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 CURL enabled."
            );
        }
    }
}
<?php
namespace Codeception\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;

/**
 * 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 = 'Codeception/Codeception';
    const SOURCE = 'http://codeception.com/codecept.phar';
    const SOURCE_PHP54 = 'http://codeception.com/php54/codecept.phar';

    /**
     * Holds the current script filename.
     * @var string
     */
    protected $filename;

    /**
     * Holds the live version string.
     * @var string
     */
    protected $liveVersion;

    /**
     * {@inheritdoc}
     */
    protected function configure()
    {
        $this->filename = $_SERVER['argv'][0];

        $this
            // ->setAliases(array('selfupdate'))
            ->setDescription(
                sprintf(
                    'Upgrade <comment>%s</comment> to the latest version',
                    $this->filename
                )
            );

        parent::configure();
    }

    /**
     * {@inheritdoc}
     */
    public function execute(InputInterface $input, OutputInterface $output)
    {
        $version = \Codeception\Codecept::VERSION;

        $output->writeln(
            sprintf(
                '<info>%s</info> version <comment>%s</comment>',
                self::NAME, $version
            )
        );

        $output->writeln("\n<info>Checking for a new version...</info>\n");
        try {
            if ($this->isOutOfDate($version)) {
                $output->writeln(
                    sprintf(
                        'A newer version is available: <comment>%s</comment>',
                        $this->liveVersion
                    )
                );
                if (!$input->getOption('no-interaction')) {

                    $dialog = $this->getHelperSet()->get('question');
                    $question = new ConfirmationQuestion("\n<question>Do you want to update?</question> ", false);
                    if (!$dialog->ask($input, $output, $question)) {
                        $output->writeln("\n<info>Bye-bye!</info>\n");

                        return;
                    }
                }
                $output->writeln("\n<info>Updating...</info>");

                $this->retrieveLatestPharFile($output);

            } else {
                $output->writeln('You are already using the latest version.');
            }

        } catch (\Exception $e) {
            $output->writeln(
                sprintf(
                    "<error>\n%s\n</error>",
                    $e->getMessage()
                )
            );
        }

    }

    /**
     * Checks whether the provided version is current.
     *
     * @param  string $version The version number to check.
     * @return boolean Returns True if a new version is available.
     */
    private function isOutOfDate($version)
    {
        $tags = $this->getGithubTags(self::GITHUB);

        $this->liveVersion = array_reduce(
            $tags,
            function ($a, $b) {
                return version_compare($a, $b, '>') ? $a : $b;
            }
        );

        return -1 != version_compare($version, $this->liveVersion, '>=');
    }

    /**
     * Returns an array of tags from a github repo.
     *
     * @param  string $repo The repository name to check upon.
     * @return array
     */
    private function getGithubTags($repo)
    {
        $jsonTags = $this->retrieveContentFromUrl(
            'https://api.github.com/repos/' . $repo . '/tags'
        );

        return array_map(
            function ($tag) {
                return $tag['name'];
            },
            json_decode($jsonTags, true)
        );
    }

    /**
     * Retrieves the body-content from the provided URL.
     *
     * @param  string $url
     * @return string
     * @throw Exception if status code is above 300
     */
    private function retrieveContentFromUrl($url)
    {
        $ctx = $this->prepareContext($url);

        $body = file_get_contents($url, 0, $ctx);

        if (isset($http_response_header)) {
            $code = substr($http_response_header[0], 9, 3);
            if (floor($code / 100) > 3) {
                throw new \Exception($http_response_header[0]);
            }
        } else {
            throw new \Exception('Request failed.');
        }

        return $body;
    }

    /**
     * Add proxy support to context if environment variable was set up
     *
     * @param array $opt context options
     * @param string $url
     */
    private function prepareProxy(&$opt, $url)
    {
        $scheme = parse_url($url)['scheme'];
        if ($scheme === 'http' && (!empty($_SERVER['HTTP_PROXY']) || !empty($_SERVER['http_proxy']))) {
            $proxy = !empty($_SERVER['http_proxy']) ? $_SERVER['http_proxy'] : $_SERVER['HTTP_PROXY'];
        }

        if ($scheme === 'https' && (!empty($_SERVER['HTTPS_PROXY']) || !empty($_SERVER['https_proxy']))) {
            $proxy = !empty($_SERVER['https_proxy']) ? $_SERVER['https_proxy'] : $_SERVER['HTTPS_PROXY'];
        }

        if (!empty($proxy)) {
            $proxy = str_replace(['http://', 'https://'], ['tcp://', 'ssl://'], $proxy);
            $opt['http']['proxy'] = $proxy;
        }

    }

    /**
     * Preparing context for request
     * @param $url
     *
     * @return resource
     */
    private function prepareContext($url)
    {
        $opts = [
            'http' => [
                'follow_location' => 1,
                'max_redirects'   => 20,
                'timeout'         => 10,
                'user_agent'      => self::NAME
            ]
        ];
        $this->prepareProxy($opts, $url);
        return stream_context_create($opts);
    }

    /**
     * Retrieves the latest phar file.
     *
     * @param OutputInterface $output
     */
    protected function retrieveLatestPharFile(OutputInterface $output)
    {
        $temp = basename($this->filename, '.phar') . '-temp.phar';

        try {
            $source = self::SOURCE;
            if (version_compare(PHP_VERSION, '5.6.0', '<')) {
                $source = self::SOURCE_PHP54;
            }

            if (@copy($source, $temp)) {
                chmod($temp, 0777 & ~umask());

                // test the phar validity
                $phar = new \Phar($temp);
                // free the variable to unlock the file
                unset($phar);
                rename($temp, $this->filename);
            } else {
                throw new \Exception('Request failed.');
            }
        } catch (\Exception $e) {
            if (
                !$e instanceof \UnexpectedValueException
                && !$e instanceof \PharException
            ) {
                throw $e;
            }
            unlink($temp);

            $output->writeln(
                sprintf(
                    "<error>\nSomething went wrong (%s).\nPlease re-run this again.</error>\n",
                    $e->getMessage()
                )
            );
        }

        $output->writeln(
            sprintf(
                "\n<comment>%s</comment> has been updated.\n",
                $this->filename
            )
        );
    }

}
<?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\Input\InputOption;
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'),
                new InputOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config'),
            ]
        );
        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, $input->getOption('config'));

        $className = $this->getClassName($class);
        $path = $this->buildPath($config['path'], $class);

        $filename = $this->completeSuffix($className, 'Test');
        $filename = $path . $filename;

        $gen = new TestGenerator($config, $class);

        $res = $this->save($filename, $gen->produce());

        if (!$res) {
            $output->writeln("<error>Test $filename already exists</error>");
            return;
        }
        $output->writeln("<info>Test was created in $filename</info>");
    }
}
<?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\Input\InputOption;
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 configure()
    {
        $this->setDefinition([
            new InputOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config'),
        ]);
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->output = $output;
        $this->buildActorsForConfig($input->getOption('config'));
    }
    
    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->buildPath(
            Configuration::supportDir(),
            $settings['class_name']) . $this->getClassName($settings['class_name']
        );
        $file .=  '.php';
        return $this->save($file, $content);
    }
    
    private function buildActions(array $settings)
    {
        $actionsGenerator = new ActionsGenerator($settings);
        $this->output->writeln(
            " -> {$settings['class_name']}Actions.php generated successfully. "
            . $actionsGenerator->getNumMethods() . " methods added"
        );
        
        $content = $actionsGenerator->produce();
        
        $file = $this->buildPath(Configuration::supportDir() . '_generated', $settings['class_name']);
        $file .= $this->getClassName($settings['class_name']) . 'Actions.php';
        return $this->save($file, $content, true);
    }

    private function buildSuiteActors($configFile)
    {
        $suites = $this->getSuites($configFile);
        if (!empty($suites)) {
            $this->output->writeln("<info>Building Actor classes for suites: " . implode(', ', $suites) . '</info>');
        }
        foreach ($suites as $suite) {
            $settings = $this->getSuiteConfig($suite, $configFile);
            $this->buildActions($settings);
            $actorBuilt = $this->buildActor($settings);
            
            if ($actorBuilt) {
                $this->output->writeln("{$settings['class_name']}.php created.");
            }
        }
    }
    
    protected function buildActorsForConfig($configFile)
    {
        $config = $this->getGlobalConfig($configFile);
        
        $path = pathinfo($configFile);
        $dir = isset($path['dirname']) ? $path['dirname'] : getcwd();

        foreach ($config['include'] as $subConfig) {
            $this->output->writeln("<comment>Included Configuration: $subConfig</comment>");
            $this->buildActorsForConfig($dir . DIRECTORY_SEPARATOR . $subConfig);
        }
        $this->buildSuiteActors($configFile);
    }
}
<?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\Input\InputOption;
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'),
            new InputOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config'),
        ]);
    }

    public function getDescription()
    {
        return 'Generates new helper';
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        $name = ucfirst($input->getArgument('name'));
        $config = Configuration::config($input->getOption('config'));

        $path = $this->buildPath(Configuration::supportDir() . 'Helper', $name);
        $filename = $path . $this->getClassName($name) . '.php';

        $res = $this->save($filename, (new Helper($name, $config['namespace']))->produce());
        if ($res) {
            $output->writeln("<info>Helper $filename created</info>");
        } else {
            $output->writeln("<error>Error creating helper $filename</error>");
        }
    }
}
<?php
namespace Codeception\Command;

use Codeception\Lib\Generator\Helper;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\ArrayInput;
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\Yaml\Yaml;
use Symfony\Component\Console\Question\Question;

/**
 * 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
{
    // defaults
    protected $namespace = '';
    protected $actorSuffix = 'Tester';
    protected $supportDir = 'tests/_support';
    protected $logDir = 'tests/_output';
    protected $dataDir = 'tests/_data';
    protected $envsDir = 'tests/_envs';

    protected function configure()
    {
        $this->setDefinition(
            [
                new InputArgument('path', InputArgument::OPTIONAL, 'custom installation path', '.'),
                new InputOption('namespace', 'ns', 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 requires files";
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        if ($input->getOption('namespace')) {
            $this->namespace = trim($input->getOption('namespace'), '\\') . '\\';
        }

        if ($input->getOption('actor')) {
            $this->actorSuffix = $input->getOption('actor');
        }

        $path = $input->getArgument('path');

        if (!is_dir($path)) {
            $output->writeln("<error>\nDirectory '$path' does not exist\n</error>");
            return;
        }

        $realpath = realpath($path);
        chdir($path);

        if (file_exists('codeception.yml')) {
            $output->writeln("<error>\nProject is already initialized in '$path'\n</error>");
            return;
        }

        $output->writeln(
            "<fg=white;bg=magenta> Initializing Codeception in " . $realpath . " </fg=white;bg=magenta>\n"
        );

        $this->createGlobalConfig();
        $output->writeln("File codeception.yml created       <- global configuration");

        $this->createDirs();

        if (!$input->getOption('empty')) {
            $this->createUnitSuite();
            $output->writeln("tests/unit created                 <- unit tests");
            $output->writeln("tests/unit.suite.yml written       <- unit tests suite configuration");
            $this->createFunctionalSuite();
            $output->writeln("tests/functional created           <- functional tests");
            $output->writeln("tests/functional.suite.yml written <- functional tests suite configuration");
            $this->createAcceptanceSuite();
            $output->writeln("tests/acceptance created           <- acceptance tests");
            $output->writeln("tests/acceptance.suite.yml written <- acceptance tests suite configuration");
        }

        if (file_exists('.gitignore')) {
            file_put_contents('tests/_output/.gitignore', '');
            file_put_contents('.gitignore', file_get_contents('.gitignore') . "\ntests/_output/*");
            $output->writeln("tests/_output was added to .gitignore");
        }

        $output->writeln(" --- ");
        $this->ignoreFolderContent('tests/_output');

        file_put_contents('tests/_bootstrap.php', "<?php\n// This is global bootstrap for autoloading\n");
        $output->writeln("tests/_bootstrap.php written <- global bootstrap file");

        $output->writeln("<info>Building initial {$this->actorSuffix} classes</info>");
        $this->getApplication()->find('build')->run(
            new ArrayInput(['command' => 'build']),
            $output
        );

        $output->writeln("<info>\nBootstrap is done. Check out " . $realpath . "/tests directory</info>");
    }

    public function createGlobalConfig()
    {
        $basicConfig = [
            'actor'    => $this->actorSuffix,
            'paths'    => [
                'tests'   => 'tests',
                'log'     => $this->logDir,
                'data'    => $this->dataDir,
                'support' => $this->supportDir,
                'envs'    => $this->envsDir,
            ],
            'settings' => [
                'bootstrap'    => '_bootstrap.php',
                'colors'       => (strtoupper(substr(PHP_OS, 0, 3)) != 'WIN'),
                'memory_limit' => '1024M'
            ],
            'extensions' => [
                'enabled' => ['Codeception\Extension\RunFailed']
            ],
            'modules'  => [
                'config' => [
                    'Db' => [
                        'dsn'      => '',
                        'user'     => '',
                        'password' => '',
                        'dump'     => 'tests/_data/dump.sql'
                    ]
                ]
            ]
        ];

        $str = Yaml::dump($basicConfig, 4);
        if ($this->namespace) {
            $namespace = rtrim($this->namespace, '\\');
            $str = "namespace: $namespace\n" . $str;
        }
        file_put_contents('codeception.yml', $str);
    }

    protected function createFunctionalSuite($actor = 'Functional')
    {
        $suiteConfig = <<<EOF
# Codeception Test Suite Configuration
#
# Suite for functional (integration) tests
# Emulate web requests and make application process them
# Include one of framework modules (Symfony2, Yii2, Laravel5) to use it

class_name: $actor{$this->actorSuffix}
modules:
    enabled:
        # add framework module here
        - \\{$this->namespace}Helper\Functional
EOF;
        $this->createSuite('functional', $actor, $suiteConfig);
    }

    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.

class_name: $actor{$this->actorSuffix}
modules:
    enabled:
        - PhpBrowser:
            url: http://localhost/myapp
        - \\{$this->namespace}Helper\Acceptance
EOF;
        $this->createSuite('acceptance', $actor, $suiteConfig);
    }

    protected function createUnitSuite($actor = 'Unit')
    {
        $suiteConfig = <<<EOF
# Codeception Test Suite Configuration
#
# Suite for unit (internal) tests.

class_name: $actor{$this->actorSuffix}
modules:
    enabled:
        - Asserts
        - \\{$this->namespace}Helper\Unit
EOF;
        $this->createSuite('unit', $actor, $suiteConfig);
    }

    protected function createSuite($suite, $actor, $config)
    {
        @mkdir("tests/$suite");
        file_put_contents(
            "tests/$suite/_bootstrap.php",
            "<?php\n// Here you can initialize variables that will be available to your tests\n"
        );
        @mkdir($this->supportDir . DIRECTORY_SEPARATOR . "Helper");
        file_put_contents(
            $this->supportDir . DIRECTORY_SEPARATOR . "Helper" . DIRECTORY_SEPARATOR . "$actor.php",
            (new Helper($actor, rtrim($this->namespace, '\\')))->produce()
        );
        file_put_contents("tests/$suite.suite.yml", $config);
    }

    protected function ignoreFolderContent($path)
    {
        if (file_exists('.gitignore')) {
            file_put_contents("{$path}/.gitignore", "*\n!.gitignore");
        }
    }


    protected function createDirs()
    {
        @mkdir('tests');
        @mkdir($this->logDir);
        @mkdir($this->dataDir);
        @mkdir($this->supportDir);
        @mkdir($this->envsDir);
        file_put_contents(
            $this->dataDir . '/dump.sql',
            '/* Replace this file with actual dump of your database */'
        );
    }

}
<?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\Input\InputOption;
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 specifed 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'),
            new InputOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config'),
        ]);
    }

    public function getDescription()
    {
        return 'Generates empty environment config';
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        $conf = $this->getGlobalConfig($input->getOption('config'));
        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->buildPath($relativePath, $file);
        $saved = $this->save($path . $file, "# `$env` environment config goes here");

        if ($saved) {
            $output->writeln("<info>$env config was created in $relativePath/$file</info>");
        } else {
            $output->writeln("<error>File $relativePath/$file already exists</error>");
        }

    }

}<?php
namespace Codeception\Command;

use Codeception\Lib\Generator\PhpUnit as PhpUnitGenerator;
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 skeleton for unit test as in classical PHPUnit.
 *
 * * `codecept g:phpunit unit UserTest`
 * * `codecept g:phpunit unit User`
 * * `codecept g:phpunit unit "App\User`
 *
 */
class GeneratePhpUnit 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'),
            new InputOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config'),
        ]);
        parent::configure();
    }

    public function getDescription()
    {
        return 'Generates empty PHPUnit test without Codeception additions';
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        $suite = $input->getArgument('suite');
        $class = $input->getArgument('class');

        $config = $this->getSuiteConfig($suite, $input->getOption('config'));

        $path = $this->buildPath($config['path'], $class);

        $filename = $this->completeSuffix($this->getClassName($class), 'Test');
        $filename = $path . $filename;

        $gen = new PhpUnitGenerator($config, $class);

        $res = $this->save($filename, $gen->produce());
        if (!$res) {
            $output->writeln("<error>Test $filename already exists</error>");
            exit;
        }

        $output->writeln("<info>Test was created in $filename</info>");
    }
}
<?php
namespace Codeception\Command;

use Codeception\Configuration;
use Codeception\Exception\ConfigurationException as ConfigurationException;
use Codeception\TestCase\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, Cept).
 *
 * * `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('config', 'c', InputOption::VALUE_REQUIRED, 'Use specified config instead of default'),
            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'),
            new InputOption('config', 'c', InputOption::VALUE_REQUIRED, 'Use specified config instead of default'),
        ]);
        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, $input->getOption('config'));

        $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 (get_class($test) == 'Codeception\TestCase\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->save($path . DIRECTORY_SEPARATOR . $name . $this->formatExtension($format), $feature, true);
                $output->writeln("* $name generated");
            }
        }

        if ($input->getOption('single-file')) {
            $this->save($path . $this->formatExtension($format), $this->decorate($scenarios, $format), true);
        }
    }

    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\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:step acceptance AdminSteps`
 * * `codecept g:step 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('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config'),
            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, $input->getOption('config'));

        $class = $this->getClassName($step);

        $path = $this->buildPath(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->save($filename, $gen->produce());

        if (!$res) {
            $output->writeln("<error>StepObject $filename already exists</error>");
            exit;
        }
        $output->writeln("<info>StepObject was created in $filename</info>");
    }
}
<?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\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Cleans `output` directory
 *
 * * `codecept clean`
 * * `codecept clean -c path/to/project`
 *
 */
class Clean extends Command
{
    use Shared\Config;

    public function getDescription()
    {
        return 'Cleans or creates _output directory';
    }

    protected function configure()
    {
        $this->setDefinition([
            new InputOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config'),
        ]);
        parent::configure();
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->getGlobalConfig($input->getOption('config'));
        $output->writeln("<info>Cleaning up " . Configuration::outputDir() . "...</info>");
        FileSystem::doEmptyDir(Configuration::outputDir());
        $output->writeln("Done");
    }
}<?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\Input\InputOption;
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'),
            new InputOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config'),
        ]);
    }

    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, $input->getOption('config'));
        $className = $this->getClassName($class);
        $path = $this->buildPath($config['path'], $class);

        $filename = $this->completeSuffix($className, 'Cest');
        $filename = $path . $filename;

        if (file_exists($filename)) {
            $output->writeln("<error>Test $filename already exists</error>");
            return;
        }
        $gen = new CestGenerator($class, $config);
        $res = $this->save($filename, $gen->produce());
        if (!$res) {
            $output->writeln("<error>Test $filename already exists</error>");
            return;
        }

        $output->writeln("<info>Test was created in $filename</info>");
    }
}
<?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\Input\InputOption;
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'),
            new InputOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Use custom path for config'),
        ]);
        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 = null;
        }

        $conf = $suite
            ? $this->getSuiteConfig($suite, $input->getOption('config'))
            : $this->getGlobalConfig($input->getOption('config'));

        if ($suite) {
            $suite = DIRECTORY_SEPARATOR . ucfirst($suite);
        }

        $path = $this->buildPath(Configuration::supportDir() . 'Page' . $suite, $class);

        $filename = $path . $this->getClassName($class) . '.php';

        $output->writeln($filename);

        $gen = new PageObjectGenerator($conf, ucfirst($suite) . '\\' . $class);
        $res = $this->save($filename, $gen->produce());

        if (!$res) {
            $output->writeln("<error>PageObject $filename already exists</error>");
            exit;
        }
        $output->writeln("<info>PageObject was created in $filename</info>");
    }

    protected function pathToPageObject($class, $suite)
    {
    }
}
<?php
namespace Codeception;

use Codeception\Lib\ModuleContainer;
use Codeception\Step\Meta;
use Codeception\Util\Locator;

abstract class Step
{
    const STACK_POSITION = 3;
    /**
     * @var    string
     */
    protected $action;

    /**
     * @var    array
     */
    protected $arguments;

    protected $debugOutput;

    public $executed = false;

    protected $line = null;
    protected $file = null;
    protected $actor = 'I';

    /**
     * @var Meta
     */
    protected $metaStep = null;

    protected $failed = false;

    public function __construct($action, array $arguments)
    {
        $this->action = $action;
        $this->arguments = $arguments;
        $this->storeCallerInfo();
    }

    protected function storeCallerInfo()
    {
        if (!function_exists('xdebug_get_function_stack')) {
            return;
        }

        ini_set('xdebug.collect_params', '1');
        $stack = xdebug_get_function_stack();
        ini_set('xdebug.collect_params', 0);
        if (count($stack) <= self::STACK_POSITION) {
            return;
        }
        $traceLine = $stack[count($stack) - self::STACK_POSITION];

        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($asString = false)
    {
        return ($asString) ? $this->getArgumentsAsString($this->arguments) : $this->arguments;
    }

    protected function getArgumentsAsString(array $arguments)
    {
        $argumentsAsJson = [];
        foreach ($arguments as $key => $argument) {
            $argumentsAsJson []= stripcslashes(json_encode($this->parseArgumentAsString($argument), JSON_UNESCAPED_UNICODE));
        }

        return implode(',', $argumentsAsJson);
    }

    protected function parseArgumentAsString($argument)
    {
        if (is_object($argument)) {
            if (method_exists($argument, '__toString')) {
                return (string)$argument;
            }
            if (get_class($argument) == 'Facebook\WebDriver\WebDriverBy') {
                return Locator::humanReadableString($argument);
            }
            return $this->getClassName($argument);
        }

        if (is_array($argument)) {
            foreach ($argument as $key => $value) {
                if (is_object($value)) {
                    $argument[$key] = $this->getClassName($value);
                }
            }
            return $argument;
        }

        if (is_resource($argument)) {
            return (string)$argument;
        }

        return $argument;
    }


    protected function getClassName($argument)
    {
        if ($argument instanceof \Closure) {
            return 'Closure';
        } elseif ((isset($argument->__mocked))) {
            return $this->formatClassName($argument->__mocked);
        } else {
            return $this->formatClassName(get_class($argument));
        }
    }

    protected function formatClassName($classname)
    {
        return trim($classname, "\\");
    }

    public function getPhpCode()
    {
        return "\${$this->actor}->" . $this->getAction() . '(' . $this->getHumanizedArguments() .')';
    }

    /**
     * @return Meta
     */
    public function getMetaStep()
    {
        return $this->metaStep;

    }

    public function __toString()
    {
        return $this->actor . ' ' . $this->humanize($this->getAction()) . ' ' . $this->getHumanizedArguments();
    }

    public function getHtml($highlightColor = '#732E81')
    {
        if (empty($this->arguments)) {
            return sprintf('%s %s', ucfirst($this->actor), $this->humanize($this->getAction()));
        }

        return sprintf('%s %s <span style="color: %s">%s</span>', ucfirst($this->actor), $this->humanize($this->getAction()), $highlightColor, $this->getHumanizedArguments());
    }

    public function getHumanizedActionWithoutArguments()
    {
        return $this->humanize($this->getAction());
    }

    public function getHumanizedArguments()
    {
        return $this->clean($this->getArguments(true));
    }

    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 strtolower($text);
    }

    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) {
            $this->failed = 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'])) {
                continue;
            }

            if (!$this->isTestFile($step['file'])) {
                continue;
            }

            $this->metaStep = new Meta($step['function'], array_values($step['params']));
            $this->metaStep->setTraceInfo($step['file'], $step['line']);

            // pageobjects or other classes should not be included with "I"
            if (!(new \ReflectionClass($step['class']))->isSubclassOf('Codeception\Actor')) {
                $this->metaStep->setActor($step['class'] . ':');
            }
            return;
        }
    }
}
<?php
namespace Codeception\Module;

use Codeception\Lib\Notification;
use Codeception\Module as CodeceptionModule;
use Codeception\Lib\Interfaces\Db as DbInterface;
use Codeception\Exception\ModuleConfigException;
use Codeception\TestCase;

/**
 * This module replaces Db module for functional and unit testing, and requires PDO instance to be set.
 * By default it will cover all database queries into transaction and rollback it afterwards.
 * The database should support nested transactions, in order to make cleanup work as expected.
 *
 * Pass PDO instance to this module from within your bootstrap file.
 *
 * In _bootstrap.php:
 *
 * ``` php
 * <?php
 * \Codeception\Module\Dbh::$dbh = $dbh;
 * ?>
 * ```
 *
 * This will make all queries in this connection run withing transaction and rolled back afterwards.
 *
 * Note, that you can't use this module with MySQL. Or perhaps you don't use transactions in your project, then it's ok.
 * Otherwise consider using ORMs like Doctrine, that emulate nested transactions, or switch to Db module.
 *
 * ## Status
 *
 * * Maintainer: **davert**
 * * Stability: **stable**
 * * Contact: codecept@davert.mail.ua
 *
 * This module despite of it's stability may act unstable because of transactions issue. If test fails with fatal error and transaction is not finished, it may affect other transactions.
 *
 * *Please review the code of non-stable modules and provide patches if you have issues.*
 *
 * ### Configuration
 *
 * * cleanup: true - enable cleanups by covering all queries inside transaction.
 *
 * ### Example
 *
 *     modules:
 *        enabled: [Dbh]
 *        config:
 *           Dbh:
 *              cleanup: false
 *
 */
class Dbh extends CodeceptionModule implements DbInterface
{
    public static $dbh;

    public function _initialize()
    {
        Notification::deprecate("Module Dbh is deprecated and will be removed in 2.2");
    }

    public function _before(TestCase $test)
    {
        if (!self::$dbh) {
            throw new ModuleConfigException(
                __CLASS__,
                "Transaction module requires PDO instance explicitly set.\n"
                . "You can use your bootstrap file to assign the dbh:\n\n"
                . '\Codeception\Module\Dbh::$dbh = $dbh'
            );
        }

        if (!self::$dbh->inTransaction()) {
            self::$dbh->beginTransaction();
        }
    }

    public function _after(TestCase $test)
    {

        if (!self::$dbh) {
            throw new ModuleConfigException(
                __CLASS__,
                "Transaction module requires PDO instance explicitly set.\n"
                . "You can use your bootstrap file to assign the dbh:\n\n"
                . '\Codeception\Module\Dbh::$dbh = $dbh'
            );
        }

        if (self::$dbh->inTransaction()) {
            self::$dbh->rollback();
        }
    }

    public function seeInDatabase($table, $criteria = [])
    {
        $res = $this->proceedSeeInDatabase($table, "count(*)", $criteria);
        \PHPUnit_Framework_Assert::assertGreaterThan(0, $res);
    }


    public function dontSeeInDatabase($table, $criteria = [])
    {
        $res = $this->proceedSeeInDatabase($table, "count(*)", $criteria);
        \PHPUnit_Framework_Assert::assertLessThan(1, $res);
    }

    protected function proceedSeeInDatabase($table, $column, $criteria)
    {
        $params = [];
        foreach ($criteria as $k => $v) {
            $params[] = "$k = ?";
        }
        $sparams = implode('AND ', $params);

        $query = sprintf('select %s from %s where %s', $column, $table, $sparams);

        $this->debugSection('Query', $query, $sparams);

        $sth = self::$dbh->prepare($query);
        $sth->execute(array_values($criteria));
        return $sth->fetchColumn();
    }

    public function grabFromDatabase($table, $column, $criteria = [])
    {
        return $this->proceedSeeInDatabase($table, $column, $criteria);
    }
}
<?php
namespace Codeception\Module;

use Codeception\Module\Filesystem;
use Codeception\TestCase;

/**
 *
 * 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": "0.3.6"
 * }
 * ```
 *
 * ## Status
 *
 * * Maintainer: **nathanmac**
 * * Stability:
 *     - FTP: **stable**
 *     - SFTP: **stable**
 * * Contact: nathan.macnamara@outlook.com
 *
 * ## 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\TestCase $test
     */
    public function _before(TestCase $test)
    {
        // Login using config settings
        $this->loginAs($this->config['user'], $this->config['password']);
    }

    /**
     * Close the FTP connection & Clear up
     */
    public function _after(TestCase $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'

                    $file = str_replace($absolutize_path, '', $file); // Replace full path from file listings if returned in listing
                    $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");
        }
    }

    /**
     * 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 = $tmp_file;
        $this->file = $contents;

        // Upload the file to server
        if ($this->isSFTP()) {
            $uploaded = @$this->ftp->put($filename, $tmp_file, NET_SFTP_LOCAL_FILE);
        } 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)
    {
        $this->ftp = new \Net_SFTP($this->config['host'], $this->config['port'], $this->config['timeout']);
        if ($this->ftp === false) {
            $this->ftp = null;
            $this->fail('failed to connect to ftp server');
        }

        if (isset($this->config['key'])) {
            $keyFile = file_get_contents($this->config['key']);
            $password = new \Crypt_RSA();
            $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\Configuration;
use Codeception\TestCase;
use Codeception\Lib\Framework;
use Codeception\Exception\ModuleRequireException;
use Codeception\Lib\Connector\Symfony2 as Symfony2Connector;
use Codeception\Lib\Interfaces\DoctrineProvider;
use Codeception\Lib\Interfaces\PartedModule;
use Symfony\Component\Finder\Finder;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * This module uses Symfony2 Crawler and HttpKernel to emulate requests and test response.
 *
 * ## Demo Project
 *
 * <https://github.com/Codeception/symfony-demo>
 *
 * ## Status
 *
 * * Maintainer: **raistlin**
 * * Stability: **stable**
 *
 * ## Config
 *
 * ### Symfony 2.x
 *
 * * app_path: 'app' - specify custom path to your app dir, where bootstrap cache and kernel interface is located.
 * * environment: 'local' - environment used for load kernel
 * * debug: true - turn on/off debug mode
 * * em_service: 'doctrine.orm.entity_manager' - use the stated EntityManager to pair with Doctrine Module.
 * * cache_router: 'false' - enable router caching between tests in order to [increase performance](http://lakion.com/blog/how-did-we-speed-up-sylius-behat-suite-with-blackfire)
 * * rebootable_client: 'true' - reboot client's kernel before each request
 *
 * ### Example (`functional.suite.yml`) - Symfony 2.x Directory Structure
 *
 * ```
 *    modules:
 *        - Symfony2:
 *            app_path: 'app/front'
 *            environment: 'local_test'
 * ```
 *
 * ### Symfony 3.x Directory Structure
 *
 * * app_path: 'app' - specify custom path to your app dir, where the kernel interface is located.
 * * var_path: 'var' - specify custom path to your var dir, where bootstrap cache is located.
 * * environment: 'local' - environment used for load kernel
 * * em_service: 'doctrine.orm.entity_manager' - use the stated EntityManager to pair with Doctrine Module.
 * * debug: true - turn on/off debug mode
 * * cache_router: 'false' - enable router caching between tests in order to [increase performance](http://lakion.com/blog/how-did-we-speed-up-sylius-behat-suite-with-blackfire)
 * * rebootable_client: 'true' - reboot client's kernel before each request
 *
 * ### Example (`functional.suite.yml`) - Symfony 3 Directory Structure
 *
 *     modules:
 *        enabled:
 *           - Symfony2:
 *               app_path: 'app/front'
 *               var_path: 'var'
 *               environment: 'local_test'
 *
 *
 * ## Public Properties
 *
 * * kernel - HttpKernel instance
 * * client - current Crawler instance
 *
 * ## Parts
 *
 * * services - allows to use Symfony2 DIC only with WebDriver or PhpBrowser modules.
 *
 * Usage example:
 *
 * ```yaml
 * class_name: AcceptanceTester
 * modules:
 *     enabled:
 *         - Symfony2:
 *             part: SERVICES
 *         - Doctrine2:
 *             depends: Symfony2
 *         - WebDriver:
 *             url: http://your-url.com
 *             browser: phantomjs
 * ```
 *
 * @property-read ContainerInterface $container
 *
 */
class Symfony2 extends Framework implements DoctrineProvider, PartedModule
{
    /**
     * @var \Symfony\Component\HttpKernel\Kernel
     */
    public $kernel;

    /**
     * @var ContainerInterface
     * @deprecated Use _getContainer() instead
     */
    private $container;

    public $config = [
        'app_path' => 'app',
        'var_path' => 'app',
        'environment' => 'test',
        'debug' => true,
        'cache_router' => false,
        'em_service' => 'doctrine.orm.entity_manager',
        'rebootable_client' => true,
    ];

    /**
     * @return array
     */
    public function _parts()
    {
        return ['services'];
    }

    /**
     * @var
     */
    protected $kernelClass;

    /**
     * Services that should be persistent permanently for all tests
     *
     * @var array
     */
    protected $permanentServices = [];

    /**
     * Services that should be persistent during test execution between kernel reboots
     *
     * @var array
     */
    protected $persistentServices = [];

    public function __get($property)
    {
        $result = null;
        if (property_exists($this, $property)) {
            switch ($property) {
                case 'container':
                    $result = $this->_getContainer();
                    break;
                default:
                    $this->fail(sprintf('Property "%s" can not be accessed.', $property));
                    break;
            }
        } else {
            $this->fail(sprintf('Property "%s" does not exist.', $property));
        }
        return $result;
    }

    public function _initialize()
    {
        $cache = Configuration::projectDir() . $this->config['var_path'] . DIRECTORY_SEPARATOR . 'bootstrap.php.cache';
        if (!file_exists($cache)) {
            throw new ModuleRequireException(__CLASS__,
                "Symfony2 bootstrap file not found in $cache\n \n" .
                "Please specify path to bootstrap file using `var_path` config option\n \n" .
                "If you are trying to load bootstrap from a Bundle provide path like:\n \n" .
                "modules:\n    enabled:\n" .
                "    - Symfony2:\n" .
                "        var_path: '../../app'\n" .
                "        app_path: '../../app'");

        }
        require_once $cache;
        $this->kernelClass = $this->getKernelClass();
        $maxNestingLevel = 200; // Symfony may have very long nesting level
        $xdebugMaxLevelKey = 'xdebug.max_nesting_level';
        if (ini_get($xdebugMaxLevelKey) < $maxNestingLevel) {
            ini_set($xdebugMaxLevelKey, $maxNestingLevel);
        }

        $this->kernel = new $this->kernelClass($this->config['environment'], $this->config['debug']);
        $this->kernel->boot();

        if ($this->config['cache_router'] === true) {
            $this->persistService('router', true);
        }
    }

    /**
     * Initialize new client instance before each test
     */
    public function _before(\Codeception\TestCase $test)
    {
        $this->persistentServices = array_merge($this->persistentServices, $this->permanentServices);
        $this->client = new Symfony2Connector($this->kernel, $this->persistentServices, $this->config['rebootable_client']);
    }

    /**
     * Update permanent services after each test
     */
    public function _after(\Codeception\TestCase $test)
    {
        foreach ($this->permanentServices as $serviceName => $service) {
            $this->permanentServices[$serviceName] = $this->grabService($serviceName);
        }
        parent::_after($test);
    }

    /**
     * Retrieve Entity Manager.
     *
     * EM service is retrieved once and then that instance returned on each call
     */
    public function _getEntityManager()
    {
        if ($this->kernel === null) {
            $this->fail('Symfony2 platform module is not loaded');
        }
        if (!isset($this->permanentServices[$this->config['em_service']])) {
            // try to persist configured EM
            $this->persistService($this->config['em_service'], true);

            if ($this->_getContainer()->has('doctrine')) {
                $this->persistService('doctrine', true);
            }
            if ($this->_getContainer()->has('doctrine.orm.default_entity_manager')) {
                $this->persistService('doctrine.orm.default_entity_manager', true);
            }
        }
        return $this->permanentServices[$this->config['em_service']];
    }

    /**
     * Return container.
     *
     * @return ContainerInterface
     */
    public function _getContainer()
    {
        return $this->kernel->getContainer();
    }

    /**
     * Attempts to guess the kernel location.
     *
     * When the Kernel is located, the file is required.
     *
     * @return string The Kernel class name
     */
    protected function getKernelClass()
    {
        $path = \Codeception\Configuration::projectDir() . $this->config['app_path'];
        if (!file_exists(\Codeception\Configuration::projectDir() . $this->config['app_path'])) {
            throw new ModuleRequireException(__CLASS__, "Can't load Kernel from $path.\nDirectory does not exists. Use `app_path` parameter to provide valid application path");
        }

        $finder = new Finder();
        $finder->name('*Kernel.php')->depth('0')->in($path);
        $results = iterator_to_array($finder);
        if (!count($results)) {
            throw new ModuleRequireException(__CLASS__, "AppKernel was not found at $path. Specify directory where Kernel class for your application is located with `app_path` parameter.");
        }

        $file = current($results);
        $class = $file->getBasename('.php');

        require_once $file;

        return $class;
    }

    /**
     * Get service $serviceName and add it to the lists of persistent services.
     * If $isPermanent then service becomes persistent between tests
     *
     * @param string  $serviceName
     * @param boolean $isPermanent
     */
    public function persistService($serviceName, $isPermanent = false)
    {
        $service = $this->grabService($serviceName);
        $this->persistentServices[$serviceName] = $service;
        if ($isPermanent) {
            $this->permanentServices[$serviceName] = $service;
        }
        if ($this->client) {
            $this->client->persistentServices[$serviceName] = $service;
        }
    }

    /**
     * Remove service $serviceName from the lists of persistent services.
     *
     * @param string $serviceName
     */
    public function unpersistService($serviceName)
    {
        if (isset($this->persistentServices[$serviceName])) {
            unset($this->persistentServices[$serviceName]);
        }
        if (isset($this->permanentServices[$serviceName])) {
            unset($this->permanentServices[$serviceName]);
        }
        if ($this->client && isset($this->client->persistentServices[$serviceName])) {
            unset($this->client->persistentServices[$serviceName]);
        }
    }

    /**
     * Invalidate previously cached routes.
     */
    public function invalidateCachedRouter()
    {
        $this->unpersistService('router');
    }

    /**
     * Opens web page using route name and parameters.
     *
     * ``` php
     * <?php
     * $I->amOnRoute('posts.create');
     * $I->amOnRoute('posts.show', array('id' => 34));
     * ?>
     * ```
     *
     * @param $routeName
     * @param array $params
     */
    public function amOnRoute($routeName, array $params = [])
    {
        $router = $this->grabService('router');
        if (!$router->getRouteCollection()->get($routeName)) {
            $this->fail(sprintf('Route with name "%s" does not exists.', $routeName));
        }
        $url = $router->generate($routeName, $params);
        $this->amOnPage($url);
    }

    /**
     * Checks that current url matches route.
     *
     * ``` php
     * <?php
     * $I->seeCurrentRouteIs('posts.index');
     * $I->seeCurrentRouteIs('posts.show', array('id' => 8));
     * ?>
     * ```
     *
     * @param $routeName
     * @param array $params
     */
    public function seeCurrentRouteIs($routeName, array $params = [])
    {
        $router = $this->grabService('router');
        if (!$router->getRouteCollection()->get($routeName)) {
            $this->fail(sprintf('Route with name "%s" does not exists.', $routeName));
        }
        $url = $router->generate($routeName, $params);
        $this->seeCurrentUrlEquals($url);
    }

    /**
     * Checks that current url matches route.
     * Unlike seeCurrentRouteIs, this can matches without exact route parameters
     *
     * ``` php
     * <?php
     * $I->seeCurrentRouteMatches('my_blog_pages');
     * ?>
     * ```
     *
     * @param $routeName
     */
    public function seeInCurrentRoute($routeName)
    {
        $router = $this->grabService('router');
        if (!$router->getRouteCollection()->get($routeName)) {
            $this->fail(sprintf('Route with name "%s" does not exists.', $routeName));
        }

        try {
            $matchedRouteName = $router->match($this->grabFromCurrentUrl())['_route'];
        } catch (\Exception\ResourceNotFoundException $e) {
            $this->fail(sprintf('The "%s" url does not match with any route', $routeName));
        }

        $this->assertEquals($matchedRouteName, $routeName);
    }

    /**
     * Checks if any email were sent by last request
     *
     * @throws \LogicException
     */
    public function seeEmailIsSent()
    {
        $profile = $this->getProfile();
        if (!$profile) {
            $this->fail('Emails can\'t be tested without Profiler');
        }
        if (!$profile->hasCollector('swiftmailer')) {
            $this->fail('Emails can\'t be tested without SwiftMailer connector');
        }

        $this->assertGreaterThan(0, $profile->getCollector('swiftmailer')->getMessageCount());
    }

    /**
     * Grabs a service from Symfony DIC container.
     * Recommended to use for unit testing.
     *
     * ``` php
     * <?php
     * $em = $I->grabServiceFromContainer('doctrine');
     * ?>
     * ```
     *
     * @param $service
     * @return mixed
     * @part services
     * @deprecated Use grabService instead
     */
    public function grabServiceFromContainer($service)
    {
        return $this->grabService($service);
    }

    /**
     * Grabs a service from Symfony DIC container.
     * Recommended to use for unit testing.
     *
     * ``` php
     * <?php
     * $em = $I->grabService('doctrine');
     * ?>
     * ```
     *
     * @param $service
     * @return mixed
     * @part services
     */
    public function grabService($service)
    {
        $container = $this->_getContainer();
        if (!$container->has($service)) {
            $this->fail("Service $service is not available in container");
        }
        return $container->get($service);
    }

    /**
     * @return \Symfony\Component\HttpKernel\Profiler\Profile
     */
    protected function getProfile()
    {
        $profiler = $this->grabService('profiler');
        $response = $this->client->getResponse();
        if (null === $response) {
            $this->fail("You must perform a request before using this method.");
        }
        return $profiler->loadProfileFromResponse($response);
    }

    /**
     * @param $url
     */
    protected function debugResponse($url)
    {
        parent::debugResponse($url);

        if ($profile = $this->getProfile()) {
            if ($profile->hasCollector('security')) {
                if ($profile->getCollector('security')->isAuthenticated()) {
                    $this->debugSection('User', $profile->getCollector('security')->getUser() . ' [' . implode(',', $profile->getCollector('security')->getRoles()) . ']');
                } else {
                    $this->debugSection('User', 'Anonymous');
                }
            }
            if ($profile->hasCollector('swiftmailer')) {
                $messages = $profile->getCollector('swiftmailer')->getMessageCount();
                if ($messages) {
                    $this->debugSection('Emails', $messages . ' sent');
                }
            }
            if ($profile->hasCollector('timer')) {
                $this->debugSection('Time', $profile->getCollector('timer')->getTime());
            }
        }
    }

    /**
     * Returns a list of recognized domain names.
     *
     * @return array
     */
    protected function getInternalDomains()
    {
        $internalDomains = [];

        $routes = $this->grabService('router')->getRouteCollection();
        /* @var \Symfony\Component\Routing\Route $route */
        foreach ($routes as $route) {
            if (!is_null($route->getHost())) {
                $compiled = $route->compile();
                if (!is_null($compiled->getHostRegex())) {
                    $internalDomains[] = $compiled->getHostRegex();
                }
            }
        }

        return array_unique($internalDomains);
    }

    /**
     * Reboot client's kernel.
     * Can be used to manually reboot kernel when 'rebootable_client' => false
     *
     * ``` php
     * <?php
     * ...
     * perform some requests
     * ...
     * $I->rebootClientKernel();
     * ...
     * perform other requests
     * ...
     *
     * ?>
     * ```
     *
     */
    public function rebootClientKernel()
    {
        if ($this->client) {
            $this->client->rebootKernel();
        }
    }
}
<?php

namespace Codeception\Module;

use Codeception\Module as CodeceptionModule;
use Codeception\Lib\Framework;
use Codeception\Exception\ModuleConfigException;
use Codeception\Exception\ModuleRequireException;
use Codeception\TestCase;

/**
 * Module for testing XMLRPC WebService.
 *
 * This module can be used either with frameworks or PHPBrowser.
 * It tries to guess the framework is is attached to.
 *
 * Whether framework is used it operates via standard framework modules.
 * Otherwise sends raw HTTP requests to url via PHPBrowser.
 *
 * ## Requirements
 *
 * * Module requires installed php_xmlrpc extension
 *
 * ## Status
 *
 * * Maintainer: **tiger-seo**
 * * Stability: **beta**
 * * Contact: tiger.seo@gmail.com
 *
 * ## Configuration
 *
 * * url *optional* - the url of api
 *
 * ## Public Properties
 *
 * * headers - array of headers going to be sent.
 * * params - array of sent data
 * * response - last response (string)
 *
 * @since 1.1.5
 * @author tiger.seo@gmail.com
 */
class XMLRPC extends CodeceptionModule
{
    protected $config = ['url' => ""];

    /**
     * @var \Symfony\Component\BrowserKit\Client
     */
    public $client = null;
    public $is_functional = false;

    public $headers = [];
    public $params = [];
    public $response = "";

    public function _initialize()
    {
        if (!function_exists('xmlrpc_encode_request')) {
            throw new ModuleRequireException(__CLASS__, "XMLRPC module requires installed php_xmlrpc extension");
        }
        parent::_initialize();
    }

    public function _before(TestCase $test)
    {
        if (!$this->client) {
            if (!strpos($this->config['url'], '://')) {
                // not valid url
                foreach ($this->getModules() as $module) {
                    if ($module instanceof Framework) {
                        $this->client = $module->client;
                        $this->is_functional = true;
                        break;
                    }
                }
            } else {
                if (!$this->hasModule('PhpBrowser')) {
                    throw new ModuleConfigException(
                        __CLASS__,
                        "For XMLRPC testing via HTTP please enable PhpBrowser module"
                    );
                }
                $this->client = $this->getModule('PhpBrowser')->client;
            }
            if (!$this->client) {
                throw new ModuleConfigException(
                    __CLASS__,
                    "Client for XMLRPC requests not initialized.\n"
                    . "Provide either PhpBrowser module, or a framework module which shares FrameworkInterface"
                );
            }
        }

        $this->headers = [];
        $this->params = [];
        $this->response = '';

        $this->client->setServerParameters([]);
    }

    /**
     * Sets HTTP header
     *
     * @param string $name
     * @param string $value
     */
    public function haveHttpHeader($name, $value)
    {
        $this->headers[$name] = $value;
    }

    /**
     * Checks response code.
     *
     * @param $num
     */
    public function seeResponseCodeIs($num)
    {
        \PHPUnit_Framework_Assert::assertEquals($num, $this->client->getInternalResponse()->getStatus());
    }

    /**
     * Checks weather last response was valid XMLRPC.
     * This is done with xmlrpc_decode function.
     *
     */
    public function seeResponseIsXMLRPC()
    {
        $result = xmlrpc_decode($this->response);
        \PHPUnit_Framework_Assert::assertNotNull($result, 'Invalid response document returned from XmlRpc server');
    }

    /**
     * Sends a XMLRPC method call to remote XMLRPC-server.
     *
     * @param string $methodName
     * @param array $parameters
     */
    public function sendXMLRPCMethodCall($methodName, $parameters = [])
    {
        if (!array_key_exists('Content-Type', $this->headers)) {
            $this->headers['Content-Type'] = 'text/xml';
        }

        foreach ($this->headers as $header => $val) {
            $this->client->setServerParameter("HTTP_$header", $val);
        }

        $url = $this->config['url'];

        if (is_array($parameters)) {
            $parameters = $this->scalarizeArray($parameters);
        }

        $requestBody = xmlrpc_encode_request($methodName, array_values($parameters));

        $this->debugSection('Request', $url . PHP_EOL . $requestBody);
        $this->client->request('POST', $url, [], [], [], $requestBody);

        $this->response = $this->client->getInternalResponse()->getContent();
        $this->debugSection('Response', $this->response);
    }
}
<?php
namespace Codeception\Module;

use Codeception\Configuration;
use Codeception\Exception\ModuleConfig;
use Codeception\Lib\Connector\Laravel4 as LaravelConnector;
use Codeception\Lib\Framework;
use Codeception\Lib\Interfaces\ActiveRecord;
use Codeception\Lib\Interfaces\PartedModule;
use Codeception\Lib\ModuleContainer;
use Codeception\Step;
use Codeception\Subscriber\ErrorHandler;
use Codeception\Util\ReflectionHelper;
use Codeception\TestCase;
use Illuminate\Auth\UserInterface;
use Illuminate\Foundation\Application;
use Illuminate\Support\ClassLoader;
use Illuminate\Workbench\Starter;
use Symfony\Component\Console\Output\BufferedOutput;

/**
 *
 * This module allows you to run functional tests for Laravel 4.
 * It should **not** be used for acceptance tests.
 *
 * ## Demo Project
 *
 * <https://github.com/Codeception/sample-l4-app>
 *
 * ## Example
 *
 *     modules:
 *         enabled:
 *             - Laravel4
 *
 * ## Status
 *
 * * Maintainer: **Jan-Henk Gerritsen**
 * * Stability: **stable**
 *
 * ## Config
 *
 * * cleanup: `boolean`, default `true` - all db queries will be run in transaction, which will be rolled back at the end of test.
 * * unit: `boolean`, default `true` - Laravel will run in unit testing mode.
 * * environment: `string`, default `testing` - When running in unit testing mode, we will set a different environment.
 * * start: `string`, default `bootstrap/start.php` - Relative path to start.php config file.
 * * root: `string`, default ` ` - Root path of our application.
 * * filters: `boolean`, default: `false` - enable or disable filters for testing.
 *
 * ## API
 *
 * * app - `Illuminate\Foundation\Application` instance
 * * client - `\Symfony\Component\BrowserKit\Client` instance
 *
 * ## Parts
 *
 * * ORM - include only haveRecord/grabRecord/seeRecord/dontSeeRecord actions
 *
 *
 */
class Laravel4 extends Framework implements ActiveRecord, PartedModule
{

    /**
     * @var \Illuminate\Foundation\Application
     */
    public $app;

    /**
     * @var array
     */
    public $config = [];

    /**
     * Constructor.
     *
     * @param ModuleContainer $container
     * @param null $config
     */
    public function __construct(ModuleContainer $container, $config = null)
    {
        $this->config = array_merge(
            [
                'cleanup' => true,
                'unit' => true,
                'environment' => 'testing',
                'start' => 'bootstrap' . DIRECTORY_SEPARATOR . 'start.php',
                'root' => '',
                'filters' => false,
            ],
            (array)$config
        );

        $projectDir = explode('workbench', Configuration::projectDir())[0];
        $projectDir .= $this->config['root'];

        $this->config['project_dir'] = $projectDir;
        $this->config['start_file'] = $projectDir . $this->config['start'];

        parent::__construct($container, null);
    }

    /**
     * @return array
     */
    public function _parts()
    {
        return ['framework', 'orm'];
    }

    /**
     * Initialize hook.
     */
    public function _initialize()
    {
        $this->checkStartFileExists();
        $this->registerAutoloaders();
        $this->revertErrorHandler();
    }

    /**
     * Before hook.
     *
     * @param \Codeception\TestCase $test
     * @throws ModuleConfig
     */
    public function _before(TestCase $test)
    {
        $this->client = new LaravelConnector($this);

        if ($this->app['db'] && $this->cleanupDatabase()) {
            $this->app['db']->beginTransaction();
        }

        if ($this->config['filters']) {
            $this->haveEnabledFilters();
        }
    }

    /**
     * After hook.
     *
     * @param \Codeception\TestCase $test
     */
    public function _after(TestCase $test)
    {
        if ($this->app['db'] && $this->cleanupDatabase()) {
            $this->app['db']->rollback();
        }

        if ($this->app['auth']) {
            $this->app['auth']->logout();
        }

        if ($this->app['session']) {
            $this->app['session']->flush();
        }

        if ($this->app['cache']) {
            $this->app['cache']->flush();
        }

        // disconnect from DB to prevent "Too many connections" issue
        if ($this->app['db']) {
            $this->app['db']->disconnect();
        }
    }

    /**
     * Make sure the Laravel start file exists.
     *
     * @throws ModuleConfig
     */
    protected function checkStartFileExists()
    {
        $startFile = $this->config['start_file'];

        if (!file_exists($startFile)) {
            throw new ModuleConfig(
                $this,
                "Laravel bootstrap start.php file not found in $startFile.\n"
                . "Please provide a valid path to it using 'start' config param. "
            );
        }
    }

    /**
     * Register Laravel autoloaders.
     */
    protected function registerAutoloaders()
    {
        require $this->config['project_dir'] . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';

        ClassLoader::register();

        if (is_dir($workbench = $this->config['project_dir'] . 'workbench')) {
            Starter::start($workbench);
        }
    }

    /**
     * Revert back to the Codeception error handler,
     * becauses Laravel registers it's own error handler.
     */
    protected function revertErrorHandler()
    {
        $handler = new ErrorHandler();
        set_error_handler([$handler, 'errorHandler']);
    }

    /**
     * Should database cleanup be performed?
     *
     * @return bool
     */
    protected function cleanupDatabase()
    {
        if (!$this->databaseTransactionsSupported()) {
            return false;
        }

        return $this->config['cleanup'];
    }

    /**
     * Does the Laravel installation support database transactions?
     *
     * @return bool
     */
    protected function databaseTransactionsSupported()
    {
        return version_compare(Application::VERSION, '4.0.6', '>=');
    }

    /**
     * Provides access the Laravel application object.
     *
     * @return \Illuminate\Foundation\Application
     */
    public function getApplication()
    {
        return $this->app;
    }

    /**
     * @param $app
     */
    public function setApplication($app)
    {
        $this->app = $app;
    }

    /**
     * Enable Laravel filters for next requests.
     */
    public function haveEnabledFilters()
    {
        $this->app['router']->enableFilters();
    }

    /**
     * Disable Laravel filters for next requests.
     */
    public function haveDisabledFilters()
    {
        $this->app['router']->disableFilters();
    }

    /**
     * Opens web page using route name and parameters.
     *
     * ``` php
     * <?php
     * $I->amOnRoute('posts.create');
     * ?>
     * ```
     *
     * @param $route
     * @param array $params
     */
    public function amOnRoute($route, $params = [])
    {
        $domain = $this->app['router']->getRoutes()->getByName($route)->domain();
        $absolute = !is_null($domain);

        $url = $this->app['url']->route($route, $params, $absolute);
        $this->amOnPage($url);
    }

    /**
     * Opens web page by action name
     *
     * ``` php
     * <?php
     * $I->amOnAction('PostsController@index');
     * ?>
     * ```
     *
     * @param $action
     * @param array $params
     */
    public function amOnAction($action, $params = [])
    {
        $domain = $this->app['router']->getRoutes()->getByAction($action)->domain();
        $absolute = !is_null($domain);

        $url = $this->app['url']->action($action, $params, $absolute);
        $this->amOnPage($url);
    }

    /**
     * Checks that current url matches route
     *
     * ``` php
     * <?php
     * $I->seeCurrentRouteIs('posts.index');
     * ?>
     * ```
     * @param $route
     * @param array $params
     */
    public function seeCurrentRouteIs($route, $params = [])
    {
        $this->seeCurrentUrlEquals($this->app['url']->route($route, $params, false));
    }

    /**
     * Checks that current url matches action
     *
     * ``` php
     * <?php
     * $I->seeCurrentActionIs('PostsController@index');
     * ?>
     * ```
     *
     * @param $action
     * @param array $params
     */
    public function seeCurrentActionIs($action, $params = [])
    {
        $this->seeCurrentUrlEquals($this->app['url']->action($action, $params, false));
    }

    /**
     * Assert that a session variable exists.
     *
     * ``` php
     * <?php
     * $I->seeInSession('key');
     * $I->seeInSession('key', 'value');
     * ?>
     * ```
     *
     * @param  string|array $key
     * @param  mixed $value
     * @return void
     */
    public function seeInSession($key, $value = null)
    {
        if (is_array($key)) {
            $this->seeSessionHasValues($key);

            return;
        }

        if (is_null($value)) {
            $this->assertTrue($this->app['session']->has($key));
        } else {
            $this->assertEquals($value, $this->app['session']->get($key));
        }
    }

    /**
     * Assert that the session has a given list of values.
     *
     * ``` php
     * <?php
     * $I->seeSessionHasValues(['key1', 'key2']);
     * $I->seeSessionHasValues(['key1' => 'value1', 'key2' => 'value2']);
     * ?>
     * ```
     *
     * @param  array $bindings
     * @return void
     */
    public function seeSessionHasValues(array $bindings)
    {
        foreach ($bindings as $key => $value) {
            if (is_int($key)) {
                $this->seeInSession($value);
            } else {
                $this->seeInSession($key, $value);
            }
        }
    }

    /**
     * Assert that Session has error messages
     * The seeSessionHasValues cannot be used, as Message bag Object is returned by Laravel4
     *
     * Useful for validation messages and generally messages array
     *  e.g.
     *  return `Redirect::to('register')->withErrors($validator);`
     *
     * Example of Usage
     *
     * ``` php
     * <?php
     * $I->seeSessionErrorMessage(array('username'=>'Invalid Username'));
     * ?>
     * ```
     * @param array $bindings
     * @deprecated
     */
    public function seeSessionErrorMessage(array $bindings)
    {
        $this->seeFormHasErrors(); //check if  has errors at all
        $this->seeFormErrorMessages($bindings);
    }

    /**
     * Assert that the session has errors bound.
     *
     * ``` php
     * <?php
     * $I->seeSessionHasErrors();
     * ?>
     * ```
     *
     * @return bool
     * @deprecated
     */
    public function seeSessionHasErrors()
    {
        $this->seeFormHasErrors();
    }

    /**
     * Assert that form errors are bound to the View.
     *
     * ``` php
     * <?php
     * $I->seeFormHasErrors();
     * ?>
     * ```
     *
     * @return bool
     */
    public function seeFormHasErrors()
    {
        $viewErrorBag = $this->app['view']->shared('errors');
        $this->assertTrue(count($viewErrorBag) > 0);
    }

    /**
     * Assert that specific form error messages are set in the view.
     *
     * Useful for validation messages and generally messages array
     *  e.g.
     *  return `Redirect::to('register')->withErrors($validator);`
     *
     * Example of Usage
     *
     * ``` php
     * <?php
     * $I->seeFormErrorMessages(array('username'=>'Invalid Username'));
     * ?>
     * ```
     * @param array $bindings
     */
    public function seeFormErrorMessages(array $bindings)
    {
        foreach ($bindings as $key => $value) {
            $this->seeFormErrorMessage($key, $value);
        }
    }

    /**
     * Assert that specific form error message is set in the view.
     *
     * Useful for validation messages and generally messages array
     *  e.g.
     *  return `Redirect::to('register')->withErrors($validator);`
     *
     * Example of Usage
     *
     * ``` php
     * <?php
     * $I->seeFormErrorMessage('username', 'Invalid Username');
     * ?>
     * ```
     * @param string $key
     * @param string $errorMessage
     */
    public function seeFormErrorMessage($key, $errorMessage)
    {
        $viewErrorBag = $this->app['view']->shared('errors');

        $this->assertEquals($errorMessage, $viewErrorBag->first($key));
    }

    /**
     * Set the currently logged in user for the application.
     * Takes either `UserInterface` instance or array of credentials.
     *
     * @param  \Illuminate\Auth\UserInterface|array $user
     * @param  string $driver
     * @return void
     * @part framework
     */
    public function amLoggedAs($user, $driver = null)
    {
        if ($user instanceof UserInterface) {
            $this->app['auth']->driver($driver)->login($user);
        } else {
            $this->app['auth']->driver($driver)->attempt($user);
        }
    }

    /**
     * Logs user out
     * @part framework
     */
    public function logout()
    {
        $this->app['auth']->logout();
    }

    /**
     * Checks that user is authenticated
     * @part framework
     */
    public function seeAuthentication()
    {
        $this->assertTrue($this->app['auth']->check(), 'User is not logged in');
    }

    /**
     * Check that user is not authenticated
     */
    public function dontSeeAuthentication()
    {
        $this->assertFalse($this->app['auth']->check(), 'User is logged in');
    }

    /**
     * Return an instance of a class from the IoC Container.
     * (http://laravel.com/docs/ioc)
     *
     * Example
     * ``` php
     * <?php
     * // In Laravel
     * App::bind('foo', function($app)
     * {
     *     return new FooBar;
     * });
     *
     * // Then in test
     * $service = $I->grabService('foo');
     *
     * // Will return an instance of FooBar, also works for singletons.
     * ?>
     * ```
     *
     * @param  string $class
     * @return mixed
     * @part framework
     */
    public function grabService($class)
    {
        return $this->app[$class];
    }

    /**
     * Inserts record into the database.
     *
     * ``` php
     * <?php
     * $user_id = $I->haveRecord('users', array('name' => 'Davert'));
     * ?>
     * ```
     *
     * @param $tableName
     * @param array $attributes
     * @return mixed
     * @part orm
     * @part framework
     */
    public function haveRecord($tableName, $attributes = array())
    {
        try {
            return $this->app['db']->table($tableName)->insertGetId($attributes);
        } catch (\Exception $e) {
            $this->fail("Couldn't insert record into table $tableName: " . $e->getMessage());
        }
    }

    /**
     * Checks that record exists in database.
     *
     * ``` php
     * <?php
     * $I->seeRecord('users', array('name' => 'davert'));
     * ?>
     * ```
     *
     * @param $tableName
     * @param array $attributes
     * @part orm
     * @part framework
     */
    public function seeRecord($tableName, $attributes = array())
    {
        $record = $this->findRecord($tableName, $attributes);
        if (!$record) {
            $this->fail("Couldn't find $tableName with " . json_encode($attributes));
        }
        $this->debugSection($tableName, json_encode($record));
    }

    /**
     * Checks that record does not exist in database.
     *
     * ``` php
     * <?php
     * $I->dontSeeRecord('users', array('name' => 'davert'));
     * ?>
     * ```
     *
     * @param $tableName
     * @param array $attributes
     * @part orm
     * @part framework
     */
    public function dontSeeRecord($tableName, $attributes = array())
    {
        $record = $this->findRecord($tableName, $attributes);
        $this->debugSection($tableName, json_encode($record));
        if ($record) {
            $this->fail("Unexpectedly managed to find $tableName with " . json_encode($attributes));
        }
    }

    /**
     * Retrieves record from database
     *
     * ``` php
     * <?php
     * $category = $I->grabRecord('users', array('name' => 'davert'));
     * ?>
     * ```
     *
     * @param $tableName
     * @param array $attributes
     * @return mixed
     * @part ORM
     * @part framework
     */
    public function grabRecord($tableName, $attributes = array())
    {
        return $this->findRecord($tableName, $attributes);
    }

    /**
     * @param $tableName
     * @param array $attributes
     * @return mixed
     */
    protected function findRecord($tableName, $attributes = array())
    {
        $query = $this->app['db']->table($tableName);
        foreach ($attributes as $key => $value) {
            $query->where($key, $value);
        }

        return $query->first();
    }

    /**
     * Calls an Artisan command and returns output as a string
     *
     * @param string $command The name of the command as displayed in the artisan command list
     * @param array $parameters An associative array of command arguments
     *
     * @return string
     */
    public function callArtisan($command, array $parameters = array())
    {
        $output = new BufferedOutput();

        /** @var \Illuminate\Console\Application $artisan */
        $artisan = $this->app['artisan'];
        $artisan->call($command, $parameters, $output);

        return $output->fetch();
    }

    /**
     * Returns a list of recognized domain names.
     * This elements of this list are regular expressions.
     *
     * @return array
     */
    protected function getInternalDomains()
    {
        $internalDomains = [$this->getApplicationDomainRegex()];

        foreach ($this->app['router']->getRoutes() as $route) {
            if (!is_null($route->domain())) {
                $internalDomains[] = $this->getDomainRegex($route);
            }
        }

        return array_unique($internalDomains);
    }

    /**
     * @return string
     */
    private function getApplicationDomainRegex()
    {
        $server = ReflectionHelper::readPrivateProperty($this->client, 'server');
        $domain = $server['HTTP_HOST'];

        return '/^' . str_replace('.', '\.', $domain) . '$/';
    }

    /**
     * Get the regex for matching the domain part of this route.
     *
     * @param \Illuminate\Routing\Route $route
     * @return string
     */
    private function getDomainRegex($route)
    {
        ReflectionHelper::invokePrivateMethod($route, 'compileRoute');
        $compiledRoute = ReflectionHelper::readPrivateProperty($route, 'compiled');

        return $compiledRoute->getHostRegex();
    }

}
<?php
namespace Codeception\Module;

use Codeception\Module as CodeceptionModule;
use Codeception\TestCase;
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: codecept@davert.mail.ua
 *
 * ## Configuration
 *
 * * host: localhost - memcached host to connect
 * * port: 11211 - default memcached port.
 *
 * Be sure you don't use the production server to connect.
 *
 * ## Public Properties
 *
 * * memcache - instance of Memcache object
 *
 */
class Memcache extends CodeceptionModule
{
    /**
     * @var \Memcache|\Memcached
     */
    public $memcache = null;

    protected $config = ['host' => 'localhost', 'port' => 11211];

    public function _before(TestCase $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');
        }
    }

    public function _after(TestCase $test)
    {
        $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.
     *
     * @param $key
     * @param $value
     */
    public function seeInMemcached($key, $value = false)
    {
        $actual = $this->memcache->get($key);
        $this->debugSection("Value", $actual);
        $this->assertEquals($value, $actual);
    }

    /**
     * Checks item in Memcached doesn't exist or is the same as expected.
     *
     * @param $key
     * @param bool $value
     */
    public function dontSeeInMemcached($key, $value = false)
    {
        $actual = $this->memcache->get($key);
        $this->debugSection("Value", $actual);
        $this->assertNotEquals($value, $actual);
    }

    /**
     * Flushes all Memcached data.
     */
    public function clearMemcache()
    {
        $this->memcache->flush();
    }
}
<?php
namespace Codeception\Module;

use Codeception\Module as CodeceptionModule;
use Codeception\Configuration as Configuration;
use Codeception\Exception\ModuleConfigException;
use Codeception\Exception\ModuleException;
use Codeception\Lib\Driver\MongoDb as MongoDbDriver;
use Codeception\TestCase;

/**
 * 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
 * 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.
 *
 * ## Status
 *
 * * Maintainer: **judgedim**, **davert**
 * * Stability: **beta**
 * * Contact: codecept@davert.mail.ua
 *
 * *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 - 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
 *
 */
class MongoDb extends CodeceptionModule
{
    /**
     * @api
     * @var
     */
    public $dbh;

    /**
     * @var
     */

    protected $dumpFile;
    protected $isDumpFileEmpty = true;

    protected $config = [
        'populate' => true,
        'cleanup'  => true,
        'dump'     => null,
        'user'     => null,
        'password' => null
    ];

    protected $populated = false;

    /**
     * @var \Codeception\Lib\Driver\MongoDb
     */
    public $driver;

    protected $requiredFields = ['dsn'];

    public function _initialize()
    {
        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;

            $content = file_get_contents($this->dumpFile);
            $content = trim(preg_replace('%/\*(?:(?!\*/).)*\*/%s', "", $content));
            if (!sizeof(explode("\n", $content))) {
                $this->isDumpFileEmpty = true;
            }
        }

        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;
        }
    }

    public function _before(TestCase $test)
    {
        if ($this->config['cleanup'] && !$this->populated) {
            $this->cleanup();
            $this->loadDump();
        }
    }

    public function _after(TestCase $test)
    {
        $this->populated = false;
    }

    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()
    {
        if ($this->isDumpFileEmpty) {
            return;
        }
        try {
            $this->driver->load($this->dumpFile);
        } catch (\Exception $e) {
            throw new ModuleException(__CLASS__, $e->getMessage());
        }
    }

    /**
     * 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);
        $collection->insert($data);
        return $data['_id'];
    }

    /**
     * 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
     * $cursor = $I->grabFromCollection('users', array('name' => 'miles'));
     * ```
     *
     * @param $collection
     * @param array $criteria
     * @return \MongoCursor
     */
    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);
    }
}
<?php
namespace Codeception\Module;

use Codeception\Lib\Framework;
use Codeception\TestCase;
use Codeception\Configuration;
use Codeception\Lib\Interfaces\DoctrineProvider;
use Codeception\Util\ReflectionHelper;
use Zend\Console\Console;
use Zend\EventManager\StaticEventManager;
use Zend\Mvc\Application;
use Zend\Version\Version;
use Zend\View\Helper\Placeholder\Registry;
use Codeception\Lib\Connector\ZF2 as ZF2Connector;

/**
 * This module allows you to run tests inside Zend Framework 2.
 *
 * File `init_autoloader` in project's root is required.
 * Uses `tests/application.config.php` config file by default.
 *
 * ## Status
 *
 * * Maintainer: **bladeofsteel**
 * * Stability: **alpha**
 * * Contact: https://github.com/bladeofsteel
 *
 * ## Config
 *
 * * config: relative path to config file (default: `tests/application.config.php`)
 *
 * ## API
 *
 * * application -  instance of `\Zend\Mvc\ApplicationInterface`
 * * db - instance of `\Zend\Db\Adapter\AdapterInterface`
 * * client - BrowserKit client
 *
 */
class ZF2 extends Framework implements DoctrineProvider
{
    protected $config = [
        'config' => 'tests/application.config.php',
    ];

    /**
     * @var \Zend\Mvc\ApplicationInterface
     */
    public $application;

    /**
     * @var \Zend\Db\Adapter\AdapterInterface
     */
    public $db;

    /**
     * @var \Codeception\Lib\Connector\ZF2
     */
    public $client;

    protected $applicationConfig;

    protected $queries = 0;
    protected $time = 0;

    /**
     * @var array Used to collect domains while recusively traversing route tree
     */
    private $domainCollector = [];

    public function _initialize()
    {
        require Configuration::projectDir() . 'init_autoloader.php';

        $this->applicationConfig = require Configuration::projectDir() . $this->config['config'];
        if (isset($applicationConfig['module_listener_options']['config_cache_enabled'])) {
            $applicationConfig['module_listener_options']['config_cache_enabled'] = false;
        }
        Console::overrideIsConsole(false);
    }

    public function _before(TestCase $test)
    {
        $this->client = new ZF2Connector();

        $this->application = Application::init($this->applicationConfig);
        $events = $this->application->getEventManager();
        $events->detach($this->application->getServiceManager()->get('SendResponseListener'));

        $this->client->setApplication($this->application);
        $_SERVER['REQUEST_URI'] = '';
    }

    public function _after(TestCase $test)
    {
        $_SESSION = [];
        $_GET = [];
        $_POST = [];
        $_COOKIE = [];

        // reset singleton
        StaticEventManager::resetInstance();

        // Reset singleton placeholder if version < 2.2.0, no longer required in 2.2.0+
        if (Version::compareVersion('2.2.0') >= 0) {
            Registry::unsetRegistry();
        }
        //Close the session, if any are open
        if (session_status() == PHP_SESSION_ACTIVE) {
            session_write_close();
        }
        $this->queries = 0;
        $this->time = 0;

        parent::_after($test);
    }

    public function _getEntityManager()
    {
        return $this->grabServiceFromContainer('Doctrine\ORM\EntityManager');
    }

    /**
     * Grabs a service from ZF2 container.
     * Recommended to use for unit testing.
     *
     * ``` php
     * <?php
     * $em = $I->grabServiceFromContainer('Doctrine\ORM\EntityManager');
     * ?>
     * ```
     *
     * @param $service
     * @return mixed
     */
    public function grabServiceFromContainer($service)
    {
        $serviceLocator = $this->application
            ? $this->application->getServiceManager()
            : Application::init($this->applicationConfig)->getServiceManager();
        if (!$serviceLocator->has($service)) {
            $this->fail("Service $service is not available in container");
        }
        return $serviceLocator->get($service);
    }

    /**
     * Opens web page using route name and parameters.
     *
     * ``` php
     * <?php
     * $I->amOnRoute('posts.create');
     * $I->amOnRoute('posts.show', array('id' => 34));
     * ?>
     * ```
     *
     * @param $routeName
     * @param array $params
     */
    public function amOnRoute($routeName, array $params = [])
    {
        $router = $this->application->getServiceManager()->get('router');
        $url = $router->assemble($params, ['name' => $routeName]);
        $this->amOnPage($url);
    }

    /**
     * Checks that current url matches route.
     *
     * ``` php
     * <?php
     * $I->seeCurrentRouteIs('posts.index');
     * $I->seeCurrentRouteIs('posts.show', ['id' => 8]));
     * ?>
     * ```
     *
     * @param $routeName
     * @param array $params
     */
    public function seeCurrentRouteIs($routeName, array $params = [])
    {
        $router = $this->application->getServiceManager()->get('router');
        $url = $router->assemble($params, ['name' => $routeName]);
        $this->seeCurrentUrlEquals($url);
    }

    protected function getInternalDomains()
    {
        /**
         * @var Zend\Mvc\Router\Http\TreeRouteStack
         */
        $router = $this->application->getServiceManager()->get('router');
        $this->domainCollector = [];
        $this->addInternalDomainsFromRoutes($router->getRoutes());
        return array_unique($this->domainCollector);
    }

    private function addInternalDomainsFromRoutes($routes)
    {
        foreach ($routes as $name => $route) {
            if ($route instanceof \Zend\Mvc\Router\Http\Hostname) {
                $this->addInternalDomain($route);
            } elseif ($route instanceof \Zend\Mvc\Router\Http\Part) {
                $parentRoute = ReflectionHelper::readPrivateProperty($route, 'route');
                if ($parentRoute instanceof \Zend\Mvc\Router\Http\Hostname) {
                    $this->addInternalDomain($parentRoute);
                }
                // this is necessary to instantiate child routes
                try {
                    $route->assemble([], []);
                } catch (\Exception $e) {
                }
                $this->addInternalDomainsFromRoutes($route->getRoutes());
            }
        }
    }

    private function addInternalDomain(\Zend\Mvc\Router\Http\Hostname $route)
    {
        $regex = ReflectionHelper::readPrivateProperty($route, 'regex');
        $this->domainCollector []= '/^' . $regex . '$/';
    }
}
<?php
namespace Codeception\Module;

use Phalcon\Di;
use Phalcon\Mvc\Model as PhalconModel;
use Codeception\TestCase;

/**
 * This module provides integration with [Phalcon framework](http://www.phalconphp.com/) (2.x).
 * Please try it and leave your feedback.
 * The module is based on the Phalcon1 module.
 *
 * ## Demo Project
 *
 * <https://github.com/phalcon/forum>
 *
 * ## Status
 *
 * * Maintainer: **Serghei Iakovlev**
 * * Stability: **stable**
 * * Contact: sadhooklay@gmail.com
 *
 * ## Example
 *
 *     modules:
 *         enabled:
 *             - Phalcon2:
 *                 bootstrap: 'app/config/bootstrap.php'
 *                 cleanup: true
 *                 savepoints: true
 *
 * ## Config
 *
 * The following configurations are required for this module:
 * * boostrap: the path of the application bootstrap file</li>
 * * cleanup: cleanup database (using transactions)</li>
 * * savepoints: use savepoints to emulate nested transactions</li>
 *
 * The application bootstrap file must return Application object but not call its handle() method.
 *
 * Sample bootstrap (`app/config/bootstrap.php`):
 *
 * ``` php
 * <?php
 * $config = include __DIR__ . "/config.php";
 * include __DIR__ . "/loader.php";
 * $di = new \Phalcon\DI\FactoryDefault();
 * include __DIR__ . "/services.php";
 * return new \Phalcon\Mvc\Application($di);
 * ?>
 * ```
 *
 * ## API
 *
 * * di - `Phalcon\Di\Injectable` instance
 * * client - `BrowserKit` client
 *
 * ## Parts
 *
 * * ORM - include only haveRecord/grabRecord/seeRecord/dontSeeRecord actions
 *
 */
class Phalcon2 extends Phalcon1
{
}
<?php
namespace Codeception\Module;

use Codeception\Module as CodeceptionModule;
use Codeception\Exception\ModuleException as ModuleException;
use Codeception\TestCase;
use Exception;
use PhpAmqpLib\Channel\AMQPChannel;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Exception\AMQPProtocolChannelException;

/**
 * This module interacts with message broker software that implements
 * the Advanced Message Queuing Protocol (AMQP) standard. For example, RabbitMQ (tested).
 * Use it to cleanup the queue between tests.
 *
 * <div class="alert alert-info">
 * To use this module with Composer you need <em>"videlalvaro/php-amqplib": "*"</em> package.
 * </div>
 *
 * ## Status
 * * Maintainer: **davert**, **tiger-seo**
 * * Stability: **alpha**
 * * Contact: codecept@davert.mail.ua
 * * Contact: tiger.seo@gmail.com
 *
 * *Please review the code of non-stable modules and provide patches if you have issues.*
 *
 * ## 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
 *
 * ### Example
 *
 *     modules:
 *         enabled:
 *             - AMQP:
 *                 host: 'localhost'
 *                 port: '5672'
 *                 username: 'guest'
 *                 password: 'guest'
 *                 vhost: '/'
 *                 queues: [queue1, queue2]
 *
 * ## Public Properties
 *
 * * connection - AMQPStreamConnection - current connection
 *
 * @since 1.1.2
 * @author tiger.seo@gmail.com
 * @author davert
 */
class AMQP extends CodeceptionModule
{
    protected $config = [
        'host'     => 'locahost',
        'username' => 'guest',
        'password' => 'guest',
        'port'     => '5672',
        'vhost'    => '/',
        'cleanup'  => true,
    ];

    /**
     * @var AMQPStreamConnection
     */
    public $connection;

    /**
     * @var AMQPChannel
     */
    protected $channel;

    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(TestCase $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 $exchange
     * @param $message string|AMQPMessage
     * @param $routing_key
     */
    public function pushToExchange($exchange, $message, $routing_key = null)
    {
        $message = $message instanceof AMQPMessage
            ? $message
            : new AMQPMessage($message);
        $this->connection->channel()->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 $queue
     * @param $message string|AMQPMessage
     */
    public function pushToQueue($queue, $message)
    {
        $message = $message instanceof AMQPMessage
            ? $message
            : new AMQPMessage($message);

        $this->connection->channel()->queue_declare($queue);
        $this->connection->channel()->basic_publish($message, '', $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 $queue
     * @param $text
     */
    public function seeMessageInQueueContainsText($queue, $text)
    {
        $msg = $this->connection->channel()->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->assertContains($text, $msg->body);
    }

    /**
     * Takes last message from queue.
     *
     * $message = $I->grabMessageFromQueue('queue.emails');
     *
     * @param $queue
     * @return AMQPMessage
     */
    public function grabMessageFromQueue($queue)
    {
        $message = $this->connection->channel()->basic_get($queue);
        return $message;
    }

    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->connection->channel()->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\Module;

use Codeception\Exception\ModuleException;
use PDOException;
use Phalcon\Di;
use Phalcon\DiInterface;
use Phalcon\Di\Injectable;
use Phalcon\Mvc\Model as PhalconModel;
use Phalcon\Mvc\RouterInterface;
use Phalcon\Mvc\Router\RouteInterface;
use Codeception\Util\ReflectionHelper;
use Phalcon\Mvc\Url;
use Codeception\TestCase;
use Codeception\Configuration;
use Codeception\Lib\Connector\Phalcon as PhalconConnector;
use Codeception\Lib\Framework;
use Codeception\Lib\Interfaces\ActiveRecord;
use Codeception\Lib\Interfaces\PartedModule;
use Codeception\Exception\ModuleConfigException;
use Exception;
use Codeception\Lib\Connector\PhalconMemorySession;

/**
 * This module provides integration with [Phalcon framework](http://www.phalconphp.com/) (1.x).
 * Please try it and leave your feedback.
 *
 * ## Demo Project
 *
 * <https://github.com/phalcon/forum>
 *
 * ## Status
 *
 * * Maintainer: **Serghei Iakovlev**
 * * Stability: **stable**
 * * Contact: sadhooklay@gmail.com
 *
 * ## Example
 *
 *     modules:
 *         enabled:
 *             - Phalcon1:
 *                 bootstrap: 'app/config/bootstrap.php'
 *                 cleanup: true
 *                 savepoints: true
 *
 * ## Config
 *
 * The following configurations are required for this module:
 * * boostrap: the path of the application bootstrap file</li>
 * * cleanup: cleanup database (using transactions)</li>
 * * savepoints: use savepoints to emulate nested transactions</li>
 *
 * The application bootstrap file must return Application object but not call its handle() method.
 *
 * Sample bootstrap (`app/config/bootstrap.php`):
 *
 * ``` php
 * <?php
 * $config = include __DIR__ . "/config.php";
 * include __DIR__ . "/loader.php";
 * $di = new \Phalcon\DI\FactoryDefault();
 * include __DIR__ . "/services.php";
 * return new \Phalcon\Mvc\Application($di);
 * ?>
 * ```
 *
 * ## API
 *
 * * di - `Phalcon\Di\Injectable` instance
 * * client - `BrowserKit` client
 *
 * ## Parts
 *
 * * ORM - include only haveRecord/grabRecord/seeRecord/dontSeeRecord actions
 *
 */
class Phalcon1 extends Framework implements ActiveRecord, PartedModule
{
    protected $config = [
        'bootstrap'  => 'app/config/bootstrap.php',
        'cleanup'    => true,
        'savepoints' => true,
    ];

    /**
     * Phalcon bootstrap file path
     */
    protected $bootstrapFile = null;

    /**
     * Dependency injection container
     * @var DiInterface
     */
    public $di = null;

    /**
     * Phalcon Connector
     * @var PhalconConnector
     */
    public $client;

    /**
     * HOOK: used after configuration is loaded
     *
     * @throws ModuleConfigException
     */
    public function _initialize()
    {
        if (!file_exists($this->bootstrapFile = Configuration::projectDir() . $this->config['bootstrap'])) {
            throw new ModuleConfigException(
                __CLASS__,
                "Bootstrap file does not exist in " . $this->config['bootstrap'] . "\n"
                . "Please create the bootstrap file that returns Application object\n"
                . "And specify path to it with 'bootstrap' config\n\n"
                . "Sample bootstrap: \n\n<?php\n"
                . '$config = include __DIR__ . "/config.php";' . "\n"
                . 'include __DIR__ . "/loader.php";' . "\n"
                . '$di = new \Phalcon\DI\FactoryDefault();' . "\n"
                . 'include __DIR__ . "/services.php";' . "\n"
                . 'return new \Phalcon\Mvc\Application($di);'
            );
        }

        $this->client = new PhalconConnector();
    }

    /**
     * HOOK: before scenario
     *
     * @param TestCase $test
     * @throws ModuleException
     */
    public function _before(TestCase $test)
    {
        $application = require $this->bootstrapFile;
        if (!$application instanceof Injectable) {
            throw new ModuleException(__CLASS__, 'Bootstrap must return \Phalcon\Di\Injectable object');
        }

        $this->di = $application->getDI();

        if (!$this->di instanceof DiInterface) {
            throw new ModuleException(__CLASS__, 'Dependency injector container must implement DiInterface');
        }

        Di::reset();
        Di::setDefault($this->di);

        if ($this->di->has('session')) {
            // Destroy existing sessions of previous tests
            $this->di['session'] = new PhalconMemorySession();
        }

        if ($this->di->has('cookies')) {
            $this->di['cookies']->useEncryption(false);
        }

        if ($this->config['cleanup'] && $this->di->has('db')) {
            if ($this->config['savepoints']) {
                $this->di['db']->setNestedTransactionsWithSavepoints(true);
            }
            $this->di['db']->begin();
        }

        // localize
        $bootstrap = $this->bootstrapFile;
        $this->client->setApplication(function () use ($bootstrap) {
            $currentDi = Di::getDefault();
            $application = require $bootstrap;
            $di = $application->getDI();
            if ($currentDi->has('db')) {
                $di['db'] = $currentDi['db'];
            }
            if ($currentDi->has('session')) {
                $di['session'] = $currentDi['session'];
            }
            if ($di->has('cookies')) {
                $di['cookies']->useEncryption(false);
            }
            return $application;
        });
    }

    /**
     * HOOK: after scenario
     *
     * @param TestCase $test
     */
    public function _after(TestCase $test)
    {
        if ($this->config['cleanup'] && isset($this->di['db'])) {
            while ($this->di['db']->isUnderTransaction()) {
                $level = $this->di['db']->getTransactionLevel();
                try {
                    $this->di['db']->rollback(true);
                } catch (PDOException $e) {
                }
                if ($level == $this->di['db']->getTransactionLevel()) {
                    break;
                }
            }
            $this->di['db']->close();
        }
        $this->di = null;
        Di::reset();

        $_SESSION = $_FILES = $_GET = $_POST = $_COOKIE = $_REQUEST = [];
    }

    public function _parts()
    {
        return ['orm'];
    }

    /**
     * Provides access the Phalcon application object.
     *
     * @see \Codeception\Lib\Connector\Phalcon::getApplication
     * @return \Phalcon\Mvc\Application|\Phalcon\Mvc\Micro|\Phalcon\Cli\Console
     */
    public function getApplication()
    {
        return $this->client->getApplication();
    }

    /**
     * Sets value to session. Use for authorization.
     *
     * @param string $key
     * @param mixed $val
     */
    public function haveInSession($key, $val)
    {
        $this->di->get('session')->set($key, $val);
        $this->debugSection('Session', json_encode($this->di['session']->toArray()));
    }

    /**
     * Checks that session contains value.
     * If value is `null` checks that session has key.
     *
     * ``` php
     * <?php
     * $I->seeInSession('key');
     * $I->seeInSession('key', 'value');
     * ?>
     * ```
     *
     * @param string $key
     * @param mixed $value
     */
    public function seeInSession($key, $value = null)
    {
        $this->debugSection('Session', json_encode($this->di['session']->toArray()));

        if (is_array($key)) {
            $this->seeSessionHasValues($key);
            return;
        }

        if (!$this->di['session']->has($key)) {
            $this->fail("No session variable with key '$key'");
        }

        if (is_null($value)) {
            $this->assertTrue($this->di['session']->has($key));
        } else {
            $this->assertEquals($value, $this->di['session']->get($key));
        }
    }

    /**
     * Assert that the session has a given list of values.
     *
     * ``` php
     * <?php
     * $I->seeSessionHasValues(['key1', 'key2']);
     * $I->seeSessionHasValues(['key1' => 'value1', 'key2' => 'value2']);
     * ?>
     * ```
     *
     * @param  array $bindings
     * @return void
     */
    public function seeSessionHasValues(array $bindings)
    {
        foreach ($bindings as $key => $value) {
            if (is_int($key)) {
                $this->seeInSession($value);
            } else {
                $this->seeInSession($key, $value);
            }
        }
    }

    /**
     * Inserts record into the database.
     *
     * ``` php
     * <?php
     * $user_id = $I->haveRecord('Phosphorum\Models\Users', ['name' => 'Phalcon']);
     * $I->haveRecord('Phosphorum\Models\Categories', ['name' => 'Testing']');
     * ?>
     * ```
     *
     * @param string $model Model name
     * @param array $attributes Model attributes
     * @return mixed
     * @part orm
     */
    public function haveRecord($model, $attributes = [])
    {
        $record = $this->getModelRecord($model);
        $res = $record->save($attributes);
        $field = function($field) {
            if (is_array($field)) {
                return implode(', ', $field);
            }

            return $field;
        };

        if (!$res) {
            $messages = $record->getMessages();
            $errors = [];
            foreach ($messages as $message) {
                $errors[] = sprintf('[%s] %s: %s', $message->getType(), $field($message->getField()), $message->getMessage());
            }

            $this->fail(sprintf("Record %s was not saved. Messages: \n%s", $model, implode(PHP_EOL, $errors)));
        }
        $this->debugSection($model, json_encode($record));

        return $this->getModelIdentity($record);
    }

    /**
     * Checks that record exists in database.
     *
     * ``` php
     * <?php
     * $I->seeRecord('Phosphorum\Models\Categories', ['name' => 'Testing']);
     * ?>
     * ```
     *
     * @param string $model Model name
     * @param array $attributes Model attributes
     */
    public function seeRecord($model, $attributes = [])
    {
        $record = $this->findRecord($model, $attributes);
        if (!$record) {
            $this->fail("Couldn't find $model with " . json_encode($attributes));
        }
        $this->debugSection($model, json_encode($record));
    }

    /**
     * Checks that record does not exist in database.
     *
     * ``` php
     * <?php
     * $I->dontSeeRecord('Phosphorum\Models\Categories', ['name' => 'Testing']);
     * ?>
     * ```
     *
     * @param string $model Model name
     * @param array $attributes Model attributes
     */
    public function dontSeeRecord($model, $attributes = [])
    {
        $record = $this->findRecord($model, $attributes);
        $this->debugSection($model, json_encode($record));
        if ($record) {
            $this->fail("Unexpectedly managed to find $model with " . json_encode($attributes));
        }
    }

    /**
     * Retrieves record from database
     *
     * ``` php
     * <?php
     * $category = $I->grabRecord('Phosphorum\Models\Categories', ['name' => 'Testing']);
     * ?>
     * ```
     *
     * @param string $model Model name
     * @param array $attributes Model attributes
     * @return mixed
     * @part orm
     */
    public function grabRecord($model, $attributes = [])
    {
        return $this->findRecord($model, $attributes);
    }

    /**
     * Resolves the service based on its configuration from Phalcon's DI container
     * Recommended to use for unit testing.
     *
     * @param string $service    Service name
     * @param array  $parameters Parameters [Optional]
     *
     * @return mixed
     */
    public function grabServiceFromDi($service, array $parameters = [])
    {
        if (!$this->di->has($service)) {
            $this->fail("Service $service is not available in container");
        }

        return $this->di->get($service, $parameters);
    }

    /**
     * Registers a service in the services container and resolve it. This record will be erased after the test.
     * Recommended to use for unit testing.
     *
     * ``` php
     * <?php
     * $filter = $I->haveServiceInDi('filter', ['className' => '\Phalcon\Filter']);
     * ?>
     * ```
     *
     * @param string $name
     * @param mixed $definition
     * @param boolean $shared
     *
     * @return mixed|null
     */
    public function haveServiceInDi($name, $definition, $shared = false)
    {
        try {
            $service = $this->di->set($name, $definition, $shared);
            return $service->resolve();
        } catch (\Exception $e) {
            $this->fail($e->getMessage());

            return null;
        }
    }

    /**
     * Opens web page using route name and parameters.
     *
     * ``` php
     * <?php
     * $I->amOnRoute('posts.create');
     * ?>
     * ```
     *
     * @param $routeName
     * @param array $params
     */
    public function amOnRoute($routeName, array $params = [])
    {
        if (!$this->di->has('url')) {
            $this->fail('Unable to resolve "url" service.');
        }

        /** @var Url $url */
        $url = $this->di->getShared('url');

        $urlParams = ['for' => $routeName];

        if ($params) {
            $urlParams += $params;
        }

        try {
            $this->amOnPage($url->get($urlParams, null, true));
        } catch (Exception $e) {
            $this->fail($e->getMessage());
        }
    }

    /**
     * Checks that current url matches route
     *
     * ``` php
     * <?php
     * $I->seeCurrentRouteIs('posts.index');
     * ?>
     * ```
     * @param string $routeName
     */
    public function seeCurrentRouteIs($routeName)
    {
        if (!$this->di->has('url')) {
            $this->fail('Unable to resolve "url" service.');
        }

        /** @var Url $url */
        $url = $this->di->getShared('url');

        try {
            $this->seeCurrentUrlEquals($url->get(['for' => $routeName], null, true));
        } catch (Exception $e) {
            $this->fail($e->getMessage());
        }
    }

    /**
     * Allows to query the first record that match the specified conditions
     *
     * @param string $model Model name
     * @param array $attributes Model attributes
     *
     * @return \Phalcon\Mvc\Model
     */
    protected function findRecord($model, $attributes = [])
    {
        $this->getModelRecord($model);
        $query = [];
        foreach ($attributes as $key => $value) {
            $query[] = "$key = '$value'";
        }
        $squery = implode(' AND ', $query);
        $this->debugSection('Query', $squery);
        return call_user_func_array([$model, 'findFirst'], [$squery]);
    }

    /**
     * Get Model Record
     *
     * @param $model
     *
     * @return \Phalcon\Mvc\Model
     * @throws ModuleException
     */
    protected function getModelRecord($model)
    {
        if (!class_exists($model)) {
            throw new ModuleException(__CLASS__, "Model $model does not exist");
        }

        $record = new $model;
        if (!$record instanceof PhalconModel) {
            throw new ModuleException(__CLASS__, "Model $model is not instance of \\Phalcon\\Mvc\\Model");
        }

        return $record;
    }

    /**
     * Get identity.
     *
     * @param \Phalcon\Mvc\Model $model
     * @return mixed
     */
    protected function getModelIdentity(PhalconModel $model)
    {
        if (property_exists($model, 'id')) {
            return $model->id;
        }

        if (!$this->di->has('modelsMetadata')) {
            return null;
        }

        $primaryKeys = $this->di->get('modelsMetadata')->getPrimaryKeyAttributes($model);

        switch (count($primaryKeys)) {
            case 0:
                return null;
            case 1:
                return $model->{$primaryKeys[0]};
            default:
                return array_intersect_key(get_object_vars($model), array_flip($primaryKeys));
        }
    }

    /**
     * Returns a list of recognized domain names
     *
     * @return array
     */
    protected function getInternalDomains()
    {
        $internalDomains = [$this->getApplicationDomainRegex()];

        /** @var RouterInterface $router */
        $router = $this->di->get('router');

        if ($router instanceof RouterInterface) {
            /** @var RouteInterface[] $routes */
            $routes = $router->getRoutes();

            foreach ($routes as $route) {
                if ($route instanceof RouteInterface) {
                    $hostName = $route->getHostName();
                    if (!empty($hostName)) {
                        $internalDomains[] = '/^' . str_replace('.', '\.', $route->getHostName()) . '$/';
                    }
                }
            }
        }

        return array_unique($internalDomains);
    }

    /**
     * @return string
     */
    private function getApplicationDomainRegex()
    {
        $server = ReflectionHelper::readPrivateProperty($this->client, 'server');
        $domain = $server['HTTP_HOST'];

        return '/^' . str_replace('.', '\.', $domain) . '$/';
    }
}
<?php
namespace Codeception\Module;

use Codeception\Module as CodeceptionModule;
use \Codeception\Util\Shared\Asserts as SharedAsserts;

/**
 * Special module for using asserts in your tests.
 */
class Asserts extends CodeceptionModule
{
    use SharedAsserts;

    /**
     * Checks that two variables are equal.
     *
     * @param        $expected
     * @param        $actual
     * @param string $message
     */
    public function assertEquals($expected, $actual, $message = '')
    {
        parent::assertEquals($expected, $actual, $message);
    }

    /**
     * Checks that two variables are not equal
     *
     * @param        $expected
     * @param        $actual
     * @param string $message
     */
    public function assertNotEquals($expected, $actual, $message = '')
    {
        parent::assertNotEquals($expected, $actual, $message);
    }

    /**
     * Checks that two variables are same
     *
     * @param        $expected
     * @param        $actual
     * @param string $message
     * @return mixed|void
     */
    public function assertSame($expected, $actual, $message = '')
    {
        parent::assertSame($expected, $actual, $message);
    }

    /**
     * Checks that two variables are not same
     *
     * @param        $expected
     * @param        $actual
     * @param string $message
     */
    public function assertNotSame($expected, $actual, $message = '')
    {
        parent::assertNotSame($expected, $actual, $message);
    }

    /**
     * Checks that actual is greater than expected
     *
     * @param        $expected
     * @param        $actual
     * @param string $message
     */
    public function assertGreaterThan($expected, $actual, $message = '')
    {
        parent::assertGreaterThan($expected, $actual, $message);
    }

    /**
     * @deprecated
     */
    public function assertGreaterThen($expected, $actual, $message = '')
    {
        parent::assertGreaterThan($expected, $actual, $message);
    }

    /**
     * Checks that actual is greater or equal than expected
     *
     * @param        $expected
     * @param        $actual
     * @param string $message
     */
    public function assertGreaterThanOrEqual($expected, $actual, $message = '')
    {
        parent::assertGreaterThanOrEqual($expected, $actual, $message);
    }

    /**
     * @deprecated
     */
    public function assertGreaterThenOrEqual($expected, $actual, $message = '')
    {
        parent::assertGreaterThanOrEqual($expected, $actual, $message);
    }

    /**
     * Checks that actual is less than expected
     *
     * @param        $expected
     * @param        $actual
     * @param string $message
     */
    public function assertLessThan($expected, $actual, $message = '')
    {
        parent::assertLessThan($expected, $actual, $message);
    }

    /**
     * Checks that actual is less or equal than expected
     *
     * @param        $expected
     * @param        $actual
     * @param string $message
     */
    public function assertLessThanOrEqual($expected, $actual, $message = '')
    {
        parent::assertLessThanOrEqual($expected, $actual, $message);
    }

    /**
     * Checks that haystack contains needle
     *
     * @param        $needle
     * @param        $haystack
     * @param string $message
     */
    public function assertContains($needle, $haystack, $message = '')
    {
        parent::assertContains($needle, $haystack, $message);
    }

    /**
     * Checks that haystack doesn't contain needle.
     *
     * @param        $needle
     * @param        $haystack
     * @param string $message
     */
    public function assertNotContains($needle, $haystack, $message = '')
    {
        parent::assertNotContains($needle, $haystack, $message);
    }

    /**
     * Checks that string match with pattern
     *
     * @param string $pattern
     * @param string $string
     * @param string $message
     */
    public function assertRegExp($pattern, $string, $message = '')
    {
        parent::assertRegExp($pattern, $string, $message);
    }

    /**
     * Checks that string not match with pattern
     *
     * @param string $pattern
     * @param string $string
     * @param string $message
     */
    public function assertNotRegExp($pattern, $string, $message = '')
    {
        parent::assertNotRegExp($pattern, $string, $message);
    }


    /**
     * Checks that variable is empty.
     *
     * @param        $actual
     * @param string $message
     */
    public function assertEmpty($actual, $message = '')
    {
        parent::assertEmpty($actual, $message);
    }

    /**
     * Checks that variable is not empty.
     *
     * @param        $actual
     * @param string $message
     */
    public function assertNotEmpty($actual, $message = '')
    {
        parent::assertNotEmpty($actual, $message);
    }

    /**
     * Checks that variable is NULL
     *
     * @param        $actual
     * @param string $message
     */
    public function assertNull($actual, $message = '')
    {
        parent::assertNull($actual, $message);
    }

    /**
     * Checks that variable is not NULL
     *
     * @param        $actual
     * @param string $message
     */
    public function assertNotNull($actual, $message = '')
    {
        parent::assertNotNull($actual, $message);
    }

    /**
     * Checks that condition is positive.
     *
     * @param        $condition
     * @param string $message
     */
    public function assertTrue($condition, $message = '')
    {
        parent::assertTrue($condition, $message);
    }

    /**
     * Checks that condition is negative.
     *
     * @param        $condition
     * @param string $message
     */
    public function assertFalse($condition, $message = '')
    {
        parent::assertFalse($condition, $message);
    }

    /**
     * Checks if file exists
     *
     * @param string $filename
     * @param string $message
     */
    public function assertFileExists($filename, $message = '')
    {
        parent::assertFileExists($filename, $message);
    }
    
    /**
     * Checks if file doesn't exist
     *
     * @param string $filename
     * @param string $message
     */
    public function assertFileNotExists($filename, $message = '')
    {
        parent::assertFileNotExists($filename, $message);
    }

    /**
     * @param $expected
     * @param $actual
     * @param $description
     */
    public function assertGreaterOrEquals($expected, $actual, $description = null)
    {
        $this->assertGreaterThanOrEqual($expected, $actual, $description);
    }

    /**
     * @param $expected
     * @param $actual
     * @param $description
     */
    public function assertLessOrEquals($expected, $actual, $description = null)
    {
        $this->assertLessThanOrEqual($expected, $actual, $description);
    }

    /**
     * @param $actual
     * @param $description
     */
    public function assertIsEmpty($actual, $description = null)
    {
        $this->assertEmpty($actual, $description);
    }

    /**
     * @param $key
     * @param $actual
     * @param $description
     */
    public function assertArrayHasKey($key, $actual, $description = null)
    {
        parent::assertArrayHasKey($key, $actual, $description);
    }

    /**
     * @param $key
     * @param $actual
     * @param $description
     */
    public function assertArrayNotHasKey($key, $actual, $description = null)
    {
        parent::assertArrayNotHasKey($key, $actual, $description);
    }

    /**
     * @param $class
     * @param $actual
     * @param $description
     */
    public function assertInstanceOf($class, $actual, $description = null)
    {
        parent::assertInstanceOf($class, $actual, $description);
    }

    /**
     * @param $class
     * @param $actual
     * @param $description
     */
    public function assertNotInstanceOf($class, $actual, $description = null)
    {
        parent::assertNotInstanceOf($class, $actual, $description);
    }

    /**
     * @param $type
     * @param $actual
     * @param $description
     */
    public function assertInternalType($type, $actual, $description = null)
    {
        parent::assertInternalType($type, $actual, $description);
    }

    /**
     * Fails the test with message.
     *
     * @param $message
     */
    public function fail($message)
    {
        parent::fail($message);
    }

    /**
     * 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();
     * });
     * ```
     *
     * @param $exception string or \Exception
     * @param $callback
     */
    public function expectException($exception, $callback)
     {
         $code = null;
         $msg = null;
         if (is_object($exception)) {
             /** @var $exception \Exception  **/
             $class = get_class($exception);
             $msg = $exception->getMessage();
             $code = $exception->getCode();
         } else {
             $class = $exception;
         }
         try {
             $callback();
         } catch (\Exception $e) {
             if (!$e instanceof $class) {
                 $this->fail(sprintf("Exception of class $class expected to be thrown, but %s caught", get_class($e)));
             }
             if (null !== $msg and $e->getMessage() !== $msg) {
                 $this->fail(sprintf("Exception of $class expected to be '$msg', but actual message was '%s'", $e->getMessage()));
             }
             if (null !== $code and $e->getCode() !== $code) {
                 $this->fail(sprintf("Exception of $class expected to have code $code, but actual code was %s", $e->getCode()));
             }
             $this->assertTrue(true); // increment assertion counter
             return;
         }
         $this->fail("Expected exception to be thrown, but nothing was caught");
     }
}
<?php
namespace Codeception\Module;

use Codeception\Exception\ConnectionException;
use Codeception\Exception\ElementNotFound;
use Codeception\Exception\MalformedLocatorException;
use Codeception\Exception\ModuleConfigException as ModuleConfigException;
use Codeception\Exception\ModuleException;
use Codeception\Exception\TestRuntimeException;
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\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\TestCase;
use Codeception\Util\Debug;
use Codeception\Util\Locator;
use Codeception\Util\Uri;
use Facebook\WebDriver\Exception\InvalidElementStateException;
use Facebook\WebDriver\Exception\InvalidSelectorException;
use Facebook\WebDriver\Exception\NoSuchElementException;
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\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;
use GuzzleHttp\Cookie\SetCookie;
use Symfony\Component\DomCrawler\Crawler;

/**
 * New generation Selenium WebDriver module.
 *
 * ## Local Testing
 *
 * ### Selenium
 *
 * 1. Download [Selenium Server](http://docs.seleniumhq.org/download/)
 * 2. Launch the daemon: `java -jar selenium-server-standalone-2.xx.xxx.jar`
 * 3. Configure this module (in acceptance.suite.yml) by setting url and browser:
 *
 * ```yaml
 *     modules:
 *        enabled:
 *           - WebDriver:
 *              url: 'http://localhost/'
 *              browser: firefox
 * ```
 *
 * ### PhantomJS
 *
 * PhantomJS is a headless alternative to Selenium Server that implements [the WebDriver protocol](https://code.google.com/p/selenium/wiki/JsonWireProtocol).
 * It allows you to run Selenium tests on a server without a GUI installed.
 *
 * 1. Download [PhantomJS](http://phantomjs.org/download.html)
 * 2. Run PhantomJS in WebDriver mode: `phantomjs --webdriver=4444`
 * 3. Configure this module (in acceptance.suite.yml) by setting url and `phantomjs` as browser:
 *
 * ```yaml
 *     modules:
 *        enabled:
 *           - WebDriver:
 *              url: 'http://localhost/'
 *              browser: phantomjs
 * ```
 *
 * ## 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
 * ```
 * ### 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* - Starting URL for your app.
 * * `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 share browser session between tests, or set to true to create a separate session for each test.
 * * `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` - Implicit wait (default 0 seconds).
 * * `capabilities` - Sets Selenium2 [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).
 * * `http_proxy` - sets http proxy server url for testing a remote server.
 * * `http_proxy_port` - sets http proxy server port
 * * `debug_log_entries` - how many selenium entries to print with `debugWebDriverLogs` or on fail (15 by default).
 *
 * 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'
 * ```
 *
 * ### Status
 *
 * Stability: **stable**
 * Based on [facebook php-webdriver](https://github.com/facebook/php-webdriver)
 *
 * ## 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. If speed is a concern, it's recommended you stick with explicitly specifying the locator type via the array syntax.
 *
 * ## 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');
 * ```
 *
 * ## Methods
 */
class WebDriver extends CodeceptionModule implements
    WebInterface,
    RemoteInterface,
    MultiSessionInterface,
    SessionSnapshot,
    ScreenshotSaver,
    PageSourceSaver,
    ElementLocator
{
    protected $requiredFields = ['browser', 'url'];
    protected $config = [
        'host'               => '127.0.0.1',
        'port'               => '4444',
        'restart'            => false,
        'wait'               => 0,
        'clear_cookies'      => true,
        'window_size'        => false,
        'capabilities'       => [],
        'connection_timeout' => null,
        'request_timeout'    => null,
        'http_proxy'         => null,
        'http_proxy_port'    => null,
        'ssl_proxy'          => null,
        'ssl_proxy_port'     => null,
        'debug_log_entries'  => 15,
    ];

    protected $wd_host;
    protected $capabilities;
    protected $connectionTimeoutInMs;
    protected $requestTimeoutInMs;
    protected $test;
    protected $sessionSnapshots = [];
    protected $httpProxy;
    protected $httpProxyPort;
    protected $sslProxy;
    protected $sslProxyPort;

    /**
     * @var RemoteWebDriver
     */
    public $webDriver;

    public function _initialize()
    {
        $this->wd_host = sprintf('http://%s:%s/wd/hub', $this->config['host'], $this->config['port']);
        $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->loadFirefoxProfile();
        try {
            $this->webDriver = RemoteWebDriver::create(
                $this->wd_host,
                $this->capabilities,
                $this->connectionTimeoutInMs,
                $this->requestTimeoutInMs,
                $this->httpProxy,
                $this->httpProxyPort
            );
        } catch (WebDriverCurlException $e) {
            throw new ConnectionException($e->getMessage() . "\n \nPlease make sure that Selenium Server or PhantomJS is running.");
        }
        $this->webDriver->manage()->timeouts()->implicitlyWait($this->config['wait']);
        $this->initialWindowSize();
    }

    public function _conflicts()
    {
        return 'Codeception\Lib\Interfaces\Web';
    }

    public function _before(TestCase $test)
    {
        if (!isset($this->webDriver)) {
            $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(TestCase $test)
    {
        if ($this->config['restart'] && isset($this->webDriver)) {
            $this->webDriver->quit();
            // RemoteWebDriver consists of four parts, executor, mouse, keyboard and touch, quit only set executor to null,
            // but RemoteWebDriver doesn't provide public access to check on executor
            // so we need to unset $this->webDriver here to shut it down completely
            $this->webDriver = null;
            return;
        }
        if ($this->config['clear_cookies'] && isset($this->webDriver)) {
            $this->webDriver->manage()->deleteAllCookies();
        }
    }

    public function _failed(TestCase $test, $fail)
    {
        $this->debugWebDriverLogs();
        $filename = str_replace(['::', '\\', '/'], ['.', '', ''], TestCase::getTestSignature($test)) . '.fail';
        $outputDir = codecept_output_dir();
        $this->_saveScreenshot($outputDir . $filename . '.png');
        $this->_savePageSource($outputDir . $filename . '.html');
        $this->debug("Screenshot and page source were saved into '$outputDir' dir");
    }

    /**
     * Print out latest Selenium Logs in debug mode
     */
    public function debugWebDriverLogs()
    {
        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));
            }
        } catch (UnknownServerException $e) {
            // This only happens with the IE driver, which doesn't support retrieving logs yet:
            // https://github.com/SeleniumHQ/selenium/issues/468
            $this->debug("Unable to retrieve Selenium logs");
        }

    }

    /**
     * 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;
    }

    public function _afterSuite()
    {
        // this is just to make sure webDriver is cleared after suite
        if (isset($this->webDriver)) {
            $this->webDriver->quit();
            unset($this->webDriver);
        }
    }

    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') {
            throw new ModuleException($this, "Current url is blank, no page was opened");
        }
        return Uri::retrieveUri($url);
    }

    public function _saveScreenshot($filename)
    {
        if ($this->webDriver !== null) {
            $this->webDriver->takeScreenshot($filename);
        } else {
            codecept_debug('WebDriver::_saveScreenshot method has been called when webDriver is not set');
            codecept_debug(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS));
        }
    }

    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)
    {
        file_put_contents($filename, $this->webDriver->getPageSource());
    }

    /**
     * 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
     * ?>
     * ```
     *
     * @param $name
     */
    public function makeScreenshot($name)
    {
        $debugDir = codecept_log_dir() . 'debug';
        if (!is_dir($debugDir)) {
            mkdir($debugDir, 0777);
        }
        $screenName = $debugDir . DIRECTORY_SEPARATOR . $name . '.png';
        $this->_saveScreenshot($screenName);
        $this->debug("Screenshot saved to $screenName");
    }

    /**
     * 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));
    }

    public function seeCookie($cookie, array $params = [])
    {
        $cookies = $this->filterCookies($this->webDriver->manage()->getCookies(), $params);
        $cookies = array_map(
            function ($c) {
                return $c['name'];
            }, $cookies
        );
        $this->debugSection('Cookies', json_encode($this->webDriver->manage()->getCookies()));
        $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->debugSection('Cookies', json_encode($this->webDriver->manage()->getCookies()));
        $this->assertNotContains($cookie, $cookies);
    }

    public function setCookie($cookie, $value, array $params = [])
    {
        $params['name'] = $cookie;
        $params['value'] = $value;
        if (isset($params['expires'])) { // PhpBrowser compatibility
            $params['expiry'] = $params['expires'];
        }
        if (!isset($params['domain'])) {
            $urlParts = parse_url($this->config['url']);
            if (isset($urlParts['host'])) {
                $params['domain'] = $urlParts['host'];
            }
        }
        $this->webDriver->manage()->addCookie($params);
        $this->debugSection('Cookies', json_encode($this->webDriver->manage()->getCookies()));
    }

    public function resetCookie($cookie, array $params = [])
    {
        $this->webDriver->manage()->deleteCookieNamed($cookie);
        $this->debugSection('Cookies', json_encode($this->webDriver->manage()->getCookies()));
    }

    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'];
    }

    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);
        }
        $nodes = $this->matchVisible($selector);
        $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) {
            $els = $this->match($page, $link);
            $el = reset($els);
        }
        if (!$el) {
            throw new ElementNotFound($link, 'Link or Button or CSS or XPath');
        }
        $el->click();
    }

    /**
     * @param $page
     * @param $link
     * @return WebDriverElement
     */
    protected function findClickable($page, $link)
    {
        if (is_array($link) or ($link instanceof WebDriverBy)) {
            return $this->matchFirstOrFail($page, $link);
        }

        // try to match by CSS or XPath
        try {
            $els = $this->match($page, $link, false);
            if (!empty($els)) {
                return reset($els);
            }
        } catch (MalformedLocatorException $e) {
            //ignore exception, link could still match on of the things below
        }

        $locator = Crawler::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 .//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]",
            ".//button[./@name = $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 = Crawler::xpathLiteral(trim($selector));
        // by text or label
        $xpath = Locator::combine(
            ".//*[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')]"
        );
        $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)
    {
        $nodes = $this->webDriver->findElements(WebDriverBy::partialLinkText($text));
        if (!$url) {
            $this->assertNodesContain($text, $nodes, 'a');
            return;
        }
        $this->assertNodesContain($text, $nodes, "a[href=$url]");
    }


    public function dontSeeLink($text, $url = null)
    {
        $nodes = $this->webDriver->findElements(WebDriverBy::partialLinkText($text));
        if (!$url) {
            $this->assertNodesNotContain($text, $nodes, 'a');
            return;
        }
        $nodes = array_filter(
            $nodes,
            function (WebDriverElement $e) use ($url) {
                return trim($e->getAttribute('href')) == trim($url);
            }
        );
        $this->assertNodesNotContain($text, $nodes, "a[href=$url]");
    }

    public function seeInCurrentUrl($uri)
    {
        $this->assertContains($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->assertNotContains($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->webDriver, $formSelector);
        if (empty($form)) {
            throw new ElementNotFound($formSelector, "Form via CSS or XPath");
        }
        $form = reset($form);
        foreach ($params as $name => $values) {
            $els = $form->findElements(WebDriverBy::name($name));
            if (empty($els)) {
                throw new ElementNotFound($name);
            }
            if (!is_array($values)) {
                $values = [$values];
            }
            foreach ($values as $value) {
                $ret = $this->proceedSeeInField($els, $value);
                if ($assertNot) {
                    $this->assertNot($ret);
                } else {
                    $this->assert($ret);
                }
            }
        }
    }

    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[@selected]'));
            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 'textarea':
                    // we include trimmed and real value of textarea for check
                    $currentValues[] = $el->getText(); // trimmed value
                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;

        foreach ($option as $opt) {
            try {
                $wdSelect->selectByVisibleText($opt);
                $matched = true;
            } catch (NoSuchElementException $e) {
            }
        }
        if ($matched) {
            return;
        }
        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) {
            }
        }
        if ($matched) {
            return;
        }
        throw new ElementNotFound(json_encode($option), "Option inside $select matched by name or value");
    }

    public function _initializeSession()
    {
        $this->webDriver = RemoteWebDriver::create($this->wd_host, $this->capabilities);
        $this->webDriver->manage()->timeouts()->implicitlyWait($this->config['wait']);
    }

    public function _loadSession($session)
    {
        $this->webDriver = $session;
    }

    public function _backupSession()
    {
        return $this->webDriver;
    }

    public function _closeSession($webdriver)
    {
        $webdriver->close();
    }

    /*
     * 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) {
            }

            try {
                $wdSelect->deselectByValue($opt);
                $matched = true;
            } catch (NoSuchElementException $e) {
            }

        }

        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->webDriver, $radioOrCheckbox);
        }

        $locator = Crawler::xpathLiteral($radioOrCheckbox);
        if ($context instanceof WebDriverElement && $context->getTagName() === 'input') {
            $contextType = $context->getAttribute('type');
            if (!in_array($contextType, ['checkbox', 'radio'], true)) {
                return null;
            }
            $nameLiteral = Crawler::xPathLiteral($context->getAttribute('name'));
            $typeLiteral = Crawler::xPathLiteral($contextType);
            $inputLocatorFragment = "input[@type = $typeLiteral][@name = $nameLiteral]";
            $xpath = Locator::combine(
                "ancestor::form//{$inputLocatorFragment}[(@id = ancestor::form//label[contains(normalize-space(string(.)), $locator)]/@for) or @placeholder = $locator]",
                "ancestor::form//label[contains(normalize-space(string(.)), $locator)]//{$inputLocatorFragment}"
            );
            if ($byValue) {
                $xpath = Locator::combine($xpath, "ancestor::form//{$inputLocatorFragment}[@value = $locator]");
            }
        } else {
            $xpath = Locator::combine(
                "//input[@type = 'checkbox' or @type = 'radio'][(@id = //label[contains(normalize-space(string(.)), $locator)]/@for) or @placeholder = $locator]",
                "//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->webDriver, $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($value);
    }

    public function attachFile($field, $filename)
    {
        $el = $this->findField($field);
        // in order to be compatible on different OS
        $filePath = realpath(codecept_data_dir() . $filename);
        if (!is_readable($filePath)) {
            throw new \InvalidArgumentException("file not found or 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($filePath);
    }

    /**
     * Grabs all visible text from the current page.
     *
     * @return string
     */
    public function getVisibleText()
    {
        $els = $this->webDriver->findElements(WebDriverBy::cssSelector('body'));
        if (count($els)) {
            return $els[0]->getText();
        }

        return "";
    }

    public function grabTextFrom($cssOrXPathOrRegex)
    {
        $els = $this->match($this->webDriver, $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->webDriver, $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->webDriver, $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 = [])
    {
        $els = $this->matchVisible($selector);
        $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
     */
    public function seeElementInDOM($selector, $attributes = [])
    {
        $els = $this->match($this->webDriver, $selector);
        $els = $this->filterByAttributes($els, $attributes);
        $this->assertNotEmpty($els);
    }


    /**
     * Opposite of `seeElementInDOM`.
     *
     * @param $selector
     */
    public function dontSeeElementInDOM($selector, $attributes = [])
    {
        $els = $this->match($this->webDriver, $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->webDriver, $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->assertContains($title, $this->webDriver->getTitle());
    }

    public function dontSeeInTitle($title)
    {
        $this->assertNotContains($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`|`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
     */
    public function seeInPopup($text)
    {
        if ($this->isPhantom()) {
            throw new ModuleException($this, 'PhantomJS does not support working with popups');
        }
        $this->assertContains($text, $this->webDriver->switchTo()->alert()->getText());
    }

    /**
     * Enters text into a native JavaScript prompt popup, as created by `window.prompt`.
     *
     * @param $keys
     */
    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',
     *     ]
     * ]);
     * ```
     * @param $selector
     * @param $params
     * @param $button
     */
    public function submitForm($selector, array $params, $button = null)
    {
        $form = $this->match($this->webDriver, $selector);
        if (empty($form)) {
            throw new ElementNotFound($selector, "Form via CSS or XPath");
        }
        $form = reset($form);

        $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)) {
            $els = $form->findElements(WebDriverBy::name($button));
            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->webDriver, $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 string to appear on the page.
     * Can also be passed a selector to search in.
     * 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 null $selector
     * @throws \Exception
     */
    public function waitForText($text, $timeout = 10, $selector = null)
    {
        if (!$selector) {
            $condition = WebDriverExpectedCondition::textToBePresentInElement(WebDriverBy::xpath('//body'), $text);
            $this->webDriver->wait($timeout)->until($condition);
            return;
        }

        $condition = WebDriverExpectedCondition::textToBePresentInElement($this->getLocator($selector), $text);
        $this->webDriver->wait($timeout)->until($condition);
    }

    /**
     * Wait for $timeout seconds.
     *
     * @param int $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."
            );
        }
        sleep($timeout);
    }

    /**
     * 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/facebook/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, the only way to access it is via the `executeInSelenium()` method, like so:
     *
     * ``` 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 frame on the page.
     *
     * Example:
     * ``` html
     * <iframe name="another_frame" src="http://example.com">
     *
     * ```
     *
     * ``` php
     * <?php
     * # switch to iframe
     * $I->switchToIFrame("another_frame");
     * # switch to parent page
     * $I->switchToIFrame();
     *
     * ```
     *
     * @param string|null $name
     */
    public function switchToIFrame($name = null)
    {
        if (is_null($name)) {
            $this->webDriver->switchTo()->defaultContent();
        } else {
            $this->webDriver->switchTo()->frame($name);
        }
    }

    /**
     * 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);
        };
        $this->webDriver->wait($timeout)->until($condition);

    }

    /**
     * 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()');
     * ?>
     * ```
     *
     * @param $script
     * @return mixed
     */
    public function executeJS($script)
    {
        return $this->webDriver->executeScript($script);
    }

    /**
     * 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->webDriver, $source);
        $tnodes = $this->matchFirstOrFail($this->webDriver, $target);

        $action = new WebDriverActions($this->webDriver);
        $action->dragAndDrop($snodes, $tnodes)->perform();
    }

    /**
     * Move mouse over the first element matched by the given locator.
     * 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'], 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, $offsetX = null, $offsetY = null)
    {
        $el = $this->matchFirstOrFail($this->webDriver, $cssOrXPath);
        $this->webDriver->getMouse()->mouseMove($el->getCoordinates(), $offsetX, $offsetY);
    }

    /**
     * Performs contextual click with the right mouse button on an element.
     *
     * @param $cssOrXPath
     * @throws \Codeception\Exception\ElementNotFound
     */
    public function clickWithRightButton($cssOrXPath)
    {
        $el = $this->matchFirstOrFail($this->webDriver, $cssOrXPath);
        $this->webDriver->getMouse()->contextClick($el->getCoordinates());
    }

    /**
     * Pauses test execution in debug mode.
     * To proceed test press "ENTER" in console.
     *
     * This method is useful while writing tests, since it allows you to inspect the current page in the middle of a test case.
     */
    public function pauseExecution()
    {
        Debug::pause();
    }

    /**
     * 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->webDriver, $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 (empty($nodes) and Locator::isCSS($selector)) {
                $isValidLocator = true;
                $nodes = $page->findElements(WebDriverBy::cssSelector($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)
    {
        $els = $this->match($page, $selector);
        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. ctrl, 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 key constants from WebDriverKeys class.
     *
     * ``` 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 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->webDriver, $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->assertThat($nodes, new WebDriverConstraint($text, $this->_getCurrentUri()), $selector);
    }

    protected function assertNodesNotContain($text, $nodes, $selector = null)
    {
        $this->assertThat($nodes, new WebDriverConstraintNot($text, $this->_getCurrentUri()), $selector);
    }

    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) {
                }

                try {
                    $wdSelect->selectByValue($value);
                    $matched = true;
                } catch (NoSuchElementException $e) {
                }
                if ($matched) {
                    return;
                }

                throw new ElementNotFound(json_encode($value), "Option inside $field matched by name or value");
                break;
            case "textarea":
                $el->sendKeys($value);
                return;
                break;
            case "div": //allows for content editable divs
                $el->sendKeys(WebDriverKeys::END);
                $el->sendKeys($value);
                return;
                break;
            //Text, Checkbox, Radio
            case "input":
                $type = $el->getAttribute('type');

                if ($type == 'checkbox') {
                    //Find by value or css,id,xpath
                    $field = $this->findCheckable($this->webDriver, $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;
                } else {
                    $el->sendKeys($value);
                    return;
                }
                break;
            default:
        }

        throw new ElementNotFound($field, "Field by name, label, CSS or XPath");
    }

    /**
     * @param $selector
     * @return array
     */
    protected function matchVisible($selector)
    {
        $els = $this->match($this->webDriver, $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");
    }

    /**
     * @param string $name
     */
    public function saveSessionSnapshot($name)
    {
        $this->sessionSnapshots[$name] = [];

        foreach ($this->webDriver->manage()->getCookies() as $cookie) {
            if ($this->cookieDomainMatchesConfigUrl($cookie)) {
                $this->sessionSnapshots[$name][] = $cookie;
            }
        }

        $this->debugSection('Snapshot', "Saved \"$name\" session snapshot");
    }

    /**
     * @param string $name
     * @return bool
     */
    public function loadSessionSnapshot($name)
    {
        if (!isset($this->sessionSnapshots[$name])) {
            return false;
        }
        foreach ($this->sessionSnapshots[$name] as $cookie) {
            $this->webDriver->manage()->addCookie($cookie);
        }
        $this->debugSection('Snapshot', "Restored \"$name\" session snapshot");
        return true;
    }

    /**
     * Check if the cookie domain matches the config URL.
     *
     * @param array $cookie
     * @return bool
     */
    private function cookieDomainMatchesConfigUrl(array $cookie)
    {
        if (!array_key_exists('domain', $cookie)) {
            return true;
        }

        $setCookie = new SetCookie();
        $setCookie->setDomain($cookie['domain']);

        return $setCookie->matchesDomain(parse_url($this->config['url'], PHP_URL_HOST));
    }

    /**
     * @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->webDriver, $selector);
        $x = $el->getLocation()->getX() + $offsetX;
        $y = $el->getLocation()->getY() + $offsetY;
        $this->webDriver->executeScript("window.scrollTo($x, $y)");
    }
}
<?php
namespace Codeception\Module;

use Codeception\Lib\Interfaces\DependsOnModule;
use Codeception\Module as CodeceptionModule;
use Codeception\TestCase;
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
 *
 * ## 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\Client
     */
    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(TestCase $test)
    {
        $this->client = &$this->connectionModule->client;
        $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", $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($this->getXmlResponse()->C14N(), $xml->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->assertContains($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($this->getXmlResponse()->C14N(), $xml->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->assertNotContains($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 seeResponseCodeIs($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' => $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\Module;

use Codeception\Exception\ModuleException;
use Codeception\Lib\InnerBrowser;
use Codeception\Lib\Interfaces\MultiSession;
use Codeception\Lib\Interfaces\Remote;
use Codeception\TestCase;
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: davert.codecept@mailican.com
 * * Works with [Guzzle](http://guzzlephp.org/)
 *
 * *Please review the code of non-stable modules and provide patches if you have issues.*
 *
 * ## Configuration
 *
 * * url *required* - start url of your app
 * * curl - curl options
 * * headers - ...
 * * 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
{

    private $isGuzzlePsr7;
    protected $requiredFields = ['url'];

    protected $config = [
        'verify' => false,
        'expect' => false,
        'timeout' => 30,
        'curl' => [],
        'refresh_max_interval' => 10,

        // required defaults (not recommended to change)
        'allow_redirects' => false,
        'http_errors' => false,
        'cookies' => true
    ];

    protected $guzzleConfigFields = [
        'headers',
        'auth',
        'proxy',
        'verify',
        'cert',
        'query',
        'ssl_key',
        'proxy',
        'expect',
        'version',
        'timeout',
        'connect_timeout'
    ];

    /**
     * @var \Codeception\Lib\Connector\Guzzle6
     */
    public $client;

    /**
     * @var GuzzleClient
     */
    public $guzzle;

    public function _initialize()
    {
        $this->client = $this->guessGuzzleConnector();
        $this->_initializeSession();
    }

    protected function guessGuzzleConnector()
    {
        if (!class_exists('GuzzleHttp\Client')) {
            throw new ModuleException($this, "Guzzle is not installed. Please install `guzzlehttp/guzzle` with composer");
        }
        if (class_exists('GuzzleHttp\Url')) {
            $this->isGuzzlePsr7 = false;
            return new \Codeception\Lib\Connector\Guzzle();
        }
        $this->isGuzzlePsr7 = true;
        return new \Codeception\Lib\Connector\Guzzle6();
    }

    public function _before(TestCase $test)
    {
        if (!$this->client) {
            $this->client = $this->guessGuzzleConnector();
        }
        $this->_initializeSession();
    }

    public function _getUrl()
    {
        return $this->config['url'];
    }

    /**
     * Sets the HTTP header to the passed value - which is used on
     * subsequent HTTP requests through PhpBrowser.
     *
     * Example:
     * ```php
     * <?php
     * $I->setHeader('X-Requested-With', 'Codeception');
     * $I->amOnPage('test-headers.php');
     * ?>
     * ```
     *
     * @param string $name the name of the request header
     * @param string $value the value to set it to for subsequent
     *        requests
     */
    public function setHeader($name, $value)
    {
        $this->client->setHeader($name, $value);
    }

    /**
     * Deletes the header with the passed name.  Subsequent requests
     * will not have the deleted header in its request.
     *
     * Example:
     * ```php
     * <?php
     * $I->setHeader('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)
    {
        $this->client->deleteHeader($name);
    }

    public function amHttpAuthenticated($username, $password)
    {
        $this->client->setAuth($username, $password);
    }

    public function amOnUrl($url)
    {
        $host = Uri::retrieveHost($url);
        $this->_reconfigure(['url' => $host]);
        $page = substr($url, strlen($host));
        $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
        $this->_reconfigure(['url' => $url]);
    }

    protected function onReconfigure()
    {
        $this->_initializeSession();
    }

    /**
     * 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 callable $function
     */
    public function executeInGuzzle(\Closure $function)
    {
        return $function($this->guzzle);
    }


    public function _getResponseCode()
    {
        return $this->getResponseStatusCode();
    }

    public function _initializeSession()
    {
        $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->setCookiesFromOptions();

        if ($this->isGuzzlePsr7) {
            $defaults['base_uri'] = $this->config['url'];
            $defaults['curl'] = $curlOptions;
            $this->guzzle = new GuzzleClient($defaults);
        } else {
            $defaults['config']['curl'] = $curlOptions;
            $this->guzzle = new GuzzleClient(['base_url' => $this->config['url'], 'defaults' => $defaults]);
            $this->client->setBaseUri($this->config['url']);
        }

        $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
        ];
    }

    public function _loadSession($session)
    {
        foreach ($session as $key => $val) {
            $this->$key = $val;
        }
    }

    public function _closeSession($session)
    {
        unset($session);
    }
}
<?php
namespace Codeception\Module;

use Codeception\Module as CodeceptionModule;
use Codeception\Exception\ModuleConfigException;
use Codeception\Lib\Interfaces\DependsOnModule;
use Codeception\Lib\Interfaces\DoctrineProvider;
use Codeception\TestCase;
use Doctrine\ORM\EntityManager;
use Codeception\Util\Stub;

/**
 * Allows integration and testing for projects with Doctrine2 ORM.
 * Doctrine2 uses EntityManager to perform all database operations.
 *
 * When using with Zend Framework 2 or Symfony2 Doctrine connection is automatically retrieved from Service Locator.
 * In this case you should include either **Symfony2** or **ZF2** module and specify it as dependent for Doctrine:
 *
 * ```
 * modules:
 *     enabled:
 *         - Symfony2
 *         - Doctrine2:
 *             depends: Symfony2
 * ```
 *
 * If you don't use any of frameworks above, you should specify a callback function to receive entity manager:
 *
 * ```
 * modules:
 *     enabled:
 *         - Doctrine2:
 *             connection_callback: ['MyDb', 'createEntityManager']
 *
 * ```
 *
 * This will use static method of `MyDb::createEntityManager()` to establish EntityManager.
 *
 * By default module will wrap everything into transaction for each test and rollback it afterwards. By doing this
 * tests won't write anything to database, and so will run much faster and will be isolate dfrom each other.
 * This behavior can be changed by specifying `cleanup: false` in config.
 *
 * ## Status
 *
 * * Maintainer: **davert**
 * * Stability: **stable**
 * * Contact: codecept@davert.mail.ua
 *
 * ## Config
 *
 * * cleanup: true - all doctrine queries will be run in transaction, which will be rolled back at the end of test.
 * * connection_callback: - callable that will return an instance of EntityManager. This is a must if you run Doctrine without Zend2 or Symfony2 frameworks
 *
 *  ### Example (`functional.suite.yml`)
 *
 *      modules:
 *         enabled: [Doctrine2]
 *         config:
 *            Doctrine2:
 *               cleanup: false
 *
 * ## Public Properties
 *
 * * `em` - Entity Manager
 */

class Doctrine2 extends CodeceptionModule implements DependsOnModule
{

    protected $config = [
        'cleanup' => true,
        'connection_callback' => false,
        'depends' => null
    ];

    protected $dependencyMessage = <<<EOF
Provide connection_callback function to establish database connection and get Entity Manager:

modules:
    enabled:
        - Doctrine2:
            connection_callback: [My\ConnectionClass, getEntityManager]

Or set a dependent module, which can be either Symfony2 or ZF2 to get EM from service locator:

modules:
    enabled:
        - Doctrine2:
            depends: Symfony2
EOF;

    /**
     * @var \Doctrine\ORM\EntityManager
     */
    public $em = null;

    /**
     * @var \Codeception\Lib\Interfaces\DoctrineProvider
     */
    private $dependentModule;

    public function _depends()
    {
        if ($this->config['connection_callback']) {
            return [];
        }
        return ['Codeception\Lib\Interfaces\DoctrineProvider' => $this->dependencyMessage];
    }

    public function _inject(DoctrineProvider $dependentModule = null)
    {
        $this->dependentModule = $dependentModule;
    }

    public function _beforeSuite($settings = [])
    {
        $this->retrieveEntityManager();
    }

    public function _before(TestCase $test)
    {
        $this->retrieveEntityManager();
        if ($this->config['cleanup']) {
            $this->em->getConnection()->beginTransaction();
        }
    }

    protected function retrieveEntityManager()
    {
        if ($this->dependentModule) {
            $this->em = $this->dependentModule->_getEntityManager();
        } else {
            if (is_callable($this->config['connection_callback'])) {
                $this->em = call_user_func($this->config['connection_callback']);
            }
        }

        if (!$this->em) {
            throw new ModuleConfigException(
                __CLASS__,
                "EntityManager can't be obtained.\n \n"
                . "Please specify either `connection_callback` config option\n"
                . "with callable which will return instance of EntityManager or\n"
                . "pass a dependent module which are Symfony2 or ZF2\n"
                . "to connect to Doctrine using Dependency Injection Container"
            );
        }


        if (!($this->em instanceof \Doctrine\ORM\EntityManager)) {
            throw new ModuleConfigException(
                __CLASS__,
                "Connection object is not an instance of \\Doctrine\\ORM\\EntityManager.\n"
                . "Use `connection_callback` or dependent framework modules to specify one"
            );
        }

        $this->em->getConnection()->connect();
    }

    public function _after(TestCase $test)
    {
        if (!$this->em instanceof \Doctrine\ORM\EntityManager) {
            return;
        }
        if ($this->config['cleanup'] && $this->em->getConnection()->isTransactionActive()) {
            try {
                $this->em->getConnection()->rollback();
            } catch (\PDOException $e) {
            }
        }
        $this->clean();
        $this->em->getConnection()->close();
    }

    protected function clean()
    {
        $em = $this->em;

        $reflectedEm = new \ReflectionClass($em);
        if ($reflectedEm->hasProperty('repositories')) {
            $property = $reflectedEm->getProperty('repositories');
            $property->setAccessible(true);
            $property->setValue($em, []);
        }
        $this->em->clear();
    }


    /**
     * Performs $em->flush();
     */
    public function flushToDatabase()
    {
        $this->em->flush();
    }


    /**
     * Adds entity to repository and flushes. You can redefine it's properties with the second parameter.
     *
     * Example:
     *
     * ``` php
     * <?php
     * $I->persistEntity(new \Entity\User, array('name' => 'Miles'));
     * $I->persistEntity($user, array('name' => 'Miles'));
     * ```
     *
     * @param $obj
     * @param array $values
     */
    public function persistEntity($obj, $values = [])
    {

        if ($values) {
            $reflectedObj = new \ReflectionClass($obj);
            foreach ($values as $key => $val) {
                $property = $reflectedObj->getProperty($key);
                $property->setAccessible(true);
                $property->setValue($obj, $val);
            }
        }

        $this->em->persist($obj);
        $this->em->flush();
    }

    /**
     * Mocks the repository.
     *
     * With this action you can redefine any method of any repository.
     * Please, note: this fake repositories will be accessible through entity manager till the end of test.
     *
     * Example:
     *
     * ``` php
     * <?php
     *
     * $I->haveFakeRepository('Entity\User', array('findByUsername' => function($username) {  return null; }));
     *
     * ```
     *
     * This creates a stub class for Entity\User repository with redefined method findByUsername, which will always return the NULL value.
     *
     * @param $classname
     * @param array $methods
     */
    public function haveFakeRepository($classname, $methods = [])
    {
        $em = $this->em;

        $metadata = $em->getMetadataFactory()->getMetadataFor($classname);
        $customRepositoryClassName = $metadata->customRepositoryClassName;

        if (!$customRepositoryClassName) {
            $customRepositoryClassName = '\Doctrine\ORM\EntityRepository';
        }

        $mock = Stub::make(
            $customRepositoryClassName, array_merge(
                [
                    '_entityName' => $metadata->name,
                    '_em' => $em,
                    '_class' => $metadata
                ],
                $methods
            )
        );
        $em->clear();
        $reflectedEm = new \ReflectionClass($em);
        if ($reflectedEm->hasProperty('repositories')) {
            $property = $reflectedEm->getProperty('repositories');
            $property->setAccessible(true);
            $property->setValue($em, array_merge($property->getValue($em), [$classname => $mock]));
        } else {
            $this->debugSection('Warning', 'Repository can\'t be mocked, the EventManager class doesn\'t have "repositories" property');
        }
    }

    /**
     * Persists record into repository.
     * This method crates an entity, and sets its properties directly (via reflection).
     * Setters of entity won't be executed, but you can create almost any entity and save it to database.
     * Returns id using `getId` of newly created entity.
     *
     * ```php
     * $I->haveInRepository('Entity\User', array('name' => 'davert'));
     * ```
     */
    public function haveInRepository($entity, array $data)
    {
        $reflectedEntity = new \ReflectionClass($entity);
        $entityObject = $reflectedEntity->newInstance();
        foreach ($reflectedEntity->getProperties() as $property) {
            /** @var $property \ReflectionProperty */
            if (!isset($data[$property->name])) {
                continue;
            }
            $property->setAccessible(true);
            $property->setValue($entityObject, $data[$property->name]);
        }
        $this->em->persist($entityObject);
        $this->em->flush();

        if (method_exists($entityObject, 'getId')) {
            $id = $entityObject->getId();
            $this->debug("$entity entity created with id:$id");
            return $id;
        }
    }

    /**
     * Flushes changes to database executes a query defined by array.
     * It builds query based on array of parameters.
     * You can use entity associations to build complex queries.
     *
     * Example:
     *
     * ``` php
     * <?php
     * $I->seeInRepository('User', array('name' => 'davert'));
     * $I->seeInRepository('User', array('name' => 'davert', 'Company' => array('name' => 'Codegyre')));
     * $I->seeInRepository('Client', array('User' => array('Company' => array('name' => 'Codegyre')));
     * ?>
     * ```
     *
     * Fails if record for given criteria can\'t be found,
     *
     * @param $entity
     * @param array $params
     */
    public function seeInRepository($entity, $params = [])
    {
        $res = $this->proceedSeeInRepository($entity, $params);
        $this->assert($res);
    }

    /**
     * Flushes changes to database and performs ->findOneBy() call for current repository.
     *
     * @param $entity
     * @param array $params
     */
    public function dontSeeInRepository($entity, $params = [])
    {
        $res = $this->proceedSeeInRepository($entity, $params);
        $this->assertNot($res);
    }

    protected function proceedSeeInRepository($entity, $params = [])
    {
        // we need to store to database...
        $this->em->flush();
        $data = $this->em->getClassMetadata($entity);
        $qb = $this->em->getRepository($entity)->createQueryBuilder('s');
        $this->buildAssociationQuery($qb, $entity, 's', $params);
        $this->debug($qb->getDQL());
        $res = $qb->getQuery()->getArrayResult();

        return ['True', (count($res) > 0), "$entity with " . json_encode($params)];
    }

    /**
     * Selects field value from repository.
     * It builds query based on array of parameters.
     * You can use entity associations to build complex queries.
     *
     * Example:
     *
     * ``` php
     * <?php
     * $email = $I->grabFromRepository('User', 'email', array('name' => 'davert'));
     * ?>
     * ```
     *
     * @version 1.1
     * @param $entity
     * @param $field
     * @param array $params
     * @return array
     */
    public function grabFromRepository($entity, $field, $params = [])
    {
        // we need to store to database...
        $this->em->flush();
        $data = $this->em->getClassMetadata($entity);
        $qb = $this->em->getRepository($entity)->createQueryBuilder('s');
        $qb->select('s.' . $field);
        $this->buildAssociationQuery($qb, $entity, 's', $params);
        $this->debug($qb->getDQL());
        return $qb->getQuery()->getSingleScalarResult();
    }

    /**
     * It's Fuckin Recursive!
     *
     * @param $qb
     * @param $assoc
     * @param $alias
     * @param $params
     */
    protected function buildAssociationQuery($qb, $assoc, $alias, $params)
    {
        $data = $this->em->getClassMetadata($assoc);
        foreach ($params as $key => $val) {
            if (isset($data->associationMappings)) {
                if ($map = array_key_exists($key, $data->associationMappings)) {
                    if (is_array($val)) {
                        $qb->innerJoin("$alias.$key", $key);
                        foreach ($val as $column => $v) {
                            if (is_array($v)) {
                                $this->buildAssociationQuery($qb, $map['targetEntity'], $column, $v);
                                continue;
                            }
                            $paramname = $key . '__' . $column;
                            $qb->andWhere("$key.$column = :$paramname");
                            $qb->setParameter($paramname, $v);
                        }
                        continue;
                    }
                }
            }
            if ($val === null) {
                $qb->andWhere("s.$key IS NULL");
            } else {
                $paramname = str_replace(".", "", "s_$key");
                $qb->andWhere("s.$key = :$paramname");
                $qb->setParameter($paramname, $val);
            }
        }
    }
}
<?php
namespace Codeception\Module;

use Codeception\Exception\ModuleConfigException;
use Codeception\Lib\Framework;
use Codeception\Configuration;
use Codeception\TestCase;
use Codeception\Lib\Interfaces\ActiveRecord;
use Codeception\Lib\Interfaces\PartedModule;
use Codeception\Lib\Connector\Yii2 as Yii2Connector;
use yii\db\ActiveRecordInterface;
use Yii;

/**
 * This module provides integration with [Yii framework](http://www.yiiframework.com/) (2.0).
 *
 *
 * ## Config
 *
 * * configFile *required* - the path to the application config file
 *
 * The entry script must return the application configuration array.
 *
 * You can use this module by setting params in your functional.suite.yml:
 * <pre>
 * class_name: TestGuy
 * modules:
 *     enabled:
 *         - Yii2:
 *             configFile: '/path/to/config.php'
 * </pre>
 *
 * ## Parts
 *
 * * ORM - include only haveRecord/grabRecord/seeRecord/dontSeeRecord actions
 *
 *
 * ## Status
 *
 * Maintainer: **qiangxue**
 * Stability: **stable**
 *
 */
class Yii2 extends Framework implements ActiveRecord, PartedModule
{
    /**
     * Application config file must be set.
     * @var array
     */
    protected $config = ['cleanup' => false];
    protected $requiredFields = ['configFile'];
    protected $transaction;

    public $app;

    public function _initialize()
    {
        if (!is_file(Configuration::projectDir() . $this->config['configFile'])) {
            throw new ModuleConfigException(
                __CLASS__,
                "The application config file does not exist: {$this->config['configFile']}"
            );
        }
    }

    public function _before(TestCase $test)
    {
        $this->client = new Yii2Connector();
        $this->client->configFile = Configuration::projectDir().$this->config['configFile'];
        $mainConfig = Configuration::config();
        if (isset($mainConfig['config']) && isset($mainConfig['config']['test_entry_url'])){
            $this->client->setServerParameter(
                'HTTPS',
                parse_url($mainConfig['config']['test_entry_url'], PHP_URL_SCHEME) === 'https'
            );
        }
        $this->app = $this->client->getApplication();

        if ($this->config['cleanup'] && isset($this->app->db)) {
            $this->transaction = $this->app->db->beginTransaction();
        }
    }

    public function _after(\Codeception\TestCase $test)
    {
        $_SESSION = [];
        $_FILES = [];
        $_GET = [];
        $_POST = [];
        $_COOKIE = [];
        $_REQUEST = [];
        if ($this->transaction && $this->config['cleanup']) {
            $this->transaction->rollback();
        }
        
        \yii\web\UploadedFile::reset();

        if (Yii::$app) {
            Yii::$app->session->destroy();
        }

        parent::_after($test);
    }

    public function _parts()
    {
        return ['orm'];
    }

    /**
     * Inserts record into the database.
     *
     * ``` php
     * <?php
     * $user_id = $I->haveRecord('app\models\User', array('name' => 'Davert'));
     * ?>
     * ```
     *
     * @param $model
     * @param array $attributes
     * @return mixed
     * @part orm
     */
    public function haveRecord($model, $attributes = [])
    {
        /** @var $record \yii\db\ActiveRecord  * */
        $record = $this->getModelRecord($model);
        $record->setAttributes($attributes, false);
        $res = $record->save(false);
        if (!$res) {
            $this->fail("Record $model was not saved");
        }

        return $record->primaryKey;
    }

    /**
     * Checks that record exists in database.
     *
     * ``` php
     * $I->seeRecord('app\models\User', array('name' => 'davert'));
     * ```
     *
     * @param $model
     * @param array $attributes
     * @part orm
     */
    public function seeRecord($model, $attributes = [])
    {
        $record = $this->findRecord($model, $attributes);
        if (!$record) {
            $this->fail("Couldn't find $model with " . json_encode($attributes));
        }
        $this->debugSection($model, json_encode($record));
    }

    /**
     * Checks that record does not exist in database.
     *
     * ``` php
     * $I->dontSeeRecord('app\models\User', array('name' => 'davert'));
     * ```
     *
     * @param $model
     * @param array $attributes
     * @part orm
     */
    public function dontSeeRecord($model, $attributes = [])
    {
        $record = $this->findRecord($model, $attributes);
        $this->debugSection($model, json_encode($record));
        if ($record) {
            $this->fail("Unexpectedly managed to find $model with " . json_encode($attributes));
        }
    }

    /**
     * Retrieves record from database
     *
     * ``` php
     * $category = $I->grabRecord('app\models\User', array('name' => 'davert'));
     * ```
     *
     * @param $model
     * @param array $attributes
     * @return mixed
     * @part orm
     */
    public function grabRecord($model, $attributes = [])
    {
        return $this->findRecord($model, $attributes);
    }

    protected function findRecord($model, $attributes = [])
    {
        $this->getModelRecord($model);
        return call_user_func([$model, 'find'])
            ->where($attributes)
            ->one();
    }

    protected function getModelRecord($model)
    {
        if (!class_exists($model)) {
            throw new \RuntimeException("Model $model does not exist");
        }
        $record = new $model;
        if (!$record instanceof ActiveRecordInterface) {
            throw new \RuntimeException("Model $model is not implement interface \\yii\\db\\ActiveRecordInterface");
        }
        return $record;
    }

    /**
     * Converting $page to valid Yii 2 URL
     *
     * Allows input like:
     *
     * ```php
     * $I->amOnPage(['site/view','page'=>'about']);
     * $I->amOnPage('index-test.php?site/index');
     * $I->amOnPage('http://localhost/index-test.php?site/index');
     * ```
     *
     * @param $page string|array parameter for \yii\web\UrlManager::createUrl()
     */
    public function amOnPage($page)
    {
        if (is_array($page)) {
            $page = Yii::$app->getUrlManager()->createUrl($page);
        }
        parent::amOnPage($page);
    }

    /**
     * Getting domain regex from rule host template
     *
     * @param string $template
     * @return string
     */
    private function getDomainRegex($template)
    {
        if (preg_match('#https?://(.*)#', $template, $matches)) {
            $template = $matches[1];
        }
        $parameters = [];
        if (strpos($template, '<') !== false) {
            $template = preg_replace_callback(
                '/<(?:\w+):?([^>]+)?>/u',
                function ($matches) use (&$parameters) {
                    $key = '#' . count($parameters) . '#';
                    $parameters[$key] = isset($matches[1]) ? $matches[1] : '\w+';
                    return $key;
                },
                $template
            );
        }
        $template = preg_quote($template);
        $template = strtr($template, $parameters);
        return '/^' . $template . '$/u';
    }

    /**
     * Returns a list of regex patterns for recognized domain names
     *
     * @return array
     */
    public function getInternalDomains()
    {
        $domains = [$this->getDomainRegex(Yii::$app->urlManager->hostInfo)];

        if (Yii::$app->urlManager->enablePrettyUrl) {
            foreach (Yii::$app->urlManager->rules as $rule) {
                /** @var \yii\web\UrlRule $rule */
                if ($rule->host !== null) {
                    $domains[] = $this->getDomainRegex($rule->host);
                }
            }
        }
        return array_unique($domains);
    }
}

<?php
namespace Codeception\Module;

use Codeception\Module as CodeceptionModule;
use Codeception\TestCase;
use Codeception\Exception\ModuleException as ModuleException;
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 Symfony\Component\BrowserKit\Cookie;
use Codeception\Util\Soap as XmlUtils;

/**
 * Module for testing REST WebService.
 *
 * This module can be used either with frameworks or PHPBrowser.
 * If a framework module is connected, the testing will occur in the application directly.
 * Otherwise, a PHPBrowser should be specified as a dependency to send requests and receive responses from a server.
 *
 *
 * ## Status
 *
 * * Maintainer: **tiger-seo**, **davert**
 * * Stability: **stable**
 * * Contact: codecept@davert.mail.ua
 * * Contact: tiger.seo@gmail.com
 *
 * ## Configuration
 *
 * * url *optional* - the url of api
 *
 * This module requires PHPBrowser or any of Framework modules enabled.
 *
 * ### Example
 *
 *     modules:
 *        enabled:
 *            - REST:
 *                depends: PhpBrowser
 *                url: 'http://serviceapp/api/v1/'
 *
 * ## 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)
 *
 */
class REST extends CodeceptionModule implements DependsOnModule, PartedModule
{
    protected $config = [
        'url'           => '',
        'xdebug_remote' => false
    ];

    protected $dependencyMessage = <<<EOF
Example configuring PhpBrowser as backend for REST module.
--
modules:
    enabled:
        - REST:
            depends: PhpBrowser
            url: http://localhost/api/
--
Framework modules can be used for testing of API as well.
EOF;

    /**
     * @var \Symfony\Component\HttpKernel\Client|\Symfony\Component\BrowserKit\Client
     */
    public $client = null;
    public $isFunctional = false;

    /**
     * @var InnerBrowser
     */
    protected $connectionModule;

    public $headers = [];
    public $params = [];
    public $response = "";

    public function _before(TestCase $test)
    {
        $this->client = &$this->connectionModule->client;
        $this->resetVariables();

        if ($this->config['xdebug_remote']
            && function_exists('xdebug_is_enabled')
            && ini_get('xdebug.remote_enable')
            && !$this->isFunctional
        ) {
            $cookie = new Cookie('XDEBUG_SESSION', $this->config['xdebug_remote'], null, '/');
            $this->client->getCookieJar()->set($cookie);
        }
    }

    protected function resetVariables()
    {
        $this->headers = [];
        $this->params = [];
        $this->response = "";
        if ($this->client) {
            $this->client->setServerParameters([]);
        }
    }

    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']]);
            }
        }
    }

    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 HTTP header
     *
     * @param $name
     * @param $value
     * @part json
     * @part xml
     */
    public function haveHttpHeader($name, $value)
    {
        $this->headers[$name] = $value;
    }

    /**
     * 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->assertEquals(1, count($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)
    {
        $this->client->setAuth($username, $password, CURLAUTH_DIGEST);
    }

    /**
     * Adds Bearer authentication via access token.
     *
     * @param $accessToken
     * @part json
     * @part xml
     */
    public function amBearerAuthenticated($accessToken)
    {
        $this->haveHttpHeader('Authorization', 'Bearer ' . $accessToken);
    }

    /**
     * Sends a POST request to given uri.
     *
     * Parameters and files (as array of filenames) can be provided.
     *
     * @param $url
     * @param array|\JsonSerializable $params
     * @param array $files
     * @part json
     * @part xml
     */
    public function sendPOST($url, $params = [], $files = [])
    {
        $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 = [])
    {
        $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.
     *
     * @param $url
     * @param array $params
     * @part json
     * @part xml
     */
    public function sendGET($url, $params = [])
    {
        $this->execute('GET', $url, $params);
    }

    /**
     * Sends PUT request to given uri.
     *
     * @param $url
     * @param array $params
     * @param array $files
     * @part json
     * @part xml
     */
    public function sendPUT($url, $params = [], $files = [])
    {
        $this->execute('PUT', $url, $params, $files);
    }

    /**
     * Sends PATCH request to given uri.
     *
     * @param       $url
     * @param array $params
     * @param array $files
     * @part json
     * @part xml
     */
    public function sendPATCH($url, $params = [], $files = [])
    {
        $this->execute('PATCH', $url, $params, $files);
    }

    /**
     * Sends DELETE request to given uri.
     *
     * @param $url
     * @param array $params
     * @param array $files
     * @part json
     * @part xml
     */
    public function sendDELETE($url, $params = [], $files = [])
    {
        $this->execute('DELETE', $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->headers['Link'] = join(', ', $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 = [])
    {
        $this->debugSection("Request headers", $this->headers);

        foreach ($this->headers as $header => $val) {
            $header = str_replace('-', '_', strtoupper($header));
            $this->client->setServerParameter("HTTP_$header", $val);

            // Issue #827 - symfony foundation requires 'CONTENT_TYPE' without HTTP_
            if ($this->isFunctional && $header === 'CONTENT_TYPE') {
                $this->client->setServerParameter($header, $val);
            }
        }

        // allow full url to be requested
        if (strpos($url, '://') === false) {
            $url = $this->config['url'] . $url;
        }

        $this->params = $parameters;

        $parameters = $this->encodeApplicationJson($method, $parameters);

        if (is_array($parameters) || $method === 'GET') {
            if (!empty($parameters) && $method === 'GET') {
                $url .= '?' . http_build_query($parameters);
            }
            if ($method == 'GET') {
                $this->debugSection("Request", "$method $url");
            } else {
                $this->debugSection("Request", "$method $url " . json_encode($parameters));
            }
            $this->client->request($method, $url, $parameters, $files);
        } else {
            $requestData = $parameters;
            if (!ctype_print($requestData) && false === mb_detect_encoding($requestData, mb_detect_order(), true)) {
                // if the request data has non-printable bytes and it is not a valid unicode string, reformat the
                // display string to signify the presence of request data
                $requestData = '[binary-data length:'.strlen($requestData).' md5:'.md5($requestData).']';
            }
            $this->debugSection("Request", "$method $url " . $requestData);
            $this->client->request($method, $url, [], $files, [], $parameters);
        }
        $this->response = (string)$this->connectionModule->_getResponseContent();
        $this->debugSection("Response", $this->response);

        if (count($this->client->getInternalRequest()->getCookies())) {
            $this->debugSection('Cookies', $this->client->getInternalRequest()->getCookies());
        }
        $this->debugSection("Headers", $this->client->getInternalResponse()->getHeaders());
        $this->debugSection("Status", $this->client->getInternalResponse()->getStatus());
    }

    protected function encodeApplicationJson($method, $parameters)
    {
        if ($method !== 'GET' && array_key_exists('Content-Type', $this->headers)
            && ($this->headers['Content-Type'] === 'application/json'
                || preg_match('!^application/.+\+json$!', $this->headers['Content-Type'])
            )
        ) {
            if ($parameters instanceof \JsonSerializable) {
                return json_encode($parameters);
            }
            if (is_array($parameters) || $parameters instanceof \ArrayAccess) {
                $parameters = $this->scalarizeArray($parameters);
                return json_encode($parameters);
            }
        }
        return $parameters;
    }

    /**
     * Checks whether last response was valid JSON.
     * This is done with json_last_error function.
     *
     * @part json
     */
    public function seeResponseIsJson()
    {
        json_decode($this->connectionModule->_getResponseContent());
        $errorCode = json_last_error();
        $errorMessage = json_last_error_msg();
        \PHPUnit_Framework_Assert::assertEquals(
            JSON_ERROR_NONE,
            $errorCode,
            sprintf(
                "Invalid json: %s. System message: %s.",
                $this->connectionModule->_getResponseContent(),
                json_last_error_msg()
            )
        );
    }

    /**
     * Checks whether the last response contains text.
     *
     * @param $text
     * @part json
     * @part xml
     */
    public function seeResponseContains($text)
    {
        $this->assertContains($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->assertNotContains($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 = [])
    {
        $jsonResponseArray = new JsonArray($this->connectionModule->_getResponseContent());
        \PHPUnit_Framework_Assert::assertTrue(
            $jsonResponseArray->containsArray($json),
            "Response JSON does not contain the provided JSON\n"
            . "- <info>" . var_export($json, true) . "</info>\n"
            . "+ " . var_export($jsonResponseArray->toArray(), true)
        );
    }

    /**
     * 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'));
     * ?>
     * ```
     *
     * @version 1.1
     * @return string
     * @part json
     * @part xml
     */
    public function grabResponse()
    {
        return $this->connectionModule->_getResponseContent();
    }

    /**
     * Returns data from the current JSON response using [JSONPath](http://goessner.net/articles/JsonPath/) as selector.
     * JsonPath is XPath equivalent for querying Json structures. Try your JsonPath expressions [online](http://jsonpath.curiousconcept.com/).
     * Even for a single value an array is returned.
     *
     * This method **require [`flow/jsonpath` > 0.2](https://github.com/FlowCommunications/JSONPath/) library to be installed**.
     *
     * 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
     * @version 2.0.9
     * @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');
     * ?>
     * ```
     * @part json
     * @version 2.0.9
     */
    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
        );
    }

    /**
     * Checks if json structure in response matches [JsonPath](http://goessner.net/articles/JsonPath/).
     * JsonPath is XPath equivalent for querying Json structures. Try your JsonPath expressions [online](http://jsonpath.curiousconcept.com/).
     * This assertion allows you to check the structure of response json.
     *
     * This method **require [`flow/jsonpath` > 0.2](https://github.com/FlowCommunications/JSONPath/) library to be installed**.
     *
     * ```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');
     * ?>
     * ```
     *
     * @part json
     * @version 2.0.9
     */
    public function seeResponseJsonMatchesJsonPath($jsonPath)
    {
        $response = $this->connectionModule->_getResponseContent();
        $this->assertNotEmpty(
            (new JsonArray($response))->filterByJsonPath($jsonPath),
            "Received JSON did not match the JsonPath provided\n" . $response
        );
    }

    /**
     * Opposite to seeResponseJsonMatchesJsonPath
     *
     * @param array $jsonPath
     * @part json
     */
    public function dontSeeResponseJsonMatchesJsonPath($jsonPath)
    {
        $response = $this->connectionModule->_getResponseContent();
        $this->assertEmpty(
            (new JsonArray($response))->filterByJsonPath($jsonPath),
            "Received JSON did (but should not) match the JsonPath provided\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.
     * Starts check with a root element. If JSON data is array it will check the first element of an array.
     * 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]');
     * ?>
     * ```
     *
     * In this case you can match that record contains fields with data types you expected.
     * The list of possible data types:
     *
     * * string
     * * integer
     * * float
     * * array (json object is array as well)
     * * boolean
     *
     * You can also use nested data type structures:
     *
     * ```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 `:` char after the type declatation.
     *
     * 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 y accessing `JsonType::addCustomFilter` method.
     * See [JsonType reference](http://codeception.com/docs/reference/JsonType).
     *
     * @part json
     * @version 2.1.3
     * @param array $jsonType
     * @param string $jsonPath
     */
    public function seeResponseMatchesJsonType(array $jsonType, $jsonPath = null)
    {
        $jsonArray = new JsonArray($this->connectionModule->_getResponseContent());
        if ($jsonPath) {
            $jsonArray = $jsonArray->filterByJsonPath($jsonPath);
        }
        $matched = (new JsonType($jsonArray))->matches($jsonType);
        $this->assertTrue($matched, $matched);
    }

    /**
     * Opposite to `seeResponseMatchesJsonType`.
     *
     * @part json
     * @see seeResponseMatchesJsonType
     * @param $jsonType jsonType structure
     * @param null $jsonPath optionally set specific path to structure with JsonPath
     * @version 2.1.3
     */
    public function dontSeeResponseMatchesJsonType($jsonType, $jsonPath = null)
    {
        $jsonArray = new JsonArray($this->connectionModule->_getResponseContent());
        if ($jsonPath) {
            $jsonArray = $jsonArray->filterByJsonPath($jsonPath);
        }
        $matched = (new JsonType($jsonArray))->matches($jsonType);
        $this->assertNotEquals(true, $matched, sprintf("Unexpectedly the response matched the %s data type", var_export($jsonType, true)));
    }

    /**
     * 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.
     *
     * @part json
     * @part xml
     * @param $code
     */
    public function seeResponseCodeIs($code)
    {
        $this->assertEquals($code, $this->getRunningClient()->getInternalResponse()->getStatus());
    }

    /**
     * Checks that response code is not equal to provided value.
     *
     * @part json
     * @part xml
     * @param $code
     */
    public function dontSeeResponseCodeIs($code)
    {
        $this->assertNotEquals($code, $this->getRunningClient()->getInternalResponse()->getStatus());
    }

    /**
     * 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 wheather 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 wheather 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 grabAttributeFrom($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->assertContains(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->assertNotContains(XmlUtils::toXml($xml)->C14N(), XmlUtils::toXml($this->connectionModule->_getResponseContent())->C14N(), "found in XML Response");
    }

    /**
     * Deprecated since 2.0.9 and removed since 2.1.0
     *
     * @param $path
     * @throws ModuleException
     * @deprecated
     */
    public function grabDataFromJsonResponse($path)
    {
        throw new ModuleException($this, "This action was deprecated in Codeception 2.0.9 and removed in 2.1. Please use `grabDataFromResponseByJsonPath` instead");
    }

    /**
     * Prevents automatic redirects to be followed by the client
     */
    public function stopFollowingRedirects()
    {
        $this->client->followRedirects(false);
    }

    /**
     * Enables automatic redirects to be followed by the client
     */
    public function startFollowingRedirects()
    {
        $this->client->followRedirects(true);
    }

}
<?php
namespace Codeception\Module;

use Codeception\Module as CodeceptionModule;

/**
 * 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 function _cleanup()
    {
        $this->output = '';
    }

    /**
     * Executes a shell command.
     * Fails If exit code is > 0. You can disable this by setting second parameter to false
     *
     * ```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->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)
    {

        \PHPUnit_Framework_Assert::assertContains($text, $this->output);
    }

    /**
     * Checks that output from latest command doesn't contain text
     *
     * @param $text
     *
     */
    public function dontSeeInShellOutput($text)
    {
        $this->debug($this->output);
        \PHPUnit_Framework_Assert::assertNotContains($text, $this->output);
    }

    public function seeShellOutputMatches($regex)
    {
        \PHPUnit_Framework_Assert::assertRegExp($regex, $this->output);
    }
}
<?php
namespace Codeception\Module;

use Codeception\Exception\ModuleConfigException;
use Codeception\Exception\ModuleException;
use Codeception\Lib\Connector\Laravel5 as LaravelConnector;
use Codeception\Lib\Framework;
use Codeception\Lib\Interfaces\ActiveRecord;
use Codeception\Lib\Interfaces\PartedModule;
use Codeception\Lib\ModuleContainer;
use Codeception\Subscriber\ErrorHandler;
use Codeception\Util\ReflectionHelper;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Facades\Facade;

/**
 *
 * This module allows you to run functional tests for Laravel 5.
 * It should **not** be used for acceptance tests.
 * See the Acceptance tests section below for more details.
 *
 * ## Demo project
 * <https://github.com/janhenkgerritsen/codeception-laravel5-sample>
 *
 * ## Status
 *
 * * Maintainer: **Jan-Henk Gerritsen**
 * * Stability: **stable**
 *
 * ## Example
 *
 *     modules:
 *         enabled:
 *             - Laravel5:
 *                 environment_file: .env.testing
 *
 * ## Config
 *
 * * cleanup: `boolean`, default `true` - all db queries will be run in transaction, which will be rolled back at the end of test.
 * * environment_file: `string`, default `.env` - The .env file to load for the tests.
 * * bootstrap: `string`, default `bootstrap/app.php` - Relative path to app.php config file.
 * * root: `string`, default `` - Root path of our application.
 * * packages: `string`, default `workbench` - Root path of application packages (if any).
 * * disable_exception_handling: `boolean`, default `true` - disable Laravel exception handling
 * * disable_middleware: `boolean`, default `false` - disable all middleware.
 * * disable_events: `boolean`, default `false` - disable all events.
 * * url: `string`, default `` - The application URL.
 *
 * ## API
 *
 * * app - `Illuminate\Foundation\Application` instance
 * * client - `\Symfony\Component\BrowserKit\Client` instance
 *
 * ## Parts
 *
 * * ORM - include only haveRecord/grabRecord/seeRecord/dontSeeRecord actions
 *
 * ## Acceptance tests
 *
 * You should not use this module for acceptance tests. If you want to use Laravel functionality with your acceptance tests,
 * for example to do test setup, you can initialize the Laravel functionality by adding the following lines of code to your
 * suite `_bootstrap.php` file:
 *
 *     require 'bootstrap/autoload.php';
 *     $app = require 'bootstrap/app.php';
 *     $app->loadEnvironmentFrom('.env.testing');
 *     $app->instance('request', new \Illuminate\Http\Request);
 *     $app->make('Illuminate\Contracts\Http\Kernel')->bootstrap();
 *
 *
 */
class Laravel5 extends Framework implements ActiveRecord, PartedModule
{

    /**
     * @var \Illuminate\Foundation\Application
     */
    public $app;

    /**
     * @var array
     */
    public $config = [];

    /**
     * Constructor.
     *
     * @param ModuleContainer $container
     * @param array|null $config
     */
    public function __construct(ModuleContainer $container, $config = null)
    {
        $this->config = array_merge(
            [
                'cleanup' => true,
                'environment_file' => '.env',
                'bootstrap' => 'bootstrap' . DIRECTORY_SEPARATOR . 'app.php',
                'root' => '',
                'packages' => 'workbench',
                'disable_exception_handling' => true,
                'disable_middleware' => false,
                'disable_events' => false,
            ],
            (array)$config
        );

        $projectDir = explode($this->config['packages'], \Codeception\Configuration::projectDir())[0];
        $projectDir .= $this->config['root'];

        $this->config['project_dir'] = $projectDir;
        $this->config['bootstrap_file'] = $projectDir . $this->config['bootstrap'];

        parent::__construct($container);
    }

    /**
     * @return array
     */
    public function _parts()
    {
        return ['orm'];
    }

    /**
     * Initialize hook.
     */
    public function _initialize()
    {
        $this->checkBootstrapFileExists();
        $this->registerAutoloaders();
        $this->revertErrorHandler();
    }

    /**
     * Before hook.
     *
     * @param \Codeception\TestCase $test
     */
    public function _before(\Codeception\TestCase $test)
    {
        $this->client = new LaravelConnector($this);

        if ($this->app['db'] && $this->config['cleanup']) {
            $this->app['db']->beginTransaction();
        }
    }

    /**
     * After hook.
     *
     * @param \Codeception\TestCase $test
     */
    public function _after(\Codeception\TestCase $test)
    {
        if ($this->app['db'] && $this->config['cleanup']) {
            $this->app['db']->rollback();
        }

        if ($this->app['auth']) {
            $this->app['auth']->logout();
        }

        if ($this->app['session']) {
            $this->app['session']->flush();
        }

        if ($this->app['cache']) {
            $this->app['cache']->flush();
        }

        // disconnect from DB to prevent "Too many connections" issue
        if ($this->app['db']) {
            $this->app['db']->disconnect();
        }
    }

    /**
     * Make sure the Laravel bootstrap file exists.
     *
     * @throws ModuleConfig
     */
    protected function checkBootstrapFileExists()
    {
        $bootstrapFile = $this->config['bootstrap_file'];

        if (!file_exists($bootstrapFile)) {
            throw new ModuleConfigException(
                $this,
                "Laravel bootstrap file not found in $bootstrapFile.\nPlease provide a valid path to it using 'bootstrap' config param. "
            );
        }
    }

    /**
     * Register Laravel autoloaders.
     */
    protected function registerAutoloaders()
    {
        require $this->config['project_dir'] . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';

        \Illuminate\Support\ClassLoader::register();
    }

    /**
     * Revert back to the Codeception error handler,
     * becauses Laravel registers it's own error handler.
     */
    protected function revertErrorHandler()
    {
        $handler = new ErrorHandler();
        set_error_handler(array($handler, 'errorHandler'));
    }

    /**
     * Provides access the Laravel application object.
     *
     * @return \Illuminate\Foundation\Application
     */
    public function getApplication()
    {
        return $this->app;
    }

    /**
     * @param $app
     */
    public function setApplication($app)
    {
        $this->app = $app;
    }

    /**
     * Enable Laravel exception handling.
     *
     * ``` php
     * <?php
     * $I->enableExceptionHandling();
     * ?>
     * ```
     */
    public function enableExceptionHandling()
    {
        $this->client->enableExceptionHandling();
    }

    /**
     * Disable Laravel exception handling.
     *
     * ``` php
     * <?php
     * $I->disableExceptionHandling();
     * ?>
     * ```
     */
    public function disableExceptionHandling()
    {
        $this->client->disableExceptionHandling();
    }

    /**
     * Disable middleware for the next requests.
     *
     * ``` php
     * <?php
     * $I->disableMiddleware();
     * ?>
     * ```
     */
    public function disableMiddleware()
    {
        $this->client->disableMiddleware();
    }

    /**
     * Disable events for the next requests.
     *
     * ``` php
     * <?php
     * $I->disableEvents();
     * ?>
     * ```
     */
    public function disableEvents()
    {
        $this->client->disableEvents();
    }

    /**
     * Make sure events fired during the test.
     *
     * ``` php
     * <?php
     * $I->seeEventTriggered('App\MyEvent');
     * $I->seeEventTriggered(new App\Events\MyEvent());
     * $I->seeEventTriggered('App\MyEvent', 'App\MyOtherEvent');
     * $I->seeEventTriggered(['App\MyEvent', 'App\MyOtherEvent']);
     * ?>
     * ```
     * @param $events
     */
    public function seeEventTriggered($events)
    {
        $events = is_array($events) ? $events : func_get_args();

        foreach ($events as $event) {
            if (!$this->client->eventTriggered($event)) {
                if (is_object($event)) {
                    $event = get_class($event);
                }

                $this->fail("The '$event' event did not trigger");
            }
        }
    }

    /**
     * Make sure events did not fire during the test.
     *
     * ``` php
     * <?php
     * $I->dontSeeEventTriggered('App\MyEvent');
     * $I->dontSeeEventTriggered(new App\Events\MyEvent());
     * $I->dontSeeEventTriggered('App\MyEvent', 'App\MyOtherEvent');
     * $I->dontSeeEventTriggered(['App\MyEvent', 'App\MyOtherEvent']);
     * ?>
     * ```
     * @param $events
     */
    public function dontSeeEventTriggered($events)
    {
        $events = is_array($events) ? $events : func_get_args();

        foreach ($events as $event) {
            if ($this->client->eventTriggered($event)) {
                if (is_object($event)) {
                    $event = get_class($event);
                }

                $this->fail("The '$event' event triggered");
            }
        }
    }

    /**
     * Opens web page using route name and parameters.
     *
     * ``` php
     * <?php
     * $I->amOnRoute('posts.create');
     * ?>
     * ```
     *
     * @param $routeName
     * @param array $params
     */
    public function amOnRoute($routeName, $params = [])
    {
        $route = $this->getRouteByName($routeName);

        $absolute = !is_null($route->domain());
        $url = $this->app['url']->route($routeName, $params, $absolute);
        $this->amOnPage($url);
    }

    /**
     * Checks that current url matches route
     *
     * ``` php
     * <?php
     * $I->seeCurrentRouteIs('posts.index');
     * ?>
     * ```
     * @param $routeName
     */
    public function seeCurrentRouteIs($routeName)
    {
        $this->getRouteByName($routeName); // Fails if route does not exists

        $currentRoute = $this->app->request->route();
        $currentRouteName = $currentRoute ? $currentRoute->getName() : '';

        if ($currentRouteName != $routeName) {
            $message = empty($currentRouteName) ? "Current route has no name" : "Current route is \"$currentRouteName\"";
            $this->fail($message);
        }
    }

    /**
     * Opens web page by action name
     *
     * ``` php
     * <?php
     * $I->amOnAction('PostsController@index');
     * ?>
     * ```
     *
     * @param $action
     * @param array $params
     */
    public function amOnAction($action, $params = [])
    {
        $route = $this->getRouteByAction($action);
        $absolute = !is_null($route->domain());
        $url = $this->app['url']->action($action, $params, $absolute);

        $this->amOnPage($url);
    }

    /**
     * Checks that current url matches action
     *
     * ``` php
     * <?php
     * $I->seeCurrentActionIs('PostsController@index');
     * ?>
     * ```
     *
     * @param $action
     */
    public function seeCurrentActionIs($action)
    {
        $this->getRouteByAction($action); // Fails if route does not exists
        $currentRoute = $this->app->request->route();
        $currentAction = $currentRoute ? $currentRoute->getActionName() : '';
        $currentAction = ltrim(str_replace($this->getRootControllerNamespace(), "", $currentAction), '\\');

        if ($currentAction != $action) {
            $this->fail("Current action is \"$currentAction\"");
        }
    }

    /**
     * @param $routeName
     * @return mixed
     */
    protected function getRouteByName($routeName)
    {
        if (!$route = $this->app['routes']->getByName($routeName)) {
            $this->fail("Route with name '$routeName' does not exist");
        }

        return $route;
    }

    /**
     * @param string $action
     * @return \Illuminate\Routing\Route
     */
    protected function getRouteByAction($action)
    {
        $namespacedAction = $this->actionWithNamespace($action);

        if (!$route = $this->app['routes']->getByAction($namespacedAction)) {
            $this->fail("Action '$action' does not exist");
        }

        return $route;
    }

    /**
     * Normalize an action to full namespaced action.
     *
     * @param string $action
     * @return string
     */
    protected function actionWithNamespace($action)
    {
        $rootNamespace = $this->getRootControllerNamespace();

        if ($rootNamespace && !(strpos($action, '\\') === 0)) {
            return $rootNamespace . '\\' . $action;
        } else {
            return trim($action, '\\');
        }
    }

    /**
     * Get the root controller namespace for the application.
     *
     * @return string
     */
    protected function getRootControllerNamespace()
    {
        $urlGenerator = $this->app['url'];
        $reflection = new \ReflectionClass($urlGenerator);

        $property = $reflection->getProperty('rootNamespace');
        $property->setAccessible(true);

        return $property->getValue($urlGenerator);
    }

    /**
     * Assert that a session variable exists.
     *
     * ``` php
     * <?php
     * $I->seeInSession('key');
     * $I->seeInSession('key', 'value');
     * ?>
     * ```
     *
     * @param  string|array $key
     * @param  mixed|null $value
     * @return void
     */
    public function seeInSession($key, $value = null)
    {
        if (is_array($key)) {
            $this->seeSessionHasValues($key);
            return;
        }

        if (! $this->app['session']->has($key)) {
            $this->fail("No session variable with key '$key'");
        }

        if (! is_null($value)) {
            $this->assertEquals($value, $this->app['session']->get($key));
        }
    }

    /**
     * Assert that the session has a given list of values.
     *
     * ``` php
     * <?php
     * $I->seeSessionHasValues(['key1', 'key2']);
     * $I->seeSessionHasValues(['key1' => 'value1', 'key2' => 'value2']);
     * ?>
     * ```
     *
     * @param  array $bindings
     * @return void
     */
    public function seeSessionHasValues(array $bindings)
    {
        foreach ($bindings as $key => $value) {
            if (is_int($key)) {
                $this->seeInSession($value);
            } else {
                $this->seeInSession($key, $value);
            }
        }
    }

    /**
     * Assert that form errors are bound to the View.
     *
     * ``` php
     * <?php
     * $I->seeFormHasErrors();
     * ?>
     * ```
     *
     * @return bool
     */
    public function seeFormHasErrors()
    {
        $viewErrorBag = $this->app->make('view')->shared('errors');
        if (count($viewErrorBag) == 0) {
            $this->fail("There are no form errors");
        }
    }

    /**
     * Assert that there are no form errors bound to the View.
     *
     * ``` php
     * <?php
     * $I->dontSeeFormErrors();
     * ?>
     * ```
     *
     * @return bool
     */
    public function dontSeeFormErrors()
    {
        $viewErrorBag = $this->app->make('view')->shared('errors');
        if (count($viewErrorBag) > 0) {
            $this->fail("Found the following form errors: \n\n" . $viewErrorBag->toJson(JSON_PRETTY_PRINT));
        }
    }

    /**
     * Assert that specific form error messages are set in the view.
     *
     * This method calls `seeFormErrorMessage` for each entry in the `$bindings` array.
     *
     * ``` php
     * <?php
     * $I->seeFormErrorMessages([
     *     'username' => 'Invalid Username',
     *     'password' => null,
     * ]);
     * ?>
     * ```
     * @param array $bindings
     */
    public function seeFormErrorMessages(array $bindings)
    {
        foreach ($bindings as $key => $value) {
            $this->seeFormErrorMessage($key, $value);
        }
    }

    /**
     * Assert that a specific form error message is set in the view.
     *
     * If you want to assert that there is a form error message for a specific key
     * but don't care about the actual error message you can omit `$expectedErrorMessage`.
     *
     * If you do pass `$expectedErrorMessage`, this method checks if the actual error message for a key
     * contains `$expectedErrorMessage`.
     *
     * ``` php
     * <?php
     * $I->seeFormErrorMessage('username');
     * $I->seeFormErrorMessage('username', 'Invalid Username');
     * ?>
     * ```
     * @param string $key
     * @param string|null $expectedErrorMessage
     */
    public function seeFormErrorMessage($key, $expectedErrorMessage = null)
    {
        $viewErrorBag = $this->app['view']->shared('errors');

        if (!($viewErrorBag->has($key))) {
            $this->fail("No form error message for key '$key'\n");
        }

        if (! is_null($expectedErrorMessage)) {
            $this->assertContains($expectedErrorMessage, $viewErrorBag->first($key));
        }
    }

    /**
     * Set the currently logged in user for the application.
     * Takes either an object that implements the User interface or
     * an array of credentials.
     *
     * ``` php
     * <?php
     * // provide array of credentials
     * $I->amLoggedAs(['username' => 'jane@example.com', 'password' => 'password']);
     *
     * // provide User object
     * $I->amLoggedAs( new User );
     *
     * // can be verified with $I->seeAuthentication();
     * ?>
     * ```
     * @param  \Illuminate\Contracts\Auth\User|array $user
     * @param  string|null $driver The authentication driver for Laravel <= 5.1.*, guard name for Laravel >= 5.2
     * @return void
     */
    public function amLoggedAs($user, $driver = null)
    {
        $guard = $auth = $this->app['auth'];

        if (method_exists($auth, 'driver')) {
            $guard = $auth->driver($driver);
        }

        if (method_exists($auth, 'guard')) {
            $guard = $auth->guard($driver);
        }

        if ($user instanceof Authenticatable) {
            $guard->login($user);
            return;
        }

        if (! $guard->attempt($user)) {
            $this->fail("Failed to login with credentials " . json_encode($user));
        }
    }

    /**
     * Logout user.
     */
    public function logout()
    {
        $this->app['auth']->logout();
    }

    /**
     * Checks that a user is authenticated.
     * You can specify the guard that should be use for Laravel >= 5.2.
     * @param string|null $guard
     */
    public function seeAuthentication($guard = null)
    {
        $auth = $this->app['auth'];

        if (method_exists($auth, 'guard')) {
            $auth = $auth->guard($guard);
        }

        if (! $auth->check()) {
            $this->fail("There is no authenticated user");
        }
    }

    /**
     * Check that user is not authenticated.
     * You can specify the guard that should be use for Laravel >= 5.2.
     * @param string|null $guard
     */
    public function dontSeeAuthentication($guard = null)
    {
        $auth = $this->app['auth'];

        if (method_exists($auth, 'guard')) {
            $auth = $auth->guard($guard);
        }

        if ($auth->check()) {
            $this->fail("There is no authenticated user");
        }
    }

    /**
     * Return an instance of a class from the IoC Container.
     * (http://laravel.com/docs/ioc)
     *
     * ``` php
     * <?php
     * // In Laravel
     * App::bind('foo', function($app)
     * {
     *     return new FooBar;
     * });
     *
     * // Then in test
     * $service = $I->grabService('foo');
     *
     * // Will return an instance of FooBar, also works for singletons.
     * ?>
     * ```
     *
     * @param  string $class
     * @return mixed
     */
    public function grabService($class)
    {
        return $this->app[$class];
    }

    /**
     * Inserts record into the database.
     *
     * ``` php
     * <?php
     * $user_id = $I->haveRecord('users', array('name' => 'Davert'));
     * ?>
     * ```
     *
     * @param $tableName
     * @param array $attributes
     * @return mixed
     * @part orm
     */
    public function haveRecord($tableName, $attributes = [])
    {
        try {
            return $this->app['db']->table($tableName)->insertGetId($attributes);
        } catch (\Exception $e) {
            $this->fail("Could not insert record into table '$tableName':\n\n" . $e->getMessage());
        }
    }

    /**
     * Checks that record exists in database.
     *
     * ``` php
     * <?php
     * $I->seeRecord('users', array('name' => 'davert'));
     * ?>
     * ```
     *
     * @param $tableName
     * @param array $attributes
     * @part orm
     */
    public function seeRecord($tableName, $attributes = [])
    {
        if (! $this->findRecord($tableName, $attributes)) {
            $this->fail("Could not find matching record in table '$tableName'");
        }
    }

    /**
     * Checks that record does not exist in database.
     *
     * ``` php
     * <?php
     * $I->dontSeeRecord('users', array('name' => 'davert'));
     * ?>
     * ```
     *
     * @param $tableName
     * @param array $attributes
     * @part orm
     */
    public function dontSeeRecord($tableName, $attributes = [])
    {
        if ($this->findRecord($tableName, $attributes)) {
            $this->fail("Unexpectedly found matching record in table '$tableName'");
        }
    }

    /**
     * Retrieves record from database
     *
     * ``` php
     * <?php
     * $category = $I->grabRecord('users', array('name' => 'davert'));
     * ?>
     * ```
     *
     * @param $tableName
     * @param array $attributes
     * @return mixed
     * @part orm
     */
    public function grabRecord($tableName, $attributes = [])
    {
        if (! $record = $this->findRecord($tableName, $attributes)) {
            $this->fail("Could not find matching record in table '$tableName'");
        }

        return $record;
    }

    /**
     * @param $tableName
     * @param array $attributes
     * @return mixed
     */
    protected function findRecord($tableName, $attributes = [])
    {
        $query = $this->app['db']->table($tableName);
        foreach ($attributes as $key => $value) {
            $query->where($key, $value);
        }

        return $query->first();
    }

    /*
     * Use Laravel's model factory to create a model.
     * Can only be used with Laravel 5.1 and later.
     *
     * ``` php
     * <?php
     * $I->haveModel('App\User');
     * $I->haveModel('App\User', ['name' => 'John Doe']);
     * $I->haveModel('App\User', [], 'admin');
     * $I->haveModel('App\User', [], 'admin', 3);
     * ?>
     * ```
     *
     * @see http://laravel.com/docs/5.1/testing#model-factories
     * @param string $model
     * @param array $attributes
     * @param string $name
     * @param int $times
     * @return mixed
     */
    public function haveModel($model, $attributes = [], $name = 'default', $times = 1)
    {
        return $this->createModel($model, $attributes, $name, $times);
    }

    /**
     * Use Laravel's model factory to create a model.
     * Can only be used with Laravel 5.1 and later.
     *
     * ``` php
     * <?php
     * $I->createModel('App\User');
     * $I->createModel('App\User', ['name' => 'John Doe']);
     * $I->createModel('App\User', [], 'admin');
     * $I->createModel('App\User', [], 'admin', 3);
     * ?>
     * ```
     *
     * @see http://laravel.com/docs/5.1/testing#model-factories
     * @param string $model
     * @param array $attributes
     * @param string $name
     * @param int $times
     * @return mixed
     */
    public function createModel($model, $attributes = [], $name = 'default', $times = 1)
    {
        try {
            return $this->modelFactory($model, $name, $times)->create($attributes);
        } catch(\Exception $e) {
            $this->fail("Could not create model: \n\n" . get_class($e) . "\n\n" . $e->getMessage());
        }
    }

    /**
     * Use Laravel's model factory to make a model.
     * Can only be used with Laravel 5.1 and later.
     *
     * ``` php
     * <?php
     * $I->makeModel('App\User');
     * $I->makeModel('App\User', ['name' => 'John Doe']);
     * $I->makeModel('App\User', [], 'admin');
     * $I->makeModel('App\User', [], 'admin', 3);
     * ?>
     * ```
     *
     * @see http://laravel.com/docs/5.1/testing#model-factories
     * @param string $model
     * @param array $attributes
     * @param string $name
     * @param int $times
     * @return mixed
     */
    public function makeModel($model, $attributes = [], $name = 'default', $times = 1)
    {
        try {
            return $this->modelFactory($model, $name, $times)->make($attributes);
        } catch(\Exception $e) {
            $this->fail("Could not make model: \n\n" . get_class($e) . "\n\n" . $e->getMessage());
        }
    }

    /**
     * @param string $model
     * @param string $name
     * @param int $times
     * @return \Illuminate\Database\Eloquent\FactoryBuilder
     * @throws ModuleException
     */
    protected function modelFactory($model, $name, $times)
    {
        if (! function_exists('factory')) {
            throw new ModuleException($this, 'The factory() method does not exist. ' .
                'This functionality relies on Laravel model factories, which were introduced in Laravel 5.1.');
        }

        return factory($model, $name, $times);
    }

    /**
     * Returns a list of recognized domain names.
     * This elements of this list are regular expressions.
     *
     * @return array
     */
    protected function getInternalDomains()
    {
        $internalDomains = [$this->getApplicationDomainRegex()];

        foreach ($this->app['routes'] as $route) {
            if (!is_null($route->domain())) {
                $internalDomains[] = $this->getDomainRegex($route);
            }
        }

        return array_unique($internalDomains);
    }

    /**
     * @return string
     */
    private function getApplicationDomainRegex()
    {
        $server = ReflectionHelper::readPrivateProperty($this->client, 'server');
        $domain = $server['HTTP_HOST'];

        return '/^' . str_replace('.', '\.', $domain) . '$/';
    }

    /**
     * Get the regex for matching the domain part of this route.
     *
     * @param \Illuminate\Routing\Route $route
     * @return string
     */
    private function getDomainRegex($route)
    {
        ReflectionHelper::invokePrivateMethod($route, 'compileRoute');
        $compiledRoute = ReflectionHelper::readPrivateProperty($route, 'compiled');

        return $compiledRoute->getHostRegex();
    }
}
<?php

namespace Codeception\Module;

use Codeception\Module as CodeceptionModule;
use Codeception\TestCase;
use Codeception\Exception\ModuleException as ModuleException;
use Codeception\Lib\Driver\Redis as RedisDriver;

/**
 * Works with Redis database.
 *
 * Cleans up Redis database after each run.
 *
 * ## Status
 *
 * * Maintainer: **judgedim**
 * * Stability: **beta**
 * * Contact: https://github.com/judgedim
 *
 * ## Configuration
 *
 * * host *required* - redis host to connect
 * * port *required* - redis port.
 * * database *required* - redis database.
 * * cleanup: true - defined data will be purged before running every test.
 *
 * ## Public Properties
 * * driver - contains Connection Driver
 *
 * ### Beta Version
 *
 * Report an issue if this module doesn't work for you.
 *
 * @author judgedim
 */
class Redis extends CodeceptionModule
{
    protected $config = [
        'cleanup' => true
    ];

    /**
     * @var RedisDriver
     */
    public $driver;

    protected $requiredFields = ['host', 'port', 'database'];

    public function _initialize()
    {
        try {
            $this->driver = new RedisDriver($this->config['host'], $this->config['port']);
            $this->driver->select_db($this->config['database']);
        } catch (\Exception $e) {
            throw new ModuleException(__CLASS__, $e->getMessage());
        }
    }

    public function _before(TestCase $test)
    {
        if ($this->config['cleanup']) {
            $this->cleanup();
        }
        parent::_before($test);
    }

    public function _after(TestCase $test)
    {
        parent::_after($test);
    }

    /**
     * Cleans up Redis database.
     */
    public function cleanupRedis()
    {
        $this->cleanup();
    }

    protected function cleanup()
    {
        try {
            $this->driver->flushdb();
        } catch (\Exception $e) {
            throw new ModuleException(__CLASS__, $e->getMessage());
        }
    }
}
<?php
namespace Codeception\Module;

use Codeception\Lib\Framework;
use Codeception\Exception\ModuleConfigException;
use Codeception\TestCase;
use Codeception\Lib\Connector\Yii1 as Yii1Connector;
use Codeception\Util\ReflectionHelper;
use Yii;

/**
 * This module provides integration with Yii framework (http://www.yiiframework.com/) (1.1.14dev).
 *
 * The following configurations are available for this module:
 * <ul>
 * <li>appPath - full path to the application, include index.php</li>
 * <li>url - full url to the index.php entry script</li>
 * </ul>
 * In your index.php you must return an array with correct configuration for the application:
 *
 * For the simple created yii application index.php will be like this:
 * <pre>
 * // change the following paths if necessary
 * $yii=dirname(__FILE__).'/../yii/framework/yii.php';
 * $config=dirname(__FILE__).'/protected/config/main.php';
 *
 * // remove the following lines when in production mode
 * defined('YII_DEBUG') or define('YII_DEBUG',true);
 * // specify how many levels of call stack should be shown in each log message
 * defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL',3);
 * require_once($yii);
 * return array(
 *        'class' => 'CWebApplication',
 *        'config' => $config,
 * );
 * </pre>
 *
 * You can use this module by setting params in your functional.suite.yml:
 * <pre>
 * class_name: TestGuy
 * modules:
 *     enabled: [Yii1, TestHelper]
 *     config:
 *         Yii1:
 *             appPath: '/path/to/index.php'
 *             url: 'http://localhost/path/to/index.php'
 * </pre>
 *
 *
 * You will also need to install [Codeception-Yii Bridge](https://github.com/Codeception/YiiBridge)
 * which include component wrappers for testing.
 *
 * When you are done, you can test this module by creating new empty Yii application and creating this scenario:
 * <pre>
 * $I = new TestGuy($scenario);
 * $I->wantTo('Test index page');
 * $I->amOnPage('/index.php');
 * $I->see('My Web Application','#header #logo');
 * $I->click('Login');
 * $I->see('Login','h1');
 * $I->see('Username');
 * $I->fillField('#LoginForm_username','demo');
 * $I->fillField('#LoginForm_password','demo');
 * $I->click('#login-form input[type="submit"]');
 * $I->seeLink('Logout (demo)');
 * $I->click('Logout (demo)');
 * $I->seeLink('Login');
 * </pre>
 * Then run codeception: php codecept.phar --steps run functional
 * You must see "OK" and that all steps are marked with asterisk (*).
 * Do not forget that after adding module in your functional.suite.yml you must run codeception "build" command.
 *
 * @property Codeception\Lib\Connector\Yii1 $client
 */
class Yii1 extends Framework
{

    /**
     * Application path and url must be set always
     * @var array
     */
    protected $requiredFields = ['appPath', 'url'];

    /**
     * Application settings array('class'=>'YourAppClass','config'=>'YourAppArrayConfig');
     * @var array
     */
    private $appSettings;

    private $_appConfig;

    public function _initialize()
    {
        if (!file_exists($this->config['appPath'])) {
            throw new ModuleConfigException(
                __CLASS__,
                "Couldn't load application config file {$this->config['appPath']}\n" .
                "Please provide application bootstrap file configured for testing"
            );
        }

        $this->appSettings = include($this->config['appPath']); //get application settings in the entry script

        // get configuration from array or file
        if (is_array($this->appSettings['config'])) {
            $this->_appConfig = $this->appSettings['config'];
        } else {
            if (!file_exists($this->appSettings['config'])) {
                throw new ModuleConfigException(
                    __CLASS__,
                    "Couldn't load configuration file from Yii app file: {$this->appSettings['config']}\n" .
                    "Please provide valid 'config' parameter"
                );
            }
            $this->_appConfig = include($this->appSettings['config']);
        }

        if (!defined('YII_ENABLE_EXCEPTION_HANDLER')) {
            define('YII_ENABLE_EXCEPTION_HANDLER', false);
        }
        if (!defined('YII_ENABLE_ERROR_HANDLER')) {
            define('YII_ENABLE_ERROR_HANDLER', false);
        }

        $_SERVER['SCRIPT_NAME'] = parse_url($this->config['url'], PHP_URL_PATH);
        $_SERVER['SCRIPT_FILENAME'] = $this->config['appPath'];

        if (!function_exists('launch_codeception_yii_bridge')) {
            throw new ModuleConfigException(
                __CLASS__,
                "Codeception-Yii Bridge is not launched. In order to run tests you need to install "
                . "https://github.com/Codeception/YiiBridge Implement function 'launch_codeception_yii_bridge' to "
                . "load all Codeception overrides"
            );
        }
        launch_codeception_yii_bridge();

        Yii::$enableIncludePath = false;
        Yii::setApplication(null);
        Yii::createApplication($this->appSettings['class'], $this->_appConfig);
    }

    /*
     * Create the client connector. Called before each test
     */
    public function _createClient()
    {
        $this->client = new Yii1Connector();
        $this->client->setServerParameter("HTTP_HOST", parse_url($this->config['url'], PHP_URL_HOST));
        $this->client->appPath = $this->config['appPath'];
        $this->client->url = $this->config['url'];
        $this->client->appSettings = [
            'class'  => $this->appSettings['class'],
            'config' => $this->_appConfig,
        ];
    }

    public function _before(TestCase $test)
    {
        $this->_createClient();
    }

    public function _after(TestCase $test)
    {
        $_SESSION = [];
        $_GET = [];
        $_POST = [];
        $_COOKIE = [];
        $_REQUEST = [];
        Yii::app()->session->close();
        parent::_after($test);
    }

    /**
     * Getting domain regex from rule template and parameters
     *
     * @param string $template
     * @param array $parameters
     * @return string
     */
    private function getDomainRegex($template, $parameters = [])
    {
        if (preg_match('#https?://(.*?)/#', $template, $matches)) {
            $template = $matches[1];
        }
        if (strpos($template, '<') !== false) {
            $template = str_replace(['<', '>'], '#', $template);
        }
        $template = preg_quote($template);
        foreach ($parameters as $name => $value) {
            $template = str_replace("#$name#", $value, $template);
        }
        return '/^' . $template . '$/u';
    }


    /**
     * Returns a list of regex patterns for recognized domain names
     *
     * @return array
     */
    public function getInternalDomains()
    {
        $domains = [$this->getDomainRegex(Yii::app()->request->getHostInfo())];
        if (Yii::app()->urlManager->urlFormat === 'path') {
            $rules = ReflectionHelper::readPrivateProperty(Yii::app()->urlManager, '_rules');
            foreach ($rules as $rule) {
                if ($rule->hasHostInfo === true) {
                    $domains[] = $this->getDomainRegex($rule->template, $rule->params);
                }
            }
        }
        return array_unique($domains);
    }
}
<?php
namespace Codeception\Module;

use Codeception\Exception\ModuleConfig;
use Codeception\Lib\Connector\Lumen as LumenConnector;
use Codeception\Lib\Framework;
use Codeception\Lib\Interfaces\ActiveRecord;
use Codeception\TestCase;
use Codeception\Step;
use Codeception\Configuration;
use Codeception\Lib\ModuleContainer;
use Codeception\Subscriber\ErrorHandler;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Facade;

/**
 *
 * This module allows you to run functional tests for Lumen.
 * Please try it and leave your feedback.
 *
 * ## Demo project
 * <https://github.com/janhenkgerritsen/codeception-lumen-sample>
 *
 * ## Status
 *
 * * Maintainer: **Jan-Henk Gerritsen**
 * * Stability: **dev**
 * * Contact: janhenkgerritsen@gmail.com
 *
 * ## Config
 *
 * * cleanup: `boolean`, default `true` - all db queries will be run in transaction, which will be rolled back at the end of test.
 * * bootstrap: `string`, default `bootstrap/app.php` - Relative path to app.php config file.
 * * root: `string`, default `` - Root path of our application.
 * * packages: `string`, default `workbench` - Root path of application packages (if any).
 *
 * ## API
 *
 * * app - `Illuminate\Foundation\Application` instance
 * * client - `BrowserKit` client
 *
 */
class Lumen extends Framework implements ActiveRecord
{

    /**
     * @var \Laravel\Lumen\Application
     */
    public $app;

    /**
     * @var array
     */
    protected $config = [];

    /**
     * Constructor.
     *
     * @param ModuleContainer $container
     * @param $config
     */
    public function __construct(ModuleContainer $container, $config = null)
    {
        $this->config = array_merge(
            array(
                'cleanup' => true,
                'bootstrap' => 'bootstrap' . DIRECTORY_SEPARATOR . 'app.php',
                'root' => '',
                'packages' => 'workbench',
            ),
            (array) $config
        );

        parent::__construct($container);
    }

    /**
     * Initialize hook.
     */
    public function _initialize()
    {
        $this->initializeLumen();
    }

    /**
     * Before hook.
     *
     * @param \Codeception\TestCase $test
     * @throws ModuleConfig
     */
    public function _before(TestCase $test)
    {
        $this->initializeLumen();

        if ($this->app['db'] && $this->config['cleanup']) {
            $this->app['db']->beginTransaction();
        }
    }

    /**
     * After hook.
     *
     * @param \Codeception\TestCase $test
     */
    public function _after(TestCase $test)
    {
        if ($this->app['db'] && $this->config['cleanup']) {
            $this->app['db']->rollback();
        }

        // disconnect from DB to prevent "Too many connections" issue
        if ($this->app['db']) {
            $this->app['db']->disconnect();
        }
    }

    /**
     * After step hook.
     *
     * @param \Codeception\Step $step
     */
    public function _afterStep(Step $step)
    {
        Facade::clearResolvedInstances();
    }

    /**
     * Initialize the Lumen framework.
     *
     * @throws ModuleConfig
     */
    protected function initializeLumen()
    {
        $this->app = $this->bootApplication();
        $this->app->instance('request', new Request());
        $this->client = new LumenConnector($this->app);
        $this->client->followRedirects(true);

        $this->revertErrorHandler();
    }

    /**
     * Boot the Lumen application object.
     *
     * @return \Laravel\Lumen\Application
     * @throws \Codeception\Exception\ModuleConfig
     */
    protected function bootApplication()
    {
        $projectDir = explode($this->config['packages'], Configuration::projectDir())[0];
        $projectDir .= $this->config['root'];
        require $projectDir . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';

        $bootstrapFile = $projectDir . $this->config['bootstrap'];

        if (! file_exists($bootstrapFile)) {
            throw new ModuleConfig(
                $this,
                "Laravel bootstrap file not found in $bootstrapFile.\n"
                . "Please provide a valid path to it using 'bootstrap' config param. "
            );
        }

        $app = require $bootstrapFile;

        return $app;
    }

    /**
     * Revert back to the Codeception error handler,
     * because Laravel registers it's own error handler.
     */
    protected function revertErrorHandler()
    {
        $handler = new ErrorHandler();
        set_error_handler(array($handler, 'errorHandler'));
    }

    /**
     * Provides access the Lumen application object.
     *
     * @return \Laravel\Lumen\Application
     */
    public function getApplication()
    {
        return $this->app;
    }

    /**
     * Opens web page using route name and parameters.
     *
     * ```php
     * <?php
     * $I->amOnRoute('homepage');
     * ?>
     * ```
     *
     * @param $routeName
     * @param array $params
     */
    public function amOnRoute($routeName, $params = [])
    {
        $route = $this->getRouteByName($routeName);

        if (! $route) {
            $this->fail("Could not find route with name '$routeName'");
        }

        $url = $this->generateUrlForRoute($route, $params);
        $this->amOnPage($url);
    }

    /**
     * Get the route for a route name.
     *
     * @param string $routeName
     * @return array|null
     */
    private function getRouteByName($routeName)
    {
        foreach ($this->app->getRoutes() as $route) {
            if ($route['method'] != 'GET') {
                return;
            }

            if (isset($route['action']['as']) && $route['action']['as'] == $routeName) {
                return $route;
            }
        }

        return null;
    }

    /**
     * Generate the URL for a route specification.
     * Replaces the route parameters from left to right with the parameters
     * passed in the $params array.
     *
     * @param array $route
     * @param array $params
     * @return string
     */
    private function generateUrlForRoute($route, $params)
    {
        $url = $route['uri'];

        while(count($params) > 0) {
            $param = array_shift($params);
            $url = preg_replace('/{.+?}/', $param, $url, 1);
        }

        return $url;
    }

    /**
     * Assert that the session has a given list of values.
     *
     * @param  string|array $key
     * @param  mixed $value
     * @return void
     */
    public function seeInSession($key, $value = null)
    {
        if (is_array($key)) {
            $this->seeSessionHasValues($key);
            return;
        }

        if (is_null($value)) {
            $this->assertTrue($this->app['session']->has($key));
        } else {
            $this->assertEquals($value, $this->app['session']->get($key));
        }
    }

    /**
     * Assert that the session has a given list of values.
     *
     * @param  array $bindings
     * @return void
     */
    public function seeSessionHasValues(array $bindings)
    {
        foreach ($bindings as $key => $value) {
            if (is_int($key)) {
                $this->seeInSession($value);
            } else {
                $this->seeInSession($key, $value);
            }
        }
    }

    /**
     * Set the currently logged in user for the application.
     * Takes either an object that implements the User interface or
     * an array of credentials.
     *
     * @param  \Illuminate\Contracts\Auth\User|array $user
     * @param  string $driver
     * @return void
     */
    public function amLoggedAs($user, $driver = null)
    {
        if ($user instanceof Authenticatable) {
            $this->app['auth']->driver($driver)->setUser($user);
        } else {
            $this->app['auth']->driver($driver)->attempt($user);
        }
    }

    /**
     * Logs user out
     */
    public function logout()
    {
        $this->app['auth']->logout();
    }

    /**
     * Checks that user is authenticated
     */
    public function seeAuthentication()
    {
        $this->assertTrue($this->app['auth']->check(), 'User is not logged in');
    }

    /**
     * Check that user is not authenticated
     */
    public function dontSeeAuthentication()
    {
        $this->assertFalse($this->app['auth']->check(), 'User is logged in');
    }

    /**
     * Return an instance of a class from the IoC Container.
     *
     * Example
     * ``` php
     * <?php
     * // In Lumen
     * App::bind('foo', function($app)
     * {
     *     return new FooBar;
     * });
     *
     * // Then in test
     * $service = $I->grabService('foo');
     *
     * // Will return an instance of FooBar, also works for singletons.
     * ?>
     * ```
     *
     * @param  string $class
     * @return mixed
     */
    public function grabService($class)
    {
        return $this->app[$class];
    }

    /**
     * Inserts record into the database.
     *
     * ``` php
     * <?php
     * $user_id = $I->haveRecord('users', array('name' => 'Davert'));
     * ?>
     * ```
     *
     * @param $tableName
     * @param array $attributes
     * @return mixed
     */
    public function haveRecord($tableName, $attributes = array())
    {
        $id = $this->app['db']->table($tableName)->insertGetId($attributes);
        if (!$id) {
            $this->fail("Couldn't insert record into table $tableName");
        }
        return $id;
    }

    /**
     * Checks that record exists in database.
     *
     * ``` php
     * $I->seeRecord('users', array('name' => 'davert'));
     * ```
     *
     * @param $tableName
     * @param array $attributes
     */
    public function seeRecord($tableName, $attributes = array())
    {
        $record = $this->findRecord($tableName, $attributes);
        if (!$record) {
            $this->fail("Couldn't find $tableName with " . json_encode($attributes));
        }
        $this->debugSection($tableName, json_encode($record));
    }

    /**
     * Checks that record does not exist in database.
     *
     * ``` php
     * <?php
     * $I->dontSeeRecord('users', array('name' => 'davert'));
     * ?>
     * ```
     *
     * @param $tableName
     * @param array $attributes
     */
    public function dontSeeRecord($tableName, $attributes = array())
    {
        $record = $this->findRecord($tableName, $attributes);
        $this->debugSection($tableName, json_encode($record));
        if ($record) {
            $this->fail("Unexpectedly managed to find $tableName with " . json_encode($attributes));
        }
    }

    /**
     * Retrieves record from database
     *
     * ``` php
     * <?php
     * $category = $I->grabRecord('users', array('name' => 'davert'));
     * ?>
     * ```
     *
     * @param $tableName
     * @param array $attributes
     * @return mixed
     */
    public function grabRecord($tableName, $attributes = array())
    {
        return $this->findRecord($tableName, $attributes);
    }

    /**
     * @param $tableName
     * @param array $attributes
     * @return mixed
     */
    protected function findRecord($tableName, $attributes = array())
    {
        $query = $this->app['db']->table($tableName);
        foreach ($attributes as $key => $value) {
            $query->where($key, $value);
        }
        return $query->first();
    }

}
<?php
namespace Codeception\Module;

use Codeception\Configuration;
use Codeception\Lib\Framework;
use Codeception\TestCase;
use Codeception\Exception\ModuleException;
use Codeception\Util\ReflectionHelper;
use Codeception\Lib\Connector\ZF1 as ZF1Connector;
use Zend_Controller_Router_Route_Hostname;
use Zend_Controller_Router_Route_Chain;

/**
 * This module allows you to run tests inside Zend Framework.
 * It acts just like ControllerTestCase, but with usage of Codeception syntax.
 *
 * It assumes, you have standard structure with __APPLICATION_PATH__ set to './application'
 * and LIBRARY_PATH set to './library'. If it's not then set the appropriate path in the Config.
 *
 * [Tutorial](http://codeception.com/01-27-2012/bdd-with-zend-framework.html)
 *
 * ## Status
 *
 * * Maintainer: **davert**
 * * Stability: **stable**
 * * Contact: codecept@davert.mail.ua
 *
 * ## Config
 *
 * * env  - environment used for testing ('testing' by default).
 * * config - relative path to your application config ('application/configs/application.ini' by default).
 * * app_path - relative path to your application folder ('application' by default).
 * * lib_path - relative path to your library folder ('library' by default).
 *
 * ## API
 *
 * * client - BrowserKit client
 * * db - current instance of Zend_Db_Adapter
 * * bootstrap - current bootstrap file.
 *
 * ## Cleaning up
 *
 * For Doctrine1 and Doctrine2 all queries are put inside rollback transaction. If you are using one of this ORMs connect their modules to speed up testing.
 *
 * Unfortunately Zend_Db doesn't support nested transactions, thus, for cleaning your database you should either use standard Db module or
 * [implement nested transactions yourself](http://blog.ekini.net/2010/03/05/zend-framework-how-to-use-nested-transactions-with-zend_db-and-mysql/).
 *
 * If your database supports nested transactions (MySQL doesn't) or you implemented them you can put all your code inside a transaction.
 * Use a generated helper TestHelper. Use this code inside of it.
 *
 * ``` php
 * <?php
 * namespace Codeception\Module;
 * class TestHelper extends \Codeception\Module {
 *      function _before($test) {
 *          $this->getModule('ZF1')->db->beginTransaction();
 *      }
 *
 *      function _after($test) {
 *          $this->getModule('ZF1')->db->rollback();
 *      }
 * }
 * ?>
 * ```
 *
 * This will make your functional tests run super-fast.
 *
 */
class ZF1 extends Framework
{
    protected $config = [
        'env' => 'testing',
        'config' => 'application/configs/application.ini',
        'app_path' => 'application',
        'lib_path' => 'library'
    ];

    /**
     * @var \Zend_Application
     */
    public $bootstrap;

    /**
     * @var \Zend_Db_Adapter_Abstract
     */
    public $db;

    /**
     * @var \Codeception\Lib\Connector\ZF1
     */
    public $client;

    protected $queries = 0;
    protected $time = 0;


    /**
     * @var array Used to collect domains while recursively traversing route tree
     */
    private $domainCollector = [];

    public function _initialize()
    {
        defined('APPLICATION_ENV') || define('APPLICATION_ENV', $this->config['env']);
        defined('APPLICATION_PATH') || define('APPLICATION_PATH', Configuration::projectDir() . $this->config['app_path']);
        defined('LIBRARY_PATH') || define('LIBRARY_PATH', Configuration::projectDir() . $this->config['lib_path']);

        // Ensure library/ is on include_path
        set_include_path(
            implode(
                PATH_SEPARATOR, [
                    LIBRARY_PATH,
                    get_include_path(),
                ]
            )
        );

        require_once 'Zend/Loader/Autoloader.php';
        \Zend_Loader_Autoloader::getInstance();
    }

    public function _before(TestCase $test)
    {
        $this->client = new ZF1Connector();

        \Zend_Session::$_unitTestEnabled = true;
        try {
            $this->bootstrap = new \Zend_Application($this->config['env'], Configuration::projectDir() . $this->config['config']);
        } catch (\Exception $e) {
            throw new ModuleException(__CLASS__, $e->getMessage());
        }
        $this->bootstrap->bootstrap();
        $this->client->setBootstrap($this->bootstrap);

        $db = $this->bootstrap->getBootstrap()->getResource('db');
        if ($db instanceof \Zend_Db_Adapter_Abstract) {
            $this->db = $db;
            $this->db->getProfiler()->setEnabled(true);
            $this->db->getProfiler()->clear();
        }
    }

    public function _after(TestCase $test)
    {
        $_SESSION = [];
        $_GET = [];
        $_POST = [];
        $_COOKIE = [];
        if ($this->bootstrap) {
            $fc = $this->bootstrap->getBootstrap()->getResource('frontcontroller');
            if ($fc) {
                $fc->resetInstance();
            }
        }
        \Zend_Layout::resetMvcInstance();
        \Zend_Controller_Action_HelperBroker::resetHelpers();
        \Zend_Session::$_unitTestEnabled = true;
        \Zend_Registry::_unsetInstance();
        $this->queries = 0;
        $this->time = 0;

        parent::_after($test);
    }

    /**
     * @param $url
     */
    protected function debugResponse($url)
    {
        parent::debugResponse($url);

        $this->debugSection('Session', json_encode($_COOKIE));
        if ($this->db) {
            $profiler = $this->db->getProfiler();
            $queries = $profiler->getTotalNumQueries() - $this->queries;
            $time = $profiler->getTotalElapsedSecs() - $this->time;
            $this->debugSection('Db', $queries . ' queries');
            $this->debugSection('Time', round($time, 2) . ' secs taken');
            $this->time = $profiler->getTotalElapsedSecs();
            $this->queries = $profiler->getTotalNumQueries();
        }
    }

    /**
     * Opens web page using route name and parameters.
     *
     * ``` php
     * <?php
     * $I->amOnRoute('posts.create');
     * $I->amOnRoute('posts.show', array('id' => 34));
     * ?>
     * ```
     *
     * @param $routeName
     * @param array $params
     */
    public function amOnRoute($routeName, array $params = [])
    {
        $router = $this->bootstrap->getBootstrap()->getResource('frontcontroller')->getRouter();
        $url = $router->assemble($params, $routeName);
        $this->amOnPage($url);
    }

    /**
     * Checks that current url matches route.
     *
     * ``` php
     * <?php
     * $I->seeCurrentRouteIs('posts.index');
     * $I->seeCurrentRouteIs('posts.show', ['id' => 8]));
     * ?>
     * ```
     *
     * @param $routeName
     * @param array $params
     */
    public function seeCurrentRouteIs($routeName, array $params = [])
    {
        $router = $this->bootstrap->getBootstrap()->getResource('frontcontroller')->getRouter();
        $url = $router->assemble($params, $routeName);
        $this->seeCurrentUrlEquals($url);
    }

    protected function getInternalDomains()
    {
        $router = $this->bootstrap->getBootstrap()->getResource('frontcontroller')->getRouter();
        $this->domainCollector = [];
        $this->addInternalDomainsFromRoutes($router->getRoutes());
        return array_unique($this->domainCollector);
    }

    private function addInternalDomainsFromRoutes($routes)
    {
        foreach ($routes as $name => $route) {
            try {
                $route->assemble([]);
            } catch (\Exception $e) {
            }
            if ($route instanceof Zend_Controller_Router_Route_Hostname) {
                $this->addInternalDomain($route);
            } elseif ($route instanceof Zend_Controller_Router_Route_Chain) {
                $chainRoutes = ReflectionHelper::readPrivateProperty($route, '_routes');
                $this->addInternalDomainsFromRoutes($chainRoutes);
            }
        }
    }

    private function addInternalDomain(Zend_Controller_Router_Route_Hostname $route)
    {
        $parts = ReflectionHelper::readPrivateProperty($route, '_parts');
        foreach ($parts as &$part) {
            if ($part === null) {
                $part = '[^.]+';
            }
        }
        $regex = implode('\.', $parts);
        $this->domainCollector []= '/^' . $regex . '$/iu';
    }
}
<?php
namespace Codeception\Module;

use Codeception\Util\FileSystem as Util;
use Symfony\Component\Finder\Finder;
use Codeception\Module as CodeceptionModule;
use Codeception\TestCase;
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(TestCase $test)
    {
        $this->path = Configuration::projectDir();
    }

    /**
     * Enters a directory In local filesystem.
     * Project root directory is used by default
     *
     * @param $path
     */
    public function amInPath($path)
    {
        chdir($this->path = $this->absolutizePath($path) . DIRECTORY_SEPARATOR);
        $this->debug('Moved to ' . getcwd());
    }

    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 $filename
     */
    public function openFile($filename)
    {
        $this->file = file_get_contents($this->absolutizePath($filename));
    }

    /**
     * Deletes a file
     *
     * ``` php
     * <?php
     * $I->deleteFile('composer.lock');
     * ?>
     * ```
     *
     * @param $filename
     */
    public function deleteFile($filename)
    {
        if (!file_exists($this->absolutizePath($filename))) {
            \PHPUnit_Framework_Assert::fail('file not found');
        }
        unlink($this->absolutizePath($filename));
    }

    /**
     * Deletes directory with all subdirectories
     *
     * ``` php
     * <?php
     * $I->deleteDir('vendor');
     * ?>
     * ```
     *
     * @param $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 $src
     * @param $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 $text
     */
    public function seeInThisFile($text)
    {
        $this->assertContains($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 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 $text
     */
    public function seeFileContentsEqual($text)
    {
        $file = str_replace("\r", '', $this->file);
        \PHPUnit_Framework_Assert::assertEquals($text, $file);
    }

    /**
     * Checks If opened file doesn't contain `text` in it
     *
     * ``` php
     * <?php
     * $I->openFile('composer.json');
     * $I->dontSeeInThisFile('codeception/codeception');
     * ?>
     * ```
     *
     * @param $text
     */
    public function dontSeeInThisFile($text)
    {
        $this->assertNotContains($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 $filename
     * @param string $path
     */
    public function seeFileFound($filename, $path = '')
    {
        if (file_exists($filename) and !$path) {
            $this->openFile($filename);
            $this->filepath = $filename;
            $this->debug($filename);
            \PHPUnit_Framework_Assert::assertFileExists($path . $filename);
            return;
        }

        $path = $this->absolutizePath($path);
        $this->debug($path);
        if (!file_exists($path)) {
            $this->fail("Directory does not exist: $path");
        }

        $files = Finder::create()->files()->name($filename)->in($path);
        foreach ($files as $file) {
            $file = $file->getRealPath();
            $this->openFile($file);
            $this->filepath = $file;
            $this->debug($file);
            \PHPUnit_Framework_Assert::assertFileExists($file);
            return;
        }
        $this->fail("$filename in $path");
    }

    /**
     * Checks if file does not exist in path
     *
     * @param $filename
     * @param string $path
     */
    public function dontSeeFileFound($filename, $path = '')
    {
        \PHPUnit_Framework_Assert::assertFileNotExists($path . $filename);
    }


    /**
     * Erases directory contents
     *
     * ``` php
     * <?php
     * $I->cleanDir('logs');
     * ?>
     * ```
     *
     * @param $dirname
     */
    public function cleanDir($dirname)
    {
        $path = $this->absolutizePath($dirname);
        Util::doEmptyDir($path);
    }

    /**
     * Saves contents to file
     *
     * @param $filename
     * @param $contents
     */
    public function writeToFile($filename, $contents)
    {
        file_put_contents($filename, $contents);
    }
}
<?php
namespace Codeception\Module;

use Codeception\Lib\Framework;
use Codeception\TestCase;
use Codeception\Configuration;
use Codeception\Lib\Connector\ZendExpressive as ZendExpressiveConnector;
use Psr\Http\Message\ResponseInterface;

/**
 * This module allows you to run tests inside Zend Expressive.
 *
 * Uses `config/container.php` file by default.
 *
 * ## Status
 *
 * * Maintainer: **Naktibalda**
 * * Stability: **alpha**
 *
 * ## Config
 *
 * * container: relative path to file which returns Container (default: `config/container.php`)
 *
 * ## API
 *
 * * application -  instance of `\Zend\Expressive\Application`
 * * container - instance of `\Interop\Container\ContainerInterface`
 * * client - BrowserKit client
 *
 */
class ZendExpressive extends Framework
{
    protected $config = [
        'container' => 'config/container.php',
    ];

    /**
     * @var \Codeception\Lib\Connector\ZendExpressive
     */
    public $client;

    /**
     * @var \Interop\Container\ContainerInterface
     */
    public $container;

    /**
     * @var \Zend\Expressive\Application
     */
    public $application;

    protected $responseCollector;

    public function _initialize()
    {
        $cwd = getcwd();
        chdir(Configuration::projectDir());
        $this->container = require Configuration::projectDir() . $this->config['container'];
        chdir($cwd);
        $this->application = $this->container->get('Zend\Expressive\Application');
        $this->initResponseCollector();
    }

    public function _before(TestCase $test)
    {
        $this->client = new ZendExpressiveConnector();
        $this->client->setApplication($this->application);
        $this->client->setResponseCollector($this->responseCollector);
    }

    public function _after(TestCase $test)
    {
        //Close the session, if any are open
        if (session_status() == PHP_SESSION_ACTIVE) {
            session_write_close();
        }

        parent::_after($test);
    }

    private function initResponseCollector()
    {
        /**
         * @var Zend\Expressive\Emitter\EmitterStack
         */
        $emitterStack = $this->application->getEmitter();
        while (!$emitterStack->isEmpty()) {
            $emitterStack->pop();
        }

        $this->responseCollector = new ZendExpressiveConnector\ResponseCollector;
        $emitterStack->unshift($this->responseCollector);
    }
}
<?php
namespace Codeception\Module;

use Codeception\Configuration;
use Codeception\Exception\ModuleConfigException;
use Codeception\Lib\Framework;
use Codeception\Lib\Interfaces\DoctrineProvider;
use Codeception\TestCase;
use Symfony\Component\HttpKernel\Client;

/**
 * Module for testing Silex applications like you would regularly do with Silex\WebTestCase.
 * This module uses Symfony2 Crawler and HttpKernel to emulate requests and get response.
 *
 * This module may be considered experimental and require feedback and pull requests from you )
 *
 * ## Status
 *
 * * Maintainer: **davert**
 * * Stability: **alpha**
 * * Contact: davert.codecept@resend.cc
 *
 * ## Config
 *
 * * app: **required** - path to Silex bootstrap file.
 * * em_service: 'db.orm.em' - use the stated EntityManager to pair with Doctrine Module.
 *
 * ### Bootstrap File
 *
 * Bootstrap is the same as [WebTestCase.createApplication](http://silex.sensiolabs.org/doc/testing.html#webtestcase) should be.
 *
 * ``` php
 * <?
 * $app = require __DIR__.'/path/to/app.php';
 * $app['debug'] = true;
 * $app['exception_handler']->disable();
 *
 * return $app; // optionally
 * ?>
 * ```
 *
 * ### Example (`functional.suite.yml`)
 *
 *     modules:
 *        enabled:
 *           - Silex:
 *              app: 'app/bootstrap.php'
 *
 * Class Silex
 * @package Codeception\Module
 */
class Silex extends Framework implements DoctrineProvider
{
    protected $app;
    protected $requiredFields = ['app'];
    protected $config = [
        'em_service' => 'db.orm.em'
    ];

    public function _initialize()
    {
        if (!file_exists(Configuration::projectDir() . $this->config['app'])) {
            throw new ModuleConfigException(__CLASS__, "Bootstrap file {$this->config['app']} not found");
        }

        $this->loadApp();
    }

    public function _before(TestCase $test)
    {
        $this->loadApp();
        $this->client = new Client($this->app);
    }

    public function _getEntityManager()
    {
        if(!isset($this->app[$this->config['em_service']])){
            return null;
        }

        return $this->app[$this->config['em_service']];
    }

    protected function loadApp()
    {
        $this->app = require Configuration::projectDir() . $this->config['app'];
        // if $app is not returned but exists
        if (isset($app)) {
            $this->app = $app;
        }
        if (!isset($this->app)) {
            throw new ModuleConfigException(__CLASS__, "\$app instance was not received from bootstrap file");
        }

        // make doctrine persistent
        $db_orm_em = $this->_getEntityManager();
        if($db_orm_em){
            $this->app->extend($this->config['em_service'], function() use ($db_orm_em){
                return $db_orm_em;
            });
        }

        // some silex apps (like bolt) may rely on global $app variable
        $GLOBALS['app'] = $this->app;
    }

    /**
     * Return an instance of a class from the Container.
     *
     * Example
     * ``` php
     * <?php
     * $I->grabService('session');
     * ?>
     * ```
     *
     * @param  string $service
     * @return mixed
     */
    public function grabService($service)
    {
        return $this->app[$service];
    }

    /**
     * Returns a list of recognized domain names
     *
     * @return array
     */
    public function getInternalDomains()
    {
        $internalDomains = [];

        foreach ($this->app['routes'] as $route) {
            if ($domain = $route->getHost()) {
                $internalDomains[] = '/^' . preg_quote($domain, '/') . '$/';
            }
        }

        return $internalDomains;
    }
}
<?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\TestCase;

/**
 * Works with SQL database.
 *
 * The most important function of this module is to clean a database before each test.
 * That's why this module was added to the global configuration file `codeception.yml`.
 * To have your database properly cleaned you should configure it to access the database.
 * This module also provides actions to perform checks in a database.
 *
 * 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 (only file)
 * * PostgreSQL
 *
 * Supported but not tested.
 *
 * * MSSQL
 * * 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.1/src/Codeception/Lib/Driver) if you run into problems loading dumps and cleaning databases.
 *
 * ## Status
 *
 * * Maintainer: **davert**
 * * stability:
 *     - Mysql: **stable**
 *     - SQLite: **stable**
 *     - Postgres: **beta**
 *     - MSSQL: **alpha**
 *     - Oracle: **alpha**
 * * Contact: codecept@davert.mail.ua
 *
 * *Please review the code of non-stable modules and provide patches if you have issues.*
 *
 * ## Config
 *
 * * dsn *required* - PDO DSN
 * * user *required* - user to access database
 * * password *required* - password
 * * dump - path to database dump
 * * populate: true - whether the the dump should be loaded before the test suite is started
 * * cleanup: true - whether the dump should be reloaded after each test
 * * reconnect: false - whether the module should reconnect to the database before each test
 *
 * ### Example
 *
 *     modules:
 *        enabled:
 *           - Db:
 *              dsn: 'mysql:host=localhost;dbname=testdb'
 *              user: 'root'
 *              password: ''
 *              dump: 'tests/_data/dump.sql'
 *              populate: true
 *              cleanup: false
 *              reconnect: true
 *
 * ### SQL data dump
 * 
 *  * 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`;
 * ```
 * 
 * ## Public Properties
 * * dbh - contains the PDO connection
 * * driver - contains the Connection Driver
 *
 */
class Db extends CodeceptionModule implements DbInterface
{
    /**
     * @api
     * @var
     */
    public $dbh;

    /**
     * @var array
     */
    protected $sql = [];

    /**
     * @var array
     */
    protected $config = [
        'populate' => true,
        'cleanup' => true,
        'reconnect' => false,
        'dump' => null
    ];

    /**
     * @var bool
     */
    protected $populated = false;

    /**
     * @var \Codeception\Lib\Driver\Db
     */
    public $driver;

    /**
     * @var array
     */
    protected $insertedRows = [];

    /**
     * @var array
     */
    protected $requiredFields = ['dsn', 'user', 'password'];

    public function _initialize()
    {
        if ($this->config['dump'] && ($this->config['cleanup'] or ($this->config['populate']))) {

            if (!file_exists(Configuration::projectDir() . $this->config['dump'])) {
                throw new ModuleConfigException(
                    __CLASS__,
                    "\nFile with dump doesn't exist.\n"
                    . "Please, check path for sql file: "
                    . $this->config['dump']
                );
            }
            $sql = file_get_contents(Configuration::projectDir() . $this->config['dump']);
            $sql = preg_replace('%/\*(?!!\d+)(?:(?!\*/).)*\*/%s', "", $sql);
            if (!empty($sql)) {
                $this->sql = explode("\n", $sql);
            }
        }

        $this->connect();

        // starting with loading dump
        if ($this->config['populate']) {
            if ($this->config['cleanup']) {
                $this->cleanup();
            }
            $this->loadDump();
            $this->populated = true;
        }
    }

    private function connect()
    {
        try {
            $this->driver = Driver::create($this->config['dsn'], $this->config['user'], $this->config['password']);
        } catch (\PDOException $e) {
            $message = $e->getMessage();
            if ($message === 'could not find driver') {
                list ($missingDriver,) = explode(':', $this->config['dsn'], 2);
                $message = "could not find $missingDriver driver";
            }

            throw new ModuleException(__CLASS__, $message . ' while creating PDO connection');
        }

        $this->dbh = $this->driver->getDbh();
    }

    private function disconnect()
    {
        $this->dbh = null;
        $this->driver = null;
    }

    public function _before(TestCase $test)
    {
        if ($this->config['reconnect']) {
            $this->connect();
        }
        if ($this->config['cleanup'] && !$this->populated) {
            $this->cleanup();
            $this->loadDump();
        }
        parent::_before($test);
    }

    public function _after(TestCase $test)
    {
        $this->populated = false;
        $this->removeInserted();
        if ($this->config['reconnect']) {
            $this->disconnect();
        }
        parent::_after($test);
    }

    protected function removeInserted()
    {
        foreach (array_reverse($this->insertedRows) as $row) {
            try {
                $this->driver->deleteQueryByCriteria($row['table'], $row['primary']);
            } catch (\Exception $e) {
                $this->debug("coudn't delete record " . json_encode($row['primary']) ." from {$row['table']}");
            }
        }
        $this->insertedRows = [];
    }

    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 {
            // don't clear database for empty dump
            if (!count($this->sql)) {
                return;
            }
            $this->driver->cleanup();
        } catch (\Exception $e) {
            throw new ModuleException(__CLASS__, $e->getMessage());
        }
    }

    protected function loadDump()
    {
        if (!$this->sql) {
            return;
        }
        try {
            $this->driver->load($this->sql);
        } catch (\PDOException $e) {
            throw new ModuleException(
                __CLASS__,
                $e->getMessage() . "\nSQL query being executed: " . $this->driver->sqlToRun
            );
        }
    }

    /**
     * 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       $table
     * @param array $data
     *
     * @return integer $id
     */
    public function haveInDatabase($table, array $data)
    {
        $query = $this->driver->insert($table, $data);
        $this->debugSection('Query', $query);

        $this->driver->executeQuery($query, array_values($data));

        try {
            $lastInsertId = (int)$this->driver->lastInsertId($table);
        } catch (\PDOException $e) {
            // ignore errors due to uncommon DB structure,
            // such as tables without _id_seq in PGSQL
            $lastInsertId = 0;
        }

        $this->addInsertedRow($table, $data, $lastInsertId);

        return $lastInsertId;
    }

    private function addInsertedRow($table, array $row, $id)
    {
        $primaryKey = $this->driver->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[] = [
            '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, 'The number of found rows (' . $actualNumber. ') does not match expected number ' . $expectedNumber . ' for criteria ' . json_encode($criteria) . ' in table ' . $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);
    }

    protected function proceedSeeInDatabase($table, $column, $criteria)
    {
        $query = $this->driver->select($column, $table, $criteria);
        $this->debugSection('Query', $query, json_encode($criteria));

        $sth = $this->driver->executeQuery($query, array_values($criteria));

        return $sth->fetchColumn();
    }

    public function grabFromDatabase($table, $column, $criteria = [])
    {
        return $this->proceedSeeInDatabase($table, $column, $criteria);
    }
}
<?php
namespace Codeception\Module;

use Codeception\Module as CodeceptionModule;
use Codeception\TestCase;
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 ~2.0
 * * Amazon SQS: aws/aws-sdk-php
 * * IronMQ: iron-io/iron_mq
 *
 * ## Status
 *
 * * Maintainer: **nathanmac**
 * * Stability:
 *     - Iron.io:    **stable**
 *     - Beanstalkd: **stable**
 *     - Amazon SQS: **stable**
 * * Contact: nathan.macnamara@outlook.com
 *
 * ## 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.
 * * 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 Anazon 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\TestCase $test
     */
    public function _before(TestCase $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':
                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
namespace Codeception\Module;

use Codeception\Module as CodeceptionModule;
use Codeception\Exception\ModuleException;
use Codeception\TestCase;

/**
 * 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
 * 'post'.sq(1); // post_521fbc63021eb
 * 'post'.sq(2); // post_521fbc6302266
 * 'post'.sq(1); // post_521fbc63021eb
 * ?>
 * ```
 *
 * Example:
 *
 * ``` php
 * <?php
 * $I->wantTo('create article');
 * $I->click('New Article');
 * $I->fillField('Title', 'Article'.sq('name'));
 * $I->fillField('Body', 'Demo article with Lorem Ipsum');
 * $I->click('save');
 * $I->see('Article'.sq('name') ,'#articles')
 * ?>
 * ```
 *
 * Populating Database:
 *
 * ``` php
 * <?php
 *
 * for ($i = 0; $i<10; $i++) {
 *      $I->haveInDatabase('users', array('login' => 'user'.sq($i), 'email' => 'user'.sq($i).'@email.com');
 * }
 * ?>
 * ```
 *
 * Cest Suite tests:
 *
 * ``` php
 * <?php
 * class UserTest
 * {
 *     public function createUser(AcceptanceTester $I)
 *     {
 *         $I->createUser('email' . sqs('user') . '@mailserver.com', sqs('login'), sqs('pwd'));
 *     }
 *
 *     public function checkEmail(AcceptanceTester $I)
 *     {
 *         $I->seeInEmailTo('email' . sqs('user') . '@mailserver.com', sqs('login'));
 *     }
 *
 *     public function removeUser(AcceptanceTester $I)
 *     {
 *         $I->removeUser('email' . sqs('user') . '@mailserver.com');
 *     }
 * }
 * ?>
 * ```
 */
class Sequence extends CodeceptionModule
{
    public static $hash = [];
    public static $suiteHash = [];

    public function _after(TestCase $t)
    {
        self::$hash = [];
    }

    public function _afterSuite()
    {
        self::$suiteHash = [];
    }
}

if (!function_exists('sq') && !function_exists('sqs')) {
    require_once __DIR__ . '/../Util/sq.php';
    require_once __DIR__ . '/../Util/sqs.php';
} else {
    throw new ModuleException('Codeception\Module\Sequence', "function 'sq' and 'sqs' already defined");
}<?php
namespace Codeception\Module;

use Codeception\Exception\ModuleException as ModuleException;
use Codeception\Exception\ModuleConfigException as ModuleConfigException;
use Codeception\Lib\Driver\Facebook as FacebookDriver;
use Codeception\Lib\Interfaces\DependsOnModule;
use Codeception\Module as BaseModule;

/**
 * Provides testing for projects integrated with Facebook API.
 * Relies on Facebook's tool Test User API.
 *
 * <div class="alert alert-info">
 * To use this module with Composer you need <em>"facebook/php-sdk4": "5.*"</em> package.
 * </div>
 *
 * ## Status
 *
 * * Maintainer: **tiger-seo**
 * * Stability: **beta**
 * * Contact: tiger.seo@gmail.com
 *
 * ## Config
 *
 * * app_id *required* - Facebook application ID
 * * secret *required* - Facebook application secret
 * * test_user - Facebook test user parameters:
 *     * name - You can specify a name for the test user you create. The specified name will also be used in the email address assigned to the test user.
 *     * locale - You can specify a locale for the test user you create, the default is en_US. The list of supported locales is available at https://www.facebook.com/translations/FacebookLocales.xml
 *     * permissions - An array of permissions. Your app is granted these permissions for the new test user. The full list of permissions is available at https://developers.facebook.com/docs/authentication/permissions
 *
 * ### Config example
 *
 *     modules:
 *         enabled:
 *             - Facebook:
 *                 depends: PhpBrowser
 *                 app_id: 412345678901234
 *                 secret: ccb79c1b0fdff54e4f7c928bf233aea5
 *                 test_user:
 *                     name: FacebookGuy
 *                     locale: uk_UA
 *                     permissions: [email, publish_stream]
 *
 * ###  Test example:
 *
 * ``` php
 * <?php
 * $I = new ApiGuy($scenario);
 * $I->am('Guest');
 * $I->wantToTest('check-in to a place be published on the Facebook using API');
 * $I->haveFacebookTestUserAccount();
 * $accessToken = $I->grabFacebookTestUserAccessToken();
 * $I->haveHttpHeader('Auth', 'FacebookToken ' . $accessToken);
 * $I->amGoingTo('send request to the backend, so that it will publish on user\'s wall on Facebook');
 * $I->sendPOST('/api/v1/some-api-endpoint');
 * $I->seePostOnFacebookWithAttachedPlace('167724369950862');
 *
 * ```
 *
 * ``` php
 * <?php
 * $I = new WebGuy($scenario);
 * $I->am('Guest');
 * $I->wantToTest('log in to site using Facebook');
 * $I->haveFacebookTestUserAccount(); // create facebook test user
 * $I->haveTestUserLoggedInOnFacebook(); // so that facebook will not ask us for login and password
 * $fbUserFirstName = $I->grabFacebookTestUserFirstName();
 * $I->amOnPage('/welcome');
 * $I->see('Welcome, Guest');
 * $I->click('Login with Facebook');
 * $I->see('Welcome, ' . $fbUserFirstName);
 *
 * ```
 *
 * @since 1.6.3
 * @author tiger.seo@gmail.com
 */
class Facebook extends BaseModule implements DependsOnModule
{
    protected $requiredFields = ['app_id', 'secret'];

    /**
     * @var FacebookDriver
     */
    protected $facebook;

    /**
     * @var array
     */
    protected $testUser = [];

    /**
     * @var PhpBrowser
     */
    protected $browserModule;

    protected $dependencyMessage = <<<EOF
Example configuring PhpBrowser
--
modules
    enabled:
        - Facebook:
            depends: PhpBrowser
            app_id: 412345678901234
            secret: ccb79c1b0fdff54e4f7c928bf233aea5
            test_user:
                name: FacebookGuy
                locale: uk_UA
                permissions: [email, publish_stream]
EOF;

    public function _depends()
    {
        return ['Codeception\Module\PhpBrowser' => $this->dependencyMessage];
    }

    public function _inject(PhpBrowser $browserModule)
    {
        $this->browserModule = $browserModule;
    }

    protected function deleteTestUser()
    {
        if (array_key_exists('id', $this->testUser)) {
            // make api-call for test user deletion
            $this->facebook->deleteTestUser($this->testUser['id']);
            $this->testUser = [];
        }
    }

    public function _initialize()
    {
        if (!array_key_exists('test_user', $this->config)) {
            $this->config['test_user'] = [
                'permissions' => [],
                'name' => 'Codeception Testuser'
            ];
        } elseif (!array_key_exists('permissions', $this->config['test_user'])) {
            $this->config['test_user']['permissions'] = [];
        } elseif (!array_key_exists('name', $this->config['test_user'])) {
            $this->config['test_user']['name'] = "codeception testuser";
        }

        $this->facebook = new FacebookDriver(
            [
                'app_id' => $this->config['app_id'],
                'secret' => $this->config['secret'],
            ],
            function ($title, $message) {
                if (version_compare(PHP_VERSION, '5.4', '>=')) {
                    $this->debugSection($title, $message);
                }
            }
        );
    }

    public function _afterSuite()
    {
        $this->deleteTestUser();
    }

    /**
     * Get facebook test user be created.
     *
     * *Please, note that the test user is created only at first invoke, unless $renew arguments is true.*
     *
     * @param bool $renew true if the test user should be recreated
     */
    public function haveFacebookTestUserAccount($renew = false)
    {
        if ($renew) {
            $this->deleteTestUser();
        }

        // make api-call for test user creation only if it's not yet created
        if (!array_key_exists('id', $this->testUser)) {
            $this->testUser = $this->facebook->createTestUser(
                $this->config['test_user']['name'],
                $this->config['test_user']['permissions']
            );
        }
    }

    /**
     * Get facebook test user be logged in on facebook.
     * This is done by going to facebook.com
     *
     * @throws ModuleConfigException
     */
    public function haveTestUserLoggedInOnFacebook()
    {
        if (!array_key_exists('id', $this->testUser)) {
            throw new ModuleException(
                __CLASS__,
                'Facebook test user was not found. Did you forget to create one?'
            );
        }

        $callbackUrl = $this->browserModule->_getUrl();
        $this->browserModule->amOnUrl('https://facebook.com/login');
        $this->browserModule->submitForm('#login_form', [
            'email' => $this->grabFacebookTestUserEmail(),
            'pass' => $this->grabFacebookTestUserPassword()
        ]);
        // if login in successful we are back on login screen:
        $this->browserModule->dontSeeInCurrentUrl('/login');
        $this->browserModule->amOnUrl($callbackUrl);
    }

    /**
     * Returns the test user access token.
     *
     * @return string
     */
    public function grabFacebookTestUserAccessToken()
    {
        return $this->testUser['access_token'];
    }

    /**
     * Returns the test user id.
     *
     * @return string
     */
    public function grabFacebookTestUserId()
    {
        return $this->testUser['id'];
    }

    /**
     * Returns the test user email.
     *
     * @return string
     */
    public function grabFacebookTestUserEmail()
    {
        return $this->testUser['email'];
    }

    /**
     * Returns URL for test user auto-login.
     *
     * @return string
     */
    public function grabFacebookTestUserLoginUrl()
    {
        return $this->testUser['login_url'];
    }

    public function grabFacebookTestUserPassword()
    {
        return $this->testUser['password'];
    }

    /**
     * Returns the test user name.
     *
     * @return string
     */
    public function grabFacebookTestUserName()
    {
        if (!array_key_exists('profile', $this->testUser)) {
            $this->testUser['profile'] = $this->facebook->getTestUserInfo($this->grabFacebookTestUserAccessToken());
        }

        return $this->testUser['profile']['name'];
    }

    /**
     * Please, note that you must have publish_actions permission to be able to publish to user's feed.
     *
     * @param array $params
     */
    public function postToFacebookAsTestUser($params)
    {
        $this->facebook->sendPostToFacebook($this->grabFacebookTestUserAccessToken(), $params);
    }

    /**
     *
     * Please, note that you must have publish_actions permission to be able to publish to user's feed.
     *
     * @param string $placeId Place identifier to be verified against user published posts
     */
    public function seePostOnFacebookWithAttachedPlace($placeId)
    {
        $place = $this->facebook->getVisitedPlaceTagForTestUser($placeId, $this->grabFacebookTestUserAccessToken());
        $this->assertEquals($placeId, $place['id'], "The place was not found on facebook page");
    }

    /**
     *
     * Please, note that you must have publish_actions permission to be able to publish to user's feed.
     *
     * @param string $message published post to be verified against the actual post on facebook
     */
    public function seePostOnFacebookWithMessage($message)
    {
        $posts = $this->facebook->getLastPostsForTestUser($this->grabFacebookTestUserAccessToken());
        $facebook_post_message = '';
        $this->assertNotEquals($message, $facebook_post_message, "You can not test for an empty message post");
        if ($posts['data']) {
            foreach ($posts['data'] as $post) {
                if (array_key_exists('message', $post) && ($post['message'] == $message)) {
                    $facebook_post_message = $post['message'];
                }
            }
        }
        $this->assertEquals($message, $facebook_post_message, "The post message was not found on facebook page");
    }
}
<?php
namespace Codeception;

use Codeception\Exception\ConfigurationException;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class Codecept
{
    const VERSION = "2.1.8";

    /**
     * @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 array
     */
    protected $options = [
        'silent'        => false,
        'debug'         => false,
        'steps'         => false,
        'html'          => false,
        'xml'           => false,
        'json'          => false,
        'tap'           => false,
        'report'        => false,
        'colors'        => false,
        'coverage'      => false,
        'coverage-xml'  => false,
        'coverage-html' => false,
        'coverage-text' => false,
        'groups'        => null,
        'excludeGroups' => null,
        'filter'        => null,
        'env'           => null,
        'fail-fast'     => false,
        'verbosity'     => 1,
        'interactive'   => true,
        'no-rebuild'    => false
    ];

    protected $config = [];

    /**
     * @var array
     */
    protected $extensions = [];

    public function __construct($options = [])
    {
        $this->result = new \PHPUnit_Framework_TestResult;
        $this->dispatcher = new EventDispatcher();

        $baseOptions = $this->mergeOptions($options);

        $this->loadExtensions($baseOptions);

        $this->config = Configuration::config();

        $this->options = $this->mergeOptions($options);

        $this->registerSubscribers();
        $this->registerPHPUnitListeners();

        $printer = new PHPUnit\ResultPrinter\UI($this->dispatcher, $this->options);
        $this->runner = new PHPUnit\Runner();
        $this->runner->setPrinter($printer);
    }

    /**
     * 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 loadExtensions($options)
    {
        $config = Configuration::config();
        foreach ($config['extensions']['enabled'] as $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 = isset($config['extensions']['config'][$extensionClass])
                ? $config['extensions']['config'][$extensionClass]
                : [];

            $extension = new $extensionClass($extensionConfig, $options);
            if (!$extension instanceof EventSubscriberInterface) {
                throw new ConfigurationException(
                    "Class $extensionClass is not an EventListener. Please create it as Extension or Group class."
                );
            }
            $this->extensions[] = $extension;
        }
    }

    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\Bootstrap());
        $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());
        }

        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));
        }

        // extensions
        foreach ($this->extensions as $subscriber) {
            $this->dispatcher->addSubscriber($subscriber);
        }
    }

    public function run($suite, $test = null)
    {
        ini_set('memory_limit', isset($this->config['settings']['memory_limit']) ? $this->config['settings']['memory_limit'] : '1024M');
        $settings = Configuration::suiteSettings($suite, Configuration::config());

        $selectedEnvironments = $this->options['env'];
        $environments = Configuration::suiteEnvironments($suite);

        if (!$selectedEnvironments or empty($environments)) {
            $this->runSuite($settings, $suite, $test);
            return;
        }

        foreach (array_unique($selectedEnvironments) as $envList) {
            $envArray = explode(',', $envList);
            $config = [];
            foreach ($envArray as $env) {
                if (isset($environments[$env])) {
                    $currentEnvironment = isset($config['current_environment']) ? [$config['current_environment']] : [];
                    $config = Configuration::mergeConfigs($config, $environments[$env]);
                    $currentEnvironment[] = $config['current_environment'];
                    $config['current_environment'] = implode(',', $currentEnvironment);
                }
            }
            if (empty($config)) {
                continue;
            }
            $suiteToRun = $suite;
            if (!empty($envList)) {
                $suiteToRun .= ' (' . implode(', ', $envArray) . ')';
            }
            $this->runSuite($config, $suiteToRun, $test);
        }
    }

    public function runSuite($settings, $suite, $test = null)
    {
        $suiteManager = new SuiteManager($this->dispatcher, $suite, $settings);
        $suiteManager->initialize();
        $suiteManager->loadTests($test);
        $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->dispatcher->dispatch(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;
    }
}
<?php
namespace Codeception\Extension;

use Codeception\Event\TestEvent;
use Codeception\Events;
use Codeception\Extension;

/**
 * This extension demonstrates how you can implement console output of your own.
 * Recommended to be used for development purposes only.
 */
class SimpleOutput 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
    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($e->getTest()->toString());
        $this->writeln(' (' . $time . 's)');
    }
}
<?php
namespace Codeception\Extension;

use Codeception\Event\PrintResultEvent;
use Codeception\Events;
use Codeception\Extension;
use Codeception\TestCase;

/**
 * Saves failed tests into tests/log/failed in order to rerun failed tests.
 *
 * To rerun failed tests just run the `failed` group:
 *
 * ```
 * php codecept run -g failed
 * ```
 *
 * 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
{
    static $events = [
        Events::RESULT_PRINT_AFTER => 'saveFailed'
    ];

    protected $config = ['file' => 'failed'];

    public function _initialize()
    {
        $logPath = str_replace($this->getRootDir(), '', $this->getLogDir()); // get local path to logs
        $this->_reconfigure(['groups' => ['failed' => $logPath . $this->config['file']]]);
    }

    public function saveFailed(PrintResultEvent $e)
    {
        $file = $this->getLogDir() . $this->config['file'];
        $result = $e->getResult();
        if ($result->wasSuccessful()) {
            if (is_file($file)) {
                unlink($file);
            }
            return;
        }
        $output = [];
        foreach ($result->failures() as $fail) {
            $output[] = $this->localizePath(TestCase::getTestFullName($fail->failedTest()));
        }
        foreach ($result->errors() as $fail) {
            $output[] = $this->localizePath(TestCase::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\Extension;
use Monolog\Handler\RotatingFileHandler;

/**
 * Log suites/tests/steps using Monolog library.
 * Monolog should be installed additionally by Composer.
 *
 * ```
 * composer require monolog/monolog
 * ```
 *
 * Steps are logged into `tests/_output/codeception.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
{
    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 $logger;

    protected $path;

    protected $config = ['max_files' => 3];

    public function __construct()
    {
        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']);
        $this->logger = new \Monolog\Logger('Codeception');
        $this->logger->pushHandler($logHandler);
    }

    public function beforeSuite(SuiteEvent $e)
    {
        $suite = str_replace('\\', '_', $e->getSuite()->getName());
        $this->logHandler = new RotatingFileHandler($this->path . $suite, $this->config['max_files']);
    }

    public function beforeTest(TestEvent $e)
    {
        $this->logger = new \Monolog\Logger($e->getTest()->getFileName());
        $this->logger->pushHandler($this->logHandler);
        $this->logger->info('------------------------------------');
        $this->logger->info("STARTED: " . ucfirst($e->getTest()->getName(false)));
    }

    public function afterTest(TestEvent $e)
    {
    }

    public function endTest(TestEvent $e)
    {
        $this->logger->info("PASSED");
    }

    public function testFail(FailEvent $e)
    {
        $this->logger->alert($e->getFail()->getMessage());
        $this->logger->info("# FAILED #");
    }

    public function testError(FailEvent $e)
    {
        $this->logger->alert($e->getFail()->getMessage());
        $this->logger->info("# ERROR #");
    }

    public function testSkipped(FailEvent $e)
    {
        $this->logger->info("# Skipped #");
    }

    public function testIncomplete(FailEvent $e)
    {
        $this->logger->info("# Incomplete #");
    }

    public function beforeStep(StepEvent $e)
    {
        $this->logger->info((string) $e->getStep());
    }

} <?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\Comment as CommentStep;
use Codeception\TestCase;
use Codeception\Util\FileSystem;
use Codeception\Util\Template;

/**
 * Saves screenshots of each step in acceptance tests and shows them as a slideshow.
 * Activated only for suites with WebDriver module enabled.
 *
 *  ![recorder](http://codeception.com/images/recorder.gif)
 *
 * Slideshows saves are saved into `tests/_output/record_*` directories.
 * Open `index.html` to see the slideshow.
 *
 * #### Installation
 *
 * Add to list of enabled extensions
 *
 * ``` yaml
 * extensions:
 *     enabled: [Codeception\Extension\Recorder]
 * ```
 *
 * #### Configuration
 *
 * * `delete_successful` (default: true) - delete records for successfully passed tests (log only failed and errored)
 * * `module` (default: WebDriver) - which module for screenshots to use. Module should implement `Codeception\Lib\Interfaces\ScreenshotSaver` interaface. Currently only WebDriver or any its children can be used.
 *
 * ``` yaml
 * extensions:
 *     config:
 *         Codeception\Extension\Recorder:
 *             delete_successful: false
 * ```
 *
 */
class Recorder extends \Codeception\Extension
{
    protected $config = [
        'delete_successful' => true,
        'module'            => 'WebDriver',
        'template'          => null,
        'animate_slides'    => true
    ];

    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/3.3.5/css/bootstrap.min.css" rel="stylesheet">

    <style>
        html,
        body {
            height: 100%;
        }
        .carousel,
        .item,
        .active {
            height: 100%;
        }
        .navbar {
            margin-bottom: 0px !important;
        }
        .carousel-caption {
            background: rgba(0,0,0,0.8);
            padding-bottom: 50px !important;
        }
        .carousel-caption.error {
            background: #c0392b !important;
        }

        .carousel-inner {
            height: 100%;
        }

        .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;
        }
    </style>
</head>
<body>
    <!-- Navigation -->
    <nav class="navbar navbar-default" role="navigation">
        <div class="navbar-header">
            <a class="navbar-brand" href="#">{{feature}}
                <small>{{test}}</small>
            </a>
        </div>
    </nav>
    <header id="steps" class="carousel{{carousel_class}}">
        <!-- Indicators -->
        <ol class="carousel-indicators">
            {{indicators}}
        </ol>

        <!-- Wrapper for Slides -->
        <div class="carousel-inner">
            {{slides}}
        </div>

        <!-- Controls -->
        <a class="left carousel-control" href="#steps" data-slide="prev">
            <span class="icon-prev"></span>
        </a>
        <a class="right carousel-control" href="#steps" data-slide="next">
            <span class="icon-next"></span>
        </a>

    </header>

    <!-- jQuery -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/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;

    protected $indicatorTemplate = <<<EOF
<li data-target="#steps" data-slide-to="{{step}}" {{isActive}}></li>
EOF;

    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/3.3.5/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <!-- Navigation -->
    <nav class="navbar navbar-default" role="navigation">
        <div class="navbar-header">
            <a class="navbar-brand" href="#">Recorded Tests
            </a>
        </div>
    </nav>
    <div class="container">
        <h1>Record #{{seed}}</h1>
        <ul>
            {{records}}
        </ul>
    </div>

</body>

</html>

EOF;

    protected $slidesTemplate = <<<EOF
<div class="item {{isActive}}">
    <div class="fill">
        <img src="{{image}}">
    </div>
    <div class="carousel-caption {{isError}}">
        <h2>{{caption}}</h2>
        <small>scroll up and down to see the full page</small>
    </div>
</div>
EOF;

    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;
    protected $dir;
    protected $slides = [];
    protected $stepNum = 0;
    protected $seed;
    protected $recordedTests = [];

    public function beforeSuite()
    {
        $this->webDriverModule = null;
        if (!$this->hasModule($this->config['module'])) {
            return;
        }
        $this->seed = uniqid();
        $this->webDriverModule = $this->getModule($this->config['module']);
        if (!$this->webDriverModule instanceof ScreenshotSaver) {
            throw new ExtensionException($this, 'You should pass module which implements Codeception\Lib\Interfaces\ScreenshotSaver 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}_{testname}</debug> ----");
    }

    public function afterSuite()
    {
        if (!$this->webDriverModule or !$this->dir) {
            return;
        }
        $links = '';
        foreach ($this->recordedTests as $link => $url) {
            $links .= "<li><a href='$url'>$link</a></li>\n";
        }
        $indexHTML = (new Template($this->indexTemplate))
            ->place('seed', $this->seed)
            ->place('records', $links)
            ->produce();

        file_put_contents(codecept_output_dir().'records.html', $indexHTML);
        $this->writeln("⏺ Records saved into: <info>file://" . codecept_output_dir().'records.html</info>');

    }

    public function before(TestEvent $e)
    {
        if (!$this->webDriverModule) {
            return;
        }
        $this->dir = null;
        $this->stepNum = 0;
        $this->slides = [];
        $testName = str_replace(['::', '\\', '/'], ['.', '', ''], TestCase::getTestSignature($e->getTest()));
        $this->dir = codecept_output_dir() . "record_{$this->seed}_$testName";
        @mkdir($this->dir);
    }

    public function cleanup(TestEvent $e)
    {
        if (!$this->webDriverModule or !$this->dir) {
            return;
        }
        if (!$this->config['delete_successful']) {
            $this->persist($e);
            return;
        }

        // deleting successfully executed tests
        FileSystem::deleteDir($this->dir);
    }

    public function persist(TestEvent $e)
    {
        if (!$this->webDriverModule or !$this->dir) {
            return;
        }
        $indicatorHtml = '';
        $slideHtml = '';
        foreach ($this->slides as $i => $step) {
            $indicatorHtml .= (new Template($this->indicatorTemplate))
                ->place('step', (int)$i)
                ->place('isActive', (int)$i ? '' : 'class="active"')
                ->produce();

            $slideHtml .= (new Template($this->slidesTemplate))
                ->place('image', $i)
                ->place('caption', $step->getHtml('#3498db'))
                ->place('isActive', (int)$i ? '' : 'active')
                ->place('isError', $step->hasFailed() ? 'error' : '')
                ->produce();
        }

        $html = (new Template($this->template))
            ->place('indicators', $indicatorHtml)
            ->place('slides', $slideHtml)
            ->place('feature', ucfirst($e->getTest()->getFeature()))
            ->place('test', TestCase::getTestSignature($e->getTest()))
            ->place('carousel_class', $this->config['animate_slides'] ? ' slide' : '')
            ->produce();

        $indexFile = $this->dir . DIRECTORY_SEPARATOR . 'index.html';
        file_put_contents($indexFile, $html);
        $testName = TestCase::getTestSignature($e->getTest()). ' - '.ucfirst($e->getTest()->getFeature());
        $this->recordedTests[$testName] = substr($indexFile, strlen(codecept_output_dir()));
    }

    public function afterStep(StepEvent $e)
    {
        if (!$this->webDriverModule or !$this->dir) {
            return;
        }
        if ($e->getStep() instanceof CommentStep) {
            return;
        }

        $filename = str_pad($this->stepNum, 3, "0", STR_PAD_LEFT) . '.png';
        $this->webDriverModule->_saveScreenshot($this->dir . DIRECTORY_SEPARATOR . $filename);
        $this->stepNum++;
        $this->slides[$filename] = $e->getStep();
    }

}<?php






















namespace Facebook;

use Facebook\HttpClients\FacebookHttpClientInterface;
use Facebook\HttpClients\FacebookCurlHttpClient;
use Facebook\HttpClients\FacebookStreamHttpClient;
use Facebook\Exceptions\FacebookSDKException;






class FacebookClient
{



const BASE_GRAPH_URL = 'https://graph.facebook.com';




const BASE_GRAPH_VIDEO_URL = 'https://graph-video.facebook.com';




const BASE_GRAPH_URL_BETA = 'https://graph.beta.facebook.com';




const BASE_GRAPH_VIDEO_URL_BETA = 'https://graph-video.beta.facebook.com';




const DEFAULT_REQUEST_TIMEOUT = 60;




const DEFAULT_FILE_UPLOAD_REQUEST_TIMEOUT = 3600;




const DEFAULT_VIDEO_UPLOAD_REQUEST_TIMEOUT = 7200;




protected $enableBetaMode = false;




protected $httpClientHandler;




public static $requestCount = 0;







public function __construct(FacebookHttpClientInterface $httpClientHandler = null, $enableBeta = false)
{
$this->httpClientHandler = $httpClientHandler ?: $this->detectHttpClientHandler();
$this->enableBetaMode = $enableBeta;
}






public function setHttpClientHandler(FacebookHttpClientInterface $httpClientHandler)
{
$this->httpClientHandler = $httpClientHandler;
}






public function getHttpClientHandler()
{
return $this->httpClientHandler;
}






public function detectHttpClientHandler()
{
return extension_loaded('curl') ? new FacebookCurlHttpClient() : new FacebookStreamHttpClient();
}






public function enableBetaMode($betaMode = true)
{
$this->enableBetaMode = $betaMode;
}








public function getBaseGraphUrl($postToVideoUrl = false)
{
if ($postToVideoUrl) {
return $this->enableBetaMode ? static::BASE_GRAPH_VIDEO_URL_BETA : static::BASE_GRAPH_VIDEO_URL;
}

return $this->enableBetaMode ? static::BASE_GRAPH_URL_BETA : static::BASE_GRAPH_URL;
}








public function prepareRequestMessage(FacebookRequest $request)
{
$postToVideoUrl = $request->containsVideoUploads();
$url = $this->getBaseGraphUrl($postToVideoUrl) . $request->getUrl();


 if ($request->containsFileUploads()) {
$requestBody = $request->getMultipartBody();
$request->setHeaders([
'Content-Type' => 'multipart/form-data; boundary=' . $requestBody->getBoundary(),
]);
} else {
$requestBody = $request->getUrlEncodedBody();
$request->setHeaders([
'Content-Type' => 'application/x-www-form-urlencoded',
]);
}

return [
$url,
$request->getMethod(),
$request->getHeaders(),
$requestBody->getBody(),
];
}










public function sendRequest(FacebookRequest $request)
{
if (get_class($request) === 'Facebook\FacebookRequest') {
$request->validateAccessToken();
}

list($url, $method, $headers, $body) = $this->prepareRequestMessage($request);


 $timeOut = static::DEFAULT_REQUEST_TIMEOUT;
if ($request->containsFileUploads()) {
$timeOut = static::DEFAULT_FILE_UPLOAD_REQUEST_TIMEOUT;
} elseif ($request->containsVideoUploads()) {
$timeOut = static::DEFAULT_VIDEO_UPLOAD_REQUEST_TIMEOUT;
}


 
 $rawResponse = $this->httpClientHandler->send($url, $method, $body, $headers, $timeOut);

static::$requestCount++;

$returnResponse = new FacebookResponse(
$request,
$rawResponse->getBody(),
$rawResponse->getHttpResponseCode(),
$rawResponse->getHeaders()
);

if ($returnResponse->isError()) {
throw $returnResponse->getThrownException();
}

return $returnResponse;
}










public function sendBatchRequest(FacebookBatchRequest $request)
{
$request->prepareRequestsForBatch();
$facebookResponse = $this->sendRequest($request);

return new FacebookBatchResponse($request, $facebookResponse);
}
}
<?php






















namespace Facebook\GraphNodes;







class GraphApplication extends GraphNode
{





public function getId()
{
return $this->getField('id');
}
}
<?php






















namespace Facebook\GraphNodes;






class GraphUser extends GraphNode
{



protected static $graphObjectMap = [
'hometown' => '\Facebook\GraphNodes\GraphPage',
'location' => '\Facebook\GraphNodes\GraphPage',
'significant_other' => '\Facebook\GraphNodes\GraphUser',
'picture' => '\Facebook\GraphNodes\GraphPicture',
];






public function getId()
{
return $this->getField('id');
}






public function getName()
{
return $this->getField('name');
}






public function getFirstName()
{
return $this->getField('first_name');
}






public function getMiddleName()
{
return $this->getField('middle_name');
}






public function getLastName()
{
return $this->getField('last_name');
}






public function getEmail()
{
return $this->getField('email');
}






public function getGender()
{
return $this->getField('gender');
}






public function getLink()
{
return $this->getField('link');
}






public function getBirthday()
{
return $this->getField('birthday');
}






public function getLocation()
{
return $this->getField('location');
}






public function getHometown()
{
return $this->getField('hometown');
}






public function getSignificantOther()
{
return $this->getField('significant_other');
}






public function getPicture()
{
return $this->getField('picture');
}
}
<?php






















namespace Facebook\GraphNodes;







class GraphAlbum extends GraphNode
{



protected static $graphObjectMap = [
'from' => '\Facebook\GraphNodes\GraphUser',
'place' => '\Facebook\GraphNodes\GraphPage',
];






public function getId()
{
return $this->getField('id');
}






public function getCanUpload()
{
return $this->getField('can_upload');
}






public function getCount()
{
return $this->getField('count');
}






public function getCoverPhoto()
{
return $this->getField('cover_photo');
}






public function getCreatedTime()
{
return $this->getField('created_time');
}






public function getUpdatedTime()
{
return $this->getField('updated_time');
}






public function getDescription()
{
return $this->getField('description');
}






public function getFrom()
{
return $this->getField('from');
}






public function getPlace()
{
return $this->getField('place');
}






public function getLink()
{
return $this->getField('link');
}






public function getLocation()
{
return $this->getField('location');
}






public function getName()
{
return $this->getField('name');
}






public function getPrivacy()
{
return $this->getField('privacy');
}








public function getType()
{
return $this->getField('type');
}
}
<?php






















namespace Facebook\GraphNodes;









class GraphList extends GraphEdge
{
}
<?php






















namespace Facebook\GraphNodes;






class GraphPage extends GraphNode
{



protected static $graphObjectMap = [
'best_page' => '\Facebook\GraphNodes\GraphPage',
'global_brand_parent_page' => '\Facebook\GraphNodes\GraphPage',
'location' => '\Facebook\GraphNodes\GraphLocation',
];






public function getId()
{
return $this->getField('id');
}






public function getCategory()
{
return $this->getField('category');
}






public function getName()
{
return $this->getField('name');
}






public function getBestPage()
{
return $this->getField('best_page');
}






public function getGlobalBrandParentPage()
{
return $this->getField('global_brand_parent_page');
}






public function getLocation()
{
return $this->getField('location');
}








public function getAccessToken()
{
return $this->getField('access_token');
}








public function getPerms()
{
return $this->getField('perms');
}
}
<?php






















namespace Facebook\GraphNodes;









use ArrayAccess;
use ArrayIterator;
use Countable;
use IteratorAggregate;

class Collection implements ArrayAccess, Countable, IteratorAggregate
{





protected $items = [];






public function __construct(array $items = [])
{
$this->items = $items;
}









public function getField($name, $default = null)
{
if (isset($this->items[$name])) {
return $this->items[$name];
}

return $default;
}












public function getProperty($name, $default = null)
{
return $this->getField($name, $default);
}






public function getFieldNames()
{
return array_keys($this->items);
}









public function getPropertyNames()
{
return $this->getFieldNames();
}






public function all()
{
return $this->items;
}






public function asArray()
{
return array_map(function ($value) {
return $value instanceof Collection ? $value->asArray() : $value;
}, $this->items);
}








public function map(\Closure $callback)
{
return new static(array_map($callback, $this->items, array_keys($this->items)));
}








public function asJson($options = 0)
{
return json_encode($this->asArray(), $options);
}






public function count()
{
return count($this->items);
}






public function getIterator()
{
return new ArrayIterator($this->items);
}








public function offsetExists($key)
{
return array_key_exists($key, $this->items);
}








public function offsetGet($key)
{
return $this->items[$key];
}









public function offsetSet($key, $value)
{
if (is_null($key)) {
$this->items[] = $value;
} else {
$this->items[$key] = $value;
}
}








public function offsetUnset($key)
{
unset($this->items[$key]);
}






public function __toString()
{
return $this->asJson();
}
}
<?php






















namespace Facebook\GraphNodes;

use Facebook\FacebookResponse;
use Facebook\Exceptions\FacebookSDKException;















class GraphNodeFactory
{



const BASE_GRAPH_NODE_CLASS = '\Facebook\GraphNodes\GraphNode';




const BASE_GRAPH_EDGE_CLASS = '\Facebook\GraphNodes\GraphEdge';




const BASE_GRAPH_OBJECT_PREFIX = '\Facebook\GraphNodes\\';




protected $response;




protected $decodedBody;






public function __construct(FacebookResponse $response)
{
$this->response = $response;
$this->decodedBody = $response->getDecodedBody();
}










public function makeGraphNode($subclassName = null)
{
$this->validateResponseAsArray();
$this->validateResponseCastableAsGraphNode();

return $this->castAsGraphNodeOrGraphEdge($this->decodedBody, $subclassName);
}








public function makeGraphAchievement()
{
return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphAchievement');
}








public function makeGraphAlbum()
{
return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphAlbum');
}








public function makeGraphPage()
{
return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphPage');
}








public function makeGraphSessionInfo()
{
return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphSessionInfo');
}








public function makeGraphUser()
{
return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphUser');
}








public function makeGraphEvent()
{
return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphEvent');
}








public function makeGraphGroup()
{
return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphGroup');
}











public function makeGraphEdge($subclassName = null, $auto_prefix = true)
{
$this->validateResponseAsArray();
$this->validateResponseCastableAsGraphEdge();

if ($subclassName && $auto_prefix) {
$subclassName = static::BASE_GRAPH_OBJECT_PREFIX . $subclassName;
}

return $this->castAsGraphNodeOrGraphEdge($this->decodedBody, $subclassName);
}






public function validateResponseAsArray()
{
if (!is_array($this->decodedBody)) {
throw new FacebookSDKException('Unable to get response from Graph as array.', 620);
}
}






public function validateResponseCastableAsGraphNode()
{
if (isset($this->decodedBody['data']) && static::isCastableAsGraphEdge($this->decodedBody['data'])) {
throw new FacebookSDKException(
'Unable to convert response from Graph to a GraphNode because the response looks like a GraphEdge. Try using GraphNodeFactory::makeGraphEdge() instead.',
620
);
}
}






public function validateResponseCastableAsGraphEdge()
{
if (!(isset($this->decodedBody['data']) && static::isCastableAsGraphEdge($this->decodedBody['data']))) {
throw new FacebookSDKException(
'Unable to convert response from Graph to a GraphEdge because the response does not look like a GraphEdge. Try using GraphNodeFactory::makeGraphNode() instead.',
620
);
}
}











public function safelyMakeGraphNode(array $data, $subclassName = null)
{
$subclassName = $subclassName ?: static::BASE_GRAPH_NODE_CLASS;
static::validateSubclass($subclassName);


 $parentNodeId = isset($data['id']) ? $data['id'] : null;

$items = [];

foreach ($data as $k => $v) {

 if (is_array($v)) {

 
 
 $graphObjectMap = $subclassName::getObjectMap();
$objectSubClass = isset($graphObjectMap[$k])
? $graphObjectMap[$k]
: null;


 $items[$k] = $this->castAsGraphNodeOrGraphEdge($v, $objectSubClass, $k, $parentNodeId);
} else {
$items[$k] = $v;
}
}

return new $subclassName($items);
}













public function castAsGraphNodeOrGraphEdge(array $data, $subclassName = null, $parentKey = null, $parentNodeId = null)
{
if (isset($data['data'])) {

 if (static::isCastableAsGraphEdge($data['data'])) {
return $this->safelyMakeGraphEdge($data, $subclassName, $parentKey, $parentNodeId);
}

 $data = $data['data'];
}


 return $this->safelyMakeGraphNode($data, $subclassName);
}













public function safelyMakeGraphEdge(array $data, $subclassName = null, $parentKey = null, $parentNodeId = null)
{
if (!isset($data['data'])) {
throw new FacebookSDKException('Cannot cast data to GraphEdge. Expected a "data" key.', 620);
}

$dataList = [];
foreach ($data['data'] as $graphNode) {
$dataList[] = $this->safelyMakeGraphNode($graphNode, $subclassName);
}

$metaData = $this->getMetaData($data);


 $parentGraphEdgeEndpoint = $parentNodeId && $parentKey ? '/' . $parentNodeId . '/' . $parentKey : null;
$className = static::BASE_GRAPH_EDGE_CLASS;

return new $className($this->response->getRequest(), $dataList, $metaData, $parentGraphEdgeEndpoint, $subclassName);
}








public function getMetaData(array $data)
{
unset($data['data']);

return $data;
}








public static function isCastableAsGraphEdge(array $data)
{
if ($data === []) {
return true;
}


 return array_keys($data) === range(0, count($data) - 1);
}








public static function validateSubclass($subclassName)
{
if ($subclassName == static::BASE_GRAPH_NODE_CLASS || is_subclass_of($subclassName, static::BASE_GRAPH_NODE_CLASS)) {
return;
}

throw new FacebookSDKException('The given subclass "' . $subclassName . '" is not valid. Cannot cast to an object that is not a GraphNode subclass.', 620);
}
}
<?php






















namespace Facebook\GraphNodes;






class GraphLocation extends GraphNode
{





public function getStreet()
{
return $this->getField('street');
}






public function getCity()
{
return $this->getField('city');
}






public function getState()
{
return $this->getField('state');
}






public function getCountry()
{
return $this->getField('country');
}






public function getZip()
{
return $this->getField('zip');
}






public function getLatitude()
{
return $this->getField('latitude');
}






public function getLongitude()
{
return $this->getField('longitude');
}
}
<?php






















namespace Facebook\GraphNodes;

use Facebook\FacebookRequest;
use Facebook\Url\FacebookUrlManipulator;
use Facebook\Exceptions\FacebookSDKException;






class GraphEdge extends Collection
{



protected $request;




protected $metaData = [];




protected $parentEdgeEndpoint;




protected $subclassName;










public function __construct(FacebookRequest $request, array $data = [], array $metaData = [], $parentEdgeEndpoint = null, $subclassName = null)
{
$this->request = $request;
$this->metaData = $metaData;
$this->parentEdgeEndpoint = $parentEdgeEndpoint;
$this->subclassName = $subclassName;

parent::__construct($data);
}






public function getParentGraphEdge()
{
return $this->parentEdgeEndpoint;
}






public function getSubClassName()
{
return $this->subclassName;
}






public function getMetaData()
{
return $this->metaData;
}






public function getNextCursor()
{
return $this->getCursor('after');
}






public function getPreviousCursor()
{
return $this->getCursor('before');
}








public function getCursor($direction)
{
if (isset($this->metaData['paging']['cursors'][$direction])) {
return $this->metaData['paging']['cursors'][$direction];
}

return null;
}










public function getPaginationUrl($direction)
{
$this->validateForPagination();


 if (!isset($this->metaData['paging'][$direction])) {
return null;
}

$pageUrl = $this->metaData['paging'][$direction];

return FacebookUrlManipulator::baseGraphUrlEndpoint($pageUrl);
}






public function validateForPagination()
{
if ($this->request->getMethod() !== 'GET') {
throw new FacebookSDKException('You can only paginate on a GET request.', 720);
}
}










public function getPaginationRequest($direction)
{
$pageUrl = $this->getPaginationUrl($direction);
if (!$pageUrl) {
return null;
}

$newRequest = clone $this->request;
$newRequest->setEndpoint($pageUrl);

return $newRequest;
}








public function getNextPageRequest()
{
return $this->getPaginationRequest('next');
}








public function getPreviousPageRequest()
{
return $this->getPaginationRequest('previous');
}








public function getTotalCount()
{
if (isset($this->metaData['summary']['total_count'])) {
return $this->metaData['summary']['total_count'];
}

return null;
}
}
<?php






















namespace Facebook\GraphNodes;






class GraphGroup extends GraphNode
{



protected static $graphObjectMap = [
'cover' => '\Facebook\GraphNodes\GraphCoverPhoto',
'venue' => '\Facebook\GraphNodes\GraphLocation',
];






public function getId()
{
return $this->getField('id');
}






public function getCover()
{
return $this->getField('cover');
}






public function getDescription()
{
return $this->getField('description');
}






public function getEmail()
{
return $this->getField('email');
}






public function getIcon()
{
return $this->getField('icon');
}






public function getLink()
{
return $this->getField('link');
}






public function getName()
{
return $this->getField('name');
}






public function getMemberRequestCount()
{
return $this->getField('member_request_count');
}






public function getOwner()
{
return $this->getField('owner');
}






public function getParent()
{
return $this->getField('parent');
}






public function getPrivacy()
{
return $this->getField('privacy');
}






public function getUpdatedTime()
{
return $this->getField('updated_time');
}






public function getVenue()
{
return $this->getField('venue');
}
}
<?php






















namespace Facebook\GraphNodes;






class GraphSessionInfo extends GraphNode
{





public function getAppId()
{
return $this->getField('app_id');
}






public function getApplication()
{
return $this->getField('application');
}






public function getExpiresAt()
{
return $this->getField('expires_at');
}






public function getIsValid()
{
return $this->getField('is_valid');
}






public function getIssuedAt()
{
return $this->getField('issued_at');
}






public function getScopes()
{
return $this->getField('scopes');
}






public function getUserId()
{
return $this->getField('user_id');
}
}
<?php






















namespace Facebook\GraphNodes;






class GraphPicture extends GraphNode
{





public function isSilhouette()
{
return $this->getField('is_silhouette');
}






public function getUrl()
{
return $this->getField('url');
}






public function getWidth()
{
return $this->getField('width');
}






public function getHeight()
{
return $this->getField('height');
}
}
<?php






















namespace Facebook\GraphNodes;

use Facebook\Exceptions\FacebookSDKException;









class GraphObjectFactory extends GraphNodeFactory
{



const BASE_GRAPH_NODE_CLASS = '\Facebook\GraphNodes\GraphObject';




const BASE_GRAPH_EDGE_CLASS = '\Facebook\GraphNodes\GraphList';










public function makeGraphObject($subclassName = null)
{
return $this->makeGraphNode($subclassName);
}








public function makeGraphEvent()
{
return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphEvent');
}











public function makeGraphList($subclassName = null, $auto_prefix = true)
{
return $this->makeGraphEdge($subclassName, $auto_prefix);
}
}
<?php






















namespace Facebook\GraphNodes;






class GraphEvent extends GraphNode
{



protected static $graphObjectMap = [
'cover' => '\Facebook\GraphNodes\GraphCoverPhoto',
'place' => '\Facebook\GraphNodes\GraphPage',
'picture' => '\Facebook\GraphNodes\GraphPicture',
'parent_group' => '\Facebook\GraphNodes\GraphGroup',
];






public function getId()
{
return $this->getField('id');
}






public function getCover()
{
return $this->getField('cover');
}






public function getDescription()
{
return $this->getField('description');
}






public function getEndTime()
{
return $this->getField('end_time');
}






public function getIsDateOnly()
{
return $this->getField('is_date_only');
}






public function getName()
{
return $this->getField('name');
}






public function getOwner()
{
return $this->getField('owner');
}






public function getParentGroup()
{
return $this->getField('parent_group');
}






public function getPlace()
{
return $this->getField('place');
}






public function getPrivacy()
{
return $this->getField('privacy');
}






public function getStartTime()
{
return $this->getField('start_time');
}






public function getTicketUri()
{
return $this->getField('ticket_uri');
}






public function getTimezone()
{
return $this->getField('timezone');
}






public function getUpdatedTime()
{
return $this->getField('updated_time');
}






public function getPicture()
{
return $this->getField('picture');
}






public function getAttendingCount()
{
return $this->getField('attending_count');
}






public function getDeclinedCount()
{
return $this->getField('declined_count');
}






public function getMaybeCount()
{
return $this->getField('maybe_count');
}






public function getNoreplyCount()
{
return $this->getField('noreply_count');
}






public function getInvitedCount()
{
return $this->getField('invited_count');
}
}
<?php






















namespace Facebook\GraphNodes;







class GraphAchievement extends GraphNode
{



protected static $graphObjectMap = [
'from' => '\Facebook\GraphNodes\GraphUser',
'application' => '\Facebook\GraphNodes\GraphApplication',
];






public function getId()
{
return $this->getField('id');
}






public function getFrom()
{
return $this->getField('from');
}






public function getPublishTime()
{
return $this->getField('publish_time');
}






public function getApplication()
{
return $this->getField('application');
}






public function getData()
{
return $this->getField('data');
}








public function getType()
{
return 'game.achievement';
}






public function isNoFeedStory()
{
return $this->getField('no_feed_story');
}
}
<?php






















namespace Facebook\GraphNodes;






class GraphCoverPhoto extends GraphNode
{





public function getId()
{
return $this->getField('id');
}






public function getSource()
{
return $this->getField('source');
}






public function getOffsetX()
{
return $this->getField('offset_x');
}






public function getOffsetY()
{
return $this->getField('offset_y');
}
}
<?php






















namespace Facebook\GraphNodes;









class GraphObject extends GraphNode
{
}
<?php






















namespace Facebook\GraphNodes;






class GraphNode extends Collection
{



protected static $graphObjectMap = [];






public function __construct(array $data = [])
{
parent::__construct($this->castItems($data));
}











public function castItems(array $data)
{
$items = [];

foreach ($data as $k => $v) {
if ($this->shouldCastAsDateTime($k)
&& (is_numeric($v)
|| $k === 'birthday'
|| $this->isIso8601DateString($v))
) {
$items[$k] = $this->castToDateTime($v);
} else {
$items[$k] = $v;
}
}

return $items;
}







public function uncastItems()
{
$items = $this->asArray();

return array_map(function ($v) {
if ($v instanceof \DateTime) {
return $v->format(\DateTime::ISO8601);
}

return $v;
}, $items);
}








public function asJson($options = 0)
{
return json_encode($this->uncastItems(), $options);
}












public function isIso8601DateString($string)
{

 
 
 
 $crazyInsaneRegexThatSomehowDetectsIso8601 = '/^([\+-]?\d{4}(?!\d{2}\b))'
. '((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?'
. '|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d'
. '|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])'
. '((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d'
. '([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/';

return preg_match($crazyInsaneRegexThatSomehowDetectsIso8601, $string) === 1;
}








public function shouldCastAsDateTime($key)
{
return in_array($key, [
'created_time',
'updated_time',
'start_time',
'end_time',
'backdated_time',
'issued_at',
'expires_at',
'birthday',
'publish_time'
], true);
}








public function castToDateTime($value)
{
if (is_int($value)) {
$dt = new \DateTime();
$dt->setTimestamp($value);
} else {
$dt = new \DateTime($value);
}

return $dt;
}






public static function getObjectMap()
{
return static::$graphObjectMap;
}
}
<?php






















namespace Facebook\Helpers;

use Facebook\FacebookApp;
use Facebook\FacebookClient;






class FacebookPageTabHelper extends FacebookCanvasHelper
{



protected $pageData;








public function __construct(FacebookApp $app, FacebookClient $client, $graphVersion = null)
{
parent::__construct($app, $client, $graphVersion);

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

$this->pageData = $this->signedRequest->get('page');
}









public function getPageData($key, $default = null)
{
if (isset($this->pageData[$key])) {
return $this->pageData[$key];
}

return $default;
}






public function isAdmin()
{
return $this->getPageData('admin') === true;
}






public function getPageId()
{
return $this->getPageData('id');
}
}
<?php






















namespace Facebook\Helpers;

use Facebook\Facebook;
use Facebook\FacebookApp;
use Facebook\FacebookClient;
use Facebook\SignedRequest;
use Facebook\Authentication\AccessToken;
use Facebook\Authentication\OAuth2Client;






abstract class FacebookSignedRequestFromInputHelper
{



protected $signedRequest;




protected $app;




protected $oAuth2Client;








public function __construct(FacebookApp $app, FacebookClient $client, $graphVersion = null)
{
$this->app = $app;
$graphVersion = $graphVersion ?: Facebook::DEFAULT_GRAPH_VERSION;
$this->oAuth2Client = new OAuth2Client($this->app, $client, $graphVersion);

$this->instantiateSignedRequest();
}






public function instantiateSignedRequest($rawSignedRequest = null)
{
$rawSignedRequest = $rawSignedRequest ?: $this->getRawSignedRequest();

if (!$rawSignedRequest) {
return;
}

$this->signedRequest = new SignedRequest($this->app, $rawSignedRequest);
}








public function getAccessToken()
{
if ($this->signedRequest && $this->signedRequest->hasOAuthData()) {
$code = $this->signedRequest->get('code');
$accessToken = $this->signedRequest->get('oauth_token');

if ($code && !$accessToken) {
return $this->oAuth2Client->getAccessTokenFromCode($code);
}

$expiresAt = $this->signedRequest->get('expires', 0);

return new AccessToken($accessToken, $expiresAt);
}

return null;
}






public function getSignedRequest()
{
return $this->signedRequest;
}






public function getUserId()
{
return $this->signedRequest ? $this->signedRequest->getUserId() : null;
}






abstract public function getRawSignedRequest();






public function getRawSignedRequestFromPost()
{
if (isset($_POST['signed_request'])) {
return $_POST['signed_request'];
}

return null;
}






public function getRawSignedRequestFromCookie()
{
if (isset($_COOKIE['fbsr_' . $this->app->getId()])) {
return $_COOKIE['fbsr_' . $this->app->getId()];
}

return null;
}
}
<?php






















namespace Facebook\Helpers;

use Facebook\Authentication\AccessToken;
use Facebook\Authentication\OAuth2Client;
use Facebook\Exceptions\FacebookSDKException;
use Facebook\PersistentData\FacebookSessionPersistentDataHandler;
use Facebook\PersistentData\PersistentDataInterface;
use Facebook\PseudoRandomString\PseudoRandomStringGeneratorFactory;
use Facebook\PseudoRandomString\PseudoRandomStringGeneratorInterface;
use Facebook\Url\FacebookUrlDetectionHandler;
use Facebook\Url\FacebookUrlManipulator;
use Facebook\Url\UrlDetectionInterface;






class FacebookRedirectLoginHelper
{



const CSRF_LENGTH = 32;




protected $oAuth2Client;




protected $urlDetectionHandler;




protected $persistentDataHandler;




protected $pseudoRandomStringGenerator;







public function __construct(OAuth2Client $oAuth2Client, PersistentDataInterface $persistentDataHandler = null, UrlDetectionInterface $urlHandler = null, PseudoRandomStringGeneratorInterface $prsg = null)
{
$this->oAuth2Client = $oAuth2Client;
$this->persistentDataHandler = $persistentDataHandler ?: new FacebookSessionPersistentDataHandler();
$this->urlDetectionHandler = $urlHandler ?: new FacebookUrlDetectionHandler();
$this->pseudoRandomStringGenerator = PseudoRandomStringGeneratorFactory::createPseudoRandomStringGenerator($prsg);
}






public function getPersistentDataHandler()
{
return $this->persistentDataHandler;
}






public function getUrlDetectionHandler()
{
return $this->urlDetectionHandler;
}






public function getPseudoRandomStringGenerator()
{
return $this->pseudoRandomStringGenerator;
}











private function makeUrl($redirectUrl, array $scope, array $params = [], $separator = '&')
{
$state = $this->pseudoRandomStringGenerator->getPseudoRandomString(static::CSRF_LENGTH);
$this->persistentDataHandler->set('state', $state);

return $this->oAuth2Client->getAuthorizationUrl($redirectUrl, $state, $scope, $params, $separator);
}










public function getLoginUrl($redirectUrl, array $scope = [], $separator = '&')
{
return $this->makeUrl($redirectUrl, $scope, [], $separator);
}












public function getLogoutUrl($accessToken, $next, $separator = '&')
{
if (!$accessToken instanceof AccessToken) {
$accessToken = new AccessToken($accessToken);
}

if ($accessToken->isAppAccessToken()) {
throw new FacebookSDKException('Cannot generate a logout URL with an app access token.', 722);
}

$params = [
'next' => $next,
'access_token' => $accessToken->getValue(),
];

return 'https://www.facebook.com/logout.php?' . http_build_query($params, null, $separator);
}










public function getReRequestUrl($redirectUrl, array $scope = [], $separator = '&')
{
$params = ['auth_type' => 'rerequest'];

return $this->makeUrl($redirectUrl, $scope, $params, $separator);
}










public function getReAuthenticationUrl($redirectUrl, array $scope = [], $separator = '&')
{
$params = ['auth_type' => 'reauthenticate'];

return $this->makeUrl($redirectUrl, $scope, $params, $separator);
}










public function getAccessToken($redirectUrl = null)
{
if (!$code = $this->getCode()) {
return null;
}

$this->validateCsrf();

$redirectUrl = $redirectUrl ?: $this->urlDetectionHandler->getCurrentUrl();

 $redirectUrl = FacebookUrlManipulator::removeParamsFromUrl($redirectUrl, ['state']);

return $this->oAuth2Client->getAccessTokenFromCode($code, $redirectUrl);
}






protected function validateCsrf()
{
$state = $this->getState();
$savedState = $this->persistentDataHandler->get('state');

if (!$state || !$savedState) {
throw new FacebookSDKException('Cross-site request forgery validation failed. Required param "state" missing.');
}

$savedLen = strlen($savedState);
$givenLen = strlen($state);

if ($savedLen !== $givenLen) {
throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
}

$result = 0;
for ($i = 0; $i < $savedLen; $i++) {
$result |= ord($state[$i]) ^ ord($savedState[$i]);
}

if ($result !== 0) {
throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
}
}






protected function getCode()
{
return $this->getInput('code');
}






protected function getState()
{
return $this->getInput('state');
}






public function getErrorCode()
{
return $this->getInput('error_code');
}






public function getError()
{
return $this->getInput('error');
}






public function getErrorReason()
{
return $this->getInput('error_reason');
}






public function getErrorDescription()
{
return $this->getInput('error_description');
}








private function getInput($key)
{
return isset($_GET[$key]) ? $_GET[$key] : null;
}
}
<?php






















namespace Facebook\Helpers;






class FacebookCanvasHelper extends FacebookSignedRequestFromInputHelper
{





public function getAppData()
{
return $this->signedRequest ? $this->signedRequest->get('app_data') : null;
}






public function getRawSignedRequest()
{
return $this->getRawSignedRequestFromPost() ?: null;
}
}
<?php






















namespace Facebook\Helpers;






class FacebookJavaScriptHelper extends FacebookSignedRequestFromInputHelper
{





public function getRawSignedRequest()
{
return $this->getRawSignedRequestFromCookie();
}
}
<?php





























if (version_compare(PHP_VERSION, '5.4.0', '<')) {
throw new Exception('The Facebook SDK requires PHP version 5.4 or higher.');
}











spl_autoload_register(function ($class) {

 $prefix = 'Facebook\\';


 $customBaseDir = '';

 if (defined('FACEBOOK_SDK_V4_SRC_DIR')) {
$customBaseDir = FACEBOOK_SDK_V4_SRC_DIR;
} elseif (defined('FACEBOOK_SDK_SRC_DIR')) {
$customBaseDir = FACEBOOK_SDK_SRC_DIR;
}

 $baseDir = $customBaseDir ?: __DIR__ . '/';


 $len = strlen($prefix);
if (strncmp($prefix, $class, $len) !== 0) {

 return;
}


 $relativeClass = substr($class, $len);


 
 
 $file = rtrim($baseDir, '/') . '/' . str_replace('\\', '/', $relativeClass) . '.php';


 if (file_exists($file)) {
require $file;
}
});
<?php






















namespace Facebook\Http;

use Facebook\FileUpload\FacebookFile;










class RequestBodyMultipart implements RequestBodyInterface
{



private $boundary;




private $params;




private $files = [];






public function __construct(array $params = [], array $files = [], $boundary = null)
{
$this->params = $params;
$this->files = $files;
$this->boundary = $boundary ?: uniqid();
}




public function getBody()
{
$body = '';


 $params = $this->getNestedParams($this->params);
foreach ($params as $k => $v) {
$body .= $this->getParamString($k, $v);
}


 foreach ($this->files as $k => $v) {
$body .= $this->getFileString($k, $v);
}


 $body .= "--{$this->boundary}--\r\n";

return $body;
}






public function getBoundary()
{
return $this->boundary;
}









private function getFileString($name, FacebookFile $file)
{
return sprintf(
"--%s\r\nContent-Disposition: form-data; name=\"%s\"; filename=\"%s\"%s\r\n\r\n%s\r\n",
$this->boundary,
$name,
$file->getFileName(),
$this->getFileHeaders($file),
$file->getContents()
);
}









private function getParamString($name, $value)
{
return sprintf(
"--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n",
$this->boundary,
$name,
$value
);
}








private function getNestedParams(array $params)
{
$query = http_build_query($params, null, '&');
$params = explode('&', $query);
$result = [];

foreach ($params as $param) {
list($key, $value) = explode('=', $param, 2);
$result[urldecode($key)] = urldecode($value);
}

return $result;
}








protected function getFileHeaders(FacebookFile $file)
{
return "\r\nContent-Type: {$file->getMimetype()}";
}
}
<?php






















namespace Facebook\Http;






class GraphRawResponse
{



protected $headers;




protected $body;




protected $httpResponseCode;








public function __construct($headers, $body, $httpStatusCode = null)
{
if (is_numeric($httpStatusCode)) {
$this->httpResponseCode = (int)$httpStatusCode;
}

if (is_array($headers)) {
$this->headers = $headers;
} else {
$this->setHeadersFromString($headers);
}

$this->body = $body;
}






public function getHeaders()
{
return $this->headers;
}






public function getBody()
{
return $this->body;
}






public function getHttpResponseCode()
{
return $this->httpResponseCode;
}






public function setHttpResponseCodeFromHeader($rawResponseHeader)
{
preg_match('|HTTP/\d\.\d\s+(\d+)\s+.*|', $rawResponseHeader, $match);
$this->httpResponseCode = (int)$match[1];
}






protected function setHeadersFromString($rawHeaders)
{

 $rawHeaders = str_replace("\r\n", "\n", $rawHeaders);


 
 $headerCollection = explode("\n\n", trim($rawHeaders));

 $rawHeader = array_pop($headerCollection);

$headerComponents = explode("\n", $rawHeader);
foreach ($headerComponents as $line) {
if (strpos($line, ': ') === false) {
$this->setHttpResponseCodeFromHeader($line);
} else {
list($key, $value) = explode(': ', $line);
$this->headers[$key] = $value;
}
}
}
}
<?php






















namespace Facebook\Http;






interface RequestBodyInterface
{





public function getBody();
}
<?php






















namespace Facebook\Http;






class RequestBodyUrlEncoded implements RequestBodyInterface
{



protected $params = [];






public function __construct(array $params)
{
$this->params = $params;
}




public function getBody()
{
return http_build_query($this->params, null, '&');
}
}
<?php






















namespace Facebook;

use Facebook\GraphNodes\GraphNodeFactory;
use Facebook\Exceptions\FacebookResponseException;
use Facebook\Exceptions\FacebookSDKException;






class FacebookResponse
{



protected $httpStatusCode;




protected $headers;




protected $body;




protected $decodedBody = [];




protected $request;




protected $thrownException;









public function __construct(FacebookRequest $request, $body = null, $httpStatusCode = null, array $headers = [])
{
$this->request = $request;
$this->body = $body;
$this->httpStatusCode = $httpStatusCode;
$this->headers = $headers;

$this->decodeBody();
}






public function getRequest()
{
return $this->request;
}






public function getApp()
{
return $this->request->getApp();
}






public function getAccessToken()
{
return $this->request->getAccessToken();
}






public function getHttpStatusCode()
{
return $this->httpStatusCode;
}






public function getHeaders()
{
return $this->headers;
}






public function getBody()
{
return $this->body;
}






public function getDecodedBody()
{
return $this->decodedBody;
}






public function getAppSecretProof()
{
return $this->request->getAppSecretProof();
}






public function getETag()
{
return isset($this->headers['ETag']) ? $this->headers['ETag'] : null;
}






public function getGraphVersion()
{
return isset($this->headers['Facebook-API-Version']) ? $this->headers['Facebook-API-Version'] : null;
}






public function isError()
{
return isset($this->decodedBody['error']);
}






public function throwException()
{
throw $this->thrownException;
}




public function makeException()
{
$this->thrownException = FacebookResponseException::create($this);
}






public function getThrownException()
{
return $this->thrownException;
}












public function decodeBody()
{
$this->decodedBody = json_decode($this->body, true);

if ($this->decodedBody === null) {
$this->decodedBody = [];
parse_str($this->body, $this->decodedBody);
} elseif (is_bool($this->decodedBody)) {

 
 
 $this->decodedBody = ['success' => $this->decodedBody];
} elseif (is_numeric($this->decodedBody)) {
$this->decodedBody = ['id' => $this->decodedBody];
}

if (!is_array($this->decodedBody)) {
$this->decodedBody = [];
}

if ($this->isError()) {
$this->makeException();
}
}













public function getGraphObject($subclassName = null)
{
return $this->getGraphNode($subclassName);
}










public function getGraphNode($subclassName = null)
{
$factory = new GraphNodeFactory($this);

return $factory->makeGraphNode($subclassName);
}








public function getGraphAlbum()
{
$factory = new GraphNodeFactory($this);

return $factory->makeGraphAlbum();
}








public function getGraphPage()
{
$factory = new GraphNodeFactory($this);

return $factory->makeGraphPage();
}








public function getGraphSessionInfo()
{
$factory = new GraphNodeFactory($this);

return $factory->makeGraphSessionInfo();
}








public function getGraphUser()
{
$factory = new GraphNodeFactory($this);

return $factory->makeGraphUser();
}








public function getGraphEvent()
{
$factory = new GraphNodeFactory($this);

return $factory->makeGraphEvent();
}








public function getGraphGroup()
{
$factory = new GraphNodeFactory($this);

return $factory->makeGraphGroup();
}














public function getGraphList($subclassName = null, $auto_prefix = true)
{
return $this->getGraphEdge($subclassName, $auto_prefix);
}











public function getGraphEdge($subclassName = null, $auto_prefix = true)
{
$factory = new GraphNodeFactory($this);

return $factory->makeGraphEdge($subclassName, $auto_prefix);
}
}
<?php






















namespace Facebook\FileUpload;






class FacebookTransferChunk
{



private $file;




private $uploadSessionId;




private $startOffset;




private $endOffset;




private $videoId;








public function __construct(FacebookFile $file, $uploadSessionId, $videoId, $startOffset, $endOffset)
{
$this->file = $file;
$this->uploadSessionId = $uploadSessionId;
$this->videoId = $videoId;
$this->startOffset = $startOffset;
$this->endOffset = $endOffset;
}






public function getFile()
{
return $this->file;
}






public function getPartialFile()
{
$maxLength = $this->endOffset - $this->startOffset;

return new FacebookFile($this->file->getFilePath(), $maxLength, $this->startOffset);
}






public function getUploadSessionId()
{
return $this->uploadSessionId;
}






public function isLastChunk()
{
return $this->startOffset === $this->endOffset;
}




public function getStartOffset()
{
return $this->startOffset;
}






public function getVideoId()
{
return $this->videoId;
}
}
<?php






















namespace Facebook\FileUpload;










class Mimetypes
{

protected static $instance;


protected $mimetypes = [
'3dml' => 'text/vnd.in3d.3dml',
'3g2' => 'video/3gpp2',
'3gp' => 'video/3gpp',
'7z' => 'application/x-7z-compressed',
'aab' => 'application/x-authorware-bin',
'aac' => 'audio/x-aac',
'aam' => 'application/x-authorware-map',
'aas' => 'application/x-authorware-seg',
'abw' => 'application/x-abiword',
'ac' => 'application/pkix-attr-cert',
'acc' => 'application/vnd.americandynamics.acc',
'ace' => 'application/x-ace-compressed',
'acu' => 'application/vnd.acucobol',
'acutc' => 'application/vnd.acucorp',
'adp' => 'audio/adpcm',
'aep' => 'application/vnd.audiograph',
'afm' => 'application/x-font-type1',
'afp' => 'application/vnd.ibm.modcap',
'ahead' => 'application/vnd.ahead.space',
'ai' => 'application/postscript',
'aif' => 'audio/x-aiff',
'aifc' => 'audio/x-aiff',
'aiff' => 'audio/x-aiff',
'air' => 'application/vnd.adobe.air-application-installer-package+zip',
'ait' => 'application/vnd.dvb.ait',
'ami' => 'application/vnd.amiga.ami',
'apk' => 'application/vnd.android.package-archive',
'application' => 'application/x-ms-application',
'apr' => 'application/vnd.lotus-approach',
'asa' => 'text/plain',
'asax' => 'application/octet-stream',
'asc' => 'application/pgp-signature',
'ascx' => 'text/plain',
'asf' => 'video/x-ms-asf',
'ashx' => 'text/plain',
'asm' => 'text/x-asm',
'asmx' => 'text/plain',
'aso' => 'application/vnd.accpac.simply.aso',
'asp' => 'text/plain',
'aspx' => 'text/plain',
'asx' => 'video/x-ms-asf',
'atc' => 'application/vnd.acucorp',
'atom' => 'application/atom+xml',
'atomcat' => 'application/atomcat+xml',
'atomsvc' => 'application/atomsvc+xml',
'atx' => 'application/vnd.antix.game-component',
'au' => 'audio/basic',
'avi' => 'video/x-msvideo',
'aw' => 'application/applixware',
'axd' => 'text/plain',
'azf' => 'application/vnd.airzip.filesecure.azf',
'azs' => 'application/vnd.airzip.filesecure.azs',
'azw' => 'application/vnd.amazon.ebook',
'bat' => 'application/x-msdownload',
'bcpio' => 'application/x-bcpio',
'bdf' => 'application/x-font-bdf',
'bdm' => 'application/vnd.syncml.dm+wbxml',
'bed' => 'application/vnd.realvnc.bed',
'bh2' => 'application/vnd.fujitsu.oasysprs',
'bin' => 'application/octet-stream',
'bmi' => 'application/vnd.bmi',
'bmp' => 'image/bmp',
'book' => 'application/vnd.framemaker',
'box' => 'application/vnd.previewsystems.box',
'boz' => 'application/x-bzip2',
'bpk' => 'application/octet-stream',
'btif' => 'image/prs.btif',
'bz' => 'application/x-bzip',
'bz2' => 'application/x-bzip2',
'c' => 'text/x-c',
'c11amc' => 'application/vnd.cluetrust.cartomobile-config',
'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg',
'c4d' => 'application/vnd.clonk.c4group',
'c4f' => 'application/vnd.clonk.c4group',
'c4g' => 'application/vnd.clonk.c4group',
'c4p' => 'application/vnd.clonk.c4group',
'c4u' => 'application/vnd.clonk.c4group',
'cab' => 'application/vnd.ms-cab-compressed',
'car' => 'application/vnd.curl.car',
'cat' => 'application/vnd.ms-pki.seccat',
'cc' => 'text/x-c',
'cct' => 'application/x-director',
'ccxml' => 'application/ccxml+xml',
'cdbcmsg' => 'application/vnd.contact.cmsg',
'cdf' => 'application/x-netcdf',
'cdkey' => 'application/vnd.mediastation.cdkey',
'cdmia' => 'application/cdmi-capability',
'cdmic' => 'application/cdmi-container',
'cdmid' => 'application/cdmi-domain',
'cdmio' => 'application/cdmi-object',
'cdmiq' => 'application/cdmi-queue',
'cdx' => 'chemical/x-cdx',
'cdxml' => 'application/vnd.chemdraw+xml',
'cdy' => 'application/vnd.cinderella',
'cer' => 'application/pkix-cert',
'cfc' => 'application/x-coldfusion',
'cfm' => 'application/x-coldfusion',
'cgm' => 'image/cgm',
'chat' => 'application/x-chat',
'chm' => 'application/vnd.ms-htmlhelp',
'chrt' => 'application/vnd.kde.kchart',
'cif' => 'chemical/x-cif',
'cii' => 'application/vnd.anser-web-certificate-issue-initiation',
'cil' => 'application/vnd.ms-artgalry',
'cla' => 'application/vnd.claymore',
'class' => 'application/java-vm',
'clkk' => 'application/vnd.crick.clicker.keyboard',
'clkp' => 'application/vnd.crick.clicker.palette',
'clkt' => 'application/vnd.crick.clicker.template',
'clkw' => 'application/vnd.crick.clicker.wordbank',
'clkx' => 'application/vnd.crick.clicker',
'clp' => 'application/x-msclip',
'cmc' => 'application/vnd.cosmocaller',
'cmdf' => 'chemical/x-cmdf',
'cml' => 'chemical/x-cml',
'cmp' => 'application/vnd.yellowriver-custom-menu',
'cmx' => 'image/x-cmx',
'cod' => 'application/vnd.rim.cod',
'com' => 'application/x-msdownload',
'conf' => 'text/plain',
'cpio' => 'application/x-cpio',
'cpp' => 'text/x-c',
'cpt' => 'application/mac-compactpro',
'crd' => 'application/x-mscardfile',
'crl' => 'application/pkix-crl',
'crt' => 'application/x-x509-ca-cert',
'cryptonote' => 'application/vnd.rig.cryptonote',
'cs' => 'text/plain',
'csh' => 'application/x-csh',
'csml' => 'chemical/x-csml',
'csp' => 'application/vnd.commonspace',
'css' => 'text/css',
'cst' => 'application/x-director',
'csv' => 'text/csv',
'cu' => 'application/cu-seeme',
'curl' => 'text/vnd.curl',
'cww' => 'application/prs.cww',
'cxt' => 'application/x-director',
'cxx' => 'text/x-c',
'dae' => 'model/vnd.collada+xml',
'daf' => 'application/vnd.mobius.daf',
'dataless' => 'application/vnd.fdsn.seed',
'davmount' => 'application/davmount+xml',
'dcr' => 'application/x-director',
'dcurl' => 'text/vnd.curl.dcurl',
'dd2' => 'application/vnd.oma.dd2+xml',
'ddd' => 'application/vnd.fujixerox.ddd',
'deb' => 'application/x-debian-package',
'def' => 'text/plain',
'deploy' => 'application/octet-stream',
'der' => 'application/x-x509-ca-cert',
'dfac' => 'application/vnd.dreamfactory',
'dic' => 'text/x-c',
'dir' => 'application/x-director',
'dis' => 'application/vnd.mobius.dis',
'dist' => 'application/octet-stream',
'distz' => 'application/octet-stream',
'djv' => 'image/vnd.djvu',
'djvu' => 'image/vnd.djvu',
'dll' => 'application/x-msdownload',
'dmg' => 'application/octet-stream',
'dms' => 'application/octet-stream',
'dna' => 'application/vnd.dna',
'doc' => 'application/msword',
'docm' => 'application/vnd.ms-word.document.macroenabled.12',
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'dot' => 'application/msword',
'dotm' => 'application/vnd.ms-word.template.macroenabled.12',
'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
'dp' => 'application/vnd.osgi.dp',
'dpg' => 'application/vnd.dpgraph',
'dra' => 'audio/vnd.dra',
'dsc' => 'text/prs.lines.tag',
'dssc' => 'application/dssc+der',
'dtb' => 'application/x-dtbook+xml',
'dtd' => 'application/xml-dtd',
'dts' => 'audio/vnd.dts',
'dtshd' => 'audio/vnd.dts.hd',
'dump' => 'application/octet-stream',
'dvi' => 'application/x-dvi',
'dwf' => 'model/vnd.dwf',
'dwg' => 'image/vnd.dwg',
'dxf' => 'image/vnd.dxf',
'dxp' => 'application/vnd.spotfire.dxp',
'dxr' => 'application/x-director',
'ecelp4800' => 'audio/vnd.nuera.ecelp4800',
'ecelp7470' => 'audio/vnd.nuera.ecelp7470',
'ecelp9600' => 'audio/vnd.nuera.ecelp9600',
'ecma' => 'application/ecmascript',
'edm' => 'application/vnd.novadigm.edm',
'edx' => 'application/vnd.novadigm.edx',
'efif' => 'application/vnd.picsel',
'ei6' => 'application/vnd.pg.osasli',
'elc' => 'application/octet-stream',
'eml' => 'message/rfc822',
'emma' => 'application/emma+xml',
'eol' => 'audio/vnd.digital-winds',
'eot' => 'application/vnd.ms-fontobject',
'eps' => 'application/postscript',
'epub' => 'application/epub+zip',
'es3' => 'application/vnd.eszigno3+xml',
'esf' => 'application/vnd.epson.esf',
'et3' => 'application/vnd.eszigno3+xml',
'etx' => 'text/x-setext',
'exe' => 'application/x-msdownload',
'exi' => 'application/exi',
'ext' => 'application/vnd.novadigm.ext',
'ez' => 'application/andrew-inset',
'ez2' => 'application/vnd.ezpix-album',
'ez3' => 'application/vnd.ezpix-package',
'f' => 'text/x-fortran',
'f4v' => 'video/x-f4v',
'f77' => 'text/x-fortran',
'f90' => 'text/x-fortran',
'fbs' => 'image/vnd.fastbidsheet',
'fcs' => 'application/vnd.isac.fcs',
'fdf' => 'application/vnd.fdf',
'fe_launch' => 'application/vnd.denovo.fcselayout-link',
'fg5' => 'application/vnd.fujitsu.oasysgp',
'fgd' => 'application/x-director',
'fh' => 'image/x-freehand',
'fh4' => 'image/x-freehand',
'fh5' => 'image/x-freehand',
'fh7' => 'image/x-freehand',
'fhc' => 'image/x-freehand',
'fig' => 'application/x-xfig',
'fli' => 'video/x-fli',
'flo' => 'application/vnd.micrografx.flo',
'flv' => 'video/x-flv',
'flw' => 'application/vnd.kde.kivio',
'flx' => 'text/vnd.fmi.flexstor',
'fly' => 'text/vnd.fly',
'fm' => 'application/vnd.framemaker',
'fnc' => 'application/vnd.frogans.fnc',
'for' => 'text/x-fortran',
'fpx' => 'image/vnd.fpx',
'frame' => 'application/vnd.framemaker',
'fsc' => 'application/vnd.fsc.weblaunch',
'fst' => 'image/vnd.fst',
'ftc' => 'application/vnd.fluxtime.clip',
'fti' => 'application/vnd.anser-web-funds-transfer-initiation',
'fvt' => 'video/vnd.fvt',
'fxp' => 'application/vnd.adobe.fxp',
'fxpl' => 'application/vnd.adobe.fxp',
'fzs' => 'application/vnd.fuzzysheet',
'g2w' => 'application/vnd.geoplan',
'g3' => 'image/g3fax',
'g3w' => 'application/vnd.geospace',
'gac' => 'application/vnd.groove-account',
'gdl' => 'model/vnd.gdl',
'geo' => 'application/vnd.dynageo',
'gex' => 'application/vnd.geometry-explorer',
'ggb' => 'application/vnd.geogebra.file',
'ggt' => 'application/vnd.geogebra.tool',
'ghf' => 'application/vnd.groove-help',
'gif' => 'image/gif',
'gim' => 'application/vnd.groove-identity-message',
'gmx' => 'application/vnd.gmx',
'gnumeric' => 'application/x-gnumeric',
'gph' => 'application/vnd.flographit',
'gqf' => 'application/vnd.grafeq',
'gqs' => 'application/vnd.grafeq',
'gram' => 'application/srgs',
'gre' => 'application/vnd.geometry-explorer',
'grv' => 'application/vnd.groove-injector',
'grxml' => 'application/srgs+xml',
'gsf' => 'application/x-font-ghostscript',
'gtar' => 'application/x-gtar',
'gtm' => 'application/vnd.groove-tool-message',
'gtw' => 'model/vnd.gtw',
'gv' => 'text/vnd.graphviz',
'gxt' => 'application/vnd.geonext',
'h' => 'text/x-c',
'h261' => 'video/h261',
'h263' => 'video/h263',
'h264' => 'video/h264',
'hal' => 'application/vnd.hal+xml',
'hbci' => 'application/vnd.hbci',
'hdf' => 'application/x-hdf',
'hh' => 'text/x-c',
'hlp' => 'application/winhlp',
'hpgl' => 'application/vnd.hp-hpgl',
'hpid' => 'application/vnd.hp-hpid',
'hps' => 'application/vnd.hp-hps',
'hqx' => 'application/mac-binhex40',
'hta' => 'application/octet-stream',
'htc' => 'text/html',
'htke' => 'application/vnd.kenameaapp',
'htm' => 'text/html',
'html' => 'text/html',
'hvd' => 'application/vnd.yamaha.hv-dic',
'hvp' => 'application/vnd.yamaha.hv-voice',
'hvs' => 'application/vnd.yamaha.hv-script',
'i2g' => 'application/vnd.intergeo',
'icc' => 'application/vnd.iccprofile',
'ice' => 'x-conference/x-cooltalk',
'icm' => 'application/vnd.iccprofile',
'ico' => 'image/x-icon',
'ics' => 'text/calendar',
'ief' => 'image/ief',
'ifb' => 'text/calendar',
'ifm' => 'application/vnd.shana.informed.formdata',
'iges' => 'model/iges',
'igl' => 'application/vnd.igloader',
'igm' => 'application/vnd.insors.igm',
'igs' => 'model/iges',
'igx' => 'application/vnd.micrografx.igx',
'iif' => 'application/vnd.shana.informed.interchange',
'imp' => 'application/vnd.accpac.simply.imp',
'ims' => 'application/vnd.ms-ims',
'in' => 'text/plain',
'ini' => 'text/plain',
'ipfix' => 'application/ipfix',
'ipk' => 'application/vnd.shana.informed.package',
'irm' => 'application/vnd.ibm.rights-management',
'irp' => 'application/vnd.irepository.package+xml',
'iso' => 'application/octet-stream',
'itp' => 'application/vnd.shana.informed.formtemplate',
'ivp' => 'application/vnd.immervision-ivp',
'ivu' => 'application/vnd.immervision-ivu',
'jad' => 'text/vnd.sun.j2me.app-descriptor',
'jam' => 'application/vnd.jam',
'jar' => 'application/java-archive',
'java' => 'text/x-java-source',
'jisp' => 'application/vnd.jisp',
'jlt' => 'application/vnd.hp-jlyt',
'jnlp' => 'application/x-java-jnlp-file',
'joda' => 'application/vnd.joost.joda-archive',
'jpe' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'jpg' => 'image/jpeg',
'jpgm' => 'video/jpm',
'jpgv' => 'video/jpeg',
'jpm' => 'video/jpm',
'js' => 'text/javascript',
'json' => 'application/json',
'kar' => 'audio/midi',
'karbon' => 'application/vnd.kde.karbon',
'kfo' => 'application/vnd.kde.kformula',
'kia' => 'application/vnd.kidspiration',
'kml' => 'application/vnd.google-earth.kml+xml',
'kmz' => 'application/vnd.google-earth.kmz',
'kne' => 'application/vnd.kinar',
'knp' => 'application/vnd.kinar',
'kon' => 'application/vnd.kde.kontour',
'kpr' => 'application/vnd.kde.kpresenter',
'kpt' => 'application/vnd.kde.kpresenter',
'ksp' => 'application/vnd.kde.kspread',
'ktr' => 'application/vnd.kahootz',
'ktx' => 'image/ktx',
'ktz' => 'application/vnd.kahootz',
'kwd' => 'application/vnd.kde.kword',
'kwt' => 'application/vnd.kde.kword',
'lasxml' => 'application/vnd.las.las+xml',
'latex' => 'application/x-latex',
'lbd' => 'application/vnd.llamagraphics.life-balance.desktop',
'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml',
'les' => 'application/vnd.hhe.lesson-player',
'lha' => 'application/octet-stream',
'link66' => 'application/vnd.route66.link66+xml',
'list' => 'text/plain',
'list3820' => 'application/vnd.ibm.modcap',
'listafp' => 'application/vnd.ibm.modcap',
'log' => 'text/plain',
'lostxml' => 'application/lost+xml',
'lrf' => 'application/octet-stream',
'lrm' => 'application/vnd.ms-lrm',
'ltf' => 'application/vnd.frogans.ltf',
'lvp' => 'audio/vnd.lucent.voice',
'lwp' => 'application/vnd.lotus-wordpro',
'lzh' => 'application/octet-stream',
'm13' => 'application/x-msmediaview',
'm14' => 'application/x-msmediaview',
'm1v' => 'video/mpeg',
'm21' => 'application/mp21',
'm2a' => 'audio/mpeg',
'm2v' => 'video/mpeg',
'm3a' => 'audio/mpeg',
'm3u' => 'audio/x-mpegurl',
'm3u8' => 'application/vnd.apple.mpegurl',
'm4a' => 'audio/mp4',
'm4u' => 'video/vnd.mpegurl',
'm4v' => 'video/mp4',
'ma' => 'application/mathematica',
'mads' => 'application/mads+xml',
'mag' => 'application/vnd.ecowin.chart',
'maker' => 'application/vnd.framemaker',
'man' => 'text/troff',
'mathml' => 'application/mathml+xml',
'mb' => 'application/mathematica',
'mbk' => 'application/vnd.mobius.mbk',
'mbox' => 'application/mbox',
'mc1' => 'application/vnd.medcalcdata',
'mcd' => 'application/vnd.mcd',
'mcurl' => 'text/vnd.curl.mcurl',
'mdb' => 'application/x-msaccess',
'mdi' => 'image/vnd.ms-modi',
'me' => 'text/troff',
'mesh' => 'model/mesh',
'meta4' => 'application/metalink4+xml',
'mets' => 'application/mets+xml',
'mfm' => 'application/vnd.mfmp',
'mgp' => 'application/vnd.osgeo.mapguide.package',
'mgz' => 'application/vnd.proteus.magazine',
'mid' => 'audio/midi',
'midi' => 'audio/midi',
'mif' => 'application/vnd.mif',
'mime' => 'message/rfc822',
'mj2' => 'video/mj2',
'mjp2' => 'video/mj2',
'mlp' => 'application/vnd.dolby.mlp',
'mmd' => 'application/vnd.chipnuts.karaoke-mmd',
'mmf' => 'application/vnd.smaf',
'mmr' => 'image/vnd.fujixerox.edmics-mmr',
'mny' => 'application/x-msmoney',
'mobi' => 'application/x-mobipocket-ebook',
'mods' => 'application/mods+xml',
'mov' => 'video/quicktime',
'movie' => 'video/x-sgi-movie',
'mp2' => 'audio/mpeg',
'mp21' => 'application/mp21',
'mp2a' => 'audio/mpeg',
'mp3' => 'audio/mpeg',
'mp4' => 'video/mp4',
'mp4a' => 'audio/mp4',
'mp4s' => 'application/mp4',
'mp4v' => 'video/mp4',
'mpc' => 'application/vnd.mophun.certificate',
'mpe' => 'video/mpeg',
'mpeg' => 'video/mpeg',
'mpg' => 'video/mpeg',
'mpg4' => 'video/mp4',
'mpga' => 'audio/mpeg',
'mpkg' => 'application/vnd.apple.installer+xml',
'mpm' => 'application/vnd.blueice.multipass',
'mpn' => 'application/vnd.mophun.application',
'mpp' => 'application/vnd.ms-project',
'mpt' => 'application/vnd.ms-project',
'mpy' => 'application/vnd.ibm.minipay',
'mqy' => 'application/vnd.mobius.mqy',
'mrc' => 'application/marc',
'mrcx' => 'application/marcxml+xml',
'ms' => 'text/troff',
'mscml' => 'application/mediaservercontrol+xml',
'mseed' => 'application/vnd.fdsn.mseed',
'mseq' => 'application/vnd.mseq',
'msf' => 'application/vnd.epson.msf',
'msh' => 'model/mesh',
'msi' => 'application/x-msdownload',
'msl' => 'application/vnd.mobius.msl',
'msty' => 'application/vnd.muvee.style',
'mts' => 'model/vnd.mts',
'mus' => 'application/vnd.musician',
'musicxml' => 'application/vnd.recordare.musicxml+xml',
'mvb' => 'application/x-msmediaview',
'mwf' => 'application/vnd.mfer',
'mxf' => 'application/mxf',
'mxl' => 'application/vnd.recordare.musicxml',
'mxml' => 'application/xv+xml',
'mxs' => 'application/vnd.triscape.mxs',
'mxu' => 'video/vnd.mpegurl',
'n-gage' => 'application/vnd.nokia.n-gage.symbian.install',
'n3' => 'text/n3',
'nb' => 'application/mathematica',
'nbp' => 'application/vnd.wolfram.player',
'nc' => 'application/x-netcdf',
'ncx' => 'application/x-dtbncx+xml',
'ngdat' => 'application/vnd.nokia.n-gage.data',
'nlu' => 'application/vnd.neurolanguage.nlu',
'nml' => 'application/vnd.enliven',
'nnd' => 'application/vnd.noblenet-directory',
'nns' => 'application/vnd.noblenet-sealer',
'nnw' => 'application/vnd.noblenet-web',
'npx' => 'image/vnd.net-fpx',
'nsf' => 'application/vnd.lotus-notes',
'oa2' => 'application/vnd.fujitsu.oasys2',
'oa3' => 'application/vnd.fujitsu.oasys3',
'oas' => 'application/vnd.fujitsu.oasys',
'obd' => 'application/x-msbinder',
'oda' => 'application/oda',
'odb' => 'application/vnd.oasis.opendocument.database',
'odc' => 'application/vnd.oasis.opendocument.chart',
'odf' => 'application/vnd.oasis.opendocument.formula',
'odft' => 'application/vnd.oasis.opendocument.formula-template',
'odg' => 'application/vnd.oasis.opendocument.graphics',
'odi' => 'application/vnd.oasis.opendocument.image',
'odm' => 'application/vnd.oasis.opendocument.text-master',
'odp' => 'application/vnd.oasis.opendocument.presentation',
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
'odt' => 'application/vnd.oasis.opendocument.text',
'oga' => 'audio/ogg',
'ogg' => 'audio/ogg',
'ogv' => 'video/ogg',
'ogx' => 'application/ogg',
'onepkg' => 'application/onenote',
'onetmp' => 'application/onenote',
'onetoc' => 'application/onenote',
'onetoc2' => 'application/onenote',
'opf' => 'application/oebps-package+xml',
'oprc' => 'application/vnd.palm',
'org' => 'application/vnd.lotus-organizer',
'osf' => 'application/vnd.yamaha.openscoreformat',
'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml',
'otc' => 'application/vnd.oasis.opendocument.chart-template',
'otf' => 'application/x-font-otf',
'otg' => 'application/vnd.oasis.opendocument.graphics-template',
'oth' => 'application/vnd.oasis.opendocument.text-web',
'oti' => 'application/vnd.oasis.opendocument.image-template',
'otp' => 'application/vnd.oasis.opendocument.presentation-template',
'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
'ott' => 'application/vnd.oasis.opendocument.text-template',
'oxt' => 'application/vnd.openofficeorg.extension',
'p' => 'text/x-pascal',
'p10' => 'application/pkcs10',
'p12' => 'application/x-pkcs12',
'p7b' => 'application/x-pkcs7-certificates',
'p7c' => 'application/pkcs7-mime',
'p7m' => 'application/pkcs7-mime',
'p7r' => 'application/x-pkcs7-certreqresp',
'p7s' => 'application/pkcs7-signature',
'p8' => 'application/pkcs8',
'pas' => 'text/x-pascal',
'paw' => 'application/vnd.pawaafile',
'pbd' => 'application/vnd.powerbuilder6',
'pbm' => 'image/x-portable-bitmap',
'pcf' => 'application/x-font-pcf',
'pcl' => 'application/vnd.hp-pcl',
'pclxl' => 'application/vnd.hp-pclxl',
'pct' => 'image/x-pict',
'pcurl' => 'application/vnd.curl.pcurl',
'pcx' => 'image/x-pcx',
'pdb' => 'application/vnd.palm',
'pdf' => 'application/pdf',
'pfa' => 'application/x-font-type1',
'pfb' => 'application/x-font-type1',
'pfm' => 'application/x-font-type1',
'pfr' => 'application/font-tdpfr',
'pfx' => 'application/x-pkcs12',
'pgm' => 'image/x-portable-graymap',
'pgn' => 'application/x-chess-pgn',
'pgp' => 'application/pgp-encrypted',
'php' => 'text/x-php',
'phps' => 'application/x-httpd-phps',
'pic' => 'image/x-pict',
'pkg' => 'application/octet-stream',
'pki' => 'application/pkixcmp',
'pkipath' => 'application/pkix-pkipath',
'plb' => 'application/vnd.3gpp.pic-bw-large',
'plc' => 'application/vnd.mobius.plc',
'plf' => 'application/vnd.pocketlearn',
'pls' => 'application/pls+xml',
'pml' => 'application/vnd.ctc-posml',
'png' => 'image/png',
'pnm' => 'image/x-portable-anymap',
'portpkg' => 'application/vnd.macports.portpkg',
'pot' => 'application/vnd.ms-powerpoint',
'potm' => 'application/vnd.ms-powerpoint.template.macroenabled.12',
'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
'ppam' => 'application/vnd.ms-powerpoint.addin.macroenabled.12',
'ppd' => 'application/vnd.cups-ppd',
'ppm' => 'image/x-portable-pixmap',
'pps' => 'application/vnd.ms-powerpoint',
'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroenabled.12',
'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
'ppt' => 'application/vnd.ms-powerpoint',
'pptm' => 'application/vnd.ms-powerpoint.presentation.macroenabled.12',
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'pqa' => 'application/vnd.palm',
'prc' => 'application/x-mobipocket-ebook',
'pre' => 'application/vnd.lotus-freelance',
'prf' => 'application/pics-rules',
'ps' => 'application/postscript',
'psb' => 'application/vnd.3gpp.pic-bw-small',
'psd' => 'image/vnd.adobe.photoshop',
'psf' => 'application/x-font-linux-psf',
'pskcxml' => 'application/pskc+xml',
'ptid' => 'application/vnd.pvi.ptid1',
'pub' => 'application/x-mspublisher',
'pvb' => 'application/vnd.3gpp.pic-bw-var',
'pwn' => 'application/vnd.3m.post-it-notes',
'pya' => 'audio/vnd.ms-playready.media.pya',
'pyv' => 'video/vnd.ms-playready.media.pyv',
'qam' => 'application/vnd.epson.quickanime',
'qbo' => 'application/vnd.intu.qbo',
'qfx' => 'application/vnd.intu.qfx',
'qps' => 'application/vnd.publishare-delta-tree',
'qt' => 'video/quicktime',
'qwd' => 'application/vnd.quark.quarkxpress',
'qwt' => 'application/vnd.quark.quarkxpress',
'qxb' => 'application/vnd.quark.quarkxpress',
'qxd' => 'application/vnd.quark.quarkxpress',
'qxl' => 'application/vnd.quark.quarkxpress',
'qxt' => 'application/vnd.quark.quarkxpress',
'ra' => 'audio/x-pn-realaudio',
'ram' => 'audio/x-pn-realaudio',
'rar' => 'application/x-rar-compressed',
'ras' => 'image/x-cmu-raster',
'rb' => 'text/plain',
'rcprofile' => 'application/vnd.ipunplugged.rcprofile',
'rdf' => 'application/rdf+xml',
'rdz' => 'application/vnd.data-vision.rdz',
'rep' => 'application/vnd.businessobjects',
'res' => 'application/x-dtbresource+xml',
'resx' => 'text/xml',
'rgb' => 'image/x-rgb',
'rif' => 'application/reginfo+xml',
'rip' => 'audio/vnd.rip',
'rl' => 'application/resource-lists+xml',
'rlc' => 'image/vnd.fujixerox.edmics-rlc',
'rld' => 'application/resource-lists-diff+xml',
'rm' => 'application/vnd.rn-realmedia',
'rmi' => 'audio/midi',
'rmp' => 'audio/x-pn-realaudio-plugin',
'rms' => 'application/vnd.jcp.javame.midlet-rms',
'rnc' => 'application/relax-ng-compact-syntax',
'roff' => 'text/troff',
'rp9' => 'application/vnd.cloanto.rp9',
'rpss' => 'application/vnd.nokia.radio-presets',
'rpst' => 'application/vnd.nokia.radio-preset',
'rq' => 'application/sparql-query',
'rs' => 'application/rls-services+xml',
'rsd' => 'application/rsd+xml',
'rss' => 'application/rss+xml',
'rtf' => 'application/rtf',
'rtx' => 'text/richtext',
's' => 'text/x-asm',
'saf' => 'application/vnd.yamaha.smaf-audio',
'sbml' => 'application/sbml+xml',
'sc' => 'application/vnd.ibm.secure-container',
'scd' => 'application/x-msschedule',
'scm' => 'application/vnd.lotus-screencam',
'scq' => 'application/scvp-cv-request',
'scs' => 'application/scvp-cv-response',
'scurl' => 'text/vnd.curl.scurl',
'sda' => 'application/vnd.stardivision.draw',
'sdc' => 'application/vnd.stardivision.calc',
'sdd' => 'application/vnd.stardivision.impress',
'sdkd' => 'application/vnd.solent.sdkm+xml',
'sdkm' => 'application/vnd.solent.sdkm+xml',
'sdp' => 'application/sdp',
'sdw' => 'application/vnd.stardivision.writer',
'see' => 'application/vnd.seemail',
'seed' => 'application/vnd.fdsn.seed',
'sema' => 'application/vnd.sema',
'semd' => 'application/vnd.semd',
'semf' => 'application/vnd.semf',
'ser' => 'application/java-serialized-object',
'setpay' => 'application/set-payment-initiation',
'setreg' => 'application/set-registration-initiation',
'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data',
'sfs' => 'application/vnd.spotfire.sfs',
'sgl' => 'application/vnd.stardivision.writer-global',
'sgm' => 'text/sgml',
'sgml' => 'text/sgml',
'sh' => 'application/x-sh',
'shar' => 'application/x-shar',
'shf' => 'application/shf+xml',
'sig' => 'application/pgp-signature',
'silo' => 'model/mesh',
'sis' => 'application/vnd.symbian.install',
'sisx' => 'application/vnd.symbian.install',
'sit' => 'application/x-stuffit',
'sitx' => 'application/x-stuffitx',
'skd' => 'application/vnd.koan',
'skm' => 'application/vnd.koan',
'skp' => 'application/vnd.koan',
'skt' => 'application/vnd.koan',
'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12',
'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
'slt' => 'application/vnd.epson.salt',
'sm' => 'application/vnd.stepmania.stepchart',
'smf' => 'application/vnd.stardivision.math',
'smi' => 'application/smil+xml',
'smil' => 'application/smil+xml',
'snd' => 'audio/basic',
'snf' => 'application/x-font-snf',
'so' => 'application/octet-stream',
'spc' => 'application/x-pkcs7-certificates',
'spf' => 'application/vnd.yamaha.smaf-phrase',
'spl' => 'application/x-futuresplash',
'spot' => 'text/vnd.in3d.spot',
'spp' => 'application/scvp-vp-response',
'spq' => 'application/scvp-vp-request',
'spx' => 'audio/ogg',
'src' => 'application/x-wais-source',
'sru' => 'application/sru+xml',
'srx' => 'application/sparql-results+xml',
'sse' => 'application/vnd.kodak-descriptor',
'ssf' => 'application/vnd.epson.ssf',
'ssml' => 'application/ssml+xml',
'st' => 'application/vnd.sailingtracker.track',
'stc' => 'application/vnd.sun.xml.calc.template',
'std' => 'application/vnd.sun.xml.draw.template',
'stf' => 'application/vnd.wt.stf',
'sti' => 'application/vnd.sun.xml.impress.template',
'stk' => 'application/hyperstudio',
'stl' => 'application/vnd.ms-pki.stl',
'str' => 'application/vnd.pg.format',
'stw' => 'application/vnd.sun.xml.writer.template',
'sub' => 'image/vnd.dvb.subtitle',
'sus' => 'application/vnd.sus-calendar',
'susp' => 'application/vnd.sus-calendar',
'sv4cpio' => 'application/x-sv4cpio',
'sv4crc' => 'application/x-sv4crc',
'svc' => 'application/vnd.dvb.service',
'svd' => 'application/vnd.svd',
'svg' => 'image/svg+xml',
'svgz' => 'image/svg+xml',
'swa' => 'application/x-director',
'swf' => 'application/x-shockwave-flash',
'swi' => 'application/vnd.aristanetworks.swi',
'sxc' => 'application/vnd.sun.xml.calc',
'sxd' => 'application/vnd.sun.xml.draw',
'sxg' => 'application/vnd.sun.xml.writer.global',
'sxi' => 'application/vnd.sun.xml.impress',
'sxm' => 'application/vnd.sun.xml.math',
'sxw' => 'application/vnd.sun.xml.writer',
't' => 'text/troff',
'tao' => 'application/vnd.tao.intent-module-archive',
'tar' => 'application/x-tar',
'tcap' => 'application/vnd.3gpp2.tcap',
'tcl' => 'application/x-tcl',
'teacher' => 'application/vnd.smart.teacher',
'tei' => 'application/tei+xml',
'teicorpus' => 'application/tei+xml',
'tex' => 'application/x-tex',
'texi' => 'application/x-texinfo',
'texinfo' => 'application/x-texinfo',
'text' => 'text/plain',
'tfi' => 'application/thraud+xml',
'tfm' => 'application/x-tex-tfm',
'thmx' => 'application/vnd.ms-officetheme',
'tif' => 'image/tiff',
'tiff' => 'image/tiff',
'tmo' => 'application/vnd.tmobile-livetv',
'torrent' => 'application/x-bittorrent',
'tpl' => 'application/vnd.groove-tool-template',
'tpt' => 'application/vnd.trid.tpt',
'tr' => 'text/troff',
'tra' => 'application/vnd.trueapp',
'trm' => 'application/x-msterminal',
'tsd' => 'application/timestamped-data',
'tsv' => 'text/tab-separated-values',
'ttc' => 'application/x-font-ttf',
'ttf' => 'application/x-font-ttf',
'ttl' => 'text/turtle',
'twd' => 'application/vnd.simtech-mindmapper',
'twds' => 'application/vnd.simtech-mindmapper',
'txd' => 'application/vnd.genomatix.tuxedo',
'txf' => 'application/vnd.mobius.txf',
'txt' => 'text/plain',
'u32' => 'application/x-authorware-bin',
'udeb' => 'application/x-debian-package',
'ufd' => 'application/vnd.ufdl',
'ufdl' => 'application/vnd.ufdl',
'umj' => 'application/vnd.umajin',
'unityweb' => 'application/vnd.unity',
'uoml' => 'application/vnd.uoml+xml',
'uri' => 'text/uri-list',
'uris' => 'text/uri-list',
'urls' => 'text/uri-list',
'ustar' => 'application/x-ustar',
'utz' => 'application/vnd.uiq.theme',
'uu' => 'text/x-uuencode',
'uva' => 'audio/vnd.dece.audio',
'uvd' => 'application/vnd.dece.data',
'uvf' => 'application/vnd.dece.data',
'uvg' => 'image/vnd.dece.graphic',
'uvh' => 'video/vnd.dece.hd',
'uvi' => 'image/vnd.dece.graphic',
'uvm' => 'video/vnd.dece.mobile',
'uvp' => 'video/vnd.dece.pd',
'uvs' => 'video/vnd.dece.sd',
'uvt' => 'application/vnd.dece.ttml+xml',
'uvu' => 'video/vnd.uvvu.mp4',
'uvv' => 'video/vnd.dece.video',
'uvva' => 'audio/vnd.dece.audio',
'uvvd' => 'application/vnd.dece.data',
'uvvf' => 'application/vnd.dece.data',
'uvvg' => 'image/vnd.dece.graphic',
'uvvh' => 'video/vnd.dece.hd',
'uvvi' => 'image/vnd.dece.graphic',
'uvvm' => 'video/vnd.dece.mobile',
'uvvp' => 'video/vnd.dece.pd',
'uvvs' => 'video/vnd.dece.sd',
'uvvt' => 'application/vnd.dece.ttml+xml',
'uvvu' => 'video/vnd.uvvu.mp4',
'uvvv' => 'video/vnd.dece.video',
'uvvx' => 'application/vnd.dece.unspecified',
'uvx' => 'application/vnd.dece.unspecified',
'vcd' => 'application/x-cdlink',
'vcf' => 'text/x-vcard',
'vcg' => 'application/vnd.groove-vcard',
'vcs' => 'text/x-vcalendar',
'vcx' => 'application/vnd.vcx',
'vis' => 'application/vnd.visionary',
'viv' => 'video/vnd.vivo',
'vor' => 'application/vnd.stardivision.writer',
'vox' => 'application/x-authorware-bin',
'vrml' => 'model/vrml',
'vsd' => 'application/vnd.visio',
'vsf' => 'application/vnd.vsf',
'vss' => 'application/vnd.visio',
'vst' => 'application/vnd.visio',
'vsw' => 'application/vnd.visio',
'vtu' => 'model/vnd.vtu',
'vxml' => 'application/voicexml+xml',
'w3d' => 'application/x-director',
'wad' => 'application/x-doom',
'wav' => 'audio/x-wav',
'wax' => 'audio/x-ms-wax',
'wbmp' => 'image/vnd.wap.wbmp',
'wbs' => 'application/vnd.criticaltools.wbs+xml',
'wbxml' => 'application/vnd.wap.wbxml',
'wcm' => 'application/vnd.ms-works',
'wdb' => 'application/vnd.ms-works',
'weba' => 'audio/webm',
'webm' => 'video/webm',
'webp' => 'image/webp',
'wg' => 'application/vnd.pmi.widget',
'wgt' => 'application/widget',
'wks' => 'application/vnd.ms-works',
'wm' => 'video/x-ms-wm',
'wma' => 'audio/x-ms-wma',
'wmd' => 'application/x-ms-wmd',
'wmf' => 'application/x-msmetafile',
'wml' => 'text/vnd.wap.wml',
'wmlc' => 'application/vnd.wap.wmlc',
'wmls' => 'text/vnd.wap.wmlscript',
'wmlsc' => 'application/vnd.wap.wmlscriptc',
'wmv' => 'video/x-ms-wmv',
'wmx' => 'video/x-ms-wmx',
'wmz' => 'application/x-ms-wmz',
'woff' => 'application/x-font-woff',
'wpd' => 'application/vnd.wordperfect',
'wpl' => 'application/vnd.ms-wpl',
'wps' => 'application/vnd.ms-works',
'wqd' => 'application/vnd.wqd',
'wri' => 'application/x-mswrite',
'wrl' => 'model/vrml',
'wsdl' => 'application/wsdl+xml',
'wspolicy' => 'application/wspolicy+xml',
'wtb' => 'application/vnd.webturbo',
'wvx' => 'video/x-ms-wvx',
'x32' => 'application/x-authorware-bin',
'x3d' => 'application/vnd.hzn-3d-crossword',
'xap' => 'application/x-silverlight-app',
'xar' => 'application/vnd.xara',
'xbap' => 'application/x-ms-xbap',
'xbd' => 'application/vnd.fujixerox.docuworks.binder',
'xbm' => 'image/x-xbitmap',
'xdf' => 'application/xcap-diff+xml',
'xdm' => 'application/vnd.syncml.dm+xml',
'xdp' => 'application/vnd.adobe.xdp+xml',
'xdssc' => 'application/dssc+xml',
'xdw' => 'application/vnd.fujixerox.docuworks',
'xenc' => 'application/xenc+xml',
'xer' => 'application/patch-ops-error+xml',
'xfdf' => 'application/vnd.adobe.xfdf',
'xfdl' => 'application/vnd.xfdl',
'xht' => 'application/xhtml+xml',
'xhtml' => 'application/xhtml+xml',
'xhvml' => 'application/xv+xml',
'xif' => 'image/vnd.xiff',
'xla' => 'application/vnd.ms-excel',
'xlam' => 'application/vnd.ms-excel.addin.macroenabled.12',
'xlc' => 'application/vnd.ms-excel',
'xlm' => 'application/vnd.ms-excel',
'xls' => 'application/vnd.ms-excel',
'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroenabled.12',
'xlsm' => 'application/vnd.ms-excel.sheet.macroenabled.12',
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'xlt' => 'application/vnd.ms-excel',
'xltm' => 'application/vnd.ms-excel.template.macroenabled.12',
'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
'xlw' => 'application/vnd.ms-excel',
'xml' => 'application/xml',
'xo' => 'application/vnd.olpc-sugar',
'xop' => 'application/xop+xml',
'xpi' => 'application/x-xpinstall',
'xpm' => 'image/x-xpixmap',
'xpr' => 'application/vnd.is-xpr',
'xps' => 'application/vnd.ms-xpsdocument',
'xpw' => 'application/vnd.intercon.formnet',
'xpx' => 'application/vnd.intercon.formnet',
'xsl' => 'application/xml',
'xslt' => 'application/xslt+xml',
'xsm' => 'application/vnd.syncml+xml',
'xspf' => 'application/xspf+xml',
'xul' => 'application/vnd.mozilla.xul+xml',
'xvm' => 'application/xv+xml',
'xvml' => 'application/xv+xml',
'xwd' => 'image/x-xwindowdump',
'xyz' => 'chemical/x-xyz',
'yaml' => 'text/yaml',
'yang' => 'application/yang',
'yin' => 'application/yin+xml',
'yml' => 'text/yaml',
'zaz' => 'application/vnd.zzazz.deck+xml',
'zip' => 'application/zip',
'zir' => 'application/vnd.zul',
'zirz' => 'application/vnd.zul',
'zmm' => 'application/vnd.handheld-entertainment+xml'
];







public static function getInstance()
{
if (!self::$instance) {
self::$instance = new self();
}

return self::$instance;
}








public function fromExtension($extension)
{
$extension = strtolower($extension);

return isset($this->mimetypes[$extension]) ? $this->mimetypes[$extension] : null;
}








public function fromFilename($filename)
{
return $this->fromExtension(pathinfo($filename, PATHINFO_EXTENSION));
}
}
<?php






















namespace Facebook\FileUpload;

use Facebook\Exceptions\FacebookSDKException;






class FacebookFile
{



protected $path;




private $maxLength;




private $offset;




protected $stream;










public function __construct($filePath, $maxLength = -1, $offset = -1)
{
$this->path = $filePath;
$this->maxLength = $maxLength;
$this->offset = $offset;
$this->open();
}




public function __destruct()
{
$this->close();
}






public function open()
{
if (!$this->isRemoteFile($this->path) && !is_readable($this->path)) {
throw new FacebookSDKException('Failed to create FacebookFile entity. Unable to read resource: ' . $this->path . '.');
}

$this->stream = fopen($this->path, 'r');

if (!$this->stream) {
throw new FacebookSDKException('Failed to create FacebookFile entity. Unable to open resource: ' . $this->path . '.');
}
}




public function close()
{
if (is_resource($this->stream)) {
fclose($this->stream);
}
}






public function getContents()
{
return stream_get_contents($this->stream, $this->maxLength, $this->offset);
}






public function getFileName()
{
return basename($this->path);
}






public function getFilePath()
{
return $this->path;
}






public function getSize()
{
return filesize($this->path);
}






public function getMimetype()
{
return Mimetypes::getInstance()->fromFilename($this->path) ?: 'text/plain';
}








protected function isRemoteFile($pathToFile)
{
return preg_match('/^(https?|ftp):\/\/.*/', $pathToFile) === 1;
}
}
<?php






















namespace Facebook\FileUpload;






class FacebookVideo extends FacebookFile
{
}
<?php






















namespace Facebook\FileUpload;

use Facebook\Authentication\AccessToken;
use Facebook\Exceptions\FacebookResponseException;
use Facebook\Exceptions\FacebookResumableUploadException;
use Facebook\Exceptions\FacebookSDKException;
use Facebook\FacebookApp;
use Facebook\FacebookClient;
use Facebook\FacebookRequest;






class FacebookResumableUploader
{



protected $app;




protected $accessToken;




protected $client;




protected $graphVersion;







public function __construct(FacebookApp $app, FacebookClient $client, $accessToken, $graphVersion)
{
$this->app = $app;
$this->client = $client;
$this->accessToken = $accessToken;
$this->graphVersion = $graphVersion;
}











public function start($endpoint, FacebookFile $file)
{
$params = [
'upload_phase' => 'start',
'file_size' => $file->getSize(),
];
$response = $this->sendUploadRequest($endpoint, $params);

return new FacebookTransferChunk($file, $response['upload_session_id'], $response['video_id'], $response['start_offset'], $response['end_offset']);
}












public function transfer($endpoint, FacebookTransferChunk $chunk, $allowToThrow = false)
{
$params = [
'upload_phase' => 'transfer',
'upload_session_id' => $chunk->getUploadSessionId(),
'start_offset' => $chunk->getStartOffset(),
'video_file_chunk' => $chunk->getPartialFile(),
];

try {
$response = $this->sendUploadRequest($endpoint, $params);
} catch (FacebookResponseException $e) {
$preException = $e->getPrevious();
if ($allowToThrow || !$preException instanceof FacebookResumableUploadException) {
throw $e;
}


 return $chunk;
}

return new FacebookTransferChunk($chunk->getFile(), $chunk->getUploadSessionId(), $chunk->getVideoId(), $response['start_offset'], $response['end_offset']);
}












public function finish($endpoint, $uploadSessionId, $metadata = [])
{
$params = array_merge($metadata, [
'upload_phase' => 'finish',
'upload_session_id' => $uploadSessionId,
]);
$response = $this->sendUploadRequest($endpoint, $params);

return $response['success'];
}









private function sendUploadRequest($endpoint, $params = [])
{
$request = new FacebookRequest($this->app, $this->accessToken, 'POST', $endpoint, $params, null, $this->graphVersion);

return $this->client->sendRequest($request)->getDecodedBody();
}
}
<?php






















namespace Facebook\Authentication;

use Facebook\Facebook;
use Facebook\FacebookApp;
use Facebook\FacebookRequest;
use Facebook\FacebookResponse;
use Facebook\FacebookClient;
use Facebook\Exceptions\FacebookResponseException;
use Facebook\Exceptions\FacebookSDKException;






class OAuth2Client
{



const BASE_AUTHORIZATION_URL = 'https://www.facebook.com';






protected $app;






protected $client;






protected $graphVersion;






protected $lastRequest;






public function __construct(FacebookApp $app, FacebookClient $client, $graphVersion = null)
{
$this->app = $app;
$this->client = $client;
$this->graphVersion = $graphVersion ?: Facebook::DEFAULT_GRAPH_VERSION;
}







public function getLastRequest()
{
return $this->lastRequest;
}








public function debugToken($accessToken)
{
$accessToken = $accessToken instanceof AccessToken ? $accessToken->getValue() : $accessToken;
$params = ['input_token' => $accessToken];

$this->lastRequest = new FacebookRequest(
$this->app,
$this->app->getAccessToken(),
'GET',
'/debug_token',
$params,
null,
$this->graphVersion
);
$response = $this->client->sendRequest($this->lastRequest);
$metadata = $response->getDecodedBody();

return new AccessTokenMetadata($metadata);
}












public function getAuthorizationUrl($redirectUrl, $state, array $scope = [], array $params = [], $separator = '&')
{
$params += [
'client_id' => $this->app->getId(),
'state' => $state,
'response_type' => 'code',
'sdk' => 'php-sdk-' . Facebook::VERSION,
'redirect_uri' => $redirectUrl,
'scope' => implode(',', $scope)
];

return static::BASE_AUTHORIZATION_URL . '/' . $this->graphVersion . '/dialog/oauth?' . http_build_query($params, null, $separator);
}











public function getAccessTokenFromCode($code, $redirectUri = '')
{
$params = [
'code' => $code,
'redirect_uri' => $redirectUri,
];

return $this->requestAnAccessToken($params);
}










public function getLongLivedAccessToken($accessToken)
{
$accessToken = $accessToken instanceof AccessToken ? $accessToken->getValue() : $accessToken;
$params = [
'grant_type' => 'fb_exchange_token',
'fb_exchange_token' => $accessToken,
];

return $this->requestAnAccessToken($params);
}











public function getCodeFromLongLivedAccessToken($accessToken, $redirectUri = '')
{
$params = [
'redirect_uri' => $redirectUri,
];

$response = $this->sendRequestWithClientParams('/oauth/client_code', $params, $accessToken);
$data = $response->getDecodedBody();

if (!isset($data['code'])) {
throw new FacebookSDKException('Code was not returned from Graph.', 401);
}

return $data['code'];
}










protected function requestAnAccessToken(array $params)
{
$response = $this->sendRequestWithClientParams('/oauth/access_token', $params);
$data = $response->getDecodedBody();

if (!isset($data['access_token'])) {
throw new FacebookSDKException('Access token was not returned from Graph.', 401);
}


 
 $expiresAt = 0;
if (isset($data['expires'])) {

 
 $expiresAt = time() + $data['expires'];
} elseif (isset($data['expires_in'])) {

 
 
 $expiresAt = time() + $data['expires_in'];
}

return new AccessToken($data['access_token'], $expiresAt);
}












protected function sendRequestWithClientParams($endpoint, array $params, $accessToken = null)
{
$params += $this->getClientParams();

$accessToken = $accessToken ?: $this->app->getAccessToken();

$this->lastRequest = new FacebookRequest(
$this->app,
$accessToken,
'GET',
$endpoint,
$params,
null,
$this->graphVersion
);

return $this->client->sendRequest($this->lastRequest);
}






protected function getClientParams()
{
return [
'client_id' => $this->app->getId(),
'client_secret' => $this->app->getSecret(),
];
}
}
<?php






















namespace Facebook\Authentication;

use Facebook\Exceptions\FacebookSDKException;









class AccessTokenMetadata
{





protected $metadata = [];






protected static $dateProperties = ['expires_at', 'issued_at'];






public function __construct(array $metadata)
{
if (!isset($metadata['data'])) {
throw new FacebookSDKException('Unexpected debug token response data.', 401);
}

$this->metadata = $metadata['data'];

$this->castTimestampsToDateTime();
}









public function getField($field, $default = null)
{
if (isset($this->metadata[$field])) {
return $this->metadata[$field];
}

return $default;
}












public function getProperty($field, $default = null)
{
return $this->getField($field, $default);
}










public function getChildProperty($parentField, $field, $default = null)
{
if (!isset($this->metadata[$parentField])) {
return $default;
}

if (!isset($this->metadata[$parentField][$field])) {
return $default;
}

return $this->metadata[$parentField][$field];
}









public function getErrorProperty($field, $default = null)
{
return $this->getChildProperty('error', $field, $default);
}









public function getMetadataProperty($field, $default = null)
{
return $this->getChildProperty('metadata', $field, $default);
}






public function getAppId()
{
return $this->getField('app_id');
}






public function getApplication()
{
return $this->getField('application');
}







public function isError()
{
return $this->getField('error') !== null;
}






public function getErrorCode()
{
return $this->getErrorProperty('code');
}






public function getErrorMessage()
{
return $this->getErrorProperty('message');
}






public function getErrorSubcode()
{
return $this->getErrorProperty('subcode');
}






public function getExpiresAt()
{
return $this->getField('expires_at');
}






public function getIsValid()
{
return $this->getField('is_valid');
}











public function getIssuedAt()
{
return $this->getField('issued_at');
}







public function getMetadata()
{
return $this->getField('metadata');
}






public function getSso()
{
return $this->getMetadataProperty('sso');
}






public function getAuthType()
{
return $this->getMetadataProperty('auth_type');
}






public function getAuthNonce()
{
return $this->getMetadataProperty('auth_nonce');
}







public function getProfileId()
{
return $this->getField('profile_id');
}







public function getScopes()
{
return $this->getField('scopes');
}






public function getUserId()
{
return $this->getField('user_id');
}









public function validateAppId($appId)
{
if ($this->getAppId() !== $appId) {
throw new FacebookSDKException('Access token metadata contains unexpected app ID.', 401);
}
}









public function validateUserId($userId)
{
if ($this->getUserId() !== $userId) {
throw new FacebookSDKException('Access token metadata contains unexpected user ID.', 401);
}
}






public function validateExpiration()
{
if (!$this->getExpiresAt() instanceof \DateTime) {
return;
}

if ($this->getExpiresAt()->getTimestamp() < time()) {
throw new FacebookSDKException('Inspection of access token metadata shows that the access token has expired.', 401);
}
}








private function convertTimestampToDateTime($timestamp)
{
$dt = new \DateTime();
$dt->setTimestamp($timestamp);

return $dt;
}




private function castTimestampsToDateTime()
{
foreach (static::$dateProperties as $key) {
if (isset($this->metadata[$key]) && $this->metadata[$key] !== 0) {
$this->metadata[$key] = $this->convertTimestampToDateTime($this->metadata[$key]);
}
}
}
}
<?php






















namespace Facebook\Authentication;






class AccessToken
{





protected $value = '';






protected $expiresAt;







public function __construct($accessToken, $expiresAt = 0)
{
$this->value = $accessToken;
if ($expiresAt) {
$this->setExpiresAtFromTimeStamp($expiresAt);
}
}








public function getAppSecretProof($appSecret)
{
return hash_hmac('sha256', $this->value, $appSecret);
}






public function getExpiresAt()
{
return $this->expiresAt;
}






public function isAppAccessToken()
{
return strpos($this->value, '|') !== false;
}






public function isLongLived()
{
if ($this->expiresAt) {
return $this->expiresAt->getTimestamp() > time() + (60 * 60 * 2);
}

if ($this->isAppAccessToken()) {
return true;
}

return false;
}






public function isExpired()
{
if ($this->getExpiresAt() instanceof \DateTime) {
return $this->getExpiresAt()->getTimestamp() < time();
}

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

return null;
}






public function getValue()
{
return $this->value;
}






public function __toString()
{
return $this->getValue();
}






protected function setExpiresAtFromTimeStamp($timeStamp)
{
$dt = new \DateTime();
$dt->setTimestamp($timeStamp);
$this->expiresAt = $dt;
}
}
<?php






















namespace Facebook;

use Facebook\Exceptions\FacebookSDKException;






class SignedRequest
{



protected $app;




protected $rawSignedRequest;




protected $payload;







public function __construct(FacebookApp $facebookApp, $rawSignedRequest = null)
{
$this->app = $facebookApp;

if (!$rawSignedRequest) {
return;
}

$this->rawSignedRequest = $rawSignedRequest;

$this->parse();
}






public function getRawSignedRequest()
{
return $this->rawSignedRequest;
}






public function getPayload()
{
return $this->payload;
}









public function get($key, $default = null)
{
if (isset($this->payload[$key])) {
return $this->payload[$key];
}

return $default;
}






public function getUserId()
{
return $this->get('user_id');
}






public function hasOAuthData()
{
return $this->get('oauth_token') || $this->get('code');
}








public function make(array $payload)
{
$payload['algorithm'] = isset($payload['algorithm']) ? $payload['algorithm'] : 'HMAC-SHA256';
$payload['issued_at'] = isset($payload['issued_at']) ? $payload['issued_at'] : time();
$encodedPayload = $this->base64UrlEncode(json_encode($payload));

$hashedSig = $this->hashSignature($encodedPayload);
$encodedSig = $this->base64UrlEncode($hashedSig);

return $encodedSig . '.' . $encodedPayload;
}





protected function parse()
{
list($encodedSig, $encodedPayload) = $this->split();


 $sig = $this->decodeSignature($encodedSig);
$hashedSig = $this->hashSignature($encodedPayload);
$this->validateSignature($hashedSig, $sig);

$this->payload = $this->decodePayload($encodedPayload);


 $this->validateAlgorithm();
}








protected function split()
{
if (strpos($this->rawSignedRequest, '.') === false) {
throw new FacebookSDKException('Malformed signed request.', 606);
}

return explode('.', $this->rawSignedRequest, 2);
}










protected function decodeSignature($encodedSig)
{
$sig = $this->base64UrlDecode($encodedSig);

if (!$sig) {
throw new FacebookSDKException('Signed request has malformed encoded signature data.', 607);
}

return $sig;
}










protected function decodePayload($encodedPayload)
{
$payload = $this->base64UrlDecode($encodedPayload);

if ($payload) {
$payload = json_decode($payload, true);
}

if (!is_array($payload)) {
throw new FacebookSDKException('Signed request has malformed encoded payload data.', 607);
}

return $payload;
}






protected function validateAlgorithm()
{
if ($this->get('algorithm') !== 'HMAC-SHA256') {
throw new FacebookSDKException('Signed request is using the wrong algorithm.', 605);
}
}










protected function hashSignature($encodedData)
{
$hashedSig = hash_hmac(
'sha256',
$encodedData,
$this->app->getSecret(),
$raw_output = true
);

if (!$hashedSig) {
throw new FacebookSDKException('Unable to hash signature from encoded payload data.', 602);
}

return $hashedSig;
}









protected function validateSignature($hashedSig, $sig)
{
if (mb_strlen($hashedSig) === mb_strlen($sig)) {
$validate = 0;
for ($i = 0; $i < mb_strlen($sig); $i++) {
$validate |= ord($hashedSig[$i]) ^ ord($sig[$i]);
}
if ($validate === 0) {
return;
}
}

throw new FacebookSDKException('Signed request has an invalid signature.', 602);
}












public function base64UrlDecode($input)
{
$urlDecodedBase64 = strtr($input, '-_', '+/');
$this->validateBase64($urlDecodedBase64);

return base64_decode($urlDecodedBase64);
}












public function base64UrlEncode($input)
{
return strtr(base64_encode($input), '+/', '-_');
}








protected function validateBase64($input)
{
if (!preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $input)) {
throw new FacebookSDKException('Signed request contains malformed base64 encoding.', 608);
}
}
}
<?php






















namespace Facebook;

use ArrayIterator;
use IteratorAggregate;
use ArrayAccess;






class FacebookBatchResponse extends FacebookResponse implements IteratorAggregate, ArrayAccess
{



protected $batchRequest;




protected $responses = [];







public function __construct(FacebookBatchRequest $batchRequest, FacebookResponse $response)
{
$this->batchRequest = $batchRequest;

$request = $response->getRequest();
$body = $response->getBody();
$httpStatusCode = $response->getHttpStatusCode();
$headers = $response->getHeaders();
parent::__construct($request, $body, $httpStatusCode, $headers);

$responses = $response->getDecodedBody();
$this->setResponses($responses);
}






public function getResponses()
{
return $this->responses;
}







public function setResponses(array $responses)
{
$this->responses = [];

foreach ($responses as $key => $graphResponse) {
$this->addResponse($key, $graphResponse);
}
}







public function addResponse($key, $response)
{
$originalRequestName = isset($this->batchRequest[$key]['name']) ? $this->batchRequest[$key]['name'] : $key;
$originalRequest = isset($this->batchRequest[$key]['request']) ? $this->batchRequest[$key]['request'] : null;

$httpResponseBody = isset($response['body']) ? $response['body'] : null;
$httpResponseCode = isset($response['code']) ? $response['code'] : null;

 $httpResponseHeaders = isset($response['headers']) ? $this->normalizeBatchHeaders($response['headers']) : [];

$this->responses[$originalRequestName] = new FacebookResponse(
$originalRequest,
$httpResponseBody,
$httpResponseCode,
$httpResponseHeaders
);
}




public function getIterator()
{
return new ArrayIterator($this->responses);
}




public function offsetSet($offset, $value)
{
$this->addResponse($offset, $value);
}




public function offsetExists($offset)
{
return isset($this->responses[$offset]);
}




public function offsetUnset($offset)
{
unset($this->responses[$offset]);
}




public function offsetGet($offset)
{
return isset($this->responses[$offset]) ? $this->responses[$offset] : null;
}









private function normalizeBatchHeaders(array $batchHeaders)
{
$headers = [];

foreach ($batchHeaders as $header) {
$headers[$header['name']] = $header['value'];
}

return $headers;
}
}
<?php






















namespace Facebook;

use Facebook\Authentication\AccessToken;
use Facebook\Url\FacebookUrlManipulator;
use Facebook\FileUpload\FacebookFile;
use Facebook\FileUpload\FacebookVideo;
use Facebook\Http\RequestBodyMultipart;
use Facebook\Http\RequestBodyUrlEncoded;
use Facebook\Exceptions\FacebookSDKException;






class FacebookRequest
{



protected $app;




protected $accessToken;




protected $method;




protected $endpoint;




protected $headers = [];




protected $params = [];




protected $files = [];




protected $eTag;




protected $graphVersion;












public function __construct(FacebookApp $app = null, $accessToken = null, $method = null, $endpoint = null, array $params = [], $eTag = null, $graphVersion = null)
{
$this->setApp($app);
$this->setAccessToken($accessToken);
$this->setMethod($method);
$this->setEndpoint($endpoint);
$this->setParams($params);
$this->setETag($eTag);
$this->graphVersion = $graphVersion ?: Facebook::DEFAULT_GRAPH_VERSION;
}








public function setAccessToken($accessToken)
{
$this->accessToken = $accessToken;
if ($accessToken instanceof AccessToken) {
$this->accessToken = $accessToken->getValue();
}

return $this;
}










public function setAccessTokenFromParams($accessToken)
{
$existingAccessToken = $this->getAccessToken();
if (!$existingAccessToken) {
$this->setAccessToken($accessToken);
} elseif ($accessToken !== $existingAccessToken) {
throw new FacebookSDKException('Access token mismatch. The access token provided in the FacebookRequest and the one provided in the URL or POST params do not match.');
}

return $this;
}






public function getAccessToken()
{
return $this->accessToken;
}






public function getAccessTokenEntity()
{
return $this->accessToken ? new AccessToken($this->accessToken) : null;
}






public function setApp(FacebookApp $app = null)
{
$this->app = $app;
}






public function getApp()
{
return $this->app;
}






public function getAppSecretProof()
{
if (!$accessTokenEntity = $this->getAccessTokenEntity()) {
return null;
}

return $accessTokenEntity->getAppSecretProof($this->app->getSecret());
}






public function validateAccessToken()
{
$accessToken = $this->getAccessToken();
if (!$accessToken) {
throw new FacebookSDKException('You must provide an access token.');
}
}








public function setMethod($method)
{
$this->method = strtoupper($method);
}






public function getMethod()
{
return $this->method;
}






public function validateMethod()
{
if (!$this->method) {
throw new FacebookSDKException('HTTP method not specified.');
}

if (!in_array($this->method, ['GET', 'POST', 'DELETE'])) {
throw new FacebookSDKException('Invalid HTTP method specified.');
}
}










public function setEndpoint($endpoint)
{

 $params = FacebookUrlManipulator::getParamsAsArray($endpoint);
if (isset($params['access_token'])) {
$this->setAccessTokenFromParams($params['access_token']);
}


 $filterParams = ['access_token', 'appsecret_proof'];
$this->endpoint = FacebookUrlManipulator::removeParamsFromUrl($endpoint, $filterParams);

return $this;
}






public function getEndpoint()
{

 return $this->endpoint;
}






public function getHeaders()
{
$headers = static::getDefaultHeaders();

if ($this->eTag) {
$headers['If-None-Match'] = $this->eTag;
}

return array_merge($this->headers, $headers);
}






public function setHeaders(array $headers)
{
$this->headers = array_merge($this->headers, $headers);
}






public function setETag($eTag)
{
$this->eTag = $eTag;
}










public function setParams(array $params = [])
{
if (isset($params['access_token'])) {
$this->setAccessTokenFromParams($params['access_token']);
}


 unset($params['access_token'], $params['appsecret_proof']);


 
 $params = $this->sanitizeFileParams($params);
$this->dangerouslySetParams($params);

return $this;
}








public function dangerouslySetParams(array $params = [])
{
$this->params = array_merge($this->params, $params);

return $this;
}








public function sanitizeFileParams(array $params)
{
foreach ($params as $key => $value) {
if ($value instanceof FacebookFile) {
$this->addFile($key, $value);
unset($params[$key]);
}
}

return $params;
}







public function addFile($key, FacebookFile $file)
{
$this->files[$key] = $file;
}




public function resetFiles()
{
$this->files = [];
}






public function getFiles()
{
return $this->files;
}






public function containsFileUploads()
{
return !empty($this->files);
}






public function containsVideoUploads()
{
foreach ($this->files as $file) {
if ($file instanceof FacebookVideo) {
return true;
}
}

return false;
}






public function getMultipartBody()
{
$params = $this->getPostParams();

return new RequestBodyMultipart($params, $this->files);
}






public function getUrlEncodedBody()
{
$params = $this->getPostParams();

return new RequestBodyUrlEncoded($params);
}






public function getParams()
{
$params = $this->params;

$accessToken = $this->getAccessToken();
if ($accessToken) {
$params['access_token'] = $accessToken;
$params['appsecret_proof'] = $this->getAppSecretProof();
}

return $params;
}






public function getPostParams()
{
if ($this->getMethod() === 'POST') {
return $this->getParams();
}

return [];
}






public function getGraphVersion()
{
return $this->graphVersion;
}






public function getUrl()
{
$this->validateMethod();

$graphVersion = FacebookUrlManipulator::forceSlashPrefix($this->graphVersion);
$endpoint = FacebookUrlManipulator::forceSlashPrefix($this->getEndpoint());

$url = $graphVersion . $endpoint;

if ($this->getMethod() !== 'POST') {
$params = $this->getParams();
$url = FacebookUrlManipulator::appendParamsToUrl($url, $params);
}

return $url;
}






public static function getDefaultHeaders()
{
return [
'User-Agent' => 'fb-php-' . Facebook::VERSION,
'Accept-Encoding' => '*',
];
}
}
<?php






















namespace Facebook\HttpClients;








class FacebookCurl
{




protected $curl;




public function init()
{
$this->curl = curl_init();
}







public function setopt($key, $value)
{
curl_setopt($this->curl, $key, $value);
}






public function setoptArray(array $options)
{
curl_setopt_array($this->curl, $options);
}






public function exec()
{
return curl_exec($this->curl);
}






public function errno()
{
return curl_errno($this->curl);
}






public function error()
{
return curl_error($this->curl);
}








public function getinfo($type)
{
return curl_getinfo($this->curl, $type);
}






public function version()
{
return curl_version();
}




public function close()
{
curl_close($this->curl);
}
}
<?php






















namespace Facebook\HttpClients;

use GuzzleHttp\Client;
use InvalidArgumentException;

class HttpClientsFactory
{
private function __construct()
{

 }











public static function createHttpClient($handler)
{
if (!$handler) {
return self::detectDefaultClient();
}

if ($handler instanceof FacebookHttpClientInterface) {
return $handler;
}

if ('stream' === $handler) {
return new FacebookStreamHttpClient();
}
if ('curl' === $handler) {
if (!extension_loaded('curl')) {
throw new Exception('The cURL extension must be loaded in order to use the "curl" handler.');
}

return new FacebookCurlHttpClient();
}

if ('guzzle' === $handler && !class_exists('GuzzleHttp\Client')) {
throw new Exception('The Guzzle HTTP client must be included in order to use the "guzzle" handler.');
}

if ($handler instanceof Client) {
return new FacebookGuzzleHttpClient($handler);
}
if ('guzzle' === $handler) {
return new FacebookGuzzleHttpClient();
}

throw new InvalidArgumentException('The http client handler must be set to "curl", "stream", "guzzle", be an instance of GuzzleHttp\Client or an instance of Facebook\HttpClients\FacebookHttpClientInterface');
}






private static function detectDefaultClient()
{
if (extension_loaded('curl')) {
return new FacebookCurlHttpClient();
}

if (class_exists('GuzzleHttp\Client')) {
return new FacebookGuzzleHttpClient();
}

return new FacebookStreamHttpClient();
}
}
<?php






















namespace Facebook\HttpClients;









class FacebookStream
{



protected $stream;




protected $responseHeaders = [];






public function streamContextCreate(array $options)
{
$this->stream = stream_context_create($options);
}






public function getResponseHeaders()
{
return $this->responseHeaders;
}








public function fileGetContents($url)
{
$rawResponse = file_get_contents($url, false, $this->stream);
$this->responseHeaders = $http_response_header ?: [];

return $rawResponse;
}
}
<?php






















namespace Facebook\HttpClients;

use Facebook\Http\GraphRawResponse;
use Facebook\Exceptions\FacebookSDKException;

class FacebookStreamHttpClient implements FacebookHttpClientInterface
{



protected $facebookStream;




public function __construct(FacebookStream $facebookStream = null)
{
$this->facebookStream = $facebookStream ?: new FacebookStream();
}




public function send($url, $method, $body, array $headers, $timeOut)
{
$options = [
'http' => [
'method' => $method,
'header' => $this->compileHeader($headers),
'content' => $body,
'timeout' => $timeOut,
'ignore_errors' => true
],
'ssl' => [
'verify_peer' => true,
'verify_peer_name' => true,
'allow_self_signed' => true, 
 'cafile' => __DIR__ . '/certs/DigiCertHighAssuranceEVRootCA.pem',
],
];

$this->facebookStream->streamContextCreate($options);
$rawBody = $this->facebookStream->fileGetContents($url);
$rawHeaders = $this->facebookStream->getResponseHeaders();

if ($rawBody === false || empty($rawHeaders)) {
throw new FacebookSDKException('Stream returned an empty response', 660);
}

$rawHeaders = implode("\r\n", $rawHeaders);

return new GraphRawResponse($rawHeaders, $rawBody);
}








public function compileHeader(array $headers)
{
$header = [];
foreach ($headers as $k => $v) {
$header[] = $k . ': ' . $v;
}

return implode("\r\n", $header);
}
}
<?php






















namespace Facebook\HttpClients;






interface FacebookHttpClientInterface
{













public function send($url, $method, $body, array $headers, $timeOut);
}
<?php






















namespace Facebook\HttpClients;

use Facebook\Http\GraphRawResponse;
use Facebook\Exceptions\FacebookSDKException;






class FacebookCurlHttpClient implements FacebookHttpClientInterface
{



protected $curlErrorMessage = '';




protected $curlErrorCode = 0;




protected $rawResponse;




protected $facebookCurl;




const CURL_PROXY_QUIRK_VER = 0x071E00;




const CONNECTION_ESTABLISHED = "HTTP/1.0 200 Connection established\r\n\r\n";




public function __construct(FacebookCurl $facebookCurl = null)
{
$this->facebookCurl = $facebookCurl ?: new FacebookCurl();
}




public function send($url, $method, $body, array $headers, $timeOut)
{
$this->openConnection($url, $method, $body, $headers, $timeOut);
$this->sendRequest();

if ($curlErrorCode = $this->facebookCurl->errno()) {
throw new FacebookSDKException($this->facebookCurl->error(), $curlErrorCode);
}


 list($rawHeaders, $rawBody) = $this->extractResponseHeadersAndBody();

$this->closeConnection();

return new GraphRawResponse($rawHeaders, $rawBody);
}










public function openConnection($url, $method, $body, array $headers, $timeOut)
{
$options = [
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => $this->compileRequestHeaders($headers),
CURLOPT_URL => $url,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => $timeOut,
CURLOPT_RETURNTRANSFER => true, 
 CURLOPT_HEADER => true, 
 CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_CAINFO => __DIR__ . '/certs/DigiCertHighAssuranceEVRootCA.pem',
];

if ($method !== "GET") {
$options[CURLOPT_POSTFIELDS] = $body;
}

$this->facebookCurl->init();
$this->facebookCurl->setoptArray($options);
}




public function closeConnection()
{
$this->facebookCurl->close();
}




public function sendRequest()
{
$this->rawResponse = $this->facebookCurl->exec();
}








public function compileRequestHeaders(array $headers)
{
$return = [];

foreach ($headers as $key => $value) {
$return[] = $key . ': ' . $value;
}

return $return;
}






public function extractResponseHeadersAndBody()
{
$headerSize = $this->getHeaderSize();

$rawHeaders = mb_substr($this->rawResponse, 0, $headerSize);
$rawBody = mb_substr($this->rawResponse, $headerSize);

return [trim($rawHeaders), trim($rawBody)];
}






private function getHeaderSize()
{
$headerSize = $this->facebookCurl->getinfo(CURLINFO_HEADER_SIZE);

 
 if ($this->needsCurlProxyFix()) {

 if (preg_match('/Content-Length: (\d+)/', $this->rawResponse, $m)) {
$headerSize = mb_strlen($this->rawResponse) - $m[1];
} elseif (stripos($this->rawResponse, self::CONNECTION_ESTABLISHED) !== false) {
$headerSize += mb_strlen(self::CONNECTION_ESTABLISHED);
}
}

return $headerSize;
}







private function needsCurlProxyFix()
{
$ver = $this->facebookCurl->version();
$version = $ver['version_number'];

return $version < self::CURL_PROXY_QUIRK_VER;
}
}
<?php






















namespace Facebook\HttpClients;

use Facebook\Http\GraphRawResponse;
use Facebook\Exceptions\FacebookSDKException;

use GuzzleHttp\Client;
use GuzzleHttp\Message\ResponseInterface;
use GuzzleHttp\Ring\Exception\RingException;
use GuzzleHttp\Exception\RequestException;

class FacebookGuzzleHttpClient implements FacebookHttpClientInterface
{



protected $guzzleClient;




public function __construct(Client $guzzleClient = null)
{
$this->guzzleClient = $guzzleClient ?: new Client();
}




public function send($url, $method, $body, array $headers, $timeOut)
{
$options = [
'headers' => $headers,
'body' => $body,
'timeout' => $timeOut,
'connect_timeout' => 10,
'verify' => __DIR__ . '/certs/DigiCertHighAssuranceEVRootCA.pem',
];
$request = $this->guzzleClient->createRequest($method, $url, $options);

try {
$rawResponse = $this->guzzleClient->send($request);
} catch (RequestException $e) {
$rawResponse = $e->getResponse();

if ($e->getPrevious() instanceof RingException || !$rawResponse instanceof ResponseInterface) {
throw new FacebookSDKException($e->getMessage(), $e->getCode());
}
}

$rawHeaders = $this->getHeadersAsString($rawResponse);
$rawBody = $rawResponse->getBody();
$httpStatusCode = $rawResponse->getStatusCode();

return new GraphRawResponse($rawHeaders, $rawBody, $httpStatusCode);
}








public function getHeadersAsString(ResponseInterface $response)
{
$headers = $response->getHeaders();
$rawHeaders = [];
foreach ($headers as $name => $values) {
$rawHeaders[] = $name . ": " . implode(", ", $values);
}

return implode("\r\n", $rawHeaders);
}
}
<?php






















namespace Facebook\Url;






class FacebookUrlManipulator
{








public static function removeParamsFromUrl($url, array $paramsToFilter)
{
$parts = parse_url($url);

$query = '';
if (isset($parts['query'])) {
$params = [];
parse_str($parts['query'], $params);


 foreach ($paramsToFilter as $paramName) {
unset($params[$paramName]);
}

if (count($params) > 0) {
$query = '?' . http_build_query($params, null, '&');
}
}

$scheme = isset($parts['scheme']) ? $parts['scheme'] . '://' : '';
$host = isset($parts['host']) ? $parts['host'] : '';
$port = isset($parts['port']) ? ':' . $parts['port'] : '';
$path = isset($parts['path']) ? $parts['path'] : '';
$fragment = isset($parts['fragment']) ? '#' . $parts['fragment'] : '';

return $scheme . $host . $port . $path . $query . $fragment;
}









public static function appendParamsToUrl($url, array $newParams = [])
{
if (empty($newParams)) {
return $url;
}

if (strpos($url, '?') === false) {
return $url . '?' . http_build_query($newParams, null, '&');
}

list($path, $query) = explode('?', $url, 2);
$existingParams = [];
parse_str($query, $existingParams);


 $newParams = array_merge($newParams, $existingParams);


 ksort($newParams);

return $path . '?' . http_build_query($newParams, null, '&');
}








public static function getParamsAsArray($url)
{
$query = parse_url($url, PHP_URL_QUERY);
if (!$query) {
return [];
}
$params = [];
parse_str($query, $params);

return $params;
}











public static function mergeUrlParams($urlToStealFrom, $urlToAddTo)
{
$newParams = static::getParamsAsArray($urlToStealFrom);

 if (!$newParams) {
return $urlToAddTo;
}

return static::appendParamsToUrl($urlToAddTo, $newParams);
}








public static function forceSlashPrefix($string)
{
if (!$string) {
return $string;
}

return strpos($string, '/') === 0 ? $string : '/' . $string;
}








public static function baseGraphUrlEndpoint($urlToTrim)
{
return '/' . preg_replace('/^https:\/\/.+\.facebook\.com(\/v.+?)?\//', '', $urlToTrim);
}
}
<?php






















namespace Facebook\Url;






interface UrlDetectionInterface
{





public function getCurrentUrl();
}
<?php






















namespace Facebook\Url;






class FacebookUrlDetectionHandler implements UrlDetectionInterface
{



public function getCurrentUrl()
{
return $this->getHttpScheme() . '://' . $this->getHostName() . $this->getServerVar('REQUEST_URI');
}






protected function getHttpScheme()
{
return $this->isBehindSsl() ? 'https' : 'http';
}






protected function isBehindSsl()
{

 $protocol = $this->getHeader('X_FORWARDED_PROTO');
if ($protocol) {
return $this->protocolWithActiveSsl($protocol);
}

$protocol = $this->getServerVar('HTTPS');
if ($protocol) {
return $this->protocolWithActiveSsl($protocol);
}

return (string)$this->getServerVar('SERVER_PORT') === '443';
}








protected function protocolWithActiveSsl($protocol)
{
$protocol = strtolower((string)$protocol);

return in_array($protocol, ['on', '1', 'https', 'ssl'], true);
}










protected function getHostName()
{

 if ($host = $this->getHeader('X_FORWARDED_HOST')) {
$elements = explode(',', $host);
$host = $elements[count($elements) - 1];
} elseif (!$host = $this->getHeader('HOST')) {
if (!$host = $this->getServerVar('SERVER_NAME')) {
$host = $this->getServerVar('SERVER_ADDR');
}
}


 
 $host = strtolower(preg_replace('/:\d+$/', '', trim($host)));


 $scheme = $this->getHttpScheme();
$port = $this->getCurrentPort();
$appendPort = ':' . $port;


 if (($scheme == 'http' && $port == '80') || ($scheme == 'https' && $port == '443')) {
$appendPort = '';
}

return $host . $appendPort;
}

protected function getCurrentPort()
{

 $port = $this->getHeader('X_FORWARDED_PORT');
if ($port) {
return (string)$port;
}

$protocol = (string)$this->getHeader('X_FORWARDED_PROTO');
if ($protocol === 'https') {
return '443';
}

return (string)$this->getServerVar('SERVER_PORT');
}








protected function getServerVar($key)
{
return isset($_SERVER[$key]) ? $_SERVER[$key] : '';
}








protected function getHeader($key)
{
return $this->getServerVar('HTTP_' . $key);
}
}
<?php






















namespace Facebook\PersistentData;

use Facebook\Exceptions\FacebookSDKException;






class FacebookSessionPersistentDataHandler implements PersistentDataInterface
{



protected $sessionPrefix = 'FBRLH_';








public function __construct($enableSessionCheck = true)
{
if ($enableSessionCheck && session_status() !== PHP_SESSION_ACTIVE) {
throw new FacebookSDKException(
'Sessions are not active. Please make sure session_start() is at the top of your script.',
720
);
}
}




public function get($key)
{
if (isset($_SESSION[$this->sessionPrefix . $key])) {
return $_SESSION[$this->sessionPrefix . $key];
}

return null;
}




public function set($key, $value)
{
$_SESSION[$this->sessionPrefix . $key] = $value;
}
}
<?php






















namespace Facebook\PersistentData;






interface PersistentDataInterface
{







public function get($key);







public function set($key, $value);
}
<?php






















namespace Facebook\PersistentData;






class FacebookMemoryPersistentDataHandler implements PersistentDataInterface
{



protected $sessionData = [];




public function get($key)
{
return isset($this->sessionData[$key]) ? $this->sessionData[$key] : null;
}




public function set($key, $value)
{
$this->sessionData[$key] = $value;
}
}
<?php






















namespace Facebook\PersistentData;

use InvalidArgumentException;

class PersistentDataFactory
{
private function __construct()
{

 }










public static function createPersistentDataHandler($handler)
{
if (!$handler) {
return session_status() === PHP_SESSION_ACTIVE
? new FacebookSessionPersistentDataHandler()
: new FacebookMemoryPersistentDataHandler();
}

if ($handler instanceof PersistentDataInterface) {
return $handler;
}

if ('session' === $handler) {
return new FacebookSessionPersistentDataHandler();
}
if ('memory' === $handler) {
return new FacebookMemoryPersistentDataHandler();
}

throw new InvalidArgumentException('The persistent data handler must be set to "session", "memory", or be an instance of Facebook\PersistentData\PersistentDataInterface');
}
}
<?php






















namespace Facebook\Exceptions;






class FacebookAuthenticationException extends FacebookSDKException
{
}
<?php






















namespace Facebook\Exceptions;






class FacebookClientException extends FacebookSDKException
{
}
<?php






















namespace Facebook\Exceptions;






class FacebookSDKException extends \Exception
{
}
<?php






















namespace Facebook\Exceptions;






class FacebookOtherException extends FacebookSDKException
{
}
<?php






















namespace Facebook\Exceptions;






class FacebookResumableUploadException extends FacebookSDKException
{
}
<?php






















namespace Facebook\Exceptions;






class FacebookServerException extends FacebookSDKException
{
}
<?php






















namespace Facebook\Exceptions;

use Facebook\FacebookResponse;






class FacebookResponseException extends FacebookSDKException
{



protected $response;




protected $responseData;







public function __construct(FacebookResponse $response, FacebookSDKException $previousException = null)
{
$this->response = $response;
$this->responseData = $response->getDecodedBody();

$errorMessage = $this->get('message', 'Unknown error from Graph.');
$errorCode = $this->get('code', -1);

parent::__construct($errorMessage, $errorCode, $previousException);
}








public static function create(FacebookResponse $response)
{
$data = $response->getDecodedBody();

if (!isset($data['error']['code']) && isset($data['code'])) {
$data = ['error' => $data];
}

$code = isset($data['error']['code']) ? $data['error']['code'] : null;
$message = isset($data['error']['message']) ? $data['error']['message'] : 'Unknown error from Graph.';

if (isset($data['error']['error_subcode'])) {
switch ($data['error']['error_subcode']) {

 case 458:
case 459:
case 460:
case 463:
case 464:
case 467:
return new static($response, new FacebookAuthenticationException($message, $code));

 case 1363030:
case 1363019:
case 1363037:
case 1363033:
case 1363021:
case 1363041:
return new static($response, new FacebookResumableUploadException($message, $code));
}
}

switch ($code) {

 case 100:
case 102:
case 190:
return new static($response, new FacebookAuthenticationException($message, $code));


 case 1:
case 2:
return new static($response, new FacebookServerException($message, $code));


 case 4:
case 17:
case 341:
return new static($response, new FacebookThrottleException($message, $code));


 case 506:
return new static($response, new FacebookClientException($message, $code));
}


 if ($code == 10 || ($code >= 200 && $code <= 299)) {
return new static($response, new FacebookAuthorizationException($message, $code));
}


 if (isset($data['error']['type']) && $data['error']['type'] === 'OAuthException') {
return new static($response, new FacebookAuthenticationException($message, $code));
}


 return new static($response, new FacebookOtherException($message, $code));
}









private function get($key, $default = null)
{
if (isset($this->responseData['error'][$key])) {
return $this->responseData['error'][$key];
}

return $default;
}






public function getHttpStatusCode()
{
return $this->response->getHttpStatusCode();
}






public function getSubErrorCode()
{
return $this->get('error_subcode', -1);
}






public function getErrorType()
{
return $this->get('type', '');
}






public function getRawResponse()
{
return $this->response->getBody();
}






public function getResponseData()
{
return $this->responseData;
}






public function getResponse()
{
return $this->response;
}
}
<?php






















namespace Facebook\Exceptions;






class FacebookAuthorizationException extends FacebookSDKException
{
}
<?php






















namespace Facebook\Exceptions;






class FacebookThrottleException extends FacebookSDKException
{
}
<?php






















namespace Facebook;

use Facebook\Authentication\AccessToken;

class FacebookApp implements \Serializable
{



protected $id;




protected $secret;





public function __construct($id, $secret)
{
$this->id = $id;
$this->secret = $secret;
}






public function getId()
{
return $this->id;
}






public function getSecret()
{
return $this->secret;
}






public function getAccessToken()
{
return new AccessToken($this->id . '|' . $this->secret);
}






public function serialize()
{
return serialize([$this->id, $this->secret]);
}






public function unserialize($serialized)
{
list($id, $secret) = unserialize($serialized);

$this->__construct($id, $secret);
}
}
<?php






















namespace Facebook;

use ArrayIterator;
use IteratorAggregate;
use ArrayAccess;
use Facebook\Authentication\AccessToken;
use Facebook\Exceptions\FacebookSDKException;






class FacebookBatchRequest extends FacebookRequest implements IteratorAggregate, ArrayAccess
{



protected $requests;




protected $attachedFiles;









public function __construct(FacebookApp $app = null, array $requests = [], $accessToken = null, $graphVersion = null)
{
parent::__construct($app, $accessToken, 'POST', '', [], null, $graphVersion);

$this->add($requests);
}











public function add($request, $name = null)
{
if (is_array($request)) {
foreach ($request as $key => $req) {
$this->add($req, $key);
}

return $this;
}

if (!$request instanceof FacebookRequest) {
throw new \InvalidArgumentException('Argument for add() must be of type array or FacebookRequest.');
}

$this->addFallbackDefaults($request);
$requestToAdd = [
'name' => $name,
'request' => $request,
];


 $attachedFiles = $this->extractFileAttachments($request);
if ($attachedFiles) {
$requestToAdd['attached_files'] = $attachedFiles;
}
$this->requests[] = $requestToAdd;

return $this;
}








public function addFallbackDefaults(FacebookRequest $request)
{
if (!$request->getApp()) {
$app = $this->getApp();
if (!$app) {
throw new FacebookSDKException('Missing FacebookApp on FacebookRequest and no fallback detected on FacebookBatchRequest.');
}
$request->setApp($app);
}

if (!$request->getAccessToken()) {
$accessToken = $this->getAccessToken();
if (!$accessToken) {
throw new FacebookSDKException('Missing access token on FacebookRequest and no fallback detected on FacebookBatchRequest.');
}
$request->setAccessToken($accessToken);
}
}










public function extractFileAttachments(FacebookRequest $request)
{
if (!$request->containsFileUploads()) {
return null;
}

$files = $request->getFiles();
$fileNames = [];
foreach ($files as $file) {
$fileName = uniqid();
$this->addFile($fileName, $file);
$fileNames[] = $fileName;
}

$request->resetFiles();


 return implode(',', $fileNames);
}






public function getRequests()
{
return $this->requests;
}






public function prepareRequestsForBatch()
{
$this->validateBatchRequestCount();

$params = [
'batch' => $this->convertRequestsToJson(),
'include_headers' => true,
];
$this->setParams($params);
}






public function convertRequestsToJson()
{
$requests = [];
foreach ($this->requests as $request) {
$attachedFiles = isset($request['attached_files']) ? $request['attached_files'] : null;
$requests[] = $this->requestEntityToBatchArray($request['request'], $request['name'], $attachedFiles);
}

return json_encode($requests);
}






public function validateBatchRequestCount()
{
$batchCount = count($this->requests);
if ($batchCount === 0) {
throw new FacebookSDKException('There are no batch requests to send.');
} elseif ($batchCount > 50) {

 throw new FacebookSDKException('You cannot send more than 50 batch requests at a time.');
}
}










public function requestEntityToBatchArray(FacebookRequest $request, $requestName = null, $attachedFiles = null)
{
$compiledHeaders = [];
$headers = $request->getHeaders();
foreach ($headers as $name => $value) {
$compiledHeaders[] = $name . ': ' . $value;
}

$batch = [
'headers' => $compiledHeaders,
'method' => $request->getMethod(),
'relative_url' => $request->getUrl(),
];


 
 $body = $request->getUrlEncodedBody()->getBody();
if ($body) {
$batch['body'] = $body;
}

if (isset($requestName)) {
$batch['name'] = $requestName;
}

if (isset($attachedFiles)) {
$batch['attached_files'] = $attachedFiles;
}


 
 

return $batch;
}






public function getIterator()
{
return new ArrayIterator($this->requests);
}




public function offsetSet($offset, $value)
{
$this->add($value, $offset);
}




public function offsetExists($offset)
{
return isset($this->requests[$offset]);
}




public function offsetUnset($offset)
{
unset($this->requests[$offset]);
}




public function offsetGet($offset)
{
return isset($this->requests[$offset]) ? $this->requests[$offset] : null;
}
}
<?php






















namespace Facebook\PseudoRandomString;

trait PseudoRandomStringGeneratorTrait
{







public function validateLength($length)
{
if (!is_int($length)) {
throw new \InvalidArgumentException('getPseudoRandomString() expects an integer for the string length');
}

if ($length < 1) {
throw new \InvalidArgumentException('getPseudoRandomString() expects a length greater than 1');
}
}









public function binToHex($binaryData, $length)
{
return mb_substr(bin2hex($binaryData), 0, $length);
}
}
<?php






















namespace Facebook\PseudoRandomString;

use Facebook\Exceptions\FacebookSDKException;
use InvalidArgumentException;

class PseudoRandomStringGeneratorFactory
{
private function __construct()
{

 }










public static function createPseudoRandomStringGenerator($generator)
{
if (!$generator) {
return self::detectDefaultPseudoRandomStringGenerator();
}

if ($generator instanceof PseudoRandomStringGeneratorInterface) {
return $generator;
}

if ('mcrypt' === $generator) {
return new McryptPseudoRandomStringGenerator();
}
if ('openssl' === $generator) {
return new OpenSslPseudoRandomStringGenerator();
}
if ('urandom' === $generator) {
return new UrandomPseudoRandomStringGenerator();
}

throw new InvalidArgumentException('The pseudo random string generator must be set to "mcrypt", "openssl", or "urandom", or be an instance of Facebook\PseudoRandomString\PseudoRandomStringGeneratorInterface');
}








private static function detectDefaultPseudoRandomStringGenerator()
{

 
 if (function_exists('mcrypt_create_iv')) {
return new McryptPseudoRandomStringGenerator();
}

if (function_exists('openssl_random_pseudo_bytes')) {
return new OpenSslPseudoRandomStringGenerator();
}

if (!ini_get('open_basedir') && is_readable('/dev/urandom')) {
return new UrandomPseudoRandomStringGenerator();
}

throw new FacebookSDKException('Unable to detect a cryptographically secure pseudo-random string generator.');
}
}
<?php






















namespace Facebook\PseudoRandomString;

use Facebook\Exceptions\FacebookSDKException;

class McryptPseudoRandomStringGenerator implements PseudoRandomStringGeneratorInterface
{
use PseudoRandomStringGeneratorTrait;




const ERROR_MESSAGE = 'Unable to generate a cryptographically secure pseudo-random string from mcrypt_create_iv(). ';




public function __construct()
{
if (!function_exists('mcrypt_create_iv')) {
throw new FacebookSDKException(
static::ERROR_MESSAGE .
'The function mcrypt_create_iv() does not exist.'
);
}
}




public function getPseudoRandomString($length)
{
$this->validateLength($length);

$binaryString = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);

if ($binaryString === false) {
throw new FacebookSDKException(
static::ERROR_MESSAGE .
'mcrypt_create_iv() returned an error.'
);
}

return $this->binToHex($binaryString, $length);
}
}
<?php






















namespace Facebook\PseudoRandomString;

use Facebook\Exceptions\FacebookSDKException;

class UrandomPseudoRandomStringGenerator implements PseudoRandomStringGeneratorInterface
{

use PseudoRandomStringGeneratorTrait;




const ERROR_MESSAGE = 'Unable to generate a cryptographically secure pseudo-random string from /dev/urandom. ';




public function __construct()
{
if (ini_get('open_basedir')) {
throw new FacebookSDKException(
static::ERROR_MESSAGE .
'There is an open_basedir constraint that prevents access to /dev/urandom.'
);
}

if (!is_readable('/dev/urandom')) {
throw new FacebookSDKException(
static::ERROR_MESSAGE .
'Unable to read from /dev/urandom.'
);
}
}




public function getPseudoRandomString($length)
{
$this->validateLength($length);

$stream = fopen('/dev/urandom', 'rb');
if (!is_resource($stream)) {
throw new FacebookSDKException(
static::ERROR_MESSAGE .
'Unable to open stream to /dev/urandom.'
);
}

if (!defined('HHVM_VERSION')) {
stream_set_read_buffer($stream, 0);
}

$binaryString = fread($stream, $length);
fclose($stream);

if (!$binaryString) {
throw new FacebookSDKException(
static::ERROR_MESSAGE .
'Stream to /dev/urandom returned no data.'
);
}

return $this->binToHex($binaryString, $length);
}
}
<?php






















namespace Facebook\PseudoRandomString;

use Facebook\Exceptions\FacebookSDKException;

class OpenSslPseudoRandomStringGenerator implements PseudoRandomStringGeneratorInterface
{
use PseudoRandomStringGeneratorTrait;




const ERROR_MESSAGE = 'Unable to generate a cryptographically secure pseudo-random string from openssl_random_pseudo_bytes().';




public function __construct()
{
if (!function_exists('openssl_random_pseudo_bytes')) {
throw new FacebookSDKException(static::ERROR_MESSAGE . 'The function openssl_random_pseudo_bytes() does not exist.');
}
}




public function getPseudoRandomString($length)
{
$this->validateLength($length);

$wasCryptographicallyStrong = false;
$binaryString = openssl_random_pseudo_bytes($length, $wasCryptographicallyStrong);

if ($binaryString === false) {
throw new FacebookSDKException(static::ERROR_MESSAGE . 'openssl_random_pseudo_bytes() returned an unknown error.');
}

if ($wasCryptographicallyStrong !== true) {
throw new FacebookSDKException(static::ERROR_MESSAGE . 'openssl_random_pseudo_bytes() returned a pseudo-random string but it was not cryptographically secure and cannot be used.');
}

return $this->binToHex($binaryString, $length);
}
}
<?php






















namespace Facebook\PseudoRandomString;






interface PseudoRandomStringGeneratorInterface
{











public function getPseudoRandomString($length);
}
<?php






















namespace Facebook;

use Facebook\Authentication\AccessToken;
use Facebook\Authentication\OAuth2Client;
use Facebook\FileUpload\FacebookFile;
use Facebook\FileUpload\FacebookResumableUploader;
use Facebook\FileUpload\FacebookTransferChunk;
use Facebook\FileUpload\FacebookVideo;
use Facebook\GraphNodes\GraphEdge;
use Facebook\Url\UrlDetectionInterface;
use Facebook\Url\FacebookUrlDetectionHandler;
use Facebook\PseudoRandomString\PseudoRandomStringGeneratorFactory;
use Facebook\PseudoRandomString\PseudoRandomStringGeneratorInterface;
use Facebook\HttpClients\HttpClientsFactory;
use Facebook\PersistentData\PersistentDataFactory;
use Facebook\PersistentData\PersistentDataInterface;
use Facebook\Helpers\FacebookCanvasHelper;
use Facebook\Helpers\FacebookJavaScriptHelper;
use Facebook\Helpers\FacebookPageTabHelper;
use Facebook\Helpers\FacebookRedirectLoginHelper;
use Facebook\Exceptions\FacebookSDKException;






class Facebook
{



const VERSION = '5.1.2';




const DEFAULT_GRAPH_VERSION = 'v2.5';




const APP_ID_ENV_NAME = 'FACEBOOK_APP_ID';




const APP_SECRET_ENV_NAME = 'FACEBOOK_APP_SECRET';




protected $app;




protected $client;




protected $oAuth2Client;




protected $urlDetectionHandler;




protected $pseudoRandomStringGenerator;




protected $defaultAccessToken;




protected $defaultGraphVersion;




protected $persistentDataHandler;




protected $lastResponse;








public function __construct(array $config = [])
{
$config = array_merge([
'app_id' => getenv(static::APP_ID_ENV_NAME),
'app_secret' => getenv(static::APP_SECRET_ENV_NAME),
'default_graph_version' => static::DEFAULT_GRAPH_VERSION,
'enable_beta_mode' => false,
'http_client_handler' => null,
'persistent_data_handler' => null,
'pseudo_random_string_generator' => null,
'url_detection_handler' => null,
], $config);

if (!$config['app_id']) {
throw new FacebookSDKException('Required "app_id" key not supplied in config and could not find fallback environment variable "' . static::APP_ID_ENV_NAME . '"');
}
if (!$config['app_secret']) {
throw new FacebookSDKException('Required "app_secret" key not supplied in config and could not find fallback environment variable "' . static::APP_SECRET_ENV_NAME . '"');
}

$this->app = new FacebookApp($config['app_id'], $config['app_secret']);
$this->client = new FacebookClient(
HttpClientsFactory::createHttpClient($config['http_client_handler']),
$config['enable_beta_mode']
);
$this->pseudoRandomStringGenerator = PseudoRandomStringGeneratorFactory::createPseudoRandomStringGenerator(
$config['pseudo_random_string_generator']
);
$this->setUrlDetectionHandler($config['url_detection_handler'] ?: new FacebookUrlDetectionHandler());
$this->persistentDataHandler = PersistentDataFactory::createPersistentDataHandler(
$config['persistent_data_handler']
);

if (isset($config['default_access_token'])) {
$this->setDefaultAccessToken($config['default_access_token']);
}


 $this->defaultGraphVersion = $config['default_graph_version'];
}






public function getApp()
{
return $this->app;
}






public function getClient()
{
return $this->client;
}






public function getOAuth2Client()
{
if (!$this->oAuth2Client instanceof OAuth2Client) {
$app = $this->getApp();
$client = $this->getClient();
$this->oAuth2Client = new OAuth2Client($app, $client, $this->defaultGraphVersion);
}

return $this->oAuth2Client;
}






public function getLastResponse()
{
return $this->lastResponse;
}






public function getUrlDetectionHandler()
{
return $this->urlDetectionHandler;
}






private function setUrlDetectionHandler(UrlDetectionInterface $urlDetectionHandler)
{
$this->urlDetectionHandler = $urlDetectionHandler;
}






public function getDefaultAccessToken()
{
return $this->defaultAccessToken;
}








public function setDefaultAccessToken($accessToken)
{
if (is_string($accessToken)) {
$this->defaultAccessToken = new AccessToken($accessToken);

return;
}

if ($accessToken instanceof AccessToken) {
$this->defaultAccessToken = $accessToken;

return;
}

throw new \InvalidArgumentException('The default access token must be of type "string" or Facebook\AccessToken');
}






public function getDefaultGraphVersion()
{
return $this->defaultGraphVersion;
}






public function getRedirectLoginHelper()
{
return new FacebookRedirectLoginHelper(
$this->getOAuth2Client(),
$this->persistentDataHandler,
$this->urlDetectionHandler,
$this->pseudoRandomStringGenerator
);
}






public function getJavaScriptHelper()
{
return new FacebookJavaScriptHelper($this->app, $this->client, $this->defaultGraphVersion);
}






public function getCanvasHelper()
{
return new FacebookCanvasHelper($this->app, $this->client, $this->defaultGraphVersion);
}






public function getPageTabHelper()
{
return new FacebookPageTabHelper($this->app, $this->client, $this->defaultGraphVersion);
}













public function get($endpoint, $accessToken = null, $eTag = null, $graphVersion = null)
{
return $this->sendRequest(
'GET',
$endpoint,
$params = [],
$accessToken,
$eTag,
$graphVersion
);
}














public function post($endpoint, array $params = [], $accessToken = null, $eTag = null, $graphVersion = null)
{
return $this->sendRequest(
'POST',
$endpoint,
$params,
$accessToken,
$eTag,
$graphVersion
);
}














public function delete($endpoint, array $params = [], $accessToken = null, $eTag = null, $graphVersion = null)
{
return $this->sendRequest(
'DELETE',
$endpoint,
$params,
$accessToken,
$eTag,
$graphVersion
);
}










public function next(GraphEdge $graphEdge)
{
return $this->getPaginationResults($graphEdge, 'next');
}










public function previous(GraphEdge $graphEdge)
{
return $this->getPaginationResults($graphEdge, 'previous');
}











public function getPaginationResults(GraphEdge $graphEdge, $direction)
{
$paginationRequest = $graphEdge->getPaginationRequest($direction);
if (!$paginationRequest) {
return null;
}

$this->lastResponse = $this->client->sendRequest($paginationRequest);


 $subClassName = $graphEdge->getSubClassName();
$graphEdge = $this->lastResponse->getGraphEdge($subClassName, false);

return count($graphEdge) > 0 ? $graphEdge : null;
}















public function sendRequest($method, $endpoint, array $params = [], $accessToken = null, $eTag = null, $graphVersion = null)
{
$accessToken = $accessToken ?: $this->defaultAccessToken;
$graphVersion = $graphVersion ?: $this->defaultGraphVersion;
$request = $this->request($method, $endpoint, $params, $accessToken, $eTag, $graphVersion);

return $this->lastResponse = $this->client->sendRequest($request);
}












public function sendBatchRequest(array $requests, $accessToken = null, $graphVersion = null)
{
$accessToken = $accessToken ?: $this->defaultAccessToken;
$graphVersion = $graphVersion ?: $this->defaultGraphVersion;
$batchRequest = new FacebookBatchRequest(
$this->app,
$requests,
$accessToken,
$graphVersion
);

return $this->lastResponse = $this->client->sendBatchRequest($batchRequest);
}















public function request($method, $endpoint, array $params = [], $accessToken = null, $eTag = null, $graphVersion = null)
{
$accessToken = $accessToken ?: $this->defaultAccessToken;
$graphVersion = $graphVersion ?: $this->defaultGraphVersion;

return new FacebookRequest(
$this->app,
$accessToken,
$method,
$endpoint,
$params,
$eTag,
$graphVersion
);
}










public function fileToUpload($pathToFile)
{
return new FacebookFile($pathToFile);
}










public function videoToUpload($pathToFile)
{
return new FacebookVideo($pathToFile);
}















public function uploadVideo($target, $pathToFile, $metadata = [], $accessToken = null, $maxTransferTries = 5, $graphVersion = null)
{
$accessToken = $accessToken ?: $this->defaultAccessToken;
$graphVersion = $graphVersion ?: $this->defaultGraphVersion;

$uploader = new FacebookResumableUploader($this->app, $this->client, $accessToken, $graphVersion);
$endpoint = '/'.$target.'/videos';
$file = $this->videoToUpload($pathToFile);
$chunk = $uploader->start($endpoint, $file);

do {
$chunk = $this->maxTriesTransfer($uploader, $endpoint, $chunk, $maxTransferTries);
} while (!$chunk->isLastChunk());

return [
'video_id' => $chunk->getVideoId(),
'success' => $uploader->finish($endpoint, $chunk->getUploadSessionId(), $metadata),
];
}













private function maxTriesTransfer(FacebookResumableUploader $uploader, $endpoint, FacebookTransferChunk $chunk, $retryCountdown)
{
$newChunk = $uploader->transfer($endpoint, $chunk, $retryCountdown < 1);

if ($newChunk !== $chunk) {
return $newChunk;
}

$retryCountdown--;


 return $this->maxTriesTransfer($uploader, $endpoint, $chunk, $retryCountdown);
}
}
<?php


namespace Facebook\WebDriver;

use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;

require_once('vendor/autoload.php');


$host = 'http://localhost:4444/wd/hub'; 
$capabilities = DesiredCapabilities::firefox();
$driver = RemoteWebDriver::create($host, $capabilities, 5000);


$driver->get('http://docs.seleniumhq.org/');


$driver->manage()->deleteAllCookies();
$driver->manage()->addCookie(array(
'name' => 'cookie_name',
'value' => 'cookie_value',
));
$cookies = $driver->manage()->getCookies();
print_r($cookies);


$link = $driver->findElement(
WebDriverBy::id('menu_about')
);
$link->click();


echo "The title is '" . $driver->getTitle() . "'\n";


echo "The current URI is '" . $driver->getCurrentURL() . "'\n";


$input = $driver->findElement(
WebDriverBy::id('q')
);
$input->sendKeys('php')->submit();


$driver->wait(10)->until(
WebDriverExpectedCondition::presenceOfAllElementsLocatedBy(
WebDriverBy::className('gsc-result')
)
);


$driver->quit();
<?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;

use Facebook\WebDriver\Exception\StaleElementReferenceException;
use Facebook\WebDriver\Exception\NoSuchFrameException;
use Facebook\WebDriver\Exception\NoSuchElementException;
use Facebook\WebDriver\Exception\NoAlertOpenException;






class WebDriverExpectedCondition {





private $apply;




public function getApply() {
return $this->apply;
}

protected function __construct($apply) {
$this->apply = $apply;
}








public static function titleIs($title) {
return new WebDriverExpectedCondition(
function ($driver) use ($title) {
return $title === $driver->getTitle();
}
);
}








public static function titleContains($title) {
return new WebDriverExpectedCondition(
function ($driver) use ($title) {
return strpos($driver->getTitle(), $title) !== false;
}
);
}









public static function presenceOfElementLocated(WebDriverBy $by) {
return new WebDriverExpectedCondition(
function ($driver) use ($by) {
return $driver->findElement($by);
}
);
}










public static function visibilityOfElementLocated(WebDriverBy $by) {
return new WebDriverExpectedCondition(
function ($driver) use ($by) {
try {
$element = $driver->findElement($by);
return $element->isDisplayed() ? $element : null;
} catch (StaleElementReferenceException $e) {
return null;
}
}
);
}










public static function visibilityOf(WebDriverElement $element) {
return new WebDriverExpectedCondition(
function ($driver) use ($element) {
return $element->isDisplayed() ? $element : null;
}
);
}









public static function presenceOfAllElementsLocatedBy(WebDriverBy $by) {
return new WebDriverExpectedCondition(
function ($driver) use ($by) {
$elements = $driver->findElements($by);
return count($elements) > 0 ? $elements : null;
}
);
}









public static function textToBePresentInElement(
WebDriverBy $by, $text) {
return new WebDriverExpectedCondition(
function ($driver) use ($by, $text) {
try {
$element_text = $driver->findElement($by)->getText();
return strpos($element_text, $text) !== false;
} catch (StaleElementReferenceException $e) {
return null;
}
}
);
}









public static function textToBePresentInElementValue(
WebDriverBy $by, $text) {
return new WebDriverExpectedCondition(
function ($driver) use ($by, $text) {
try {
$element_text = $driver->findElement($by)->getAttribute('value');
return strpos($element_text, $text) !== false;
} catch (StaleElementReferenceException $e) {
return null;
}
}
);
}










public static function frameToBeAvailableAndSwitchToIt($frame_locator) {
return new WebDriverExpectedCondition(
function ($driver) use ($frame_locator) {
try {
return $driver->switchTo()->frame($frame_locator);
} catch (NoSuchFrameException $e) {
return false;
}
}
);
}









public static function invisibilityOfElementLocated(WebDriverBy $by) {
return new WebDriverExpectedCondition(
function ($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 WebDriverExpectedCondition(
function ($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 =
WebDriverExpectedCondition::visibilityOfElementLocated($by);
return new WebDriverExpectedCondition(
function ($driver) use ($visibility_of_element_located) {
$element = call_user_func(
$visibility_of_element_located->getApply(),
$driver
);
try {
if ($element !== null && $element->isEnabled()) {
return $element;
} else {
return null;
}
} catch (StaleElementReferenceException $e) {
return null;
}
}
);
}








public static function stalenessOf(WebDriverElement $element) {
return new WebDriverExpectedCondition(
function ($driver) use ($element) {
try {
$element->isEnabled();
return false;
} catch (StaleElementReferenceException $e) {
return true;
}
}
);
}














public static function refreshed(WebDriverExpectedCondition $condition) {
return new WebDriverExpectedCondition(
function ($driver) use ($condition) {
try {
return call_user_func($condition->getApply(), $driver);
} catch (StaleElementReferenceException $e) {
return null;
}
}
);
}







public static function elementToBeSelected($element_or_by) {
return WebDriverExpectedCondition::elementSelectionStateToBe(
$element_or_by,
true
);
}








public static function elementSelectionStateToBe(
$element_or_by,
$selected
) {
if ($element_or_by instanceof WebDriverElement) {
return new WebDriverExpectedCondition(
function ($driver) use ($element_or_by, $selected) {
return $element_or_by->isSelected() === $selected;
}
);
} else if ($element_or_by instanceof WebDriverBy) {
return new WebDriverExpectedCondition(
function ($driver) use ($element_or_by, $selected) {
try {
$element = $driver->findElement($element_or_by);
return $element->isSelected() === $selected;
} catch (StaleElementReferenceException $e) {
return null;
}
}
);
}
}







public static function alertIsPresent() {
return new WebDriverExpectedCondition(
function ($driver) {
try {

 
 
 $alert = $driver->switchTo()->alert();
$alert->getText();
return $alert;
} catch (NoAlertOpenException $e) {
return null;
}
}
);
}







public static function not(WebDriverExpectedCondition $condition) {
return new WebDriverExpectedCondition(
function ($driver) use ($condition) {
$result = call_user_func($condition->getApply(), $driver);
return !$result;
}
);
}
}
<?php














namespace Facebook\WebDriver;

interface WebDriverKeyboard {







public function sendKeys($keys);








public function pressKey($key);








public function releaseKey($key);
}
<?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 LEFT_SHIFT = "\xEE\x80\x88";
const CONTROL = "\xEE\x80\x89";
const LEFT_CONTROL = "\xEE\x80\x89";
const ALT = "\xEE\x80\x8A";
const LEFT_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 LEFT = "\xEE\x80\x92";
const ARROW_LEFT = "\xEE\x80\x92";
const UP = "\xEE\x80\x93";
const ARROW_UP = "\xEE\x80\x93";
const RIGHT = "\xEE\x80\x94";
const ARROW_RIGHT = "\xEE\x80\x94";
const DOWN = "\xEE\x80\x95";
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 COMMAND = "\xEE\x80\xBD"; 
 const ZENKAKU_HANKAKU = "\xEE\x80\xC0";






public static function encode($keys) {

if (is_numeric($keys)) {
$keys = '' . $keys;
}

if (is_string($keys)) {
$keys = array($keys);
}

$encoded = array();
foreach ($keys as $key) {
if (is_array($key)) {

 $key = implode('', $key).self::NULL;
}
$encoded[] = (string)$key;
}

return $encoded;
}
}
<?php














namespace Facebook\WebDriver;




interface WebDriverAction {




public function perform();
}
<?php














namespace Facebook\WebDriver;




class WebDriverPoint {

private $x, $y;

public function __construct($x, $y) {
$this->x = $x;
$this->y = $y;
}






public function getX() {
return $this->x;
}






public function getY() {
return $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(WebDriverPoint $point) {
return $this->x === $point->getX() &&
$this->y === $point->getY();
}
}
<?php














namespace Facebook\WebDriver;




interface WebDriverTargetLocator {







public function defaultContent();








public function frame($frame);








public function window($handle);







public function alert();







public function activeElement();
}
<?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\Remote;

use Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates;
use Facebook\WebDriver\WebDriverMouse;




class RemoteMouse implements WebDriverMouse {




private $executor;




public function __construct(RemoteExecuteMethod $executor) {
$this->executor = $executor;
}






public function click(WebDriverCoordinates $where = null) {
$this->moveIfNeeded($where);
$this->executor->execute(DriverCommand::CLICK, array(
'button' => 0,
));
return $this;
}






public function contextClick(WebDriverCoordinates $where = null) {
$this->moveIfNeeded($where);
$this->executor->execute(DriverCommand::CLICK, array(
'button' => 2,
));
return $this;
}






public function doubleClick(WebDriverCoordinates $where = null) {
$this->moveIfNeeded($where);
$this->executor->execute(DriverCommand::DOUBLE_CLICK);
return $this;
}






public function mouseDown(WebDriverCoordinates $where = null) {
$this->moveIfNeeded($where);
$this->executor->execute(DriverCommand::MOUSE_DOWN);
return $this;
}








public function mouseMove(WebDriverCoordinates $where = null,
$x_offset = null,
$y_offset = null) {
$params = array();
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) {
$this->moveIfNeeded($where);
$this->executor->execute(DriverCommand::MOUSE_UP);
return $this;
}





protected function moveIfNeeded(WebDriverCoordinates $where = null) {
if ($where) {
$this->mouseMove($where);
}
}
}
<?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 GET_AVAILABLE_LOG_TYPES = "getAvailableLogTypes";
const GET_LOG = "getLog";
const GET_SESSION_LOGS = "getSessionLogs";


 const GET_NETWORK_CONNECTION = "getNetworkConnection";
const SET_NETWORK_CONNECTION = "setNetworkConnection";

private function __construct()
{
}
}
<?php














namespace Facebook\WebDriver\Remote;

use Exception;
use Facebook\WebDriver\Chrome\ChromeOptions;
use Facebook\WebDriver\Firefox\FirefoxDriver;
use Facebook\WebDriver\Firefox\FirefoxPreferences;
use Facebook\WebDriver\Firefox\FirefoxProfile;
use Facebook\WebDriver\WebDriverCapabilities;
use Facebook\WebDriver\WebDriverPlatform;

class DesiredCapabilities implements WebDriverCapabilities {

private $capabilities;

public function __construct(array $capabilities = array()) {
$this->capabilities = $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) {
$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(
'isJavascriptEnable() is a htmlunit-only option. '.
'See https://code.google.com/p/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[FirefoxDriver::PROFILE]) &&
$this->capabilities[FirefoxDriver::PROFILE] instanceof FirefoxProfile) {
$this->capabilities[FirefoxDriver::PROFILE] =
$this->capabilities[FirefoxDriver::PROFILE]->encode();
}

return $this->capabilities;
}






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;
}




public static function android() {
return new DesiredCapabilities(array(
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::ANDROID,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANDROID,
));
}




public static function chrome() {
return new DesiredCapabilities(array(
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::CHROME,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY,
));
}




public static function firefox() {
$caps = new DesiredCapabilities(array(
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::FIREFOX,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY,
));


 $profile = new FirefoxProfile();
$profile->setPreference(FirefoxPreferences::READER_PARSE_ON_LOAD_ENABLED, false);
$caps->setCapability(FirefoxDriver::PROFILE, $profile);

return $caps;
}




public static function htmlUnit() {
return new DesiredCapabilities(array(
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::HTMLUNIT,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY,
));
}




public static function htmlUnitWithJS() {
$caps = new DesiredCapabilities(array(
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::HTMLUNIT,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY,
));
return $caps->setJavascriptEnabled(true);
}




public static function internetExplorer() {
return new DesiredCapabilities(array(
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::IE,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::WINDOWS,
));
}




public static function iphone() {
return new DesiredCapabilities(array(
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::IPHONE,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::MAC,
));
}




public static function ipad() {
return new DesiredCapabilities(array(
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::IPAD,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::MAC,
));
}




public static function opera() {
return new DesiredCapabilities(array(
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::OPERA,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY,
));
}




public static function safari() {
return new DesiredCapabilities(array(
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::SAFARI,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY,
));
}




public static function phantomjs() {
return new DesiredCapabilities(array(
WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::PHANTOMJS,
WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY,
));
}
}
<?php














namespace Facebook\WebDriver\Remote;

interface ExecuteMethod {






public function execute($command_name, array $parameters = array());
}
<?php














namespace Facebook\WebDriver\Remote;

use Facebook\WebDriver\WebDriverTargetLocator;
use Facebook\WebDriver\WebDriverElement;
use Facebook\WebDriver\WebDriverAlert;
use Facebook\WebDriver\WebDriver;




class RemoteTargetLocator implements WebDriverTargetLocator {

protected $executor;
protected $driver;

public function __construct($executor, $driver) {
$this->executor = $executor;
$this->driver = $driver;
}







public function defaultContent() {
$params = array('id' => null);
$this->executor->execute(DriverCommand::SWITCH_TO_FRAME, $params);

return $this->driver;
}








public function frame($frame) {
if ($frame instanceof WebDriverElement) {
$id = array('ELEMENT' => $frame->getID());
} else {
$id = (string)$frame;
}

$params = array('id' => $id);
$this->executor->execute(DriverCommand::SWITCH_TO_FRAME, $params);

return $this->driver;
}








public function window($handle) {
$params = array('name' => (string)$handle);
$this->executor->execute(DriverCommand::SWITCH_TO_WINDOW, $params);

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, $response['ELEMENT']);
}
}
<?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\WebDriverCommandExecutor;
use Facebook\WebDriver\WebDriverElement;
use Facebook\WebDriver\WebDriverNavigation;
use Facebook\WebDriver\WebDriverOptions;
use Facebook\WebDriver\WebDriverWait;

class RemoteWebDriver implements WebDriver, JavaScriptExecutor {



protected $executor;



protected $sessionID;



protected $mouse;



protected $keyboard;



protected $touch;



protected $executeMethod;

protected function __construct() {}












public static function create(
$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
) {
$url = preg_replace('#/+$#', '', $url);


 
 if ($desired_capabilities instanceof DesiredCapabilities) {
$desired_capabilities = $desired_capabilities->toArray();
}

$executor = new HttpCommandExecutor($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);
}

$command = new WebDriverCommand(
null,
DriverCommand::NEW_SESSION,
array('desiredCapabilities' => $desired_capabilities)
);

$response = $executor->execute($command);

$driver = new static();
$driver->setSessionID($response->getSessionID())
->setCommandExecutor($executor);
return $driver;
}












public static function createBySessionID(
$session_id,
$url = 'http://localhost:4444/wd/hub'
) {
$driver = new static();
$driver->setSessionID($session_id)
->setCommandExecutor(new HttpCommandExecutor($url));
return $driver;
}






public function close() {
$this->execute(DriverCommand::CLOSE, array());

return $this;
}









public function findElement(WebDriverBy $by) {
$params = array('using' => $by->getMechanism(), 'value' => $by->getValue());
$raw_element = $this->execute(
DriverCommand::FIND_ELEMENT,
$params
);

return $this->newElement($raw_element['ELEMENT']);
}










public function findElements(WebDriverBy $by) {
$params = array('using' => $by->getMechanism(), 'value' => $by->getValue());
$raw_elements = $this->execute(
DriverCommand::FIND_ELEMENTS,
$params
);

$elements = array();
foreach ($raw_elements as $raw_element) {
$elements[] = $this->newElement($raw_element['ELEMENT']);
}
return $elements;
}








public function get($url) {
$params = array('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,
array()
);
}






public function getWindowHandles() {
return $this->execute(DriverCommand::GET_WINDOW_HANDLES, array());
}






public function quit() {
$this->execute(DriverCommand::QUIT);
$this->executor = null;
}







private function prepareScriptArguments(array $arguments) {
$args = array();
foreach ($arguments as $key => $value) {
if ($value instanceof WebDriverElement) {
$args[$key] = array('ELEMENT'=>$value->getID());
} else {
if (is_array($value)) {
$value = $this->prepareScriptArguments($value);
}
$args[$key] = $value;
}
}
return $args;
}










public function executeScript($script, array $arguments = array()) {
$params = array(
'script' => $script,
'args' => $this->prepareScriptArguments($arguments),
);
return $this->execute(DriverCommand::EXECUTE_SCRIPT, $params);
}














public function executeAsyncScript($script, array $arguments = array()) {
$params = array(
'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)
);
if ($save_as) {
file_put_contents($save_as, $screenshot);
}
return $screenshot;
}














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());
}








public function navigate() {
return new WebDriverNavigation($this->getExecuteMethod());
}







public function switchTo() {
return new RemoteTargetLocator($this->getExecuteMethod(), $this);
}




public function getMouse() {
if (!$this->mouse) {
$this->mouse = new RemoteMouse($this->getExecuteMethod());
}
return $this->mouse;
}




public function getKeyboard() {
if (!$this->keyboard) {
$this->keyboard = new RemoteKeyboard($this->getExecuteMethod());
}
return $this->keyboard;
}




public function getTouch() {
if (!$this->touch) {
$this->touch = new RemoteTouchScreen($this->getExecuteMethod());
}
return $this->touch;
}

protected function getExecuteMethod() {
if (!$this->executeMethod) {
$this->executeMethod = new RemoteExecuteMethod($this);
}
return $this->executeMethod;
}






public function action() {
return new WebDriverActions($this);
}







protected function newElement($id) {
return new RemoteWebElement($this->getExecuteMethod(), $id);
}







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 static function getAllSessions(
$url = 'http://localhost:4444/wd/hub',
$timeout_in_ms = 30000
) {
$executor = new HttpCommandExecutor($url);
$executor->setConnectionTimeout($timeout_in_ms);

$command = new WebDriverCommand(
null,
DriverCommand::GET_ALL_SESSIONS,
array()
);

return $executor->execute($command)->getValue();
}

public function execute($command_name, $params = array()) {
$command = new WebDriverCommand(
$this->sessionID,
$command_name,
$params
);

$response = $this->executor->execute($command);
return $response->getValue();
}
}
<?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 RemoteExecuteMethod implements ExecuteMethod {

private $driver;




public function __construct(RemoteWebDriver $driver) {
$this->driver = $driver;
}






public function execute(
$command_name,
array $parameters = array()
) {
return $this->driver->execute($command_name, $parameters);
}
}
<?php














namespace Facebook\WebDriver\Remote\Service;

use Exception;
use Facebook\WebDriver\Net\URLChecker;

class DriverService {




private $executable;




private $url;




private $args;




private $environment;




private $process;







public function __construct(
$executable,
$port,
$args = array(),
$environment = null
) {
$this->executable = self::checkExecutable($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;
}

$pipes = array();
$this->process = proc_open(
sprintf("%s %s", $this->executable, implode(' ', $this->args)),
$descriptorspec = array(
0 => array('pipe', 'r'), 
 1 => array('pipe', 'w'), 
 2 => array('pipe', 'a'), 
 ),
$pipes,
null,
$this->environment
);

$checker = new URLChecker();
$checker->waitUntilAvailable(20 * 1000, $this->url.'/status');

return $this;
}




public function stop() {
if ($this->process === null) {
return $this;
}

proc_terminate($this->process);
$this->process = null;

$checker = new URLChecker();
$checker->waitUntilUnAvailable(3 * 1000, $this->url.'/shutdown');

return $this;
}




public function isRunning() {
if ($this->process === null) {
return false;
}

$status = proc_get_status($this->process);
return $status['running'];
}








protected static function checkExecutable($executable) {
if (!is_file($executable)) {
throw new Exception("'$executable' is not a file.");
}

if (!is_executable($executable)) {
throw new Exception("'$executable' is not executable.");
}

return $executable;
}
}
<?php














namespace Facebook\WebDriver\Remote\Service;

use Facebook\WebDriver\Exception\WebDriverException;
use Facebook\WebDriver\Remote\DriverCommand;
use Facebook\WebDriver\Remote\HttpCommandExecutor;
use Facebook\WebDriver\Remote\WebDriverCommand;





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 WebDriverException('The driver server has died.');
}
throw $e;
}
}

}
<?php














namespace Facebook\WebDriver\Remote;

use Facebook\WebDriver\Exception\WebDriverException;
use Facebook\WebDriver\WebDriverCommandExecutor;
use InvalidArgumentException;
use BadMethodCallException;




class HttpCommandExecutor implements WebDriverCommandExecutor {





protected static $commands = array(
DriverCommand::ACCEPT_ALERT => array('method' => 'POST', 'url' => '/session/:sessionId/accept_alert'),
DriverCommand::ADD_COOKIE => array('method' => 'POST', 'url' => '/session/:sessionId/cookie'),
DriverCommand::CLEAR_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/element/:id/clear'),
DriverCommand::CLICK_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/element/:id/click'),
DriverCommand::CLOSE => array('method' => 'DELETE', 'url' => '/session/:sessionId/window'),
DriverCommand::DELETE_ALL_COOKIES => array('method' => 'DELETE', 'url' => '/session/:sessionId/cookie'),
DriverCommand::DELETE_COOKIE => array('method' => 'DELETE', 'url' => '/session/:sessionId/cookie/:name'),
DriverCommand::DISMISS_ALERT => array('method' => 'POST', 'url' => '/session/:sessionId/dismiss_alert'),
DriverCommand::ELEMENT_EQUALS => array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/equals/:other'),
DriverCommand::FIND_CHILD_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/element/:id/element'),
DriverCommand::FIND_CHILD_ELEMENTS => array('method' => 'POST', 'url' => '/session/:sessionId/element/:id/elements'),
DriverCommand::EXECUTE_SCRIPT => array('method' => 'POST', 'url' => '/session/:sessionId/execute'),
DriverCommand::EXECUTE_ASYNC_SCRIPT => array('method' => 'POST', 'url' => '/session/:sessionId/execute_async'),
DriverCommand::FIND_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/element'),
DriverCommand::FIND_ELEMENTS => array('method' => 'POST', 'url' => '/session/:sessionId/elements'),
DriverCommand::SWITCH_TO_FRAME => array('method' => 'POST', 'url' => '/session/:sessionId/frame'),
DriverCommand::SWITCH_TO_WINDOW => array('method' => 'POST', 'url' => '/session/:sessionId/window'),
DriverCommand::GET => array('method' => 'POST', 'url' => '/session/:sessionId/url'),
DriverCommand::GET_ACTIVE_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/element/active'),
DriverCommand::GET_ALERT_TEXT => array('method' => 'GET', 'url' => '/session/:sessionId/alert_text'),
DriverCommand::GET_ALL_COOKIES => array('method' => 'GET', 'url' => '/session/:sessionId/cookie'),
DriverCommand::GET_ALL_SESSIONS => array('method' => 'GET', 'url' => '/sessions'),
DriverCommand::GET_AVAILABLE_LOG_TYPES => array('method' => 'GET', 'url' => '/session/:sessionId/log/types'),
DriverCommand::GET_CURRENT_URL => array('method' => 'GET', 'url' => '/session/:sessionId/url'),
DriverCommand::GET_CURRENT_WINDOW_HANDLE => array('method' => 'GET', 'url' => '/session/:sessionId/window_handle'),
DriverCommand::GET_ELEMENT_ATTRIBUTE => array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/attribute/:name'),
DriverCommand::GET_ELEMENT_VALUE_OF_CSS_PROPERTY => array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/css/:propertyName'),
DriverCommand::GET_ELEMENT_LOCATION => array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/location'),
DriverCommand::GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW => array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/location_in_view'),
DriverCommand::GET_ELEMENT_SIZE => array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/size'),
DriverCommand::GET_ELEMENT_TAG_NAME => array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/name'),
DriverCommand::GET_ELEMENT_TEXT => array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/text'),
DriverCommand::GET_LOG => array('method' => 'POST', 'url' => '/session/:sessionId/log'),
DriverCommand::GET_PAGE_SOURCE => array('method' => 'GET', 'url' => '/session/:sessionId/source'),
DriverCommand::GET_SCREEN_ORIENTATION => array('method' => 'GET', 'url' => '/session/:sessionId/orientation'),
DriverCommand::GET_CAPABILITIES => array('method' => 'GET', 'url' => '/session/:sessionId'),
DriverCommand::GET_TITLE => array('method' => 'GET', 'url' => '/session/:sessionId/title'),
DriverCommand::GET_WINDOW_HANDLES => array('method' => 'GET', 'url' => '/session/:sessionId/window_handles'),
DriverCommand::GET_WINDOW_POSITION => array('method' => 'GET', 'url' => '/session/:sessionId/window/:windowHandle/position'),
DriverCommand::GET_WINDOW_SIZE => array('method' => 'GET', 'url' => '/session/:sessionId/window/:windowHandle/size'),
DriverCommand::GO_BACK => array('method' => 'POST', 'url' => '/session/:sessionId/back'),
DriverCommand::GO_FORWARD => array('method' => 'POST', 'url' => '/session/:sessionId/forward'),
DriverCommand::IS_ELEMENT_DISPLAYED=> array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/displayed'),
DriverCommand::IS_ELEMENT_ENABLED=> array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/enabled'),
DriverCommand::IS_ELEMENT_SELECTED=> array('method' => 'GET', 'url' => '/session/:sessionId/element/:id/selected'),
DriverCommand::MAXIMIZE_WINDOW => array('method' => 'POST', 'url' => '/session/:sessionId/window/:windowHandle/maximize'),
DriverCommand::MOUSE_DOWN => array('method' => 'POST', 'url' => '/session/:sessionId/buttondown'),
DriverCommand::MOUSE_UP => array('method' => 'POST', 'url' => '/session/:sessionId/buttonup'),
DriverCommand::CLICK => array('method' => 'POST', 'url' => '/session/:sessionId/click'),
DriverCommand::DOUBLE_CLICK => array('method' => 'POST', 'url' => '/session/:sessionId/doubleclick'),
DriverCommand::MOVE_TO => array('method' => 'POST', 'url' => '/session/:sessionId/moveto'),
DriverCommand::NEW_SESSION => array('method' => 'POST', 'url' => '/session'),
DriverCommand::QUIT => array('method' => 'DELETE', 'url' => '/session/:sessionId'),
DriverCommand::REFRESH => array('method' => 'POST', 'url' => '/session/:sessionId/refresh'),
DriverCommand::UPLOAD_FILE => array('method' => 'POST', 'url' => '/session/:sessionId/file'), 
 DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/keys'),
DriverCommand::SET_ALERT_VALUE => array('method' => 'POST', 'url' => '/session/:sessionId/alert_text'),
DriverCommand::SEND_KEYS_TO_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/element/:id/value'),
DriverCommand::IMPLICITLY_WAIT => array('method' => 'POST', 'url' => '/session/:sessionId/timeouts/implicit_wait'),
DriverCommand::SET_SCREEN_ORIENTATION => array('method' => 'POST', 'url' => '/session/:sessionId/orientation'),
DriverCommand::SET_TIMEOUT => array('method' => 'POST', 'url' => '/session/:sessionId/timeouts'),
DriverCommand::SET_SCRIPT_TIMEOUT => array('method' => 'POST', 'url' => '/session/:sessionId/timeouts/async_script'),
DriverCommand::SET_WINDOW_POSITION => array('method' => 'POST', 'url' => '/session/:sessionId/window/:windowHandle/position'),
DriverCommand::SET_WINDOW_SIZE => array('method' => 'POST', 'url' => '/session/:sessionId/window/:windowHandle/size'),
DriverCommand::SUBMIT_ELEMENT => array('method' => 'POST', 'url' => '/session/:sessionId/element/:id/submit'),
DriverCommand::SCREENSHOT => array('method' => 'GET', 'url' => '/session/:sessionId/screenshot'),
DriverCommand::TOUCH_SINGLE_TAP => array('method' => 'POST', 'url' => '/session/:sessionId/touch/click'),
DriverCommand::TOUCH_DOWN => array('method' => 'POST', 'url' => '/session/:sessionId/touch/down'),
DriverCommand::TOUCH_DOUBLE_TAP => array('method' => 'POST', 'url' => '/session/:sessionId/touch/doubleclick'),
DriverCommand::TOUCH_FLICK => array('method' => 'POST', 'url' => '/session/:sessionId/touch/flick'),
DriverCommand::TOUCH_LONG_PRESS => array('method' => 'POST', 'url' => '/session/:sessionId/touch/longclick'),
DriverCommand::TOUCH_MOVE => array('method' => 'POST', 'url' => '/session/:sessionId/touch/move'),
DriverCommand::TOUCH_SCROLL => array('method' => 'POST', 'url' => '/session/:sessionId/touch/scroll'),
DriverCommand::TOUCH_UP => array('method' => 'POST', 'url' => '/session/:sessionId/touch/up'),
);




protected $url;



protected $curl;






public function __construct($url, $http_proxy = null, $http_proxy_port = null) {
$this->url = $url;
$this->curl = curl_init();

if (!empty($http_proxy)) {
curl_setopt($this->curl, CURLOPT_PROXY, $http_proxy);
if (!empty($http_proxy_port)) {
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,
array(
'Content-Type: application/json;charset=UTF-8',
'Accept: application/json',
)
);
$this->setRequestTimeout(30000);
$this->setConnectionTimeout(30000);
}







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) {
if (!isset(self::$commands[$command->getName()])) {
throw new InvalidArgumentException(
$command->getName()." is not a valid command."
);
}
$raw = self::$commands[$command->getName()];
$http_method = $raw['method'];
$url = $raw['url'];
$url = str_replace(':sessionId', $command->getSessionID(), $url);
$params = $command->getParameters();
foreach ($params as $name => $value) {
if ($name[0] === ':') {
$url = str_replace($name, $value, $url);
if ($http_method != 'POST') {
unset($params[$name]);
}
}
}

if ($params && is_array($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);
}

$encoded_params = null;

if ($http_method === 'POST' && $params && is_array($params)) {
$encoded_params = json_encode($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 ($params && is_array($params)) {
$msg .= sprintf(' with params: %s', json_encode($params));
}
WebDriverException::throwException(-1, $msg . "\n\n" . $error, array());
}

$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($results) && array_key_exists('sessionId', $results)) {
$sessionId = $results['sessionId'];
}

$status = isset($results['status']) ? $results['status'] : 0;
WebDriverException::throwException($status, $message, $results);

$response = new WebDriverResponse($sessionId);
return $response
->setStatus($status)
->setValue($value);
}




public function getAddressOfRemoteServer() {
return $this->url;
}
}
<?php














namespace Facebook\WebDriver\Remote;

class UselessFileDetector implements FileDetector {





public function getLocalFile($file) {
return null;
}
}
<?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 Facebook\WebDriver\WebDriverKeys;
use Facebook\WebDriver\WebDriverKeyboard;




class RemoteKeyboard implements WebDriverKeyboard {




private $executor;




public function __construct(RemoteExecuteMethod $executor) {
$this->executor = $executor;
}






public function sendKeys($keys) {
$this->executor->execute(DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT, array(
'value' => WebDriverKeys::encode($keys),
));
return $this;
}








public function pressKey($key) {
$this->executor->execute(DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT, array(
'value' => array((string)$key),
));
return $this;
}








public function releaseKey($key) {
$this->executor->execute(DriverCommand::SEND_KEYS_TO_ACTIVE_ELEMENT, array(
'value' => array((string)$key),
));
return $this;
}
}
<?php














namespace Facebook\WebDriver\Remote;

class WebDriverCommand {

private $sessionID;

private $name;

private $parameters;






public function __construct($session_id, $name, $parameters) {
$this->sessionID = $session_id;
$this->name = $name;
$this->parameters = $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 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;





public function __construct(RemoteExecuteMethod $executor, $id) {
$this->executor = $executor;
$this->id = $id;
$this->fileDetector = new UselessFileDetector();
}







public function clear() {
$this->executor->execute(
DriverCommand::CLEAR_ELEMENT,
array(':id' => $this->id)
);
return $this;
}






public function click() {
$this->executor->execute(
DriverCommand::CLICK_ELEMENT,
array(':id' => $this->id)
);
return $this;
}










public function findElement(WebDriverBy $by) {
$params = array(
'using' => $by->getMechanism(),
'value' => $by->getValue(),
':id' => $this->id,
);
$raw_element = $this->executor->execute(
DriverCommand::FIND_CHILD_ELEMENT,
$params
);

return $this->newElement($raw_element['ELEMENT']);
}









public function findElements(WebDriverBy $by) {
$params = array(
'using' => $by->getMechanism(),
'value' => $by->getValue(),
':id' => $this->id,
);
$raw_elements = $this->executor->execute(
DriverCommand::FIND_CHILD_ELEMENTS,
$params
);

$elements = array();
foreach ($raw_elements as $raw_element) {
$elements[] = $this->newElement($raw_element['ELEMENT']);
}
return $elements;
}







public function getAttribute($attribute_name) {
$params = array(
':name' => $attribute_name,
':id' => $this->id,
);
return $this->executor->execute(
DriverCommand::GET_ELEMENT_ATTRIBUTE,
$params
);
}







public function getCSSValue($css_property_name) {
$params = array(
':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,
array(':id' => $this->id)
);
return new WebDriverPoint($location['x'], $location['y']);
}







public function getLocationOnScreenOnceScrolledIntoView() {
$location = $this->executor->execute(
DriverCommand::GET_ELEMENT_LOCATION_ONCE_SCROLLED_INTO_VIEW,
array(':id' => $this->id)
);
return new WebDriverPoint($location['x'], $location['y']);
}




public function getCoordinates() {
$element = $this;

$on_screen = null; 
 $in_view_port = function () use ($element) {
return $element->getLocationOnScreenOnceScrolledIntoView();
};
$on_page = 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,
array(':id' => $this->id)
);
return new WebDriverDimension($size['width'], $size['height']);
}






public function getTagName() {

 
 
 
 return strtolower($this->executor->execute(
DriverCommand::GET_ELEMENT_TAG_NAME,
array(':id' => $this->id)
));
}







public function getText() {
return $this->executor->execute(
DriverCommand::GET_ELEMENT_TEXT,
array(':id' => $this->id)
);
}







public function isDisplayed() {
return $this->executor->execute(
DriverCommand::IS_ELEMENT_DISPLAYED,
array(':id' => $this->id)
);
}







public function isEnabled() {
return $this->executor->execute(
DriverCommand::IS_ELEMENT_ENABLED,
array(':id' => $this->id)
);
}






public function isSelected() {
return $this->executor->execute(
DriverCommand::IS_ELEMENT_SELECTED,
array(':id' => $this->id)
);
}







public function sendKeys($value) {
$local_file = $this->fileDetector->getLocalFile($value);
if ($local_file === null) {
$params = array(
'value' => WebDriverKeys::encode($value),
':id' => $this->id,
);
$this->executor->execute(DriverCommand::SEND_KEYS_TO_ELEMENT, $params);
} else {
$remote_path = $this->upload($local_file);
$params = array(
'value' => WebDriverKeys::encode($remote_path),
':id' => $this->id,
);
$this->executor->execute(DriverCommand::SEND_KEYS_TO_ELEMENT, $params);
}
return $this;
}









private function upload($local_file) {
if (!is_file($local_file)) {
throw new WebDriverException("You may only upload files: " . $local_file);
}


 $temp_zip = tempnam(sys_get_temp_dir(), 'WebDriverZip');
$zip = new ZipArchive();
if ($zip->open($temp_zip, ZipArchive::CREATE) !== true) {
return false;
}
$info = pathinfo($local_file);
$file_name = $info['basename'];
$zip->addFile($local_file, $file_name);
$zip->close();
$params = array(
'file' => base64_encode(file_get_contents($temp_zip)),
);
$remote_path = $this->executor->execute(
DriverCommand::UPLOAD_FILE,
$params
);
unlink($temp_zip);
return $remote_path;
}
















public function setFileDetector(FileDetector $detector) {
$this->fileDetector = $detector;
return $this;
}







public function submit() {
$this->executor->execute(
DriverCommand::SUBMIT_ELEMENT,
array(':id' => $this->id)
);

return $this;
}






public function getID() {
return $this->id;
}







public function equals(WebDriverElement $other) {
return $this->executor->execute(DriverCommand::ELEMENT_EQUALS, array(
':id' => $this->id,
':other' => $other->getID(),
));
}








protected function newElement($id) {
return new static($this->executor, $id);
}
}
<?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,
array('element' => $element->getID())
);

return $this;
}






public function doubleTap(WebDriverElement $element) {
$this->executor->execute(
DriverCommand::TOUCH_DOUBLE_TAP,
array('element' => $element->getID())
);

return $this;
}







public function down($x, $y) {
$this->executor->execute(DriverCommand::TOUCH_DOWN, array(
'x' => $x,
'y' => $y,
));

return $this;
}








public function flick($xspeed, $yspeed) {
$this->executor->execute(DriverCommand::TOUCH_FLICK, array(
'xspeed' => $xspeed,
'yspeed' => $yspeed,
));

return $this;
}









public function flickFromElement(
WebDriverElement $element, $xoffset, $yoffset, $speed
) {
$this->executor->execute(DriverCommand::TOUCH_FLICK, array(
'xoffset' => $xoffset,
'yoffset' => $yoffset,
'element' => $element->getID(),
'speed' => $speed,
));

return $this;
}






public function longPress(WebDriverElement $element) {
$this->executor->execute(
DriverCommand::TOUCH_LONG_PRESS,
array('element' => $element->getID())
);

return $this;
}







public function move($x, $y) {
$this->executor->execute(DriverCommand::TOUCH_MOVE, array(
'x' => $x,
'y' => $y,
));

return $this;
}







public function scroll($xoffset, $yoffset) {
$this->executor->execute(DriverCommand::TOUCH_SCROLL, array(
'xoffset' => $xoffset,
'yoffset' => $yoffset,
));

return $this;
}








public function scrollFromElement(
WebDriverElement $element, $xoffset, $yoffset
) {
$this->executor->execute(DriverCommand::TOUCH_SCROLL, array(
'element' => $element->getID(),
'xoffset' => $xoffset,
'yoffset' => $yoffset,
));

return $this;
}








public function up($x, $y) {
$this->executor->execute(DriverCommand::TOUCH_UP, array(
'x' => $x,
'y' => $y,
));

return $this;
}

}
<?php














namespace Facebook\WebDriver\Remote;

class LocalFileDetector implements FileDetector {





public function getLocalFile($file) {
if (is_file($file)) {
return $file;
}
return null;
}
}
<?php














namespace Facebook\WebDriver\Remote;




class WebDriverBrowserType {
const FIREFOX = "firefox";
const FIREFOX_2 = "firefox2";
const FIREFOX_3 = "firefox3";
const FIREFOX_PROXY = "firefoxproxy";
const FIREFOX_CHROME = "firefoxchrome";
const GOOGLECHROME = "googlechrome";
const SAFARI = "safari";
const OPERA = "opera";
const IEXPLORE= "iexplore";
const IEXPLORE_PROXY= "iexploreproxy";
const SAFARI_PROXY = "safariproxy";
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\Chrome;

use Facebook\WebDriver\Remote\DesiredCapabilities;






class ChromeOptions {




const CAPABILITY = "chromeOptions";




private $arguments = array();




private $binary = '';




private $extensions = array();




private $experimentalOptions = array();








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 = $this->experimentalOptions;


 
 
 
 $options['binary'] = $this->binary;

if ($this->arguments) {
$options['args'] = $this->arguments;
}

if ($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\Service\DriverService;

class ChromeDriverService extends DriverService {


 const CHROME_DRIVER_EXE_PROPERTY = "webdriver.chrome.driver";

public static function createDefaultService() {
$exe = getenv(self::CHROME_DRIVER_EXE_PROPERTY);
$port = 9515; 
 $args = array("--port=$port");
$service = new ChromeDriverService($exe, $port, $args);
return $service;
}

}
<?php














namespace Facebook\WebDriver\Chrome;

use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\DriverCommand;
use Facebook\WebDriver\Remote\Service\DriverCommandExecutor;
use Facebook\WebDriver\Exception\WebDriverException;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Remote\WebDriverCommand;

class ChromeDriver extends RemoteWebDriver {

public static function start(
DesiredCapabilities $desired_capabilities = null,
ChromeDriverService $service = null
) {
if ($desired_capabilities === null) {
$desired_capabilities = DesiredCapabilities::chrome();
}
if ($service === null) {
$service = ChromeDriverService::createDefaultService();
}
$executor = new DriverCommandExecutor($service);
$driver = new static();
$driver->setCommandExecutor($executor)
->startSession($desired_capabilities);
return $driver;
}

public function startSession($desired_capabilities) {
$command = new WebDriverCommand(
null,
DriverCommand::NEW_SESSION,
array(
'desiredCapabilities' => $desired_capabilities->toArray(),
)
);
$response = $this->executor->execute($command);
$this->setSessionID($response->getSessionID());
}






public static function create(
$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
) {
throw new WebDriverException('Please use ChromeDriver::start() instead.');
}









public static function createBySessionID(
$session_id,
$url = 'http://localhost:4444/wd/hub'
) {
throw new WebDriverException('Please use ChromeDriver::start() instead.');
}
}
<?php














namespace Facebook\WebDriver\Firefox;

use Facebook\WebDriver\Exception\WebDriverException;
use FilesystemIterator;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use ZipArchive;

class FirefoxProfile {




private $preferences = array();




private $extensions = array();




private $extensions_datas = array();




private $rdf_file;





public function addExtension($extension) {
$this->extensions[] = $extension;
return $this;
}





public function addExtensionDatas($extension_datas) {
if (!is_dir($extension_datas)) {
return;
}

$this->extensions_datas[basename($extension_datas)] = $extension_datas;
return $this;
}





public function setRdfFile($rdf_file) {
if (!is_file($rdf_file)) {
return;
}

$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) {
if ($item->isDir()) {
mkdir($temp_dir . DIRECTORY_SEPARATOR . $dirname . DIRECTORY_SEPARATOR . $iterator->getSubPathName());
} else {
copy($item, $temp_dir . DIRECTORY_SEPARATOR . $dirname . DIRECTORY_SEPARATOR . $iterator->getSubPathName());
}
}
}

$content = "";
foreach ($this->preferences as $key => $value) {
$content .= sprintf("user_pref(\"%s\", %s);\n", $key, $value);
}
file_put_contents($temp_dir.'/user.js', $content);

$zip = new ZipArchive();
$temp_zip = tempnam(sys_get_temp_dir(), 'WebDriverFirefoxProfileZip');
$zip->open($temp_zip, ZipArchive::CREATE);

$dir = new RecursiveDirectoryIterator($temp_dir);
$files = new RecursiveIteratorIterator($dir);
foreach ($files as $name => $object) {
if (is_dir($name)) {
continue;
}
$dir_prefix = preg_replace(
'#\\\\#',
'\\\\\\\\',
$temp_dir.DIRECTORY_SEPARATOR
);
$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';

 
 $matches = array();
$xml = file_get_contents($install_rdf_path);
preg_match('#<em:id>([^<]+)</em:id>#', $xml, $matches);
$ext_dir = $profile_dir.'/extensions/'.$matches[1];

mkdir($ext_dir, 0777, true);

$this->extractTo($extension, $ext_dir);


 $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 ($zip->open($xpi)) {
$zip->extractTo($target_dir);
$zip->close();
} else {
throw new \Exception("Failed to open the firefox extension. '$xpi'");
}
return $this;
}
}
<?php














namespace Facebook\WebDriver\Firefox;

class FirefoxDriver {
const PROFILE = 'firefox_profile';

private function __construct()
{
}
}
<?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';

private function __construct()
{
}
}
<?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;
return $this;
}




public function getDispatcher() {
return $this->dispatcher;
}





protected function dispatch($method) {
if (!$this->dispatcher) {
return;
}

$arguments = func_get_args();
unset($arguments[0]);
$this->dispatcher->dispatch($method, $arguments);
}




public function getWebDriver() {
return $this->driver;
}





protected function newElement(WebDriverElement $element) {
return new EventFiringWebElement($element, $this->getDispatcher());
}






public function get($url) {
$this->dispatch('beforeNavigateTo', $url, $this);
try {
$this->driver->get($url);
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
$this->dispatch('afterNavigateTo', $url, $this);
return $this;
}






public function findElements(WebDriverBy $by) {
$this->dispatch('beforeFindBy', $by, null, $this);
try {
$elements = array();
foreach ($this->driver->findElements($by) as $element) {
$elements[] = $this->newElement($element);
}
} catch (WebDriverException $exception) {
$this->dispatchOnException($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);
}
$this->dispatch('afterFindBy', $by, null, $this);
return $element;
}







public function executeScript($script, array $arguments = array()) {
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);
}
$this->dispatch('afterScript', $script, $this);
return $result;
}







public function executeAsyncScript($script, array $arguments = array()) {
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);
}
$this->dispatch('afterScript', $script, $this);
return $result;
}





public function close() {
try {
$this->driver->close();
return $this;
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}





public function getCurrentURL() {
try {
return $this->driver->getCurrentURL();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}





public function getPageSource() {
try {
return $this->driver->getPageSource();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}





public function getTitle() {
try {
return $this->driver->getTitle();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}





public function getWindowHandle() {
try {
return $this->driver->getWindowHandle();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}





public function getWindowHandles() {
try {
return $this->driver->getWindowHandles();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}




public function quit() {
try {
$this->driver->quit();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}






public function takeScreenshot($save_as = null) {
try {
return $this->driver->takeScreenshot($save_as);
} catch (WebDriverException $exception) {
$this->dispatchOnException($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);
}
}





public function manage() {
try {
return $this->driver->manage();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}





public function navigate() {
try {
return new EventFiringWebDriverNavigation(
$this->driver->navigate(),
$this->getDispatcher()
);
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}





public function switchTo() {
try {
return $this->driver->switchTo();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}





public function getTouch() {
try {
return $this->driver->getTouch();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}

private function dispatchOnException($exception) {
$this->dispatch('onException', $exception, $this);
throw $exception;
}

public function execute($name, $params) {
try {
return $this->driver->execute($name, $params);
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}
}
<?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;
return $this;
}




public function getDispatcher() {
return $this->dispatcher;
}





protected function dispatch($method) {
if (!$this->dispatcher) {
return;
}
$arguments = func_get_args();
unset($arguments[0]);
$this->dispatcher->dispatch($method, $arguments);
}




public function getElement() {
return $this->element;
}





protected function newElement(WebDriverElement $element) {
return new static($element, $this->getDispatcher());
}






public function sendKeys($value) {

$this->dispatch('beforeChangeValueOf', $this);
try {
$this->element->sendKeys($value);
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
$this->dispatch('afterChangeValueOf', $this);
return $this;

}





public function click() {
$this->dispatch('beforeClickOn', $this);
try {
$this->element->click();
} catch (WebDriverException $exception) {
$this->dispatchOnException($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);
}
$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 = array();
foreach ($this->element->findElements($by) as $element) {
$elements[] = $this->newElement($element);
}
} catch (WebDriverException $exception) {
$this->dispatchOnException($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);
}
}






public function getAttribute($attribute_name) {
try {
return $this->element->getAttribute($attribute_name);
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}






public function getCSSValue($css_property_name) {
try {
return $this->element->getCSSValue($css_property_name);
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}





public function getLocation() {
try {
return $this->element->getLocation();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}





public function getLocationOnScreenOnceScrolledIntoView() {
try {
return $this->element->getLocationOnScreenOnceScrolledIntoView();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}




public function getCoordinates() {
try {
return $this->element->getCoordinates();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}






public function getSize() {
try {
return $this->element->getSize();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}





public function getTagName() {
try {
return $this->element->getTagName();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}





public function getText() {
try {
return $this->element->getText();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}





public function isDisplayed() {
try {
return $this->element->isDisplayed();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}





public function isEnabled() {
try {
return $this->element->isEnabled();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}





public function isSelected() {
try {
return $this->element->isSelected();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}





public function submit() {
try {
$this->element->submit();
return $this;
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}





public function getID() {
try {
return $this->element->getID();
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}








public function equals(WebDriverElement $other) {
try {
return $this->element->equals($other);
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
}

private function dispatchOnException($exception) {
$this->dispatch(
'onException',
$exception,
$this->dispatcher->getDefaultDriver()
);
throw $exception;
}


}
<?php














namespace Facebook\WebDriver\Support\Events;

use Facebook\WebDriver\Exception\WebDriverException;
use Facebook\WebDriver\WebDriverDispatcher;
use Facebook\WebDriver\WebDriverNavigation;

class EventFiringWebDriverNavigation {




protected $navigator;




protected $dispatcher;





public function __construct(WebDriverNavigation $navigator,
WebDriverDispatcher $dispatcher) {
$this->navigator = $navigator;
$this->dispatcher = $dispatcher;
return $this;
}




public function getDispatcher() {
return $this->dispatcher;
}





protected function dispatch($method) {
if (!$this->dispatcher) {
return;
}

$arguments = func_get_args();
unset($arguments[0]);
$this->dispatcher->dispatch($method, $arguments);
}




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);
}
}






public function to($url) {
$this->dispatch(
'beforeNavigateTo',
$url,
$this->getDispatcher()->getDefaultDriver()
);
try {
$this->navigator->to($url);
} catch (WebDriverException $exception) {
$this->dispatchOnException($exception);
}
$this->dispatch(
'afterNavigateTo',
$url,
$this->getDispatcher()->getDefaultDriver()
);
return $this;
}

private function dispatchOnException($exception) {
$this->dispatch('onException', $exception);
throw $exception;
}
}
<?php














namespace Facebook\WebDriver;




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\Remote\DriverCommand;




class WebDriverAlert {

protected $executor;

public function __construct($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,
array('text' => $value)
);
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;




interface WebDriverHasInputDevices {




public function getKeyboard();




public function getMouse();
}
<?php














namespace Facebook\WebDriver;

use Facebook\WebDriver\Remote\DriverCommand;




class WebDriverTimeouts {

protected $executor;

public function __construct($executor) {
$this->executor = $executor;
}








public function implicitlyWait($seconds) {
$this->executor->execute(
DriverCommand::IMPLICITLY_WAIT,
array('ms' => $seconds * 1000)
);
return $this;
}








public function setScriptTimeout($seconds) {
$this->executor->execute(
DriverCommand::SET_SCRIPT_TIMEOUT,
array('ms' => $seconds * 1000)
);
return $this;
}








public function pageLoadTimeout($seconds) {
$this->executor->execute(DriverCommand::SET_TIMEOUT, array(
'type' => 'page load',
'ms' => $seconds * 1000,
));
return $this;
}
}
<?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;

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 JavaScriptExecutor {










public function executeScript($script, array $arguments = array());














public function executeAsyncScript($script, array $arguments = array());

}
<?php














namespace Facebook\WebDriver;

use Facebook\WebDriver\Remote\DriverCommand;
use Facebook\WebDriver\Remote\ExecuteMethod;










class WebDriverNavigation {

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 = array('url' => (string)$url);
$this->executor->execute(DriverCommand::GET, $params);
return $this;
}
}
<?php














namespace Facebook\WebDriver;

use Facebook\WebDriver\Exception\IndexOutOfBoundsException;
use Facebook\WebDriver\Remote\DriverCommand;




class WebDriverWindow {

protected $executor;

public function __construct($executor) {
$this->executor = $executor;
}







public function getPosition() {
$position = $this->executor->execute(
DriverCommand::GET_WINDOW_POSITION,
array(':windowHandle' => 'current')
);
return new WebDriverPoint(
$position['x'],
$position['y']
);
}







public function getSize() {
$size = $this->executor->execute(
DriverCommand::GET_WINDOW_SIZE,
array(':windowHandle' => 'current')
);
return new WebDriverDimension(
$size['width'],
$size['height']
);
}






public function maximize() {
$this->executor->execute(
DriverCommand::MAXIMIZE_WINDOW,
array(':windowHandle' => 'current')
);
return $this;
}








public function setSize(WebDriverDimension $size) {
$params = array(
'width' => $size->getWidth(),
'height' => $size->getHeight(),
':windowHandle' => 'current',
);
$this->executor->execute(DriverCommand::SET_WINDOW_SIZE, $params);
return $this;
}








public function setPosition(WebDriverPoint $position) {
$params = array(
'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 = strtoupper($orientation);
if (!in_array($orientation, array('PORTRAIT', 'LANDSCAPE'))) {
throw new IndexOutOfBoundsException(
"Orientation must be either PORTRAIT, or LANDSCAPE"
);
}

$this->executor->execute(
DriverCommand::SET_SCREEN_ORIENTATION,
array('orientation' => $orientation)
);

return $this;

}

}
<?php














namespace Facebook\WebDriver;

use Facebook\WebDriver\Remote\DriverCommand;
use Facebook\WebDriver\Remote\ExecuteMethod;
use InvalidArgumentException;




class WebDriverOptions {

protected $executor;

public function __construct(ExecuteMethod $executor) {
$this->executor = $executor;
}




















public function addCookie(array $cookie) {
$this->validate($cookie);
$this->executor->execute(
DriverCommand::ADD_COOKIE,
array('cookie' => $cookie)
);
return $this;
}






public function deleteAllCookies() {
$this->executor->execute(DriverCommand::DELETE_ALL_COOKIES);
return $this;
}







public function deleteCookieNamed($name) {
$this->executor->execute(
DriverCommand::DELETE_COOKIE,
array(':name' => $name)
);
return $this;
}








public function getCookieNamed($name) {
$cookies = $this->getCookies();
foreach ($cookies as $cookie) {
if ($cookie['name'] === $name) {
return $cookie;
}
}
return null;
}






public function getCookies() {
return $this->executor->execute(DriverCommand::GET_ALL_COOKIES);
}

private function validate(array $cookie) {
if (!isset($cookie['name']) ||
$cookie['name'] === '' ||
strpos($cookie['name'], ';') !== false) {
throw new InvalidArgumentException(
'"name" should be non-empty and does not contain a ";"');
}

if (!isset($cookie['value'])) {
throw new InvalidArgumentException(
'"value" is required when setting a cookie.');
}

if (isset($cookie['domain']) && strpos($cookie['domain'], ':') !== false) {
throw new InvalidArgumentException(
'"domain" should not contain a port:'.(string)$cookie['domain']);
}
}






public function timeouts() {
return new WebDriverTimeouts($this->executor);
}







public function window() {
return new WebDriverWindow($this->executor);
}








public function getLog($log_type) {
return $this->executor->execute(
DriverCommand::GET_LOG,
array('type' => $log_type)
);
}







public function getAvailableLogTypes() {
return $this->executor->execute(DriverCommand::GET_AVAILABLE_LOG_TYPES);
}

}
<?php














namespace Facebook\WebDriver;





interface WebDriverSearchContext {










public function findElement(WebDriverBy $locator);









public function findElements(WebDriverBy $locator);
}
<?php














namespace Facebook\WebDriver;

use Facebook\WebDriver\Exception\UnexpectedTagNameException;
use Facebook\WebDriver\Exception\NoSuchElementException;
use Facebook\WebDriver\Exception\UnsupportedOperationException;




class WebDriverSelect {

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 = array();
foreach ($this->getOptions() as $option) {
if ($option->isSelected()) {
$selected_options[] = $option;
}
}
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 deselectAll() {
if (!$this->isMultiple()) {
throw new UnsupportedOperationException(
'You may only deselect all options of a multi-select'
);
}

foreach ($this->getOptions() as $option) {
if ($option->isSelected()) {
$option->click();
}
}
}










public function selectByIndex($index) {
$matched = false;
foreach ($this->getOptions() as $option) {
if ($option->getAttribute('index') === (string)$index) {
if (!$option->isSelected()) {
$option->click();
if (!$this->isMultiple()) {
return;
}
}
$matched = true;
}
}
if (!$matched) {
throw new NoSuchElementException(
sprintf('Cannot locate option with index: %d', $index)
);
}
}













public function selectByValue($value) {
$matched = false;
$xpath = './/option[@value = '.$this->escapeQuotes($value).']';
$options = $this->element->findElements(WebDriverBy::xpath($xpath));

foreach ($options as $option) {
if (!$option->isSelected()) {
$option->click();
}
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(.) = '.$this->escapeQuotes($text).']';
$options = $this->element->findElements(WebDriverBy::xpath($xpath));

foreach ($options as $option) {
if (!$option->isSelected()) {
$option->click();
}
if (!$this->isMultiple()) {
return;
}
$matched = true;
}


 
 if (!$matched) {
foreach ($this->getOptions() as $option) {
if ($option->getText() === $text) {
if (!$option->isSelected()) {
$option->click();
}
if (!$this->isMultiple()) {
return;
}
$matched = true;
}
}
}

if (!$matched) {
throw new NoSuchElementException(
sprintf('Cannot locate option with text: %s', $text)
);
}
}







public function deselectByIndex($index) {
foreach ($this->getOptions() as $option) {
if ($option->getAttribute('index') === (string)$index &&
$option->isSelected()) {
$option->click();
}
}
}










public function deselectByValue($value) {
$xpath = './/option[@value = '.$this->escapeQuotes($value).']';
$options = $this->element->findElements(WebDriverBy::xpath($xpath));
foreach ($options as $option) {
if ($option->isSelected()) {
$option->click();
}
}
}










public function deselectByVisibleText($text) {
$xpath = './/option[normalize-space(.) = '.$this->escapeQuotes($text).']';
$options = $this->element->findElements(WebDriverBy::xpath($xpath));
foreach ($options as $option) {
if ($option->isSelected()) {
$option->click();
}
}
}








protected function escapeQuotes($to_escape) {
if (strpos($to_escape, '"') !== false && strpos($to_escape, "'") !== false) {
$substrings = explode('"', $to_escape);

$escaped = "concat(";
$first = true;
foreach ($substrings as $string) {
if (!$first) {
$escaped .= ", '\"',";
$first = false;
}
$escaped .= '"' . $string . '"';
}
return $escaped;
}

if (strpos($to_escape, '"') !== false) {
return sprintf("'%s'", $to_escape);
}

return sprintf('"%s"', $to_escape);
}

}
<?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\Exception;

class NoSuchFrameException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;

class NoScriptResultException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;


class SessionNotCreatedException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;


class MoveTargetOutOfBoundsException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;


class InvalidCoordinatesException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;


class ElementNotSelectableException 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 NoSuchCollectionException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;

class NoStringWrapperException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;

class NoSuchElementException extends WebDriverException {

}<?php

namespace Facebook\WebDriver\Exception;

class NoStringException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;

class UnknownServerException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;


class NoSuchDocumentException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;

class NoSuchWindowException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;


class IMENotAvailableException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;


class ExpectedException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;

class InvalidCookieDomainException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;


class NullPointerException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;

class NoStringLengthException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;


class WebDriverCurlException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;

class UnknownCommandException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;

class UnexpectedAlertOpenException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;

class TimeOutException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;

class StaleElementReferenceException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;

class InvalidElementStateException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;


class UnrecognizedExceptionException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;

class XPathLookupException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;

class UnexpectedJavascriptException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;


class IMEEngineActivationFailedException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;

class NoSuchDriverException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;

class UnableToSetCookieException 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) {
switch ($status_code) {
case -1:
throw new WebDriverCurlException($message);
case 0:

 break;
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 NoAlertOpenException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;

class ElementNotVisibleException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;


class InvalidSelectorException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;


class UnsupportedOperationException extends WebDriverException {

}<?php

namespace Facebook\WebDriver\Exception;

class NoCollectionException extends WebDriverException {

}<?php














namespace Facebook\WebDriver\Exception;


class ScriptTimeoutException extends WebDriverException {

}<?php

namespace Facebook\WebDriver\Exception;

class IndexOutOfBoundsException extends WebDriverException {

}<?php














namespace Facebook\WebDriver;

use Facebook\WebDriver\Remote\WebDriverCommand;




interface WebDriverCommandExecutor {






public function execute(WebDriverCommand $command);
}
<?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 WebDriverBy('class name', $class_name);
}







public static function cssSelector($css_selector) {
return new WebDriverBy('css selector', $css_selector);
}







public static function id($id) {
return new WebDriverBy('id', $id);
}







public static function name($name) {
return new WebDriverBy('name', $name);
}







public static function linkText($link_text) {
return new WebDriverBy('link text', $link_text);
}








public static function partialLinkText($partial_link_text) {
return new WebDriverBy('partial link text', $partial_link_text);
}







public static function tagName($tag_name) {
return new WebDriverBy('tag name', $tag_name);
}







public static function xpath($xpath) {
return new WebDriverBy('xpath', $xpath);
}
}
<?php














namespace Facebook\WebDriver\Interactions;

use Facebook\WebDriver\WebDriverAction;




class WebDriverCompositeAction implements WebDriverAction {

private $actions = array();







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\Interactions;

use Facebook\WebDriver\Interactions\Internal\WebDriverClickAndHoldAction;
use Facebook\WebDriver\Interactions\Internal\WebDriverMoveToOffsetAction;
use Facebook\WebDriver\Interactions\Internal\WebDriverButtonReleaseAction;
use Facebook\WebDriver\Interactions\Internal\WebDriverDoubleClickAction;
use Facebook\WebDriver\Interactions\Internal\WebDriverSendKeysAction;
use Facebook\WebDriver\Interactions\Internal\WebDriverClickAction;
use Facebook\WebDriver\Interactions\Internal\WebDriverKeyDownAction;
use Facebook\WebDriver\Interactions\Internal\WebDriverContextClickAction;
use Facebook\WebDriver\Interactions\Internal\WebDriverKeyUpAction;
use Facebook\WebDriver\Interactions\Internal\WebDriverMouseMoveAction;
use Facebook\WebDriver\WebDriverElement;
use Facebook\WebDriver\WebDriver;




class WebDriverActions {

protected $driver;
protected $keyboard;
protected $mouse;
protected $action;

public function __construct(WebDriver $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\WebDriverTouchScreen;
use Facebook\WebDriver\Interactions\Touch\WebDriverDoubleTapAction;
use Facebook\WebDriver\Interactions\Touch\WebDriverFlickAction;
use Facebook\WebDriver\Interactions\Touch\WebDriverFlickFromElementAction;
use Facebook\WebDriver\Interactions\Touch\WebDriverLongPressAction;
use Facebook\WebDriver\Interactions\Touch\WebDriverTapAction;
use Facebook\WebDriver\Interactions\Touch\WebDriverScrollFromElementAction;
use Facebook\WebDriver\Interactions\Touch\WebDriverDownAction;
use Facebook\WebDriver\Interactions\Touch\WebDriverMoveAction;
use Facebook\WebDriver\Interactions\Touch\WebDriverScrollAction;
use Facebook\WebDriver\WebDriverUpAction;
use Facebook\WebDriver\WebDriverElement;
use Facebook\WebDriver\WebDriver;




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\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 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\WebDriverAction;

class WebDriverLongPressAction
extends WebDriverTouchAction
implements WebDriverAction {

public function perform() {
$this->touchScreen->longPress($this->locationProvider);
}
}
<?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 WebDriverFlickAction
extends WebDriverTouchAction
implements WebDriverAction {






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\Internal\WebDriverLocatable;
use Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates;




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\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 WebDriverTapAction
extends WebDriverTouchAction
implements WebDriverAction {

public function perform() {
$this->touchScreen->tap($this->locationProvider);
}
}
<?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;
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;
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\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;
use Facebook\WebDriver\WebDriverKeyboard;
use Facebook\WebDriver\Internal\WebDriverLocatable;
use Facebook\WebDriver\WebDriverMouse;

abstract class WebDriverSingleKeyAction
extends WebDriverKeysRelatedAction
implements WebDriverAction {

protected $key;

public function __construct(
WebDriverKeyboard $keyboard,
WebDriverMouse $mouse,
WebDriverLocatable $location_provider = null,
$key = null) {
parent::__construct($keyboard, $mouse, $location_provider);
$this->key = $key;
}
}
<?php














namespace Facebook\WebDriver\Interactions\Internal;

use Facebook\WebDriver\WebDriverAction;
use Facebook\WebDriver\WebDriverKeyboard;
use Facebook\WebDriver\Internal\WebDriverLocatable;
use Facebook\WebDriver\WebDriverMouse;

class WebDriverSendKeysAction
extends WebDriverKeysRelatedAction
implements WebDriverAction {

private $keys;







public function __construct(
WebDriverKeyboard $keyboard,
WebDriverMouse $mouse,
WebDriverLocatable $location_provider = null,
$keys = null) {
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;
use Facebook\WebDriver\Internal\WebDriverLocatable;
use Facebook\WebDriver\WebDriverMouse;

class WebDriverMoveToOffsetAction
extends WebDriverMouseAction
implements WebDriverAction {

private $xOffset, $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 WebDriverMouseMoveAction
extends WebDriverMouseAction
implements WebDriverAction {

public function perform() {
$this->mouse->mouseMove($this->getActionLocation());
}
}
<?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\WebDriverAction;




class WebDriverContextClickAction
extends WebDriverMouseAction
implements WebDriverAction {

public function perform() {
$this->mouse->contextClick($this->getActionLocation());
}
}
<?php














namespace Facebook\WebDriver\Interactions\Internal;

use Facebook\WebDriver\WebDriverAction;

class WebDriverKeyDownAction
extends WebDriverSingleKeyAction
implements WebDriverAction {

public function perform() {
$this->focusOnElement();
$this->keyboard->pressKey($this->key);
}
}
<?php














namespace Facebook\WebDriver\Interactions\Internal;

use Facebook\WebDriver\WebDriverMouse;
use Facebook\WebDriver\Internal\WebDriverLocatable;




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;

use Facebook\WebDriver\WebDriverAction;

class WebDriverKeyUpAction
extends WebDriverSingleKeyAction
implements WebDriverAction {

public function perform() {
$this->focusOnElement();
$this->keyboard->releaseKey($this->key);
}
}
<?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 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\WebDriverMouse;
use Facebook\WebDriver\WebDriverKeyboard;




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 Closure;
use Facebook\WebDriver\Exception\UnsupportedOperationException;
use Facebook\WebDriver\WebDriverPoint;




class WebDriverCoordinates {

private
$onScreen,
$inViewPort,
$onPage,
$auxiliary;

public function __construct(
$on_screen,
Closure $in_view_port,
Closure $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\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($timeout_in_ms, $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($timeout_in_ms, $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($timeout_in_ms, $url) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, self::CONNECT_TIMEOUT_MS);

 curl_setopt(
$ch,
156, 
 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\Support\Events\EventFiringWebDriver;

class WebDriverDispatcher {




protected $listeners = array();




protected $driver = null;








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(array($listener, $method), $arguments);
}
return $this;
}

}
<?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\Internal;

use Facebook\WebDriver\Interactions\Internal\WebDriverCoordinates;




interface WebDriverLocatable {




public function getCoordinates();
}
<?php














namespace Facebook\WebDriver;




class WebDriverDimension {

private $height, $width;

public function __construct($width, $height) {
$this->width = $width;
$this->height = $height;
}






public function getHeight() {
return $this->height;
}






public function getWidth() {
return $this->width;
}








public function equals(WebDriverDimension $dimension) {
return $this->height === $dimension->getHeight() &&
$this->width === $dimension->getWidth();
}
}
<?php














abstract class PHPUnit_Util_PHP
{





public static function factory()
{
if (DIRECTORY_SEPARATOR == '\\') {
return new PHPUnit_Util_PHP_Windows;
}

return new PHPUnit_Util_PHP_Default;
}










public function runTestJob($job, PHPUnit_Framework_Test $test, PHPUnit_Framework_TestResult $result)
{
$result->startTest($test);

$_result = $this->runJob($job);

$this->processChildResult(
$test,
$result,
$_result['stdout'],
$_result['stderr']
);
}











abstract public function runJob($job, array $settings = array());








protected function settingsToParameters(array $settings)
{
$buffer = '';

foreach ($settings as $setting) {
$buffer .= ' -d ' . $setting;
}

return $buffer;
}











private function processChildResult(PHPUnit_Framework_Test $test, PHPUnit_Framework_TestResult $result, $stdout, $stderr)
{
$time = 0;

if (!empty($stderr)) {
$result->addError(
$test,
new PHPUnit_Framework_Exception(trim($stderr)),
$time
);
} else {
set_error_handler(function ($errno, $errstr, $errfile, $errline) {
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();
} catch (ErrorException $e) {
restore_error_handler();
$childResult = false;

$result->addError(
$test,
new PHPUnit_Framework_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'];

if ($result->getCollectCodeCoverageInformation()) {
$result->getCodeCoverage()->merge(
$childResult->getCodeCoverage()
);
}

$time = $childResult->time();
$notImplemented = $childResult->notImplemented();
$risky = $childResult->risky();
$skipped = $childResult->skipped();
$errors = $childResult->errors();
$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($failures)) {
$result->addFailure(
$test,
$this->getException($failures[0]),
$time
);
}
}
}

$result->endTest($test, $time);

if (!empty($output)) {
print $output;
}
}











private function getException(PHPUnit_Framework_TestFailure $error)
{
$exception = $error->thrownException();

if ($exception instanceof __PHP_Incomplete_Class) {
$exceptionArray = array();
foreach ((array) $exception as $key => $value) {
$key = substr($key, strrpos($key, "\0") + 1);
$exceptionArray[$key] = $value;
}

$exception = new PHPUnit_Framework_SyntheticError(
sprintf(
'%s: %s',
$exceptionArray['_PHP_Incomplete_Class_Name'],
$exceptionArray['message']
),
$exceptionArray['code'],
$exceptionArray['file'],
$exceptionArray['line'],
$exceptionArray['trace']
);
}

return $exception;
}
}
<?php














class PHPUnit_Util_Getopt
{
public static function getopt(array $args, $short_options, $long_options = null)
{
if (empty($args)) {
return array(array(), array());
}

$opts = array();
$non_opts = array();

if ($long_options) {
sort($long_options);
}

if (isset($args[0][0]) && $args[0][0] != '-') {
array_shift($args);
}

reset($args);
array_map('trim', $args);

while (list($i, $arg) = each($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;
} elseif (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 array($opts, $non_opts);
}

protected static function parseShortOption($arg, $short_options, &$opts, &$args)
{
$argLen = strlen($arg);

for ($i = 0; $i < $argLen; $i++) {
$opt = $arg[$i];
$opt_arg = null;

if (($spec = strstr($short_options, $opt)) === false ||
$arg[$i] == ':') {
throw new PHPUnit_Framework_Exception(
"unrecognized option -- $opt"
);
}

if (strlen($spec) > 1 && $spec[1] == ':') {
if (strlen($spec) > 2 && $spec[2] == ':') {
if ($i + 1 < $argLen) {
$opts[] = array($opt, substr($arg, $i + 1));
break;
}
} else {
if ($i + 1 < $argLen) {
$opts[] = array($opt, substr($arg, $i + 1));
break;
} elseif (list(, $opt_arg) = each($args)) {
} else {
throw new PHPUnit_Framework_Exception(
"option requires an argument -- $opt"
);
}
}
}

$opts[] = array($opt, $opt_arg);
}
}

protected static function parseLongOption($arg, $long_options, &$opts, &$args)
{
$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);

for ($i = 0; $i < $count; $i++) {
$long_opt = $long_options[$i];
$opt_start = substr($long_opt, 0, $opt_len);

if ($opt_start != $opt) {
continue;
}

$opt_rest = substr($long_opt, $opt_len);

if ($opt_rest != '' && $opt[0] != '=' && $i + 1 < $count &&
$opt == substr($long_options[$i+1], 0, $opt_len)) {
throw new PHPUnit_Framework_Exception(
"option --$opt is ambiguous"
);
}

if (substr($long_opt, -1) == '=') {
if (substr($long_opt, -2) != '==') {
if (!strlen($opt_arg) &&
!(list(, $opt_arg) = each($args))) {
throw new PHPUnit_Framework_Exception(
"option --$opt requires an argument"
);
}
}
} elseif ($opt_arg) {
throw new PHPUnit_Framework_Exception(
"option --$opt doesn't allow an argument"
);
}

$full_option = '--' . preg_replace('/={1,2}$/', '', $long_opt);
$opts[] = array($full_option, $opt_arg);

return;
}

throw new PHPUnit_Framework_Exception("unrecognized option --$opt");
}
}
<?php









use SebastianBergmann\Environment\Runtime;






class PHPUnit_Util_PHP_Default extends PHPUnit_Util_PHP
{










public function runJob($job, array $settings = array())
{
$runtime = new Runtime;
$runtime = $runtime->getBinary() . $this->settingsToParameters($settings);

if ('phpdbg' === PHP_SAPI) {
$runtime .= ' -qrr ' . escapeshellarg(__DIR__ . '/eval-stdin.php');
}

$process = proc_open(
$runtime,
array(
0 => array('pipe', 'r'),
1 => array('pipe', 'w'),
2 => array('pipe', 'w')
),
$pipes
);

if (!is_resource($process)) {
throw new PHPUnit_Framework_Exception(
'Unable to spawn worker process'
);
}

$this->process($pipes[0], $job);
fclose($pipes[0]);

$stdout = stream_get_contents($pipes[1]);
fclose($pipes[1]);

$stderr = stream_get_contents($pipes[2]);
fclose($pipes[2]);

proc_close($process);
$this->cleanup();

return array('stdout' => $stdout, 'stderr' => $stderr);
}









protected function process($pipe, $job)
{
fwrite($pipe, $job);
}




protected function cleanup()
{
}
}
<?php
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 PHP_CodeCoverage(
null,
unserialize('{codeCoverageFilter}')
)
);
}

$result->beStrictAboutTestsThatDoNotTestAnything({isStrictAboutTestsThatDoNotTestAnything});
$result->beStrictAboutOutputDuringTests({isStrictAboutOutputDuringTests});
$result->beStrictAboutTestSize({isStrictAboutTestSize});
$result->beStrictAboutTodoAnnotatedTests({isStrictAboutTodoAnnotatedTests});

$test = new {className}('{methodName}', unserialize('{data}'), '{dataName}');
$test->setDependencyInput(unserialize('{dependencyInput}'));
$test->setInIsolation(TRUE);

ob_end_clean();
$test->run($result);
$output = '';
if (!$test->hasExpectationOnOutput()) {
$output = $test->getActualOutput();
}

rewind(STDOUT);
if ($stdout = stream_get_contents(STDOUT)) {
$output = $stdout . $output;
}

print serialize(
array(
'testResult' => $test->getResult(),
'numAssertions' => $test->getNumAssertions(),
'result' => $result,
'output' => $output
)
);
}

$configurationFilePath = '{configurationFilePath}';

if ('' !== $configurationFilePath) {
$configuration = PHPUnit_Util_Configuration::getInstance($configurationFilePath);
$configuration->handlePHPConfiguration();
unset($configuration);
}

{constants}
{included_files}
{globals}

if (isset($GLOBALS['__PHPUNIT_BOOTSTRAP'])) {
require_once $GLOBALS['__PHPUNIT_BOOTSTRAP'];
unset($GLOBALS['__PHPUNIT_BOOTSTRAP']);
}

__phpunit_run_isolated_test();
<?php









use SebastianBergmann\Environment\Runtime;






class PHPUnit_Util_PHP_Windows extends PHPUnit_Util_PHP_Default
{



private $tempFile;









public function runJob($job, array $settings = array())
{
$runtime = new Runtime;

if (false === $stdout_handle = tmpfile()) {
throw new PHPUnit_Framework_Exception(
'A temporary file could not be created; verify that your TEMP environment variable is writable'
);
}

$process = proc_open(
$runtime->getBinary() . $this->settingsToParameters($settings),
array(
0 => array('pipe', 'r'),
1 => $stdout_handle,
2 => array('pipe', 'w')
),
$pipes
);

if (!is_resource($process)) {
throw new PHPUnit_Framework_Exception(
'Unable to spawn worker process'
);
}

$this->process($pipes[0], $job);
fclose($pipes[0]);

$stderr = stream_get_contents($pipes[2]);
fclose($pipes[2]);

proc_close($process);

rewind($stdout_handle);
$stdout = stream_get_contents($stdout_handle);
fclose($stdout_handle);

$this->cleanup();

return array('stdout' => $stdout, 'stderr' => $stderr);
}









protected function process($pipe, $job)
{
if (!($this->tempFile = tempnam(sys_get_temp_dir(), 'PHPUnit')) ||
file_put_contents($this->tempFile, $job) === false) {
throw new PHPUnit_Framework_Exception(
'Unable to write temporary file'
);
}

fwrite(
$pipe,
'<?php require_once ' . var_export($this->tempFile, true) . '; ?>'
);
}




protected function cleanup()
{
unlink($this->tempFile);
}
}
<?php

eval('?>' . file_get_contents('php://input'));
<?php














class PHPUnit_Util_String
{







public static function convertToUtf8($string)
{
if (!self::isUtf8($string)) {
if (function_exists('mb_convert_encoding')) {
$string = mb_convert_encoding($string, 'UTF-8');
} else {
$string = utf8_encode($string);
}
}

return $string;
}








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;
}
}
<?php















class PHPUnit_Util_InvalidArgumentHelper
{







public static function factory($argument, $type, $value = null)
{
$stack = debug_backtrace(false);

return new PHPUnit_Framework_Exception(
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









if (!function_exists('trait_exists')) {
function trait_exists($traitname, $autoload = true)
{
return false;
}
}






class PHPUnit_Util_Test
{
const REGEX_DATA_PROVIDER = '/@dataProvider\s+([a-zA-Z0-9._:-\\\\x7f-\xff]+)/';
const REGEX_TEST_WITH = '/@testWith\s+/';
const REGEX_EXPECTED_EXCEPTION = '(@expectedException\s+([:.\w\\\\x7f-\xff]+)(?:[\t ]+(\S*))?(?:[\t ]+(\S*))?\s*$)m';
const REGEX_REQUIRES_VERSION = '/@requires\s+(?P<name>PHP(?:Unit)?)\s+(?P<value>[\d\.-]+(dev|(RC|alpha|beta)[\d\.])?)[ \t]*\r?$/m';
const REGEX_REQUIRES_OS = '/@requires\s+OS\s+(?P<value>.+?)[ \t]*\r?$/m';
const REGEX_REQUIRES = '/@requires\s+(?P<name>function|extension)\s+(?P<value>([^ ]+?))[ \t]*\r?$/m';

const UNKNOWN = -1;
const SMALL = 0;
const MEDIUM = 1;
const LARGE = 2;

private static $annotationCache = array();

private static $hookMethods = array();







public static function describe(PHPUnit_Framework_Test $test, $asString = true)
{
if ($asString) {
if ($test instanceof PHPUnit_Framework_SelfDescribing) {
return $test->toString();
} else {
return get_class($test);
}
} else {
if ($test instanceof PHPUnit_Framework_TestCase) {
return array(
get_class($test), $test->getName()
);
} elseif ($test instanceof PHPUnit_Framework_SelfDescribing) {
return array('', $test->toString());
} else {
return array('', get_class($test));
}
}
}











public static function getLinesToBeCovered($className, $methodName)
{
$annotations = self::parseTestMethodAnnotations(
$className,
$methodName
);

if (isset($annotations['class']['coversNothing']) || isset($annotations['method']['coversNothing'])) {
return false;
}

return self::getLinesToBeCoveredOrUsed($className, $methodName, 'covers');
}











public static function getLinesToBeUsed($className, $methodName)
{
return self::getLinesToBeCoveredOrUsed($className, $methodName, 'uses');
}












private static function getLinesToBeCoveredOrUsed($className, $methodName, $mode)
{
$annotations = self::parseTestMethodAnnotations(
$className,
$methodName
);

$classShortcut = null;

if (!empty($annotations['class'][$mode . 'DefaultClass'])) {
if (count($annotations['class'][$mode . 'DefaultClass']) > 1) {
throw new PHPUnit_Framework_CodeCoverageException(
sprintf(
'More than one @%sClass annotation in class or interface "%s".',
$mode,
$className
)
);
}

$classShortcut = $annotations['class'][$mode . 'DefaultClass'][0];
}

$list = array();

if (isset($annotations['class'][$mode])) {
$list = $annotations['class'][$mode];
}

if (isset($annotations['method'][$mode])) {
$list = array_merge($list, $annotations['method'][$mode]);
}

$codeList = array();

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];

$codeList = array_merge(
$codeList,
self::resolveElementToReflectionObjects($element)
);
}

return self::resolveReflectionObjectsToLines($codeList);
}











public static function getRequirements($className, $methodName)
{
$reflector = new ReflectionClass($className);
$docComment = $reflector->getDocComment();
$reflector = new ReflectionMethod($className, $methodName);
$docComment .= "\n" . $reflector->getDocComment();
$requires = array();

if ($count = preg_match_all(self::REGEX_REQUIRES_OS, $docComment, $matches)) {
$requires['OS'] = sprintf(
'/%s/i',
addcslashes($matches['value'][$count - 1], '/')
);
}
if ($count = preg_match_all(self::REGEX_REQUIRES_VERSION, $docComment, $matches)) {
for ($i = 0; $i < $count; $i++) {
$requires[$matches['name'][$i]] = $matches['value'][$i];
}
}


 $matches = array();

if ($count = preg_match_all(self::REGEX_REQUIRES, $docComment, $matches)) {
for ($i = 0; $i < $count; $i++) {
$name = $matches['name'][$i] . 's';
if (!isset($requires[$name])) {
$requires[$name] = array();
}
$requires[$name][] = $matches['value'][$i];
}
}

return $requires;
}











public static function getMissingRequirements($className, $methodName)
{
$required = static::getRequirements($className, $methodName);
$missing = array();

if (!empty($required['PHP']) && version_compare(PHP_VERSION, $required['PHP'], '<')) {
$missing[] = sprintf('PHP %s (or later) is required.', $required['PHP']);
}

if (!empty($required['PHPUnit'])) {
$phpunitVersion = PHPUnit_Runner_Version::id();
if (version_compare($phpunitVersion, $required['PHPUnit'], '<')) {
$missing[] = sprintf('PHPUnit %s (or later) is required.', $required['PHPUnit']);
}
}

if (!empty($required['OS']) && !preg_match($required['OS'], PHP_OS)) {
$missing[] = sprintf('Operating system matching %s is required.', $required['OS']);
}

if (!empty($required['functions'])) {
foreach ($required['functions'] as $function) {
$pieces = explode('::', $function);
if (2 === count($pieces) && method_exists($pieces[0], $pieces[1])) {
continue;
}
if (function_exists($function)) {
continue;
}
$missing[] = sprintf('Function %s is required.', $function);
}
}

if (!empty($required['extensions'])) {
foreach ($required['extensions'] as $extension) {
if (!extension_loaded($extension)) {
$missing[] = sprintf('Extension %s is required.', $extension);
}
}
}

return $missing;
}











public static function getExpectedException($className, $methodName)
{
$reflector = new ReflectionMethod($className, $methodName);
$docComment = $reflector->getDocComment();
$docComment = substr($docComment, 3, -2);

if (preg_match(self::REGEX_EXPECTED_EXCEPTION, $docComment, $matches)) {
$annotations = self::parseTestMethodAnnotations(
$className,
$methodName
);

$class = $matches[1];
$code = null;
$message = '';
$messageRegExp = '';

if (isset($matches[2])) {
$message = trim($matches[2]);
} elseif (isset($annotations['method']['expectedExceptionMessage'])) {
$message = self::parseAnnotationContent(
$annotations['method']['expectedExceptionMessage'][0]
);
}

if (isset($annotations['method']['expectedExceptionMessageRegExp'])) {
$messageRegExp = self::parseAnnotationContent(
$annotations['method']['expectedExceptionMessageRegExp'][0]
);
}

if (isset($matches[3])) {
$code = $matches[3];
} elseif (isset($annotations['method']['expectedExceptionCode'])) {
$code = self::parseAnnotationContent(
$annotations['method']['expectedExceptionCode'][0]
);
}

if (is_numeric($code)) {
$code = (int) $code;
} elseif (is_string($code) && defined($code)) {
$code = (int) constant($code);
}

return array(
'class' => $class, 'code' => $code, 'message' => $message, 'message_regex' => $messageRegExp
);
}

return false;
}












private static function parseAnnotationContent($message)
{
if (strpos($message, '::') !== false && count(explode('::', $message) == 2)) {
if (defined($message)) {
$message = constant($message);
}
}

return $message;
}














public static function getProvidedData($className, $methodName)
{
$reflector = new ReflectionMethod($className, $methodName);
$docComment = $reflector->getDocComment();
$data = null;

if ($dataProviderData = self::getDataFromDataProviderAnnotation($docComment, $className, $methodName)) {
$data = $dataProviderData;
}

if ($testWithData = self::getDataFromTestWithAnnotation($docComment)) {
$data = $testWithData;
}

if ($data !== null) {
if (is_object($data)) {
$data = iterator_to_array($data);
}

foreach ($data as $key => $value) {
if (!is_array($value)) {
throw new PHPUnit_Framework_Exception(
sprintf(
'Data set %s is invalid.',
is_int($key) ? '#' . $key : '"' . $key . '"'
)
);
}
}
}

return $data;
}













private static function getDataFromDataProviderAnnotation($docComment, $className, $methodName)
{
if (preg_match(self::REGEX_DATA_PROVIDER, $docComment, $matches)) {
$dataProviderMethodNameNamespace = explode('\\', $matches[1]);
$leaf = explode('::', array_pop($dataProviderMethodNameNamespace));
$dataProviderMethodName = array_pop($leaf);

if (!empty($dataProviderMethodNameNamespace)) {
$dataProviderMethodNameNamespace = implode('\\', $dataProviderMethodNameNamespace) . '\\';
} else {
$dataProviderMethodNameNamespace = '';
}

if (!empty($leaf)) {
$dataProviderClassName = $dataProviderMethodNameNamespace . array_pop($leaf);
} else {
$dataProviderClassName = $className;
}

$dataProviderClass = new ReflectionClass($dataProviderClassName);
$dataProviderMethod = $dataProviderClass->getMethod(
$dataProviderMethodName
);

if ($dataProviderMethod->isStatic()) {
$object = null;
} else {
$object = $dataProviderClass->newInstance();
}

if ($dataProviderMethod->getNumberOfParameters() == 0) {
$data = $dataProviderMethod->invoke($object);
} else {
$data = $dataProviderMethod->invoke($object, $methodName);
}

return $data;
}
}









public static function getDataFromTestWithAnnotation($docComment)
{
$docComment = self::cleanUpMultiLineAnnotation($docComment);
if (preg_match(self::REGEX_TEST_WITH, $docComment, $matches, PREG_OFFSET_CAPTURE)) {
$offset = strlen($matches[0][0]) + $matches[0][1];
$annotationContent = substr($docComment, $offset);
$data = array();
foreach (explode("\n", $annotationContent) as $candidateRow) {
$candidateRow = trim($candidateRow);
$dataSet = json_decode($candidateRow, true);
if (json_last_error() != JSON_ERROR_NONE) {
break;
}
$data[] = $dataSet;
}

if (!$data) {
throw new PHPUnit_Framework_Exception('The dataset for the @testWith annotation cannot be parsed.');
}

return $data;
}
}

private static function cleanUpMultiLineAnnotation($docComment)
{

 $docComment = preg_replace('/' . '\n' . '\s*' . '\*' . '\s?' . '/', "\n", $docComment);
$docComment = substr($docComment, 0, -1);
$docComment = rtrim($docComment, "\n");

return $docComment;
}











public static function parseTestMethodAnnotations($className, $methodName = '')
{
if (!isset(self::$annotationCache[$className])) {
$class = new ReflectionClass($className);
self::$annotationCache[$className] = self::parseAnnotations($class->getDocComment());
}

if (!empty($methodName) && !isset(self::$annotationCache[$className . '::' . $methodName])) {
try {
$method = new ReflectionMethod($className, $methodName);
$annotations = self::parseAnnotations($method->getDocComment());
} catch (ReflectionException $e) {
$annotations = array();
}
self::$annotationCache[$className . '::' . $methodName] = $annotations;
}

return array(
'class' => self::$annotationCache[$className],
'method' => !empty($methodName) ? self::$annotationCache[$className . '::' . $methodName] : array()
);
}








private static function parseAnnotations($docblock)
{
$annotations = array();

 $docblock = substr($docblock, 3, -2);

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]][] = $matches['value'][$i];
}
}

return $annotations;
}











public static function getBackupSettings($className, $methodName)
{
return array(
'backupGlobals' => self::getBooleanAnnotationSetting(
$className,
$methodName,
'backupGlobals'
),
'backupStaticAttributes' => self::getBooleanAnnotationSetting(
$className,
$methodName,
'backupStaticAttributes'
)
);
}











public static function getDependencies($className, $methodName)
{
$annotations = self::parseTestMethodAnnotations(
$className,
$methodName
);

$dependencies = array();

if (isset($annotations['class']['depends'])) {
$dependencies = $annotations['class']['depends'];
}

if (isset($annotations['method']['depends'])) {
$dependencies = array_merge(
$dependencies,
$annotations['method']['depends']
);
}

return array_unique($dependencies);
}











public static function getErrorHandlerSettings($className, $methodName)
{
return self::getBooleanAnnotationSetting(
$className,
$methodName,
'errorHandler'
);
}











public static function getGroups($className, $methodName = '')
{
$annotations = self::parseTestMethodAnnotations(
$className,
$methodName
);

$groups = array();

if (isset($annotations['method']['author'])) {
$groups = $annotations['method']['author'];
} elseif (isset($annotations['class']['author'])) {
$groups = $annotations['class']['author'];
}

if (isset($annotations['class']['group'])) {
$groups = array_merge($groups, $annotations['class']['group']);
}

if (isset($annotations['method']['group'])) {
$groups = array_merge($groups, $annotations['method']['group']);
}

if (isset($annotations['class']['ticket'])) {
$groups = array_merge($groups, $annotations['class']['ticket']);
}

if (isset($annotations['method']['ticket'])) {
$groups = array_merge($groups, $annotations['method']['ticket']);
}

foreach (array('method', 'class') as $element) {
foreach (array('small', 'medium', 'large') as $size) {
if (isset($annotations[$element][$size])) {
$groups[] = $size;
break 2;
}

if (isset($annotations[$element][$size])) {
$groups[] = $size;
break 2;
}
}
}

return array_unique($groups);
}











public static function getSize($className, $methodName)
{
$groups = array_flip(self::getGroups($className, $methodName));
$size = self::UNKNOWN;
$class = new ReflectionClass($className);

if (isset($groups['large']) ||
(class_exists('PHPUnit_Extensions_Database_TestCase', false) &&
$class->isSubclassOf('PHPUnit_Extensions_Database_TestCase')) ||
(class_exists('PHPUnit_Extensions_SeleniumTestCase', false) &&
$class->isSubclassOf('PHPUnit_Extensions_SeleniumTestCase'))) {
$size = self::LARGE;
} elseif (isset($groups['medium'])) {
$size = self::MEDIUM;
} elseif (isset($groups['small'])) {
$size = self::SMALL;
}

return $size;
}











public static function getTickets($className, $methodName)
{
$annotations = self::parseTestMethodAnnotations(
$className,
$methodName
);

$tickets = array();

if (isset($annotations['class']['ticket'])) {
$tickets = $annotations['class']['ticket'];
}

if (isset($annotations['method']['ticket'])) {
$tickets = array_merge($tickets, $annotations['method']['ticket']);
}

return array_unique($tickets);
}











public static function getProcessIsolationSettings($className, $methodName)
{
$annotations = self::parseTestMethodAnnotations(
$className,
$methodName
);

if (isset($annotations['class']['runTestsInSeparateProcesses']) ||
isset($annotations['method']['runInSeparateProcess'])) {
return true;
} else {
return false;
}
}











public static function getPreserveGlobalStateSettings($className, $methodName)
{
return self::getBooleanAnnotationSetting(
$className,
$methodName,
'preserveGlobalState'
);
}








public static function getHookMethods($className)
{
if (!class_exists($className, false)) {
return self::emptyHookMethodsArray();
}

if (!isset(self::$hookMethods[$className])) {
self::$hookMethods[$className] = self::emptyHookMethodsArray();

try {
$class = new ReflectionClass($className);

foreach ($class->getMethods() as $method) {
if (self::isBeforeClassMethod($method)) {
self::$hookMethods[$className]['beforeClass'][] = $method->getName();
}

if (self::isBeforeMethod($method)) {
self::$hookMethods[$className]['before'][] = $method->getName();
}

if (self::isAfterMethod($method)) {
self::$hookMethods[$className]['after'][] = $method->getName();
}

if (self::isAfterClassMethod($method)) {
self::$hookMethods[$className]['afterClass'][] = $method->getName();
}
}
} catch (ReflectionException $e) {
}
}

return self::$hookMethods[$className];
}






private static function emptyHookMethodsArray()
{
return array(
'beforeClass' => array('setUpBeforeClass'),
'before' => array('setUp'),
'after' => array('tearDown'),
'afterClass' => array('tearDownAfterClass')
);
}










private static function getBooleanAnnotationSetting($className, $methodName, $settingName)
{
$annotations = self::parseTestMethodAnnotations(
$className,
$methodName
);

$result = null;

if (isset($annotations['class'][$settingName])) {
if ($annotations['class'][$settingName][0] == 'enabled') {
$result = true;
} elseif ($annotations['class'][$settingName][0] == 'disabled') {
$result = false;
}
}

if (isset($annotations['method'][$settingName])) {
if ($annotations['method'][$settingName][0] == 'enabled') {
$result = true;
} elseif ($annotations['method'][$settingName][0] == 'disabled') {
$result = false;
}
}

return $result;
}










private static function resolveElementToReflectionObjects($element)
{
$codeToCoverList = array();

if (strpos($element, '\\') !== false && function_exists($element)) {
$codeToCoverList[] = new ReflectionFunction($element);
} elseif (strpos($element, '::') !== false) {
list($className, $methodName) = explode('::', $element);

if (isset($methodName[0]) && $methodName[0] == '<') {
$classes = array($className);

foreach ($classes as $className) {
if (!class_exists($className) &&
!interface_exists($className)) {
throw new PHPUnit_Framework_InvalidCoversTargetException(
sprintf(
'Trying to @cover or @use not existing class or ' .
'interface "%s".',
$className
)
);
}

$class = new ReflectionClass($className);
$methods = $class->getMethods();
$inverse = isset($methodName[1]) && $methodName[1] == '!';

if (strpos($methodName, 'protected')) {
$visibility = 'isProtected';
} elseif (strpos($methodName, 'private')) {
$visibility = 'isPrivate';
} elseif (strpos($methodName, 'public')) {
$visibility = 'isPublic';
}

foreach ($methods as $method) {
if ($inverse && !$method->$visibility()) {
$codeToCoverList[] = $method;
} elseif (!$inverse && $method->$visibility()) {
$codeToCoverList[] = $method;
}
}
}
} else {
$classes = array($className);

foreach ($classes as $className) {
if ($className == '' && function_exists($methodName)) {
$codeToCoverList[] = new ReflectionFunction(
$methodName
);
} else {
if (!((class_exists($className) ||
interface_exists($className) ||
trait_exists($className)) &&
method_exists($className, $methodName))) {
throw new PHPUnit_Framework_InvalidCoversTargetException(
sprintf(
'Trying to @cover or @use not existing method "%s::%s".',
$className,
$methodName
)
);
}

$codeToCoverList[] = new ReflectionMethod(
$className,
$methodName
);
}
}
}
} else {
$extended = false;

if (strpos($element, '<extended>') !== false) {
$element = str_replace('<extended>', '', $element);
$extended = true;
}

$classes = array($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 PHPUnit_Framework_InvalidCoversTargetException(
sprintf(
'Trying to @cover or @use not existing class or ' .
'interface "%s".',
$className
)
);
}

$codeToCoverList[] = new ReflectionClass($className);
}
}

return $codeToCoverList;
}






private static function resolveReflectionObjectsToLines(array $reflectors)
{
$result = array();

foreach ($reflectors as $reflector) {
$filename = $reflector->getFileName();

if (!isset($result[$filename])) {
$result[$filename] = array();
}

$result[$filename] = array_unique(
array_merge(
$result[$filename],
range($reflector->getStartLine(), $reflector->getEndLine())
)
);
}

return $result;
}








private static function isBeforeClassMethod(ReflectionMethod $method)
{
return $method->isStatic() && strpos($method->getDocComment(), '@beforeClass') !== false;
}








private static function isBeforeMethod(ReflectionMethod $method)
{
return preg_match('/@before\b/', $method->getDocComment());
}








private static function isAfterClassMethod(ReflectionMethod $method)
{
return $method->isStatic() && strpos($method->getDocComment(), '@afterClass') !== false;
}








private static function isAfterMethod(ReflectionMethod $method)
{
return preg_match('/@after\b/', $method->getDocComment());
}
}
<?php












class PHPUnit_Util_GlobalState
{



protected static $superGlobalArrays = array(
'_ENV',
'_POST',
'_GET',
'_COOKIE',
'_SERVER',
'_FILES',
'_REQUEST'
);




protected static $superGlobalArraysLong = array(
'HTTP_ENV_VARS',
'HTTP_POST_VARS',
'HTTP_GET_VARS',
'HTTP_COOKIE_VARS',
'HTTP_SERVER_VARS',
'HTTP_POST_FILES'
);

public static function getIncludedFilesAsString()
{
return static::processIncludedFilesAsString(get_included_files());
}

public static function processIncludedFilesAsString(array $files)
{
$blacklist = new PHPUnit_Util_Blacklist;
$prefix = false;
$result = '';

if (defined('__PHPUNIT_PHAR__')) {
$prefix = 'phar://' . __PHPUNIT_PHAR__ . '/';
}

for ($i = count($files) - 1; $i > 0; $i--) {
$file = $files[$i];

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()
{
$result = '';
$iniSettings = ini_get_all(null, false);

foreach ($iniSettings as $key => $value) {
$result .= sprintf(
'@ini_set(%s, %s);' . "\n",
self::exportVariable($key),
self::exportVariable($value)
);
}

return $result;
}

public static function getConstantsAsString()
{
$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()
{
$result = '';
$superGlobalArrays = self::getSuperGlobalArrays();

foreach ($superGlobalArrays 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 = $superGlobalArrays;
$blacklist[] = 'GLOBALS';

foreach (array_keys($GLOBALS) as $key) {
if (!in_array($key, $blacklist) && !$GLOBALS[$key] instanceof Closure) {
$result .= sprintf(
'$GLOBALS[\'%s\'] = %s;' . "\n",
$key,
self::exportVariable($GLOBALS[$key])
);
}
}

return $result;
}

protected static function getSuperGlobalArrays()
{
if (ini_get('register_long_arrays') == '1') {
return array_merge(
self::$superGlobalArrays,
self::$superGlobalArraysLong
);
} else {
return self::$superGlobalArrays;
}
}

protected static function exportVariable($variable)
{
if (is_scalar($variable) || is_null($variable) ||
(is_array($variable) && self::arrayOnlyContainsScalars($variable))) {
return var_export($variable, true);
}

return 'unserialize(' .
var_export(serialize($variable), true) .
')';
}

protected static function arrayOnlyContainsScalars(array $array)
{
$result = true;

foreach ($array as $element) {
if (is_array($element)) {
$result = self::arrayOnlyContainsScalars($element);
} elseif (!is_scalar($element) && !is_null($element)) {
$result = false;
}

if ($result === false) {
break;
}
}

return $result;
}
}
<?php














class PHPUnit_Util_Log_JSON extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener
{



protected $currentTestSuiteName = '';




protected $currentTestName = '';




protected $currentTestPass = true;








public function addError(PHPUnit_Framework_Test $test, Exception $e, $time)
{
$this->writeCase(
'error',
$time,
PHPUnit_Util_Filter::getFilteredStacktrace($e, false),
$e->getMessage(),
$test
);

$this->currentTestPass = false;
}








public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time)
{
$this->writeCase(
'fail',
$time,
PHPUnit_Util_Filter::getFilteredStacktrace($e, false),
$e->getMessage(),
$test
);

$this->currentTestPass = false;
}








public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
$this->writeCase(
'error',
$time,
PHPUnit_Util_Filter::getFilteredStacktrace($e, false),
'Incomplete Test: ' . $e->getMessage(),
$test
);

$this->currentTestPass = false;
}










public function addRiskyTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
$this->writeCase(
'error',
$time,
PHPUnit_Util_Filter::getFilteredStacktrace($e, false),
'Risky Test: ' . $e->getMessage(),
$test
);

$this->currentTestPass = false;
}








public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
$this->writeCase(
'error',
$time,
PHPUnit_Util_Filter::getFilteredStacktrace($e, false),
'Skipped Test: ' . $e->getMessage(),
$test
);

$this->currentTestPass = false;
}






public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
{
$this->currentTestSuiteName = $suite->getName();
$this->currentTestName = '';

$this->write(
array(
'event' => 'suiteStart',
'suite' => $this->currentTestSuiteName,
'tests' => count($suite)
)
);
}






public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
{
$this->currentTestSuiteName = '';
$this->currentTestName = '';
}






public function startTest(PHPUnit_Framework_Test $test)
{
$this->currentTestName = PHPUnit_Util_Test::describe($test);
$this->currentTestPass = true;

$this->write(
array(
'event' => 'testStart',
'suite' => $this->currentTestSuiteName,
'test' => $this->currentTestName
)
);
}







public function endTest(PHPUnit_Framework_Test $test, $time)
{
if ($this->currentTestPass) {
$this->writeCase('pass', $time, array(), '', $test);
}
}








protected function writeCase($status, $time, array $trace = array(), $message = '', $test = null)
{
$output = '';

 if ($test !== null && method_exists($test, 'hasOutput') && $test->hasOutput()) {
$output = $test->getActualOutput();
}
$this->write(
array(
'event' => 'test',
'suite' => $this->currentTestSuiteName,
'test' => $this->currentTestName,
'status' => $status,
'time' => $time,
'trace' => $trace,
'message' => PHPUnit_Util_String::convertToUtf8($message),
'output' => $output,
)
);
}




public function write($buffer)
{
array_walk_recursive($buffer, function (&$input) {
if (is_string($input)) {
$input = PHPUnit_Util_String::convertToUtf8($input);
}
});

$flags = 0;

if (defined('JSON_PRETTY_PRINT')) {
$flags |= JSON_PRETTY_PRINT;
}

parent::write(json_encode($buffer, $flags));
}
}
<?php















class PHPUnit_Util_Log_TAP extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener
{



protected $testNumber = 0;




protected $testSuiteLevel = 0;




protected $testSuccessful = true;










public function __construct($out = null)
{
parent::__construct($out);
$this->write("TAP version 13\n");
}








public function addError(PHPUnit_Framework_Test $test, Exception $e, $time)
{
$this->writeNotOk($test, 'Error');
}








public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time)
{
$this->writeNotOk($test, 'Failure');

$message = explode(
"\n",
PHPUnit_Framework_TestFailure::exceptionToString($e)
);

$diagnostic = array(
'message' => $message[0],
'severity' => 'fail'
);

if ($e instanceof PHPUnit_Framework_ExpectationFailedException) {
$cf = $e->getComparisonFailure();

if ($cf !== null) {
$diagnostic['data'] = array(
'got' => $cf->getActual(),
'expected' => $cf->getExpected()
);
}
}

$yaml = new Symfony\Component\Yaml\Dumper;

$this->write(
sprintf(
"  ---\n%s  ...\n",
$yaml->dump($diagnostic, 2, 2)
)
);
}








public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
$this->writeNotOk($test, '', 'TODO Incomplete Test');
}










public function addRiskyTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
$this->write(
sprintf(
"ok %d - # RISKY%s\n",
$this->testNumber,
$e->getMessage() != '' ? ' ' . $e->getMessage() : ''
)
);

$this->testSuccessful = false;
}










public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
$this->write(
sprintf(
"ok %d - # SKIP%s\n",
$this->testNumber,
$e->getMessage() != '' ? ' ' . $e->getMessage() : ''
)
);

$this->testSuccessful = false;
}






public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
{
$this->testSuiteLevel++;
}






public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
{
$this->testSuiteLevel--;

if ($this->testSuiteLevel == 0) {
$this->write(sprintf("1..%d\n", $this->testNumber));
}
}






public function startTest(PHPUnit_Framework_Test $test)
{
$this->testNumber++;
$this->testSuccessful = true;
}







public function endTest(PHPUnit_Framework_Test $test, $time)
{
if ($this->testSuccessful === true) {
$this->write(
sprintf(
"ok %d - %s\n",
$this->testNumber,
PHPUnit_Util_Test::describe($test)
)
);
}

$this->writeDiagnostics($test);
}






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::describe($test),
$directive != '' ? ' # ' . $directive : ''
)
);

$this->testSuccessful = false;
}




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
)
);
}
}
}
<?php
















class PHPUnit_Util_Log_JUnit extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener
{



protected $document;




protected $root;




protected $logIncompleteSkipped = false;




protected $writeDocument = true;




protected $testSuites = array();




protected $testSuiteTests = array(0);




protected $testSuiteAssertions = array(0);




protected $testSuiteErrors = array(0);




protected $testSuiteFailures = array(0);




protected $testSuiteTimes = array(0);




protected $testSuiteLevel = 0;




protected $currentTestCase = null;




protected $attachCurrentTestCase = true;







public function __construct($out = null, $logIncompleteSkipped = 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->logIncompleteSkipped = $logIncompleteSkipped;
}




public function flush()
{
if ($this->writeDocument === true) {
$this->write($this->getXML());
}

parent::flush();
}








public function addError(PHPUnit_Framework_Test $test, Exception $e, $time)
{
if ($this->currentTestCase === null) {
return;
}

if ($test instanceof PHPUnit_Framework_SelfDescribing) {
$buffer = $test->toString() . "\n";
} else {
$buffer = '';
}

$buffer .= PHPUnit_Framework_TestFailure::exceptionToString($e) .
"\n" .
PHPUnit_Util_Filter::getFilteredStacktrace($e);

$error = $this->document->createElement(
'error',
PHPUnit_Util_XML::prepareString($buffer)
);

$error->setAttribute('type', get_class($e));

$this->currentTestCase->appendChild($error);

$this->testSuiteErrors[$this->testSuiteLevel]++;
}








public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time)
{
if ($this->currentTestCase === null) {
return;
}

if ($test instanceof PHPUnit_Framework_SelfDescribing) {
$buffer = $test->toString() . "\n";
} else {
$buffer = '';
}

$buffer .= PHPUnit_Framework_TestFailure::exceptionToString($e) .
"\n" .
PHPUnit_Util_Filter::getFilteredStacktrace($e);

$failure = $this->document->createElement(
'failure',
PHPUnit_Util_XML::prepareString($buffer)
);

$failure->setAttribute('type', get_class($e));

$this->currentTestCase->appendChild($failure);

$this->testSuiteFailures[$this->testSuiteLevel]++;
}








public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
if ($this->logIncompleteSkipped && $this->currentTestCase !== null) {
$error = $this->document->createElement(
'error',
PHPUnit_Util_XML::prepareString(
"Incomplete Test\n" .
PHPUnit_Util_Filter::getFilteredStacktrace($e)
)
);

$error->setAttribute('type', get_class($e));

$this->currentTestCase->appendChild($error);

$this->testSuiteErrors[$this->testSuiteLevel]++;
} else {
$this->attachCurrentTestCase = false;
}
}










public function addRiskyTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
if ($this->logIncompleteSkipped && $this->currentTestCase !== null) {
$error = $this->document->createElement(
'error',
PHPUnit_Util_XML::prepareString(
"Risky Test\n" .
PHPUnit_Util_Filter::getFilteredStacktrace($e)
)
);

$error->setAttribute('type', get_class($e));

$this->currentTestCase->appendChild($error);

$this->testSuiteErrors[$this->testSuiteLevel]++;
} else {
$this->attachCurrentTestCase = false;
}
}










public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
if ($this->logIncompleteSkipped && $this->currentTestCase !== null) {
$error = $this->document->createElement(
'error',
PHPUnit_Util_XML::prepareString(
"Skipped Test\n" .
PHPUnit_Util_Filter::getFilteredStacktrace($e)
)
);

$error->setAttribute('type', get_class($e));

$this->currentTestCase->appendChild($error);

$this->testSuiteErrors[$this->testSuiteLevel]++;
} else {
$this->attachCurrentTestCase = false;
}
}








public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
{
$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->testSuiteTimes[$this->testSuiteLevel] = 0;
}








public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
{
$this->testSuites[$this->testSuiteLevel]->setAttribute(
'tests',
$this->testSuiteTests[$this->testSuiteLevel]
);

$this->testSuites[$this->testSuiteLevel]->setAttribute(
'assertions',
$this->testSuiteAssertions[$this->testSuiteLevel]
);

$this->testSuites[$this->testSuiteLevel]->setAttribute(
'failures',
$this->testSuiteFailures[$this->testSuiteLevel]
);

$this->testSuites[$this->testSuiteLevel]->setAttribute(
'errors',
$this->testSuiteErrors[$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->testSuiteTimes[$this->testSuiteLevel - 1] += $this->testSuiteTimes[$this->testSuiteLevel];
}

$this->testSuiteLevel--;
}






public function startTest(PHPUnit_Framework_Test $test)
{
$testCase = $this->document->createElement('testcase');
$testCase->setAttribute('name', $test->getName());

if ($test instanceof PHPUnit_Framework_TestCase) {
$class = new ReflectionClass($test);
$methodName = $test->getName();

if ($class->hasMethod($methodName)) {
$method = $class->getMethod($test->getName());

$testCase->setAttribute('class', $class->getName());
$testCase->setAttribute('file', $class->getFileName());
$testCase->setAttribute('line', $method->getStartLine());
}
}

$this->currentTestCase = $testCase;
}







public function endTest(PHPUnit_Framework_Test $test, $time)
{
if ($this->attachCurrentTestCase) {
if ($test instanceof PHPUnit_Framework_TestCase) {
$numAssertions = $test->getNumAssertions();
$this->testSuiteAssertions[$this->testSuiteLevel] += $numAssertions;

$this->currentTestCase->setAttribute(
'assertions',
$numAssertions
);
}

$this->currentTestCase->setAttribute(
'time',
sprintf('%F', $time)
);

$this->testSuites[$this->testSuiteLevel]->appendChild(
$this->currentTestCase
);

$this->testSuiteTests[$this->testSuiteLevel]++;
$this->testSuiteTimes[$this->testSuiteLevel] += $time;

if (method_exists($test, 'hasOutput') && $test->hasOutput()) {
$systemOut = $this->document->createElement('system-out');
$systemOut->appendChild(
$this->document->createTextNode($test->getActualOutput())
);
$this->currentTestCase->appendChild($systemOut);
}
}

$this->attachCurrentTestCase = true;
$this->currentTestCase = null;
}








public function getXML()
{
return $this->document->saveXML();
}












public function setWriteDocument($flag)
{
if (is_bool($flag)) {
$this->writeDocument = $flag;
}
}
}
<?php














class PHPUnit_Util_Filter
{








public static function getFilteredStacktrace(Exception $e, $asString = true)
{
$prefix = false;
$script = realpath($GLOBALS['_SERVER']['SCRIPT_NAME']);

if (defined('__PHPUNIT_PHAR_ROOT__')) {
$prefix = __PHPUNIT_PHAR_ROOT__;
}

if ($asString === true) {
$filteredStacktrace = '';
} else {
$filteredStacktrace = array();
}

if ($e instanceof PHPUnit_Framework_SyntheticError) {
$eTrace = $e->getSyntheticTrace();
$eFile = $e->getSyntheticFile();
$eLine = $e->getSyntheticLine();
} elseif ($e instanceof PHPUnit_Framework_Exception) {
$eTrace = $e->getSerializableTrace();
$eFile = $e->getFile();
$eLine = $e->getLine();
} else {
if ($e->getPrevious()) {
$e = $e->getPrevious();
}
$eTrace = $e->getTrace();
$eFile = $e->getFile();
$eLine = $e->getLine();
}

if (!self::frameExists($eTrace, $eFile, $eLine)) {
array_unshift(
$eTrace,
array('file' => $eFile, 'line' => $eLine)
);
}

$blacklist = new PHPUnit_Util_Blacklist;

foreach ($eTrace as $frame) {
if (isset($frame['file']) && is_file($frame['file']) &&
!$blacklist->isBlacklisted($frame['file']) &&
($prefix === false || strpos($frame['file'], $prefix) !== 0) &&
$frame['file'] !== $script) {
if ($asString === true) {
$filteredStacktrace .= sprintf(
"%s:%s\n",
$frame['file'],
isset($frame['line']) ? $frame['line'] : '?'
);
} else {
$filteredStacktrace[] = $frame;
}
}
}

return $filteredStacktrace;
}










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














class PHPUnit_Util_Type
{
public static function isType($type)
{
return in_array(
$type,
array(
'numeric',
'integer',
'int',
'float',
'string',
'boolean',
'bool',
'null',
'array',
'object',
'resource',
'scalar'
)
);
}
}
<?php














class PHPUnit_Util_TestSuiteIterator implements RecursiveIterator
{



protected $position;




protected $tests;




public function __construct(PHPUnit_Framework_TestSuite $testSuite)
{
$this->tests = $testSuite->tests();
}




public function rewind()
{
$this->position = 0;
}






public function valid()
{
return $this->position < count($this->tests);
}






public function key()
{
return $this->position;
}






public function current()
{
return $this->valid() ? $this->tests[$this->position] : null;
}




public function next()
{
$this->position++;
}






public function getChildren()
{
return new self(
$this->tests[$this->position]
);
}






public function hasChildren()
{
return $this->tests[$this->position] instanceof PHPUnit_Framework_TestSuite;
}
}
<?php














class PHPUnit_Util_XML
{












public static function prepareString($string)
{
return preg_replace(
'/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]/',
'',
htmlspecialchars(
PHPUnit_Util_String::convertToUtf8($string),
ENT_QUOTES,
'UTF-8'
)
);
}













public static function loadFile($filename, $isHtml = false, $xinclude = false, $strict = false)
{
$reporting = error_reporting(0);
$contents = file_get_contents($filename);
error_reporting($reporting);

if ($contents === false) {
throw new PHPUnit_Framework_Exception(
sprintf(
'Could not read "%s".',
$filename
)
);
}

return self::load($contents, $isHtml, $filename, $xinclude, $strict);
}

























public static function load($actual, $isHtml = false, $filename = '', $xinclude = false, $strict = false)
{
if ($actual instanceof DOMDocument) {
return $actual;
}

if (!is_string($actual)) {
throw new PHPUnit_Framework_Exception('Could not load XML from ' . gettype($actual));
}

if ($actual === '') {
throw new PHPUnit_Framework_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 ($xinclude) {
@chdir($cwd);
}

if ($loaded === false || ($strict && $message !== '')) {
if ($filename !== '') {
throw new PHPUnit_Framework_Exception(
sprintf(
'Could not load "%s".%s',
$filename,
$message != '' ? "\n" . $message : ''
)
);
} else {
if ($message === '') {
$message = 'Could not load XML for unknown reason';
}
throw new PHPUnit_Framework_Exception($message);
}
}

return $document;
}








public static function nodeToText(DOMNode $node)
{
if ($node->childNodes->length == 1) {
return $node->textContent;
}

$result = '';

foreach ($node->childNodes as $childNode) {
$result .= $node->ownerDocument->saveXML($childNode);
}

return $result;
}






public static function removeCharacterDataNodes(DOMNode $node)
{
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 xmlToVariable(DOMElement $element)
{
$variable = null;

switch ($element->tagName) {
case 'array':
$variable = array();

foreach ($element->getElementsByTagName('element') as $element) {
$item = $element->childNodes->item(0);

if ($item instanceof DOMText) {
$item = $element->childNodes->item(1);
}

$value = self::xmlToVariable($item);

if ($element->hasAttribute('key')) {
$variable[(string) $element->getAttribute('key')] = $value;
} else {
$variable[] = $value;
}
}
break;

case 'object':
$className = $element->getAttribute('class');

if ($element->hasChildNodes()) {
$arguments = $element->childNodes->item(1)->childNodes;
$constructorArgs = array();

foreach ($arguments as $argument) {
if ($argument instanceof DOMElement) {
$constructorArgs[] = self::xmlToVariable($argument);
}
}

$class = new ReflectionClass($className);
$variable = $class->newInstanceArgs($constructorArgs);
} else {
$variable = new $className;
}
break;

case 'boolean':
$variable = $element->textContent == 'true' ? true : false;
break;

case 'integer':
case 'double':
case 'string':
$variable = $element->textContent;

settype($variable, $element->tagName);
break;
}

return $variable;
}













public static function assertValidKeys(array $hash, array $validKeys)
{
$valids = array();


 
 foreach ($validKeys as $key => $val) {
is_int($key) ? $valids[$val] = null : $valids[$key] = $val;
}

$validKeys = array_keys($valids);


 foreach ($hash as $key => $value) {
if (!in_array($key, $validKeys)) {
$unknown[] = $key;
}
}

if (!empty($unknown)) {
throw new PHPUnit_Framework_Exception(
'Unknown key(s): ' . implode(', ', $unknown)
);
}


 foreach ($valids as $key => $value) {
if (!isset($hash[$key])) {
$hash[$key] = $value;
}
}

return $hash;
}












public static function convertSelectToTag($selector, $content = true)
{
$selector = trim(preg_replace("/\s+/", ' ', $selector));


 while (preg_match('/\[[^\]]+"[^"]+\s[^"]+"\]/', $selector)) {
$selector = preg_replace(
'/(\[[^\]]+"[^"]+)\s([^"]+"\])/',
'$1__SPACE__$2',
$selector
);
}

if (strstr($selector, ' ')) {
$elements = explode(' ', $selector);
} else {
$elements = array($selector);
}

$previousTag = array();

foreach (array_reverse($elements) as $element) {
$element = str_replace('__SPACE__', ' ', $element);


 if ($element == '>') {
$previousTag = array('child' => $previousTag['descendant']);
continue;
}


 if ($element == '+') {
$previousTag = array('adjacent-sibling' => $previousTag['descendant']);
continue;
}

$tag = array();


 preg_match("/^([^\.#\[]*)/", $element, $eltMatches);

if (!empty($eltMatches[1])) {
$tag['tag'] = $eltMatches[1];
}


 
 preg_match_all(
"/(\[[^\]]*\]*|#[^\.#\[]*|\.[^\.#\[]*)/",
$element,
$matches
);

if (!empty($matches[1])) {
$classes = array();
$attrs = array();

foreach ($matches[1] as $match) {

 if (substr($match, 0, 1) == '#') {
$tag['id'] = substr($match, 1);
} 
 elseif (substr($match, 0, 1) == '.') {
$classes[] = substr($match, 1);
} 
 elseif (substr($match, 0, 1) == '[' &&
substr($match, -1, 1) == ']') {
$attribute = substr($match, 1, strlen($match) - 2);
$attribute = str_replace('"', '', $attribute);


 if (strstr($attribute, '~=')) {
list($key, $value) = explode('~=', $attribute);
$value = "regexp:/.*\b$value\b.*/";
} 
 elseif (strstr($attribute, '*=')) {
list($key, $value) = explode('*=', $attribute);
$value = "regexp:/.*$value.*/";
} 
 else {
list($key, $value) = explode('=', $attribute);
}

$attrs[$key] = $value;
}
}

if (!empty($classes)) {
$tag['class'] = implode(' ', $classes);
}

if (!empty($attrs)) {
$tag['attributes'] = $attrs;
}
}


 if (is_string($content)) {
$tag['content'] = $content;
}


 if (!empty($previousTag['descendant'])) {
$tag['descendant'] = $previousTag['descendant'];
} elseif (!empty($previousTag['child'])) {
$tag['child'] = $previousTag['child'];
} elseif (!empty($previousTag['adjacent-sibling'])) {
$tag['adjacent-sibling'] = $previousTag['adjacent-sibling'];
unset($tag['content']);
}

$previousTag = array('descendant' => $tag);
}

return $tag;
}






















public static function cssSelect($selector, $content, $actual, $isHtml = true)
{
$matcher = self::convertSelectToTag($selector, $content);
$dom = self::load($actual, $isHtml);
$tags = self::findNodes($dom, $matcher, $isHtml);

return $tags;
}












public static function findNodes(DOMDocument $dom, array $options, $isHtml = true)
{
$valid = array(
'id', 'class', 'tag', 'content', 'attributes', 'parent',
'child', 'ancestor', 'descendant', 'children', 'adjacent-sibling'
);

$filtered = array();
$options = self::assertValidKeys($options, $valid);


 if ($options['id']) {
$options['attributes']['id'] = $options['id'];
}

if ($options['class']) {
$options['attributes']['class'] = $options['class'];
}

$nodes = array();


 if ($options['tag']) {
if ($isHtml) {
$elements = self::getElementsByCaseInsensitiveTagName(
$dom,
$options['tag']
);
} else {
$elements = $dom->getElementsByTagName($options['tag']);
}

foreach ($elements as $element) {
$nodes[] = $element;
}

if (empty($nodes)) {
return false;
}
} 
 else {
$tags = array(
'a', 'abbr', 'acronym', 'address', 'area', 'b', 'base', 'bdo',
'big', 'blockquote', 'body', 'br', 'button', 'caption', 'cite',
'code', 'col', 'colgroup', 'dd', 'del', 'div', 'dfn', 'dl',
'dt', 'em', 'fieldset', 'form', 'frame', 'frameset', 'h1', 'h2',
'h3', 'h4', 'h5', 'h6', 'head', 'hr', 'html', 'i', 'iframe',
'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'link',
'map', 'meta', 'noframes', 'noscript', 'object', 'ol', 'optgroup',
'option', 'p', 'param', 'pre', 'q', 'samp', 'script', 'select',
'small', 'span', 'strong', 'style', 'sub', 'sup', 'table',
'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'title',
'tr', 'tt', 'ul', 'var',

 'article', 'aside', 'audio', 'bdi', 'canvas', 'command',
'datalist', 'details', 'dialog', 'embed', 'figure', 'figcaption',
'footer', 'header', 'hgroup', 'keygen', 'mark', 'meter', 'nav',
'output', 'progress', 'ruby', 'rt', 'rp', 'track', 'section',
'source', 'summary', 'time', 'video', 'wbr'
);

foreach ($tags as $tag) {
if ($isHtml) {
$elements = self::getElementsByCaseInsensitiveTagName(
$dom,
$tag
);
} else {
$elements = $dom->getElementsByTagName($tag);
}

foreach ($elements as $element) {
$nodes[] = $element;
}
}

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


 if ($options['attributes']) {
foreach ($nodes as $node) {
$invalid = false;

foreach ($options['attributes'] as $name => $value) {

 if (preg_match('/^regexp\s*:\s*(.*)/i', $value, $matches)) {
if (!preg_match($matches[1], $node->getAttribute($name))) {
$invalid = true;
}
} 
 elseif ($name == 'class') {

 $findClasses = explode(
' ',
preg_replace("/\s+/", ' ', $value)
);

$allClasses = explode(
' ',
preg_replace("/\s+/", ' ', $node->getAttribute($name))
);


 foreach ($findClasses as $findClass) {
if (!in_array($findClass, $allClasses)) {
$invalid = true;
}
}
} 
 else {
if ($node->getAttribute($name) != $value) {
$invalid = true;
}
}
}


 if (!$invalid) {
$filtered[] = $node;
}
}

$nodes = $filtered;
$filtered = array();

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


 if ($options['content'] !== null) {
foreach ($nodes as $node) {
$invalid = false;


 if (preg_match('/^regexp\s*:\s*(.*)/i', $options['content'], $matches)) {
if (!preg_match($matches[1], self::getNodeText($node))) {
$invalid = true;
}
} 
 elseif ($options['content'] === '') {
if (self::getNodeText($node) !== '') {
$invalid = true;
}
} 
 elseif (strstr(self::getNodeText($node), $options['content']) === false) {
$invalid = true;
}

if (!$invalid) {
$filtered[] = $node;
}
}

$nodes = $filtered;
$filtered = array();

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


 if ($options['parent']) {
$parentNodes = self::findNodes($dom, $options['parent'], $isHtml);
$parentNode = isset($parentNodes[0]) ? $parentNodes[0] : null;

foreach ($nodes as $node) {
if ($parentNode !== $node->parentNode) {
continue;
}

$filtered[] = $node;
}

$nodes = $filtered;
$filtered = array();

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


 if ($options['child']) {
$childNodes = self::findNodes($dom, $options['child'], $isHtml);
$childNodes = !empty($childNodes) ? $childNodes : array();

foreach ($nodes as $node) {
foreach ($node->childNodes as $child) {
foreach ($childNodes as $childNode) {
if ($childNode === $child) {
$filtered[] = $node;
}
}
}
}

$nodes = $filtered;
$filtered = array();

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


 if ($options['adjacent-sibling']) {
$adjacentSiblingNodes = self::findNodes($dom, $options['adjacent-sibling'], $isHtml);
$adjacentSiblingNodes = !empty($adjacentSiblingNodes) ? $adjacentSiblingNodes : array();

foreach ($nodes as $node) {
$sibling = $node;

while ($sibling = $sibling->nextSibling) {
if ($sibling->nodeType !== XML_ELEMENT_NODE) {
continue;
}

foreach ($adjacentSiblingNodes as $adjacentSiblingNode) {
if ($sibling === $adjacentSiblingNode) {
$filtered[] = $node;
break;
}
}

break;
}
}

$nodes = $filtered;
$filtered = array();

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


 if ($options['ancestor']) {
$ancestorNodes = self::findNodes($dom, $options['ancestor'], $isHtml);
$ancestorNode = isset($ancestorNodes[0]) ? $ancestorNodes[0] : null;

foreach ($nodes as $node) {
$parent = $node->parentNode;

while ($parent && $parent->nodeType != XML_HTML_DOCUMENT_NODE) {
if ($parent === $ancestorNode) {
$filtered[] = $node;
}

$parent = $parent->parentNode;
}
}

$nodes = $filtered;
$filtered = array();

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


 if ($options['descendant']) {
$descendantNodes = self::findNodes($dom, $options['descendant'], $isHtml);
$descendantNodes = !empty($descendantNodes) ? $descendantNodes : array();

foreach ($nodes as $node) {
foreach (self::getDescendants($node) as $descendant) {
foreach ($descendantNodes as $descendantNode) {
if ($descendantNode === $descendant) {
$filtered[] = $node;
}
}
}
}

$nodes = $filtered;
$filtered = array();

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


 if ($options['children']) {
$validChild = array('count', 'greater_than', 'less_than', 'only');
$childOptions = self::assertValidKeys(
$options['children'],
$validChild
);

foreach ($nodes as $node) {
$childNodes = $node->childNodes;

foreach ($childNodes as $childNode) {
if ($childNode->nodeType !== XML_CDATA_SECTION_NODE &&
$childNode->nodeType !== XML_TEXT_NODE) {
$children[] = $childNode;
}
}


 if (!empty($children)) {

 if ($childOptions['count'] !== null) {
if (count($children) !== $childOptions['count']) {
break;
}
} 
 elseif ($childOptions['less_than'] !== null &&
$childOptions['greater_than'] !== null) {
if (count($children) >= $childOptions['less_than'] ||
count($children) <= $childOptions['greater_than']) {
break;
}
} 
 elseif ($childOptions['less_than'] !== null) {
if (count($children) >= $childOptions['less_than']) {
break;
}
} 
 elseif ($childOptions['greater_than'] !== null) {
if (count($children) <= $childOptions['greater_than']) {
break;
}
}


 if ($childOptions['only']) {
$onlyNodes = self::findNodes(
$dom,
$childOptions['only'],
$isHtml
);


 foreach ($children as $child) {
$matched = false;

foreach ($onlyNodes as $onlyNode) {
if ($onlyNode === $child) {
$matched = true;
}
}

if (!$matched) {
break 2;
}
}
}

$filtered[] = $node;
}
}

$nodes = $filtered;

if (empty($nodes)) {
return;
}
}


 return !empty($nodes) ? $nodes : array();
}










protected static function getDescendants(DOMNode $node)
{
$allChildren = array();
$childNodes = $node->childNodes ? $node->childNodes : array();

foreach ($childNodes as $child) {
if ($child->nodeType === XML_CDATA_SECTION_NODE ||
$child->nodeType === XML_TEXT_NODE) {
continue;
}

$children = self::getDescendants($child);
$allChildren = array_merge($allChildren, $children, array($child));
}

return isset($allChildren) ? $allChildren : array();
}











protected static function getElementsByCaseInsensitiveTagName(DOMDocument $dom, $tag)
{
$elements = $dom->getElementsByTagName(strtolower($tag));

if ($elements->length == 0) {
$elements = $dom->getElementsByTagName(strtoupper($tag));
}

return $elements;
}










protected static function getNodeText(DOMNode $node)
{
if (!$node->childNodes instanceof DOMNodeList) {
return '';
}

$result = '';

foreach ($node->childNodes as $childNode) {
if ($childNode->nodeType === XML_TEXT_NODE ||
$childNode->nodeType === XML_CDATA_SECTION_NODE) {
$result .= trim($childNode->data) . ' ';
} else {
$result .= self::getNodeText($childNode);
}
}

return str_replace('  ', ' ', $result);
}
}
<?php














class PHPUnit_Util_Fileloader
{










public static function checkAndLoad($filename)
{
$includePathFilename = stream_resolve_include_path($filename);

if (!$includePathFilename || !is_readable($includePathFilename)) {
throw new PHPUnit_Framework_Exception(
sprintf('Cannot open file "%s".' . "\n", $filename)
);
}

self::load($includePathFilename);

return $includePathFilename;
}










public static function load($filename)
{
$oldVariableNames = array_keys(get_defined_vars());

include_once $filename;

$newVariables = get_defined_vars();
$newVariableNames = array_diff(
array_keys($newVariables),
$oldVariableNames
);

foreach ($newVariableNames as $variableName) {
if ($variableName != 'oldVariableNames') {
$GLOBALS[$variableName] = $newVariables[$variableName];
}
}

return $filename;
}
}
<?php














class PHPUnit_Util_Printer
{





protected $autoFlush = false;




protected $out;




protected $outTarget;




protected $printsHTML = false;








public function __construct($out = null)
{
if ($out !== null) {
if (is_string($out)) {
if (strpos($out, 'socket://') === 0) {
$out = explode(':', str_replace('socket://', '', $out));

if (sizeof($out) != 2) {
throw new PHPUnit_Framework_Exception;
}

$this->out = fsockopen($out[0], $out[1]);
} else {
if (strpos($out, 'php://') === false &&
!is_dir(dirname($out))) {
mkdir(dirname($out), 0777, true);
}

$this->out = fopen($out, 'wt');
}

$this->outTarget = $out;
} else {
$this->out = $out;
}
}
}




public function flush()
{
if ($this->out && strncmp($this->outTarget, 'php://', 6) !== 0) {
fclose($this->out);
}

if ($this->printsHTML === true &&
$this->outTarget !== null &&
strpos($this->outTarget, 'php://') !== 0 &&
strpos($this->outTarget, 'socket://') !== 0 &&
extension_loaded('tidy')) {
file_put_contents(
$this->outTarget,
tidy_repair_file(
$this->outTarget,
array('indent' => true, 'wrap' => 0),
'utf8'
)
);
}
}










public function incrementalFlush()
{
if ($this->out) {
fflush($this->out);
} else {
flush();
}
}




public function write($buffer)
{
if ($this->out) {
fwrite($this->out, $buffer);

if ($this->autoFlush) {
$this->incrementalFlush();
}
} else {
if (PHP_SAPI != 'cli') {
$buffer = htmlspecialchars($buffer);
}

print $buffer;

if ($this->autoFlush) {
$this->incrementalFlush();
}
}
}








public function getAutoFlush()
{
return $this->autoFlush;
}











public function setAutoFlush($autoFlush)
{
if (is_bool($autoFlush)) {
$this->autoFlush = $autoFlush;
} else {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean');
}
}
}
<?php














class PHPUnit_Util_Regex
{
public static function pregMatchSafe($pattern, $subject, $matches = null, $flags = 0, $offset = 0)
{
$handler_terminator = PHPUnit_Util_ErrorHandler::handleErrorOnce(E_WARNING);
$match = preg_match($pattern, $subject, $matches, $flags, $offset);
$handler_terminator(); 

return $match;
}
}
<?php














abstract class PHPUnit_Util_TestDox_ResultPrinter extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener
{



protected $prettifier;




protected $testClass = '';




protected $testStatus = false;




protected $tests = array();




protected $successful = 0;




protected $failed = 0;




protected $risky = 0;




protected $skipped = 0;




protected $incomplete = 0;




protected $currentTestClassPrettified;




protected $currentTestMethodPrettified;






public function __construct($out = null)
{
parent::__construct($out);

$this->prettifier = new PHPUnit_Util_TestDox_NamePrettifier;
$this->startRun();
}




public function flush()
{
$this->doEndClass();
$this->endRun();

parent::flush();
}








public function addError(PHPUnit_Framework_Test $test, Exception $e, $time)
{
if (!$this->isOfInterest($test)) {
return;
}

$this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_ERROR;
$this->failed++;
}








public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time)
{
if (!$this->isOfInterest($test)) {
return;
}

$this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE;
$this->failed++;
}








public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
if (!$this->isOfInterest($test)) {
return;
}

$this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_INCOMPLETE;
$this->incomplete++;
}










public function addRiskyTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
if (!$this->isOfInterest($test)) {
return;
}

$this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_RISKY;
$this->risky++;
}










public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
if (!$this->isOfInterest($test)) {
return;
}

$this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_SKIPPED;
$this->skipped++;
}








public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
{
}








public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
{
}






public function startTest(PHPUnit_Framework_Test $test)
{
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->startClass($class);

$this->testClass = $class;
$this->tests = array();
}

$prettified = false;

$annotations = $test->getAnnotations();

if (isset($annotations['method']['testdox'][0])) {
$this->currentTestMethodPrettified = $annotations['method']['testdox'][0];
$prettified = true;
}

if (!$prettified) {
$this->currentTestMethodPrettified = $this->prettifier->prettifyTestMethod($test->getName(false));
}

$this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_PASSED;
}







public function endTest(PHPUnit_Framework_Test $test, $time)
{
if (!$this->isOfInterest($test)) {
return;
}

if (!isset($this->tests[$this->currentTestMethodPrettified])) {
if ($this->testStatus == PHPUnit_Runner_BaseTestRunner::STATUS_PASSED) {
$this->tests[$this->currentTestMethodPrettified]['success'] = 1;
$this->tests[$this->currentTestMethodPrettified]['failure'] = 0;
} else {
$this->tests[$this->currentTestMethodPrettified]['success'] = 0;
$this->tests[$this->currentTestMethodPrettified]['failure'] = 1;
}
} else {
if ($this->testStatus == PHPUnit_Runner_BaseTestRunner::STATUS_PASSED) {
$this->tests[$this->currentTestMethodPrettified]['success']++;
} else {
$this->tests[$this->currentTestMethodPrettified]['failure']++;
}
}

$this->currentTestClassPrettified = null;
$this->currentTestMethodPrettified = null;
}




protected function doEndClass()
{
foreach ($this->tests as $name => $data) {
$this->onTest($name, $data['failure'] == 0);
}

$this->endClass($this->testClass);
}




protected function startRun()
{
}






protected function startClass($name)
{
}







protected function onTest($name, $success = true)
{
}






protected function endClass($name)
{
}




protected function endRun()
{
}

private function isOfInterest(PHPUnit_Framework_Test $test)
{
return $test instanceof PHPUnit_Framework_TestCase && get_class($test) != 'PHPUnit_Framework_Warning';
}
}
<?php














class PHPUnit_Util_TestDox_ResultPrinter_Text extends PHPUnit_Util_TestDox_ResultPrinter
{





protected function startClass($name)
{
$this->write($this->currentTestClassPrettified . "\n");
}







protected function onTest($name, $success = true)
{
if ($success) {
$this->write(' [x] ');
} else {
$this->write(' [ ] ');
}

$this->write($name . "\n");
}






protected function endClass($name)
{
$this->write("\n");
}
}
<?php














class PHPUnit_Util_TestDox_ResultPrinter_HTML extends PHPUnit_Util_TestDox_ResultPrinter
{



protected $printsHTML = true;




protected function startRun()
{
$this->write('<html><body>');
}






protected function startClass($name)
{
$this->write(
'<h2 id="' . $name . '">' . $this->currentTestClassPrettified .
'</h2><ul>'
);
}







protected function onTest($name, $success = true)
{
if (!$success) {
$strikeOpen = '<span style="text-decoration:line-through;">';
$strikeClose = '</span>';
} else {
$strikeOpen = '';
$strikeClose = '';
}

$this->write('<li>' . $strikeOpen . $name . $strikeClose . '</li>');
}






protected function endClass($name)
{
$this->write('</ul>');
}




protected function endRun()
{
$this->write('</body></html>');
}
}
<?php














class PHPUnit_Util_TestDox_NamePrettifier
{



protected $prefix = 'Test';




protected $suffix = 'Test';




protected $strings = array();








public function prettifyTestClass($name)
{
$title = $name;

if ($this->suffix !== null &&
$this->suffix == substr($name, -1 * strlen($this->suffix))) {
$title = substr($title, 0, strripos($title, $this->suffix));
}

if ($this->prefix !== null &&
$this->prefix == substr($name, 0, strlen($this->prefix))) {
$title = substr($title, strlen($this->prefix));
}

if (substr($title, 0, 1) == '\\') {
$title = substr($title, 1);
}

return $title;
}








public function prettifyTestMethod($name)
{
$buffer = '';

if (!is_string($name) || strlen($name) == 0) {
return $buffer;
}

$string = preg_replace('#\d+$#', '', $name, -1, $count);

if (in_array($string, $this->strings)) {
$name = $string;
} elseif ($count == 0) {
$this->strings[] = $string;
}

if (substr($name, 0, 4) == 'test') {
$name = substr($name, 4);
}

$name[0] = strtoupper($name[0]);

if (strpos($name, '_') !== false) {
return trim(str_replace('_', ' ', $name));
}

$max = strlen($name);
$wasNumeric = false;

for ($i = 0; $i < $max; $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;
}






public function setPrefix($prefix)
{
$this->prefix = $prefix;
}






public function setSuffix($suffix)
{
$this->suffix = $suffix;
}
}
<?php












































































































































class PHPUnit_Util_Configuration
{
private static $instances = array();

protected $document;
protected $xpath;
protected $filename;






protected function __construct($filename)
{
$this->filename = $filename;
$this->document = PHPUnit_Util_XML::loadFile($filename, false, true, true);
$this->xpath = new DOMXPath($this->document);
}




final private function __clone()
{
}










public static function getInstance($filename)
{
$realpath = realpath($filename);

if ($realpath === false) {
throw new PHPUnit_Framework_Exception(
sprintf(
'Could not read "%s".',
$filename
)
);
}

if (!isset(self::$instances[$realpath])) {
self::$instances[$realpath] = new self($realpath);
}

return self::$instances[$realpath];
}








public function getFilename()
{
return $this->filename;
}








public function getFilterConfiguration()
{
$addUncoveredFilesFromWhitelist = true;
$processUncoveredFilesFromWhitelist = false;

$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
);
}
}

return array(
'blacklist' => array(
'include' => array(
'directory' => $this->readFilterDirectories(
'filter/blacklist/directory'
),
'file' => $this->readFilterFiles(
'filter/blacklist/file'
)
),
'exclude' => array(
'directory' => $this->readFilterDirectories(
'filter/blacklist/exclude/directory'
),
'file' => $this->readFilterFiles(
'filter/blacklist/exclude/file'
)
)
),
'whitelist' => array(
'addUncoveredFilesFromWhitelist' => $addUncoveredFilesFromWhitelist,
'processUncoveredFilesFromWhitelist' => $processUncoveredFilesFromWhitelist,
'include' => array(
'directory' => $this->readFilterDirectories(
'filter/whitelist/directory'
),
'file' => $this->readFilterFiles(
'filter/whitelist/file'
)
),
'exclude' => array(
'directory' => $this->readFilterDirectories(
'filter/whitelist/exclude/directory'
),
'file' => $this->readFilterFiles(
'filter/whitelist/exclude/file'
)
)
)
);
}








public function getGroupConfiguration()
{
$groups = array(
'include' => array(),
'exclude' => array()
);

foreach ($this->xpath->query('groups/include/group') as $group) {
$groups['include'][] = (string) $group->textContent;
}

foreach ($this->xpath->query('groups/exclude/group') as $group) {
$groups['exclude'][] = (string) $group->textContent;
}

return $groups;
}








public function getListenerConfiguration()
{
$result = array();

foreach ($this->xpath->query('listeners/listener') as $listener) {
$class = (string) $listener->getAttribute('class');
$file = '';
$arguments = array();

if ($listener->getAttribute('file')) {
$file = $this->toAbsolutePath(
(string) $listener->getAttribute('file'),
true
);
}

foreach ($listener->childNodes as $node) {
if ($node instanceof DOMElement && $node->tagName == 'arguments') {
foreach ($node->childNodes as $argument) {
if ($argument instanceof DOMElement) {
if ($argument->tagName == 'file' ||
$argument->tagName == 'directory') {
$arguments[] = $this->toAbsolutePath((string) $argument->textContent);
} else {
$arguments[] = PHPUnit_Util_XML::xmlToVariable($argument);
}
}
}
}
}

$result[] = array(
'class' => $class,
'file' => $file,
'arguments' => $arguments
);
}

return $result;
}






public function getLoggingConfiguration()
{
$result = array();

foreach ($this->xpath->query('logging/log') as $log) {
$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 == 'junit') {
if ($log->hasAttribute('logIncompleteSkipped')) {
$result['logIncompleteSkipped'] = $this->getBoolean(
(string) $log->getAttribute('logIncompleteSkipped'),
false
);
}
} 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()
{
$result = array(
'include_path' => array(),
'ini' => array(),
'const' => array(),
'var' => array(),
'env' => array(),
'post' => array(),
'get' => array(),
'cookie' => array(),
'server' => array(),
'files' => array(),
'request' => array()
);

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) {
$name = (string) $ini->getAttribute('name');
$value = (string) $ini->getAttribute('value');

$result['ini'][$name] = $value;
}

foreach ($this->xpath->query('php/const') as $const) {
$name = (string) $const->getAttribute('name');
$value = (string) $const->getAttribute('value');

$result['const'][$name] = $this->getBoolean($value, $value);
}

foreach (array('var', 'env', 'post', 'get', 'cookie', 'server', 'files', 'request') as $array) {
foreach ($this->xpath->query('php/' . $array) as $var) {
$name = (string) $var->getAttribute('name');
$value = (string) $var->getAttribute('value');

$result[$array][$name] = $this->getBoolean($value, $value);
}
}

return $result;
}






public function handlePHPConfiguration()
{
$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 => $value) {
if (defined($value)) {
$value = constant($value);
}

ini_set($name, $value);
}

foreach ($configuration['const'] as $name => $value) {
if (!defined($name)) {
define($name, $value);
}
}

foreach (array('var', 'post', 'get', 'cookie', 'server', 'files', 'request') as $array) {

 switch ($array) {
case 'var':
$target = &$GLOBALS;
break;

case 'server':
$target = &$_SERVER;
break;

default:
$target = &$GLOBALS['_' . strtoupper($array)];
break;
}

foreach ($configuration[$array] as $name => $value) {
$target[$name] = $value;
}
}

foreach ($configuration['env'] as $name => $value) {
if (false === getenv($name)) {
putenv("{$name}={$value}");
}
if (!isset($_ENV[$name])) {
$_ENV[$name] = $value;
}
}
}








public function getPHPUnitConfiguration()
{
$result = array();
$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'] = PHPUnit_TextUI_ResultPrinter::COLOR_AUTO;
} else {
$result['colors'] = PHPUnit_TextUI_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'),
true
);
}

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('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('mapTestClassNameToCoveredClassName')) {
$result['mapTestClassNameToCoveredClassName'] = $this->getBoolean(
(string) $root->getAttribute('mapTestClassNameToCoveredClassName'),
false
);
}

if ($root->hasAttribute('processIsolation')) {
$result['processIsolation'] = $this->getBoolean(
(string) $root->getAttribute('processIsolation'),
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('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('testSuiteLoaderClass')) {
$result['testSuiteLoaderClass'] = (string) $root->getAttribute(
'testSuiteLoaderClass'
);
}

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('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('beStrictAboutTestsThatDoNotTestAnything')) {
$result['reportUselessTests'] = $this->getBoolean(
(string) $root->getAttribute('beStrictAboutTestsThatDoNotTestAnything'),
false
);
}

if ($root->hasAttribute('checkForUnintentionallyCoveredCode')) {
$result['strictCoverage'] = $this->getBoolean(
(string) $root->getAttribute('checkForUnintentionallyCoveredCode'),
false
);
}

if ($root->hasAttribute('beStrictAboutOutputDuringTests')) {
$result['disallowTestOutput'] = $this->getBoolean(
(string) $root->getAttribute('beStrictAboutOutputDuringTests'),
false
);
}

if ($root->hasAttribute('beStrictAboutChangesToGlobalState')) {
$result['disallowChangesToGlobalState'] = $this->getBoolean(
(string) $root->getAttribute('beStrictAboutChangesToGlobalState'),
false
);
}

if ($root->hasAttribute('beStrictAboutTestSize')) {
$result['enforceTimeLimit'] = $this->getBoolean(
(string) $root->getAttribute('beStrictAboutTestSize'),
false
);
}

if ($root->hasAttribute('beStrictAboutTodoAnnotatedTests')) {
$result['disallowTodoAnnotatedTests'] = $this->getBoolean(
(string) $root->getAttribute('beStrictAboutTodoAnnotatedTests'),
false
);
}

if ($root->hasAttribute('strict')) {
$flag = $this->getBoolean(
(string) $root->getAttribute('strict'),
false
);

$result['reportUselessTests'] = $flag;
$result['strictCoverage'] = $flag;
$result['disallowTestOutput'] = $flag;
$result['enforceTimeLimit'] = $flag;
$result['disallowTodoAnnotatedTests'] = $flag;
$result['deprecatedStrictModeSetting'] = true;
}

if ($root->hasAttribute('verbose')) {
$result['verbose'] = $this->getBoolean(
(string) $root->getAttribute('verbose'),
false
);
}

return $result;
}








public function getSeleniumBrowserConfiguration()
{
$result = array();

foreach ($this->xpath->query('selenium/browser') as $config) {
$name = (string) $config->getAttribute('name');
$browser = (string) $config->getAttribute('browser');

if ($config->hasAttribute('host')) {
$host = (string) $config->getAttribute('host');
} else {
$host = 'localhost';
}

if ($config->hasAttribute('port')) {
$port = $this->getInteger(
(string) $config->getAttribute('port'),
4444
);
} else {
$port = 4444;
}

if ($config->hasAttribute('timeout')) {
$timeout = $this->getInteger(
(string) $config->getAttribute('timeout'),
30000
);
} else {
$timeout = 30000;
}

$result[] = array(
'name' => $name,
'browser' => $browser,
'host' => $host,
'port' => $port,
'timeout' => $timeout
);
}

return $result;
}








public function getTestSuiteConfiguration($testSuiteFilter = null)
{
$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);
}

if ($testSuiteNodes->length > 1) {
$suite = new PHPUnit_Framework_TestSuite;

foreach ($testSuiteNodes as $testSuiteNode) {
$suite->addTestSuite(
$this->getTestSuite($testSuiteNode, $testSuiteFilter)
);
}

return $suite;
}
}








protected function getTestSuite(DOMElement $testSuiteNode, $testSuiteFilter = null)
{
if ($testSuiteNode->hasAttribute('name')) {
$suite = new PHPUnit_Framework_TestSuite(
(string) $testSuiteNode->getAttribute('name')
);
} else {
$suite = new PHPUnit_Framework_TestSuite;
}

$exclude = array();

foreach ($testSuiteNode->getElementsByTagName('exclude') as $excludeNode) {
$excludeFile = (string) $excludeNode->textContent;
if ($excludeFile) {
$exclude[] = $this->toAbsolutePath($excludeFile);
}
}

$fileIteratorFacade = new File_Iterator_Facade;

foreach ($testSuiteNode->getElementsByTagName('directory') as $directoryNode) {
if ($testSuiteFilter && $directoryNode->parentNode->getAttribute('name') != $testSuiteFilter) {
continue;
}

$directory = (string) $directoryNode->textContent;

if (empty($directory)) {
continue;
}

if ($directoryNode->hasAttribute('phpVersion')) {
$phpVersion = (string) $directoryNode->getAttribute('phpVersion');
} else {
$phpVersion = PHP_VERSION;
}

if ($directoryNode->hasAttribute('phpVersionOperator')) {
$phpVersionOperator = (string) $directoryNode->getAttribute('phpVersionOperator');
} else {
$phpVersionOperator = '>=';
}

if (!version_compare(PHP_VERSION, $phpVersion, $phpVersionOperator)) {
continue;
}

if ($directoryNode->hasAttribute('prefix')) {
$prefix = (string) $directoryNode->getAttribute('prefix');
} else {
$prefix = '';
}

if ($directoryNode->hasAttribute('suffix')) {
$suffix = (string) $directoryNode->getAttribute('suffix');
} else {
$suffix = 'Test.php';
}

$files = $fileIteratorFacade->getFilesAsArray(
$this->toAbsolutePath($directory),
$suffix,
$prefix,
$exclude
);
$suite->addTestFiles($files);
}

foreach ($testSuiteNode->getElementsByTagName('file') as $fileNode) {
if ($testSuiteFilter && $fileNode->parentNode->getAttribute('name') != $testSuiteFilter) {
continue;
}

$file = (string) $fileNode->textContent;

if (empty($file)) {
continue;
}


 $file = $fileIteratorFacade->getFilesAsArray(
$this->toAbsolutePath($file)
);

if (!isset($file[0])) {
continue;
}

$file = $file[0];

if ($fileNode->hasAttribute('phpVersion')) {
$phpVersion = (string) $fileNode->getAttribute('phpVersion');
} else {
$phpVersion = PHP_VERSION;
}

if ($fileNode->hasAttribute('phpVersionOperator')) {
$phpVersionOperator = (string) $fileNode->getAttribute('phpVersionOperator');
} else {
$phpVersionOperator = '>=';
}

if (!version_compare(PHP_VERSION, $phpVersion, $phpVersionOperator)) {
continue;
}

$suite->addTestFile($file);
}

return $suite;
}









protected function getBoolean($value, $default)
{
if (strtolower($value) == 'false') {
return false;
} elseif (strtolower($value) == 'true') {
return true;
}

return $default;
}









protected function getInteger($value, $default)
{
if (is_numeric($value)) {
return (int) $value;
}

return $default;
}








protected function readFilterDirectories($query)
{
$directories = array();

foreach ($this->xpath->query($query) as $directory) {
$directoryPath = (string) $directory->textContent;

if (!$directoryPath) {
continue;
}

if ($directory->hasAttribute('prefix')) {
$prefix = (string) $directory->getAttribute('prefix');
} else {
$prefix = '';
}

if ($directory->hasAttribute('suffix')) {
$suffix = (string) $directory->getAttribute('suffix');
} else {
$suffix = '.php';
}

if ($directory->hasAttribute('group')) {
$group = (string) $directory->getAttribute('group');
} else {
$group = 'DEFAULT';
}

$directories[] = array(
'path' => $this->toAbsolutePath($directoryPath),
'prefix' => $prefix,
'suffix' => $suffix,
'group' => $group
);
}

return $directories;
}








protected function readFilterFiles($query)
{
$files = array();

foreach ($this->xpath->query($query) as $file) {
$filePath = (string) $file->textContent;

if ($filePath) {
$files[] = $this->toAbsolutePath($filePath);
}
}

return $files;
}









protected function toAbsolutePath($path, $useIncludePath = false)
{
$path = trim($path);

if ($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;
}
}
<?php














class PHPUnit_Util_Filesystem
{



protected static $buffer = array();












public static function classNameToFilename($className)
{
return str_replace(
array('_', '\\'),
DIRECTORY_SEPARATOR,
$className
) . '.php';
}
}
<?php














class PHPUnit_Util_Blacklist
{



public static $blacklistedClassNames = array(
'File_Iterator' => 1,
'PHP_CodeCoverage' => 1,
'PHP_Invoker' => 1,
'PHP_Timer' => 1,
'PHP_Token' => 1,
'PHPUnit_Framework_TestCase' => 2,
'PHPUnit_Extensions_Database_TestCase' => 2,
'PHPUnit_Framework_MockObject_Generator' => 2,
'PHPUnit_Extensions_SeleniumTestCase' => 2,
'Text_Template' => 1,
'Symfony\Component\Yaml\Yaml' => 1,
'SebastianBergmann\Diff\Diff' => 1,
'SebastianBergmann\Environment\Runtime' => 1,
'SebastianBergmann\Comparator\Comparator' => 1,
'SebastianBergmann\Exporter\Exporter' => 1,
'SebastianBergmann\GlobalState\Snapshot' => 1,
'SebastianBergmann\RecursionContext\Context' => 1,
'SebastianBergmann\Version' => 1,
'Composer\Autoload\ClassLoader' => 1,
'Doctrine\Instantiator\Instantiator' => 1,
'phpDocumentor\Reflection\DocBlock' => 1,
'Prophecy\Prophet' => 1
);




private static $directories;






public function getBlacklistedDirectories()
{
$this->initialize();

return self::$directories;
}






public function isBlacklisted($file)
{
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()
{
if (self::$directories === null) {
self::$directories = array();

foreach (self::$blacklistedClassNames as $className => $parent) {
if (!class_exists($className)) {
continue;
}

$reflector = new ReflectionClass($className);
$directory = $reflector->getFileName();

for ($i = 0; $i < $parent; $i++) {
$directory = dirname($directory);
}

self::$directories[] = $directory;
}


 
 
 if (DIRECTORY_SEPARATOR === '\\') {

 
 self::$directories[] = sys_get_temp_dir() . '\\PHP';
}
}
}
}
<?php












require_once dirname(__DIR__) . '/Framework/Error.php';
require_once dirname(__DIR__) . '/Framework/Error/Notice.php';
require_once dirname(__DIR__) . '/Framework/Error/Warning.php';
require_once dirname(__DIR__) . '/Framework/Error/Deprecated.php';






class PHPUnit_Util_ErrorHandler
{
protected static $errorStack = array();






public static function getErrorStack()
{
return self::$errorStack;
}









public static function handleError($errno, $errstr, $errfile, $errline)
{
if (!($errno & error_reporting())) {
return false;
}

self::$errorStack[] = array($errno, $errstr, $errfile, $errline);

$trace = debug_backtrace(false);
array_shift($trace);

foreach ($trace as $frame) {
if ($frame['function'] == '__toString') {
return false;
}
}

if ($errno == E_NOTICE || $errno == E_USER_NOTICE || $errno == E_STRICT) {
if (PHPUnit_Framework_Error_Notice::$enabled !== true) {
return false;
}

$exception = 'PHPUnit_Framework_Error_Notice';
} elseif ($errno == E_WARNING || $errno == E_USER_WARNING) {
if (PHPUnit_Framework_Error_Warning::$enabled !== true) {
return false;
}

$exception = 'PHPUnit_Framework_Error_Warning';
} elseif ($errno == E_DEPRECATED || $errno == E_USER_DEPRECATED) {
if (PHPUnit_Framework_Error_Deprecated::$enabled !== true) {
return false;
}

$exception = 'PHPUnit_Framework_Error_Deprecated';
} else {
$exception = 'PHPUnit_Framework_Error';
}

throw new $exception($errstr, $errno, $errfile, $errline);
}









public static function handleErrorOnce($severity = E_WARNING)
{
$terminator = function () {
static $expired = false;
if (!$expired) {
$expired = true;

 return restore_error_handler();
}
};

set_error_handler(function ($errno, $errstr) use ($severity) {
if ($errno === $severity) {
return;
}

return false;
});

return $terminator;
}
}
<?php














class PHPUnit_Extensions_PhptTestSuite extends PHPUnit_Framework_TestSuite
{







public function __construct($directory)
{
if (is_string($directory) && is_dir($directory)) {
$this->setName($directory);

$facade = new File_Iterator_Facade;
$files = $facade->getFilesAsArray($directory, '.phpt');

foreach ($files as $file) {
$this->addTestFile($file);
}
} else {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'directory name');
}
}
}
<?php
























class PHPUnit_Extensions_GroupTestSuite extends PHPUnit_Framework_TestSuite
{
public function __construct(PHPUnit_Framework_TestSuite $suite, array $groups)
{
$groupSuites = array();
$name = $suite->getName();

foreach ($groups as $group) {
$groupSuites[$group] = new PHPUnit_Framework_TestSuite($name . ' - ' . $group);
$this->addTest($groupSuites[$group]);
}

$tests = new RecursiveIteratorIterator(
new PHPUnit_Util_TestSuiteIterator($suite),
RecursiveIteratorIterator::LEAVES_ONLY
);

foreach ($tests as $test) {
if ($test instanceof PHPUnit_Framework_TestCase) {
$testGroups = PHPUnit_Util_Test::getGroups(
get_class($test),
$test->getName(false)
);

foreach ($groups as $group) {
foreach ($testGroups as $testGroup) {
if ($group == $testGroup) {
$groupSuites[$group]->addTest($test);
}
}
}
}
}
}
}
<?php


















class PHPUnit_Extensions_TestDecorator extends PHPUnit_Framework_Assert implements PHPUnit_Framework_Test, PHPUnit_Framework_SelfDescribing
{





protected $test = null;






public function __construct(PHPUnit_Framework_Test $test)
{
$this->test = $test;
}






public function toString()
{
return $this->test->toString();
}







public function basicRun(PHPUnit_Framework_TestResult $result)
{
$this->test->run($result);
}







public function count()
{
return count($this->test);
}






protected function createResult()
{
return new PHPUnit_Framework_TestResult;
}






public function getTest()
{
return $this->test;
}









public function run(PHPUnit_Framework_TestResult $result = null)
{
if ($result === null) {
$result = $this->createResult();
}

$this->basicRun($result);

return $result;
}
}
<?php














class PHPUnit_Extensions_PhptTestCase implements PHPUnit_Framework_Test, PHPUnit_Framework_SelfDescribing
{



private $filename;




private $settings = array(
'allow_url_fopen=1',
'auto_append_file=',
'auto_prepend_file=',
'disable_functions=',
'display_errors=1',
'docref_root=',
'docref_ext=.html',
'error_append_string=',
'error_prepend_string=',
'error_reporting=-1',
'html_errors=0',
'log_errors=0',
'magic_quotes_runtime=0',
'output_handler=',
'open_basedir=',
'output_buffering=Off',
'report_memleaks=0',
'report_zend_debug=0',
'safe_mode=0',
'track_errors=1',
'xdebug.default_enable=0'
);








public function __construct($filename)
{
if (!is_string($filename)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

if (!is_file($filename)) {
throw new PHPUnit_Framework_Exception(
sprintf(
'File "%s" does not exist.',
$filename
)
);
}

$this->filename = $filename;
}






public function count()
{
return 1;
}








public function run(PHPUnit_Framework_TestResult $result = null)
{
$sections = $this->parse();
$code = $this->render($sections['FILE']);

if ($result === null) {
$result = new PHPUnit_Framework_TestResult;
}

$php = PHPUnit_Util_PHP::factory();
$skip = false;
$time = 0;
$settings = $this->settings;

$result->startTest($this);

if (isset($sections['INI'])) {
$settings = array_merge($settings, $this->parseIniSection($sections['INI']));
}

if (isset($sections['SKIPIF'])) {
$jobResult = $php->runJob($sections['SKIPIF'], $settings);

if (!strncasecmp('skip', ltrim($jobResult['stdout']), 4)) {
if (preg_match('/^\s*skip\s*(.+)\s*/i', $jobResult['stdout'], $message)) {
$message = substr($message[1], 2);
} else {
$message = '';
}

$result->addFailure($this, new PHPUnit_Framework_SkippedTestError($message), 0);

$skip = true;
}
}

if (!$skip) {
PHP_Timer::start();
$jobResult = $php->runJob($code, $settings);
$time = PHP_Timer::stop();

if (isset($sections['EXPECT'])) {
$assertion = 'assertEquals';
$expected = $sections['EXPECT'];
} else {
$assertion = 'assertStringMatchesFormat';
$expected = $sections['EXPECTF'];
}

$output = preg_replace('/\r\n/', "\n", trim($jobResult['stdout']));
$expected = preg_replace('/\r\n/', "\n", trim($expected));

try {
PHPUnit_Framework_Assert::$assertion($expected, $output);
} catch (PHPUnit_Framework_AssertionFailedError $e) {
$result->addFailure($this, $e, $time);
} catch (Throwable $t) {
$result->addError($this, $t, $time);
} catch (Exception $e) {
$result->addError($this, $e, $time);
}
}

$result->endTest($this, $time);

return $result;
}






public function getName()
{
return $this->toString();
}






public function toString()
{
return $this->filename;
}






private function parse()
{
$sections = array();
$section = '';

foreach (file($this->filename) as $line) {
if (preg_match('/^--([_A-Z]+)--/', $line, $result)) {
$section = $result[1];
$sections[$section] = '';
continue;
} elseif (empty($section)) {
throw new PHPUnit_Framework_Exception('Invalid PHPT file');
}

$sections[$section] .= $line;
}

if (!isset($sections['FILE']) ||
(!isset($sections['EXPECT']) && !isset($sections['EXPECTF']))) {
throw new PHPUnit_Framework_Exception('Invalid PHPT file');
}

return $sections;
}






private function render($code)
{
return str_replace(
array(
'__DIR__',
'__FILE__'
),
array(
"'" . dirname($this->filename) . "'",
"'" . $this->filename . "'"
),
$code
);
}








protected function parseIniSection($content)
{
return preg_split('/\n|\r/', $content, -1, PREG_SPLIT_NO_EMPTY);
}
}
<?php














abstract class PHPUnit_Extensions_TicketListener implements PHPUnit_Framework_TestListener
{



protected $ticketCounts = array();




protected $ran = false;








public function addError(PHPUnit_Framework_Test $test, Exception $e, $time)
{
}








public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time)
{
}








public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
}










public function addRiskyTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
}










public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
}








public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
{
}








public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
{
}






public function startTest(PHPUnit_Framework_Test $test)
{
if (!$test instanceof PHPUnit_Framework_Warning) {
if ($this->ran) {
return;
}

$name = $test->getName(false);
$tickets = PHPUnit_Util_Test::getTickets(get_class($test), $name);

foreach ($tickets as $ticket) {
$this->ticketCounts[$ticket][$name] = 1;
}

$this->ran = true;
}
}







public function endTest(PHPUnit_Framework_Test $test, $time)
{
if (!$test instanceof PHPUnit_Framework_Warning) {
if ($test->getStatus() == PHPUnit_Runner_BaseTestRunner::STATUS_PASSED) {
$ifStatus = array('assigned', 'new', 'reopened');
$newStatus = 'closed';
$message = 'Automatically closed by PHPUnit (test passed).';
$resolution = 'fixed';
$cumulative = true;
} elseif ($test->getStatus() == PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE) {
$ifStatus = array('closed');
$newStatus = 'reopened';
$message = 'Automatically reopened by PHPUnit (test failed).';
$resolution = '';
$cumulative = false;
} else {
return;
}

$name = $test->getName(false);
$tickets = PHPUnit_Util_Test::getTickets(get_class($test), $name);

foreach ($tickets as $ticket) {

 if ($test->getStatus() == PHPUnit_Runner_BaseTestRunner::STATUS_PASSED) {
unset($this->ticketCounts[$ticket][$name]);
}


 
 if ($cumulative) {

 if (count($this->ticketCounts[$ticket]) > 0) {

 $adjustTicket = false;
} else {

 $adjustTicket = true;
}
} else {
$adjustTicket = true;
}

$ticketInfo = $this->getTicketInfo($ticket);

if ($adjustTicket && in_array($ticketInfo['status'], $ifStatus)) {
$this->updateTicket($ticket, $newStatus, $message, $resolution);
}
}
}
}






abstract protected function getTicketInfo($ticketId = null);







abstract protected function updateTicket($ticketId, $newStatus, $message, $resolution);
}
<?php














class PHPUnit_Extensions_RepeatedTest extends PHPUnit_Extensions_TestDecorator
{



protected $processIsolation = false;




protected $timesRepeat = 1;








public function __construct(PHPUnit_Framework_Test $test, $timesRepeat = 1, $processIsolation = false)
{
parent::__construct($test);

if (is_integer($timesRepeat) &&
$timesRepeat >= 0) {
$this->timesRepeat = $timesRepeat;
} else {
throw PHPUnit_Util_InvalidArgumentHelper::factory(
2,
'positive integer'
);
}

$this->processIsolation = $processIsolation;
}







public function count()
{
return $this->timesRepeat * count($this->test);
}











public function run(PHPUnit_Framework_TestResult $result = null)
{
if ($result === null) {
$result = $this->createResult();
}


 for ($i = 0; $i < $this->timesRepeat && !$result->shouldStop(); $i++) {

 if ($this->test instanceof PHPUnit_Framework_TestSuite) {
$this->test->setRunTestInSeparateProcess($this->processIsolation);
}
$this->test->run($result);
}

return $result;
}
}
<?php














interface PHPUnit_Runner_TestSuiteLoader
{






public function load($suiteClassName, $suiteClassFile = '');






public function reload(ReflectionClass $aClass);
}
<?php












class PHPUnit_Runner_Exception extends RuntimeException implements PHPUnit_Exception
{
}
<?php














class PHPUnit_Runner_StandardTestSuiteLoader implements PHPUnit_Runner_TestSuiteLoader
{








public function load($suiteClassName, $suiteClassFile = '')
{
$suiteClassName = str_replace('.php', '', $suiteClassName);

if (empty($suiteClassFile)) {
$suiteClassFile = PHPUnit_Util_Filesystem::classNameToFilename(
$suiteClassName
);
}

if (!class_exists($suiteClassName, false)) {
$loadedClasses = get_declared_classes();

$filename = PHPUnit_Util_Fileloader::checkAndLoad($suiteClassFile);

$loadedClasses = array_values(
array_diff(get_declared_classes(), $loadedClasses)
);
}

if (!class_exists($suiteClassName, false) && !empty($loadedClasses)) {
$offset = 0 - strlen($suiteClassName);

foreach ($loadedClasses as $loadedClass) {
$class = new ReflectionClass($loadedClass);
if (substr($loadedClass, $offset) === $suiteClassName &&
$class->getFileName() == $filename) {
$suiteClassName = $loadedClass;
break;
}
}
}

if (!class_exists($suiteClassName, false) && !empty($loadedClasses)) {
$testCaseClass = 'PHPUnit_Framework_TestCase';

foreach ($loadedClasses as $loadedClass) {
$class = new ReflectionClass($loadedClass);
$classFile = $class->getFileName();

if ($class->isSubclassOf($testCaseClass) &&
!$class->isAbstract()) {
$suiteClassName = $loadedClass;
$testCaseClass = $loadedClass;

if ($classFile == realpath($suiteClassFile)) {
break;
}
}

if ($class->hasMethod('suite')) {
$method = $class->getMethod('suite');

if (!$method->isAbstract() &&
$method->isPublic() &&
$method->isStatic()) {
$suiteClassName = $loadedClass;

if ($classFile == realpath($suiteClassFile)) {
break;
}
}
}
}
}

if (class_exists($suiteClassName, false)) {
$class = new ReflectionClass($suiteClassName);

if ($class->getFileName() == realpath($suiteClassFile)) {
return $class;
}
}

throw new PHPUnit_Framework_Exception(
sprintf(
"Class '%s' could not be found in '%s'.",
$suiteClassName,
$suiteClassFile
)
);
}






public function reload(ReflectionClass $aClass)
{
return $aClass;
}
}
<?php












class PHPUnit_Runner_Filter_Factory
{



private $filters = array();





public function addFilter(ReflectionClass $filter, $args)
{
if (!$filter->isSubclassOf('RecursiveFilterIterator')) {
throw new InvalidArgumentException(
sprintf(
'Class "%s" does not extend RecursiveFilterIterator',
$filter->name
)
);
}

$this->filters[] = array($filter, $args);
}




public function factory(Iterator $iterator, PHPUnit_Framework_TestSuite $suite)
{
foreach ($this->filters as $filter) {
list($class, $args) = $filter;
$iterator = $class->newInstance($iterator, $args, $suite);
}

return $iterator;
}
}
<?php












class PHPUnit_Runner_Filter_Test extends RecursiveFilterIterator
{



protected $filter = null;




protected $filterMin;



protected $filterMax;





public function __construct(RecursiveIterator $iterator, $filter)
{
parent::__construct($iterator);
$this->setFilter($filter);
}




protected function setFilter($filter)
{
if (PHPUnit_Util_Regex::pregMatchSafe($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 = $matches[2];
$this->filterMax = $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/', str_replace(
'/',
'\\/',
$filter
));
}

$this->filter = $filter;
}




public function accept()
{
$test = $this->getInnerIterator()->current();

if ($test instanceof PHPUnit_Framework_TestSuite) {
return true;
}

$tmp = PHPUnit_Util_Test::describe($test, false);

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 $accepted;
}
}
<?php












abstract class PHPUnit_Runner_Filter_GroupFilterIterator extends RecursiveFilterIterator
{



protected $groupTests = array();






public function __construct(RecursiveIterator $iterator, array $groups, PHPUnit_Framework_TestSuite $suite)
{
parent::__construct($iterator);

foreach ($suite->getGroupDetails() as $group => $tests) {
if (in_array($group, $groups)) {
$testHashes = array_map(
function ($test) {
return spl_object_hash($test);
},
$tests
);

$this->groupTests = array_merge($this->groupTests, $testHashes);
}
}
}




public function accept()
{
$test = $this->getInnerIterator()->current();

if ($test instanceof PHPUnit_Framework_TestSuite) {
return true;
}

return $this->doAccept(spl_object_hash($test));
}

abstract protected function doAccept($hash);
}
<?php












class PHPUnit_Runner_Filter_Group_Include extends PHPUnit_Runner_Filter_GroupFilterIterator
{
protected function doAccept($hash)
{
return in_array($hash, $this->groupTests);
}
}
<?php












class PHPUnit_Runner_Filter_Group_Exclude extends PHPUnit_Runner_Filter_GroupFilterIterator
{
protected function doAccept($hash)
{
return !in_array($hash, $this->groupTests);
}
}
<?php














abstract class PHPUnit_Runner_BaseTestRunner
{
const STATUS_PASSED = 0;
const STATUS_SKIPPED = 1;
const STATUS_INCOMPLETE = 2;
const STATUS_FAILURE = 3;
const STATUS_ERROR = 4;
const STATUS_RISKY = 5;
const SUITE_METHODNAME = 'suite';






public function getLoader()
{
return new PHPUnit_Runner_StandardTestSuiteLoader;
}












public function getTest($suiteClassName, $suiteClassFile = '', $suffixes = '')
{
if (is_dir($suiteClassName) &&
!is_file($suiteClassName . '.php') && empty($suiteClassFile)) {
$facade = new File_Iterator_Facade;
$files = $facade->getFilesAsArray(
$suiteClassName,
$suffixes
);

$suite = new PHPUnit_Framework_TestSuite($suiteClassName);
$suite->addTestFiles($files);

return $suite;
}

try {
$testClass = $this->loadSuiteClass(
$suiteClassName,
$suiteClassFile
);
} catch (PHPUnit_Framework_Exception $e) {
$this->runFailed($e->getMessage());

return;
}

try {
$suiteMethod = $testClass->getMethod(self::SUITE_METHODNAME);

if (!$suiteMethod->isStatic()) {
$this->runFailed(
'suite() method must be static.'
);

return;
}

try {
$test = $suiteMethod->invoke(null, $testClass->getName());
} catch (ReflectionException $e) {
$this->runFailed(
sprintf(
"Failed to invoke suite() method.\n%s",
$e->getMessage()
)
);

return;
}
} catch (ReflectionException $e) {
try {
$test = new PHPUnit_Framework_TestSuite($testClass);
} catch (PHPUnit_Framework_Exception $e) {
$test = new PHPUnit_Framework_TestSuite;
$test->setName($suiteClassName);
}
}

$this->clearStatus();

return $test;
}









protected function loadSuiteClass($suiteClassName, $suiteClassFile = '')
{
$loader = $this->getLoader();

return $loader->load($suiteClassName, $suiteClassFile);
}




protected function clearStatus()
{
}







abstract protected function runFailed($message);
}
<?php














class PHPUnit_Runner_Version
{
private static $pharVersion;
private static $version;






public static function id()
{
if (self::$pharVersion !== null) {
return self::$pharVersion;
}

if (self::$version === null) {
$version = new SebastianBergmann\Version('4.8.24', dirname(dirname(__DIR__)));
self::$version = $version->getVersion();
}

return self::$version;
}






public static function series()
{
if (strpos(self::id(), '-')) {
$tmp = explode('-', self::id());

return $tmp[0];
}

return implode('.', array_slice(explode('.', self::id()), 0, 2));
}




public static function getVersionString()
{
return 'PHPUnit ' . self::id() . ' by Sebastian Bergmann and contributors.';
}






public static function getReleaseChannel()
{
if (strpos(self::$pharVersion, 'alpha') !== false) {
return '-alpha';
}

if (strpos(self::$pharVersion, 'beta') !== false) {
return '-beta';
}

return '';
}
}
<?php







































class PHPUnit_Framework_TestSuite implements PHPUnit_Framework_Test, PHPUnit_Framework_SelfDescribing, IteratorAggregate
{





private $cachedNumTests;






protected $backupGlobals = null;






protected $backupStaticAttributes = null;




private $disallowChangesToGlobalState = null;




protected $runTestInSeparateProcess = false;






protected $name = '';






protected $groups = array();






protected $tests = array();






protected $numTests = -1;




protected $testCase = false;




protected $foundClasses = array();




private $iteratorFilter = null;























public function __construct($theClass = '', $name = '')
{
$argumentsValid = false;

if (is_object($theClass) &&
$theClass instanceof ReflectionClass) {
$argumentsValid = true;
} elseif (is_string($theClass) &&
$theClass !== '' &&
class_exists($theClass, false)) {
$argumentsValid = true;

if ($name == '') {
$name = $theClass;
}

$theClass = new ReflectionClass($theClass);
} elseif (is_string($theClass)) {
$this->setName($theClass);

return;
}

if (!$argumentsValid) {
throw new PHPUnit_Framework_Exception;
}

if (!$theClass->isSubclassOf('PHPUnit_Framework_TestCase')) {
throw new PHPUnit_Framework_Exception(
'Class "' . $theClass->name . '" does not extend PHPUnit_Framework_TestCase.'
);
}

if ($name != '') {
$this->setName($name);
} else {
$this->setName($theClass->getName());
}

$constructor = $theClass->getConstructor();

if ($constructor !== null &&
!$constructor->isPublic()) {
$this->addTest(
self::warning(
sprintf(
'Class "%s" has no public constructor.',
$theClass->getName()
)
)
);

return;
}

foreach ($theClass->getMethods() as $method) {
$this->addTestMethod($theClass, $method);
}

if (empty($this->tests)) {
$this->addTest(
self::warning(
sprintf(
'No tests found in class "%s".',
$theClass->getName()
)
)
);
}

$this->testCase = true;
}






public function toString()
{
return $this->getName();
}







public function addTest(PHPUnit_Framework_Test $test, $groups = array())
{
$class = new ReflectionClass($test);

if (!$class->isAbstract()) {
$this->tests[] = $test;
$this->numTests = -1;

if ($test instanceof self &&
empty($groups)) {
$groups = $test->getGroups();
}

if (empty($groups)) {
$groups = array('default');
}

foreach ($groups as $group) {
if (!isset($this->groups[$group])) {
$this->groups[$group] = array($test);
} else {
$this->groups[$group][] = $test;
}
}
}
}








public function addTestSuite($testClass)
{
if (is_string($testClass) && class_exists($testClass)) {
$testClass = new ReflectionClass($testClass);
}

if (!is_object($testClass)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(
1,
'class name or object'
);
}

if ($testClass instanceof self) {
$this->addTest($testClass);
} elseif ($testClass instanceof ReflectionClass) {
$suiteMethod = false;

if (!$testClass->isAbstract()) {
if ($testClass->hasMethod(PHPUnit_Runner_BaseTestRunner::SUITE_METHODNAME)) {
$method = $testClass->getMethod(
PHPUnit_Runner_BaseTestRunner::SUITE_METHODNAME
);

if ($method->isStatic()) {
$this->addTest(
$method->invoke(null, $testClass->getName())
);

$suiteMethod = true;
}
}
}

if (!$suiteMethod && !$testClass->isAbstract()) {
$this->addTest(new self($testClass));
}
} else {
throw new PHPUnit_Framework_Exception;
}
}















public function addTestFile($filename)
{
if (!is_string($filename)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

if (file_exists($filename) && substr($filename, -5) == '.phpt') {
$this->addTest(
new PHPUnit_Extensions_PhptTestCase($filename)
);

return;
}


 
 $classes = get_declared_classes();
$filename = PHPUnit_Util_Fileloader::checkAndLoad($filename);
$newClasses = array_diff(get_declared_classes(), $classes);


 
 
 
 if ($newClasses) {

 
 
 $this->foundClasses = array_merge($newClasses, $this->foundClasses);
}


 
 
 
 $shortname = basename($filename, '.php');
$shortnameRegEx = '/(?:^|_|\\\\)' . preg_quote($shortname, '/') . '$/';

foreach ($this->foundClasses as $i => $className) {
if (preg_match($shortnameRegEx, $className)) {
$class = new ReflectionClass($className);

if ($class->getFileName() == $filename) {
$newClasses = array($className);
unset($this->foundClasses[$i]);
break;
}
}
}

foreach ($newClasses as $className) {
$class = new ReflectionClass($className);

if (!$class->isAbstract()) {
if ($class->hasMethod(PHPUnit_Runner_BaseTestRunner::SUITE_METHODNAME)) {
$method = $class->getMethod(
PHPUnit_Runner_BaseTestRunner::SUITE_METHODNAME
);

if ($method->isStatic()) {
$this->addTest($method->invoke(null, $className));
}
} elseif ($class->implementsInterface('PHPUnit_Framework_Test')) {
$this->addTestSuite($class);
}
}
}

$this->numTests = -1;
}










public function addTestFiles($filenames)
{
if (!(is_array($filenames) ||
(is_object($filenames) && $filenames instanceof Iterator))) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(
1,
'array or iterator'
);
}

foreach ($filenames as $filename) {
$this->addTestFile((string) $filename);
}
}








public function count($preferCache = false)
{
if ($preferCache && $this->cachedNumTests != null) {
$numTests = $this->cachedNumTests;
} else {
$numTests = 0;
foreach ($this as $test) {
$numTests += count($test);
}
$this->cachedNumTests = $numTests;
}

return $numTests;
}









public static function createTest(ReflectionClass $theClass, $name)
{
$className = $theClass->getName();

if (!$theClass->isInstantiable()) {
return self::warning(
sprintf('Cannot instantiate class "%s".', $className)
);
}

$backupSettings = PHPUnit_Util_Test::getBackupSettings(
$className,
$name
);

$preserveGlobalState = PHPUnit_Util_Test::getPreserveGlobalStateSettings(
$className,
$name
);

$runTestInSeparateProcess = PHPUnit_Util_Test::getProcessIsolationSettings(
$className,
$name
);

$constructor = $theClass->getConstructor();

if ($constructor !== null) {
$parameters = $constructor->getParameters();


 if (count($parameters) < 2) {
$test = new $className;
} 
 else {
try {
$data = PHPUnit_Util_Test::getProvidedData(
$className,
$name
);
} catch (PHPUnit_Framework_IncompleteTestError $e) {
$message = sprintf(
'Test for %s::%s marked incomplete by data provider',
$className,
$name
);

$_message = $e->getMessage();

if (!empty($_message)) {
$message .= "\n" . $_message;
}

$data = self::incompleteTest($className, $name, $message);
} catch (PHPUnit_Framework_SkippedTestError $e) {
$message = sprintf(
'Test for %s::%s skipped by data provider',
$className,
$name
);

$_message = $e->getMessage();

if (!empty($_message)) {
$message .= "\n" . $_message;
}

$data = self::skipTest($className, $name, $message);
} catch (Throwable $_t) {
$t = $_t;
} catch (Exception $_t) {
$t = $_t;
}

if (isset($t)) {
$message = sprintf(
'The data provider specified for %s::%s is invalid.',
$className,
$name
);

$_message = $t->getMessage();

if (!empty($_message)) {
$message .= "\n" . $_message;
}

$data = self::warning($message);
}


 if (isset($data)) {
$test = new PHPUnit_Framework_TestSuite_DataProvider(
$className . '::' . $name
);

if (empty($data)) {
$data = self::warning(
sprintf(
'No tests found in suite "%s".',
$test->getName()
)
);
}

$groups = PHPUnit_Util_Test::getGroups($className, $name);

if ($data instanceof PHPUnit_Framework_Warning ||
$data instanceof PHPUnit_Framework_SkippedTestCase ||
$data instanceof PHPUnit_Framework_IncompleteTestCase) {
$test->addTest($data, $groups);
} else {
foreach ($data as $_dataName => $_data) {
$_test = new $className($name, $_data, $_dataName);

if ($runTestInSeparateProcess) {
$_test->setRunTestInSeparateProcess(true);

if ($preserveGlobalState !== null) {
$_test->setPreserveGlobalState($preserveGlobalState);
}
}

if ($backupSettings['backupGlobals'] !== null) {
$_test->setBackupGlobals(
$backupSettings['backupGlobals']
);
}

if ($backupSettings['backupStaticAttributes'] !== null) {
$_test->setBackupStaticAttributes(
$backupSettings['backupStaticAttributes']
);
}

$test->addTest($_test, $groups);
}
}
} else {
$test = new $className;
}
}
}

if (!isset($test)) {
throw new PHPUnit_Framework_Exception('No valid test provided.');
}

if ($test instanceof PHPUnit_Framework_TestCase) {
$test->setName($name);

if ($runTestInSeparateProcess) {
$test->setRunTestInSeparateProcess(true);

if ($preserveGlobalState !== null) {
$test->setPreserveGlobalState($preserveGlobalState);
}
}

if ($backupSettings['backupGlobals'] !== null) {
$test->setBackupGlobals($backupSettings['backupGlobals']);
}

if ($backupSettings['backupStaticAttributes'] !== null) {
$test->setBackupStaticAttributes(
$backupSettings['backupStaticAttributes']
);
}
}

return $test;
}






protected function createResult()
{
return new PHPUnit_Framework_TestResult;
}






public function getName()
{
return $this->name;
}








public function getGroups()
{
return array_keys($this->groups);
}

public function getGroupDetails()
{
return $this->groups;
}








public function setGroupDetails(array $groups)
{
$this->groups = $groups;
}








public function run(PHPUnit_Framework_TestResult $result = null)
{
if ($result === null) {
$result = $this->createResult();
}

if (count($this) == 0) {
return $result;
}

$hookMethods = PHPUnit_Util_Test::getHookMethods($this->name);

$result->startTestSuite($this);

try {
$this->setUp();

foreach ($hookMethods['beforeClass'] as $beforeClassMethod) {
if ($this->testCase === true &&
class_exists($this->name, false) &&
method_exists($this->name, $beforeClassMethod)) {
if ($missingRequirements = PHPUnit_Util_Test::getMissingRequirements($this->name, $beforeClassMethod)) {
$this->markTestSuiteSkipped(implode(PHP_EOL, $missingRequirements));
}

call_user_func(array($this->name, $beforeClassMethod));
}
}
} catch (PHPUnit_Framework_SkippedTestSuiteError $e) {
$numTests = count($this);

for ($i = 0; $i < $numTests; $i++) {
$result->startTest($this);
$result->addFailure($this, $e, 0);
$result->endTest($this, 0);
}

$this->tearDown();
$result->endTestSuite($this);

return $result;
} catch (Throwable $_t) {
$t = $_t;
} catch (Exception $_t) {
$t = $_t;
}

if (isset($t)) {
$numTests = count($this);

for ($i = 0; $i < $numTests; $i++) {
$result->startTest($this);
$result->addError($this, $t, 0);
$result->endTest($this, 0);
}

$this->tearDown();
$result->endTestSuite($this);

return $result;
}

foreach ($this as $test) {
if ($result->shouldStop()) {
break;
}

if ($test instanceof PHPUnit_Framework_TestCase ||
$test instanceof self) {
$test->setDisallowChangesToGlobalState($this->disallowChangesToGlobalState);
$test->setBackupGlobals($this->backupGlobals);
$test->setBackupStaticAttributes($this->backupStaticAttributes);
$test->setRunTestInSeparateProcess($this->runTestInSeparateProcess);
}

$test->run($result);
}

foreach ($hookMethods['afterClass'] as $afterClassMethod) {
if ($this->testCase === true && class_exists($this->name, false) && method_exists($this->name, $afterClassMethod)) {
call_user_func(array($this->name, $afterClassMethod));
}
}

$this->tearDown();

$result->endTestSuite($this);

return $result;
}








public function setRunTestInSeparateProcess($runTestInSeparateProcess)
{
if (is_bool($runTestInSeparateProcess)) {
$this->runTestInSeparateProcess = $runTestInSeparateProcess;
} else {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean');
}
}









public function runTest(PHPUnit_Framework_Test $test, PHPUnit_Framework_TestResult $result)
{
$test->run($result);
}






public function setName($name)
{
$this->name = $name;
}








public function testAt($index)
{
if (isset($this->tests[$index])) {
return $this->tests[$index];
} else {
return false;
}
}






public function tests()
{
return $this->tests;
}








public function setTests(array $tests)
{
$this->tests = $tests;
}










public function markTestSuiteSkipped($message = '')
{
throw new PHPUnit_Framework_SkippedTestSuiteError($message);
}





protected function addTestMethod(ReflectionClass $class, ReflectionMethod $method)
{
if (!$this->isTestMethod($method)) {
return;
}

$name = $method->getName();

if (!$method->isPublic()) {
$this->addTest(
self::warning(
sprintf(
'Test method "%s" in test class "%s" is not public.',
$name,
$class->getName()
)
)
);

return;
}

$test = self::createTest($class, $name);

if ($test instanceof PHPUnit_Framework_TestCase ||
$test instanceof PHPUnit_Framework_TestSuite_DataProvider) {
$test->setDependencies(
PHPUnit_Util_Test::getDependencies($class->getName(), $name)
);
}

$this->addTest(
$test,
PHPUnit_Util_Test::getGroups($class->getName(), $name)
);
}






public static function isTestMethod(ReflectionMethod $method)
{
if (strpos($method->name, 'test') === 0) {
return true;
}


 
 $doc_comment = $method->getDocComment();

return strpos($doc_comment, '@test') !== false ||
strpos($doc_comment, '@scenario') !== false;
}






protected static function warning($message)
{
return new PHPUnit_Framework_Warning($message);
}










protected static function skipTest($class, $methodName, $message)
{
return new PHPUnit_Framework_SkippedTestCase($class, $methodName, $message);
}










protected static function incompleteTest($class, $methodName, $message)
{
return new PHPUnit_Framework_IncompleteTestCase($class, $methodName, $message);
}






public function setDisallowChangesToGlobalState($disallowChangesToGlobalState)
{
if (is_null($this->disallowChangesToGlobalState) && is_bool($disallowChangesToGlobalState)) {
$this->disallowChangesToGlobalState = $disallowChangesToGlobalState;
}
}






public function setBackupGlobals($backupGlobals)
{
if (is_null($this->backupGlobals) && is_bool($backupGlobals)) {
$this->backupGlobals = $backupGlobals;
}
}






public function setBackupStaticAttributes($backupStaticAttributes)
{
if (is_null($this->backupStaticAttributes) &&
is_bool($backupStaticAttributes)) {
$this->backupStaticAttributes = $backupStaticAttributes;
}
}








public function getIterator()
{
$iterator = new PHPUnit_Util_TestSuiteIterator($this);

if ($this->iteratorFilter !== null) {
$iterator = $this->iteratorFilter->factory($iterator, $this);
}

return $iterator;
}

public function injectFilter(PHPUnit_Runner_Filter_Factory $filter)
{
$this->iteratorFilter = $filter;
foreach ($this as $test) {
if ($test instanceof self) {
$test->injectFilter($filter);
}
}
}







protected function setUp()
{
}







protected function tearDown()
{
}
}
<?php















class PHPUnit_Framework_InvalidCoversTargetError extends PHPUnit_Framework_AssertionFailedError implements PHPUnit_Framework_SkippedTest
{
}
<?php















class PHPUnit_Framework_IncompleteTestError extends PHPUnit_Framework_AssertionFailedError implements PHPUnit_Framework_IncompleteTest
{
}
<?php














interface PHPUnit_Framework_Test extends Countable
{







public function run(PHPUnit_Framework_TestResult $result = null);
}
<?php















interface PHPUnit_Framework_RiskyTest
{
}
<?php














class PHPUnit_Framework_SyntheticError extends PHPUnit_Framework_AssertionFailedError
{





protected $syntheticFile = '';






protected $syntheticLine = 0;






protected $syntheticTrace = array();










public function __construct($message, $code, $file, $line, $trace)
{
parent::__construct($message, $code);

$this->syntheticFile = $file;
$this->syntheticLine = $line;
$this->syntheticTrace = $trace;
}




public function getSyntheticFile()
{
return $this->syntheticFile;
}




public function getSyntheticLine()
{
return $this->syntheticLine;
}




public function getSyntheticTrace()
{
return $this->syntheticTrace;
}
}
<?php















interface PHPUnit_Framework_IncompleteTest
{
}
<?php




















class PHPUnit_Framework_ExceptionWrapper extends PHPUnit_Framework_Exception
{



protected $classname;




protected $previous;




public function __construct($e)
{

 
 parent::__construct($e->getMessage(), (int) $e->getCode());

$this->classname = get_class($e);
$this->file = $e->getFile();
$this->line = $e->getLine();

$this->serializableTrace = $e->getTrace();

foreach ($this->serializableTrace as $i => $call) {
unset($this->serializableTrace[$i]['args']);
}

if ($e->getPrevious()) {
$this->previous = new self($e->getPrevious());
}
}




public function getClassname()
{
return $this->classname;
}




public function getPreviousWrapped()
{
return $this->previous;
}




public function __toString()
{
$string = PHPUnit_Framework_TestFailure::exceptionToString($this);

if ($trace = PHPUnit_Util_Filter::getFilteredStacktrace($this)) {
$string .= "\n" . $trace;
}

if ($this->previous) {
$string .= "\nCaused by\n" . $this->previous;
}

return $string;
}
}
<?php















class PHPUnit_Framework_UnintentionallyCoveredCodeError extends PHPUnit_Framework_RiskyTestError
{
}
<?php












class PHPUnit_Framework_InvalidCoversTargetException extends PHPUnit_Framework_CodeCoverageException
{
}
<?php














abstract class PHPUnit_Framework_Assert
{



private static $count = 0;










public static function assertArrayHasKey($key, $array, $message = '')
{
if (!(is_integer($key) || is_string($key))) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(
1,
'integer or string'
);
}

if (!(is_array($array) || $array instanceof ArrayAccess)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(
2,
'array or ArrayAccess'
);
}

$constraint = new PHPUnit_Framework_Constraint_ArrayHasKey($key);

self::assertThat($array, $constraint, $message);
}











public static function assertArraySubset($subset, $array, $strict = false, $message = '')
{
if (!is_array($subset)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(
1,
'array or ArrayAccess'
);
}

if (!is_array($array)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(
2,
'array or ArrayAccess'
);
}

$constraint = new PHPUnit_Framework_Constraint_ArraySubset($subset, $strict);

self::assertThat($array, $constraint, $message);
}










public static function assertArrayNotHasKey($key, $array, $message = '')
{
if (!(is_integer($key) || is_string($key))) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(
1,
'integer or string'
);
}

if (!(is_array($array) || $array instanceof ArrayAccess)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(
2,
'array or ArrayAccess'
);
}

$constraint = new PHPUnit_Framework_Constraint_Not(
new PHPUnit_Framework_Constraint_ArrayHasKey($key)
);

self::assertThat($array, $constraint, $message);
}













public static function assertContains($needle, $haystack, $message = '', $ignoreCase = false, $checkForObjectIdentity = true, $checkForNonObjectIdentity = false)
{
if (is_array($haystack) ||
is_object($haystack) && $haystack instanceof Traversable) {
$constraint = new PHPUnit_Framework_Constraint_TraversableContains(
$needle,
$checkForObjectIdentity,
$checkForNonObjectIdentity
);
} elseif (is_string($haystack)) {
if (!is_string($needle)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(
1,
'string'
);
}

$constraint = new PHPUnit_Framework_Constraint_StringContains(
$needle,
$ignoreCase
);
} else {
throw PHPUnit_Util_InvalidArgumentHelper::factory(
2,
'array, traversable or string'
);
}

self::assertThat($haystack, $constraint, $message);
}















public static function assertAttributeContains($needle, $haystackAttributeName, $haystackClassOrObject, $message = '', $ignoreCase = false, $checkForObjectIdentity = true, $checkForNonObjectIdentity = false)
{
self::assertContains(
$needle,
self::readAttribute($haystackClassOrObject, $haystackAttributeName),
$message,
$ignoreCase,
$checkForObjectIdentity,
$checkForNonObjectIdentity
);
}













public static function assertNotContains($needle, $haystack, $message = '', $ignoreCase = false, $checkForObjectIdentity = true, $checkForNonObjectIdentity = false)
{
if (is_array($haystack) ||
is_object($haystack) && $haystack instanceof Traversable) {
$constraint = new PHPUnit_Framework_Constraint_Not(
new PHPUnit_Framework_Constraint_TraversableContains(
$needle,
$checkForObjectIdentity,
$checkForNonObjectIdentity
)
);
} elseif (is_string($haystack)) {
if (!is_string($needle)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(
1,
'string'
);
}

$constraint = new PHPUnit_Framework_Constraint_Not(
new PHPUnit_Framework_Constraint_StringContains(
$needle,
$ignoreCase
)
);
} else {
throw PHPUnit_Util_InvalidArgumentHelper::factory(
2,
'array, traversable or string'
);
}

self::assertThat($haystack, $constraint, $message);
}















public static function assertAttributeNotContains($needle, $haystackAttributeName, $haystackClassOrObject, $message = '', $ignoreCase = false, $checkForObjectIdentity = true, $checkForNonObjectIdentity = false)
{
self::assertNotContains(
$needle,
self::readAttribute($haystackClassOrObject, $haystackAttributeName),
$message,
$ignoreCase,
$checkForObjectIdentity,
$checkForNonObjectIdentity
);
}











public static function assertContainsOnly($type, $haystack, $isNativeType = null, $message = '')
{
if (!(is_array($haystack) ||
is_object($haystack) && $haystack instanceof Traversable)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(
2,
'array or traversable'
);
}

if ($isNativeType == null) {
$isNativeType = PHPUnit_Util_Type::isType($type);
}

self::assertThat(
$haystack,
new PHPUnit_Framework_Constraint_TraversableContainsOnly(
$type,
$isNativeType
),
$message
);
}








public static function assertContainsOnlyInstancesOf($classname, $haystack, $message = '')
{
if (!(is_array($haystack) ||
is_object($haystack) && $haystack instanceof Traversable)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(
2,
'array or traversable'
);
}

self::assertThat(
$haystack,
new PHPUnit_Framework_Constraint_TraversableContainsOnly(
$classname,
false
),
$message
);
}













public static function assertAttributeContainsOnly($type, $haystackAttributeName, $haystackClassOrObject, $isNativeType = null, $message = '')
{
self::assertContainsOnly(
$type,
self::readAttribute($haystackClassOrObject, $haystackAttributeName),
$isNativeType,
$message
);
}











public static function assertNotContainsOnly($type, $haystack, $isNativeType = null, $message = '')
{
if (!(is_array($haystack) ||
is_object($haystack) && $haystack instanceof Traversable)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(
2,
'array or traversable'
);
}

if ($isNativeType == null) {
$isNativeType = PHPUnit_Util_Type::isType($type);
}

self::assertThat(
$haystack,
new PHPUnit_Framework_Constraint_Not(
new PHPUnit_Framework_Constraint_TraversableContainsOnly(
$type,
$isNativeType
)
),
$message
);
}














public static function assertAttributeNotContainsOnly($type, $haystackAttributeName, $haystackClassOrObject, $isNativeType = null, $message = '')
{
self::assertNotContainsOnly(
$type,
self::readAttribute($haystackClassOrObject, $haystackAttributeName),
$isNativeType,
$message
);
}








public static function assertCount($expectedCount, $haystack, $message = '')
{
if (!is_int($expectedCount)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'integer');
}

if (!$haystack instanceof Countable &&
!$haystack instanceof Traversable &&
!is_array($haystack)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'countable or traversable');
}

self::assertThat(
$haystack,
new PHPUnit_Framework_Constraint_Count($expectedCount),
$message
);
}












public static function assertAttributeCount($expectedCount, $haystackAttributeName, $haystackClassOrObject, $message = '')
{
self::assertCount(
$expectedCount,
self::readAttribute($haystackClassOrObject, $haystackAttributeName),
$message
);
}








public static function assertNotCount($expectedCount, $haystack, $message = '')
{
if (!is_int($expectedCount)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'integer');
}

if (!$haystack instanceof Countable &&
!$haystack instanceof Traversable &&
!is_array($haystack)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'countable or traversable');
}

$constraint = new PHPUnit_Framework_Constraint_Not(
new PHPUnit_Framework_Constraint_Count($expectedCount)
);

self::assertThat($haystack, $constraint, $message);
}












public static function assertAttributeNotCount($expectedCount, $haystackAttributeName, $haystackClassOrObject, $message = '')
{
self::assertNotCount(
$expectedCount,
self::readAttribute($haystackClassOrObject, $haystackAttributeName),
$message
);
}












public static function assertEquals($expected, $actual, $message = '', $delta = 0.0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false)
{
$constraint = new PHPUnit_Framework_Constraint_IsEqual(
$expected,
$delta,
$maxDepth,
$canonicalize,
$ignoreCase
);

self::assertThat($actual, $constraint, $message);
}













public static function assertAttributeEquals($expected, $actualAttributeName, $actualClassOrObject, $message = '', $delta = 0.0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false)
{
self::assertEquals(
$expected,
self::readAttribute($actualClassOrObject, $actualAttributeName),
$message,
$delta,
$maxDepth,
$canonicalize,
$ignoreCase
);
}














public static function assertNotEquals($expected, $actual, $message = '', $delta = 0.0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false)
{
$constraint = new PHPUnit_Framework_Constraint_Not(
new PHPUnit_Framework_Constraint_IsEqual(
$expected,
$delta,
$maxDepth,
$canonicalize,
$ignoreCase
)
);

self::assertThat($actual, $constraint, $message);
}













public static function assertAttributeNotEquals($expected, $actualAttributeName, $actualClassOrObject, $message = '', $delta = 0.0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false)
{
self::assertNotEquals(
$expected,
self::readAttribute($actualClassOrObject, $actualAttributeName),
$message,
$delta,
$maxDepth,
$canonicalize,
$ignoreCase
);
}









public static function assertEmpty($actual, $message = '')
{
self::assertThat($actual, self::isEmpty(), $message);
}











public static function assertAttributeEmpty($haystackAttributeName, $haystackClassOrObject, $message = '')
{
self::assertEmpty(
self::readAttribute($haystackClassOrObject, $haystackAttributeName),
$message
);
}









public static function assertNotEmpty($actual, $message = '')
{
self::assertThat($actual, self::logicalNot(self::isEmpty()), $message);
}











public static function assertAttributeNotEmpty($haystackAttributeName, $haystackClassOrObject, $message = '')
{
self::assertNotEmpty(
self::readAttribute($haystackClassOrObject, $haystackAttributeName),
$message
);
}










public static function assertGreaterThan($expected, $actual, $message = '')
{
self::assertThat($actual, self::greaterThan($expected), $message);
}











public static function assertAttributeGreaterThan($expected, $actualAttributeName, $actualClassOrObject, $message = '')
{
self::assertGreaterThan(
$expected,
self::readAttribute($actualClassOrObject, $actualAttributeName),
$message
);
}










public static function assertGreaterThanOrEqual($expected, $actual, $message = '')
{
self::assertThat(
$actual,
self::greaterThanOrEqual($expected),
$message
);
}











public static function assertAttributeGreaterThanOrEqual($expected, $actualAttributeName, $actualClassOrObject, $message = '')
{
self::assertGreaterThanOrEqual(
$expected,
self::readAttribute($actualClassOrObject, $actualAttributeName),
$message
);
}










public static function assertLessThan($expected, $actual, $message = '')
{
self::assertThat($actual, self::lessThan($expected), $message);
}











public static function assertAttributeLessThan($expected, $actualAttributeName, $actualClassOrObject, $message = '')
{
self::assertLessThan(
$expected,
self::readAttribute($actualClassOrObject, $actualAttributeName),
$message
);
}










public static function assertLessThanOrEqual($expected, $actual, $message = '')
{
self::assertThat($actual, self::lessThanOrEqual($expected), $message);
}











public static function assertAttributeLessThanOrEqual($expected, $actualAttributeName, $actualClassOrObject, $message = '')
{
self::assertLessThanOrEqual(
$expected,
self::readAttribute($actualClassOrObject, $actualAttributeName),
$message
);
}













public static function assertFileEquals($expected, $actual, $message = '', $canonicalize = false, $ignoreCase = false)
{
self::assertFileExists($expected, $message);
self::assertFileExists($actual, $message);

self::assertEquals(
file_get_contents($expected),
file_get_contents($actual),
$message,
0,
10,
$canonicalize,
$ignoreCase
);
}













public static function assertFileNotEquals($expected, $actual, $message = '', $canonicalize = false, $ignoreCase = false)
{
self::assertFileExists($expected, $message);
self::assertFileExists($actual, $message);

self::assertNotEquals(
file_get_contents($expected),
file_get_contents($actual),
$message,
0,
10,
$canonicalize,
$ignoreCase
);
}













public static function assertStringEqualsFile($expectedFile, $actualString, $message = '', $canonicalize = false, $ignoreCase = false)
{
self::assertFileExists($expectedFile, $message);

self::assertEquals(
file_get_contents($expectedFile),
$actualString,
$message,
0,
10,
$canonicalize,
$ignoreCase
);
}













public static function assertStringNotEqualsFile($expectedFile, $actualString, $message = '', $canonicalize = false, $ignoreCase = false)
{
self::assertFileExists($expectedFile, $message);

self::assertNotEquals(
file_get_contents($expectedFile),
$actualString,
$message,
0,
10,
$canonicalize,
$ignoreCase
);
}









public static function assertFileExists($filename, $message = '')
{
if (!is_string($filename)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

$constraint = new PHPUnit_Framework_Constraint_FileExists;

self::assertThat($filename, $constraint, $message);
}









public static function assertFileNotExists($filename, $message = '')
{
if (!is_string($filename)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

$constraint = new PHPUnit_Framework_Constraint_Not(
new PHPUnit_Framework_Constraint_FileExists
);

self::assertThat($filename, $constraint, $message);
}









public static function assertTrue($condition, $message = '')
{
self::assertThat($condition, self::isTrue(), $message);
}









public static function assertNotTrue($condition, $message = '')
{
self::assertThat($condition, self::logicalNot(self::isTrue()), $message);
}









public static function assertFalse($condition, $message = '')
{
self::assertThat($condition, self::isFalse(), $message);
}









public static function assertNotFalse($condition, $message = '')
{
self::assertThat($condition, self::logicalNot(self::isFalse()), $message);
}







public static function assertNotNull($actual, $message = '')
{
self::assertThat($actual, self::logicalNot(self::isNull()), $message);
}







public static function assertNull($actual, $message = '')
{
self::assertThat($actual, self::isNull(), $message);
}










public static function assertClassHasAttribute($attributeName, $className, $message = '')
{
if (!is_string($attributeName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

if (!preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $attributeName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'valid attribute name');
}

if (!is_string($className) || !class_exists($className)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'class name', $className);
}

$constraint = new PHPUnit_Framework_Constraint_ClassHasAttribute(
$attributeName
);

self::assertThat($className, $constraint, $message);
}










public static function assertClassNotHasAttribute($attributeName, $className, $message = '')
{
if (!is_string($attributeName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

if (!preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $attributeName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'valid attribute name');
}

if (!is_string($className) || !class_exists($className)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'class name', $className);
}

$constraint = new PHPUnit_Framework_Constraint_Not(
new PHPUnit_Framework_Constraint_ClassHasAttribute($attributeName)
);

self::assertThat($className, $constraint, $message);
}










public static function assertClassHasStaticAttribute($attributeName, $className, $message = '')
{
if (!is_string($attributeName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

if (!preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $attributeName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'valid attribute name');
}

if (!is_string($className) || !class_exists($className)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'class name', $className);
}

$constraint = new PHPUnit_Framework_Constraint_ClassHasStaticAttribute(
$attributeName
);

self::assertThat($className, $constraint, $message);
}










public static function assertClassNotHasStaticAttribute($attributeName, $className, $message = '')
{
if (!is_string($attributeName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

if (!preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $attributeName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'valid attribute name');
}

if (!is_string($className) || !class_exists($className)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'class name', $className);
}

$constraint = new PHPUnit_Framework_Constraint_Not(
new PHPUnit_Framework_Constraint_ClassHasStaticAttribute(
$attributeName
)
);

self::assertThat($className, $constraint, $message);
}










public static function assertObjectHasAttribute($attributeName, $object, $message = '')
{
if (!is_string($attributeName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

if (!preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $attributeName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'valid attribute name');
}

if (!is_object($object)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'object');
}

$constraint = new PHPUnit_Framework_Constraint_ObjectHasAttribute(
$attributeName
);

self::assertThat($object, $constraint, $message);
}










public static function assertObjectNotHasAttribute($attributeName, $object, $message = '')
{
if (!is_string($attributeName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

if (!preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $attributeName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'valid attribute name');
}

if (!is_object($object)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'object');
}

$constraint = new PHPUnit_Framework_Constraint_Not(
new PHPUnit_Framework_Constraint_ObjectHasAttribute($attributeName)
);

self::assertThat($object, $constraint, $message);
}










public static function assertSame($expected, $actual, $message = '')
{
if (is_bool($expected) && is_bool($actual)) {
self::assertEquals($expected, $actual, $message);
} else {
$constraint = new PHPUnit_Framework_Constraint_IsIdentical(
$expected
);

self::assertThat($actual, $constraint, $message);
}
}










public static function assertAttributeSame($expected, $actualAttributeName, $actualClassOrObject, $message = '')
{
self::assertSame(
$expected,
self::readAttribute($actualClassOrObject, $actualAttributeName),
$message
);
}










public static function assertNotSame($expected, $actual, $message = '')
{
if (is_bool($expected) && is_bool($actual)) {
self::assertNotEquals($expected, $actual, $message);
} else {
$constraint = new PHPUnit_Framework_Constraint_Not(
new PHPUnit_Framework_Constraint_IsIdentical($expected)
);

self::assertThat($actual, $constraint, $message);
}
}










public static function assertAttributeNotSame($expected, $actualAttributeName, $actualClassOrObject, $message = '')
{
self::assertNotSame(
$expected,
self::readAttribute($actualClassOrObject, $actualAttributeName),
$message
);
}










public static function assertInstanceOf($expected, $actual, $message = '')
{
if (!(is_string($expected) && (class_exists($expected) || interface_exists($expected)))) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'class or interface name');
}

$constraint = new PHPUnit_Framework_Constraint_IsInstanceOf(
$expected
);

self::assertThat($actual, $constraint, $message);
}











public static function assertAttributeInstanceOf($expected, $attributeName, $classOrObject, $message = '')
{
self::assertInstanceOf(
$expected,
self::readAttribute($classOrObject, $attributeName),
$message
);
}










public static function assertNotInstanceOf($expected, $actual, $message = '')
{
if (!(is_string($expected) && (class_exists($expected) || interface_exists($expected)))) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'class or interface name');
}

$constraint = new PHPUnit_Framework_Constraint_Not(
new PHPUnit_Framework_Constraint_IsInstanceOf($expected)
);

self::assertThat($actual, $constraint, $message);
}











public static function assertAttributeNotInstanceOf($expected, $attributeName, $classOrObject, $message = '')
{
self::assertNotInstanceOf(
$expected,
self::readAttribute($classOrObject, $attributeName),
$message
);
}










public static function assertInternalType($expected, $actual, $message = '')
{
if (!is_string($expected)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

$constraint = new PHPUnit_Framework_Constraint_IsType(
$expected
);

self::assertThat($actual, $constraint, $message);
}











public static function assertAttributeInternalType($expected, $attributeName, $classOrObject, $message = '')
{
self::assertInternalType(
$expected,
self::readAttribute($classOrObject, $attributeName),
$message
);
}










public static function assertNotInternalType($expected, $actual, $message = '')
{
if (!is_string($expected)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

$constraint = new PHPUnit_Framework_Constraint_Not(
new PHPUnit_Framework_Constraint_IsType($expected)
);

self::assertThat($actual, $constraint, $message);
}











public static function assertAttributeNotInternalType($expected, $attributeName, $classOrObject, $message = '')
{
self::assertNotInternalType(
$expected,
self::readAttribute($classOrObject, $attributeName),
$message
);
}








public static function assertRegExp($pattern, $string, $message = '')
{
if (!is_string($pattern)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

if (!is_string($string)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string');
}

$constraint = new PHPUnit_Framework_Constraint_PCREMatch($pattern);

self::assertThat($string, $constraint, $message);
}










public static function assertNotRegExp($pattern, $string, $message = '')
{
if (!is_string($pattern)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

if (!is_string($string)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string');
}

$constraint = new PHPUnit_Framework_Constraint_Not(
new PHPUnit_Framework_Constraint_PCREMatch($pattern)
);

self::assertThat($string, $constraint, $message);
}









public static function assertSameSize($expected, $actual, $message = '')
{
if (!$expected instanceof Countable &&
!$expected instanceof Traversable &&
!is_array($expected)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'countable or traversable');
}

if (!$actual instanceof Countable &&
!$actual instanceof Traversable &&
!is_array($actual)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'countable or traversable');
}

self::assertThat(
$actual,
new PHPUnit_Framework_Constraint_SameSize($expected),
$message
);
}









public static function assertNotSameSize($expected, $actual, $message = '')
{
if (!$expected instanceof Countable &&
!$expected instanceof Traversable &&
!is_array($expected)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'countable or traversable');
}

if (!$actual instanceof Countable &&
!$actual instanceof Traversable &&
!is_array($actual)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'countable or traversable');
}

$constraint = new PHPUnit_Framework_Constraint_Not(
new PHPUnit_Framework_Constraint_SameSize($expected)
);

self::assertThat($actual, $constraint, $message);
}










public static function assertStringMatchesFormat($format, $string, $message = '')
{
if (!is_string($format)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

if (!is_string($string)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string');
}

$constraint = new PHPUnit_Framework_Constraint_StringMatches($format);

self::assertThat($string, $constraint, $message);
}










public static function assertStringNotMatchesFormat($format, $string, $message = '')
{
if (!is_string($format)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

if (!is_string($string)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string');
}

$constraint = new PHPUnit_Framework_Constraint_Not(
new PHPUnit_Framework_Constraint_StringMatches($format)
);

self::assertThat($string, $constraint, $message);
}










public static function assertStringMatchesFormatFile($formatFile, $string, $message = '')
{
self::assertFileExists($formatFile, $message);

if (!is_string($string)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string');
}

$constraint = new PHPUnit_Framework_Constraint_StringMatches(
file_get_contents($formatFile)
);

self::assertThat($string, $constraint, $message);
}










public static function assertStringNotMatchesFormatFile($formatFile, $string, $message = '')
{
self::assertFileExists($formatFile, $message);

if (!is_string($string)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string');
}

$constraint = new PHPUnit_Framework_Constraint_Not(
new PHPUnit_Framework_Constraint_StringMatches(
file_get_contents($formatFile)
)
);

self::assertThat($string, $constraint, $message);
}










public static function assertStringStartsWith($prefix, $string, $message = '')
{
if (!is_string($prefix)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

if (!is_string($string)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string');
}

$constraint = new PHPUnit_Framework_Constraint_StringStartsWith(
$prefix
);

self::assertThat($string, $constraint, $message);
}










public static function assertStringStartsNotWith($prefix, $string, $message = '')
{
if (!is_string($prefix)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

if (!is_string($string)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string');
}

$constraint = new PHPUnit_Framework_Constraint_Not(
new PHPUnit_Framework_Constraint_StringStartsWith($prefix)
);

self::assertThat($string, $constraint, $message);
}










public static function assertStringEndsWith($suffix, $string, $message = '')
{
if (!is_string($suffix)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

if (!is_string($string)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string');
}

$constraint = new PHPUnit_Framework_Constraint_StringEndsWith($suffix);

self::assertThat($string, $constraint, $message);
}










public static function assertStringEndsNotWith($suffix, $string, $message = '')
{
if (!is_string($suffix)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

if (!is_string($string)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string');
}

$constraint = new PHPUnit_Framework_Constraint_Not(
new PHPUnit_Framework_Constraint_StringEndsWith($suffix)
);

self::assertThat($string, $constraint, $message);
}










public static function assertXmlFileEqualsXmlFile($expectedFile, $actualFile, $message = '')
{
$expected = PHPUnit_Util_XML::loadFile($expectedFile);
$actual = PHPUnit_Util_XML::loadFile($actualFile);

self::assertEquals($expected, $actual, $message);
}










public static function assertXmlFileNotEqualsXmlFile($expectedFile, $actualFile, $message = '')
{
$expected = PHPUnit_Util_XML::loadFile($expectedFile);
$actual = PHPUnit_Util_XML::loadFile($actualFile);

self::assertNotEquals($expected, $actual, $message);
}










public static function assertXmlStringEqualsXmlFile($expectedFile, $actualXml, $message = '')
{
$expected = PHPUnit_Util_XML::loadFile($expectedFile);
$actual = PHPUnit_Util_XML::load($actualXml);

self::assertEquals($expected, $actual, $message);
}










public static function assertXmlStringNotEqualsXmlFile($expectedFile, $actualXml, $message = '')
{
$expected = PHPUnit_Util_XML::loadFile($expectedFile);
$actual = PHPUnit_Util_XML::load($actualXml);

self::assertNotEquals($expected, $actual, $message);
}










public static function assertXmlStringEqualsXmlString($expectedXml, $actualXml, $message = '')
{
$expected = PHPUnit_Util_XML::load($expectedXml);
$actual = PHPUnit_Util_XML::load($actualXml);

self::assertEquals($expected, $actual, $message);
}










public static function assertXmlStringNotEqualsXmlString($expectedXml, $actualXml, $message = '')
{
$expected = PHPUnit_Util_XML::load($expectedXml);
$actual = PHPUnit_Util_XML::load($actualXml);

self::assertNotEquals($expected, $actual, $message);
}











public static function assertEqualXMLStructure(DOMElement $expectedElement, DOMElement $actualElement, $checkAttributes = false, $message = '')
{
$tmp = new DOMDocument;
$expectedElement = $tmp->importNode($expectedElement, true);

$tmp = new DOMDocument;
$actualElement = $tmp->importNode($actualElement, true);

unset($tmp);

self::assertEquals(
$expectedElement->tagName,
$actualElement->tagName,
$message
);

if ($checkAttributes) {
self::assertEquals(
$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
);

if (!$actualAttribute) {
self::fail(
sprintf(
'%s%sCould not find attribute "%s" on node "%s"',
$message,
!empty($message) ? "\n" : '',
$expectedAttribute->name,
$expectedElement->tagName
)
);
}
}
}

PHPUnit_Util_XML::removeCharacterDataNodes($expectedElement);
PHPUnit_Util_XML::removeCharacterDataNodes($actualElement);

self::assertEquals(
$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++) {
self::assertEqualXMLStructure(
$expectedElement->childNodes->item($i),
$actualElement->childNodes->item($i),
$checkAttributes,
$message
);
}
}


























public static function assertSelectCount($selector, $count, $actual, $message = '', $isHtml = true)
{
trigger_error(__METHOD__ . ' is deprecated', E_USER_DEPRECATED);

self::assertSelectEquals(
$selector,
true,
$count,
$actual,
$message,
$isHtml
);
}
















public static function assertSelectRegExp($selector, $pattern, $count, $actual, $message = '', $isHtml = true)
{
trigger_error(__METHOD__ . ' is deprecated', E_USER_DEPRECATED);

self::assertSelectEquals(
$selector,
"regexp:$pattern",
$count,
$actual,
$message,
$isHtml
);
}
















public static function assertSelectEquals($selector, $content, $count, $actual, $message = '', $isHtml = true)
{
trigger_error(__METHOD__ . ' is deprecated', E_USER_DEPRECATED);

$tags = PHPUnit_Util_XML::cssSelect(
$selector,
$content,
$actual,
$isHtml
);


 if (is_numeric($count)) {
$counted = $tags ? count($tags) : 0;
self::assertEquals($count, $counted, $message);
} 
 elseif (is_bool($count)) {
$any = count($tags) > 0 && $tags[0] instanceof DOMNode;

if ($count) {
self::assertTrue($any, $message);
} else {
self::assertFalse($any, $message);
}
} 
 elseif (is_array($count) &&
(isset($count['>']) || isset($count['<']) ||
isset($count['>=']) || isset($count['<=']))) {
$counted = $tags ? count($tags) : 0;

if (isset($count['>'])) {
self::assertTrue($counted > $count['>'], $message);
}

if (isset($count['>='])) {
self::assertTrue($counted >= $count['>='], $message);
}

if (isset($count['<'])) {
self::assertTrue($counted < $count['<'], $message);
}

if (isset($count['<='])) {
self::assertTrue($counted <= $count['<='], $message);
}
} else {
throw new PHPUnit_Framework_Exception;
}
}











































































































































public static function assertTag($matcher, $actual, $message = '', $isHtml = true)
{
trigger_error(__METHOD__ . ' is deprecated', E_USER_DEPRECATED);

$dom = PHPUnit_Util_XML::load($actual, $isHtml);
$tags = PHPUnit_Util_XML::findNodes($dom, $matcher, $isHtml);
$matched = count($tags) > 0 && $tags[0] instanceof DOMNode;

self::assertTrue($matched, $message);
}
















public static function assertNotTag($matcher, $actual, $message = '', $isHtml = true)
{
trigger_error(__METHOD__ . ' is deprecated', E_USER_DEPRECATED);

$dom = PHPUnit_Util_XML::load($actual, $isHtml);
$tags = PHPUnit_Util_XML::findNodes($dom, $matcher, $isHtml);
$matched = count($tags) > 0 && $tags[0] instanceof DOMNode;

self::assertFalse($matched, $message);
}










public static function assertThat($value, PHPUnit_Framework_Constraint $constraint, $message = '')
{
self::$count += count($constraint);

$constraint->evaluate($value, $message);
}









public static function assertJson($actualJson, $message = '')
{
if (!is_string($actualJson)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

self::assertThat($actualJson, self::isJson(), $message);
}








public static function assertJsonStringEqualsJsonString($expectedJson, $actualJson, $message = '')
{
self::assertJson($expectedJson, $message);
self::assertJson($actualJson, $message);

$expected = json_decode($expectedJson);
$actual = json_decode($actualJson);

self::assertEquals($expected, $actual, $message);
}








public static function assertJsonStringNotEqualsJsonString($expectedJson, $actualJson, $message = '')
{
self::assertJson($expectedJson, $message);
self::assertJson($actualJson, $message);

$expected = json_decode($expectedJson);
$actual = json_decode($actualJson);

self::assertNotEquals($expected, $actual, $message);
}








public static function assertJsonStringEqualsJsonFile($expectedFile, $actualJson, $message = '')
{
self::assertFileExists($expectedFile, $message);
$expectedJson = file_get_contents($expectedFile);

self::assertJson($expectedJson, $message);
self::assertJson($actualJson, $message);


 $constraint = new PHPUnit_Framework_Constraint_JsonMatches(
$expectedJson
);

self::assertThat($actualJson, $constraint, $message);
}








public static function assertJsonStringNotEqualsJsonFile($expectedFile, $actualJson, $message = '')
{
self::assertFileExists($expectedFile, $message);
$expectedJson = file_get_contents($expectedFile);

self::assertJson($expectedJson, $message);
self::assertJson($actualJson, $message);


 $constraint = new PHPUnit_Framework_Constraint_JsonMatches(
$expectedJson
);

self::assertThat($actualJson, new PHPUnit_Framework_Constraint_Not($constraint), $message);
}








public static function assertJsonFileNotEqualsJsonFile($expectedFile, $actualFile, $message = '')
{
self::assertFileExists($expectedFile, $message);
self::assertFileExists($actualFile, $message);

$actualJson = file_get_contents($actualFile);
$expectedJson = file_get_contents($expectedFile);

self::assertJson($expectedJson, $message);
self::assertJson($actualJson, $message);


 $constraintExpected = new PHPUnit_Framework_Constraint_JsonMatches(
$expectedJson
);

$constraintActual = new PHPUnit_Framework_Constraint_JsonMatches($actualJson);

self::assertThat($expectedJson, new PHPUnit_Framework_Constraint_Not($constraintActual), $message);
self::assertThat($actualJson, new PHPUnit_Framework_Constraint_Not($constraintExpected), $message);
}








public static function assertJsonFileEqualsJsonFile($expectedFile, $actualFile, $message = '')
{
self::assertFileExists($expectedFile, $message);
self::assertFileExists($actualFile, $message);

$actualJson = file_get_contents($actualFile);
$expectedJson = file_get_contents($expectedFile);

self::assertJson($expectedJson, $message);
self::assertJson($actualJson, $message);


 $constraintExpected = new PHPUnit_Framework_Constraint_JsonMatches(
$expectedJson
);

$constraintActual = new PHPUnit_Framework_Constraint_JsonMatches($actualJson);

self::assertThat($expectedJson, $constraintActual, $message);
self::assertThat($actualJson, $constraintExpected, $message);
}








public static function logicalAnd()
{
$constraints = func_get_args();

$constraint = new PHPUnit_Framework_Constraint_And;
$constraint->setConstraints($constraints);

return $constraint;
}








public static function logicalOr()
{
$constraints = func_get_args();

$constraint = new PHPUnit_Framework_Constraint_Or;
$constraint->setConstraints($constraints);

return $constraint;
}










public static function logicalNot(PHPUnit_Framework_Constraint $constraint)
{
return new PHPUnit_Framework_Constraint_Not($constraint);
}








public static function logicalXor()
{
$constraints = func_get_args();

$constraint = new PHPUnit_Framework_Constraint_Xor;
$constraint->setConstraints($constraints);

return $constraint;
}








public static function anything()
{
return new PHPUnit_Framework_Constraint_IsAnything;
}








public static function isTrue()
{
return new PHPUnit_Framework_Constraint_IsTrue;
}








public static function callback($callback)
{
return new PHPUnit_Framework_Constraint_Callback($callback);
}








public static function isFalse()
{
return new PHPUnit_Framework_Constraint_IsFalse;
}








public static function isJson()
{
return new PHPUnit_Framework_Constraint_IsJson;
}








public static function isNull()
{
return new PHPUnit_Framework_Constraint_IsNull;
}











public static function attribute(PHPUnit_Framework_Constraint $constraint, $attributeName)
{
return new PHPUnit_Framework_Constraint_Attribute(
$constraint,
$attributeName
);
}













public static function contains($value, $checkForObjectIdentity = true, $checkForNonObjectIdentity = false)
{
return new PHPUnit_Framework_Constraint_TraversableContains($value, $checkForObjectIdentity, $checkForNonObjectIdentity);
}











public static function containsOnly($type)
{
return new PHPUnit_Framework_Constraint_TraversableContainsOnly($type);
}









public static function containsOnlyInstancesOf($classname)
{
return new PHPUnit_Framework_Constraint_TraversableContainsOnly($classname, false);
}










public static function arrayHasKey($key)
{
return new PHPUnit_Framework_Constraint_ArrayHasKey($key);
}














public static function equalTo($value, $delta = 0.0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false)
{
return new PHPUnit_Framework_Constraint_IsEqual(
$value,
$delta,
$maxDepth,
$canonicalize,
$ignoreCase
);
}

















public static function attributeEqualTo($attributeName, $value, $delta = 0.0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false)
{
return self::attribute(
self::equalTo(
$value,
$delta,
$maxDepth,
$canonicalize,
$ignoreCase
),
$attributeName
);
}








public static function isEmpty()
{
return new PHPUnit_Framework_Constraint_IsEmpty;
}








public static function fileExists()
{
return new PHPUnit_Framework_Constraint_FileExists;
}










public static function greaterThan($value)
{
return new PHPUnit_Framework_Constraint_GreaterThan($value);
}












public static function greaterThanOrEqual($value)
{
return self::logicalOr(
new PHPUnit_Framework_Constraint_IsEqual($value),
new PHPUnit_Framework_Constraint_GreaterThan($value)
);
}










public static function classHasAttribute($attributeName)
{
return new PHPUnit_Framework_Constraint_ClassHasAttribute(
$attributeName
);
}











public static function classHasStaticAttribute($attributeName)
{
return new PHPUnit_Framework_Constraint_ClassHasStaticAttribute(
$attributeName
);
}










public static function objectHasAttribute($attributeName)
{
return new PHPUnit_Framework_Constraint_ObjectHasAttribute(
$attributeName
);
}










public static function identicalTo($value)
{
return new PHPUnit_Framework_Constraint_IsIdentical($value);
}










public static function isInstanceOf($className)
{
return new PHPUnit_Framework_Constraint_IsInstanceOf($className);
}










public static function isType($type)
{
return new PHPUnit_Framework_Constraint_IsType($type);
}










public static function lessThan($value)
{
return new PHPUnit_Framework_Constraint_LessThan($value);
}












public static function lessThanOrEqual($value)
{
return self::logicalOr(
new PHPUnit_Framework_Constraint_IsEqual($value),
new PHPUnit_Framework_Constraint_LessThan($value)
);
}










public static function matchesRegularExpression($pattern)
{
return new PHPUnit_Framework_Constraint_PCREMatch($pattern);
}










public static function matches($string)
{
return new PHPUnit_Framework_Constraint_StringMatches($string);
}










public static function stringStartsWith($prefix)
{
return new PHPUnit_Framework_Constraint_StringStartsWith($prefix);
}











public static function stringContains($string, $case = true)
{
return new PHPUnit_Framework_Constraint_StringContains($string, $case);
}










public static function stringEndsWith($suffix)
{
return new PHPUnit_Framework_Constraint_StringEndsWith($suffix);
}








public static function countOf($count)
{
return new PHPUnit_Framework_Constraint_Count($count);
}







public static function fail($message = '')
{
throw new PHPUnit_Framework_AssertionFailedError($message);
}












public static function readAttribute($classOrObject, $attributeName)
{
if (!is_string($attributeName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string');
}

if (!preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $attributeName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'valid attribute name');
}

if (is_string($classOrObject)) {
if (!class_exists($classOrObject)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(
1,
'class name'
);
}

return self::getStaticAttribute(
$classOrObject,
$attributeName
);
} elseif (is_object($classOrObject)) {
return self::getObjectAttribute(
$classOrObject,
$attributeName
);
} else {
throw PHPUnit_Util_InvalidArgumentHelper::factory(
1,
'class name or object'
);
}
}














public static function getStaticAttribute($className, $attributeName)
{
if (!is_string($className)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

if (!class_exists($className)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'class name');
}

if (!is_string($attributeName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string');
}

if (!preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $attributeName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'valid attribute name');
}

$class = new ReflectionClass($className);

while ($class) {
$attributes = $class->getStaticProperties();

if (array_key_exists($attributeName, $attributes)) {
return $attributes[$attributeName];
}

$class = $class->getParentClass();
}

throw new PHPUnit_Framework_Exception(
sprintf(
'Attribute "%s" not found in class.',
$attributeName
)
);
}














public static function getObjectAttribute($object, $attributeName)
{
if (!is_object($object)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'object');
}

if (!is_string($attributeName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string');
}

if (!preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $attributeName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'valid attribute name');
}

try {
$attribute = new ReflectionProperty($object, $attributeName);
} catch (ReflectionException $e) {
$reflector = new ReflectionObject($object);

while ($reflector = $reflector->getParentClass()) {
try {
$attribute = $reflector->getProperty($attributeName);
break;
} catch (ReflectionException $e) {
}
}
}

if (isset($attribute)) {
if (!$attribute || $attribute->isPublic()) {
return $object->$attributeName;
}

$attribute->setAccessible(true);
$value = $attribute->getValue($object);
$attribute->setAccessible(false);

return $value;
}

throw new PHPUnit_Framework_Exception(
sprintf(
'Attribute "%s" not found in object.',
$attributeName
)
);
}










public static function markTestIncomplete($message = '')
{
throw new PHPUnit_Framework_IncompleteTestError($message);
}










public static function markTestSkipped($message = '')
{
throw new PHPUnit_Framework_SkippedTestError($message);
}








public static function getCount()
{
return self::$count;
}






public static function resetCount()
{
self::$count = 0;
}
}
<?php









use SebastianBergmann\GlobalState\Snapshot;
use SebastianBergmann\GlobalState\Restorer;
use SebastianBergmann\GlobalState\Blacklist;
use SebastianBergmann\Diff\Differ;
use SebastianBergmann\Exporter\Exporter;
use Prophecy\Exception\Prediction\PredictionException;
use Prophecy\Prophet;















































abstract class PHPUnit_Framework_TestCase extends PHPUnit_Framework_Assert implements PHPUnit_Framework_Test, PHPUnit_Framework_SelfDescribing
{







protected $backupGlobals = null;




protected $backupGlobalsBlacklist = array();








protected $backupStaticAttributes = null;




protected $backupStaticAttributesBlacklist = array();






protected $runTestInSeparateProcess = null;







protected $preserveGlobalState = true;






private $inIsolation = false;




private $data = array();




private $dataName = '';




private $useErrorHandler = null;






private $expectedException = null;






private $expectedExceptionMessage = '';






private $expectedExceptionMessageRegExp = '';






private $expectedExceptionCode;






private $name = null;




private $dependencies = array();




private $dependencyInput = array();




private $iniSettings = array();




private $locale = array();




private $mockObjects = array();




private $mockObjectGenerator = null;




private $status;




private $statusMessage = '';




private $numAssertions = 0;




private $result;




private $testResult;




private $output = '';




private $outputExpectedRegex = null;




private $outputExpectedString = null;




private $outputCallback = false;




private $outputBufferingActive = false;




private $outputBufferingLevel;




private $snapshot;




private $prophet;




private $disallowChangesToGlobalState = false;








public function __construct($name = null, array $data = array(), $dataName = '')
{
if ($name !== null) {
$this->setName($name);
}

$this->data = $data;
$this->dataName = $dataName;
}






public function toString()
{
$class = new ReflectionClass($this);

$buffer = sprintf(
'%s::%s',
$class->name,
$this->getName(false)
);

return $buffer . $this->getDataSetAsString();
}






public function count()
{
return 1;
}








public function getAnnotations()
{
return PHPUnit_Util_Test::parseTestMethodAnnotations(
get_class($this),
$this->name
);
}








public function getName($withDataSet = true)
{
if ($withDataSet) {
return $this->name . $this->getDataSetAsString(false);
} else {
return $this->name;
}
}








public function getSize()
{
return PHPUnit_Util_Test::getSize(
get_class($this),
$this->getName(false)
);
}






public function getActualOutput()
{
if (!$this->outputBufferingActive) {
return $this->output;
} else {
return ob_get_contents();
}
}






public function hasOutput()
{
if (strlen($this->output) === 0) {
return false;
}

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

return true;
}








public function expectOutputRegex($expectedRegex)
{
if ($this->outputExpectedString !== null) {
throw new PHPUnit_Framework_Exception;
}

if (is_string($expectedRegex) || is_null($expectedRegex)) {
$this->outputExpectedRegex = $expectedRegex;
}
}






public function expectOutputString($expectedString)
{
if ($this->outputExpectedRegex !== null) {
throw new PHPUnit_Framework_Exception;
}

if (is_string($expectedString) || is_null($expectedString)) {
$this->outputExpectedString = $expectedString;
}
}







public function hasPerformedExpectationsOnOutput()
{
return $this->hasExpectationOnOutput();
}






public function hasExpectationOnOutput()
{
return is_string($this->outputExpectedString) || is_string($this->outputExpectedRegex);
}






public function getExpectedException()
{
return $this->expectedException;
}








public function setExpectedException($exceptionName, $exceptionMessage = '', $exceptionCode = null)
{
$this->expectedException = $exceptionName;
$this->expectedExceptionMessage = $exceptionMessage;
$this->expectedExceptionCode = $exceptionCode;
}








public function setExpectedExceptionRegExp($exceptionName, $exceptionMessageRegExp = '', $exceptionCode = null)
{
$this->expectedException = $exceptionName;
$this->expectedExceptionMessageRegExp = $exceptionMessageRegExp;
$this->expectedExceptionCode = $exceptionCode;
}




protected function setExpectedExceptionFromAnnotation()
{
try {
$expectedException = PHPUnit_Util_Test::getExpectedException(
get_class($this),
$this->name
);

if ($expectedException !== false) {
$this->setExpectedException(
$expectedException['class'],
$expectedException['message'],
$expectedException['code']
);

if (!empty($expectedException['message_regex'])) {
$this->setExpectedExceptionRegExp(
$expectedException['class'],
$expectedException['message_regex'],
$expectedException['code']
);
}
}
} catch (ReflectionException $e) {
}
}






public function setUseErrorHandler($useErrorHandler)
{
$this->useErrorHandler = $useErrorHandler;
}




protected function setUseErrorHandlerFromAnnotation()
{
try {
$useErrorHandler = PHPUnit_Util_Test::getErrorHandlerSettings(
get_class($this),
$this->name
);

if ($useErrorHandler !== null) {
$this->setUseErrorHandler($useErrorHandler);
}
} catch (ReflectionException $e) {
}
}




protected function checkRequirements()
{
if (!$this->name || !method_exists($this, $this->name)) {
return;
}

$missingRequirements = PHPUnit_Util_Test::getMissingRequirements(
get_class($this),
$this->name
);

if (!empty($missingRequirements)) {
$this->markTestSkipped(implode(PHP_EOL, $missingRequirements));
}
}








public function getStatus()
{
return $this->status;
}








public function getStatusMessage()
{
return $this->statusMessage;
}








public function hasFailed()
{
$status = $this->getStatus();

return $status == PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE ||
$status == PHPUnit_Runner_BaseTestRunner::STATUS_ERROR;
}











public function run(PHPUnit_Framework_TestResult $result = null)
{
if ($result === null) {
$result = $this->createResult();
}

if (!$this instanceof PHPUnit_Framework_Warning) {
$this->setTestResultObject($result);
$this->setUseErrorHandlerFromAnnotation();
}

if ($this->useErrorHandler !== null) {
$oldErrorHandlerSetting = $result->getConvertErrorsToExceptions();
$result->convertErrorsToExceptions($this->useErrorHandler);
}

if (!$this instanceof PHPUnit_Framework_Warning && !$this->handleDependencies()) {
return;
}

if ($this->runTestInSeparateProcess === true &&
$this->inIsolation !== true &&
!$this instanceof PHPUnit_Extensions_SeleniumTestCase &&
!$this instanceof PHPUnit_Extensions_PhptTestCase) {
$class = new ReflectionClass($this);

$template = new Text_Template(
__DIR__ . '/../Util/PHP/Template/TestCaseMethod.tpl'
);

if ($this->preserveGlobalState) {
$constants = PHPUnit_Util_GlobalState::getConstantsAsString();
$globals = PHPUnit_Util_GlobalState::getGlobalsAsString();
$includedFiles = PHPUnit_Util_GlobalState::getIncludedFilesAsString();
$iniSettings = PHPUnit_Util_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';
$isStrictAboutTestSize = $result->isStrictAboutTestSize() ? 'true' : 'false';
$isStrictAboutTodoAnnotatedTests = $result->isStrictAboutTodoAnnotatedTests() ? '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 = (isset($GLOBALS['__PHPUNIT_CONFIGURATION_FILE']) ? $GLOBALS['__PHPUNIT_CONFIGURATION_FILE'] : '');

$template->setVar(
array(
'composerAutoload' => $composerAutoload,
'phar' => $phar,
'filename' => $class->getFileName(),
'className' => $class->getName(),
'methodName' => $this->name,
'collectCodeCoverageInformation' => $coverage,
'data' => $data,
'dataName' => $dataName,
'dependencyInput' => $dependencyInput,
'constants' => $constants,
'globals' => $globals,
'include_path' => $includePath,
'included_files' => $includedFiles,
'iniSettings' => $iniSettings,
'isStrictAboutTestsThatDoNotTestAnything' => $isStrictAboutTestsThatDoNotTestAnything,
'isStrictAboutOutputDuringTests' => $isStrictAboutOutputDuringTests,
'isStrictAboutTestSize' => $isStrictAboutTestSize,
'isStrictAboutTodoAnnotatedTests' => $isStrictAboutTodoAnnotatedTests,
'codeCoverageFilter' => $codeCoverageFilter,
'configurationFilePath' => $configurationFilePath
)
);

$this->prepareTemplate($template);

$php = PHPUnit_Util_PHP::factory();
$php->runTestJob($template->render(), $this, $result);
} else {
$result->run($this);
}

if ($this->useErrorHandler !== null) {
$result->convertErrorsToExceptions($oldErrorHandlerSetting);
}

$this->result = null;

return $result;
}




public function runBare()
{
$this->numAssertions = 0;

$this->snapshotGlobalState();
$this->startOutputBuffering();
clearstatcache();
$currentWorkingDirectory = getcwd();

$hookMethods = PHPUnit_Util_Test::getHookMethods(get_class($this));

try {
$hasMetRequirements = false;
$this->checkRequirements();
$hasMetRequirements = true;

if ($this->inIsolation) {
foreach ($hookMethods['beforeClass'] as $method) {
$this->$method();
}
}

$this->setExpectedExceptionFromAnnotation();

foreach ($hookMethods['before'] as $method) {
$this->$method();
}

$this->assertPreConditions();
$this->testResult = $this->runTest();
$this->verifyMockObjects();
$this->assertPostConditions();

$this->status = PHPUnit_Runner_BaseTestRunner::STATUS_PASSED;
} catch (PHPUnit_Framework_IncompleteTest $e) {
$this->status = PHPUnit_Runner_BaseTestRunner::STATUS_INCOMPLETE;
$this->statusMessage = $e->getMessage();
} catch (PHPUnit_Framework_SkippedTest $e) {
$this->status = PHPUnit_Runner_BaseTestRunner::STATUS_SKIPPED;
$this->statusMessage = $e->getMessage();
} catch (PHPUnit_Framework_AssertionFailedError $e) {
$this->status = PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE;
$this->statusMessage = $e->getMessage();
} catch (PredictionException $e) {
$this->status = PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE;
$this->statusMessage = $e->getMessage();
} catch (Throwable $_e) {
$e = $_e;
} catch (Exception $_e) {
$e = $_e;
}

if (isset($_e)) {
$this->status = PHPUnit_Runner_BaseTestRunner::STATUS_ERROR;
$this->statusMessage = $_e->getMessage();
}


 $this->mockObjects = array();
$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) {
if (!isset($e)) {
$e = $_e;
}
} catch (Exception $_e) {
if (!isset($e)) {
$e = $_e;
}
}

try {
$this->stopOutputBuffering();
} catch (PHPUnit_Framework_RiskyTestError $_e) {
if (!isset($e)) {
$e = $_e;
}
}

clearstatcache();

if ($currentWorkingDirectory != getcwd()) {
chdir($currentWorkingDirectory);
}

$this->restoreGlobalState();


 foreach ($this->iniSettings as $varName => $oldValue) {
ini_set($varName, $oldValue);
}

$this->iniSettings = array();


 foreach ($this->locale as $category => $locale) {
setlocale($category, $locale);
}


 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;
} catch (Exception $_e) {
$e = $_e;
}
}


 if (isset($e)) {
if ($e instanceof PredictionException) {
$e = new PHPUnit_Framework_AssertionFailedError($e->getMessage());
}

if (!$e instanceof Exception) {

 throw $e;
}

$this->onNotSuccessfulTest($e);
}
}









protected function runTest()
{
if ($this->name === null) {
throw new PHPUnit_Framework_Exception(
'PHPUnit_Framework_TestCase::$name must not be null.'
);
}

try {
$class = new ReflectionClass($this);
$method = $class->getMethod($this->name);
} catch (ReflectionException $e) {
$this->fail($e->getMessage());
}

try {
$testResult = $method->invokeArgs(
$this,
array_merge($this->data, $this->dependencyInput)
);
} catch (Throwable $_e) {
$e = $_e;
} catch (Exception $_e) {
$e = $_e;
}

if (isset($e)) {
$checkException = false;

if (is_string($this->expectedException)) {
$checkException = true;

if ($e instanceof PHPUnit_Framework_Exception) {
$checkException = false;
}

$reflector = new ReflectionClass($this->expectedException);

if ($this->expectedException == 'PHPUnit_Framework_Exception' ||
$reflector->isSubclassOf('PHPUnit_Framework_Exception')) {
$checkException = true;
}
}

if ($checkException) {
$this->assertThat(
$e,
new PHPUnit_Framework_Constraint_Exception(
$this->expectedException
)
);

if (is_string($this->expectedExceptionMessage) &&
!empty($this->expectedExceptionMessage)) {
$this->assertThat(
$e,
new PHPUnit_Framework_Constraint_ExceptionMessage(
$this->expectedExceptionMessage
)
);
}

if (is_string($this->expectedExceptionMessageRegExp) &&
!empty($this->expectedExceptionMessageRegExp)) {
$this->assertThat(
$e,
new PHPUnit_Framework_Constraint_ExceptionMessageRegExp(
$this->expectedExceptionMessageRegExp
)
);
}

if ($this->expectedExceptionCode !== null) {
$this->assertThat(
$e,
new PHPUnit_Framework_Constraint_ExceptionCode(
$this->expectedExceptionCode
)
);
}

return;
} else {
throw $e;
}
}

if ($this->expectedException !== null) {
$this->assertThat(
null,
new PHPUnit_Framework_Constraint_Exception(
$this->expectedException
)
);
}

return $testResult;
}






protected function verifyMockObjects()
{
foreach ($this->mockObjects as $mockObject) {
if ($mockObject->__phpunit_hasMatchers()) {
$this->numAssertions++;
}

$mockObject->__phpunit_verify();
}

if ($this->prophet !== null) {
try {
$this->prophet->checkPredictions();
} catch (Throwable $e) {

} catch (Exception $e) {

}

foreach ($this->prophet->getProphecies() as $objectProphecy) {
foreach ($objectProphecy->getMethodProphecies() as $methodProphecies) {
foreach ($methodProphecies as $methodProphecy) {
$this->numAssertions += count($methodProphecy->getCheckedPredictions());
}
}
}

if (isset($e)) {
throw $e;
}
}
}






public function setName($name)
{
$this->name = $name;
}








public function setDependencies(array $dependencies)
{
$this->dependencies = $dependencies;
}








public function hasDependencies()
{
return count($this->dependencies) > 0;
}








public function setDependencyInput(array $dependencyInput)
{
$this->dependencyInput = $dependencyInput;
}






public function setDisallowChangesToGlobalState($disallowChangesToGlobalState)
{
$this->disallowChangesToGlobalState = $disallowChangesToGlobalState;
}








public function setBackupGlobals($backupGlobals)
{
if (is_null($this->backupGlobals) && is_bool($backupGlobals)) {
$this->backupGlobals = $backupGlobals;
}
}








public function setBackupStaticAttributes($backupStaticAttributes)
{
if (is_null($this->backupStaticAttributes) &&
is_bool($backupStaticAttributes)) {
$this->backupStaticAttributes = $backupStaticAttributes;
}
}








public function setRunTestInSeparateProcess($runTestInSeparateProcess)
{
if (is_bool($runTestInSeparateProcess)) {
if ($this->runTestInSeparateProcess === null) {
$this->runTestInSeparateProcess = $runTestInSeparateProcess;
}
} else {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean');
}
}








public function setPreserveGlobalState($preserveGlobalState)
{
if (is_bool($preserveGlobalState)) {
$this->preserveGlobalState = $preserveGlobalState;
} else {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean');
}
}








public function setInIsolation($inIsolation)
{
if (is_bool($inIsolation)) {
$this->inIsolation = $inIsolation;
} else {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean');
}
}






public function isInIsolation()
{
return $this->inIsolation;
}






public function getResult()
{
return $this->testResult;
}






public function setResult($result)
{
$this->testResult = $result;
}








public function setOutputCallback($callback)
{
if (!is_callable($callback)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'callback');
}

$this->outputCallback = $callback;
}






public function getTestResultObject()
{
return $this->result;
}






public function setTestResultObject(PHPUnit_Framework_TestResult $result)
{
$this->result = $result;
}













protected function iniSet($varName, $newValue)
{
if (!is_string($varName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

$currentValue = ini_set($varName, $newValue);

if ($currentValue !== false) {
$this->iniSettings[$varName] = $currentValue;
} else {
throw new PHPUnit_Framework_Exception(
sprintf(
'INI setting "%s" could not be set to "%s".',
$varName,
$newValue
)
);
}
}












protected function setLocale()
{
$args = func_get_args();

if (count($args) < 2) {
throw new PHPUnit_Framework_Exception;
}

$category = $args[0];
$locale = $args[1];

$categories = array(
LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME
);

if (defined('LC_MESSAGES')) {
$categories[] = LC_MESSAGES;
}

if (!in_array($category, $categories)) {
throw new PHPUnit_Framework_Exception;
}

if (!is_array($locale) && !is_string($locale)) {
throw new PHPUnit_Framework_Exception;
}

$this->locale[$category] = setlocale($category, null);

$result = call_user_func_array('setlocale', $args);

if ($result === false) {
throw new PHPUnit_Framework_Exception(
'The locale functionality is not implemented on your platform, ' .
'the specified locale does not exist or the category name is ' .
'invalid.'
);
}
}























public function getMock($originalClassName, $methods = array(), array $arguments = array(), $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $cloneArguments = false, $callOriginalMethods = false)
{
$mockObject = $this->getMockObjectGenerator()->getMock(
$originalClassName,
$methods,
$arguments,
$mockClassName,
$callOriginalConstructor,
$callOriginalClone,
$callAutoload,
$cloneArguments,
$callOriginalMethods
);

$this->mockObjects[] = $mockObject;

return $mockObject;
}










public function getMockBuilder($className)
{
return new PHPUnit_Framework_MockObject_MockBuilder($this, $className);
}



















protected function getMockClass($originalClassName, $methods = array(), array $arguments = array(), $mockClassName = '', $callOriginalConstructor = false, $callOriginalClone = true, $callAutoload = true, $cloneArguments = false)
{
$mock = $this->getMock(
$originalClassName,
$methods,
$arguments,
$mockClassName,
$callOriginalConstructor,
$callOriginalClone,
$callAutoload,
$cloneArguments
);

return get_class($mock);
}





















public function getMockForAbstractClass($originalClassName, array $arguments = array(), $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $mockedMethods = array(), $cloneArguments = false)
{
$mockObject = $this->getMockObjectGenerator()->getMockForAbstractClass(
$originalClassName,
$arguments,
$mockClassName,
$callOriginalConstructor,
$callOriginalClone,
$callAutoload,
$mockedMethods,
$cloneArguments
);

$this->mockObjects[] = $mockObject;

return $mockObject;
}















protected function getMockFromWsdl($wsdlFile, $originalClassName = '', $mockClassName = '', array $methods = array(), $callOriginalConstructor = true, array $options = array())
{
if ($originalClassName === '') {
$originalClassName = str_replace('.wsdl', '', basename($wsdlFile));
}

if (!class_exists($originalClassName)) {
eval(
$this->getMockObjectGenerator()->generateClassFromWsdl(
$wsdlFile,
$originalClassName,
$methods,
$options
)
);
}

return $this->getMock(
$originalClassName,
$methods,
array('', $options),
$mockClassName,
$callOriginalConstructor,
false,
false
);
}





















public function getMockForTrait($traitName, array $arguments = array(), $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $mockedMethods = array(), $cloneArguments = false)
{
$mockObject = $this->getMockObjectGenerator()->getMockForTrait(
$traitName,
$arguments,
$mockClassName,
$callOriginalConstructor,
$callOriginalClone,
$callAutoload,
$mockedMethods,
$cloneArguments
);

$this->mockObjects[] = $mockObject;

return $mockObject;
}


















protected function getObjectForTrait($traitName, array $arguments = array(), $traitClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $cloneArguments = false)
{
return $this->getMockObjectGenerator()->getObjectForTrait(
$traitName,
$arguments,
$traitClassName,
$callOriginalConstructor,
$callOriginalClone,
$callAutoload,
$cloneArguments
);
}










protected function prophesize($classOrInterface = null)
{
return $this->getProphet()->prophesize($classOrInterface);
}








public function addToAssertionCount($count)
{
$this->numAssertions += $count;
}








public function getNumAssertions()
{
return $this->numAssertions;
}









public static function any()
{
return new PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount;
}








public static function never()
{
return new PHPUnit_Framework_MockObject_Matcher_InvokedCount(0);
}











public static function atLeast($requiredInvocations)
{
return new PHPUnit_Framework_MockObject_Matcher_InvokedAtLeastCount(
$requiredInvocations
);
}








public static function atLeastOnce()
{
return new PHPUnit_Framework_MockObject_Matcher_InvokedAtLeastOnce;
}








public static function once()
{
return new PHPUnit_Framework_MockObject_Matcher_InvokedCount(1);
}











public static function exactly($count)
{
return new PHPUnit_Framework_MockObject_Matcher_InvokedCount($count);
}











public static function atMost($allowedInvocations)
{
return new PHPUnit_Framework_MockObject_Matcher_InvokedAtMostCount(
$allowedInvocations
);
}











public static function at($index)
{
return new PHPUnit_Framework_MockObject_Matcher_InvokedAtIndex($index);
}








public static function returnValue($value)
{
return new PHPUnit_Framework_MockObject_Stub_Return($value);
}








public static function returnValueMap(array $valueMap)
{
return new PHPUnit_Framework_MockObject_Stub_ReturnValueMap($valueMap);
}








public static function returnArgument($argumentIndex)
{
return new PHPUnit_Framework_MockObject_Stub_ReturnArgument(
$argumentIndex
);
}








public static function returnCallback($callback)
{
return new PHPUnit_Framework_MockObject_Stub_ReturnCallback($callback);
}










public static function returnSelf()
{
return new PHPUnit_Framework_MockObject_Stub_ReturnSelf();
}








public static function throwException(Exception $exception)
{
return new PHPUnit_Framework_MockObject_Stub_Exception($exception);
}








public static function onConsecutiveCalls()
{
$args = func_get_args();

return new PHPUnit_Framework_MockObject_Stub_ConsecutiveCalls($args);
}










protected function getDataSetAsString($includeData = true)
{
$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);
}

$exporter = new Exporter;

if ($includeData) {
$buffer .= sprintf(' (%s)', $exporter->shortenedRecursiveExport($this->data));
}
}

return $buffer;
}






protected function createResult()
{
return new PHPUnit_Framework_TestResult;
}




protected function handleDependencies()
{
if (!empty($this->dependencies) && !$this->inIsolation) {
$className = get_class($this);
$passed = $this->result->passed();
$passedKeys = array_keys($passed);
$numKeys = count($passedKeys);

for ($i = 0; $i < $numKeys; $i++) {
$pos = strpos($passedKeys[$i], ' with data set');

if ($pos !== false) {
$passedKeys[$i] = substr($passedKeys[$i], 0, $pos);
}
}

$passedKeys = array_flip(array_unique($passedKeys));

foreach ($this->dependencies as $dependency) {
if (strpos($dependency, '::') === false) {
$dependency = $className . '::' . $dependency;
}

if (!isset($passedKeys[$dependency])) {
$this->result->addError(
$this,
new PHPUnit_Framework_SkippedTestError(
sprintf(
'This test depends on "%s" to pass.',
$dependency
)
),
0
);

return false;
}

if (isset($passed[$dependency])) {
if ($passed[$dependency]['size'] != PHPUnit_Util_Test::UNKNOWN &&
$this->getSize() != PHPUnit_Util_Test::UNKNOWN &&
$passed[$dependency]['size'] > $this->getSize()) {
$this->result->addError(
$this,
new PHPUnit_Framework_SkippedTestError(
'This test depends on a test that is larger than itself.'
),
0
);

return false;
}

$this->dependencyInput[$dependency] = $passed[$dependency]['result'];
} else {
$this->dependencyInput[$dependency] = null;
}
}
}

return true;
}






public static function setUpBeforeClass()
{
}





protected function setUp()
{
}









protected function assertPreConditions()
{
}









protected function assertPostConditions()
{
}





protected function tearDown()
{
}






public static function tearDownAfterClass()
{
}










protected function onNotSuccessfulTest(Exception $e)
{
throw $e;
}








protected function prepareTemplate(Text_Template $template)
{
}






protected function getMockObjectGenerator()
{
if (null === $this->mockObjectGenerator) {
$this->mockObjectGenerator = new PHPUnit_Framework_MockObject_Generator;
}

return $this->mockObjectGenerator;
}




private function startOutputBuffering()
{
while (!defined('PHPUNIT_TESTSUITE') && ob_get_level() > 0) {
ob_end_clean();
}

ob_start();

$this->outputBufferingActive = true;
$this->outputBufferingLevel = ob_get_level();
}




private function stopOutputBuffering()
{
if (ob_get_level() != $this->outputBufferingLevel) {
while (ob_get_level() > 0) {
ob_end_clean();
}

throw new PHPUnit_Framework_RiskyTestError(
'Test code or tested code did not (only) close its own output buffers'
);
}

$output = ob_get_contents();

if ($this->outputCallback === false) {
$this->output = $output;
} else {
$this->output = call_user_func_array(
$this->outputCallback,
array($output)
);
}

ob_end_clean();

$this->outputBufferingActive = false;
$this->outputBufferingLevel = ob_get_level();
}

private function snapshotGlobalState()
{
$backupGlobals = $this->backupGlobals === null || $this->backupGlobals === true;

if ($this->runTestInSeparateProcess || $this->inIsolation ||
(!$backupGlobals && !$this->backupStaticAttributes)) {
return;
}

$this->snapshot = $this->createGlobalStateSnapshot($backupGlobals);
}

private function restoreGlobalState()
{
if (!$this->snapshot instanceof Snapshot) {
return;
}

$backupGlobals = $this->backupGlobals === null || $this->backupGlobals === true;

if ($this->disallowChangesToGlobalState) {
try {
$this->compareGlobalStateSnapshots(
$this->snapshot,
$this->createGlobalStateSnapshot($backupGlobals)
);
} catch (PHPUnit_Framework_RiskyTestError $rte) {

 }
}

$restorer = new Restorer;

if ($backupGlobals) {
$restorer->restoreGlobalVariables($this->snapshot);
}

if ($this->backupStaticAttributes) {
$restorer->restoreStaticAttributes($this->snapshot);
}

$this->snapshot = null;

if (isset($rte)) {
throw $rte;
}
}






private function createGlobalStateSnapshot($backupGlobals)
{
$blacklist = new Blacklist;

foreach ($this->backupGlobalsBlacklist as $globalVariable) {
$blacklist->addGlobalVariable($globalVariable);
}

if (!defined('PHPUNIT_TESTSUITE')) {
$blacklist->addClassNamePrefix('PHPUnit');
$blacklist->addClassNamePrefix('File_Iterator');
$blacklist->addClassNamePrefix('PHP_CodeCoverage');
$blacklist->addClassNamePrefix('PHP_Invoker');
$blacklist->addClassNamePrefix('PHP_Timer');
$blacklist->addClassNamePrefix('PHP_Token');
$blacklist->addClassNamePrefix('Symfony');
$blacklist->addClassNamePrefix('Text_Template');
$blacklist->addClassNamePrefix('Doctrine\Instantiator');

foreach ($this->backupStaticAttributesBlacklist as $class => $attributes) {
foreach ($attributes as $attribute) {
$blacklist->addStaticAttribute($class, $attribute);
}
}
}

return new Snapshot(
$blacklist,
$backupGlobals,
$this->backupStaticAttributes,
false,
false,
false,
false,
false,
false,
false
);
}







private function compareGlobalStateSnapshots(Snapshot $before, Snapshot $after)
{
$backupGlobals = $this->backupGlobals === null || $this->backupGlobals === true;

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, $header)
{
if ($before != $after) {
$differ = new Differ($header);
$exporter = new Exporter;

$diff = $differ->diff(
$exporter->export($before),
$exporter->export($after)
);

throw new PHPUnit_Framework_RiskyTestError(
$diff
);
}
}






private function getProphet()
{
if ($this->prophet === null) {
$this->prophet = new Prophet;
}

return $this->prophet;
}
}
<?php















class PHPUnit_Framework_SkippedTestSuiteError extends PHPUnit_Framework_AssertionFailedError implements PHPUnit_Framework_SkippedTest
{
}
<?php












class PHPUnit_Framework_CodeCoverageException extends PHPUnit_Framework_Exception
{
}
<?php

















function any()
{
return call_user_func_array(
'PHPUnit_Framework_TestCase::any',
func_get_args()
);
}








function anything()
{
return call_user_func_array(
'PHPUnit_Framework_Assert::anything',
func_get_args()
);
}










function arrayHasKey($key)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::arrayHasKey',
func_get_args()
);
}










function assertArrayHasKey($key, $array, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertArrayHasKey',
func_get_args()
);
}











function assertArraySubset($subset, $array, $strict = false, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertArraySubset',
func_get_args()
);
}










function assertArrayNotHasKey($key, $array, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertArrayNotHasKey',
func_get_args()
);
}















function assertAttributeContains($needle, $haystackAttributeName, $haystackClassOrObject, $message = '', $ignoreCase = false, $checkForObjectIdentity = true, $checkForNonObjectIdentity = false)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertAttributeContains',
func_get_args()
);
}













function assertAttributeContainsOnly($type, $haystackAttributeName, $haystackClassOrObject, $isNativeType = null, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertAttributeContainsOnly',
func_get_args()
);
}












function assertAttributeCount($expectedCount, $haystackAttributeName, $haystackClassOrObject, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertAttributeCount',
func_get_args()
);
}











function assertAttributeEmpty($haystackAttributeName, $haystackClassOrObject, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertAttributeEmpty',
func_get_args()
);
}













function assertAttributeEquals($expected, $actualAttributeName, $actualClassOrObject, $message = '', $delta = 0.0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertAttributeEquals',
func_get_args()
);
}











function assertAttributeGreaterThan($expected, $actualAttributeName, $actualClassOrObject, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertAttributeGreaterThan',
func_get_args()
);
}











function assertAttributeGreaterThanOrEqual($expected, $actualAttributeName, $actualClassOrObject, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertAttributeGreaterThanOrEqual',
func_get_args()
);
}











function assertAttributeInstanceOf($expected, $attributeName, $classOrObject, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertAttributeInstanceOf',
func_get_args()
);
}











function assertAttributeInternalType($expected, $attributeName, $classOrObject, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertAttributeInternalType',
func_get_args()
);
}











function assertAttributeLessThan($expected, $actualAttributeName, $actualClassOrObject, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertAttributeLessThan',
func_get_args()
);
}











function assertAttributeLessThanOrEqual($expected, $actualAttributeName, $actualClassOrObject, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertAttributeLessThanOrEqual',
func_get_args()
);
}















function assertAttributeNotContains($needle, $haystackAttributeName, $haystackClassOrObject, $message = '', $ignoreCase = false, $checkForObjectIdentity = true, $checkForNonObjectIdentity = false)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertAttributeNotContains',
func_get_args()
);
}














function assertAttributeNotContainsOnly($type, $haystackAttributeName, $haystackClassOrObject, $isNativeType = null, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertAttributeNotContainsOnly',
func_get_args()
);
}












function assertAttributeNotCount($expectedCount, $haystackAttributeName, $haystackClassOrObject, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertAttributeNotCount',
func_get_args()
);
}











function assertAttributeNotEmpty($haystackAttributeName, $haystackClassOrObject, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertAttributeNotEmpty',
func_get_args()
);
}













function assertAttributeNotEquals($expected, $actualAttributeName, $actualClassOrObject, $message = '', $delta = 0.0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertAttributeNotEquals',
func_get_args()
);
}











function assertAttributeNotInstanceOf($expected, $attributeName, $classOrObject, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertAttributeNotInstanceOf',
func_get_args()
);
}











function assertAttributeNotInternalType($expected, $attributeName, $classOrObject, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertAttributeNotInternalType',
func_get_args()
);
}










function assertAttributeNotSame($expected, $actualAttributeName, $actualClassOrObject, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertAttributeNotSame',
func_get_args()
);
}










function assertAttributeSame($expected, $actualAttributeName, $actualClassOrObject, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertAttributeSame',
func_get_args()
);
}










function assertClassHasAttribute($attributeName, $className, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertClassHasAttribute',
func_get_args()
);
}










function assertClassHasStaticAttribute($attributeName, $className, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertClassHasStaticAttribute',
func_get_args()
);
}










function assertClassNotHasAttribute($attributeName, $className, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertClassNotHasAttribute',
func_get_args()
);
}










function assertClassNotHasStaticAttribute($attributeName, $className, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertClassNotHasStaticAttribute',
func_get_args()
);
}













function assertContains($needle, $haystack, $message = '', $ignoreCase = false, $checkForObjectIdentity = true, $checkForNonObjectIdentity = false)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertContains',
func_get_args()
);
}











function assertContainsOnly($type, $haystack, $isNativeType = null, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertContainsOnly',
func_get_args()
);
}








function assertContainsOnlyInstancesOf($classname, $haystack, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertContainsOnlyInstancesOf',
func_get_args()
);
}








function assertCount($expectedCount, $haystack, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertCount',
func_get_args()
);
}









function assertEmpty($actual, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertEmpty',
func_get_args()
);
}











function assertEqualXMLStructure(DOMElement $expectedElement, DOMElement $actualElement, $checkAttributes = false, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertEqualXMLStructure',
func_get_args()
);
}












function assertEquals($expected, $actual, $message = '', $delta = 0.0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertEquals',
func_get_args()
);
}









function assertNotTrue($condition, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertNotTrue',
func_get_args()
);
}









function assertFalse($condition, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertFalse',
func_get_args()
);
}













function assertFileEquals($expected, $actual, $message = '', $canonicalize = false, $ignoreCase = false)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertFileEquals',
func_get_args()
);
}









function assertFileExists($filename, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertFileExists',
func_get_args()
);
}













function assertFileNotEquals($expected, $actual, $message = '', $canonicalize = false, $ignoreCase = false)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertFileNotEquals',
func_get_args()
);
}









function assertFileNotExists($filename, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertFileNotExists',
func_get_args()
);
}










function assertGreaterThan($expected, $actual, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertGreaterThan',
func_get_args()
);
}










function assertGreaterThanOrEqual($expected, $actual, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertGreaterThanOrEqual',
func_get_args()
);
}










function assertInstanceOf($expected, $actual, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertInstanceOf',
func_get_args()
);
}










function assertInternalType($expected, $actual, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertInternalType',
func_get_args()
);
}









function assertJson($actualJson, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertJson',
func_get_args()
);
}








function assertJsonFileEqualsJsonFile($expectedFile, $actualFile, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertJsonFileEqualsJsonFile',
func_get_args()
);
}








function assertJsonFileNotEqualsJsonFile($expectedFile, $actualFile, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertJsonFileNotEqualsJsonFile',
func_get_args()
);
}








function assertJsonStringEqualsJsonFile($expectedFile, $actualJson, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertJsonStringEqualsJsonFile',
func_get_args()
);
}








function assertJsonStringEqualsJsonString($expectedJson, $actualJson, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertJsonStringEqualsJsonString',
func_get_args()
);
}








function assertJsonStringNotEqualsJsonFile($expectedFile, $actualJson, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertJsonStringNotEqualsJsonFile',
func_get_args()
);
}








function assertJsonStringNotEqualsJsonString($expectedJson, $actualJson, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertJsonStringNotEqualsJsonString',
func_get_args()
);
}










function assertLessThan($expected, $actual, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertLessThan',
func_get_args()
);
}










function assertLessThanOrEqual($expected, $actual, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertLessThanOrEqual',
func_get_args()
);
}













function assertNotContains($needle, $haystack, $message = '', $ignoreCase = false, $checkForObjectIdentity = true, $checkForNonObjectIdentity = false)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertNotContains',
func_get_args()
);
}











function assertNotContainsOnly($type, $haystack, $isNativeType = null, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertNotContainsOnly',
func_get_args()
);
}








function assertNotCount($expectedCount, $haystack, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertNotCount',
func_get_args()
);
}









function assertNotEmpty($actual, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertNotEmpty',
func_get_args()
);
}














function assertNotEquals($expected, $actual, $message = '', $delta = 0.0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertNotEquals',
func_get_args()
);
}










function assertNotInstanceOf($expected, $actual, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertNotInstanceOf',
func_get_args()
);
}










function assertNotInternalType($expected, $actual, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertNotInternalType',
func_get_args()
);
}









function assertNotFalse($condition, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertNotFalse',
func_get_args()
);
}







function assertNotNull($actual, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertNotNull',
func_get_args()
);
}










function assertNotRegExp($pattern, $string, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertNotRegExp',
func_get_args()
);
}










function assertNotSame($expected, $actual, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertNotSame',
func_get_args()
);
}









function assertNotSameSize($expected, $actual, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertNotSameSize',
func_get_args()
);
}














function assertNotTag($matcher, $actual, $message = '', $isHtml = true)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertNotTag',
func_get_args()
);
}







function assertNull($actual, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertNull',
func_get_args()
);
}










function assertObjectHasAttribute($attributeName, $object, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertObjectHasAttribute',
func_get_args()
);
}










function assertObjectNotHasAttribute($attributeName, $object, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertObjectNotHasAttribute',
func_get_args()
);
}








function assertRegExp($pattern, $string, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertRegExp',
func_get_args()
);
}










function assertSame($expected, $actual, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertSame',
func_get_args()
);
}









function assertSameSize($expected, $actual, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertSameSize',
func_get_args()
);
}
























function assertSelectCount($selector, $count, $actual, $message = '', $isHtml = true)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertSelectCount',
func_get_args()
);
}














function assertSelectEquals($selector, $content, $count, $actual, $message = '', $isHtml = true)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertSelectEquals',
func_get_args()
);
}














function assertSelectRegExp($selector, $pattern, $count, $actual, $message = '', $isHtml = true)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertSelectRegExp',
func_get_args()
);
}










function assertStringEndsNotWith($suffix, $string, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertStringEndsNotWith',
func_get_args()
);
}










function assertStringEndsWith($suffix, $string, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertStringEndsWith',
func_get_args()
);
}













function assertStringEqualsFile($expectedFile, $actualString, $message = '', $canonicalize = false, $ignoreCase = false)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertStringEqualsFile',
func_get_args()
);
}










function assertStringMatchesFormat($format, $string, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertStringMatchesFormat',
func_get_args()
);
}










function assertStringMatchesFormatFile($formatFile, $string, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertStringMatchesFormatFile',
func_get_args()
);
}













function assertStringNotEqualsFile($expectedFile, $actualString, $message = '', $canonicalize = false, $ignoreCase = false)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertStringNotEqualsFile',
func_get_args()
);
}










function assertStringNotMatchesFormat($format, $string, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertStringNotMatchesFormat',
func_get_args()
);
}










function assertStringNotMatchesFormatFile($formatFile, $string, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertStringNotMatchesFormatFile',
func_get_args()
);
}










function assertStringStartsNotWith($prefix, $string, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertStringStartsNotWith',
func_get_args()
);
}










function assertStringStartsWith($prefix, $string, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertStringStartsWith',
func_get_args()
);
}









































































































































function assertTag($matcher, $actual, $message = '', $isHtml = true)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertTag',
func_get_args()
);
}










function assertThat($value, PHPUnit_Framework_Constraint $constraint, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertThat',
func_get_args()
);
}









function assertTrue($condition, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertTrue',
func_get_args()
);
}










function assertXmlFileEqualsXmlFile($expectedFile, $actualFile, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertXmlFileEqualsXmlFile',
func_get_args()
);
}










function assertXmlFileNotEqualsXmlFile($expectedFile, $actualFile, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertXmlFileNotEqualsXmlFile',
func_get_args()
);
}










function assertXmlStringEqualsXmlFile($expectedFile, $actualXml, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertXmlStringEqualsXmlFile',
func_get_args()
);
}










function assertXmlStringEqualsXmlString($expectedXml, $actualXml, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertXmlStringEqualsXmlString',
func_get_args()
);
}










function assertXmlStringNotEqualsXmlFile($expectedFile, $actualXml, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertXmlStringNotEqualsXmlFile',
func_get_args()
);
}










function assertXmlStringNotEqualsXmlString($expectedXml, $actualXml, $message = '')
{
return call_user_func_array(
'PHPUnit_Framework_Assert::assertXmlStringNotEqualsXmlString',
func_get_args()
);
}











function at($index)
{
return call_user_func_array(
'PHPUnit_Framework_TestCase::at',
func_get_args()
);
}








function atLeastOnce()
{
return call_user_func_array(
'PHPUnit_Framework_TestCase::atLeastOnce',
func_get_args()
);
}











function attribute(PHPUnit_Framework_Constraint $constraint, $attributeName)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::attribute',
func_get_args()
);
}

















function attributeEqualTo($attributeName, $value, $delta = 0.0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::attributeEqualTo',
func_get_args()
);
}








function callback($callback)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::callback',
func_get_args()
);
}










function classHasAttribute($attributeName)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::classHasAttribute',
func_get_args()
);
}











function classHasStaticAttribute($attributeName)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::classHasStaticAttribute',
func_get_args()
);
}













function contains($value, $checkForObjectIdentity = true, $checkForNonObjectIdentity = false)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::contains',
func_get_args()
);
}











function containsOnly($type)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::containsOnly',
func_get_args()
);
}









function containsOnlyInstancesOf($classname)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::containsOnlyInstancesOf',
func_get_args()
);
}














function equalTo($value, $delta = 0.0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::equalTo',
func_get_args()
);
}











function exactly($count)
{
return call_user_func_array(
'PHPUnit_Framework_TestCase::exactly',
func_get_args()
);
}








function fileExists()
{
return call_user_func_array(
'PHPUnit_Framework_Assert::fileExists',
func_get_args()
);
}










function greaterThan($value)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::greaterThan',
func_get_args()
);
}












function greaterThanOrEqual($value)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::greaterThanOrEqual',
func_get_args()
);
}










function identicalTo($value)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::identicalTo',
func_get_args()
);
}








function isEmpty()
{
return call_user_func_array(
'PHPUnit_Framework_Assert::isEmpty',
func_get_args()
);
}








function isFalse()
{
return call_user_func_array(
'PHPUnit_Framework_Assert::isFalse',
func_get_args()
);
}










function isInstanceOf($className)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::isInstanceOf',
func_get_args()
);
}








function isJson()
{
return call_user_func_array(
'PHPUnit_Framework_Assert::isJson',
func_get_args()
);
}








function isNull()
{
return call_user_func_array(
'PHPUnit_Framework_Assert::isNull',
func_get_args()
);
}








function isTrue()
{
return call_user_func_array(
'PHPUnit_Framework_Assert::isTrue',
func_get_args()
);
}










function isType($type)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::isType',
func_get_args()
);
}










function lessThan($value)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::lessThan',
func_get_args()
);
}












function lessThanOrEqual($value)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::lessThanOrEqual',
func_get_args()
);
}








function logicalAnd()
{
return call_user_func_array(
'PHPUnit_Framework_Assert::logicalAnd',
func_get_args()
);
}










function logicalNot(PHPUnit_Framework_Constraint $constraint)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::logicalNot',
func_get_args()
);
}








function logicalOr()
{
return call_user_func_array(
'PHPUnit_Framework_Assert::logicalOr',
func_get_args()
);
}








function logicalXor()
{
return call_user_func_array(
'PHPUnit_Framework_Assert::logicalXor',
func_get_args()
);
}










function matches($string)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::matches',
func_get_args()
);
}










function matchesRegularExpression($pattern)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::matchesRegularExpression',
func_get_args()
);
}








function never()
{
return call_user_func_array(
'PHPUnit_Framework_TestCase::never',
func_get_args()
);
}










function objectHasAttribute($attributeName)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::objectHasAttribute',
func_get_args()
);
}








function onConsecutiveCalls()
{
return call_user_func_array(
'PHPUnit_Framework_TestCase::onConsecutiveCalls',
func_get_args()
);
}








function once()
{
return call_user_func_array(
'PHPUnit_Framework_TestCase::once',
func_get_args()
);
}








function returnArgument($argumentIndex)
{
return call_user_func_array(
'PHPUnit_Framework_TestCase::returnArgument',
func_get_args()
);
}








function returnCallback($callback)
{
return call_user_func_array(
'PHPUnit_Framework_TestCase::returnCallback',
func_get_args()
);
}










function returnSelf()
{
return call_user_func_array(
'PHPUnit_Framework_TestCase::returnSelf',
func_get_args()
);
}








function returnValue($value)
{
return call_user_func_array(
'PHPUnit_Framework_TestCase::returnValue',
func_get_args()
);
}








function returnValueMap(array $valueMap)
{
return call_user_func_array(
'PHPUnit_Framework_TestCase::returnValueMap',
func_get_args()
);
}











function stringContains($string, $case = true)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::stringContains',
func_get_args()
);
}










function stringEndsWith($suffix)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::stringEndsWith',
func_get_args()
);
}










function stringStartsWith($prefix)
{
return call_user_func_array(
'PHPUnit_Framework_Assert::stringStartsWith',
func_get_args()
);
}








function throwException(Exception $exception)
{
return call_user_func_array(
'PHPUnit_Framework_TestCase::throwException',
func_get_args()
);
}
<?php

















class PHPUnit_Framework_Constraint_ClassHasStaticAttribute extends PHPUnit_Framework_Constraint_ClassHasAttribute
{








protected function matches($other)
{
$class = new ReflectionClass($other);

if ($class->hasProperty($this->attributeName)) {
$attribute = $class->getProperty($this->attributeName);

return $attribute->isStatic();
} else {
return false;
}
}








public function toString()
{
return sprintf(
'has static attribute "%s"',
$this->attributeName
);
}
}
<?php














class PHPUnit_Framework_Constraint_IsNull extends PHPUnit_Framework_Constraint
{








protected function matches($other)
{
return $other === null;
}






public function toString()
{
return 'is null';
}
}
<?php














class PHPUnit_Framework_Constraint_Xor extends PHPUnit_Framework_Constraint
{



protected $constraints = array();




public function setConstraints(array $constraints)
{
$this->constraints = array();

foreach ($constraints as $constraint) {
if (!($constraint instanceof PHPUnit_Framework_Constraint)) {
$constraint = new PHPUnit_Framework_Constraint_IsEqual(
$constraint
);
}

$this->constraints[] = $constraint;
}
}



















public function evaluate($other, $description = '', $returnResult = false)
{
$success = true;
$lastResult = null;
$constraint = 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()
{
$text = '';

foreach ($this->constraints as $key => $constraint) {
if ($key > 0) {
$text .= ' xor ';
}

$text .= $constraint->toString();
}

return $text;
}








public function count()
{
$count = 0;

foreach ($this->constraints as $constraint) {
$count += count($constraint);
}

return $count;
}
}
<?php














class PHPUnit_Framework_Constraint_Not extends PHPUnit_Framework_Constraint
{



protected $constraint;




public function __construct($constraint)
{
parent::__construct();

if (!($constraint instanceof PHPUnit_Framework_Constraint)) {
$constraint = new PHPUnit_Framework_Constraint_IsEqual($constraint);
}

$this->constraint = $constraint;
}






public static function negate($string)
{
return str_replace(
array(
'contains ',
'exists',
'has ',
'is ',
'are ',
'matches ',
'starts with ',
'ends with ',
'reference ',
'not not '
),
array(
'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 '
),
$string
);
}



















public function evaluate($other, $description = '', $returnResult = false)
{
$success = !$this->constraint->evaluate($other, $description, true);

if ($returnResult) {
return $success;
}

if (!$success) {
$this->fail($other, $description);
}
}











protected function failureDescription($other)
{
switch (get_class($this->constraint)) {
case 'PHPUnit_Framework_Constraint_And':
case 'PHPUnit_Framework_Constraint_Not':
case 'PHPUnit_Framework_Constraint_Or':
return 'not( ' . $this->constraint->failureDescription($other) . ' )';

default:
return self::negate(
$this->constraint->failureDescription($other)
);
}
}






public function toString()
{
switch (get_class($this->constraint)) {
case 'PHPUnit_Framework_Constraint_And':
case 'PHPUnit_Framework_Constraint_Not':
case 'PHPUnit_Framework_Constraint_Or':
return 'not( ' . $this->constraint->toString() . ' )';

default:
return self::negate(
$this->constraint->toString()
);
}
}








public function count()
{
return count($this->constraint);
}
}
<?php














class PHPUnit_Framework_Constraint_IsEmpty extends PHPUnit_Framework_Constraint
{








protected function matches($other)
{
if ($other instanceof Countable) {
return count($other) === 0;
}

return empty($other);
}






public function toString()
{
return 'is empty';
}











protected function failureDescription($other)
{
$type = gettype($other);

return sprintf(
'%s %s %s',
$type[0] == 'a' || $type[0] == 'o' ? 'an' : 'a',
$type,
$this->toString()
);
}
}
<?php




















class PHPUnit_Framework_Constraint_StringContains extends PHPUnit_Framework_Constraint
{



protected $string;




protected $ignoreCase;





public function __construct($string, $ignoreCase = false)
{
parent::__construct();

$this->string = $string;
$this->ignoreCase = $ignoreCase;
}









protected function matches($other)
{
if ($this->ignoreCase) {
return stripos($other, $this->string) !== false;
} else {
return strpos($other, $this->string) !== false;
}
}






public function toString()
{
if ($this->ignoreCase) {
$string = strtolower($this->string);
} else {
$string = $this->string;
}

return sprintf(
'contains "%s"',
$string
);
}
}
<?php














class PHPUnit_Framework_Constraint_IsFalse extends PHPUnit_Framework_Constraint
{








protected function matches($other)
{
return $other === false;
}






public function toString()
{
return 'is false';
}
}
<?php















class PHPUnit_Framework_Constraint_StringEndsWith extends PHPUnit_Framework_Constraint
{



protected $suffix;




public function __construct($suffix)
{
parent::__construct();
$this->suffix = $suffix;
}









protected function matches($other)
{
return substr($other, 0 - strlen($this->suffix)) == $this->suffix;
}






public function toString()
{
return 'ends with "' . $this->suffix . '"';
}
}
<?php

















class PHPUnit_Framework_Constraint_IsInstanceOf extends PHPUnit_Framework_Constraint
{



protected $className;




public function __construct($className)
{
parent::__construct();
$this->className = $className;
}









protected function matches($other)
{
return ($other instanceof $this->className);
}











protected function failureDescription($other)
{
return sprintf(
'%s is an instance of %s "%s"',
$this->exporter->shortenedExport($other),
$this->getType(),
$this->className
);
}






public function toString()
{
return sprintf(
'is instance of %s "%s"',
$this->getType(),
$this->className
);
}

private function getType()
{
try {
$reflection = new ReflectionClass($this->className);
if ($reflection->isInterface()) {
return 'interface';
}
} catch (ReflectionException $e) {
}

return 'class';
}
}
<?php















class PHPUnit_Framework_Constraint_TraversableContains extends PHPUnit_Framework_Constraint
{



protected $checkForObjectIdentity;




protected $checkForNonObjectIdentity;




protected $value;








public function __construct($value, $checkForObjectIdentity = true, $checkForNonObjectIdentity = false)
{
parent::__construct();

if (!is_bool($checkForObjectIdentity)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'boolean');
}

if (!is_bool($checkForNonObjectIdentity)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(3, 'boolean');
}

$this->checkForObjectIdentity = $checkForObjectIdentity;
$this->checkForNonObjectIdentity = $checkForNonObjectIdentity;
$this->value = $value;
}









protected function matches($other)
{
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;
} else if (!$this->checkForObjectIdentity && $element == $this->value) {
return true;
}
}
} else {
foreach ($other as $element) {
if ($this->checkForNonObjectIdentity && $element === $this->value) {
return true;
} else if (!$this->checkForNonObjectIdentity && $element == $this->value) {
return true;
}
}
}

return false;
}






public function toString()
{
if (is_string($this->value) && strpos($this->value, "\n") !== false) {
return 'contains "' . $this->value . '"';
} else {
return 'contains ' . $this->exporter->export($this->value);
}
}











protected function failureDescription($other)
{
return sprintf(
'%s %s',
is_array($other) ? 'an array' : 'a traversable',
$this->toString()
);
}
}
<?php












class PHPUnit_Framework_Constraint_Count extends PHPUnit_Framework_Constraint
{



protected $expectedCount = 0;




public function __construct($expected)
{
parent::__construct();
$this->expectedCount = $expected;
}









protected function matches($other)
{
return $this->expectedCount === $this->getCountOf($other);
}






protected function getCountOf($other)
{
if ($other instanceof Countable || is_array($other)) {
return count($other);
} elseif ($other instanceof Traversable) {
if ($other instanceof IteratorAggregate) {
$iterator = $other->getIterator();
} else {
$iterator = $other;
}

$key = $iterator->key();
$count = iterator_count($iterator);


 
 if ($key !== null) {
$iterator->rewind();
while ($iterator->valid() && $key !== $iterator->key()) {
$iterator->next();
}
}

return $count;
}
}











protected function failureDescription($other)
{
return sprintf(
'actual size %d matches expected size %d',
$this->getCountOf($other),
$this->expectedCount
);
}




public function toString()
{
return sprintf(
'count matches %d',
$this->expectedCount
);
}
}
<?php












class PHPUnit_Framework_Constraint_SameSize extends PHPUnit_Framework_Constraint_Count
{



protected $expectedCount;




public function __construct($expected)
{
parent::__construct($this->getCountOf($expected));
}
}
<?php
















class PHPUnit_Framework_Constraint_FileExists extends PHPUnit_Framework_Constraint
{








protected function matches($other)
{
return file_exists($other);
}











protected function failureDescription($other)
{
return sprintf(
'file "%s" exists',
$other
);
}






public function toString()
{
return 'file exists';
}
}
<?php















class PHPUnit_Framework_Constraint_TraversableContainsOnly extends PHPUnit_Framework_Constraint
{



protected $constraint;




protected $type;





public function __construct($type, $isNativeType = true)
{
parent::__construct();

if ($isNativeType) {
$this->constraint = new PHPUnit_Framework_Constraint_IsType($type);
} else {
$this->constraint = new PHPUnit_Framework_Constraint_IsInstanceOf(
$type
);
}

$this->type = $type;
}



















public function evaluate($other, $description = '', $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()
{
return 'contains only values of type "' . $this->type . '"';
}
}
<?php




















class PHPUnit_Framework_Constraint_IsEqual extends PHPUnit_Framework_Constraint
{



protected $value;




protected $delta = 0.0;




protected $maxDepth = 10;




protected $canonicalize = false;




protected $ignoreCase = false;




protected $lastFailure;










public function __construct($value, $delta = 0.0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false)
{
parent::__construct();

if (!is_numeric($delta)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'numeric');
}

if (!is_int($maxDepth)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(3, 'integer');
}

if (!is_bool($canonicalize)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(4, 'boolean');
}

if (!is_bool($ignoreCase)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(5, 'boolean');
}

$this->value = $value;
$this->delta = $delta;
$this->maxDepth = $maxDepth;
$this->canonicalize = $canonicalize;
$this->ignoreCase = $ignoreCase;
}



















public function evaluate($other, $description = '', $returnResult = false)
{

 
 
 if ($this->value === $other) {
return true;
}

$comparatorFactory = SebastianBergmann\Comparator\Factory::getInstance();

try {
$comparator = $comparatorFactory->getComparatorFor(
$this->value,
$other
);

$comparator->assertEquals(
$this->value,
$other,
$this->delta,
$this->canonicalize,
$this->ignoreCase
);
} catch (SebastianBergmann\Comparator\ComparisonFailure $f) {
if ($returnResult) {
return false;
}

throw new PHPUnit_Framework_ExpectationFailedException(
trim($description . "\n" . $f->getMessage()),
$f
);
}

return true;
}






public function toString()
{
$delta = '';

if (is_string($this->value)) {
if (strpos($this->value, "\n") !== false) {
return 'is equal to <text>';
} else {
return sprintf(
'is equal to <string:%s>',
$this->value
);
}
} else {
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














class PHPUnit_Framework_Constraint_And extends PHPUnit_Framework_Constraint
{



protected $constraints = array();




protected $lastConstraint = null;






public function setConstraints(array $constraints)
{
$this->constraints = array();

foreach ($constraints as $constraint) {
if (!($constraint instanceof PHPUnit_Framework_Constraint)) {
throw new PHPUnit_Framework_Exception(
'All parameters to ' . __CLASS__ .
' must be a constraint object.'
);
}

$this->constraints[] = $constraint;
}
}



















public function evaluate($other, $description = '', $returnResult = false)
{
$success = true;
$constraint = null;

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()
{
$text = '';

foreach ($this->constraints as $key => $constraint) {
if ($key > 0) {
$text .= ' and ';
}

$text .= $constraint->toString();
}

return $text;
}








public function count()
{
$count = 0;

foreach ($this->constraints as $constraint) {
$count += count($constraint);
}

return $count;
}
}
<?php














class PHPUnit_Framework_Constraint_IsAnything extends PHPUnit_Framework_Constraint
{


















public function evaluate($other, $description = '', $returnResult = false)
{
return $returnResult ? true : null;
}






public function toString()
{
return 'is anything';
}








public function count()
{
return 0;
}
}
<?php



















class PHPUnit_Framework_Constraint_ArrayHasKey extends PHPUnit_Framework_Constraint
{



protected $key;




public function __construct($key)
{
parent::__construct();
$this->key = $key;
}









protected function matches($other)
{
if (is_array($other)) {
return array_key_exists($this->key, $other);
}

if ($other instanceof ArrayAccess) {
return $other->offsetExists($this->key);
}

return false;
}






public function toString()
{
return 'has the key ' . $this->exporter->export($this->key);
}











protected function failureDescription($other)
{
return 'an array ' . $this->toString();
}
}
<?php

















class PHPUnit_Framework_Constraint_ArraySubset extends PHPUnit_Framework_Constraint
{



protected $subset;




protected $strict;





public function __construct($subset, $strict = false)
{
parent::__construct();
$this->strict = $strict;
$this->subset = $subset;
}









protected function matches($other)
{
$patched = array_replace_recursive($other, $this->subset);

if ($this->strict) {
return $other === $patched;
} else {
return $other == $patched;
}
}






public function toString()
{
return 'has the subset ' . $this->exporter->export($this->subset);
}











protected function failureDescription($other)
{
return 'an array ' . $this->toString();
}
}
<?php












class PHPUnit_Framework_Constraint_ExceptionCode extends PHPUnit_Framework_Constraint
{



protected $expectedCode;




public function __construct($expected)
{
parent::__construct();
$this->expectedCode = $expected;
}









protected function matches($other)
{
return (string) $other->getCode() == (string) $this->expectedCode;
}











protected function failureDescription($other)
{
return sprintf(
'%s is equal to expected exception code %s',
$this->exporter->export($other->getCode()),
$this->exporter->export($this->expectedCode)
);
}




public function toString()
{
return 'exception code is ';
}
}
<?php












class PHPUnit_Framework_Constraint_Callback extends PHPUnit_Framework_Constraint
{
private $callback;






public function __construct($callback)
{
if (!is_callable($callback)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(
1,
'callable'
);
}

parent::__construct();

$this->callback = $callback;
}









protected function matches($other)
{
return call_user_func($this->callback, $other);
}






public function toString()
{
return 'is accepted by specified callback';
}
}
<?php












class PHPUnit_Framework_Constraint_Attribute extends PHPUnit_Framework_Constraint_Composite
{



protected $attributeName;





public function __construct(PHPUnit_Framework_Constraint $constraint, $attributeName)
{
parent::__construct($constraint);

$this->attributeName = $attributeName;
}



















public function evaluate($other, $description = '', $returnResult = false)
{
return parent::evaluate(
PHPUnit_Framework_Assert::readAttribute(
$other,
$this->attributeName
),
$description,
$returnResult
);
}






public function toString()
{
return 'attribute "' . $this->attributeName . '" ' .
$this->innerConstraint->toString();
}











protected function failureDescription($other)
{
return $this->toString();
}
}
<?php














class PHPUnit_Framework_Constraint_JsonMatches extends PHPUnit_Framework_Constraint
{



protected $value;






public function __construct($value)
{
parent::__construct();
$this->value = $value;
}











protected function matches($other)
{
$decodedOther = json_decode($other);
if (json_last_error()) {
return false;
}

$decodedValue = json_decode($this->value);
if (json_last_error()) {
return false;
}

return $decodedOther == $decodedValue;
}






public function toString()
{
return sprintf(
'matches JSON string "%s"',
$this->value
);
}
}
<?php














class PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider
{








public static function determineJsonError($error, $prefix = '')
{
switch ($error) {
case JSON_ERROR_NONE:
return;
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($type)
{
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












class PHPUnit_Framework_Constraint_ExceptionMessage extends PHPUnit_Framework_Constraint
{



protected $expectedMessage;




public function __construct($expected)
{
parent::__construct();
$this->expectedMessage = $expected;
}









protected function matches($other)
{
return strpos($other->getMessage(), $this->expectedMessage) !== false;
}











protected function failureDescription($other)
{
return sprintf(
"exception message '%s' contains '%s'",
$other->getMessage(),
$this->expectedMessage
);
}




public function toString()
{
return 'exception message contains ';
}
}
<?php















class PHPUnit_Framework_Constraint_LessThan extends PHPUnit_Framework_Constraint
{



protected $value;




public function __construct($value)
{
parent::__construct();
$this->value = $value;
}









protected function matches($other)
{
return $this->value > $other;
}






public function toString()
{
return 'is less than ' . $this->exporter->export($this->value);
}
}
<?php















class PHPUnit_Framework_Constraint_GreaterThan extends PHPUnit_Framework_Constraint
{



protected $value;




public function __construct($value)
{
parent::__construct();
$this->value = $value;
}









protected function matches($other)
{
return $this->value < $other;
}






public function toString()
{
return 'is greater than ' . $this->exporter->export($this->value);
}
}
<?php














class PHPUnit_Framework_Constraint_IsTrue extends PHPUnit_Framework_Constraint
{








protected function matches($other)
{
return $other === true;
}






public function toString()
{
return 'is true';
}
}
<?php












class PHPUnit_Framework_Constraint_ExceptionMessageRegExp extends PHPUnit_Framework_Constraint
{



protected $expectedMessageRegExp;




public function __construct($expected)
{
parent::__construct();
$this->expectedMessageRegExp = $expected;
}









protected function matches($other)
{
$match = PHPUnit_Util_Regex::pregMatchSafe($this->expectedMessageRegExp, $other->getMessage());

if (false === $match) {
throw new PHPUnit_Framework_Exception(
"Invalid expected exception message regex given: '{$this->expectedMessageRegExp}'"
);
}

return 1 === $match;
}











protected function failureDescription($other)
{
return sprintf(
"exception message '%s' matches '%s'",
$other->getMessage(),
$this->expectedMessageRegExp
);
}




public function toString()
{
return 'exception message matches ';
}
}
<?php






















class PHPUnit_Framework_Constraint_IsIdentical extends PHPUnit_Framework_Constraint
{



const EPSILON = 0.0000000001;




protected $value;




public function __construct($value)
{
parent::__construct();
$this->value = $value;
}



















public function evaluate($other, $description = '', $returnResult = false)
{
if (is_double($this->value) && is_double($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 SebastianBergmann\Comparator\ComparisonFailure(
$this->value,
$other,
$this->value,
$other
);
}

$this->fail($other, $description, $f);
}
}











protected function failureDescription($other)
{
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';
}

return parent::failureDescription($other);
}






public function toString()
{
if (is_object($this->value)) {
return 'is identical to an object of class "' .
get_class($this->value) . '"';
} else {
return 'is identical to ' .
$this->exporter->export($this->value);
}
}
}
<?php

















class PHPUnit_Framework_Constraint_IsType extends PHPUnit_Framework_Constraint
{
const TYPE_ARRAY = 'array';
const TYPE_BOOL = 'bool';
const TYPE_FLOAT = 'float';
const TYPE_INT = 'int';
const TYPE_NULL = 'null';
const TYPE_NUMERIC = 'numeric';
const TYPE_OBJECT = 'object';
const TYPE_RESOURCE = 'resource';
const TYPE_STRING = 'string';
const TYPE_SCALAR = 'scalar';
const TYPE_CALLABLE = 'callable';




protected $types = array(
'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
);




protected $type;






public function __construct($type)
{
parent::__construct();

if (!isset($this->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;
}









protected function matches($other)
{
switch ($this->type) {
case 'numeric':
return is_numeric($other);

case 'integer':
case 'int':
return is_integer($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 is_null($other);

case 'array':
return is_array($other);

case 'object':
return is_object($other);

case 'resource':
return is_resource($other) || is_string(@get_resource_type($other));

case 'scalar':
return is_scalar($other);

case 'callable':
return is_callable($other);
}
}






public function toString()
{
return sprintf(
'is of type "%s"',
$this->type
);
}
}
<?php

















class PHPUnit_Framework_Constraint_ClassHasAttribute extends PHPUnit_Framework_Constraint
{



protected $attributeName;




public function __construct($attributeName)
{
parent::__construct();
$this->attributeName = $attributeName;
}









protected function matches($other)
{
$class = new ReflectionClass($other);

return $class->hasProperty($this->attributeName);
}






public function toString()
{
return sprintf(
'has attribute "%s"',
$this->attributeName
);
}











protected function failureDescription($other)
{
return sprintf(
'%sclass "%s" %s',
is_object($other) ? 'object of ' : '',
is_object($other) ? get_class($other) : $other,
$this->toString()
);
}
}
<?php




















class PHPUnit_Framework_Constraint_PCREMatch extends PHPUnit_Framework_Constraint
{



protected $pattern;




public function __construct($pattern)
{
parent::__construct();
$this->pattern = $pattern;
}









protected function matches($other)
{
return preg_match($this->pattern, $other) > 0;
}






public function toString()
{
return sprintf(
'matches PCRE pattern "%s"',
$this->pattern
);
}
}
<?php












class PHPUnit_Framework_Constraint_Exception extends PHPUnit_Framework_Constraint
{



protected $className;




public function __construct($className)
{
parent::__construct();
$this->className = $className;
}









protected function matches($other)
{
return $other instanceof $this->className;
}











protected function failureDescription($other)
{
if ($other !== null) {
$message = '';
if ($other instanceof Exception) {
$message = '. Message was: "' . $other->getMessage() . '" at'
. "\n" . $other->getTraceAsString();
}

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
);
}






public function toString()
{
return sprintf(
'exception of type "%s"',
$this->className
);
}
}
<?php















class PHPUnit_Framework_Constraint_StringStartsWith extends PHPUnit_Framework_Constraint
{



protected $prefix;




public function __construct($prefix)
{
parent::__construct();
$this->prefix = $prefix;
}









protected function matches($other)
{
return strpos($other, $this->prefix) === 0;
}






public function toString()
{
return 'starts with "' . $this->prefix . '"';
}
}
<?php

















class PHPUnit_Framework_Constraint_ObjectHasAttribute extends PHPUnit_Framework_Constraint_ClassHasAttribute
{








protected function matches($other)
{
$object = new ReflectionObject($other);

return $object->hasProperty($this->attributeName);
}
}
<?php












abstract class PHPUnit_Framework_Constraint_Composite extends PHPUnit_Framework_Constraint
{



protected $innerConstraint;




public function __construct(PHPUnit_Framework_Constraint $innerConstraint)
{
parent::__construct();
$this->innerConstraint = $innerConstraint;
}



















public function evaluate($other, $description = '', $returnResult = false)
{
try {
return $this->innerConstraint->evaluate(
$other,
$description,
$returnResult
);
} catch (PHPUnit_Framework_ExpectationFailedException $e) {
$this->fail($other, $description);
}
}






public function count()
{
return count($this->innerConstraint);
}
}
<?php









use SebastianBergmann\Diff\Differ;






class PHPUnit_Framework_Constraint_StringMatches extends PHPUnit_Framework_Constraint_PCREMatch
{



protected $string;




public function __construct($string)
{
parent::__construct($string);

$this->pattern = $this->createPatternFromFormat(
preg_replace('/\r\n/', "\n", $string)
);

$this->string = $string;
}

protected function failureDescription($other)
{
return 'format description matches text';
}

protected function additionalFailureDescription($other)
{
$from = preg_split('(\r\n|\r|\n)', $this->string);
$to = preg_split('(\r\n|\r|\n)', $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);

$differ = new Differ("--- Expected\n+++ Actual\n");

return $differ->diff($this->string, $other);
}

protected function createPatternFromFormat($string)
{
$string = str_replace(
array(
'%e',
'%s',
'%S',
'%a',
'%A',
'%w',
'%i',
'%d',
'%x',
'%f',
'%c'
),
array(
'\\' . DIRECTORY_SEPARATOR,
'[^\r\n]+',
'[^\r\n]*',
'.+',
'.*',
'\s*',
'[+-]?\d+',
'\d+',
'[0-9a-fA-F]+',
'[+-]?\.?\d+\.?\d*(?:[Ee][+-]?\d+)?',
'.'
),
preg_quote($string, '/')
);

return '/^' . $string . '$/s';
}
}
<?php














class PHPUnit_Framework_Constraint_IsJson extends PHPUnit_Framework_Constraint
{








protected function matches($other)
{
json_decode($other);
if (json_last_error()) {
return false;
}

return true;
}











protected function failureDescription($other)
{
json_decode($other);
$error = PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider::determineJsonError(
json_last_error()
);

return sprintf(
'%s is valid JSON (%s)',
$this->exporter->shortenedExport($other),
$error
);
}






public function toString()
{
return 'is valid JSON';
}
}
<?php














class PHPUnit_Framework_Constraint_Or extends PHPUnit_Framework_Constraint
{



protected $constraints = array();




public function setConstraints(array $constraints)
{
$this->constraints = array();

foreach ($constraints as $constraint) {
if (!($constraint instanceof PHPUnit_Framework_Constraint)) {
$constraint = new PHPUnit_Framework_Constraint_IsEqual(
$constraint
);
}

$this->constraints[] = $constraint;
}
}



















public function evaluate($other, $description = '', $returnResult = false)
{
$success = false;
$constraint = null;

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()
{
$text = '';

foreach ($this->constraints as $key => $constraint) {
if ($key > 0) {
$text .= ' or ';
}

$text .= $constraint->toString();
}

return $text;
}








public function count()
{
$count = 0;

foreach ($this->constraints as $constraint) {
$count += count($constraint);
}

return $count;
}
}
<?php















class PHPUnit_Framework_OutputError extends PHPUnit_Framework_AssertionFailedError
{
}
<?php














class PHPUnit_Framework_AssertionFailedError extends PHPUnit_Framework_Exception implements PHPUnit_Framework_SelfDescribing
{





public function toString()
{
return $this->getMessage();
}
}
<?php














interface PHPUnit_Framework_TestListener
{







public function addError(PHPUnit_Framework_Test $test, Exception $e, $time);








public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time);








public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time);










public function addRiskyTest(PHPUnit_Framework_Test $test, Exception $e, $time);










public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time);








public function startTestSuite(PHPUnit_Framework_TestSuite $suite);








public function endTestSuite(PHPUnit_Framework_TestSuite $suite);






public function startTest(PHPUnit_Framework_Test $test);







public function endTest(PHPUnit_Framework_Test $test, $time);
}
<?php


















class PHPUnit_Framework_ExpectationFailedException extends PHPUnit_Framework_AssertionFailedError
{



protected $comparisonFailure;

public function __construct($message, SebastianBergmann\Comparator\ComparisonFailure $comparisonFailure = null, Exception $previous = null)
{
$this->comparisonFailure = $comparisonFailure;

parent::__construct($message, 0, $previous);
}




public function getComparisonFailure()
{
return $this->comparisonFailure;
}
}
<?php














class PHPUnit_Framework_Warning extends PHPUnit_Framework_TestCase
{



protected $message = '';




protected $backupGlobals = false;




protected $backupStaticAttributes = false;




protected $runTestInSeparateProcess = false;




protected $useErrorHandler = false;




public function __construct($message = '')
{
$this->message = $message;
parent::__construct('Warning');
}




protected function runTest()
{
$this->fail($this->message);
}






public function getMessage()
{
return $this->message;
}








public function toString()
{
return 'Warning';
}
}
<?php















class PHPUnit_Framework_RiskyTestError extends PHPUnit_Framework_AssertionFailedError implements PHPUnit_Framework_RiskyTest
{
}
<?php



















class PHPUnit_Framework_Error_Deprecated extends PHPUnit_Framework_Error
{
public static $enabled = true;
}
<?php



















class PHPUnit_Framework_Error_Notice extends PHPUnit_Framework_Error
{
public static $enabled = true;
}
<?php



















class PHPUnit_Framework_Error_Warning extends PHPUnit_Framework_Error
{
public static $enabled = true;
}
<?php















class PHPUnit_Framework_SkippedTestError extends PHPUnit_Framework_AssertionFailedError implements PHPUnit_Framework_SkippedTest
{
}
<?php
















abstract class PHPUnit_Framework_BaseTestListener implements PHPUnit_Framework_TestListener
{
public function addError(PHPUnit_Framework_Test $test, Exception $e, $time)
{
}

public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time)
{
}

public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
}

public function addRiskyTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
}

public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
}

public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
{
}

public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
{
}

public function startTest(PHPUnit_Framework_Test $test)
{
}

public function endTest(PHPUnit_Framework_Test $test, $time)
{
}
}
<?php














class PHPUnit_Framework_TestFailure
{



private $testName;




protected $failedTest;




protected $thrownException;







public function __construct(PHPUnit_Framework_Test $failedTest, Exception $thrownException)
{
if ($failedTest instanceof PHPUnit_Framework_SelfDescribing) {
$this->testName = $failedTest->toString();
} else {
$this->testName = get_class($failedTest);
}
if (!$failedTest instanceof PHPUnit_Framework_TestCase || !$failedTest->isInIsolation()) {
$this->failedTest = $failedTest;
}
$this->thrownException = $thrownException;
}






public function toString()
{
return sprintf(
'%s: %s',
$this->testName,
$this->thrownException->getMessage()
);
}








public function getExceptionAsString()
{
return self::exceptionToString($this->thrownException);
}










public static function exceptionToString(Exception $e)
{
if ($e instanceof PHPUnit_Framework_SelfDescribing) {
$buffer = $e->toString();

if ($e instanceof PHPUnit_Framework_ExpectationFailedException && $e->getComparisonFailure()) {
$buffer = $buffer . $e->getComparisonFailure()->getDiff();
}

if (!empty($buffer)) {
$buffer = trim($buffer) . "\n";
}
} elseif ($e instanceof PHPUnit_Framework_Error) {
$buffer = $e->getMessage() . "\n";
} elseif ($e instanceof PHPUnit_Framework_ExceptionWrapper) {
$buffer = $e->getClassname() . ': ' . $e->getMessage() . "\n";
} else {
$buffer = get_class($e) . ': ' . $e->getMessage() . "\n";
}

return $buffer;
}








public function getTestName()
{
return $this->testName;
}











public function failedTest()
{
return $this->failedTest;
}






public function thrownException()
{
return $this->thrownException;
}






public function exceptionMessage()
{
return $this->thrownException()->getMessage();
}







public function isFailure()
{
return ($this->thrownException() instanceof PHPUnit_Framework_AssertionFailedError);
}
}
<?php














class PHPUnit_Framework_SkippedTestCase extends PHPUnit_Framework_TestCase
{



protected $message = '';




protected $backupGlobals = false;




protected $backupStaticAttributes = false;




protected $runTestInSeparateProcess = false;




protected $useErrorHandler = false;




protected $useOutputBuffering = false;




public function __construct($className, $methodName, $message = '')
{
$this->message = $message;
parent::__construct($className . '::' . $methodName);
}




protected function runTest()
{
$this->markTestSkipped($this->message);
}




public function getMessage()
{
return $this->message;
}






public function toString()
{
return $this->getName();
}
}
<?php






























class PHPUnit_Framework_Exception extends RuntimeException implements PHPUnit_Exception
{



protected $serializableTrace;

public function __construct($message = '', $code = 0, Exception $previous = null)
{
parent::__construct($message, $code, $previous);

$this->serializableTrace = $this->getTrace();
foreach ($this->serializableTrace as $i => $call) {
unset($this->serializableTrace[$i]['args']);
}
}






public function getSerializableTrace()
{
return $this->serializableTrace;
}




public function __toString()
{
$string = PHPUnit_Framework_TestFailure::exceptionToString($this);

if ($trace = PHPUnit_Util_Filter::getFilteredStacktrace($this)) {
$string .= "\n" . $trace;
}

return $string;
}

public function __sleep()
{
return array_keys(get_object_vars($this));
}
}
<?php














interface PHPUnit_Framework_SkippedTest
{
}
<?php









use SebastianBergmann\Exporter\Exporter;






abstract class PHPUnit_Framework_Constraint implements Countable, PHPUnit_Framework_SelfDescribing
{
protected $exporter;

public function __construct()
{
$this->exporter = new Exporter;
}



















public function evaluate($other, $description = '', $returnResult = false)
{
$success = false;

if ($this->matches($other)) {
$success = true;
}

if ($returnResult) {
return $success;
}

if (!$success) {
$this->fail($other, $description);
}
}











protected function matches($other)
{
return false;
}








public function count()
{
return 1;
}










protected function fail($other, $description, SebastianBergmann\Comparator\ComparisonFailure $comparisonFailure = null)
{
$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 PHPUnit_Framework_ExpectationFailedException(
$failureDescription,
$comparisonFailure
);
}











protected function additionalFailureDescription($other)
{
return '';
}














protected function failureDescription($other)
{
return $this->exporter->export($other) . ' ' . $this->toString();
}
}
<?php














class PHPUnit_Framework_TestResult implements Countable
{



protected $passed = array();




protected $errors = array();




protected $failures = array();




protected $notImplemented = array();




protected $risky = array();




protected $skipped = array();




protected $listeners = array();




protected $runTests = 0;




protected $time = 0;




protected $topTestSuite = null;






protected $codeCoverage;




protected $convertErrorsToExceptions = true;




protected $stop = false;




protected $stopOnError = false;




protected $stopOnFailure = false;




protected $beStrictAboutTestsThatDoNotTestAnything = false;




protected $beStrictAboutOutputDuringTests = false;




protected $beStrictAboutTestSize = false;




protected $beStrictAboutTodoAnnotatedTests = false;




protected $stopOnRisky = false;




protected $stopOnIncomplete = false;




protected $stopOnSkipped = false;




protected $lastTestFailed = false;




protected $timeoutForSmallTests = 1;




protected $timeoutForMediumTests = 10;




protected $timeoutForLargeTests = 60;






public function addListener(PHPUnit_Framework_TestListener $listener)
{
$this->listeners[] = $listener;
}






public function removeListener(PHPUnit_Framework_TestListener $listener)
{
foreach ($this->listeners as $key => $_listener) {
if ($listener === $_listener) {
unset($this->listeners[$key]);
}
}
}






public function flushListeners()
{
foreach ($this->listeners as $listener) {
if ($listener instanceof PHPUnit_Util_Printer) {
$listener->flush();
}
}
}








public function addError(PHPUnit_Framework_Test $test, Exception $e, $time)
{
if ($e instanceof PHPUnit_Framework_RiskyTest) {
$this->risky[] = new PHPUnit_Framework_TestFailure($test, $e);
$notifyMethod = 'addRiskyTest';

if ($this->stopOnRisky) {
$this->stop();
}
} elseif ($e instanceof PHPUnit_Framework_IncompleteTest) {
$this->notImplemented[] = new PHPUnit_Framework_TestFailure($test, $e);
$notifyMethod = 'addIncompleteTest';

if ($this->stopOnIncomplete) {
$this->stop();
}
} elseif ($e instanceof PHPUnit_Framework_SkippedTest) {
$this->skipped[] = new PHPUnit_Framework_TestFailure($test, $e);
$notifyMethod = 'addSkippedTest';

if ($this->stopOnSkipped) {
$this->stop();
}
} else {
$this->errors[] = new PHPUnit_Framework_TestFailure($test, $e);
$notifyMethod = 'addError';

if ($this->stopOnError || $this->stopOnFailure) {
$this->stop();
}
}

foreach ($this->listeners as $listener) {
$listener->$notifyMethod($test, $e, $time);
}

$this->lastTestFailed = true;
$this->time += $time;
}









public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time)
{
if ($e instanceof PHPUnit_Framework_RiskyTest ||
$e instanceof PHPUnit_Framework_OutputError) {
$this->risky[] = new PHPUnit_Framework_TestFailure($test, $e);
$notifyMethod = 'addRiskyTest';

if ($this->stopOnRisky) {
$this->stop();
}
} elseif ($e instanceof PHPUnit_Framework_IncompleteTest) {
$this->notImplemented[] = new PHPUnit_Framework_TestFailure($test, $e);
$notifyMethod = 'addIncompleteTest';

if ($this->stopOnIncomplete) {
$this->stop();
}
} elseif ($e instanceof PHPUnit_Framework_SkippedTest) {
$this->skipped[] = new PHPUnit_Framework_TestFailure($test, $e);
$notifyMethod = 'addSkippedTest';

if ($this->stopOnSkipped) {
$this->stop();
}
} else {
$this->failures[] = new PHPUnit_Framework_TestFailure($test, $e);
$notifyMethod = 'addFailure';

if ($this->stopOnFailure) {
$this->stop();
}
}

foreach ($this->listeners as $listener) {
$listener->$notifyMethod($test, $e, $time);
}

$this->lastTestFailed = true;
$this->time += $time;
}








public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
{
if ($this->topTestSuite === null) {
$this->topTestSuite = $suite;
}

foreach ($this->listeners as $listener) {
$listener->startTestSuite($suite);
}
}








public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
{
foreach ($this->listeners as $listener) {
$listener->endTestSuite($suite);
}
}






public function startTest(PHPUnit_Framework_Test $test)
{
$this->lastTestFailed = false;
$this->runTests += count($test);

foreach ($this->listeners as $listener) {
$listener->startTest($test);
}
}







public function endTest(PHPUnit_Framework_Test $test, $time)
{
foreach ($this->listeners as $listener) {
$listener->endTest($test, $time);
}

if (!$this->lastTestFailed && $test instanceof PHPUnit_Framework_TestCase) {
$class = get_class($test);
$key = $class . '::' . $test->getName();

$this->passed[$key] = array(
'result' => $test->getResult(),
'size' => PHPUnit_Util_Test::getSize(
$class,
$test->getName(false)
)
);

$this->time += $time;
}
}








public function allHarmless()
{
return $this->riskyCount() == 0;
}








public function riskyCount()
{
return count($this->risky);
}






public function allCompletelyImplemented()
{
return $this->notImplementedCount() == 0;
}






public function notImplementedCount()
{
return count($this->notImplemented);
}








public function risky()
{
return $this->risky;
}






public function notImplemented()
{
return $this->notImplemented;
}








public function noneSkipped()
{
return $this->skippedCount() == 0;
}








public function skippedCount()
{
return count($this->skipped);
}








public function skipped()
{
return $this->skipped;
}






public function errorCount()
{
return count($this->errors);
}






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






public function failureCount()
{
return count($this->failures);
}






public function failures()
{
return $this->failures;
}








public function passed()
{
return $this->passed;
}








public function topTestSuite()
{
return $this->topTestSuite;
}








public function getCollectCodeCoverageInformation()
{
return $this->codeCoverage !== null;
}






public function run(PHPUnit_Framework_Test $test)
{
PHPUnit_Framework_Assert::resetCount();

$error = false;
$failure = false;
$incomplete = false;
$risky = false;
$skipped = false;

$this->startTest($test);

$errorHandlerSet = false;

if ($this->convertErrorsToExceptions) {
$oldErrorHandler = set_error_handler(
array('PHPUnit_Util_ErrorHandler', 'handleError'),
E_ALL | E_STRICT
);

if ($oldErrorHandler === null) {
$errorHandlerSet = true;
} else {
restore_error_handler();
}
}

$collectCodeCoverage = $this->codeCoverage !== null &&
!$test instanceof PHPUnit_Extensions_SeleniumTestCase &&
!$test instanceof PHPUnit_Framework_Warning;

if ($collectCodeCoverage) {

 if (!$this->codeCoverage->filter()->hasWhitelist()) {
$classes = $this->getHierarchy(get_class($test), true);

foreach ($classes as $class) {
$this->codeCoverage->filter()->addFileToBlacklist(
$class->getFileName()
);
}
}

$this->codeCoverage->start($test);
}

PHP_Timer::start();

try {
if (!$test instanceof PHPUnit_Framework_Warning &&
$test->getSize() != PHPUnit_Util_Test::UNKNOWN &&
$this->beStrictAboutTestSize &&
extension_loaded('pcntl') && class_exists('PHP_Invoker')) {
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;
}

$invoker = new PHP_Invoker;
$invoker->invoke(array($test, 'runBare'), array(), $_timeout);
} else {
$test->runBare();
}
} catch (PHPUnit_Framework_AssertionFailedError $e) {
$failure = true;

if ($e instanceof PHPUnit_Framework_RiskyTestError) {
$risky = true;
} elseif ($e instanceof PHPUnit_Framework_IncompleteTestError) {
$incomplete = true;
} elseif ($e instanceof PHPUnit_Framework_SkippedTestError) {
$skipped = true;
}
} catch (PHPUnit_Framework_Exception $e) {
$error = true;
} catch (Throwable $e) {
$e = new PHPUnit_Framework_ExceptionWrapper($e);
$error = true;
} catch (Exception $e) {
$e = new PHPUnit_Framework_ExceptionWrapper($e);
$error = true;
}

$time = PHP_Timer::stop();
$test->addToAssertionCount(PHPUnit_Framework_Assert::getCount());

if ($this->beStrictAboutTestsThatDoNotTestAnything &&
$test->getNumAssertions() == 0) {
$risky = true;
}

if ($collectCodeCoverage) {
$append = !$risky && !$incomplete && !$skipped;
$linesToBeCovered = array();
$linesToBeUsed = array();

if ($append && $test instanceof PHPUnit_Framework_TestCase) {
$linesToBeCovered = PHPUnit_Util_Test::getLinesToBeCovered(
get_class($test),
$test->getName(false)
);

$linesToBeUsed = PHPUnit_Util_Test::getLinesToBeUsed(
get_class($test),
$test->getName(false)
);
}

try {
$this->codeCoverage->stop(
$append,
$linesToBeCovered,
$linesToBeUsed
);
} catch (PHP_CodeCoverage_Exception_UnintentionallyCoveredCode $cce) {
$this->addFailure(
$test,
new PHPUnit_Framework_UnintentionallyCoveredCodeError(
'This test executed code that is not listed as code to be covered or used:' .
PHP_EOL . $cce->getMessage()
),
$time
);
} catch (PHPUnit_Framework_InvalidCoversTargetException $cce) {
$this->addFailure(
$test,
new PHPUnit_Framework_InvalidCoversTargetError(
$cce->getMessage()
),
$time
);
} catch (PHP_CodeCoverage_Exception $cce) {
$error = true;

if (!isset($e)) {
$e = $cce;
}
}
}

if ($errorHandlerSet === true) {
restore_error_handler();
}

if ($error === true) {
$this->addError($test, $e, $time);
} elseif ($failure === true) {
$this->addFailure($test, $e, $time);
} elseif ($this->beStrictAboutTestsThatDoNotTestAnything &&
$test->getNumAssertions() == 0) {
$this->addFailure(
$test,
new PHPUnit_Framework_RiskyTestError(
'This test did not perform any assertions'
),
$time
);
} elseif ($this->beStrictAboutOutputDuringTests && $test->hasOutput()) {
$this->addFailure(
$test,
new PHPUnit_Framework_OutputError(
sprintf(
'This test printed output: %s',
$test->getActualOutput()
)
),
$time
);
} elseif ($this->beStrictAboutTodoAnnotatedTests && $test instanceof PHPUnit_Framework_TestCase) {
$annotations = $test->getAnnotations();

if (isset($annotations['method']['todo'])) {
$this->addFailure(
$test,
new PHPUnit_Framework_RiskyTestError(
'Test method is annotated with @todo'
),
$time
);
}
}

$this->endTest($test, $time);
}






public function count()
{
return $this->runTests;
}






public function shouldStop()
{
return $this->stop;
}




public function stop()
{
$this->stop = true;
}








public function getCodeCoverage()
{
return $this->codeCoverage;
}








public function setCodeCoverage(PHP_CodeCoverage $codeCoverage)
{
$this->codeCoverage = $codeCoverage;
}










public function convertErrorsToExceptions($flag)
{
if (!is_bool($flag)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean');
}

$this->convertErrorsToExceptions = $flag;
}








public function getConvertErrorsToExceptions()
{
return $this->convertErrorsToExceptions;
}










public function stopOnError($flag)
{
if (!is_bool($flag)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean');
}

$this->stopOnError = $flag;
}










public function stopOnFailure($flag)
{
if (!is_bool($flag)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean');
}

$this->stopOnFailure = $flag;
}








public function beStrictAboutTestsThatDoNotTestAnything($flag)
{
if (!is_bool($flag)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean');
}

$this->beStrictAboutTestsThatDoNotTestAnything = $flag;
}






public function isStrictAboutTestsThatDoNotTestAnything()
{
return $this->beStrictAboutTestsThatDoNotTestAnything;
}








public function beStrictAboutOutputDuringTests($flag)
{
if (!is_bool($flag)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean');
}

$this->beStrictAboutOutputDuringTests = $flag;
}






public function isStrictAboutOutputDuringTests()
{
return $this->beStrictAboutOutputDuringTests;
}








public function beStrictAboutTestSize($flag)
{
if (!is_bool($flag)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean');
}

$this->beStrictAboutTestSize = $flag;
}






public function isStrictAboutTestSize()
{
return $this->beStrictAboutTestSize;
}








public function beStrictAboutTodoAnnotatedTests($flag)
{
if (!is_bool($flag)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean');
}

$this->beStrictAboutTodoAnnotatedTests = $flag;
}






public function isStrictAboutTodoAnnotatedTests()
{
return $this->beStrictAboutTodoAnnotatedTests;
}










public function stopOnRisky($flag)
{
if (!is_bool($flag)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean');
}

$this->stopOnRisky = $flag;
}










public function stopOnIncomplete($flag)
{
if (!is_bool($flag)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean');
}

$this->stopOnIncomplete = $flag;
}










public function stopOnSkipped($flag)
{
if (!is_bool($flag)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean');
}

$this->stopOnSkipped = $flag;
}






public function time()
{
return $this->time;
}






public function wasSuccessful()
{
return empty($this->errors) && empty($this->failures);
}










public function setTimeoutForSmallTests($timeout)
{
if (!is_integer($timeout)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'integer');
}

$this->timeoutForSmallTests = $timeout;
}










public function setTimeoutForMediumTests($timeout)
{
if (!is_integer($timeout)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'integer');
}

$this->timeoutForMediumTests = $timeout;
}










public function setTimeoutForLargeTests($timeout)
{
if (!is_integer($timeout)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'integer');
}

$this->timeoutForLargeTests = $timeout;
}









protected function getHierarchy($className, $asReflectionObjects = false)
{
if ($asReflectionObjects) {
$classes = array(new ReflectionClass($className));
} else {
$classes = array($className);
}

$done = false;

while (!$done) {
if ($asReflectionObjects) {
$class = new ReflectionClass(
$classes[count($classes) - 1]->getName()
);
} else {
$class = new ReflectionClass($classes[count($classes) - 1]);
}

$parent = $class->getParentClass();

if ($parent !== false) {
if ($asReflectionObjects) {
$classes[] = $parent;
} else {
$classes[] = $parent->getName();
}
} else {
$done = true;
}
}

return $classes;
}
}
<?php














interface PHPUnit_Framework_SelfDescribing
{





public function toString();
}
<?php














class PHPUnit_Framework_IncompleteTestCase extends PHPUnit_Framework_TestCase
{



protected $message = '';




protected $backupGlobals = false;




protected $backupStaticAttributes = false;




protected $runTestInSeparateProcess = false;




protected $useErrorHandler = false;




protected $useOutputBuffering = false;






public function __construct($className, $methodName, $message = '')
{
$this->message = $message;
parent::__construct($className . '::' . $methodName);
}




protected function runTest()
{
$this->markTestIncomplete($this->message);
}




public function getMessage()
{
return $this->message;
}






public function toString()
{
return $this->getName();
}
}
<?php














class PHPUnit_Framework_Error extends PHPUnit_Framework_Exception
{









public function __construct($message, $code, $file, $line, Exception $previous = null)
{
parent::__construct($message, $code, $previous);

$this->file = $file;
$this->line = $line;
}
}
<?php












class PHPUnit_Framework_TestSuite_DataProvider extends PHPUnit_Framework_TestSuite
{





public function setDependencies(array $dependencies)
{
foreach ($this->tests as $test) {
$test->setDependencies($dependencies);
}
}
}
<?php














interface PHPUnit_Exception
{
}
<?php









use SebastianBergmann\Environment\Console;






class PHPUnit_TextUI_ResultPrinter extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener
{
const EVENT_TEST_START = 0;
const EVENT_TEST_END = 1;
const EVENT_TESTSUITE_START = 2;
const EVENT_TESTSUITE_END = 3;

const COLOR_NEVER = 'never';
const COLOR_AUTO = 'auto';
const COLOR_ALWAYS = 'always';
const COLOR_DEFAULT = self::COLOR_NEVER;




private static $ansiCodes = array(
'bold' => 1,
'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-black' => 40,
'bg-red' => 41,
'bg-green' => 42,
'bg-yellow' => 43,
'bg-blue' => 44,
'bg-magenta' => 45,
'bg-cyan' => 46,
'bg-white' => 47
);




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;














public function __construct($out = null, $verbose = false, $colors = self::COLOR_DEFAULT, $debug = false, $numberOfColumns = 80)
{
parent::__construct($out);

if (!is_bool($verbose)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'boolean');
}

$availableColors = array(self::COLOR_NEVER, self::COLOR_AUTO, self::COLOR_ALWAYS);

if (!in_array($colors, $availableColors)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(
3,
vsprintf('value from "%s", "%s" or "%s"', $availableColors)
);
}

if (!is_bool($debug)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(4, 'boolean');
}

if (!is_int($numberOfColumns) && $numberOfColumns != 'max') {
throw PHPUnit_Util_InvalidArgumentHelper::factory(5, 'integer or "max"');
}

$console = new Console;
$maxNumberOfColumns = $console->getNumberOfColumns();

if ($numberOfColumns == 'max' || $numberOfColumns > $maxNumberOfColumns) {
$numberOfColumns = $maxNumberOfColumns;
}

$this->numberOfColumns = $numberOfColumns;
$this->verbose = $verbose;
$this->debug = $debug;

if ($colors === self::COLOR_AUTO && $console->hasColorSupport()) {
$this->colors = true;
} else {
$this->colors = (self::COLOR_ALWAYS === $colors);
}
}




public function printResult(PHPUnit_Framework_TestResult $result)
{
$this->printHeader();

$this->printErrors($result);
$printSeparator = $result->errorCount() > 0;

if ($printSeparator && $result->failureCount() > 0) {
$this->write("\n--\n\n");
}

$printSeparator = $printSeparator || $result->failureCount() > 0;
$this->printFailures($result);

if ($this->verbose) {
if ($printSeparator && $result->riskyCount() > 0) {
$this->write("\n--\n\n");
}

$printSeparator = $printSeparator ||
$result->riskyCount() > 0;

$this->printRisky($result);

if ($printSeparator && $result->notImplementedCount() > 0) {
$this->write("\n--\n\n");
}

$printSeparator = $printSeparator ||
$result->notImplementedCount() > 0;

$this->printIncompletes($result);

if ($printSeparator && $result->skippedCount() > 0) {
$this->write("\n--\n\n");
}

$this->printSkipped($result);
}

$this->printFooter($result);
}





protected function printDefects(array $defects, $type)
{
$count = count($defects);

if ($count == 0) {
return;
}

$this->write(
sprintf(
"There %s %d %s%s:\n",
($count == 1) ? 'was' : 'were',
$count,
$type,
($count == 1) ? '' : 's'
)
);

$i = 1;

foreach ($defects as $defect) {
$this->printDefect($defect, $i++);
}
}





protected function printDefect(PHPUnit_Framework_TestFailure $defect, $count)
{
$this->printDefectHeader($defect, $count);
$this->printDefectTrace($defect);
}





protected function printDefectHeader(PHPUnit_Framework_TestFailure $defect, $count)
{
$this->write(
sprintf(
"\n%d) %s\n",
$count,
$defect->getTestName()
)
);
}




protected function printDefectTrace(PHPUnit_Framework_TestFailure $defect)
{
$e = $defect->thrownException();
$this->write((string) $e);

while ($e = $e->getPrevious()) {
$this->write("\nCaused by\n" . $e);
}
}




protected function printErrors(PHPUnit_Framework_TestResult $result)
{
$this->printDefects($result->errors(), 'error');
}




protected function printFailures(PHPUnit_Framework_TestResult $result)
{
$this->printDefects($result->failures(), 'failure');
}




protected function printIncompletes(PHPUnit_Framework_TestResult $result)
{
$this->printDefects($result->notImplemented(), 'incomplete test');
}






protected function printRisky(PHPUnit_Framework_TestResult $result)
{
$this->printDefects($result->risky(), 'risky test');
}






protected function printSkipped(PHPUnit_Framework_TestResult $result)
{
$this->printDefects($result->skipped(), 'skipped test');
}

protected function printHeader()
{
$this->write("\n\n" . PHP_Timer::resourceUsage() . "\n\n");
}




protected function printFooter(PHPUnit_Framework_TestResult $result)
{
if (count($result) === 0) {
$this->writeWithColor(
'fg-black, bg-yellow',
'No tests executed!'
);
} elseif ($result->wasSuccessful() &&
$result->allHarmless() &&
$result->allCompletelyImplemented() &&
$result->noneSkipped()) {
$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'
)
);
} else {
if ($result->wasSuccessful()) {
$color = 'fg-black, bg-yellow';

if ($this->verbose) {
$this->write("\n");
}

$this->writeWithColor(
$color,
'OK, but incomplete, skipped, or risky tests!'
);
} else {
$color = 'fg-white, bg-red';

$this->write("\n");
$this->writeWithColor($color, 'FAILURES!');
}

$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->skippedCount(), 'Skipped', $color);
$this->writeCountString($result->notImplementedCount(), 'Incomplete', $color);
$this->writeCountString($result->riskyCount(), 'Risky', $color);
$this->writeWithColor($color, '.', true);
}
}



public function printWaitPrompt()
{
$this->write("\n<RETURN> to continue\n");
}








public function addError(PHPUnit_Framework_Test $test, Exception $e, $time)
{
$this->writeProgressWithColor('fg-red, bold', 'E');
$this->lastTestFailed = true;
}








public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time)
{
$this->writeProgressWithColor('bg-red, fg-white', 'F');
$this->lastTestFailed = true;
}








public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
$this->writeProgressWithColor('fg-yellow, bold', 'I');
$this->lastTestFailed = true;
}










public function addRiskyTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
$this->writeProgressWithColor('fg-yellow, bold', 'R');
$this->lastTestFailed = true;
}










public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
$this->writeProgressWithColor('fg-cyan, bold', 'S');
$this->lastTestFailed = true;
}








public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
{
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(PHPUnit_Framework_TestSuite $suite)
{
}






public function startTest(PHPUnit_Framework_Test $test)
{
if ($this->debug) {
$this->write(
sprintf(
"\nStarting test '%s'.\n",
PHPUnit_Util_Test::describe($test)
)
);
}
}







public function endTest(PHPUnit_Framework_Test $test, $time)
{
if (!$this->lastTestFailed) {
$this->writeProgress('.');
}

if ($test instanceof PHPUnit_Framework_TestCase) {
$this->numAssertions += $test->getNumAssertions();
} elseif ($test instanceof PHPUnit_Extensions_PhptTestCase) {
$this->numAssertions++;
}

$this->lastTestFailed = false;

if ($test instanceof PHPUnit_Framework_TestCase) {
if (!$test->hasExpectationOnOutput()) {
$this->write($test->getActualOutput());
}
}
}




protected function writeProgress($progress)
{
$this->write($progress);
$this->column++;
$this->numTestsRun++;

if ($this->column == $this->maxColumn) {
$this->write(
sprintf(
' %' . $this->numTestsWidth . 'd / %' .
$this->numTestsWidth . 'd (%3s%%)',
$this->numTestsRun,
$this->numTests,
floor(($this->numTestsRun / $this->numTests) * 100)
)
);

$this->writeNewLine();
}
}

protected function writeNewLine()
{
$this->column = 0;
$this->write("\n");
}












protected function formatWithColor($color, $buffer)
{
if (!$this->colors) {
return $buffer;
}

$codes = array_map('trim', explode(',', $color));
$lines = explode("\n", $buffer);
$padding = max(array_map('strlen', $lines));
$styles = array();

foreach ($codes as $code) {
$styles[] = self::$ansiCodes[$code];
}

$style = sprintf("\x1b[%sm", implode(';', $styles));

$styledLines = array();

foreach ($lines as $line) {
$styledLines[] = $style . str_pad($line, $padding) . "\x1b[0m";
}

return implode("\n", $styledLines);
}










protected function writeWithColor($color, $buffer, $lf = true)
{
$this->write($this->formatWithColor($color, $buffer));

if ($lf) {
$this->write("\n");
}
}









protected function writeProgressWithColor($color, $buffer)
{
$buffer = $this->formatWithColor($color, $buffer);
$this->writeProgress($buffer);
}









private function writeCountString($count, $name, $color, $always = false)
{
static $first = true;

if ($always || $count > 0) {
$this->writeWithColor(
$color,
sprintf(
'%s%s: %d',
!$first ? ', ' : '',
$name,
$count
),
false
);

$first = false;
}
}
}
<?php









use SebastianBergmann\Environment\Runtime;







class PHPUnit_TextUI_TestRunner extends PHPUnit_Runner_BaseTestRunner
{
const SUCCESS_EXIT = 0;
const FAILURE_EXIT = 1;
const EXCEPTION_EXIT = 2;




protected $codeCoverageFilter;




protected $loader = null;




protected $printer = null;




protected static $versionStringPrinted = false;




private $missingExtensions = array();




private $runtime;







public function __construct(PHPUnit_Runner_TestSuiteLoader $loader = null, PHP_CodeCoverage_Filter $filter = null)
{
if ($filter === null) {
$filter = $this->getCodeCoverageFilter();
}

$this->codeCoverageFilter = $filter;
$this->loader = $loader;
$this->runtime = new Runtime;
}









public static function run($test, array $arguments = array())
{
if ($test instanceof ReflectionClass) {
$test = new PHPUnit_Framework_TestSuite($test);
}

if ($test instanceof PHPUnit_Framework_Test) {
$aTestRunner = new self;

return $aTestRunner->doRun(
$test,
$arguments
);
} else {
throw new PHPUnit_Framework_Exception(
'No test case or test suite found.'
);
}
}




protected function createTestResult()
{
return new PHPUnit_Framework_TestResult;
}

private function processSuiteFilters(PHPUnit_Framework_TestSuite $suite, array $arguments)
{
if (!$arguments['filter'] &&
empty($arguments['groups']) &&
empty($arguments['excludeGroups'])) {
return;
}

$filterFactory = new PHPUnit_Runner_Filter_Factory();

if (!empty($arguments['excludeGroups'])) {
$filterFactory->addFilter(
new ReflectionClass('PHPUnit_Runner_Filter_Group_Exclude'),
$arguments['excludeGroups']
);
}

if (!empty($arguments['groups'])) {
$filterFactory->addFilter(
new ReflectionClass('PHPUnit_Runner_Filter_Group_Include'),
$arguments['groups']
);
}

if ($arguments['filter']) {
$filterFactory->addFilter(
new ReflectionClass('PHPUnit_Runner_Filter_Test'),
$arguments['filter']
);
}
$suite->injectFilter($filterFactory);
}







public function doRun(PHPUnit_Framework_Test $suite, array $arguments = array())
{
if (isset($arguments['configuration'])) {
$GLOBALS['__PHPUNIT_CONFIGURATION_FILE'] = $arguments['configuration'];
}

$this->handleConfiguration($arguments);

$this->processSuiteFilters($suite, $arguments);

if (isset($arguments['bootstrap'])) {
$GLOBALS['__PHPUNIT_BOOTSTRAP'] = $arguments['bootstrap'];
}

if ($arguments['backupGlobals'] === false) {
$suite->setBackupGlobals(false);
}

if ($arguments['backupStaticAttributes'] === true) {
$suite->setBackupStaticAttributes(true);
}

if ($arguments['disallowChangesToGlobalState'] === true) {
$suite->setDisallowChangesToGlobalState(true);
}

if (is_integer($arguments['repeat'])) {
$test = new PHPUnit_Extensions_RepeatedTest(
$suite,
$arguments['repeat'],
$arguments['processIsolation']
);

$suite = new PHPUnit_Framework_TestSuite();
$suite->addTest($test);
}

$result = $this->createTestResult();

if (!$arguments['convertErrorsToExceptions']) {
$result->convertErrorsToExceptions(false);
}

if (!$arguments['convertNoticesToExceptions']) {
PHPUnit_Framework_Error_Notice::$enabled = false;
}

if (!$arguments['convertWarningsToExceptions']) {
PHPUnit_Framework_Error_Warning::$enabled = false;
}

if ($arguments['stopOnError']) {
$result->stopOnError(true);
}

if ($arguments['stopOnFailure']) {
$result->stopOnFailure(true);
}

if ($arguments['stopOnIncomplete']) {
$result->stopOnIncomplete(true);
}

if ($arguments['stopOnRisky']) {
$result->stopOnRisky(true);
}

if ($arguments['stopOnSkipped']) {
$result->stopOnSkipped(true);
}

if ($this->printer === null) {
if (isset($arguments['printer']) &&
$arguments['printer'] instanceof PHPUnit_Util_Printer) {
$this->printer = $arguments['printer'];
} else {
$printerClass = 'PHPUnit_TextUI_ResultPrinter';

if (isset($arguments['printer']) &&
is_string($arguments['printer']) &&
class_exists($arguments['printer'], false)) {
$class = new ReflectionClass($arguments['printer']);

if ($class->isSubclassOf('PHPUnit_TextUI_ResultPrinter')) {
$printerClass = $arguments['printer'];
}
}

$this->printer = new $printerClass(
isset($arguments['stderr']) ? 'php://stderr' : null,
$arguments['verbose'],
$arguments['colors'],
$arguments['debug'],
$arguments['columns']
);
}
}

if (!$this->printer instanceof PHPUnit_Util_Log_TAP) {
$this->printer->write(
PHPUnit_Runner_Version::getVersionString() . "\n"
);

self::$versionStringPrinted = true;

if ($arguments['verbose']) {
$this->printer->write(
sprintf(
"\nRuntime:\t%s",
$this->runtime->getNameWithVersion()
)
);

if ($this->runtime->hasXdebug()) {
$this->printer->write(
sprintf(
' with Xdebug %s',
phpversion('xdebug')
)
);
}

if (isset($arguments['configuration'])) {
$this->printer->write(
sprintf(
"\nConfiguration:\t%s",
$arguments['configuration']->getFilename()
)
);
}

$this->printer->write("\n");
}

if (isset($arguments['deprecatedStrictModeOption'])) {
print "Warning:\tDeprecated option \"--strict\" used\n";
} elseif (isset($arguments['deprecatedStrictModeSetting'])) {
print "Warning:\tDeprecated configuration setting \"strict\" used\n";
}

if (isset($arguments['deprecatedSeleniumConfiguration'])) {
print "Warning:\tDeprecated configuration setting \"selenium\" used\n";
}
}

foreach ($arguments['listeners'] as $listener) {
$result->addListener($listener);
}

$result->addListener($this->printer);

if (isset($arguments['testdoxHTMLFile'])) {
$result->addListener(
new PHPUnit_Util_TestDox_ResultPrinter_HTML(
$arguments['testdoxHTMLFile']
)
);
}

if (isset($arguments['testdoxTextFile'])) {
$result->addListener(
new PHPUnit_Util_TestDox_ResultPrinter_Text(
$arguments['testdoxTextFile']
)
);
}

$codeCoverageReports = 0;

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 && (!extension_loaded('tokenizer') || !$this->runtime->canCollectCodeCoverage())) {
if (!extension_loaded('tokenizer')) {
$this->showExtensionNotLoadedWarning(
'tokenizer',
'No code coverage will be generated.'
);
} elseif (!extension_loaded('Xdebug')) {
$this->showExtensionNotLoadedWarning(
'Xdebug',
'No code coverage will be generated.'
);
}

$codeCoverageReports = 0;
}

if (!$this->printer instanceof PHPUnit_Util_Log_TAP) {
if ($codeCoverageReports > 0 && !$this->codeCoverageFilter->hasWhitelist()) {
$this->printer->write("Warning:\tNo whitelist configured for code coverage\n");
}

$this->printer->write("\n");
}

if ($codeCoverageReports > 0) {
$codeCoverage = new PHP_CodeCoverage(
null,
$this->codeCoverageFilter
);

$codeCoverage->setAddUncoveredFilesFromWhitelist(
$arguments['addUncoveredFilesFromWhitelist']
);

$codeCoverage->setCheckForUnintentionallyCoveredCode(
$arguments['strictCoverage']
);

$codeCoverage->setProcessUncoveredFilesFromWhitelist(
$arguments['processUncoveredFilesFromWhitelist']
);

if (isset($arguments['forceCoversAnnotation'])) {
$codeCoverage->setForceCoversAnnotation(
$arguments['forceCoversAnnotation']
);
}

if (isset($arguments['mapTestClassNameToCoveredClassName'])) {
$codeCoverage->setMapTestClassNameToCoveredClassName(
$arguments['mapTestClassNameToCoveredClassName']
);
}

$result->setCodeCoverage($codeCoverage);
}

if ($codeCoverageReports > 1) {
if (isset($arguments['cacheTokens'])) {
$codeCoverage->setCacheTokens($arguments['cacheTokens']);
}
}

if (isset($arguments['jsonLogfile'])) {
$result->addListener(
new PHPUnit_Util_Log_JSON($arguments['jsonLogfile'])
);
}

if (isset($arguments['tapLogfile'])) {
$result->addListener(
new PHPUnit_Util_Log_TAP($arguments['tapLogfile'])
);
}

if (isset($arguments['junitLogfile'])) {
$result->addListener(
new PHPUnit_Util_Log_JUnit(
$arguments['junitLogfile'],
$arguments['logIncompleteSkipped']
)
);
}

$result->beStrictAboutTestsThatDoNotTestAnything($arguments['reportUselessTests']);
$result->beStrictAboutOutputDuringTests($arguments['disallowTestOutput']);
$result->beStrictAboutTodoAnnotatedTests($arguments['disallowTodoAnnotatedTests']);
$result->beStrictAboutTestSize($arguments['enforceTimeLimit']);
$result->setTimeoutForSmallTests($arguments['timeoutForSmallTests']);
$result->setTimeoutForMediumTests($arguments['timeoutForMediumTests']);
$result->setTimeoutForLargeTests($arguments['timeoutForLargeTests']);

if ($suite instanceof PHPUnit_Framework_TestSuite) {
$suite->setRunTestInSeparateProcess($arguments['processIsolation']);
}

$suite->run($result);

unset($suite);
$result->flushListeners();

if ($this->printer instanceof PHPUnit_TextUI_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 PHP_CodeCoverage_Report_Clover;
$writer->process($codeCoverage, $arguments['coverageClover']);

$this->printer->write(" done\n");
unset($writer);
} catch (PHP_CodeCoverage_Exception $e) {
$this->printer->write(
" failed\n" . $e->getMessage() . "\n"
);
}
}

if (isset($arguments['coverageCrap4J'])) {
$this->printer->write(
"\nGenerating Crap4J report XML file ..."
);

try {
$writer = new PHP_CodeCoverage_Report_Crap4j($arguments['crap4jThreshold']);
$writer->process($codeCoverage, $arguments['coverageCrap4J']);

$this->printer->write(" done\n");
unset($writer);
} catch (PHP_CodeCoverage_Exception $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 PHP_CodeCoverage_Report_HTML(
$arguments['reportLowUpperBound'],
$arguments['reportHighLowerBound'],
sprintf(
' and <a href="https://phpunit.de/">PHPUnit %s</a>',
PHPUnit_Runner_Version::id()
)
);

$writer->process($codeCoverage, $arguments['coverageHtml']);

$this->printer->write(" done\n");
unset($writer);
} catch (PHP_CodeCoverage_Exception $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 PHP_CodeCoverage_Report_PHP;
$writer->process($codeCoverage, $arguments['coveragePHP']);

$this->printer->write(" done\n");
unset($writer);
} catch (PHP_CodeCoverage_Exception $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'] != PHPUnit_TextUI_ResultPrinter::COLOR_NEVER;
} else {
$outputStream = new PHPUnit_Util_Printer($arguments['coverageText']);
$colors = false;
}

$processor = new PHP_CodeCoverage_Report_Text(
$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 PHP_CodeCoverage_Report_XML;
$writer->process($codeCoverage, $arguments['coverageXml']);

$this->printer->write(" done\n");
unset($writer);
} catch (PHP_CodeCoverage_Exception $e) {
$this->printer->write(
" failed\n" . $e->getMessage() . "\n"
);
}
}
}

return $result;
}




public function setPrinter(PHPUnit_TextUI_ResultPrinter $resultPrinter)
{
$this->printer = $resultPrinter;
}







protected function runFailed($message)
{
$this->write($message . PHP_EOL);
exit(self::FAILURE_EXIT);
}






protected function write($buffer)
{
if (PHP_SAPI != 'cli') {
$buffer = htmlspecialchars($buffer);
}

if ($this->printer !== null) {
$this->printer->write($buffer);
} else {
print $buffer;
}
}








public function getLoader()
{
if ($this->loader === null) {
$this->loader = new PHPUnit_Runner_StandardTestSuiteLoader;
}

return $this->loader;
}






protected function handleConfiguration(array &$arguments)
{
if (isset($arguments['configuration']) &&
!$arguments['configuration'] instanceof PHPUnit_Util_Configuration) {
$arguments['configuration'] = PHPUnit_Util_Configuration::getInstance(
$arguments['configuration']
);
}

$arguments['debug'] = isset($arguments['debug']) ? $arguments['debug'] : false;
$arguments['filter'] = isset($arguments['filter']) ? $arguments['filter'] : false;
$arguments['listeners'] = isset($arguments['listeners']) ? $arguments['listeners'] : array();

if (isset($arguments['configuration'])) {
$arguments['configuration']->handlePHPConfiguration();

$phpunitConfiguration = $arguments['configuration']->getPHPUnitConfiguration();

if (isset($phpunitConfiguration['deprecatedStrictModeSetting'])) {
$arguments['deprecatedStrictModeSetting'] = true;
}

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['disallowChangesToGlobalState']) &&
!isset($arguments['disallowChangesToGlobalState'])) {
$arguments['disallowChangesToGlobalState'] = $phpunitConfiguration['disallowChangesToGlobalState'];
}

if (isset($phpunitConfiguration['bootstrap']) &&
!isset($arguments['bootstrap'])) {
$arguments['bootstrap'] = $phpunitConfiguration['bootstrap'];
}

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['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['stopOnError']) &&
!isset($arguments['stopOnError'])) {
$arguments['stopOnError'] = $phpunitConfiguration['stopOnError'];
}

if (isset($phpunitConfiguration['stopOnFailure']) &&
!isset($arguments['stopOnFailure'])) {
$arguments['stopOnFailure'] = $phpunitConfiguration['stopOnFailure'];
}

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['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['disallowTestOutput']) &&
!isset($arguments['disallowTestOutput'])) {
$arguments['disallowTestOutput'] = $phpunitConfiguration['disallowTestOutput'];
}

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['verbose']) &&
!isset($arguments['verbose'])) {
$arguments['verbose'] = $phpunitConfiguration['verbose'];
}

if (isset($phpunitConfiguration['forceCoversAnnotation']) &&
!isset($arguments['forceCoversAnnotation'])) {
$arguments['forceCoversAnnotation'] = $phpunitConfiguration['forceCoversAnnotation'];
}

if (isset($phpunitConfiguration['mapTestClassNameToCoveredClassName']) &&
!isset($arguments['mapTestClassNameToCoveredClassName'])) {
$arguments['mapTestClassNameToCoveredClassName'] = $phpunitConfiguration['mapTestClassNameToCoveredClassName'];
}

$groupCliArgs = array();

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']->getListenerConfiguration() as $listener) {
if (!class_exists($listener['class'], false) &&
$listener['file'] !== '') {
require_once $listener['file'];
}

if (class_exists($listener['class'])) {
if (count($listener['arguments']) == 0) {
$listener = new $listener['class'];
} else {
$listenerClass = new ReflectionClass(
$listener['class']
);
$listener = $listenerClass->newInstanceArgs(
$listener['arguments']
);
}

if ($listener instanceof PHPUnit_Framework_TestListener) {
$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['json']) &&
!isset($arguments['jsonLogfile'])) {
$arguments['jsonLogfile'] = $loggingConfiguration['json'];
}

if (isset($loggingConfiguration['plain'])) {
$arguments['listeners'][] = new PHPUnit_TextUI_ResultPrinter(
$loggingConfiguration['plain'],
true
);
}

if (isset($loggingConfiguration['tap']) &&
!isset($arguments['tapLogfile'])) {
$arguments['tapLogfile'] = $loggingConfiguration['tap'];
}

if (isset($loggingConfiguration['junit']) &&
!isset($arguments['junitLogfile'])) {
$arguments['junitLogfile'] = $loggingConfiguration['junit'];

if (isset($loggingConfiguration['logIncompleteSkipped']) &&
!isset($arguments['logIncompleteSkipped'])) {
$arguments['logIncompleteSkipped'] = $loggingConfiguration['logIncompleteSkipped'];
}
}

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($arguments['coverageClover']) ||
isset($arguments['coverageCrap4J']) ||
isset($arguments['coverageHtml']) ||
isset($arguments['coveragePHP']) ||
isset($arguments['coverageText']) ||
isset($arguments['coverageXml'])) &&
$this->runtime->canCollectCodeCoverage()) {
$filterConfiguration = $arguments['configuration']->getFilterConfiguration();
$arguments['addUncoveredFilesFromWhitelist'] = $filterConfiguration['whitelist']['addUncoveredFilesFromWhitelist'];
$arguments['processUncoveredFilesFromWhitelist'] = $filterConfiguration['whitelist']['processUncoveredFilesFromWhitelist'];

if (empty($filterConfiguration['whitelist']['include']['directory']) &&
empty($filterConfiguration['whitelist']['include']['file'])) {
foreach ($filterConfiguration['blacklist']['include']['directory'] as $dir) {
$this->codeCoverageFilter->addDirectoryToBlacklist(
$dir['path'],
$dir['suffix'],
$dir['prefix'],
$dir['group']
);
}

foreach ($filterConfiguration['blacklist']['include']['file'] as $file) {
$this->codeCoverageFilter->addFileToBlacklist($file);
}

foreach ($filterConfiguration['blacklist']['exclude']['directory'] as $dir) {
$this->codeCoverageFilter->removeDirectoryFromBlacklist(
$dir['path'],
$dir['suffix'],
$dir['prefix'],
$dir['group']
);
}

foreach ($filterConfiguration['blacklist']['exclude']['file'] as $file) {
$this->codeCoverageFilter->removeFileFromBlacklist($file);
}
}

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);
}
}
}

$arguments['addUncoveredFilesFromWhitelist'] = isset($arguments['addUncoveredFilesFromWhitelist']) ? $arguments['addUncoveredFilesFromWhitelist'] : true;
$arguments['processUncoveredFilesFromWhitelist'] = isset($arguments['processUncoveredFilesFromWhitelist']) ? $arguments['processUncoveredFilesFromWhitelist'] : false;
$arguments['backupGlobals'] = isset($arguments['backupGlobals']) ? $arguments['backupGlobals'] : null;
$arguments['backupStaticAttributes'] = isset($arguments['backupStaticAttributes']) ? $arguments['backupStaticAttributes'] : null;
$arguments['disallowChangesToGlobalState'] = isset($arguments['disallowChangesToGlobalState']) ? $arguments['disallowChangesToGlobalState'] : null;
$arguments['cacheTokens'] = isset($arguments['cacheTokens']) ? $arguments['cacheTokens'] : false;
$arguments['columns'] = isset($arguments['columns']) ? $arguments['columns'] : 80;
$arguments['colors'] = isset($arguments['colors']) ? $arguments['colors'] : PHPUnit_TextUI_ResultPrinter::COLOR_DEFAULT;
$arguments['convertErrorsToExceptions'] = isset($arguments['convertErrorsToExceptions']) ? $arguments['convertErrorsToExceptions'] : true;
$arguments['convertNoticesToExceptions'] = isset($arguments['convertNoticesToExceptions']) ? $arguments['convertNoticesToExceptions'] : true;
$arguments['convertWarningsToExceptions'] = isset($arguments['convertWarningsToExceptions']) ? $arguments['convertWarningsToExceptions'] : true;
$arguments['excludeGroups'] = isset($arguments['excludeGroups']) ? $arguments['excludeGroups'] : array();
$arguments['groups'] = isset($arguments['groups']) ? $arguments['groups'] : array();
$arguments['logIncompleteSkipped'] = isset($arguments['logIncompleteSkipped']) ? $arguments['logIncompleteSkipped'] : false;
$arguments['processIsolation'] = isset($arguments['processIsolation']) ? $arguments['processIsolation'] : false;
$arguments['repeat'] = isset($arguments['repeat']) ? $arguments['repeat'] : false;
$arguments['reportHighLowerBound'] = isset($arguments['reportHighLowerBound']) ? $arguments['reportHighLowerBound'] : 90;
$arguments['reportLowUpperBound'] = isset($arguments['reportLowUpperBound']) ? $arguments['reportLowUpperBound'] : 50;
$arguments['crap4jThreshold'] = isset($arguments['crap4jThreshold']) ? $arguments['crap4jThreshold'] : 30;
$arguments['stopOnError'] = isset($arguments['stopOnError']) ? $arguments['stopOnError'] : false;
$arguments['stopOnFailure'] = isset($arguments['stopOnFailure']) ? $arguments['stopOnFailure'] : false;
$arguments['stopOnIncomplete'] = isset($arguments['stopOnIncomplete']) ? $arguments['stopOnIncomplete'] : false;
$arguments['stopOnRisky'] = isset($arguments['stopOnRisky']) ? $arguments['stopOnRisky'] : false;
$arguments['stopOnSkipped'] = isset($arguments['stopOnSkipped']) ? $arguments['stopOnSkipped'] : false;
$arguments['timeoutForSmallTests'] = isset($arguments['timeoutForSmallTests']) ? $arguments['timeoutForSmallTests'] : 1;
$arguments['timeoutForMediumTests'] = isset($arguments['timeoutForMediumTests']) ? $arguments['timeoutForMediumTests'] : 10;
$arguments['timeoutForLargeTests'] = isset($arguments['timeoutForLargeTests']) ? $arguments['timeoutForLargeTests'] : 60;
$arguments['reportUselessTests'] = isset($arguments['reportUselessTests']) ? $arguments['reportUselessTests'] : false;
$arguments['strictCoverage'] = isset($arguments['strictCoverage']) ? $arguments['strictCoverage'] : false;
$arguments['disallowTestOutput'] = isset($arguments['disallowTestOutput']) ? $arguments['disallowTestOutput'] : false;
$arguments['enforceTimeLimit'] = isset($arguments['enforceTimeLimit']) ? $arguments['enforceTimeLimit'] : false;
$arguments['disallowTodoAnnotatedTests'] = isset($arguments['disallowTodoAnnotatedTests']) ? $arguments['disallowTodoAnnotatedTests'] : false;
$arguments['verbose'] = isset($arguments['verbose']) ? $arguments['verbose'] : false;
}







private function showExtensionNotLoadedWarning($extension, $message = '')
{
if (isset($this->missingExtensions[$extension])) {
return;
}

$this->write("Warning:\t" . 'The ' . $extension . ' extension is not loaded' . "\n");

if (!empty($message)) {
$this->write("\t\t" . $message . "\n");
}

$this->missingExtensions[$extension] = true;
}




private function getCodeCoverageFilter()
{
$filter = new PHP_CodeCoverage_Filter;

if (defined('__PHPUNIT_PHAR__')) {
$filter->addFileToBlacklist(__PHPUNIT_PHAR__);
}

$blacklist = new PHPUnit_Util_Blacklist;

foreach ($blacklist->getBlacklistedDirectories() as $directory) {
$filter->addDirectoryToBlacklist($directory);
}

return $filter;
}
}
<?php















class PHPUnit_TextUI_Command
{



protected $arguments = array(
'listGroups' => false,
'loader' => null,
'useDefaultConfiguration' => true
);




protected $options = array();




protected $longOptions = array(
'colors==' => null,
'bootstrap=' => 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,
'exclude-group=' => null,
'filter=' => null,
'testsuite=' => null,
'group=' => null,
'help' => null,
'include-path=' => null,
'list-groups' => null,
'loader=' => null,
'log-json=' => null,
'log-junit=' => null,
'log-tap=' => null,
'process-isolation' => null,
'repeat=' => null,
'stderr' => null,
'stop-on-error' => null,
'stop-on-failure' => null,
'stop-on-incomplete' => null,
'stop-on-risky' => null,
'stop-on-skipped' => null,
'report-useless-tests' => null,
'strict-coverage' => null,
'disallow-test-output' => null,
'enforce-time-limit' => null,
'disallow-todo-tests' => null,
'strict-global-state' => null,
'strict' => null,
'tap' => null,
'testdox' => null,
'testdox-html=' => null,
'testdox-text=' => null,
'test-suffix=' => null,
'no-configuration' => null,
'no-coverage' => null,
'no-globals-backup' => null,
'printer=' => null,
'static-backup' => null,
'verbose' => null,
'version' => null
);




private $versionStringPrinted = false;




public static function main($exit = true)
{
$command = new static;

return $command->run($_SERVER['argv'], $exit);
}







public function run(array $argv, $exit = true)
{
$this->handleArguments($argv);

$runner = $this->createRunner();

if (is_object($this->arguments['test']) &&
$this->arguments['test'] instanceof PHPUnit_Framework_Test) {
$suite = $this->arguments['test'];
} else {
$suite = $runner->getTest(
$this->arguments['test'],
$this->arguments['testFile'],
$this->arguments['testSuffixes']
);
}

if ($this->arguments['listGroups']) {
$this->printVersionString();

print "Available test group(s):\n";

$groups = $suite->getGroups();
sort($groups);

foreach ($groups as $group) {
print " - $group\n";
}

if ($exit) {
exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT);
} else {
return PHPUnit_TextUI_TestRunner::SUCCESS_EXIT;
}
}

unset($this->arguments['test']);
unset($this->arguments['testFile']);

try {
$result = $runner->doRun($suite, $this->arguments);
} catch (PHPUnit_Framework_Exception $e) {
print $e->getMessage() . "\n";
}

$ret = PHPUnit_TextUI_TestRunner::FAILURE_EXIT;

if (isset($result) && $result->wasSuccessful()) {
$ret = PHPUnit_TextUI_TestRunner::SUCCESS_EXIT;
} elseif (!isset($result) || $result->errorCount() > 0) {
$ret = PHPUnit_TextUI_TestRunner::EXCEPTION_EXIT;
}

if ($exit) {
exit($ret);
} else {
return $ret;
}
}








protected function createRunner()
{
return new PHPUnit_TextUI_TestRunner($this->arguments['loader']);
}














































protected function handleArguments(array $argv)
{
if (defined('__PHPUNIT_PHAR__')) {
$this->longOptions['check-version'] = null;
$this->longOptions['selfupdate'] = null;
$this->longOptions['self-update'] = null;
$this->longOptions['selfupgrade'] = null;
$this->longOptions['self-upgrade'] = null;
}

try {
$this->options = PHPUnit_Util_Getopt::getopt(
$argv,
'd:c:hv',
array_keys($this->longOptions)
);
} catch (PHPUnit_Framework_Exception $e) {
$this->showError($e->getMessage());
}

foreach ($this->options[0] as $option) {
switch ($option[0]) {
case '--colors':
$this->arguments['colors'] = $option[1] ?: PHPUnit_TextUI_ResultPrinter::COLOR_AUTO;
break;

case '--bootstrap':
$this->arguments['bootstrap'] = $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], true);
}
}
break;

case '--debug':
$this->arguments['debug'] = true;
break;

case 'h':
case '--help':
$this->showHelp();
exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT);
break;

case '--filter':
$this->arguments['filter'] = $option[1];
break;

case '--testsuite':
$this->arguments['testsuite'] = $option[1];
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 '--printer':
$this->arguments['printer'] = $option[1];
break;

case '--loader':
$this->arguments['loader'] = $option[1];
break;

case '--log-json':
$this->arguments['jsonLogfile'] = $option[1];
break;

case '--log-junit':
$this->arguments['junitLogfile'] = $option[1];
break;

case '--log-tap':
$this->arguments['tapLogfile'] = $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-error':
$this->arguments['stopOnError'] = true;
break;

case '--stop-on-failure':
$this->arguments['stopOnFailure'] = 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 '--tap':
$this->arguments['printer'] = 'PHPUnit_Util_Log_TAP';
break;

case '--testdox':
$this->arguments['printer'] = 'PHPUnit_Util_TestDox_ResultPrinter_Text';
break;

case '--testdox-html':
$this->arguments['testdoxHTMLFile'] = $option[1];
break;

case '--testdox-text':
$this->arguments['testdoxTextFile'] = $option[1];
break;

case '--no-configuration':
$this->arguments['useDefaultConfiguration'] = false;
break;

case '--no-coverage':
$this->arguments['noCoverage'] = true;
break;

case '--no-globals-backup':
$this->arguments['backupGlobals'] = false;
break;

case '--static-backup':
$this->arguments['backupStaticAttributes'] = true;
break;

case 'v':
case '--verbose':
$this->arguments['verbose'] = true;
break;

case '--version':
$this->printVersionString();
exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT);
break;

case '--report-useless-tests':
$this->arguments['reportUselessTests'] = true;
break;

case '--strict-coverage':
$this->arguments['strictCoverage'] = true;
break;

case '--strict-global-state':
$this->arguments['disallowChangesToGlobalState'] = true;
break;

case '--disallow-test-output':
$this->arguments['disallowTestOutput'] = true;
break;

case '--enforce-time-limit':
$this->arguments['enforceTimeLimit'] = true;
break;

case '--disallow-todo-tests':
$this->arguments['disallowTodoAnnotatedTests'] = true;
break;

case '--strict':
$this->arguments['reportUselessTests'] = true;
$this->arguments['strictCoverage'] = true;
$this->arguments['disallowTestOutput'] = true;
$this->arguments['enforceTimeLimit'] = true;
$this->arguments['disallowTodoAnnotatedTests'] = true;
$this->arguments['deprecatedStrictModeOption'] = true;
break;

case '--check-version':
$this->handleVersionCheck();
break;

case '--selfupdate':
case '--self-update':
$this->handleSelfUpdate();
break;

case '--selfupgrade':
case '--self-upgrade':
$this->handleSelfUpdate(true);
break;

case '--whitelist':
$this->arguments['whitelist'] = $option[1];
break;

default:
$optionName = str_replace('--', '', $option[0]);

if (isset($this->longOptions[$optionName])) {
$handler = $this->longOptions[$optionName];
} elseif (isset($this->longOptions[$optionName . '='])) {
$handler = $this->longOptions[$optionName . '='];
}

if (isset($handler) && is_callable(array($this, $handler))) {
$this->$handler($option[1]);
}
}
}

$this->handleCustomTestSuite();

if (!isset($this->arguments['test'])) {
if (isset($this->options[1][0])) {
$this->arguments['test'] = $this->options[1][0];
}

if (isset($this->options[1][1])) {
$this->arguments['testFile'] = realpath($this->options[1][1]);
} else {
$this->arguments['testFile'] = '';
}

if (isset($this->arguments['test']) &&
is_file($this->arguments['test']) &&
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['testSuffixes'])) {
$this->arguments['testSuffixes'] = array('Test.php', '.phpt');
}

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 = PHPUnit_Util_Configuration::getInstance(
$this->arguments['configuration']
);
} catch (Throwable $e) {
print $e->getMessage() . "\n";
exit(PHPUnit_TextUI_TestRunner::FAILURE_EXIT);
} catch (Exception $e) {
print $e->getMessage() . "\n";
exit(PHPUnit_TextUI_TestRunner::FAILURE_EXIT);
}

$phpunit = $configuration->getPHPUnitConfiguration();

$configuration->handlePHPConfiguration();




if (isset($this->arguments['bootstrap'])) {
$this->handleBootstrap($this->arguments['bootstrap']);
} elseif (isset($phpunit['bootstrap'])) {
$this->handleBootstrap($phpunit['bootstrap']);
}




if (isset($phpunit['stderr']) && ! isset($this->arguments['stderr'])) {
$this->arguments['stderr'] = $phpunit['stderr'];
}

if (isset($phpunit['columns']) && ! isset($this->arguments['columns'])) {
$this->arguments['columns'] = $phpunit['columns'];
}

if (isset($phpunit['printerClass'])) {
if (isset($phpunit['printerFile'])) {
$file = $phpunit['printerFile'];
} else {
$file = '';
}

$this->arguments['printer'] = $this->handlePrinter(
$phpunit['printerClass'],
$file
);
}

if (isset($phpunit['testSuiteLoaderClass'])) {
if (isset($phpunit['testSuiteLoaderFile'])) {
$file = $phpunit['testSuiteLoaderFile'];
} else {
$file = '';
}

$this->arguments['loader'] = $this->handleLoader(
$phpunit['testSuiteLoaderClass'],
$file
);
}

$browsers = $configuration->getSeleniumBrowserConfiguration();

if (!empty($browsers)) {
$this->arguments['deprecatedSeleniumConfiguration'] = true;

if (class_exists('PHPUnit_Extensions_SeleniumTestCase')) {
PHPUnit_Extensions_SeleniumTestCase::$browsers = $browsers;
}
}

if (!isset($this->arguments['test'])) {
$testSuite = $configuration->getTestSuiteConfiguration(isset($this->arguments['testsuite']) ? $this->arguments['testsuite'] : null);

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']) && is_string($this->arguments['test']) && substr($this->arguments['test'], -5, 5) == '.phpt') {
$test = new PHPUnit_Extensions_PhptTestCase($this->arguments['test']);

$this->arguments['test'] = new PHPUnit_Framework_TestSuite;
$this->arguments['test']->addTest($test);
}

if (!isset($this->arguments['test']) ||
(isset($this->arguments['testDatabaseLogRevision']) && !isset($this->arguments['testDatabaseDSN']))) {
$this->showHelp();
exit(PHPUnit_TextUI_TestRunner::EXCEPTION_EXIT);
}
}









protected function handleLoader($loaderClass, $loaderFile = '')
{
if (!class_exists($loaderClass, false)) {
if ($loaderFile == '') {
$loaderFile = PHPUnit_Util_Filesystem::classNameToFilename(
$loaderClass
);
}

$loaderFile = stream_resolve_include_path($loaderFile);

if ($loaderFile) {
require $loaderFile;
}
}

if (class_exists($loaderClass, false)) {
$class = new ReflectionClass($loaderClass);

if ($class->implementsInterface('PHPUnit_Runner_TestSuiteLoader') &&
$class->isInstantiable()) {
return $class->newInstance();
}
}

if ($loaderClass == 'PHPUnit_Runner_StandardTestSuiteLoader') {
return;
}

$this->showError(
sprintf(
'Could not use "%s" as loader.',
$loaderClass
)
);
}









protected function handlePrinter($printerClass, $printerFile = '')
{
if (!class_exists($printerClass, false)) {
if ($printerFile == '') {
$printerFile = PHPUnit_Util_Filesystem::classNameToFilename(
$printerClass
);
}

$printerFile = stream_resolve_include_path($printerFile);

if ($printerFile) {
require $printerFile;
}
}

if (class_exists($printerClass)) {
$class = new ReflectionClass($printerClass);

if ($class->implementsInterface('PHPUnit_Framework_TestListener') &&
$class->isSubclassOf('PHPUnit_Util_Printer') &&
$class->isInstantiable()) {
if ($class->isSubclassOf('PHPUnit_TextUI_ResultPrinter')) {
return $printerClass;
}

$outputStream = isset($this->arguments['stderr']) ? 'php://stderr' : null;

return $class->newInstance($outputStream);
}
}

$this->showError(
sprintf(
'Could not use "%s" as printer.',
$printerClass
)
);
}






protected function handleBootstrap($filename)
{
try {
PHPUnit_Util_Fileloader::checkAndLoad($filename);
} catch (PHPUnit_Framework_Exception $e) {
$this->showError($e->getMessage());
}
}




protected function handleSelfUpdate($upgrade = false)
{
$this->printVersionString();

$localFilename = realpath($_SERVER['argv'][0]);

if (!is_writable($localFilename)) {
print 'No write permission to update ' . $localFilename . "\n";
exit(PHPUnit_TextUI_TestRunner::EXCEPTION_EXIT);
}

if (!extension_loaded('openssl')) {
print "The OpenSSL extension is not loaded.\n";
exit(PHPUnit_TextUI_TestRunner::EXCEPTION_EXIT);
}

if (!$upgrade) {
$remoteFilename = sprintf(
'https://phar.phpunit.de/phpunit-%s.phar',
file_get_contents(
sprintf(
'https://phar.phpunit.de/latest-version-of/phpunit-%s',
PHPUnit_Runner_Version::series()
)
)
);
} else {
$remoteFilename = sprintf(
'https://phar.phpunit.de/phpunit%s.phar',
PHPUnit_Runner_Version::getReleaseChannel()
);
}

$tempFilename = tempnam(sys_get_temp_dir(), 'phpunit') . '.phar';


 $caFile = dirname($tempFilename) . '/ca.pem';
copy(__PHPUNIT_PHAR_ROOT__ . '/ca.pem', $caFile);

print 'Updating the PHPUnit PHAR ... ';

$options = array(
'ssl' => array(
'allow_self_signed' => false,
'cafile' => $caFile,
'verify_peer' => true
)
);

if (PHP_VERSION_ID < 50600) {
$options['ssl']['CN_match'] = 'phar.phpunit.de';
$options['ssl']['SNI_server_name'] = 'phar.phpunit.de';
}

file_put_contents(
$tempFilename,
file_get_contents(
$remoteFilename,
false,
stream_context_create($options)
)
);

chmod($tempFilename, 0777 & ~umask());

try {
$phar = new Phar($tempFilename);
unset($phar);
rename($tempFilename, $localFilename);
unlink($caFile);
} catch (Throwable $_e) {
$e = $_e;
} catch (Exception $_e) {
$e = $_e;
}

if (isset($e)) {
unlink($caFile);
unlink($tempFilename);
print " done\n\n" . $e->getMessage() . "\n";
exit(2);
}

print " done\n";
exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT);
}




protected function handleVersionCheck()
{
$this->printVersionString();

$latestVersion = file_get_contents('https://phar.phpunit.de/latest-version-of/phpunit');
$isOutdated = version_compare($latestVersion, PHPUnit_Runner_Version::id(), '>');

if ($isOutdated) {
print "You are not using the latest version of PHPUnit.\n";
print 'Use "phpunit --self-upgrade" to install PHPUnit ' . $latestVersion . "\n";
} else {
print "You are using the latest version of PHPUnit.\n";
}

exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT);
}




protected function showHelp()
{
$this->printVersionString();

print <<<EOT
Usage: phpunit [options] UnitTest [UnitTest.php]
       phpunit [options] <directory>

Code Coverage Options:

  --coverage-clover <file>  Generate code coverage report in Clover XML format.
  --coverage-crap4j <file>  Generate code coverage report in Crap4J XML format.
  --coverage-html <dir>     Generate code coverage report in HTML format.
  --coverage-php <file>     Export PHP_CodeCoverage object to file.
  --coverage-text=<file>    Generate code coverage report in text format.
                            Default: Standard output.
  --coverage-xml <dir>      Generate code coverage report in PHPUnit XML format.

Logging Options:

  --log-junit <file>        Log test execution in JUnit XML format to file.
  --log-tap <file>          Log test execution in TAP format to file.
  --log-json <file>         Log test execution in JSON format.
  --testdox-html <file>     Write agile documentation in HTML format to file.
  --testdox-text <file>     Write agile documentation in Text format to file.

Test Selection Options:

  --filter <pattern>        Filter which tests to run.
  --testsuite <pattern>     Filter which testsuite to run.
  --group ...               Only runs tests from the specified group(s).
  --exclude-group ...       Exclude tests from the specified group(s).
  --list-groups             List available test groups.
  --test-suffix ...         Only search for test in files with specified
                            suffix(es). Default: Test.php,.phpt

Test Execution Options:

  --report-useless-tests    Be strict about tests that do not test anything.
  --strict-coverage         Be strict about unintentionally covered code.
  --strict-global-state     Be strict about changes to global state
  --disallow-test-output    Be strict about output during tests.
  --enforce-time-limit      Enforce time limit based on test size.
  --disallow-todo-tests     Disallow @todo-annotated tests.

  --process-isolation       Run each test in a separate PHP process.
  --no-globals-backup       Do not backup and restore \$GLOBALS for each test.
  --static-backup           Backup and restore static attributes for each test.

  --colors=<flag>           Use colors in output ("never", "auto" or "always").
  --columns <n>             Number of columns to use for progress output.
  --columns max             Use maximum number of columns for progress output.
  --stderr                  Write to STDERR instead of STDOUT.
  --stop-on-error           Stop execution upon first error.
  --stop-on-failure         Stop execution upon first error or failure.
  --stop-on-risky           Stop execution upon first risky test.
  --stop-on-skipped         Stop execution upon first skipped test.
  --stop-on-incomplete      Stop execution upon first incomplete test.
  -v|--verbose              Output more verbose information.
  --debug                   Display debugging information during test execution.

  --loader <loader>         TestSuiteLoader implementation to use.
  --repeat <times>          Runs the test(s) repeatedly.
  --tap                     Report test execution progress in TAP format.
  --testdox                 Report test execution progress in TestDox format.
  --printer <printer>       TestListener implementation to use.

Configuration Options:

  --bootstrap <file>        A "bootstrap" PHP file that is run before the tests.
  -c|--configuration <file> Read configuration from XML file.
  --no-configuration        Ignore default configuration file (phpunit.xml).
  --no-coverage             Ignore code coverage configuration.
  --include-path <path(s)>  Prepend PHP's include_path with given path(s).
  -d key[=value]            Sets a php.ini value.

Miscellaneous Options:

  -h|--help                 Prints this usage information.
  --version                 Prints the version and exits.

EOT;

if (defined('__PHPUNIT_PHAR__')) {
print "\n  --check-version           Check whether PHPUnit is the latest version.";
print "\n  --self-update             Update PHPUnit to the latest version within the same\n                            release series.\n";
print "\n  --self-upgrade            Upgrade PHPUnit to the latest version.\n";
}
}




protected function handleCustomTestSuite()
{
}

private function printVersionString()
{
if ($this->versionStringPrinted) {
return;
}

print PHPUnit_Runner_Version::getVersionString() . "\n\n";

$this->versionStringPrinted = true;
}



private function showError($message)
{
$this->printVersionString();

print $message . "\n";

exit(PHPUnit_TextUI_TestRunner::FAILURE_EXIT);
}
}
#!/usr/bin/env php
<?php
if (!isset($argv[1])) {
exit(1);
}

if ($argv[1] == 'alpha' || $argv[1] == 'beta') {
$version = sprintf('%s-%s', $argv[1], date('Y-m-d'));
} else {
$version = $argv[1];
}

file_put_contents(
__DIR__ . '/phar/phpunit/Runner/Version.php',
str_replace(
'private static $pharVersion;',
'private static $pharVersion = "' . $version . '";',
file_get_contents(__DIR__ . '/phar/phpunit/Runner/Version.php')
)
);

print $version;
#!/usr/bin/env php
<?php
print 'phpunit/phpunit: ';

$tag = @exec('git describe --tags 2>&1');

if (strpos($tag, '-') === false && strpos($tag, 'No names found') === false) {
print $tag;
} else {
$branch = @exec('git rev-parse --abbrev-ref HEAD');
$hash = @exec('git log -1 --format="%H"');
print $branch . '@' . $hash;
}

print "\n";

$lock = json_decode(file_get_contents(__DIR__ . '/../composer.lock'));

foreach ($lock->packages as $package) {
print $package->name . ': ' . $package->version;

if (!preg_match('/^[v= ]*(([0-9]+)(\\.([0-9]+)(\\.([0-9]+)(-([0-9]+))?(-?([a-zA-Z-+][a-zA-Z0-9\\.\\-:]*)?)?)?)?)$/', $package->version)) {
print '@' . $package->source->reference;
}

print "\n";
}
<?php
















class File_Iterator_Factory
{







public function getFileIterator($paths, $suffixes = '', $prefixes = '', array $exclude = array())
{
if (is_string($paths)) {
$paths = array($paths);
}

$paths = $this->getPathsAfterResolvingWildcards($paths);
$exclude = $this->getPathsAfterResolvingWildcards($exclude);

if (is_string($prefixes)) {
if ($prefixes != '') {
$prefixes = array($prefixes);
} else {
$prefixes = array();
}
}

if (is_string($suffixes)) {
if ($suffixes != '') {
$suffixes = array($suffixes);
} else {
$suffixes = array();
}
}

$iterator = new AppendIterator;

foreach ($paths as $path) {
if (is_dir($path)) {
$iterator->append(
new File_Iterator(
new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::FOLLOW_SYMLINKS)
),
$suffixes,
$prefixes,
$exclude,
$path
)
);
}
}

return $iterator;
}





protected function getPathsAfterResolvingWildcards(array $paths)
{
$_paths = array();

foreach ($paths as $path) {
if ($locals = glob($path, GLOB_ONLYDIR)) {
$_paths = array_merge($_paths, $locals);
} else {
$_paths[] = $path;
}
}

return $_paths;
}
}
<?php

















class File_Iterator_Facade
{








public function getFilesAsArray($paths, $suffixes = '', $prefixes = '', array $exclude = array(), $commonPath = FALSE)
{
if (is_string($paths)) {
$paths = array($paths);
}

$factory = new File_Iterator_Factory;
$iterator = $factory->getFileIterator(
$paths, $suffixes, $prefixes, $exclude
);

$files = array();

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 array(
'commonPath' => $this->getCommonPath($files),
'files' => $files
);
} else {
return $files;
}
}







protected function getCommonPath(array $files)
{
$count = count($files);

if ($count == 0) {
return '';
}

if ($count == 1) {
return dirname($files[0]) . DIRECTORY_SEPARATOR;
}

$_files = array();

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 File_Iterator extends FilterIterator
{
const PREFIX = 0;
const SUFFIX = 1;




protected $suffixes = array();




protected $prefixes = array();




protected $exclude = array();




protected $basepath;








public function __construct(Iterator $iterator, array $suffixes = array(), array $prefixes = array(), array $exclude = array(), $basepath = NULL)
{
$exclude = array_filter(array_map('realpath', $exclude));

if ($basepath !== NULL) {
$basepath = realpath($basepath);
}

if ($basepath === FALSE) {
$basepath = NULL;
} else {
foreach ($exclude as &$_exclude) {
$_exclude = str_replace($basepath, '', $_exclude);
}
}

$this->prefixes = $prefixes;
$this->suffixes = $suffixes;
$this->exclude = $exclude;
$this->basepath = $basepath;

parent::__construct($iterator);
}




public function accept()
{
$current = $this->getInnerIterator()->current();
$filename = $current->getFilename();
$realpath = $current->getRealPath();

if ($this->basepath !== NULL) {
$realpath = str_replace($this->basepath, '', $realpath);
}


 if (preg_match('=/\.[^/]*/=', $realpath)) {
return FALSE;
}

return $this->acceptPath($realpath) &&
$this->acceptPrefix($filename) &&
$this->acceptSuffix($filename);
}






protected function acceptPath($path)
{
foreach ($this->exclude as $exclude) {
if (strpos($path, $exclude) === 0) {
return FALSE;
}
}

return TRUE;
}






protected function acceptPrefix($filename)
{
return $this->acceptSubString($filename, $this->prefixes, self::PREFIX);
}






protected function acceptSuffix($filename)
{
return $this->acceptSubString($filename, $this->suffixes, self::SUFFIX);
}








protected function acceptSubString($filename, array $subStrings, $type)
{
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














class PHP_Timer
{



private static $times = array(
'hour' => 3600000,
'minute' => 60000,
'second' => 1000
);




private static $startTimes = array();




public static $requestTime;




public static function start()
{
array_push(self::$startTimes, microtime(true));
}






public static function stop()
{
return microtime(true) - array_pop(self::$startTimes);
}







public static function secondsToTimeString($time)
{
$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()
{
return self::secondsToTimeString(microtime(true) - self::$requestTime);
}






public static function resourceUsage()
{
return sprintf(
'Time: %s, Memory: %4.2fMb',
self::timeSinceStartOfRequest(),
memory_get_peak_usage(true) / 1048576
);
}
}

if (isset($_SERVER['REQUEST_TIME_FLOAT'])) {
PHP_Timer::$requestTime = $_SERVER['REQUEST_TIME_FLOAT'];
} elseif (isset($_SERVER['REQUEST_TIME'])) {
PHP_Timer::$requestTime = $_SERVER['REQUEST_TIME'];
} else {
PHP_Timer::$requestTime = microtime(true);
}
<?php














interface PHP_CodeCoverage_Driver
{




const LINE_EXECUTED = 1;





const LINE_NOT_EXECUTED = -1;





const LINE_NOT_EXECUTABLE = -2;




public function start();






public function stop();
}
<?php














class PHP_CodeCoverage_Filter
{





private $blacklistedFiles = array();






private $whitelistedFiles = array();








public function addDirectoryToBlacklist($directory, $suffix = '.php', $prefix = '')
{
$facade = new File_Iterator_Facade;
$files = $facade->getFilesAsArray($directory, $suffix, $prefix);

foreach ($files as $file) {
$this->addFileToBlacklist($file);
}
}






public function addFileToBlacklist($filename)
{
$this->blacklistedFiles[realpath($filename)] = true;
}






public function addFilesToBlacklist(array $files)
{
foreach ($files as $file) {
$this->addFileToBlacklist($file);
}
}








public function removeDirectoryFromBlacklist($directory, $suffix = '.php', $prefix = '')
{
$facade = new File_Iterator_Facade;
$files = $facade->getFilesAsArray($directory, $suffix, $prefix);

foreach ($files as $file) {
$this->removeFileFromBlacklist($file);
}
}






public function removeFileFromBlacklist($filename)
{
$filename = realpath($filename);

if (isset($this->blacklistedFiles[$filename])) {
unset($this->blacklistedFiles[$filename]);
}
}








public function addDirectoryToWhitelist($directory, $suffix = '.php', $prefix = '')
{
$facade = new File_Iterator_Facade;
$files = $facade->getFilesAsArray($directory, $suffix, $prefix);

foreach ($files as $file) {
$this->addFileToWhitelist($file);
}
}






public function addFileToWhitelist($filename)
{
$this->whitelistedFiles[realpath($filename)] = true;
}






public function addFilesToWhitelist(array $files)
{
foreach ($files as $file) {
$this->addFileToWhitelist($file);
}
}








public function removeDirectoryFromWhitelist($directory, $suffix = '.php', $prefix = '')
{
$facade = new File_Iterator_Facade;
$files = $facade->getFilesAsArray($directory, $suffix, $prefix);

foreach ($files as $file) {
$this->removeFileFromWhitelist($file);
}
}






public function removeFileFromWhitelist($filename)
{
$filename = realpath($filename);

if (isset($this->whitelistedFiles[$filename])) {
unset($this->whitelistedFiles[$filename]);
}
}







public function isFile($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) {
return false;
}

return file_exists($filename);
}











public function isFiltered($filename)
{
if (!$this->isFile($filename)) {
return true;
}

$filename = realpath($filename);

if (!empty($this->whitelistedFiles)) {
return !isset($this->whitelistedFiles[$filename]);
}

return isset($this->blacklistedFiles[$filename]);
}






public function getBlacklist()
{
return array_keys($this->blacklistedFiles);
}






public function getWhitelist()
{
return array_keys($this->whitelistedFiles);
}







public function hasWhitelist()
{
return !empty($this->whitelistedFiles);
}







public function getBlacklistedFiles()
{
return $this->blacklistedFiles;
}







public function setBlacklistedFiles($blacklistedFiles)
{
$this->blacklistedFiles = $blacklistedFiles;
}







public function getWhitelistedFiles()
{
return $this->whitelistedFiles;
}







public function setWhitelistedFiles($whitelistedFiles)
{
$this->whitelistedFiles = $whitelistedFiles;
}
}
<?php















class PHP_CodeCoverage_Util_InvalidArgumentHelper
{





public static function factory($argument, $type, $value = null)
{
$stack = debug_backtrace(false);

return new PHP_CodeCoverage_Exception(
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














class PHP_CodeCoverage_Report_PHP
{





public function process(PHP_CodeCoverage $coverage, $target = null)
{
$filter = $coverage->filter();

$output = sprintf(
'<?php
$coverage = new PHP_CodeCoverage;
$coverage->setData(%s);
$coverage->setTests(%s);

$filter = $coverage->filter();
$filter->setBlacklistedFiles(%s);
$filter->setWhitelistedFiles(%s);

return $coverage;',
var_export($coverage->getData(true), 1),
var_export($coverage->getTests(), 1),
var_export($filter->getBlacklistedFiles(), 1),
var_export($filter->getWhitelistedFiles(), 1)
);

if ($target !== null) {
return file_put_contents($target, $output);
} else {
return $output;
}
}
}
<?php














class PHP_CodeCoverage_Report_Factory
{




public function create(PHP_CodeCoverage $coverage)
{
$files = $coverage->getData();
$commonPath = $this->reducePaths($files);
$root = new PHP_CodeCoverage_Report_Node_Directory(
$commonPath,
null
);

$this->addItems(
$root,
$this->buildDirectoryStructure($files),
$coverage->getTests(),
$coverage->getCacheTokens()
);

return $root;
}







private function addItems(PHP_CodeCoverage_Report_Node_Directory $root, array $items, array $tests, $cacheTokens)
{
foreach ($items as $key => $value) {
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($files)
{
$result = array();

foreach ($files as $path => $file) {
$path = explode('/', $path);
$pointer = &$result;
$max = count($path);

for ($i = 0; $i < $max; $i++) {
if ($i == ($max - 1)) {
$type = '/f';
} else {
$type = '';
}

$pointer = &$pointer[$path[$i] . $type];
}

$pointer = $file;
}

return $result;
}









































private function reducePaths(&$files)
{
if (empty($files)) {
return '.';
}

$commonPath = '';
$paths = array_keys($files);

if (count($files) == 1) {
$commonPath = dirname($paths[0]) . '/';
$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] = strtr($paths[$i], '/', DIRECTORY_SEPARATOR);
}
$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('/', $paths[$i])] = $files[$original[$i]];
unset($files[$original[$i]]);
}

ksort($files);

return substr($commonPath, 0, -1);
}
}
<?php














class PHP_CodeCoverage_Report_Node_Directory extends PHP_CodeCoverage_Report_Node implements IteratorAggregate
{



protected $children = array();




protected $directories = array();




protected $files = array();




protected $classes;




protected $traits;




protected $functions;




protected $linesOfCode = null;




protected $numFiles = -1;




protected $numExecutableLines = -1;




protected $numExecutedLines = -1;




protected $numClasses = -1;




protected $numTestedClasses = -1;




protected $numTraits = -1;




protected $numTestedTraits = -1;




protected $numMethods = -1;




protected $numTestedMethods = -1;




protected $numFunctions = -1;




protected $numTestedFunctions = -1;






public function count()
{
if ($this->numFiles == -1) {
$this->numFiles = 0;

foreach ($this->children as $child) {
$this->numFiles += count($child);
}
}

return $this->numFiles;
}






public function getIterator()
{
return new RecursiveIteratorIterator(
new PHP_CodeCoverage_Report_Node_Iterator($this),
RecursiveIteratorIterator::SELF_FIRST
);
}







public function addDirectory($name)
{
$directory = new self($name, $this);

$this->children[] = $directory;
$this->directories[] = &$this->children[count($this->children) - 1];

return $directory;
}











public function addFile($name, array $coverageData, array $testData, $cacheTokens)
{
$file = new PHP_CodeCoverage_Report_Node_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()
{
return $this->directories;
}






public function getFiles()
{
return $this->files;
}






public function getChildNodes()
{
return $this->children;
}






public function getClasses()
{
if ($this->classes === null) {
$this->classes = array();

foreach ($this->children as $child) {
$this->classes = array_merge(
$this->classes,
$child->getClasses()
);
}
}

return $this->classes;
}






public function getTraits()
{
if ($this->traits === null) {
$this->traits = array();

foreach ($this->children as $child) {
$this->traits = array_merge(
$this->traits,
$child->getTraits()
);
}
}

return $this->traits;
}






public function getFunctions()
{
if ($this->functions === null) {
$this->functions = array();

foreach ($this->children as $child) {
$this->functions = array_merge(
$this->functions,
$child->getFunctions()
);
}
}

return $this->functions;
}






public function getLinesOfCode()
{
if ($this->linesOfCode === null) {
$this->linesOfCode = array('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()
{
if ($this->numExecutableLines == -1) {
$this->numExecutableLines = 0;

foreach ($this->children as $child) {
$this->numExecutableLines += $child->getNumExecutableLines();
}
}

return $this->numExecutableLines;
}






public function getNumExecutedLines()
{
if ($this->numExecutedLines == -1) {
$this->numExecutedLines = 0;

foreach ($this->children as $child) {
$this->numExecutedLines += $child->getNumExecutedLines();
}
}

return $this->numExecutedLines;
}






public function getNumClasses()
{
if ($this->numClasses == -1) {
$this->numClasses = 0;

foreach ($this->children as $child) {
$this->numClasses += $child->getNumClasses();
}
}

return $this->numClasses;
}






public function getNumTestedClasses()
{
if ($this->numTestedClasses == -1) {
$this->numTestedClasses = 0;

foreach ($this->children as $child) {
$this->numTestedClasses += $child->getNumTestedClasses();
}
}

return $this->numTestedClasses;
}






public function getNumTraits()
{
if ($this->numTraits == -1) {
$this->numTraits = 0;

foreach ($this->children as $child) {
$this->numTraits += $child->getNumTraits();
}
}

return $this->numTraits;
}






public function getNumTestedTraits()
{
if ($this->numTestedTraits == -1) {
$this->numTestedTraits = 0;

foreach ($this->children as $child) {
$this->numTestedTraits += $child->getNumTestedTraits();
}
}

return $this->numTestedTraits;
}






public function getNumMethods()
{
if ($this->numMethods == -1) {
$this->numMethods = 0;

foreach ($this->children as $child) {
$this->numMethods += $child->getNumMethods();
}
}

return $this->numMethods;
}






public function getNumTestedMethods()
{
if ($this->numTestedMethods == -1) {
$this->numTestedMethods = 0;

foreach ($this->children as $child) {
$this->numTestedMethods += $child->getNumTestedMethods();
}
}

return $this->numTestedMethods;
}






public function getNumFunctions()
{
if ($this->numFunctions == -1) {
$this->numFunctions = 0;

foreach ($this->children as $child) {
$this->numFunctions += $child->getNumFunctions();
}
}

return $this->numFunctions;
}






public function getNumTestedFunctions()
{
if ($this->numTestedFunctions == -1) {
$this->numTestedFunctions = 0;

foreach ($this->children as $child) {
$this->numTestedFunctions += $child->getNumTestedFunctions();
}
}

return $this->numTestedFunctions;
}
}
<?php














class PHP_CodeCoverage_Report_Node_Iterator implements RecursiveIterator
{



protected $position;




protected $nodes;






public function __construct(PHP_CodeCoverage_Report_Node_Directory $node)
{
$this->nodes = $node->getChildNodes();
}




public function rewind()
{
$this->position = 0;
}






public function valid()
{
return $this->position < count($this->nodes);
}






public function key()
{
return $this->position;
}






public function current()
{
return $this->valid() ? $this->nodes[$this->position] : null;
}




public function next()
{
$this->position++;
}






public function getChildren()
{
return new self(
$this->nodes[$this->position]
);
}






public function hasChildren()
{
return $this->nodes[$this->position] instanceof PHP_CodeCoverage_Report_Node_Directory;
}
}
<?php














class PHP_CodeCoverage_Report_Node_File extends PHP_CodeCoverage_Report_Node
{



protected $coverageData;




protected $testData;




protected $numExecutableLines = 0;




protected $numExecutedLines = 0;




protected $classes = array();




protected $traits = array();




protected $functions = array();




protected $linesOfCode = array();




protected $numTestedTraits = 0;




protected $numTestedClasses = 0;




protected $numMethods = null;




protected $numTestedMethods = null;




protected $numTestedFunctions = null;




protected $startLines = array();




protected $endLines = array();




protected $cacheTokens;











public function __construct($name, PHP_CodeCoverage_Report_Node $parent, array $coverageData, array $testData, $cacheTokens)
{
if (!is_bool($cacheTokens)) {
throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(
1,
'boolean'
);
}

parent::__construct($name, $parent);

$this->coverageData = $coverageData;
$this->testData = $testData;
$this->cacheTokens = $cacheTokens;

$this->calculateStatistics();
}






public function count()
{
return 1;
}






public function getCoverageData()
{
return $this->coverageData;
}






public function getTestData()
{
return $this->testData;
}






public function getClasses()
{
return $this->classes;
}






public function getTraits()
{
return $this->traits;
}






public function getFunctions()
{
return $this->functions;
}






public function getLinesOfCode()
{
return $this->linesOfCode;
}






public function getNumExecutableLines()
{
return $this->numExecutableLines;
}






public function getNumExecutedLines()
{
return $this->numExecutedLines;
}






public function getNumClasses()
{
return count($this->classes);
}






public function getNumTestedClasses()
{
return $this->numTestedClasses;
}






public function getNumTraits()
{
return count($this->traits);
}






public function getNumTestedTraits()
{
return $this->numTestedTraits;
}






public function getNumMethods()
{
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()
{
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()
{
return count($this->functions);
}






public function getNumTestedFunctions()
{
if ($this->numTestedFunctions === null) {
$this->numTestedFunctions = 0;

foreach ($this->functions as $function) {
if ($function['executableLines'] > 0 &&
$function['coverage'] == 100) {
$this->numTestedFunctions++;
}
}
}

return $this->numTestedFunctions;
}




protected function calculateStatistics()
{
$classStack = $functionStack = array();

if ($this->cacheTokens) {
$tokens = PHP_Token_Stream_CachingFactory::get($this->getPath());
} else {
$tokens = new PHP_Token_Stream($this->getPath());
}

$this->processClasses($tokens);
$this->processTraits($tokens);
$this->processFunctions($tokens);
$this->linesOfCode = $tokens->getLinesOfCode();
unset($tokens);

for ($lineNumber = 1; $lineNumber <= $this->linesOfCode['loc']; $lineNumber++) {
if (isset($this->startLines[$lineNumber])) {

 if (isset($this->startLines[$lineNumber]['className'])) {
if (isset($currentClass)) {
$classStack[] = &$currentClass;
}

$currentClass = &$this->startLines[$lineNumber];
} 
 elseif (isset($this->startLines[$lineNumber]['traitName'])) {
$currentTrait = &$this->startLines[$lineNumber];
} 
 elseif (isset($this->startLines[$lineNumber]['methodName'])) {
$currentMethod = &$this->startLines[$lineNumber];
} 
 elseif (isset($this->startLines[$lineNumber]['functionName'])) {
if (isset($currentFunction)) {
$functionStack[] = &$currentFunction;
}

$currentFunction = &$this->startLines[$lineNumber];
}
}

if (isset($this->coverageData[$lineNumber])) {
if (isset($currentClass)) {
$currentClass['executableLines']++;
}

if (isset($currentTrait)) {
$currentTrait['executableLines']++;
}

if (isset($currentMethod)) {
$currentMethod['executableLines']++;
}

if (isset($currentFunction)) {
$currentFunction['executableLines']++;
}

$this->numExecutableLines++;

if (count($this->coverageData[$lineNumber]) > 0) {
if (isset($currentClass)) {
$currentClass['executedLines']++;
}

if (isset($currentTrait)) {
$currentTrait['executedLines']++;
}

if (isset($currentMethod)) {
$currentMethod['executedLines']++;
}

if (isset($currentFunction)) {
$currentFunction['executedLines']++;
}

$this->numExecutedLines++;
}
}

if (isset($this->endLines[$lineNumber])) {

 if (isset($this->endLines[$lineNumber]['className'])) {
unset($currentClass);

if ($classStack) {
end($classStack);
$key = key($classStack);
$currentClass = &$classStack[$key];
unset($classStack[$key]);
}
} 
 elseif (isset($this->endLines[$lineNumber]['traitName'])) {
unset($currentTrait);
} 
 elseif (isset($this->endLines[$lineNumber]['methodName'])) {
unset($currentMethod);
} 
 elseif (isset($this->endLines[$lineNumber]['functionName'])) {
unset($currentFunction);

if ($functionStack) {
end($functionStack);
$key = key($functionStack);
$currentFunction = &$functionStack[$key];
unset($functionStack[$key]);
}
}
}
}

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'];
}

if ($trait['executableLines'] > 0) {
$trait['coverage'] = ($trait['executedLines'] /
$trait['executableLines']) * 100;
} else {
$trait['coverage'] = 100;
}

if ($trait['coverage'] == 100) {
$this->numTestedClasses++;
}

$trait['crap'] = $this->crap(
$trait['ccn'],
$trait['coverage']
);
}

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'];
}

if ($class['executableLines'] > 0) {
$class['coverage'] = ($class['executedLines'] /
$class['executableLines']) * 100;
} else {
$class['coverage'] = 100;
}

if ($class['coverage'] == 100) {
$this->numTestedClasses++;
}

$class['crap'] = $this->crap(
$class['ccn'],
$class['coverage']
);
}
}




protected function processClasses(PHP_Token_Stream $tokens)
{
$classes = $tokens->getClasses();
unset($tokens);

$link = $this->getId() . '.html#';

foreach ($classes as $className => $class) {
$this->classes[$className] = array(
'className' => $className,
'methods' => array(),
'startLine' => $class['startLine'],
'executableLines' => 0,
'executedLines' => 0,
'ccn' => 0,
'coverage' => 0,
'crap' => 0,
'package' => $class['package'],
'link' => $link . $class['startLine']
);

$this->startLines[$class['startLine']] = &$this->classes[$className];
$this->endLines[$class['endLine']] = &$this->classes[$className];

foreach ($class['methods'] as $methodName => $method) {
$this->classes[$className]['methods'][$methodName] = array(
'methodName' => $methodName,
'signature' => $method['signature'],
'startLine' => $method['startLine'],
'endLine' => $method['endLine'],
'executableLines' => 0,
'executedLines' => 0,
'ccn' => $method['ccn'],
'coverage' => 0,
'crap' => 0,
'link' => $link . $method['startLine']
);

$this->startLines[$method['startLine']] = &$this->classes[$className]['methods'][$methodName];
$this->endLines[$method['endLine']] = &$this->classes[$className]['methods'][$methodName];
}
}
}




protected function processTraits(PHP_Token_Stream $tokens)
{
$traits = $tokens->getTraits();
unset($tokens);

$link = $this->getId() . '.html#';

foreach ($traits as $traitName => $trait) {
$this->traits[$traitName] = array(
'traitName' => $traitName,
'methods' => array(),
'startLine' => $trait['startLine'],
'executableLines' => 0,
'executedLines' => 0,
'ccn' => 0,
'coverage' => 0,
'crap' => 0,
'package' => $trait['package'],
'link' => $link . $trait['startLine']
);

$this->startLines[$trait['startLine']] = &$this->traits[$traitName];
$this->endLines[$trait['endLine']] = &$this->traits[$traitName];

foreach ($trait['methods'] as $methodName => $method) {
$this->traits[$traitName]['methods'][$methodName] = array(
'methodName' => $methodName,
'signature' => $method['signature'],
'startLine' => $method['startLine'],
'endLine' => $method['endLine'],
'executableLines' => 0,
'executedLines' => 0,
'ccn' => $method['ccn'],
'coverage' => 0,
'crap' => 0,
'link' => $link . $method['startLine']
);

$this->startLines[$method['startLine']] = &$this->traits[$traitName]['methods'][$methodName];
$this->endLines[$method['endLine']] = &$this->traits[$traitName]['methods'][$methodName];
}
}
}




protected function processFunctions(PHP_Token_Stream $tokens)
{
$functions = $tokens->getFunctions();
unset($tokens);

$link = $this->getId() . '.html#';

foreach ($functions as $functionName => $function) {
$this->functions[$functionName] = array(
'functionName' => $functionName,
'signature' => $function['signature'],
'startLine' => $function['startLine'],
'executableLines' => 0,
'executedLines' => 0,
'ccn' => $function['ccn'],
'coverage' => 0,
'crap' => 0,
'link' => $link . $function['startLine']
);

$this->startLines[$function['startLine']] = &$this->functions[$functionName];
$this->endLines[$function['endLine']] = &$this->functions[$functionName];
}
}










protected function crap($ccn, $coverage)
{
if ($coverage == 0) {
return (string) (pow($ccn, 2) + $ccn);
}

if ($coverage >= 95) {
return (string) $ccn;
}

return sprintf(
'%01.2F',
pow($ccn, 2) * pow(1 - $coverage/100, 3) + $ccn
);
}
}
<?php














class PHP_CodeCoverage_Report_HTML_Renderer_Directory extends PHP_CodeCoverage_Report_HTML_Renderer
{




public function render(PHP_CodeCoverage_Report_Node_Directory $node, $file)
{
$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(
array(
'id' => $node->getId(),
'items' => $items
)
);

$template->renderTo($file);
}






protected function renderItem(PHP_CodeCoverage_Report_Node $item, $total = false)
{
$data = array(
'numClasses' => $item->getNumClassesAndTraits(),
'numTestedClasses' => $item->getNumTestedClassesAndTraits(),
'numMethods' => $item->getNumMethods(),
'numTestedMethods' => $item->getNumTestedMethods(),
'linesExecutedPercent' => $item->getLineExecutedPercent(false),
'linesExecutedPercentAsString' => $item->getLineExecutedPercent(),
'numExecutedLines' => $item->getNumExecutedLines(),
'numExecutableLines' => $item->getNumExecutableLines(),
'testedMethodsPercent' => $item->getTestedMethodsPercent(false),
'testedMethodsPercentAsString' => $item->getTestedMethodsPercent(),
'testedClassesPercent' => $item->getTestedClassesAndTraitsPercent(false),
'testedClassesPercentAsString' => $item->getTestedClassesAndTraitsPercent()
);

if ($total) {
$data['name'] = 'Total';
} else {
if ($item instanceof PHP_CodeCoverage_Report_Node_Directory) {
$data['name'] = sprintf(
'<a href="%s/index.html">%s</a>',
$item->getName(),
$item->getName()
);

$data['icon'] = '<span class="glyphicon glyphicon-folder-open"></span> ';
} else {
$data['name'] = sprintf(
'<a href="%s.html">%s</a>',
$item->getName(),
$item->getName()
);

$data['icon'] = '<span class="glyphicon glyphicon-file"></span> ';
}
}

return $this->renderItemTemplate(
new Text_Template($this->templatePath . 'directory_item.html', '{{', '}}'),
$data
);
}
}
<?php














class PHP_CodeCoverage_Report_HTML_Renderer_Dashboard extends PHP_CodeCoverage_Report_HTML_Renderer
{




public function render(PHP_CodeCoverage_Report_Node_Directory $node, $file)
{
$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(
array(
'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, $baseLink)
{
$result = array('class' => array(), 'method' => array());

foreach ($classes as $className => $class) {
foreach ($class['methods'] as $methodName => $method) {
if ($className != '*') {
$methodName = $className . '::' . $methodName;
}

$result['method'][] = array(
$method['coverage'],
$method['ccn'],
sprintf(
'<a href="%s">%s</a>',
str_replace($baseLink, '', $method['link']),
$methodName
)
);
}

$result['class'][] = array(
$class['coverage'],
$class['ccn'],
sprintf(
'<a href="%s">%s</a>',
str_replace($baseLink, '', $class['link']),
$className
)
);
}

return array(
'class' => json_encode($result['class']),
'method' => json_encode($result['method'])
);
}







protected function coverageDistribution(array $classes)
{
$result = array(
'class' => array(
'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' => array(
'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 array(
'class' => json_encode(array_values($result['class'])),
'method' => json_encode(array_values($result['method']))
);
}








protected function insufficientCoverage(array $classes, $baseLink)
{
$leastTestedClasses = array();
$leastTestedMethods = array();
$result = array('class' => '', 'method' => '');

foreach ($classes as $className => $class) {
foreach ($class['methods'] as $methodName => $method) {
if ($method['coverage'] < $this->highLowerBound) {
if ($className != '*') {
$key = $className . '::' . $methodName;
} else {
$key = $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) {
list($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, $baseLink)
{
$classRisks = array();
$methodRisks = array();
$result = array('class' => '', 'method' => '');

foreach ($classes as $className => $class) {
foreach ($class['methods'] as $methodName => $method) {
if ($method['coverage'] < $this->highLowerBound &&
$method['ccn'] > 1) {
if ($className != '*') {
$key = $className . '::' . $methodName;
} else {
$key = $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) {
list($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(PHP_CodeCoverage_Report_Node $node)
{
return sprintf(
'        <li><a href="index.html">%s</a></li>' . "\n" .
'        <li class="active">(Dashboard)</li>' . "\n",
$node->getName()
);
}
}
body {
 padding-top: 10px;
}

.popover {
 max-width: none;
}

.glyphicon {
 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: 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}/*!
 * Bootstrap v3.3.4 (http://getbootstrap.com)
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 *//*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{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 #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.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-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-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-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.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{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.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{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.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{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date],input[type=time],input[type=datetime-local],input[type=month]{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px \9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.form-group-sm .form-control{height:30px;line-height:30px}select[multiple].form-group-sm .form-control,textarea.form-group-sm .form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:5px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.form-group-lg .form-control{height:46px;line-height:46px}select[multiple].form-group-lg .form-control,textarea.form-group-lg .form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:10px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.33px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.active,.btn-default.focus,.btn-default:active,.btn-default:focus,.btn-default:hover,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.active,.btn-primary.focus,.btn-primary:active,.btn-primary:focus,.btn-primary:hover,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.active,.btn-success.focus,.btn-success:active,.btn-success:focus,.btn-success:hover,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.active,.btn-info.focus,.btn-info:active,.btn-info:focus,.btn-info:hover,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.active,.btn-warning.focus,.btn-warning:active,.btn-warning:focus,.btn-warning:hover,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.active,.btn-danger.focus,.btn-danger:active,.btn-danger:focus,.btn-danger:hover,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px solid}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px)and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:2;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px 15px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding:48px 0}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-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-image:-o-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-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);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-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-image:-o-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-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)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-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-image:-o-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-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)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-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-image:-o-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-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)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-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-image:-o-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-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)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.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-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-weight:400;line-height:1.4;filter:alpha(opacity=0);opacity:0}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-weight:400;line-height:1.42857143;text-align:left;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000;perspective:1000}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;margin-top:-10px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px)and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px)and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px)and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px)and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px)and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px)and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px)and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px)and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px)and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px)and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}!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:0/0}function r(n){return null===n?0/0:+n}function u(n){return!isNaN(n)}function i(n){return{left:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n(t[i],e)<0?r=i+1:u=i}return r},right:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n(t[i],e)>0?u=i:r=i+1}return r}}}function o(n){return n.length}function a(n){for(var t=1;n*t%1;)t*=10;return t}function c(n,t){for(var e in t)Object.defineProperty(n.prototype,e,{value:t[e],enumerable:!1})}function l(){this._=Object.create(null)}function s(n){return(n+="")===pa||n[0]===va?va+n:n}function f(n){return(n+="")[0]===va?n.slice(1):n}function h(n){return s(n)in this._}function g(n){return(n=s(n))in this._&&delete this._[n]}function p(){var n=[];for(var t in this._)n.push(f(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 m(){this._=Object.create(null)}function y(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=da.length;r>e;++e){var u=da[e]+t;if(u in n)return u}}function b(){}function _(){}function w(n){function t(){for(var t,r=e,u=-1,i=r.length;++u<i;)(t=r[u].on)&&t.apply(this,arguments);return n}var e=[],r=new l;return t.on=function(t,u){var i,o=r.get(t);return arguments.length<2?o&&o.on:(o&&(o.on=null,e=e.slice(0,i=e.indexOf(o)).concat(e.slice(i+1)),r.remove(t)),u&&e.push(r.set(t,{on:u})),n)},t}function S(){ta.event.preventDefault()}function k(){for(var n,t=ta.event;n=t.sourceEvent;)t=n;return t}function E(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(u){try{var i=u.sourceEvent=ta.event;u.target=n,ta.event=u,t[u.type].apply(e,r)}finally{ta.event=i}}},t}function A(n){return ya(n,_a),n}function N(n){return"function"==typeof n?n:function(){return Ma(n,this)}}function C(n){return"function"==typeof n?n:function(){return xa(n,this)}}function z(n,t){function e(){this.removeAttribute(n)}function r(){this.removeAttributeNS(n.space,n.local)}function u(){this.setAttribute(n,t)}function i(){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=ta.ns.qualify(n),null==t?n.local?r:e:"function"==typeof t?n.local?a:o:n.local?i:u}function q(n){return n.trim().replace(/\s+/g," ")}function L(n){return new RegExp("(?:^|\\s+)"+ta.requote(n)+"(?:\\s+|$)","g")}function T(n){return(n+"").trim().split(/^|\s+/)}function R(n,t){function e(){for(var e=-1;++e<u;)n[e](this,t)}function r(){for(var e=-1,r=t.apply(this,arguments);++e<u;)n[e](this,r)}n=T(n).map(D);var u=n.length;return"function"==typeof t?r:e}function D(n){var t=L(n);return function(e,r){if(u=e.classList)return r?u.add(n):u.remove(n);var u=e.getAttribute("class")||"";r?(t.lastIndex=0,t.test(u)||e.setAttribute("class",q(u+" "+n))):e.setAttribute("class",q(u.replace(t," ")))}}function P(n,t,e){function r(){this.style.removeProperty(n)}function u(){this.style.setProperty(n,t,e)}function i(){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?i:u}function U(n,t){function e(){delete this[n]}function r(){this[n]=t}function u(){var e=t.apply(this,arguments);null==e?delete this[n]:this[n]=e}return null==t?e:"function"==typeof t?u:r}function j(n){function t(){var t=this.ownerDocument,e=this.namespaceURI;return e?t.createElementNS(e,n):t.createElement(n)}function e(){return this.ownerDocument.createElementNS(n.space,n.local)}return"function"==typeof n?n:(n=ta.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 ba(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 u,i=n[e],o=0,a=i.length;a>o;o++)(u=i[o])&&t(u,o,e);return n}function Z(n){return ya(n,Sa),n}function V(n){var t,e;return function(r,u,i){var o,a=n[i].update,c=a.length;for(i!=e&&(e=i,t=0),u>=t&&(t=u+1);!(o=a[t])&&++t<c;);return o}}function X(n,t,e){function r(){var t=this[o];t&&(this.removeEventListener(n,t,t.$),delete this[o])}function u(){var u=c(t,ra(arguments));r.call(this),this.addEventListener(n,this[o]=u,u.$=e),u._=t}function i(){var t,e=new RegExp("^__on([^.]+)"+ta.requote(n)+"$");for(var r in this)if(t=r.match(e)){var u=this[r];this.removeEventListener(t[1],u,u.$),delete this[r]}}var o="__on"+n,a=n.indexOf("."),c=$;a>0&&(n=n.slice(0,a));var l=ka.get(n);return l&&(n=l,c=B),a?t?u:r:t?b:i}function $(n,t){return function(e){var r=ta.event;ta.event=e,t[0]=this.__data__;try{n.apply(this,t)}finally{ta.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-"+ ++Aa,u="click"+r,i=ta.select(t(e)).on("touchmove"+r,S).on("dragstart"+r,S).on("selectstart"+r,S);if(null==Ea&&(Ea="onselectstart"in e?!1:x(e.style,"userSelect")),Ea){var o=n(e).style,a=o[Ea];o[Ea]="none"}return function(n){if(i.on(r,null),Ea&&(o[Ea]=a),n){var t=function(){i.on(u,null)};i.on(u,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 u=r.createSVGPoint();if(0>Na){var i=t(n);if(i.scrollX||i.scrollY){r=ta.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var o=r[0][0].getScreenCTM();Na=!(o.f||o.e),r.remove()}}return Na?(u.x=e.pageX,u.y=e.pageY):(u.x=e.clientX,u.y=e.clientY),u=u.matrixTransform(n.getScreenCTM().inverse()),[u.x,u.y]}var a=n.getBoundingClientRect();return[e.clientX-a.left-n.clientLeft,e.clientY-a.top-n.clientTop]}function G(){return ta.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 nt(n){return n>1?0:-1>n?qa:Math.acos(n)}function tt(n){return n>1?Ra:-1>n?-Ra:Math.asin(n)}function et(n){return((n=Math.exp(n))-1/n)/2}function rt(n){return((n=Math.exp(n))+1/n)/2}function ut(n){return((n=Math.exp(2*n))-1)/(n+1)}function it(n){return(n=Math.sin(n/2))*n}function ot(){}function at(n,t,e){return this instanceof at?(this.h=+n,this.s=+t,void(this.l=+e)):arguments.length<2?n instanceof at?new at(n.h,n.s,n.l):bt(""+n,_t,at):new at(n,t,e)}function ct(n,t,e){function r(n){return n>360?n-=360:0>n&&(n+=360),60>n?i+(o-i)*n/60:180>n?o:240>n?i+(o-i)*(240-n)/60:i}function u(n){return Math.round(255*r(n))}var i,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,i=2*e-o,new mt(u(n+120),u(n),u(n-120))}function lt(n,t,e){return this instanceof lt?(this.h=+n,this.c=+t,void(this.l=+e)):arguments.length<2?n instanceof lt?new lt(n.h,n.c,n.l):n instanceof ft?gt(n.l,n.a,n.b):gt((n=wt((n=ta.rgb(n)).r,n.g,n.b)).l,n.a,n.b):new lt(n,t,e)}function st(n,t,e){return isNaN(n)&&(n=0),isNaN(t)&&(t=0),new ft(e,Math.cos(n*=Da)*t,Math.sin(n)*t)}function ft(n,t,e){return this instanceof ft?(this.l=+n,this.a=+t,void(this.b=+e)):arguments.length<2?n instanceof ft?new ft(n.l,n.a,n.b):n instanceof lt?st(n.h,n.c,n.l):wt((n=mt(n)).r,n.g,n.b):new ft(n,t,e)}function ht(n,t,e){var r=(n+16)/116,u=r+t/500,i=r-e/200;return u=pt(u)*Xa,r=pt(r)*$a,i=pt(i)*Ba,new mt(dt(3.2404542*u-1.5371385*r-.4985314*i),dt(-.969266*u+1.8760108*r+.041556*i),dt(.0556434*u-.2040259*r+1.0572252*i))}function gt(n,t,e){return n>0?new lt(Math.atan2(e,t)*Pa,Math.sqrt(t*t+e*e),n):new lt(0/0,0/0,n)}function pt(n){return n>.206893034?n*n*n:(n-4/29)/7.787037}function vt(n){return n>.008856?Math.pow(n,1/3):7.787037*n+4/29}function dt(n){return Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n,1/2.4)-.055))}function mt(n,t,e){return this instanceof mt?(this.r=~~n,this.g=~~t,void(this.b=~~e)):arguments.length<2?n instanceof mt?new mt(n.r,n.g,n.b):bt(""+n,mt,ct):new mt(n,t,e)}function yt(n){return new mt(n>>16,n>>8&255,255&n)}function Mt(n){return yt(n)+""}function xt(n){return 16>n?"0"+Math.max(0,n).toString(16):Math.min(255,n).toString(16)}function bt(n,t,e){var r,u,i,o=0,a=0,c=0;if(r=/([a-z]+)\((.*)\)/i.exec(n))switch(u=r[2].split(","),r[1]){case"hsl":return e(parseFloat(u[0]),parseFloat(u[1])/100,parseFloat(u[2])/100);case"rgb":return t(kt(u[0]),kt(u[1]),kt(u[2]))}return(i=Ga.get(n.toLowerCase()))?t(i.r,i.g,i.b):(null==n||"#"!==n.charAt(0)||isNaN(i=parseInt(n.slice(1),16))||(4===n.length?(o=(3840&i)>>4,o=o>>4|o,a=240&i,a=a>>4|a,c=15&i,c=c<<4|c):7===n.length&&(o=(16711680&i)>>16,a=(65280&i)>>8,c=255&i)),t(o,a,c))}function _t(n,t,e){var r,u,i=Math.min(n/=255,t/=255,e/=255),o=Math.max(n,t,e),a=o-i,c=(o+i)/2;return a?(u=.5>c?a/(o+i):a/(2-o-i),r=n==o?(t-e)/a+(e>t?6:0):t==o?(e-n)/a+2:(n-t)/a+4,r*=60):(r=0/0,u=c>0&&1>c?0:r),new at(r,u,c)}function wt(n,t,e){n=St(n),t=St(t),e=St(e);var r=vt((.4124564*n+.3575761*t+.1804375*e)/Xa),u=vt((.2126729*n+.7151522*t+.072175*e)/$a),i=vt((.0193339*n+.119192*t+.9503041*e)/Ba);return ft(116*u-16,500*(r-u),200*(u-i))}function St(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function kt(n){var t=parseFloat(n);return"%"===n.charAt(n.length-1)?Math.round(2.55*t):t}function Et(n){return"function"==typeof n?n:function(){return n}}function At(n){return function(t,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=null),Nt(t,e,n,r)}}function Nt(n,t,e,r){function u(){var n,t=c.status;if(!t&&zt(c)||t>=200&&300>t||304===t){try{n=e.call(i,c)}catch(r){return void o.error.call(i,r)}o.load.call(i,n)}else o.error.call(i,c)}var i={},o=ta.dispatch("beforesend","progress","load","error"),a={},c=new XMLHttpRequest,l=null;return!this.XDomainRequest||"withCredentials"in c||!/^(http(s)?:)?\/\//.test(n)||(c=new XDomainRequest),"onload"in c?c.onload=c.onerror=u:c.onreadystatechange=function(){c.readyState>3&&u()},c.onprogress=function(n){var t=ta.event;ta.event=n;try{o.progress.call(i,c)}finally{ta.event=t}},i.header=function(n,t){return n=(n+"").toLowerCase(),arguments.length<2?a[n]:(null==t?delete a[n]:a[n]=t+"",i)},i.mimeType=function(n){return arguments.length?(t=null==n?null:n+"",i):t},i.responseType=function(n){return arguments.length?(l=n,i):l},i.response=function(n){return e=n,i},["get","post"].forEach(function(n){i[n]=function(){return i.send.apply(i,[n].concat(ra(arguments)))}}),i.send=function(e,r,u){if(2===arguments.length&&"function"==typeof r&&(u=r,r=null),c.open(e,n,!0),null==t||"accept"in a||(a.accept=t+",*/*"),c.setRequestHeader)for(var s in a)c.setRequestHeader(s,a[s]);return null!=t&&c.overrideMimeType&&c.overrideMimeType(t),null!=l&&(c.responseType=l),null!=u&&i.on("error",u).on("load",function(n){u(null,n)}),o.beforesend.call(i,c),c.send(null==r?null:r),i},i.abort=function(){return c.abort(),i},ta.rebind(i,o,"on"),null==r?i:i.get(Ct(r))}function Ct(n){return 1===n.length?function(t,e){n(null==t?e:null)}:n}function zt(n){var t=n.responseType;return t&&"text"!==t?n.response:n.responseText}function qt(){var n=Lt(),t=Tt()-n;t>24?(isFinite(t)&&(clearTimeout(tc),tc=setTimeout(qt,t)),nc=0):(nc=1,rc(qt))}function Lt(){var n=Date.now();for(ec=Ka;ec;)n>=ec.t&&(ec.f=ec.c(n-ec.t)),ec=ec.n;return n}function Tt(){for(var n,t=Ka,e=1/0;t;)t.f?t=n?n.n=t.n:Ka=t.n:(t.t<e&&(e=t.t),t=(n=t).n);return Qa=n,e}function Rt(n,t){return t-(n?Math.ceil(Math.log(n)/Math.LN10):1)}function Dt(n,t){var e=Math.pow(10,3*ga(8-t));return{scale:t>8?function(n){return n/e}:function(n){return n*e},symbol:n}}function Pt(n){var t=n.decimal,e=n.thousands,r=n.grouping,u=n.currency,i=r&&e?function(n,t){for(var u=n.length,i=[],o=0,a=r[0],c=0;u>0&&a>0&&(c+a+1>t&&(a=Math.max(1,t-c)),i.push(n.substring(u-=a,u+a)),!((c+=a+1)>t));)a=r[o=(o+1)%r.length];return i.reverse().join(e)}:y;return function(n){var e=ic.exec(n),r=e[1]||" ",o=e[2]||">",a=e[3]||"-",c=e[4]||"",l=e[5],s=+e[6],f=e[7],h=e[8],g=e[9],p=1,v="",d="",m=!1,y=!0;switch(h&&(h=+h.substring(1)),(l||"0"===r&&"="===o)&&(l=r="0",o="="),g){case"n":f=!0,g="g";break;case"%":p=100,d="%",g="f";break;case"p":p=100,d="%",g="r";break;case"b":case"o":case"x":case"X":"#"===c&&(v="0"+g.toLowerCase());case"c":y=!1;case"d":m=!0,h=0;break;case"s":p=-1,g="r"}"$"===c&&(v=u[0],d=u[1]),"r"!=g||h||(g="g"),null!=h&&("g"==g?h=Math.max(1,Math.min(21,h)):("e"==g||"f"==g)&&(h=Math.max(0,Math.min(20,h)))),g=oc.get(g)||Ut;var M=l&&f;return function(n){var e=d;if(m&&n%1)return"";var u=0>n||0===n&&0>1/n?(n=-n,"-"):"-"===a?"":a;if(0>p){var c=ta.formatPrefix(n,h);n=c.scale(n),e=c.symbol+d}else n*=p;n=g(n,h);var x,b,_=n.lastIndexOf(".");if(0>_){var w=y?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);!l&&f&&(x=i(x,1/0));var S=v.length+x.length+b.length+(M?0:u.length),k=s>S?new Array(S=s-S+1).join(r):"";return M&&(x=i(k+x,k.length?s-b.length:1/0)),u+=v,n=x+b,("<"===o?u+n+k:">"===o?k+u+n:"^"===o?k.substring(0,S>>=1)+u+n+k.substring(S):u+(M?n:k+n))+e}}}function Ut(n){return n+""}function jt(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function Ft(n,t,e){function r(t){var e=n(t),r=i(e,1);return r-t>t-e?e:r}function u(e){return t(e=n(new cc(e-1)),1),e}function i(n,e){return t(n=new cc(+n),e),n}function o(n,r,i){var o=u(n),a=[];if(i>1)for(;r>o;)e(o)%i||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{cc=jt;var r=new jt;return r._=n,o(r,t,e)}finally{cc=Date}}n.floor=n,n.round=r,n.ceil=u,n.offset=i,n.range=o;var c=n.utc=Ht(n);return c.floor=c,c.round=Ht(r),c.ceil=Ht(u),c.offset=Ht(i),c.range=a,n}function Ht(n){return function(t,e){try{cc=jt;var r=new jt;return r._=t,n(r,e)._}finally{cc=Date}}}function Ot(n){function t(n){function t(t){for(var e,u,i,o=[],a=-1,c=0;++a<r;)37===n.charCodeAt(a)&&(o.push(n.slice(c,a)),null!=(u=sc[e=n.charAt(++a)])&&(e=n.charAt(++a)),(i=N[e])&&(e=i(t,null==u?"e"===e?" ":"0":u)),o.push(e),c=a+1);return o.push(n.slice(c,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},u=e(r,n,t,0);if(u!=t.length)return null;"p"in r&&(r.H=r.H%12+12*r.p);var i=null!=r.Z&&cc!==jt,o=new(i?jt:cc);return"j"in r?o.setFullYear(r.y,0,r.j):"w"in r&&("W"in r||"U"in r)?(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),i?o._:o},t.toString=function(){return n},t}function e(n,t,e,r){for(var u,i,o,a=0,c=t.length,l=e.length;c>a;){if(r>=l)return-1;if(u=t.charCodeAt(a++),37===u){if(o=t.charAt(a++),i=C[o in sc?t.charAt(a++):o],!i||(r=i(n,e,r))<0)return-1}else if(u!=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 u(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 i(n,t,e){E.lastIndex=0;var r=E.exec(t.slice(e));return r?(n.m=A.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,N.c.toString(),t,r)}function c(n,t,r){return e(n,N.x.toString(),t,r)}function l(n,t,r){return e(n,N.X.toString(),t,r)}function s(n,t,e){var r=M.get(t.slice(e,e+=2).toLowerCase());return null==r?-1:(n.p=r,e)}var f=n.dateTime,h=n.date,g=n.time,p=n.periods,v=n.days,d=n.shortDays,m=n.months,y=n.shortMonths;t.utc=function(n){function e(n){try{cc=jt;var t=new cc;return t._=n,r(t)}finally{cc=Date}}var r=t(n);return e.parse=function(n){try{cc=jt;var t=r.parse(n);return t&&t._}finally{cc=Date}},e.toString=r.toString,e},t.multi=t.utc.multi=ae;var M=ta.map(),x=Yt(v),b=Zt(v),_=Yt(d),w=Zt(d),S=Yt(m),k=Zt(m),E=Yt(y),A=Zt(y);p.forEach(function(n,t){M.set(n.toLowerCase(),t)});var N={a:function(n){return d[n.getDay()]},A:function(n){return v[n.getDay()]},b:function(n){return y[n.getMonth()]},B:function(n){return m[n.getMonth()]},c:t(f),d:function(n,t){return It(n.getDate(),t,2)},e:function(n,t){return It(n.getDate(),t,2)},H:function(n,t){return It(n.getHours(),t,2)},I:function(n,t){return It(n.getHours()%12||12,t,2)},j:function(n,t){return It(1+ac.dayOfYear(n),t,3)},L:function(n,t){return It(n.getMilliseconds(),t,3)},m:function(n,t){return It(n.getMonth()+1,t,2)},M:function(n,t){return It(n.getMinutes(),t,2)},p:function(n){return p[+(n.getHours()>=12)]},S:function(n,t){return It(n.getSeconds(),t,2)},U:function(n,t){return It(ac.sundayOfYear(n),t,2)},w:function(n){return n.getDay()},W:function(n,t){return It(ac.mondayOfYear(n),t,2)},x:t(h),X:t(g),y:function(n,t){return It(n.getFullYear()%100,t,2)},Y:function(n,t){return It(n.getFullYear()%1e4,t,4)},Z:ie,"%":function(){return"%"}},C={a:r,A:u,b:i,B:o,c:a,d:Qt,e:Qt,H:te,I:te,j:ne,L:ue,m:Kt,M:ee,p:s,S:re,U:Xt,w:Vt,W:$t,x:c,X:l,y:Wt,Y:Bt,Z:Jt,"%":oe};return t}function It(n,t,e){var r=0>n?"-":"",u=(r?-n:n)+"",i=u.length;return r+(e>i?new Array(e-i+1).join(t)+u:u)}function Yt(n){return new RegExp("^(?:"+n.map(ta.requote).join("|")+")","i")}function Zt(n){for(var t=new l,e=-1,r=n.length;++e<r;)t.set(n[e].toLowerCase(),e);return t}function Vt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+1));return r?(n.w=+r[0],e+r[0].length):-1}function Xt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e));return r?(n.U=+r[0],e+r[0].length):-1}function $t(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e));return r?(n.W=+r[0],e+r[0].length):-1}function Bt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+4));return r?(n.y=+r[0],e+r[0].length):-1}function Wt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.y=Gt(+r[0]),e+r[0].length):-1}function Jt(n,t,e){return/^[+-]\d{4}$/.test(t=t.slice(e,e+5))?(n.Z=-t,e+5):-1}function Gt(n){return n+(n>68?1900:2e3)}function Kt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.m=r[0]-1,e+r[0].length):-1}function Qt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.d=+r[0],e+r[0].length):-1}function ne(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+3));return r?(n.j=+r[0],e+r[0].length):-1}function te(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.H=+r[0],e+r[0].length):-1}function ee(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.M=+r[0],e+r[0].length):-1}function re(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.S=+r[0],e+r[0].length):-1}function ue(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+3));return r?(n.L=+r[0],e+r[0].length):-1}function ie(n){var t=n.getTimezoneOffset(),e=t>0?"-":"+",r=ga(t)/60|0,u=ga(t)%60;return e+It(r,"0",2)+It(u,"0",2)}function oe(n,t,e){hc.lastIndex=0;var r=hc.exec(t.slice(e,e+1));return r?e+r[0].length:-1}function ae(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 ce(){}function le(n,t,e){var r=e.s=n+t,u=r-n,i=r-u;e.t=n-i+(t-u)}function se(n,t){n&&dc.hasOwnProperty(n.type)&&dc[n.type](n,t)}function fe(n,t,e){var r,u=-1,i=n.length-e;for(t.lineStart();++u<i;)r=n[u],t.point(r[0],r[1],r[2]);t.lineEnd()}function he(n,t){var e=-1,r=n.length;for(t.polygonStart();++e<r;)fe(n[e],t,1);t.polygonEnd()}function ge(){function n(n,t){n*=Da,t=t*Da/2+qa/4;var e=n-r,o=e>=0?1:-1,a=o*e,c=Math.cos(t),l=Math.sin(t),s=i*l,f=u*c+s*Math.cos(a),h=s*o*Math.sin(a);yc.add(Math.atan2(h,f)),r=n,u=c,i=l}var t,e,r,u,i;Mc.point=function(o,a){Mc.point=n,r=(t=o)*Da,u=Math.cos(a=(e=a)*Da/2+qa/4),i=Math.sin(a)},Mc.lineEnd=function(){n(t,e)}}function pe(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 ve(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]}function de(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 me(n,t){n[0]+=t[0],n[1]+=t[1],n[2]+=t[2]}function ye(n,t){return[n[0]*t,n[1]*t,n[2]*t]}function Me(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 xe(n){return[Math.atan2(n[1],n[0]),tt(n[2])]}function be(n,t){return ga(n[0]-t[0])<Ca&&ga(n[1]-t[1])<Ca}function _e(n,t){n*=Da;var e=Math.cos(t*=Da);we(e*Math.cos(n),e*Math.sin(n),Math.sin(t))}function we(n,t,e){++xc,_c+=(n-_c)/xc,wc+=(t-wc)/xc,Sc+=(e-Sc)/xc}function Se(){function n(n,u){n*=Da;var i=Math.cos(u*=Da),o=i*Math.cos(n),a=i*Math.sin(n),c=Math.sin(u),l=Math.atan2(Math.sqrt((l=e*c-r*a)*l+(l=r*o-t*c)*l+(l=t*a-e*o)*l),t*o+e*a+r*c);bc+=l,kc+=l*(t+(t=o)),Ec+=l*(e+(e=a)),Ac+=l*(r+(r=c)),we(t,e,r)}var t,e,r;qc.point=function(u,i){u*=Da;var o=Math.cos(i*=Da);t=o*Math.cos(u),e=o*Math.sin(u),r=Math.sin(i),qc.point=n,we(t,e,r)}}function ke(){qc.point=_e}function Ee(){function n(n,t){n*=Da;var e=Math.cos(t*=Da),o=e*Math.cos(n),a=e*Math.sin(n),c=Math.sin(t),l=u*c-i*a,s=i*o-r*c,f=r*a-u*o,h=Math.sqrt(l*l+s*s+f*f),g=r*o+u*a+i*c,p=h&&-nt(g)/h,v=Math.atan2(h,g);Nc+=p*l,Cc+=p*s,zc+=p*f,bc+=v,kc+=v*(r+(r=o)),Ec+=v*(u+(u=a)),Ac+=v*(i+(i=c)),we(r,u,i)}var t,e,r,u,i;qc.point=function(o,a){t=o,e=a,qc.point=n,o*=Da;var c=Math.cos(a*=Da);r=c*Math.cos(o),u=c*Math.sin(o),i=Math.sin(a),we(r,u,i)},qc.lineEnd=function(){n(t,e),qc.lineEnd=ke,qc.point=_e}}function Ae(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 Ne(){return!0}function Ce(n,t,e,r,u){var i=[],o=[];if(n.forEach(function(n){if(!((t=n.length-1)<=0)){var t,e=n[0],r=n[t];if(be(e,r)){u.lineStart();for(var a=0;t>a;++a)u.point((e=n[a])[0],e[1]);return void u.lineEnd()}var c=new qe(e,n,null,!0),l=new qe(e,null,c,!1);c.o=l,i.push(c),o.push(l),c=new qe(r,n,null,!1),l=new qe(r,null,c,!0),c.o=l,i.push(c),o.push(l)}}),o.sort(t),ze(i),ze(o),i.length){for(var a=0,c=e,l=o.length;l>a;++a)o[a].e=c=!c;for(var s,f,h=i[0];;){for(var g=h,p=!0;g.v;)if((g=g.n)===h)return;s=g.z,u.lineStart();do{if(g.v=g.o.v=!0,g.e){if(p)for(var a=0,l=s.length;l>a;++a)u.point((f=s[a])[0],f[1]);else r(g.x,g.n.x,1,u);g=g.n}else{if(p){s=g.p.z;for(var a=s.length-1;a>=0;--a)u.point((f=s[a])[0],f[1])}else r(g.x,g.p.x,-1,u);g=g.p}g=g.o,s=g.z,p=!p}while(!g.v);u.lineEnd()}}}function ze(n){if(t=n.length){for(var t,e,r=0,u=n[0];++r<t;)u.n=e=n[r],e.p=u,u=e;u.n=e=n[0],e.p=u}}function qe(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 Le(n,t,e,r){return function(u,i){function o(t,e){var r=u(t,e);n(t=r[0],e=r[1])&&i.point(t,e)}function a(n,t){var e=u(n,t);d.point(e[0],e[1])}function c(){y.point=a,d.lineStart()}function l(){y.point=o,d.lineEnd()}function s(n,t){v.push([n,t]);var e=u(n,t);x.point(e[0],e[1])}function f(){x.lineStart(),v=[]}function h(){s(v[0][0],v[0][1]),x.lineEnd();var n,t=x.clean(),e=M.buffer(),r=e.length;if(v.pop(),p.push(v),v=null,r)if(1&t){n=e[0];var u,r=n.length-1,o=-1;if(r>0){for(b||(i.polygonStart(),b=!0),i.lineStart();++o<r;)i.point((u=n[o])[0],u[1]);i.lineEnd()}}else r>1&&2&t&&e.push(e.pop().concat(e.shift())),g.push(e.filter(Te))}var g,p,v,d=t(i),m=u.invert(r[0],r[1]),y={point:o,lineStart:c,lineEnd:l,polygonStart:function(){y.point=s,y.lineStart=f,y.lineEnd=h,g=[],p=[]},polygonEnd:function(){y.point=o,y.lineStart=c,y.lineEnd=l,g=ta.merge(g);var n=Fe(m,p);g.length?(b||(i.polygonStart(),b=!0),Ce(g,De,n,e,i)):n&&(b||(i.polygonStart(),b=!0),i.lineStart(),e(null,null,1,i),i.lineEnd()),b&&(i.polygonEnd(),b=!1),g=p=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}},M=Re(),x=t(M),b=!1;return y}}function Te(n){return n.length>1}function Re(){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 De(n,t){return((n=n.x)[0]<0?n[1]-Ra-Ca:Ra-n[1])-((t=t.x)[0]<0?t[1]-Ra-Ca:Ra-t[1])}function Pe(n){var t,e=0/0,r=0/0,u=0/0;return{lineStart:function(){n.lineStart(),t=1},point:function(i,o){var a=i>0?qa:-qa,c=ga(i-e);ga(c-qa)<Ca?(n.point(e,r=(r+o)/2>0?Ra:-Ra),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),n.point(i,r),t=0):u!==a&&c>=qa&&(ga(e-u)<Ca&&(e-=u*Ca),ga(i-a)<Ca&&(i-=a*Ca),r=Ue(e,r,i,o),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),t=0),n.point(e=i,r=o),u=a},lineEnd:function(){n.lineEnd(),e=r=0/0},clean:function(){return 2-t}}}function Ue(n,t,e,r){var u,i,o=Math.sin(n-e);return ga(o)>Ca?Math.atan((Math.sin(t)*(i=Math.cos(r))*Math.sin(e)-Math.sin(r)*(u=Math.cos(t))*Math.sin(n))/(u*i*o)):(t+r)/2}function je(n,t,e,r){var u;if(null==n)u=e*Ra,r.point(-qa,u),r.point(0,u),r.point(qa,u),r.point(qa,0),r.point(qa,-u),r.point(0,-u),r.point(-qa,-u),r.point(-qa,0),r.point(-qa,u);else if(ga(n[0]-t[0])>Ca){var i=n[0]<t[0]?qa:-qa;u=e*i/2,r.point(-i,u),r.point(0,u),r.point(i,u)}else r.point(t[0],t[1])}function Fe(n,t){var e=n[0],r=n[1],u=[Math.sin(e),-Math.cos(e),0],i=0,o=0;yc.reset();for(var a=0,c=t.length;c>a;++a){var l=t[a],s=l.length;if(s)for(var f=l[0],h=f[0],g=f[1]/2+qa/4,p=Math.sin(g),v=Math.cos(g),d=1;;){d===s&&(d=0),n=l[d];var m=n[0],y=n[1]/2+qa/4,M=Math.sin(y),x=Math.cos(y),b=m-h,_=b>=0?1:-1,w=_*b,S=w>qa,k=p*M;if(yc.add(Math.atan2(k*_*Math.sin(w),v*x+k*Math.cos(w))),i+=S?b+_*La:b,S^h>=e^m>=e){var E=de(pe(f),pe(n));Me(E);var A=de(u,E);Me(A);var N=(S^b>=0?-1:1)*tt(A[2]);(r>N||r===N&&(E[0]||E[1]))&&(o+=S^b>=0?1:-1)}if(!d++)break;h=m,p=M,v=x,f=n}}return(-Ca>i||Ca>i&&0>yc)^1&o}function He(n){function t(n,t){return Math.cos(n)*Math.cos(t)>i}function e(n){var e,i,c,l,s;return{lineStart:function(){l=c=!1,s=1},point:function(f,h){var g,p=[f,h],v=t(f,h),d=o?v?0:u(f,h):v?u(f+(0>f?qa:-qa),h):0;if(!e&&(l=c=v)&&n.lineStart(),v!==c&&(g=r(e,p),(be(e,g)||be(p,g))&&(p[0]+=Ca,p[1]+=Ca,v=t(p[0],p[1]))),v!==c)s=0,v?(n.lineStart(),g=r(p,e),n.point(g[0],g[1])):(g=r(e,p),n.point(g[0],g[1]),n.lineEnd()),e=g;else if(a&&e&&o^v){var m;d&i||!(m=r(p,e,!0))||(s=0,o?(n.lineStart(),n.point(m[0][0],m[0][1]),n.point(m[1][0],m[1][1]),n.lineEnd()):(n.point(m[1][0],m[1][1]),n.lineEnd(),n.lineStart(),n.point(m[0][0],m[0][1])))}!v||e&&be(e,p)||n.point(p[0],p[1]),e=p,c=v,i=d},lineEnd:function(){c&&n.lineEnd(),e=null},clean:function(){return s|(l&&c)<<1}}}function r(n,t,e){var r=pe(n),u=pe(t),o=[1,0,0],a=de(r,u),c=ve(a,a),l=a[0],s=c-l*l;if(!s)return!e&&n;var f=i*c/s,h=-i*l/s,g=de(o,a),p=ye(o,f),v=ye(a,h);me(p,v);var d=g,m=ve(p,d),y=ve(d,d),M=m*m-y*(ve(p,p)-1);if(!(0>M)){var x=Math.sqrt(M),b=ye(d,(-m-x)/y);if(me(b,p),b=xe(b),!e)return b;var _,w=n[0],S=t[0],k=n[1],E=t[1];w>S&&(_=w,w=S,S=_);var A=S-w,N=ga(A-qa)<Ca,C=N||Ca>A;if(!N&&k>E&&(_=k,k=E,E=_),C?N?k+E>0^b[1]<(ga(b[0]-w)<Ca?k:E):k<=b[1]&&b[1]<=E:A>qa^(w<=b[0]&&b[0]<=S)){var z=ye(d,(-m+x)/y);return me(z,p),[b,xe(z)]}}}function u(t,e){var r=o?n:qa-n,u=0;return-r>t?u|=1:t>r&&(u|=2),-r>e?u|=4:e>r&&(u|=8),u}var i=Math.cos(n),o=i>0,a=ga(i)>Ca,c=gr(n,6*Da);return Le(t,e,c,o?[0,-n]:[-qa,n-qa])}function Oe(n,t,e,r){return function(u){var i,o=u.a,a=u.b,c=o.x,l=o.y,s=a.x,f=a.y,h=0,g=1,p=s-c,v=f-l;if(i=n-c,p||!(i>0)){if(i/=p,0>p){if(h>i)return;g>i&&(g=i)}else if(p>0){if(i>g)return;i>h&&(h=i)}if(i=e-c,p||!(0>i)){if(i/=p,0>p){if(i>g)return;i>h&&(h=i)}else if(p>0){if(h>i)return;g>i&&(g=i)}if(i=t-l,v||!(i>0)){if(i/=v,0>v){if(h>i)return;g>i&&(g=i)}else if(v>0){if(i>g)return;i>h&&(h=i)}if(i=r-l,v||!(0>i)){if(i/=v,0>v){if(i>g)return;i>h&&(h=i)}else if(v>0){if(h>i)return;g>i&&(g=i)}return h>0&&(u.a={x:c+h*p,y:l+h*v}),1>g&&(u.b={x:c+g*p,y:l+g*v}),u}}}}}}function Ie(n,t,e,r){function u(r,u){return ga(r[0]-n)<Ca?u>0?0:3:ga(r[0]-e)<Ca?u>0?2:1:ga(r[1]-t)<Ca?u>0?1:0:u>0?3:2}function i(n,t){return o(n.x,t.x)}function o(n,t){var e=u(n,1),r=u(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 c(n){for(var t=0,e=d.length,r=n[1],u=0;e>u;++u)for(var i,o=1,a=d[u],c=a.length,l=a[0];c>o;++o)i=a[o],l[1]<=r?i[1]>r&&Q(l,i,n)>0&&++t:i[1]<=r&&Q(l,i,n)<0&&--t,l=i;return 0!==t}function l(i,a,c,l){var s=0,f=0;if(null==i||(s=u(i,c))!==(f=u(a,c))||o(i,a)<0^c>0){do l.point(0===s||3===s?n:e,s>1?r:t);while((s=(s+c+4)%4)!==f)}else l.point(a[0],a[1])}function s(u,i){return u>=n&&e>=u&&i>=t&&r>=i}function f(n,t){s(n,t)&&a.point(n,t)}function h(){C.point=p,d&&d.push(m=[]),S=!0,w=!1,b=_=0/0}function g(){v&&(p(y,M),x&&w&&A.rejoin(),v.push(A.buffer())),C.point=f,w&&a.lineEnd()}function p(n,t){n=Math.max(-Tc,Math.min(Tc,n)),t=Math.max(-Tc,Math.min(Tc,t));var e=s(n,t);if(d&&m.push([n,t]),S)y=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}};N(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,m,y,M,x,b,_,w,S,k,E=a,A=Re(),N=Oe(n,t,e,r),C={point:f,lineStart:h,lineEnd:g,polygonStart:function(){a=A,v=[],d=[],k=!0},polygonEnd:function(){a=E,v=ta.merge(v);var t=c([n,r]),e=k&&t,u=v.length;(e||u)&&(a.polygonStart(),e&&(a.lineStart(),l(null,null,1,a),a.lineEnd()),u&&Ce(v,i,t,l,a),a.polygonEnd()),v=d=m=null}};return C}}function Ye(n){var t=0,e=qa/3,r=ir(n),u=r(t,e);return u.parallels=function(n){return arguments.length?r(t=n[0]*qa/180,e=n[1]*qa/180):[t/qa*180,e/qa*180]},u}function Ze(n,t){function e(n,t){var e=Math.sqrt(i-2*u*Math.sin(t))/u;return[e*Math.sin(n*=u),o-e*Math.cos(n)]}var r=Math.sin(n),u=(r+Math.sin(t))/2,i=1+r*(2*u-r),o=Math.sqrt(i)/u;return e.invert=function(n,t){var e=o-t;return[Math.atan2(n,e)/u,tt((i-(n*n+e*e)*u*u)/(2*u))]},e}function Ve(){function n(n,t){Dc+=u*n-r*t,r=n,u=t}var t,e,r,u;Hc.point=function(i,o){Hc.point=n,t=r=i,e=u=o},Hc.lineEnd=function(){n(t,e)}}function Xe(n,t){Pc>n&&(Pc=n),n>jc&&(jc=n),Uc>t&&(Uc=t),t>Fc&&(Fc=t)}function $e(){function n(n,t){o.push("M",n,",",t,i)}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 u(){o.push("Z")}var i=Be(4.5),o=[],a={point:n,lineStart:function(){a.point=t},lineEnd:r,polygonStart:function(){a.lineEnd=u},polygonEnd:function(){a.lineEnd=r,a.point=n},pointRadius:function(n){return i=Be(n),a},result:function(){if(o.length){var n=o.join("");return o=[],n}}};return a}function Be(n){return"m0,"+n+"a"+n+","+n+" 0 1,1 0,"+-2*n+"a"+n+","+n+" 0 1,1 0,"+2*n+"z"}function We(n,t){_c+=n,wc+=t,++Sc}function Je(){function n(n,r){var u=n-t,i=r-e,o=Math.sqrt(u*u+i*i);kc+=o*(t+n)/2,Ec+=o*(e+r)/2,Ac+=o,We(t=n,e=r)}var t,e;Ic.point=function(r,u){Ic.point=n,We(t=r,e=u)}}function Ge(){Ic.point=We}function Ke(){function n(n,t){var e=n-r,i=t-u,o=Math.sqrt(e*e+i*i);kc+=o*(r+n)/2,Ec+=o*(u+t)/2,Ac+=o,o=u*n-r*t,Nc+=o*(r+n),Cc+=o*(u+t),zc+=3*o,We(r=n,u=t)}var t,e,r,u;Ic.point=function(i,o){Ic.point=n,We(t=r=i,e=u=o)},Ic.lineEnd=function(){n(t,e)}}function Qe(n){function t(t,e){n.moveTo(t+o,e),n.arc(t,e,o,0,La)}function e(t,e){n.moveTo(t,e),a.point=r}function r(t,e){n.lineTo(t,e)}function u(){a.point=t}function i(){n.closePath()}var o=4.5,a={point:t,lineStart:function(){a.point=e},lineEnd:u,polygonStart:function(){a.lineEnd=i},polygonEnd:function(){a.lineEnd=u,a.point=t},pointRadius:function(n){return o=n,a},result:b};return a}function nr(n){function t(n){return(a?r:e)(n)}function e(t){return rr(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=0/0,S.point=i,t.lineStart()}function i(e,r){var i=pe([e,r]),o=n(e,r);u(M,x,y,b,_,w,M=o[0],x=o[1],y=e,b=i[0],_=i[1],w=i[2],a,t),t.point(M,x)}function o(){S.point=e,t.lineEnd()}function c(){r(),S.point=l,S.lineEnd=s}function l(n,t){i(f=n,h=t),g=M,p=x,v=b,d=_,m=w,S.point=i}function s(){u(M,x,y,b,_,w,g,p,f,v,d,m,a,t),S.lineEnd=o,o()}var f,h,g,p,v,d,m,y,M,x,b,_,w,S={point:e,lineStart:r,lineEnd:o,polygonStart:function(){t.polygonStart(),S.lineStart=c
},polygonEnd:function(){t.polygonEnd(),S.lineStart=r}};return S}function u(t,e,r,a,c,l,s,f,h,g,p,v,d,m){var y=s-t,M=f-e,x=y*y+M*M;if(x>4*i&&d--){var b=a+g,_=c+p,w=l+v,S=Math.sqrt(b*b+_*_+w*w),k=Math.asin(w/=S),E=ga(ga(w)-1)<Ca||ga(r-h)<Ca?(r+h)/2:Math.atan2(_,b),A=n(E,k),N=A[0],C=A[1],z=N-t,q=C-e,L=M*z-y*q;(L*L/x>i||ga((y*z+M*q)/x-.5)>.3||o>a*g+c*p+l*v)&&(u(t,e,r,a,c,l,N,C,E,b/=S,_/=S,w,d,m),m.point(N,C),u(N,C,E,b,_,w,s,f,h,g,p,v,d,m))}}var i=.5,o=Math.cos(30*Da),a=16;return t.precision=function(n){return arguments.length?(a=(i=n*n)>0&&16,t):Math.sqrt(i)},t}function tr(n){var t=nr(function(t,e){return n([t*Pa,e*Pa])});return function(n){return or(t(n))}}function er(n){this.stream=n}function rr(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 ur(n){return ir(function(){return n})()}function ir(n){function t(n){return n=a(n[0]*Da,n[1]*Da),[n[0]*h+c,l-n[1]*h]}function e(n){return n=a.invert((n[0]-c)/h,(l-n[1])/h),n&&[n[0]*Pa,n[1]*Pa]}function r(){a=Ae(o=lr(m,M,x),i);var n=i(v,d);return c=g-n[0]*h,l=p+n[1]*h,u()}function u(){return s&&(s.valid=!1,s=null),t}var i,o,a,c,l,s,f=nr(function(n,t){return n=i(n,t),[n[0]*h+c,l-n[1]*h]}),h=150,g=480,p=250,v=0,d=0,m=0,M=0,x=0,b=Lc,_=y,w=null,S=null;return t.stream=function(n){return s&&(s.valid=!1),s=or(b(o,f(_(n)))),s.valid=!0,s},t.clipAngle=function(n){return arguments.length?(b=null==n?(w=n,Lc):He((w=+n)*Da),u()):w},t.clipExtent=function(n){return arguments.length?(S=n,_=n?Ie(n[0][0],n[0][1],n[1][0],n[1][1]):y,u()):S},t.scale=function(n){return arguments.length?(h=+n,r()):h},t.translate=function(n){return arguments.length?(g=+n[0],p=+n[1],r()):[g,p]},t.center=function(n){return arguments.length?(v=n[0]%360*Da,d=n[1]%360*Da,r()):[v*Pa,d*Pa]},t.rotate=function(n){return arguments.length?(m=n[0]%360*Da,M=n[1]%360*Da,x=n.length>2?n[2]%360*Da:0,r()):[m*Pa,M*Pa,x*Pa]},ta.rebind(t,f,"precision"),function(){return i=n.apply(this,arguments),t.invert=i.invert&&e,r()}}function or(n){return rr(n,function(t,e){n.point(t*Da,e*Da)})}function ar(n,t){return[n,t]}function cr(n,t){return[n>qa?n-La:-qa>n?n+La:n,t]}function lr(n,t,e){return n?t||e?Ae(fr(n),hr(t,e)):fr(n):t||e?hr(t,e):cr}function sr(n){return function(t,e){return t+=n,[t>qa?t-La:-qa>t?t+La:t,e]}}function fr(n){var t=sr(n);return t.invert=sr(-n),t}function hr(n,t){function e(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,l=Math.sin(t),s=l*r+a*u;return[Math.atan2(c*i-s*o,a*r-l*u),tt(s*i+c*o)]}var r=Math.cos(n),u=Math.sin(n),i=Math.cos(t),o=Math.sin(t);return e.invert=function(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,l=Math.sin(t),s=l*i-c*o;return[Math.atan2(c*i+l*o,a*r+s*u),tt(s*r-a*u)]},e}function gr(n,t){var e=Math.cos(n),r=Math.sin(n);return function(u,i,o,a){var c=o*t;null!=u?(u=pr(e,u),i=pr(e,i),(o>0?i>u:u>i)&&(u+=o*La)):(u=n+o*La,i=n-.5*c);for(var l,s=u;o>0?s>i:i>s;s-=c)a.point((l=xe([e,-r*Math.cos(s),-r*Math.sin(s)]))[0],l[1])}}function pr(n,t){var e=pe(t);e[0]-=n,Me(e);var r=nt(-e[1]);return((-e[2]<0?-r:r)+2*Math.PI-Ca)%(2*Math.PI)}function vr(n,t,e){var r=ta.range(n,t-Ca,e).concat(t);return function(n){return r.map(function(t){return[n,t]})}}function dr(n,t,e){var r=ta.range(n,t-Ca,e).concat(t);return function(n){return r.map(function(t){return[t,n]})}}function mr(n){return n.source}function yr(n){return n.target}function Mr(n,t,e,r){var u=Math.cos(t),i=Math.sin(t),o=Math.cos(r),a=Math.sin(r),c=u*Math.cos(n),l=u*Math.sin(n),s=o*Math.cos(e),f=o*Math.sin(e),h=2*Math.asin(Math.sqrt(it(r-t)+u*o*it(e-n))),g=1/Math.sin(h),p=h?function(n){var t=Math.sin(n*=h)*g,e=Math.sin(h-n)*g,r=e*c+t*s,u=e*l+t*f,o=e*i+t*a;return[Math.atan2(u,r)*Pa,Math.atan2(o,Math.sqrt(r*r+u*u))*Pa]}:function(){return[n*Pa,t*Pa]};return p.distance=h,p}function xr(){function n(n,u){var i=Math.sin(u*=Da),o=Math.cos(u),a=ga((n*=Da)-t),c=Math.cos(a);Yc+=Math.atan2(Math.sqrt((a=o*Math.sin(a))*a+(a=r*i-e*o*c)*a),e*i+r*o*c),t=n,e=i,r=o}var t,e,r;Zc.point=function(u,i){t=u*Da,e=Math.sin(i*=Da),r=Math.cos(i),Zc.point=n},Zc.lineEnd=function(){Zc.point=Zc.lineEnd=b}}function br(n,t){function e(t,e){var r=Math.cos(t),u=Math.cos(e),i=n(r*u);return[i*u*Math.sin(t),i*Math.sin(e)]}return e.invert=function(n,e){var r=Math.sqrt(n*n+e*e),u=t(r),i=Math.sin(u),o=Math.cos(u);return[Math.atan2(n*i,r*o),Math.asin(r&&e*i/r)]},e}function _r(n,t){function e(n,t){o>0?-Ra+Ca>t&&(t=-Ra+Ca):t>Ra-Ca&&(t=Ra-Ca);var e=o/Math.pow(u(t),i);return[e*Math.sin(i*n),o-e*Math.cos(i*n)]}var r=Math.cos(n),u=function(n){return Math.tan(qa/4+n/2)},i=n===t?Math.sin(n):Math.log(r/Math.cos(t))/Math.log(u(t)/u(n)),o=r*Math.pow(u(n),i)/i;return i?(e.invert=function(n,t){var e=o-t,r=K(i)*Math.sqrt(n*n+e*e);return[Math.atan2(n,e)/i,2*Math.atan(Math.pow(o/r,1/i))-Ra]},e):Sr}function wr(n,t){function e(n,t){var e=i-t;return[e*Math.sin(u*n),i-e*Math.cos(u*n)]}var r=Math.cos(n),u=n===t?Math.sin(n):(r-Math.cos(t))/(t-n),i=r/u+n;return ga(u)<Ca?ar:(e.invert=function(n,t){var e=i-t;return[Math.atan2(n,e)/u,i-K(u)*Math.sqrt(n*n+e*e)]},e)}function Sr(n,t){return[n,Math.log(Math.tan(qa/4+t/2))]}function kr(n){var t,e=ur(n),r=e.scale,u=e.translate,i=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=u.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.clipExtent=function(n){var o=i.apply(e,arguments);if(o===e){if(t=null==n){var a=qa*r(),c=u();i([[c[0]-a,c[1]-a],[c[0]+a,c[1]+a]])}}else t&&(o=null);return o},e.clipExtent(null)}function Er(n,t){return[Math.log(Math.tan(qa/4+t/2)),-n]}function Ar(n){return n[0]}function Nr(n){return n[1]}function Cr(n){for(var t=n.length,e=[0,1],r=2,u=2;t>u;u++){for(;r>1&&Q(n[e[r-2]],n[e[r-1]],n[u])<=0;)--r;e[r++]=u}return e.slice(0,r)}function zr(n,t){return n[0]-t[0]||n[1]-t[1]}function qr(n,t,e){return(e[0]-t[0])*(n[1]-t[1])<(e[1]-t[1])*(n[0]-t[0])}function Lr(n,t,e,r){var u=n[0],i=e[0],o=t[0]-u,a=r[0]-i,c=n[1],l=e[1],s=t[1]-c,f=r[1]-l,h=(a*(c-l)-f*(u-i))/(f*o-a*s);return[u+h*o,c+h*s]}function Tr(n){var t=n[0],e=n[n.length-1];return!(t[0]-e[0]||t[1]-e[1])}function Rr(){tu(this),this.edge=this.site=this.circle=null}function Dr(n){var t=el.pop()||new Rr;return t.site=n,t}function Pr(n){Xr(n),Qc.remove(n),el.push(n),tu(n)}function Ur(n){var t=n.circle,e=t.x,r=t.cy,u={x:e,y:r},i=n.P,o=n.N,a=[n];Pr(n);for(var c=i;c.circle&&ga(e-c.circle.x)<Ca&&ga(r-c.circle.cy)<Ca;)i=c.P,a.unshift(c),Pr(c),c=i;a.unshift(c),Xr(c);for(var l=o;l.circle&&ga(e-l.circle.x)<Ca&&ga(r-l.circle.cy)<Ca;)o=l.N,a.push(l),Pr(l),l=o;a.push(l),Xr(l);var s,f=a.length;for(s=1;f>s;++s)l=a[s],c=a[s-1],Kr(l.edge,c.site,l.site,u);c=a[0],l=a[f-1],l.edge=Jr(c.site,l.site,null,u),Vr(c),Vr(l)}function jr(n){for(var t,e,r,u,i=n.x,o=n.y,a=Qc._;a;)if(r=Fr(a,o)-i,r>Ca)a=a.L;else{if(u=i-Hr(a,o),!(u>Ca)){r>-Ca?(t=a.P,e=a):u>-Ca?(t=a,e=a.N):t=e=a;break}if(!a.R){t=a;break}a=a.R}var c=Dr(n);if(Qc.insert(t,c),t||e){if(t===e)return Xr(t),e=Dr(t.site),Qc.insert(c,e),c.edge=e.edge=Jr(t.site,c.site),Vr(t),void Vr(e);if(!e)return void(c.edge=Jr(t.site,c.site));Xr(t),Xr(e);var l=t.site,s=l.x,f=l.y,h=n.x-s,g=n.y-f,p=e.site,v=p.x-s,d=p.y-f,m=2*(h*d-g*v),y=h*h+g*g,M=v*v+d*d,x={x:(d*y-g*M)/m+s,y:(h*M-v*y)/m+f};Kr(e.edge,l,p,x),c.edge=Jr(l,n,null,x),e.edge=Jr(n,p,null,x),Vr(t),Vr(e)}}function Fr(n,t){var e=n.site,r=e.x,u=e.y,i=u-t;if(!i)return r;var o=n.P;if(!o)return-1/0;e=o.site;var a=e.x,c=e.y,l=c-t;if(!l)return a;var s=a-r,f=1/i-1/l,h=s/l;return f?(-h+Math.sqrt(h*h-2*f*(s*s/(-2*l)-c+l/2+u-i/2)))/f+r:(r+a)/2}function Hr(n,t){var e=n.N;if(e)return Fr(e,t);var r=n.site;return r.y===t?r.x:1/0}function Or(n){this.site=n,this.edges=[]}function Ir(n){for(var t,e,r,u,i,o,a,c,l,s,f=n[0][0],h=n[1][0],g=n[0][1],p=n[1][1],v=Kc,d=v.length;d--;)if(i=v[d],i&&i.prepare())for(a=i.edges,c=a.length,o=0;c>o;)s=a[o].end(),r=s.x,u=s.y,l=a[++o%c].start(),t=l.x,e=l.y,(ga(r-t)>Ca||ga(u-e)>Ca)&&(a.splice(o,0,new Qr(Gr(i.site,s,ga(r-f)<Ca&&p-u>Ca?{x:f,y:ga(t-f)<Ca?e:p}:ga(u-p)<Ca&&h-r>Ca?{x:ga(e-p)<Ca?t:h,y:p}:ga(r-h)<Ca&&u-g>Ca?{x:h,y:ga(t-h)<Ca?e:g}:ga(u-g)<Ca&&r-f>Ca?{x:ga(e-g)<Ca?t:f,y:g}:null),i.site,null)),++c)}function Yr(n,t){return t.angle-n.angle}function Zr(){tu(this),this.x=this.y=this.arc=this.site=this.cy=null}function Vr(n){var t=n.P,e=n.N;if(t&&e){var r=t.site,u=n.site,i=e.site;if(r!==i){var o=u.x,a=u.y,c=r.x-o,l=r.y-a,s=i.x-o,f=i.y-a,h=2*(c*f-l*s);if(!(h>=-za)){var g=c*c+l*l,p=s*s+f*f,v=(f*g-l*p)/h,d=(c*p-s*g)/h,f=d+a,m=rl.pop()||new Zr;m.arc=n,m.site=u,m.x=v+o,m.y=f+Math.sqrt(v*v+d*d),m.cy=f,n.circle=m;for(var y=null,M=tl._;M;)if(m.y<M.y||m.y===M.y&&m.x<=M.x){if(!M.L){y=M.P;break}M=M.L}else{if(!M.R){y=M;break}M=M.R}tl.insert(y,m),y||(nl=m)}}}}function Xr(n){var t=n.circle;t&&(t.P||(nl=t.N),tl.remove(t),rl.push(t),tu(t),n.circle=null)}function $r(n){for(var t,e=Gc,r=Oe(n[0][0],n[0][1],n[1][0],n[1][1]),u=e.length;u--;)t=e[u],(!Br(t,n)||!r(t)||ga(t.a.x-t.b.x)<Ca&&ga(t.a.y-t.b.y)<Ca)&&(t.a=t.b=null,e.splice(u,1))}function Br(n,t){var e=n.b;if(e)return!0;var r,u,i=n.a,o=t[0][0],a=t[1][0],c=t[0][1],l=t[1][1],s=n.l,f=n.r,h=s.x,g=s.y,p=f.x,v=f.y,d=(h+p)/2,m=(g+v)/2;if(v===g){if(o>d||d>=a)return;if(h>p){if(i){if(i.y>=l)return}else i={x:d,y:c};e={x:d,y:l}}else{if(i){if(i.y<c)return}else i={x:d,y:l};e={x:d,y:c}}}else if(r=(h-p)/(v-g),u=m-r*d,-1>r||r>1)if(h>p){if(i){if(i.y>=l)return}else i={x:(c-u)/r,y:c};e={x:(l-u)/r,y:l}}else{if(i){if(i.y<c)return}else i={x:(l-u)/r,y:l};e={x:(c-u)/r,y:c}}else if(v>g){if(i){if(i.x>=a)return}else i={x:o,y:r*o+u};e={x:a,y:r*a+u}}else{if(i){if(i.x<o)return}else i={x:a,y:r*a+u};e={x:o,y:r*o+u}}return n.a=i,n.b=e,!0}function Wr(n,t){this.l=n,this.r=t,this.a=this.b=null}function Jr(n,t,e,r){var u=new Wr(n,t);return Gc.push(u),e&&Kr(u,n,t,e),r&&Kr(u,t,n,r),Kc[n.i].edges.push(new Qr(u,n,t)),Kc[t.i].edges.push(new Qr(u,t,n)),u}function Gr(n,t,e){var r=new Wr(n,null);return r.a=t,r.b=e,Gc.push(r),r}function Kr(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 Qr(n,t,e){var r=n.a,u=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(u.x-r.x,r.y-u.y):Math.atan2(r.x-u.x,u.y-r.y)}function nu(){this._=null}function tu(n){n.U=n.C=n.L=n.R=n.P=n.N=null}function eu(n,t){var e=t,r=t.R,u=e.U;u?u.L===e?u.L=r:u.R=r:n._=r,r.U=u,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function ru(n,t){var e=t,r=t.L,u=e.U;u?u.L===e?u.L=r:u.R=r:n._=r,r.U=u,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function uu(n){for(;n.L;)n=n.L;return n}function iu(n,t){var e,r,u,i=n.sort(ou).pop();for(Gc=[],Kc=new Array(n.length),Qc=new nu,tl=new nu;;)if(u=nl,i&&(!u||i.y<u.y||i.y===u.y&&i.x<u.x))(i.x!==e||i.y!==r)&&(Kc[i.i]=new Or(i),jr(i),e=i.x,r=i.y),i=n.pop();else{if(!u)break;Ur(u.arc)}t&&($r(t),Ir(t));var o={cells:Kc,edges:Gc};return Qc=tl=Gc=Kc=null,o}function ou(n,t){return t.y-n.y||t.x-n.x}function au(n,t,e){return(n.x-e.x)*(t.y-n.y)-(n.x-t.x)*(e.y-n.y)}function cu(n){return n.x}function lu(n){return n.y}function su(){return{leaf:!0,nodes:[],point:null,x:null,y:null}}function fu(n,t,e,r,u,i){if(!n(t,e,r,u,i)){var o=.5*(e+u),a=.5*(r+i),c=t.nodes;c[0]&&fu(n,c[0],e,r,o,a),c[1]&&fu(n,c[1],o,r,u,a),c[2]&&fu(n,c[2],e,a,o,i),c[3]&&fu(n,c[3],o,a,u,i)}}function hu(n,t,e,r,u,i,o){var a,c=1/0;return function l(n,s,f,h,g){if(!(s>i||f>o||r>h||u>g)){if(p=n.point){var p,v=t-n.x,d=e-n.y,m=v*v+d*d;if(c>m){var y=Math.sqrt(c=m);r=t-y,u=e-y,i=t+y,o=e+y,a=p}}for(var M=n.nodes,x=.5*(s+h),b=.5*(f+g),_=t>=x,w=e>=b,S=w<<1|_,k=S+4;k>S;++S)if(n=M[3&S])switch(3&S){case 0:l(n,s,f,x,b);break;case 1:l(n,x,f,h,b);break;case 2:l(n,s,b,x,g);break;case 3:l(n,x,b,h,g)}}}(n,r,u,i,o),a}function gu(n,t){n=ta.rgb(n),t=ta.rgb(t);var e=n.r,r=n.g,u=n.b,i=t.r-e,o=t.g-r,a=t.b-u;return function(n){return"#"+xt(Math.round(e+i*n))+xt(Math.round(r+o*n))+xt(Math.round(u+a*n))}}function pu(n,t){var e,r={},u={};for(e in n)e in t?r[e]=mu(n[e],t[e]):u[e]=n[e];for(e in t)e in n||(u[e]=t[e]);return function(n){for(e in r)u[e]=r[e](n);return u}}function vu(n,t){return n=+n,t=+t,function(e){return n*(1-e)+t*e}}function du(n,t){var e,r,u,i=il.lastIndex=ol.lastIndex=0,o=-1,a=[],c=[];for(n+="",t+="";(e=il.exec(n))&&(r=ol.exec(t));)(u=r.index)>i&&(u=t.slice(i,u),a[o]?a[o]+=u:a[++o]=u),(e=e[0])===(r=r[0])?a[o]?a[o]+=r:a[++o]=r:(a[++o]=null,c.push({i:o,x:vu(e,r)})),i=ol.lastIndex;return i<t.length&&(u=t.slice(i),a[o]?a[o]+=u:a[++o]=u),a.length<2?c[0]?(t=c[0].x,function(n){return t(n)+""}):function(){return t}:(t=c.length,function(n){for(var e,r=0;t>r;++r)a[(e=c[r]).i]=e.x(n);return a.join("")})}function mu(n,t){for(var e,r=ta.interpolators.length;--r>=0&&!(e=ta.interpolators[r](n,t)););return e}function yu(n,t){var e,r=[],u=[],i=n.length,o=t.length,a=Math.min(n.length,t.length);for(e=0;a>e;++e)r.push(mu(n[e],t[e]));for(;i>e;++e)u[e]=n[e];for(;o>e;++e)u[e]=t[e];return function(n){for(e=0;a>e;++e)u[e]=r[e](n);return u}}function Mu(n){return function(t){return 0>=t?0:t>=1?1:n(t)}}function xu(n){return function(t){return 1-n(1-t)}}function bu(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}function _u(n){return n*n}function wu(n){return n*n*n}function Su(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 ku(n){return function(t){return Math.pow(t,n)}}function Eu(n){return 1-Math.cos(n*Ra)}function Au(n){return Math.pow(2,10*(n-1))}function Nu(n){return 1-Math.sqrt(1-n*n)}function Cu(n,t){var e;return arguments.length<2&&(t=.45),arguments.length?e=t/La*Math.asin(1/n):(n=1,e=t/4),function(r){return 1+n*Math.pow(2,-10*r)*Math.sin((r-e)*La/t)}}function zu(n){return n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}function qu(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 Lu(n,t){n=ta.hcl(n),t=ta.hcl(t);var e=n.h,r=n.c,u=n.l,i=t.h-e,o=t.c-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.c:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return st(e+i*n,r+o*n,u+a*n)+""}}function Tu(n,t){n=ta.hsl(n),t=ta.hsl(t);var e=n.h,r=n.s,u=n.l,i=t.h-e,o=t.s-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.s:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return ct(e+i*n,r+o*n,u+a*n)+""}}function Ru(n,t){n=ta.lab(n),t=ta.lab(t);var e=n.l,r=n.a,u=n.b,i=t.l-e,o=t.a-r,a=t.b-u;return function(n){return ht(e+i*n,r+o*n,u+a*n)+""}}function Du(n,t){return t-=n,function(e){return Math.round(n+t*e)}}function Pu(n){var t=[n.a,n.b],e=[n.c,n.d],r=ju(t),u=Uu(t,e),i=ju(Fu(e,t,-u))||0;t[0]*e[1]<e[0]*t[1]&&(t[0]*=-1,t[1]*=-1,r*=-1,u*=-1),this.rotate=(r?Math.atan2(t[1],t[0]):Math.atan2(-e[0],e[1]))*Pa,this.translate=[n.e,n.f],this.scale=[r,i],this.skew=i?Math.atan2(u,i)*Pa:0}function Uu(n,t){return n[0]*t[0]+n[1]*t[1]}function ju(n){var t=Math.sqrt(Uu(n,n));return t&&(n[0]/=t,n[1]/=t),t}function Fu(n,t,e){return n[0]+=e*t[0],n[1]+=e*t[1],n}function Hu(n,t){var e,r=[],u=[],i=ta.transform(n),o=ta.transform(t),a=i.translate,c=o.translate,l=i.rotate,s=o.rotate,f=i.skew,h=o.skew,g=i.scale,p=o.scale;return a[0]!=c[0]||a[1]!=c[1]?(r.push("translate(",null,",",null,")"),u.push({i:1,x:vu(a[0],c[0])},{i:3,x:vu(a[1],c[1])})):r.push(c[0]||c[1]?"translate("+c+")":""),l!=s?(l-s>180?s+=360:s-l>180&&(l+=360),u.push({i:r.push(r.pop()+"rotate(",null,")")-2,x:vu(l,s)})):s&&r.push(r.pop()+"rotate("+s+")"),f!=h?u.push({i:r.push(r.pop()+"skewX(",null,")")-2,x:vu(f,h)}):h&&r.push(r.pop()+"skewX("+h+")"),g[0]!=p[0]||g[1]!=p[1]?(e=r.push(r.pop()+"scale(",null,",",null,")"),u.push({i:e-4,x:vu(g[0],p[0])},{i:e-2,x:vu(g[1],p[1])})):(1!=p[0]||1!=p[1])&&r.push(r.pop()+"scale("+p+")"),e=u.length,function(n){for(var t,i=-1;++i<e;)r[(t=u[i]).i]=t.x(n);return r.join("")}}function Ou(n,t){return t=(t-=n=+n)||1/t,function(e){return(e-n)/t}}function Iu(n,t){return t=(t-=n=+n)||1/t,function(e){return Math.max(0,Math.min(1,(e-n)/t))}}function Yu(n){for(var t=n.source,e=n.target,r=Vu(t,e),u=[t];t!==r;)t=t.parent,u.push(t);for(var i=u.length;e!==r;)u.splice(i,0,e),e=e.parent;return u}function Zu(n){for(var t=[],e=n.parent;null!=e;)t.push(n),n=e,e=e.parent;return t.push(n),t}function Vu(n,t){if(n===t)return n;for(var e=Zu(n),r=Zu(t),u=e.pop(),i=r.pop(),o=null;u===i;)o=u,u=e.pop(),i=r.pop();return o}function Xu(n){n.fixed|=2}function $u(n){n.fixed&=-7}function Bu(n){n.fixed|=4,n.px=n.x,n.py=n.y}function Wu(n){n.fixed&=-5}function Ju(n,t,e){var r=0,u=0;if(n.charge=0,!n.leaf)for(var i,o=n.nodes,a=o.length,c=-1;++c<a;)i=o[c],null!=i&&(Ju(i,t,e),n.charge+=i.charge,r+=i.charge*i.cx,u+=i.charge*i.cy);if(n.point){n.leaf||(n.point.x+=Math.random()-.5,n.point.y+=Math.random()-.5);var l=t*e[n.point.index];n.charge+=n.pointCharge=l,r+=l*n.point.x,u+=l*n.point.y}n.cx=r/n.charge,n.cy=u/n.charge}function Gu(n,t){return ta.rebind(n,t,"sort","children","value"),n.nodes=n,n.links=ri,n}function Ku(n,t){for(var e=[n];null!=(n=e.pop());)if(t(n),(u=n.children)&&(r=u.length))for(var r,u;--r>=0;)e.push(u[r])}function Qu(n,t){for(var e=[n],r=[];null!=(n=e.pop());)if(r.push(n),(i=n.children)&&(u=i.length))for(var u,i,o=-1;++o<u;)e.push(i[o]);for(;null!=(n=r.pop());)t(n)}function ni(n){return n.children}function ti(n){return n.value}function ei(n,t){return t.value-n.value}function ri(n){return ta.merge(n.map(function(n){return(n.children||[]).map(function(t){return{source:n,target:t}})}))}function ui(n){return n.x}function ii(n){return n.y}function oi(n,t,e){n.y0=t,n.y=e}function ai(n){return ta.range(n.length)}function ci(n){for(var t=-1,e=n[0].length,r=[];++t<e;)r[t]=0;return r}function li(n){for(var t,e=1,r=0,u=n[0][1],i=n.length;i>e;++e)(t=n[e][1])>u&&(r=e,u=t);return r}function si(n){return n.reduce(fi,0)}function fi(n,t){return n+t[1]}function hi(n,t){return gi(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}function gi(n,t){for(var e=-1,r=+n[0],u=(n[1]-r)/t,i=[];++e<=t;)i[e]=u*e+r;return i}function pi(n){return[ta.min(n),ta.max(n)]}function vi(n,t){return n.value-t.value}function di(n,t){var e=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pack_next=e,e._pack_prev=t}function mi(n,t){n._pack_next=t,t._pack_prev=n}function yi(n,t){var e=t.x-n.x,r=t.y-n.y,u=n.r+t.r;return.999*u*u>e*e+r*r}function Mi(n){function t(n){s=Math.min(n.x-n.r,s),f=Math.max(n.x+n.r,f),h=Math.min(n.y-n.r,h),g=Math.max(n.y+n.r,g)}if((e=n.children)&&(l=e.length)){var e,r,u,i,o,a,c,l,s=1/0,f=-1/0,h=1/0,g=-1/0;if(e.forEach(xi),r=e[0],r.x=-r.r,r.y=0,t(r),l>1&&(u=e[1],u.x=u.r,u.y=0,t(u),l>2))for(i=e[2],wi(r,u,i),t(i),di(r,i),r._pack_prev=i,di(i,u),u=r._pack_next,o=3;l>o;o++){wi(r,u,i=e[o]);var p=0,v=1,d=1;for(a=u._pack_next;a!==u;a=a._pack_next,v++)if(yi(a,i)){p=1;break}if(1==p)for(c=r._pack_prev;c!==a._pack_prev&&!yi(c,i);c=c._pack_prev,d++);p?(d>v||v==d&&u.r<r.r?mi(r,u=a):mi(r=c,u),o--):(di(r,i),u=i,t(i))}var m=(s+f)/2,y=(h+g)/2,M=0;for(o=0;l>o;o++)i=e[o],i.x-=m,i.y-=y,M=Math.max(M,i.r+Math.sqrt(i.x*i.x+i.y*i.y));n.r=M,e.forEach(bi)}}function xi(n){n._pack_next=n._pack_prev=n}function bi(n){delete n._pack_next,delete n._pack_prev}function _i(n,t,e,r){var u=n.children;if(n.x=t+=r*n.x,n.y=e+=r*n.y,n.r*=r,u)for(var i=-1,o=u.length;++i<o;)_i(u[i],t,e,r)}function wi(n,t,e){var r=n.r+e.r,u=t.x-n.x,i=t.y-n.y;if(r&&(u||i)){var o=t.r+e.r,a=u*u+i*i;o*=o,r*=r;var c=.5+(r-o)/(2*a),l=Math.sqrt(Math.max(0,2*o*(r+a)-(r-=a)*r-o*o))/(2*a);e.x=n.x+c*u+l*i,e.y=n.y+c*i-l*u}else e.x=n.x+r,e.y=n.y}function Si(n,t){return n.parent==t.parent?1:2}function ki(n){var t=n.children;return t.length?t[0]:n.t}function Ei(n){var t,e=n.children;return(t=e.length)?e[t-1]:n.t}function Ai(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 Ni(n){for(var t,e=0,r=0,u=n.children,i=u.length;--i>=0;)t=u[i],t.z+=e,t.m+=e,e+=t.s+(r+=t.c)}function Ci(n,t,e){return n.a.parent===t.parent?n.a:e}function zi(n){return 1+ta.max(n,function(n){return n.y})}function qi(n){return n.reduce(function(n,t){return n+t.x},0)/n.length}function Li(n){var t=n.children;return t&&t.length?Li(t[0]):n}function Ti(n){var t,e=n.children;return e&&(t=e.length)?Ti(e[t-1]):n}function Ri(n){return{x:n.x,y:n.y,dx:n.dx,dy:n.dy}}function Di(n,t){var e=n.x+t[3],r=n.y+t[0],u=n.dx-t[1]-t[3],i=n.dy-t[0]-t[2];return 0>u&&(e+=u/2,u=0),0>i&&(r+=i/2,i=0),{x:e,y:r,dx:u,dy:i}}function Pi(n){var t=n[0],e=n[n.length-1];return e>t?[t,e]:[e,t]}function Ui(n){return n.rangeExtent?n.rangeExtent():Pi(n.range())}function ji(n,t,e,r){var u=e(n[0],n[1]),i=r(t[0],t[1]);return function(n){return i(u(n))}}function Fi(n,t){var e,r=0,u=n.length-1,i=n[r],o=n[u];return i>o&&(e=r,r=u,u=e,e=i,i=o,o=e),n[r]=t.floor(i),n[u]=t.ceil(o),n}function Hi(n){return n?{floor:function(t){return Math.floor(t/n)*n},ceil:function(t){return Math.ceil(t/n)*n}}:ml}function Oi(n,t,e,r){var u=[],i=[],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;)u.push(e(n[o-1],n[o])),i.push(r(t[o-1],t[o]));return function(t){var e=ta.bisect(n,t,1,a)-1;return i[e](u[e](t))}}function Ii(n,t,e,r){function u(){var u=Math.min(n.length,t.length)>2?Oi:ji,c=r?Iu:Ou;return o=u(n,t,c,e),a=u(t,n,c,mu),i}function i(n){return o(n)}var o,a;return i.invert=function(n){return a(n)},i.domain=function(t){return arguments.length?(n=t.map(Number),u()):n},i.range=function(n){return arguments.length?(t=n,u()):t},i.rangeRound=function(n){return i.range(n).interpolate(Du)},i.clamp=function(n){return arguments.length?(r=n,u()):r},i.interpolate=function(n){return arguments.length?(e=n,u()):e},i.ticks=function(t){return Xi(n,t)},i.tickFormat=function(t,e){return $i(n,t,e)},i.nice=function(t){return Zi(n,t),u()},i.copy=function(){return Ii(n,t,e,r)},u()}function Yi(n,t){return ta.rebind(n,t,"range","rangeRound","interpolate","clamp")}function Zi(n,t){return Fi(n,Hi(Vi(n,t)[2]))}function Vi(n,t){null==t&&(t=10);var e=Pi(n),r=e[1]-e[0],u=Math.pow(10,Math.floor(Math.log(r/t)/Math.LN10)),i=t/r*u;return.15>=i?u*=10:.35>=i?u*=5:.75>=i&&(u*=2),e[0]=Math.ceil(e[0]/u)*u,e[1]=Math.floor(e[1]/u)*u+.5*u,e[2]=u,e}function Xi(n,t){return ta.range.apply(ta,Vi(n,t))}function $i(n,t,e){var r=Vi(n,t);if(e){var u=ic.exec(e);if(u.shift(),"s"===u[8]){var i=ta.formatPrefix(Math.max(ga(r[0]),ga(r[1])));return u[7]||(u[7]="."+Bi(i.scale(r[2]))),u[8]="f",e=ta.format(u.join("")),function(n){return e(i.scale(n))+i.symbol}}u[7]||(u[7]="."+Wi(u[8],r)),e=u.join("")}else e=",."+Bi(r[2])+"f";return ta.format(e)}function Bi(n){return-Math.floor(Math.log(n)/Math.LN10+.01)}function Wi(n,t){var e=Bi(t[2]);return n in yl?Math.abs(e-Bi(Math.max(ga(t[0]),ga(t[1]))))+ +("e"!==n):e-2*("%"===n)}function Ji(n,t,e,r){function u(n){return(e?Math.log(0>n?0:n):-Math.log(n>0?0:-n))/Math.log(t)}function i(n){return e?Math.pow(t,n):-Math.pow(t,-n)}function o(t){return n(u(t))}return o.invert=function(t){return i(n.invert(t))},o.domain=function(t){return arguments.length?(e=t[0]>=0,n.domain((r=t.map(Number)).map(u)),o):r},o.base=function(e){return arguments.length?(t=+e,n.domain(r.map(u)),o):t},o.nice=function(){var t=Fi(r.map(u),e?Math:xl);return n.domain(t),r=t.map(i),o},o.ticks=function(){var n=Pi(r),o=[],a=n[0],c=n[1],l=Math.floor(u(a)),s=Math.ceil(u(c)),f=t%1?2:t;if(isFinite(s-l)){if(e){for(;s>l;l++)for(var h=1;f>h;h++)o.push(i(l)*h);o.push(i(l))}else for(o.push(i(l));l++<s;)for(var h=f-1;h>0;h--)o.push(i(l)*h);for(l=0;o[l]<a;l++);for(s=o.length;o[s-1]>c;s--);o=o.slice(l,s)}return o},o.tickFormat=function(n,t){if(!arguments.length)return Ml;arguments.length<2?t=Ml:"function"!=typeof t&&(t=ta.format(t));var r,a=Math.max(.1,n/o.ticks().length),c=e?(r=1e-12,Math.ceil):(r=-1e-12,Math.floor);return function(n){return n/i(c(u(n)+r))<=a?t(n):""}},o.copy=function(){return Ji(n.copy(),t,e,r)},Yi(o,n)}function Gi(n,t,e){function r(t){return n(u(t))}var u=Ki(t),i=Ki(1/t);return r.invert=function(t){return i(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain((e=t.map(Number)).map(u)),r):e},r.ticks=function(n){return Xi(e,n)},r.tickFormat=function(n,t){return $i(e,n,t)},r.nice=function(n){return r.domain(Zi(e,n))},r.exponent=function(o){return arguments.length?(u=Ki(t=o),i=Ki(1/t),n.domain(e.map(u)),r):t},r.copy=function(){return Gi(n.copy(),t,e)},Yi(r,n)}function Ki(n){return function(t){return 0>t?-Math.pow(-t,n):Math.pow(t,n)}}function Qi(n,t){function e(e){return i[((u.get(e)||("range"===t.t?u.set(e,n.push(e)):0/0))-1)%i.length]}function r(t,e){return ta.range(n.length).map(function(n){return t+e*n})}var u,i,o;return e.domain=function(r){if(!arguments.length)return n;n=[],u=new l;for(var i,o=-1,a=r.length;++o<a;)u.has(i=r[o])||u.set(i,n.push(i));return e[t.t].apply(e,t.a)},e.range=function(n){return arguments.length?(i=n,o=0,t={t:"range",a:arguments},e):i},e.rangePoints=function(u,a){arguments.length<2&&(a=0);var c=u[0],l=u[1],s=n.length<2?(c=(c+l)/2,0):(l-c)/(n.length-1+a);return i=r(c+s*a/2,s),o=0,t={t:"rangePoints",a:arguments},e},e.rangeRoundPoints=function(u,a){arguments.length<2&&(a=0);var c=u[0],l=u[1],s=n.length<2?(c=l=Math.round((c+l)/2),0):(l-c)/(n.length-1+a)|0;return i=r(c+Math.round(s*a/2+(l-c-(n.length-1+a)*s)/2),s),o=0,t={t:"rangeRoundPoints",a:arguments},e},e.rangeBands=function(u,a,c){arguments.length<2&&(a=0),arguments.length<3&&(c=a);var l=u[1]<u[0],s=u[l-0],f=u[1-l],h=(f-s)/(n.length-a+2*c);return i=r(s+h*c,h),l&&i.reverse(),o=h*(1-a),t={t:"rangeBands",a:arguments},e},e.rangeRoundBands=function(u,a,c){arguments.length<2&&(a=0),arguments.length<3&&(c=a);var l=u[1]<u[0],s=u[l-0],f=u[1-l],h=Math.floor((f-s)/(n.length-a+2*c));return i=r(s+Math.round((f-s-(n.length-a)*h)/2),h),l&&i.reverse(),o=Math.round(h*(1-a)),t={t:"rangeRoundBands",a:arguments},e},e.rangeBand=function(){return o},e.rangeExtent=function(){return Pi(t.a[0])},e.copy=function(){return Qi(n,t)},e.domain(n)}function no(n,t){function i(){var e=0,r=t.length;for(a=[];++e<r;)a[e-1]=ta.quantile(n,e/r);return o}function o(n){return isNaN(n=+n)?void 0:t[ta.bisect(a,n)]}var a;return o.domain=function(t){return arguments.length?(n=t.map(r).filter(u).sort(e),i()):n},o.range=function(n){return arguments.length?(t=n,i()):t},o.quantiles=function(){return a},o.invertExtent=function(e){return e=t.indexOf(e),0>e?[0/0,0/0]:[e>0?a[e-1]:n[0],e<a.length?a[e]:n[n.length-1]]},o.copy=function(){return no(n,t)},i()}function to(n,t,e){function r(t){return e[Math.max(0,Math.min(o,Math.floor(i*(t-n))))]}function u(){return i=e.length/(t-n),o=e.length-1,r}var i,o;return r.domain=function(e){return arguments.length?(n=+e[0],t=+e[e.length-1],u()):[n,t]},r.range=function(n){return arguments.length?(e=n,u()):e},r.invertExtent=function(t){return t=e.indexOf(t),t=0>t?0/0:t/i+n,[t,t+1/i]},r.copy=function(){return to(n,t,e)},u()}function eo(n,t){function e(e){return e>=e?t[ta.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 eo(n,t)},e}function ro(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 Xi(n,t)},t.tickFormat=function(t,e){return $i(n,t,e)},t.copy=function(){return ro(n)},t}function uo(){return 0}function io(n){return n.innerRadius}function oo(n){return n.outerRadius}function ao(n){return n.startAngle}function co(n){return n.endAngle}function lo(n){return n&&n.padAngle}function so(n,t,e,r){return(n-e)*t-(t-r)*n>0?0:1}function fo(n,t,e,r,u){var i=n[0]-t[0],o=n[1]-t[1],a=(u?r:-r)/Math.sqrt(i*i+o*o),c=a*o,l=-a*i,s=n[0]+c,f=n[1]+l,h=t[0]+c,g=t[1]+l,p=(s+h)/2,v=(f+g)/2,d=h-s,m=g-f,y=d*d+m*m,M=e-r,x=s*g-h*f,b=(0>m?-1:1)*Math.sqrt(M*M*y-x*x),_=(x*m-d*b)/y,w=(-x*d-m*b)/y,S=(x*m+d*b)/y,k=(-x*d+m*b)/y,E=_-p,A=w-v,N=S-p,C=k-v;return E*E+A*A>N*N+C*C&&(_=S,w=k),[[_-c,w-l],[_*e/M,w*e/M]]}function ho(n){function t(t){function o(){l.push("M",i(n(s),a))}for(var c,l=[],s=[],f=-1,h=t.length,g=Et(e),p=Et(r);++f<h;)u.call(this,c=t[f],f)?s.push([+g.call(this,c,f),+p.call(this,c,f)]):s.length&&(o(),s=[]);return s.length&&o(),l.length?l.join(""):null}var e=Ar,r=Nr,u=Ne,i=go,o=i.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?(u=n,t):u},t.interpolate=function(n){return arguments.length?(o="function"==typeof n?i=n:(i=El.get(n)||go).key,t):o},t.tension=function(n){return arguments.length?(a=n,t):a},t}function go(n){return n.join("L")}function po(n){return go(n)+"Z"}function vo(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("H",(r[0]+(r=n[t])[0])/2,"V",r[1]);return e>1&&u.push("H",r[0]),u.join("")}function mo(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("V",(r=n[t])[1],"H",r[0]);return u.join("")}function yo(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("H",(r=n[t])[0],"V",r[1]);return u.join("")}function Mo(n,t){return n.length<4?go(n):n[1]+_o(n.slice(1,-1),wo(n,t))}function xo(n,t){return n.length<3?go(n):n[0]+_o((n.push(n[0]),n),wo([n[n.length-2]].concat(n,[n[1]]),t))}function bo(n,t){return n.length<3?go(n):n[0]+_o(n,wo(n,t))}function _o(n,t){if(t.length<1||n.length!=t.length&&n.length!=t.length+2)return go(n);var e=n.length!=t.length,r="",u=n[0],i=n[1],o=t[0],a=o,c=1;if(e&&(r+="Q"+(i[0]-2*o[0]/3)+","+(i[1]-2*o[1]/3)+","+i[0]+","+i[1],u=n[1],c=2),t.length>1){a=t[1],i=n[c],c++,r+="C"+(u[0]+o[0])+","+(u[1]+o[1])+","+(i[0]-a[0])+","+(i[1]-a[1])+","+i[0]+","+i[1];for(var l=2;l<t.length;l++,c++)i=n[c],a=t[l],r+="S"+(i[0]-a[0])+","+(i[1]-a[1])+","+i[0]+","+i[1]}if(e){var s=n[c];r+="Q"+(i[0]+2*a[0]/3)+","+(i[1]+2*a[1]/3)+","+s[0]+","+s[1]}return r}function wo(n,t){for(var e,r=[],u=(1-t)/2,i=n[0],o=n[1],a=1,c=n.length;++a<c;)e=i,i=o,o=n[a],r.push([u*(o[0]-e[0]),u*(o[1]-e[1])]);return r}function So(n){if(n.length<3)return go(n);var t=1,e=n.length,r=n[0],u=r[0],i=r[1],o=[u,u,u,(r=n[1])[0]],a=[i,i,i,r[1]],c=[u,",",i,"L",No(Cl,o),",",No(Cl,a)];for(n.push(n[e-1]);++t<=e;)r=n[t],o.shift(),o.push(r[0]),a.shift(),a.push(r[1]),Co(c,o,a);return n.pop(),c.push("L",r),c.join("")}function ko(n){if(n.length<4)return go(n);for(var t,e=[],r=-1,u=n.length,i=[0],o=[0];++r<3;)t=n[r],i.push(t[0]),o.push(t[1]);for(e.push(No(Cl,i)+","+No(Cl,o)),--r;++r<u;)t=n[r],i.shift(),i.push(t[0]),o.shift(),o.push(t[1]),Co(e,i,o);return e.join("")}function Eo(n){for(var t,e,r=-1,u=n.length,i=u+4,o=[],a=[];++r<4;)e=n[r%u],o.push(e[0]),a.push(e[1]);for(t=[No(Cl,o),",",No(Cl,a)],--r;++r<i;)e=n[r%u],o.shift(),o.push(e[0]),a.shift(),a.push(e[1]),Co(t,o,a);return t.join("")}function Ao(n,t){var e=n.length-1;if(e)for(var r,u,i=n[0][0],o=n[0][1],a=n[e][0]-i,c=n[e][1]-o,l=-1;++l<=e;)r=n[l],u=l/e,r[0]=t*r[0]+(1-t)*(i+u*a),r[1]=t*r[1]+(1-t)*(o+u*c);return So(n)}function No(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]+n[3]*t[3]}function Co(n,t,e){n.push("C",No(Al,t),",",No(Al,e),",",No(Nl,t),",",No(Nl,e),",",No(Cl,t),",",No(Cl,e))}function zo(n,t){return(t[1]-n[1])/(t[0]-n[0])}function qo(n){for(var t=0,e=n.length-1,r=[],u=n[0],i=n[1],o=r[0]=zo(u,i);++t<e;)r[t]=(o+(o=zo(u=i,i=n[t+1])))/2;return r[t]=o,r}function Lo(n){for(var t,e,r,u,i=[],o=qo(n),a=-1,c=n.length-1;++a<c;)t=zo(n[a],n[a+1]),ga(t)<Ca?o[a]=o[a+1]=0:(e=o[a]/t,r=o[a+1]/t,u=e*e+r*r,u>9&&(u=3*t/Math.sqrt(u),o[a]=u*e,o[a+1]=u*r));for(a=-1;++a<=c;)u=(n[Math.min(c,a+1)][0]-n[Math.max(0,a-1)][0])/(6*(1+o[a]*o[a])),i.push([u||0,o[a]*u||0]);return i}function To(n){return n.length<3?go(n):n[0]+_o(n,Lo(n))}function Ro(n){for(var t,e,r,u=-1,i=n.length;++u<i;)t=n[u],e=t[0],r=t[1]-Ra,t[0]=e*Math.cos(r),t[1]=e*Math.sin(r);return n}function Do(n){function t(t){function c(){v.push("M",a(n(m),f),s,l(n(d.reverse()),f),"Z")}for(var h,g,p,v=[],d=[],m=[],y=-1,M=t.length,x=Et(e),b=Et(u),_=e===r?function(){return g}:Et(r),w=u===i?function(){return p}:Et(i);++y<M;)o.call(this,h=t[y],y)?(d.push([g=+x.call(this,h,y),p=+b.call(this,h,y)]),m.push([+_.call(this,h,y),+w.call(this,h,y)])):d.length&&(c(),d=[],m=[]);return d.length&&c(),v.length?v.join(""):null}var e=Ar,r=Ar,u=0,i=Nr,o=Ne,a=go,c=a.key,l=a,s="L",f=.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?(u=i=n,t):i},t.y0=function(n){return arguments.length?(u=n,t):u},t.y1=function(n){return arguments.length?(i=n,t):i},t.defined=function(n){return arguments.length?(o=n,t):o},t.interpolate=function(n){return arguments.length?(c="function"==typeof n?a=n:(a=El.get(n)||go).key,l=a.reverse||a,s=a.closed?"M":"L",t):c},t.tension=function(n){return arguments.length?(f=n,t):f},t}function Po(n){return n.radius}function Uo(n){return[n.x,n.y]}function jo(n){return function(){var t=n.apply(this,arguments),e=t[0],r=t[1]-Ra;return[e*Math.cos(r),e*Math.sin(r)]}}function Fo(){return 64}function Ho(){return"circle"}function Oo(n){var t=Math.sqrt(n/qa);return"M0,"+t+"A"+t+","+t+" 0 1,1 0,"+-t+"A"+t+","+t+" 0 1,1 0,"+t+"Z"}function Io(n){return function(){var t,e;(t=this[n])&&(e=t[t.active])&&(--t.count?delete t[t.active]:delete this[n],t.active+=.5,e.event&&e.event.interrupt.call(this,this.__data__,e.index))}}function Yo(n,t,e){return ya(n,Pl),n.namespace=t,n.id=e,n}function Zo(n,t,e,r){var u=n.id,i=n.namespace;return Y(n,"function"==typeof e?function(n,o,a){n[i][u].tween.set(t,r(e.call(n,n.__data__,o,a)))}:(e=r(e),function(n){n[i][u].tween.set(t,e)}))}function Vo(n){return null==n&&(n=""),function(){this.textContent=n}}function Xo(n){return null==n?"__transition__":"__transition_"+n+"__"}function $o(n,t,e,r,u){var i=n[e]||(n[e]={active:0,count:0}),o=i[r];if(!o){var a=u.time;o=i[r]={tween:new l,time:a,delay:u.delay,duration:u.duration,ease:u.ease,index:t},u=null,++i.count,ta.timer(function(u){function c(e){if(i.active>r)return s();var u=i[i.active];u&&(--i.count,delete i[i.active],u.event&&u.event.interrupt.call(n,n.__data__,u.index)),i.active=r,o.event&&o.event.start.call(n,n.__data__,t),o.tween.forEach(function(e,r){(r=r.call(n,n.__data__,t))&&v.push(r)}),h=o.ease,f=o.duration,ta.timer(function(){return p.c=l(e||1)?Ne:l,1},0,a)}function l(e){if(i.active!==r)return 1;for(var u=e/f,a=h(u),c=v.length;c>0;)v[--c].call(n,a);return u>=1?(o.event&&o.event.end.call(n,n.__data__,t),s()):void 0}function s(){return--i.count?delete i[r]:delete n[e],1}var f,h,g=o.delay,p=ec,v=[];return p.t=g+a,u>=g?c(u-g):void(p.c=c)},0,a)}}function Bo(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate("+(isFinite(r)?r:e(n))+",0)"})}function Wo(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate(0,"+(isFinite(r)?r:e(n))+")"})}function Jo(n){return n.toISOString()}function Go(n,t,e){function r(t){return n(t)}function u(n,e){var r=n[1]-n[0],u=r/e,i=ta.bisect(Vl,u);return i==Vl.length?[t.year,Vi(n.map(function(n){return n/31536e6}),e)[2]]:i?t[u/Vl[i-1]<Vl[i]/u?i-1:i]:[Bl,Vi(n,e)[2]]}return r.invert=function(t){return Ko(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain(t),r):n.domain().map(Ko)},r.nice=function(n,t){function e(e){return!isNaN(e)&&!n.range(e,Ko(+e+1),t).length}var i=r.domain(),o=Pi(i),a=null==n?u(o,10):"number"==typeof n&&u(o,n);return a&&(n=a[0],t=a[1]),r.domain(Fi(i,t>1?{floor:function(t){for(;e(t=n.floor(t));)t=Ko(t-1);return t},ceil:function(t){for(;e(t=n.ceil(t));)t=Ko(+t+1);return t}}:n))},r.ticks=function(n,t){var e=Pi(r.domain()),i=null==n?u(e,10):"number"==typeof n?u(e,n):!n.range&&[{range:n},t];return i&&(n=i[0],t=i[1]),n.range(e[0],Ko(+e[1]+1),1>t?1:t)},r.tickFormat=function(){return e},r.copy=function(){return Go(n.copy(),t,e)},Yi(r,n)}function Ko(n){return new Date(n)}function Qo(n){return JSON.parse(n.responseText)}function na(n){var t=ua.createRange();return t.selectNode(ua.body),t.createContextualFragment(n.responseText)}var ta={version:"3.5.5"},ea=[].slice,ra=function(n){return ea.call(n)},ua=this.document;if(ua)try{ra(ua.documentElement.childNodes)[0].nodeType}catch(ia){ra=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}),ua)try{ua.createElement("DIV").style.setProperty("opacity",0,"")}catch(oa){var aa=this.Element.prototype,ca=aa.setAttribute,la=aa.setAttributeNS,sa=this.CSSStyleDeclaration.prototype,fa=sa.setProperty;aa.setAttribute=function(n,t){ca.call(this,n,t+"")},aa.setAttributeNS=function(n,t,e){la.call(this,n,t,e+"")},sa.setProperty=function(n,t,e){fa.call(this,n,t+"",e)}}ta.ascending=e,ta.descending=function(n,t){return n>t?-1:t>n?1:t>=n?0:0/0},ta.min=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u<i;)if(null!=(r=n[u])&&r>=r){e=r;break}for(;++u<i;)null!=(r=n[u])&&e>r&&(e=r)}else{for(;++u<i;)if(null!=(r=t.call(n,n[u],u))&&r>=r){e=r;break}for(;++u<i;)null!=(r=t.call(n,n[u],u))&&e>r&&(e=r)}return e},ta.max=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u<i;)if(null!=(r=n[u])&&r>=r){e=r;break}for(;++u<i;)null!=(r=n[u])&&r>e&&(e=r)}else{for(;++u<i;)if(null!=(r=t.call(n,n[u],u))&&r>=r){e=r;break}for(;++u<i;)null!=(r=t.call(n,n[u],u))&&r>e&&(e=r)}return e},ta.extent=function(n,t){var e,r,u,i=-1,o=n.length;if(1===arguments.length){for(;++i<o;)if(null!=(r=n[i])&&r>=r){e=u=r;break}for(;++i<o;)null!=(r=n[i])&&(e>r&&(e=r),r>u&&(u=r))}else{for(;++i<o;)if(null!=(r=t.call(n,n[i],i))&&r>=r){e=u=r;break}for(;++i<o;)null!=(r=t.call(n,n[i],i))&&(e>r&&(e=r),r>u&&(u=r))}return[e,u]},ta.sum=function(n,t){var e,r=0,i=n.length,o=-1;if(1===arguments.length)for(;++o<i;)u(e=+n[o])&&(r+=e);else for(;++o<i;)u(e=+t.call(n,n[o],o))&&(r+=e);return r},ta.mean=function(n,t){var e,i=0,o=n.length,a=-1,c=o;if(1===arguments.length)for(;++a<o;)u(e=r(n[a]))?i+=e:--c;else for(;++a<o;)u(e=r(t.call(n,n[a],a)))?i+=e:--c;return c?i/c:void 0},ta.quantile=function(n,t){var e=(n.length-1)*t+1,r=Math.floor(e),u=+n[r-1],i=e-r;return i?u+i*(n[r]-u):u},ta.median=function(n,t){var i,o=[],a=n.length,c=-1;if(1===arguments.length)for(;++c<a;)u(i=r(n[c]))&&o.push(i);else for(;++c<a;)u(i=r(t.call(n,n[c],c)))&&o.push(i);return o.length?ta.quantile(o.sort(e),.5):void 0},ta.variance=function(n,t){var e,i,o=n.length,a=0,c=0,l=-1,s=0;if(1===arguments.length)for(;++l<o;)u(e=r(n[l]))&&(i=e-a,a+=i/++s,c+=i*(e-a));else for(;++l<o;)u(e=r(t.call(n,n[l],l)))&&(i=e-a,a+=i/++s,c+=i*(e-a));return s>1?c/(s-1):void 0},ta.deviation=function(){var n=ta.variance.apply(this,arguments);return n?Math.sqrt(n):n};var ha=i(e);ta.bisectLeft=ha.left,ta.bisect=ta.bisectRight=ha.right,ta.bisector=function(n){return i(1===n.length?function(t,r){return e(n(t),r)}:n)},ta.shuffle=function(n,t,e){(i=arguments.length)<3&&(e=n.length,2>i&&(t=0));for(var r,u,i=e-t;i;)u=Math.random()*i--|0,r=n[i+t],n[i+t]=n[u+t],n[u+t]=r;return n},ta.permute=function(n,t){for(var e=t.length,r=new Array(e);e--;)r[e]=n[t[e]];return r},ta.pairs=function(n){for(var t,e=0,r=n.length-1,u=n[0],i=new Array(0>r?0:r);r>e;)i[e]=[t=u,u=n[++e]];return i},ta.zip=function(){if(!(r=arguments.length))return[];for(var n=-1,t=ta.min(arguments,o),e=new Array(t);++n<t;)for(var r,u=-1,i=e[n]=new Array(r);++u<r;)i[u]=arguments[u][n];return e},ta.transpose=function(n){return ta.zip.apply(ta,n)},ta.keys=function(n){var t=[];for(var e in n)t.push(e);return t},ta.values=function(n){var t=[];for(var e in n)t.push(n[e]);return t},ta.entries=function(n){var t=[];for(var e in n)t.push({key:e,value:n[e]});return t},ta.merge=function(n){for(var t,e,r,u=n.length,i=-1,o=0;++i<u;)o+=n[i].length;for(e=new Array(o);--u>=0;)for(r=n[u],t=r.length;--t>=0;)e[--o]=r[t];return e};var ga=Math.abs;ta.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,u=[],i=a(ga(e)),o=-1;if(n*=i,t*=i,e*=i,0>e)for(;(r=n+e*++o)>t;)u.push(r/i);else for(;(r=n+e*++o)<t;)u.push(r/i);return u},ta.map=function(n,t){var e=new l;if(n instanceof l)n.forEach(function(n,t){e.set(n,t)});else if(Array.isArray(n)){var r,u=-1,i=n.length;if(1===arguments.length)for(;++u<i;)e.set(u,n[u]);else for(;++u<i;)e.set(t.call(n,r=n[u],u),r)}else for(var o in n)e.set(o,n[o]);return e};var pa="__proto__",va="\x00";c(l,{has:h,get:function(n){return this._[s(n)]},set:function(n,t){return this._[s(n)]=t},remove:g,keys:p,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:f(t),value:this._[t]});return n},size:v,empty:d,forEach:function(n){for(var t in this._)n.call(this,f(t),this._[t])}}),ta.nest=function(){function n(t,o,a){if(a>=i.length)return r?r.call(u,o):e?o.sort(e):o;for(var c,s,f,h,g=-1,p=o.length,v=i[a++],d=new l;++g<p;)(h=d.get(c=v(s=o[g])))?h.push(s):d.set(c,[s]);return t?(s=t(),f=function(e,r){s.set(e,n(t,r,a))}):(s={},f=function(e,r){s[e]=n(t,r,a)}),d.forEach(f),s}function t(n,e){if(e>=i.length)return n;var r=[],u=o[e++];return n.forEach(function(n,u){r.push({key:n,values:t(u,e)})}),u?r.sort(function(n,t){return u(n.key,t.key)}):r}var e,r,u={},i=[],o=[];return u.map=function(t,e){return n(e,t,0)},u.entries=function(e){return t(n(ta.map,e,0),0)},u.key=function(n){return i.push(n),u},u.sortKeys=function(n){return o[i.length-1]=n,u},u.sortValues=function(n){return e=n,u},u.rollup=function(n){return r=n,u},u},ta.set=function(n){var t=new m;if(n)for(var e=0,r=n.length;r>e;++e)t.add(n[e]);return t},c(m,{has:h,add:function(n){return this._[s(n+="")]=!0,n},remove:g,values:p,size:v,empty:d,forEach:function(n){for(var t in this._)n.call(this,f(t))}}),ta.behavior={},ta.rebind=function(n,t){for(var e,r=1,u=arguments.length;++r<u;)n[e=arguments[r]]=M(n,t,t[e]);return n};var da=["webkit","ms","moz","Moz","o","O"];ta.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}},ta.event=null,ta.requote=function(n){return n.replace(ma,"\\$&")};var ma=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,ya={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var e in t)n[e]=t[e]},Ma=function(n,t){return t.querySelector(n)},xa=function(n,t){return t.querySelectorAll(n)},ba=function(n,t){var e=n.matches||n[x(n,"matchesSelector")];return(ba=function(n,t){return e.call(n,t)})(n,t)};"function"==typeof Sizzle&&(Ma=function(n,t){return Sizzle(n,t)[0]||null},xa=Sizzle,ba=Sizzle.matchesSelector),ta.selection=function(){return ta.select(ua.documentElement)};var _a=ta.selection.prototype=[];_a.select=function(n){var t,e,r,u,i=[];n=N(n);for(var o=-1,a=this.length;++o<a;){i.push(t=[]),t.parentNode=(r=this[o]).parentNode;for(var c=-1,l=r.length;++c<l;)(u=r[c])?(t.push(e=n.call(u,u.__data__,c,o)),e&&"__data__"in u&&(e.__data__=u.__data__)):t.push(null)}return A(i)},_a.selectAll=function(n){var t,e,r=[];n=C(n);for(var u=-1,i=this.length;++u<i;)for(var o=this[u],a=-1,c=o.length;++a<c;)(e=o[a])&&(r.push(t=ra(n.call(e,e.__data__,a,u))),t.parentNode=e);return A(r)};var wa={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};ta.ns={prefix:wa,qualify:function(n){var t=n.indexOf(":"),e=n;return t>=0&&(e=n.slice(0,t),n=n.slice(t+1)),wa.hasOwnProperty(e)?{space:wa[e],local:n}:n}},_a.attr=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node();return n=ta.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))},_a.classed=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node(),r=(n=T(n)).length,u=-1;if(t=e.classList){for(;++u<r;)if(!t.contains(n[u]))return!1}else for(t=e.getAttribute("class");++u<r;)if(!L(n[u]).test(t))return!1;return!0}for(t in n)this.each(R(t,n[t]));return this}return this.each(R(n,t))},_a.style=function(n,e,r){var u=arguments.length;if(3>u){if("string"!=typeof n){2>u&&(e="");for(r in n)this.each(P(r,n[r],e));return this}if(2>u){var i=this.node();return t(i).getComputedStyle(i,null).getPropertyValue(n)}r=""}return this.each(P(n,e,r))},_a.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))},_a.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},_a.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},_a.append=function(n){return n=j(n),this.select(function(){return this.appendChild(n.apply(this,arguments))})},_a.insert=function(n,t){return n=j(n),t=N(t),this.select(function(){return this.insertBefore(n.apply(this,arguments),t.apply(this,arguments)||null)})},_a.remove=function(){return this.each(F)},_a.data=function(n,t){function e(n,e){var r,u,i,o=n.length,f=e.length,h=Math.min(o,f),g=new Array(f),p=new Array(f),v=new Array(o);if(t){var d,m=new l,y=new Array(o);for(r=-1;++r<o;)m.has(d=t.call(u=n[r],u.__data__,r))?v[r]=u:m.set(d,u),y[r]=d;for(r=-1;++r<f;)(u=m.get(d=t.call(e,i=e[r],r)))?u!==!0&&(g[r]=u,u.__data__=i):p[r]=H(i),m.set(d,!0);for(r=-1;++r<o;)m.get(y[r])!==!0&&(v[r]=n[r])}else{for(r=-1;++r<h;)u=n[r],i=e[r],u?(u.__data__=i,g[r]=u):p[r]=H(i);for(;f>r;++r)p[r]=H(e[r]);for(;o>r;++r)v[r]=n[r]}p.update=g,p.parentNode=g.parentNode=v.parentNode=n.parentNode,a.push(p),c.push(g),s.push(v)}var r,u,i=-1,o=this.length;if(!arguments.length){for(n=new Array(o=(r=this[0]).length);++i<o;)(u=r[i])&&(n[i]=u.__data__);return n}var a=Z([]),c=A([]),s=A([]);if("function"==typeof n)for(;++i<o;)e(r=this[i],n.call(r,r.parentNode.__data__,i));else for(;++i<o;)e(r=this[i],n);return c.enter=function(){return a},c.exit=function(){return s},c},_a.datum=function(n){return arguments.length?this.property("__data__",n):this.property("__data__")},_a.filter=function(n){var t,e,r,u=[];"function"!=typeof n&&(n=O(n));for(var i=0,o=this.length;o>i;i++){u.push(t=[]),t.parentNode=(e=this[i]).parentNode;for(var a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return A(u)},_a.order=function(){for(var n=-1,t=this.length;++n<t;)for(var e,r=this[n],u=r.length-1,i=r[u];--u>=0;)(e=r[u])&&(i&&i!==e.nextSibling&&i.parentNode.insertBefore(e,i),i=e);return this},_a.sort=function(n){n=I.apply(this,arguments);for(var t=-1,e=this.length;++t<e;)this[t].sort(n);return this.order()},_a.each=function(n){return Y(this,function(t,e,r){n.call(t,t.__data__,e,r)})},_a.call=function(n){var t=ra(arguments);return n.apply(t[0]=this,t),this},_a.empty=function(){return!this.node()},_a.node=function(){for(var n=0,t=this.length;t>n;n++)for(var e=this[n],r=0,u=e.length;u>r;r++){var i=e[r];if(i)return i}return null},_a.size=function(){var n=0;return Y(this,function(){++n}),n};var Sa=[];ta.selection.enter=Z,ta.selection.enter.prototype=Sa,Sa.append=_a.append,Sa.empty=_a.empty,Sa.node=_a.node,Sa.call=_a.call,Sa.size=_a.size,Sa.select=function(n){for(var t,e,r,u,i,o=[],a=-1,c=this.length;++a<c;){r=(u=this[a]).update,o.push(t=[]),t.parentNode=u.parentNode;for(var l=-1,s=u.length;++l<s;)(i=u[l])?(t.push(r[l]=e=n.call(u.parentNode,i.__data__,l,a)),e.__data__=i.__data__):t.push(null)}return A(o)},Sa.insert=function(n,t){return arguments.length<2&&(t=V(this)),_a.insert.call(this,n,t)},ta.select=function(t){var e;return"string"==typeof t?(e=[Ma(t,ua)],e.parentNode=ua.documentElement):(e=[t],e.parentNode=n(t)),A([e])},ta.selectAll=function(n){var t;return"string"==typeof n?(t=ra(xa(n,ua)),t.parentNode=ua.documentElement):(t=n,t.parentNode=null),A([t])},_a.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 ka=ta.map({mouseenter:"mouseover",mouseleave:"mouseout"});ua&&ka.forEach(function(n){"on"+n in ua&&ka.remove(n)});var Ea,Aa=0;ta.mouse=function(n){return J(n,k())};var Na=this.navigator&&/WebKit/.test(this.navigator.userAgent)?-1:0;ta.touch=function(n,t,e){if(arguments.length<3&&(e=t,t=k().changedTouches),t)for(var r,u=0,i=t.length;i>u;++u)if((r=t[u]).identifier===e)return J(n,r)},ta.behavior.drag=function(){function n(){this.on("mousedown.drag",i).on("touchstart.drag",o)}function e(n,t,e,i,o){return function(){function a(){var n,e,r=t(h,v);r&&(n=r[0]-M[0],e=r[1]-M[1],p|=n|e,M=r,g({type:"drag",x:r[0]+l[0],y:r[1]+l[1],dx:n,dy:e}))}function c(){t(h,v)&&(m.on(i+d,null).on(o+d,null),y(p&&ta.event.target===f),g({type:"dragend"}))}var l,s=this,f=ta.event.target,h=s.parentNode,g=r.of(s,arguments),p=0,v=n(),d=".drag"+(null==v?"":"-"+v),m=ta.select(e(f)).on(i+d,a).on(o+d,c),y=W(f),M=t(h,v);u?(l=u.apply(s,arguments),l=[l.x-M[0],l.y-M[1]]):l=[0,0],g({type:"dragstart"})}}var r=E(n,"drag","dragstart","dragend"),u=null,i=e(b,ta.mouse,t,"mousemove","mouseup"),o=e(G,ta.touch,y,"touchmove","touchend");return n.origin=function(t){return arguments.length?(u=t,n):u},ta.rebind(n,r,"on")},ta.touches=function(n,t){return arguments.length<2&&(t=k().touches),t?ra(t).map(function(t){var e=J(n,t);return e.identifier=t.identifier,e}):[]};var Ca=1e-6,za=Ca*Ca,qa=Math.PI,La=2*qa,Ta=La-Ca,Ra=qa/2,Da=qa/180,Pa=180/qa,Ua=Math.SQRT2,ja=2,Fa=4;ta.interpolateZoom=function(n,t){function e(n){var t=n*y;if(m){var e=rt(v),o=i/(ja*h)*(e*ut(Ua*t+v)-et(v));return[r+o*l,u+o*s,i*e/rt(Ua*t+v)]}return[r+n*l,u+n*s,i*Math.exp(Ua*t)]}var r=n[0],u=n[1],i=n[2],o=t[0],a=t[1],c=t[2],l=o-r,s=a-u,f=l*l+s*s,h=Math.sqrt(f),g=(c*c-i*i+Fa*f)/(2*i*ja*h),p=(c*c-i*i-Fa*f)/(2*c*ja*h),v=Math.log(Math.sqrt(g*g+1)-g),d=Math.log(Math.sqrt(p*p+1)-p),m=d-v,y=(m||Math.log(c/i))/Ua;return e.duration=1e3*y,e},ta.behavior.zoom=function(){function n(n){n.on(q,f).on(Oa+".zoom",g).on("dblclick.zoom",p).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 u(n){k.k=Math.max(N[0],Math.min(N[1],n))}function i(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},u(Math.pow(2,o)),i(d=e,r),t=ta.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 c(n){z++||n({type:"zoomstart"})}function l(n){a(),n({type:"zoom",scale:k.k,translate:[k.x,k.y]})}function s(n){--z||n({type:"zoomend"}),d=null}function f(){function n(){f=1,i(ta.mouse(u),g),l(a)}function r(){h.on(L,null).on(T,null),p(f&&ta.event.target===o),s(a)}var u=this,o=ta.event.target,a=D.of(u,arguments),f=0,h=ta.select(t(u)).on(L,n).on(T,r),g=e(ta.mouse(u)),p=W(u);Dl.call(u),c(a)}function h(){function n(){var n=ta.touches(p);return g=k.k,n.forEach(function(n){n.identifier in d&&(d[n.identifier]=e(n))}),n}function t(){var t=ta.event.target;ta.select(t).on(x,r).on(b,a),_.push(t);for(var e=ta.event.changedTouches,u=0,i=e.length;i>u;++u)d[e[u].identifier]=null;var c=n(),l=Date.now();if(1===c.length){if(500>l-M){var s=c[0];o(p,s,d[s.identifier],Math.floor(Math.log(k.k)/Math.LN2)+1),S()}M=l}else if(c.length>1){var s=c[0],f=c[1],h=s[0]-f[0],g=s[1]-f[1];m=h*h+g*g}}function r(){var n,t,e,r,o=ta.touches(p);Dl.call(p);for(var a=0,c=o.length;c>a;++a,r=null)if(e=o[a],r=d[e.identifier]){if(t)break;n=e,t=r}if(r){var s=(s=e[0]-n[0])*s+(s=e[1]-n[1])*s,f=m&&Math.sqrt(s/m);n=[(n[0]+e[0])/2,(n[1]+e[1])/2],t=[(t[0]+r[0])/2,(t[1]+r[1])/2],u(f*g)}M=null,i(n,t),l(v)}function a(){if(ta.event.touches.length){for(var t=ta.event.changedTouches,e=0,r=t.length;r>e;++e)delete d[t[e].identifier];for(var u in d)return void n()}ta.selectAll(_).on(y,null),w.on(q,f).on(R,h),E(),s(v)}var g,p=this,v=D.of(p,arguments),d={},m=0,y=".zoom-"+ta.event.changedTouches[0].identifier,x="touchmove"+y,b="touchend"+y,_=[],w=ta.select(p),E=W(p);t(),c(v),w.on(q,null).on(R,t)}function g(){var n=D.of(this,arguments);y?clearTimeout(y):(v=e(d=m||ta.mouse(this)),Dl.call(this),c(n)),y=setTimeout(function(){y=null,s(n)},50),S(),u(Math.pow(2,.002*Ha())*k.k),i(d,v),l(n)}function p(){var n=ta.mouse(this),t=Math.log(k.k)/Math.LN2;o(this,n,e(n),ta.event.shiftKey?Math.ceil(t)-1:Math.floor(t)+1)}var v,d,m,y,M,x,b,_,w,k={x:0,y:0,k:1},A=[960,500],N=Ia,C=250,z=0,q="mousedown.zoom",L="mousemove.zoom",T="mouseup.zoom",R="touchstart.zoom",D=E(n,"zoomstart","zoom","zoomend");return Oa||(Oa="onwheel"in ua?(Ha=function(){return-ta.event.deltaY*(ta.event.deltaMode?120:1)},"wheel"):"onmousewheel"in ua?(Ha=function(){return ta.event.wheelDelta},"mousewheel"):(Ha=function(){return-ta.event.detail},"MozMousePixelScroll")),n.event=function(n){n.each(function(){var n=D.of(this,arguments),t=k;Tl?ta.select(this).transition().each("start.zoom",function(){k=this.__chart__||{x:0,y:0,k:1},c(n)}).tween("zoom:zoom",function(){var e=A[0],r=A[1],u=d?d[0]:e/2,i=d?d[1]:r/2,o=ta.interpolateZoom([(u-k.x)/k.k,(i-k.y)/k.k,e/k.k],[(u-t.x)/t.k,(i-t.y)/t.k,e/t.k]);return function(t){var r=o(t),a=e/r[2];this.__chart__=k={x:u-r[0]*a,y:i-r[1]*a,k:a},l(n)}}).each("interrupt.zoom",function(){s(n)}).each("end.zoom",function(){s(n)}):(this.__chart__=k,c(n),l(n),s(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:+t},a(),n):k.k},n.scaleExtent=function(t){return arguments.length?(N=null==t?Ia:[+t[0],+t[1]],n):N},n.center=function(t){return arguments.length?(m=t&&[+t[0],+t[1]],n):m},n.size=function(t){return arguments.length?(A=t&&[+t[0],+t[1]],n):A},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},ta.rebind(n,D,"on")};var Ha,Oa,Ia=[0,1/0];ta.color=ot,ot.prototype.toString=function(){return this.rgb()+""},ta.hsl=at;var Ya=at.prototype=new ot;Ya.brighter=function(n){return n=Math.pow(.7,arguments.length?n:1),new at(this.h,this.s,this.l/n)},Ya.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new at(this.h,this.s,n*this.l)},Ya.rgb=function(){return ct(this.h,this.s,this.l)},ta.hcl=lt;var Za=lt.prototype=new ot;Za.brighter=function(n){return new lt(this.h,this.c,Math.min(100,this.l+Va*(arguments.length?n:1)))},Za.darker=function(n){return new lt(this.h,this.c,Math.max(0,this.l-Va*(arguments.length?n:1)))},Za.rgb=function(){return st(this.h,this.c,this.l).rgb()},ta.lab=ft;var Va=18,Xa=.95047,$a=1,Ba=1.08883,Wa=ft.prototype=new ot;Wa.brighter=function(n){return new ft(Math.min(100,this.l+Va*(arguments.length?n:1)),this.a,this.b)},Wa.darker=function(n){return new ft(Math.max(0,this.l-Va*(arguments.length?n:1)),this.a,this.b)},Wa.rgb=function(){return ht(this.l,this.a,this.b)},ta.rgb=mt;var Ja=mt.prototype=new ot;Ja.brighter=function(n){n=Math.pow(.7,arguments.length?n:1);var t=this.r,e=this.g,r=this.b,u=30;return t||e||r?(t&&u>t&&(t=u),e&&u>e&&(e=u),r&&u>r&&(r=u),new mt(Math.min(255,t/n),Math.min(255,e/n),Math.min(255,r/n))):new mt(u,u,u)},Ja.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new mt(n*this.r,n*this.g,n*this.b)},Ja.hsl=function(){return _t(this.r,this.g,this.b)},Ja.toString=function(){return"#"+xt(this.r)+xt(this.g)+xt(this.b)};var Ga=ta.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});Ga.forEach(function(n,t){Ga.set(n,yt(t))}),ta.functor=Et,ta.xhr=At(y),ta.dsv=function(n,t){function e(n,e,i){arguments.length<3&&(i=e,e=null);var o=Nt(n,t,null==e?r:u(e),i);return o.row=function(n){return arguments.length?o.response(null==(e=n)?r:u(n)):e},o}function r(n){return e.parse(n.responseText)}function u(n){return function(t){return e.parse(t.responseText,n)}}function i(t){return t.map(o).join(n)}function o(n){return a.test(n)?'"'+n.replace(/\"/g,'""')+'"':n}var a=new RegExp('["'+n+"\n]"),c=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 u=new Function("d","return {"+n.map(function(n,t){return JSON.stringify(n)+": d["+t+"]"}).join(",")+"}");r=t?function(n,e){return t(u(n),e)}:u})},e.parseRows=function(n,t){function e(){if(s>=l)return o;if(u)return u=!1,i;var t=s;if(34===n.charCodeAt(t)){for(var e=t;e++<l;)if(34===n.charCodeAt(e)){if(34!==n.charCodeAt(e+1))break;++e}s=e+2;var r=n.charCodeAt(e+1);return 13===r?(u=!0,10===n.charCodeAt(e+2)&&++s):10===r&&(u=!0),n.slice(t+1,e).replace(/""/g,'"')}for(;l>s;){var r=n.charCodeAt(s++),a=1;if(10===r)u=!0;else if(13===r)u=!0,10===n.charCodeAt(s)&&(++s,++a);else if(r!==c)continue;return n.slice(t,s-a)}return n.slice(t)}for(var r,u,i={},o={},a=[],l=n.length,s=0,f=0;(r=e())!==o;){for(var h=[];r!==i&&r!==o;)h.push(r),r=e();t&&null==(h=t(h,f++))||a.push(h)}return a},e.format=function(t){if(Array.isArray(t[0]))return e.formatRows(t);var r=new m,u=[];return t.forEach(function(n){for(var t in n)r.has(t)||u.push(r.add(t))}),[u.map(o).join(n)].concat(t.map(function(t){return u.map(function(n){return o(t[n])}).join(n)})).join("\n")},e.formatRows=function(n){return n.map(i).join("\n")},e},ta.csv=ta.dsv(",","text/csv"),ta.tsv=ta.dsv("	","text/tab-separated-values");var Ka,Qa,nc,tc,ec,rc=this[x(this,"requestAnimationFrame")]||function(n){setTimeout(n,17)};ta.timer=function(n,t,e){var r=arguments.length;2>r&&(t=0),3>r&&(e=Date.now());var u=e+t,i={c:n,t:u,f:!1,n:null};Qa?Qa.n=i:Ka=i,Qa=i,nc||(tc=clearTimeout(tc),nc=1,rc(qt))},ta.timer.flush=function(){Lt(),Tt()},ta.round=function(n,t){return t?Math.round(n*(t=Math.pow(10,t)))/t:Math.round(n)};var uc=["y","z","a","f","p","n","\xb5","m","","k","M","G","T","P","E","Z","Y"].map(Dt);ta.formatPrefix=function(n,t){var e=0;return n&&(0>n&&(n*=-1),t&&(n=ta.round(n,Rt(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)))),uc[8+e/3]};var ic=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,oc=ta.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=ta.round(n,Rt(n,t))).toFixed(Math.max(0,Math.min(20,Rt(n*(1+1e-15),t))))}}),ac=ta.time={},cc=Date;jt.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(){lc.setUTCDate.apply(this._,arguments)},setDay:function(){lc.setUTCDay.apply(this._,arguments)},setFullYear:function(){lc.setUTCFullYear.apply(this._,arguments)},setHours:function(){lc.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){lc.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){lc.setUTCMinutes.apply(this._,arguments)},setMonth:function(){lc.setUTCMonth.apply(this._,arguments)},setSeconds:function(){lc.setUTCSeconds.apply(this._,arguments)},setTime:function(){lc.setTime.apply(this._,arguments)}};var lc=Date.prototype;ac.year=Ft(function(n){return n=ac.day(n),n.setMonth(0,1),n},function(n,t){n.setFullYear(n.getFullYear()+t)},function(n){return n.getFullYear()}),ac.years=ac.year.range,ac.years.utc=ac.year.utc.range,ac.day=Ft(function(n){var t=new cc(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}),ac.days=ac.day.range,ac.days.utc=ac.day.utc.range,ac.dayOfYear=function(n){var t=ac.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=ac[n]=Ft(function(n){return(n=ac.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=ac.year(n).getDay();return Math.floor((ac.dayOfYear(n)+(e+t)%7)/7)-(e!==t)});ac[n+"s"]=e.range,ac[n+"s"].utc=e.utc.range,ac[n+"OfYear"]=function(n){var e=ac.year(n).getDay();return Math.floor((ac.dayOfYear(n)+(e+t)%7)/7)}}),ac.week=ac.sunday,ac.weeks=ac.sunday.range,ac.weeks.utc=ac.sunday.utc.range,ac.weekOfYear=ac.sundayOfYear;var sc={"-":"",_:" ",0:"0"},fc=/^\s*\d+/,hc=/^%/;ta.locale=function(n){return{numberFormat:Pt(n),timeFormat:Ot(n)}};var gc=ta.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"]});ta.format=gc.numberFormat,ta.geo={},ce.prototype={s:0,t:0,add:function(n){le(n,this.t,pc),le(pc.s,this.s,this),this.s?this.t+=pc.t:this.s=pc.t
},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var pc=new ce;ta.geo.stream=function(n,t){n&&vc.hasOwnProperty(n.type)?vc[n.type](n,t):se(n,t)};var vc={Feature:function(n,t){se(n.geometry,t)},FeatureCollection:function(n,t){for(var e=n.features,r=-1,u=e.length;++r<u;)se(e[r].geometry,t)}},dc={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,u=e.length;++r<u;)n=e[r],t.point(n[0],n[1],n[2])},LineString:function(n,t){fe(n.coordinates,t,0)},MultiLineString:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)fe(e[r],t,0)},Polygon:function(n,t){he(n.coordinates,t)},MultiPolygon:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)he(e[r],t)},GeometryCollection:function(n,t){for(var e=n.geometries,r=-1,u=e.length;++r<u;)se(e[r],t)}};ta.geo.area=function(n){return mc=0,ta.geo.stream(n,Mc),mc};var mc,yc=new ce,Mc={sphere:function(){mc+=4*qa},point:b,lineStart:b,lineEnd:b,polygonStart:function(){yc.reset(),Mc.lineStart=ge},polygonEnd:function(){var n=2*yc;mc+=0>n?4*qa+n:n,Mc.lineStart=Mc.lineEnd=Mc.point=b}};ta.geo.bounds=function(){function n(n,t){M.push(x=[s=n,h=n]),f>t&&(f=t),t>g&&(g=t)}function t(t,e){var r=pe([t*Da,e*Da]);if(m){var u=de(m,r),i=[u[1],-u[0],0],o=de(i,u);Me(o),o=xe(o);var c=t-p,l=c>0?1:-1,v=o[0]*Pa*l,d=ga(c)>180;if(d^(v>l*p&&l*t>v)){var y=o[1]*Pa;y>g&&(g=y)}else if(v=(v+360)%360-180,d^(v>l*p&&l*t>v)){var y=-o[1]*Pa;f>y&&(f=y)}else f>e&&(f=e),e>g&&(g=e);d?p>t?a(s,t)>a(s,h)&&(h=t):a(t,h)>a(s,h)&&(s=t):h>=s?(s>t&&(s=t),t>h&&(h=t)):t>p?a(s,t)>a(s,h)&&(h=t):a(t,h)>a(s,h)&&(s=t)}else n(t,e);m=r,p=t}function e(){b.point=t}function r(){x[0]=s,x[1]=h,b.point=n,m=null}function u(n,e){if(m){var r=n-p;y+=ga(r)>180?r+(r>0?360:-360):r}else v=n,d=e;Mc.point(n,e),t(n,e)}function i(){Mc.lineStart()}function o(){u(v,d),Mc.lineEnd(),ga(y)>Ca&&(s=-(h=180)),x[0]=s,x[1]=h,m=null}function a(n,t){return(t-=n)<0?t+360:t}function c(n,t){return n[0]-t[0]}function l(n,t){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var s,f,h,g,p,v,d,m,y,M,x,b={point:n,lineStart:e,lineEnd:r,polygonStart:function(){b.point=u,b.lineStart=i,b.lineEnd=o,y=0,Mc.polygonStart()},polygonEnd:function(){Mc.polygonEnd(),b.point=n,b.lineStart=e,b.lineEnd=r,0>yc?(s=-(h=180),f=-(g=90)):y>Ca?g=90:-Ca>y&&(f=-90),x[0]=s,x[1]=h}};return function(n){g=h=-(s=f=1/0),M=[],ta.geo.stream(n,b);var t=M.length;if(t){M.sort(c);for(var e,r=1,u=M[0],i=[u];t>r;++r)e=M[r],l(e[0],u)||l(e[1],u)?(a(u[0],e[1])>a(u[0],u[1])&&(u[1]=e[1]),a(e[0],u[1])>a(u[0],u[1])&&(u[0]=e[0])):i.push(u=e);for(var o,e,p=-1/0,t=i.length-1,r=0,u=i[t];t>=r;u=e,++r)e=i[r],(o=a(u[1],e[0]))>p&&(p=o,s=e[0],h=u[1])}return M=x=null,1/0===s||1/0===f?[[0/0,0/0],[0/0,0/0]]:[[s,f],[h,g]]}}(),ta.geo.centroid=function(n){xc=bc=_c=wc=Sc=kc=Ec=Ac=Nc=Cc=zc=0,ta.geo.stream(n,qc);var t=Nc,e=Cc,r=zc,u=t*t+e*e+r*r;return za>u&&(t=kc,e=Ec,r=Ac,Ca>bc&&(t=_c,e=wc,r=Sc),u=t*t+e*e+r*r,za>u)?[0/0,0/0]:[Math.atan2(e,t)*Pa,tt(r/Math.sqrt(u))*Pa]};var xc,bc,_c,wc,Sc,kc,Ec,Ac,Nc,Cc,zc,qc={sphere:b,point:_e,lineStart:Se,lineEnd:ke,polygonStart:function(){qc.lineStart=Ee},polygonEnd:function(){qc.lineStart=Se}},Lc=Le(Ne,Pe,je,[-qa,-qa/2]),Tc=1e9;ta.geo.clipExtent=function(){var n,t,e,r,u,i,o={stream:function(n){return u&&(u.valid=!1),u=i(n),u.valid=!0,u},extent:function(a){return arguments.length?(i=Ie(n=+a[0][0],t=+a[0][1],e=+a[1][0],r=+a[1][1]),u&&(u.valid=!1,u=null),o):[[n,t],[e,r]]}};return o.extent([[0,0],[960,500]])},(ta.geo.conicEqualArea=function(){return Ye(Ze)}).raw=Ze,ta.geo.albers=function(){return ta.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},ta.geo.albersUsa=function(){function n(n){var i=n[0],o=n[1];return t=null,e(i,o),t||(r(i,o),t)||u(i,o),t}var t,e,r,u,i=ta.geo.albers(),o=ta.geo.conicEqualArea().rotate([154,0]).center([-2,58.5]).parallels([55,65]),a=ta.geo.conicEqualArea().rotate([157,0]).center([-3,19.9]).parallels([8,18]),c={point:function(n,e){t=[n,e]}};return n.invert=function(n){var t=i.scale(),e=i.translate(),r=(n[0]-e[0])/t,u=(n[1]-e[1])/t;return(u>=.12&&.234>u&&r>=-.425&&-.214>r?o:u>=.166&&.234>u&&r>=-.214&&-.115>r?a:i).invert(n)},n.stream=function(n){var t=i.stream(n),e=o.stream(n),r=a.stream(n);return{point:function(n,u){t.point(n,u),e.point(n,u),r.point(n,u)},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?(i.precision(t),o.precision(t),a.precision(t),n):i.precision()},n.scale=function(t){return arguments.length?(i.scale(t),o.scale(.35*t),a.scale(t),n.translate(i.translate())):i.scale()},n.translate=function(t){if(!arguments.length)return i.translate();var l=i.scale(),s=+t[0],f=+t[1];return e=i.translate(t).clipExtent([[s-.455*l,f-.238*l],[s+.455*l,f+.238*l]]).stream(c).point,r=o.translate([s-.307*l,f+.201*l]).clipExtent([[s-.425*l+Ca,f+.12*l+Ca],[s-.214*l-Ca,f+.234*l-Ca]]).stream(c).point,u=a.translate([s-.205*l,f+.212*l]).clipExtent([[s-.214*l+Ca,f+.166*l+Ca],[s-.115*l-Ca,f+.234*l-Ca]]).stream(c).point,n},n.scale(1070)};var Rc,Dc,Pc,Uc,jc,Fc,Hc={point:b,lineStart:b,lineEnd:b,polygonStart:function(){Dc=0,Hc.lineStart=Ve},polygonEnd:function(){Hc.lineStart=Hc.lineEnd=Hc.point=b,Rc+=ga(Dc/2)}},Oc={point:Xe,lineStart:b,lineEnd:b,polygonStart:b,polygonEnd:b},Ic={point:We,lineStart:Je,lineEnd:Ge,polygonStart:function(){Ic.lineStart=Ke},polygonEnd:function(){Ic.point=We,Ic.lineStart=Je,Ic.lineEnd=Ge}};ta.geo.path=function(){function n(n){return n&&("function"==typeof a&&i.pointRadius(+a.apply(this,arguments)),o&&o.valid||(o=u(i)),ta.geo.stream(n,o)),i.result()}function t(){return o=null,n}var e,r,u,i,o,a=4.5;return n.area=function(n){return Rc=0,ta.geo.stream(n,u(Hc)),Rc},n.centroid=function(n){return _c=wc=Sc=kc=Ec=Ac=Nc=Cc=zc=0,ta.geo.stream(n,u(Ic)),zc?[Nc/zc,Cc/zc]:Ac?[kc/Ac,Ec/Ac]:Sc?[_c/Sc,wc/Sc]:[0/0,0/0]},n.bounds=function(n){return jc=Fc=-(Pc=Uc=1/0),ta.geo.stream(n,u(Oc)),[[Pc,Uc],[jc,Fc]]},n.projection=function(n){return arguments.length?(u=(e=n)?n.stream||tr(n):y,t()):e},n.context=function(n){return arguments.length?(i=null==(r=n)?new $e:new Qe(n),"function"!=typeof a&&i.pointRadius(a),t()):r},n.pointRadius=function(t){return arguments.length?(a="function"==typeof t?t:(i.pointRadius(+t),+t),n):a},n.projection(ta.geo.albersUsa()).context(null)},ta.geo.transform=function(n){return{stream:function(t){var e=new er(t);for(var r in n)e[r]=n[r];return e}}},er.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()}},ta.geo.projection=ur,ta.geo.projectionMutator=ir,(ta.geo.equirectangular=function(){return ur(ar)}).raw=ar.invert=ar,ta.geo.rotation=function(n){function t(t){return t=n(t[0]*Da,t[1]*Da),t[0]*=Pa,t[1]*=Pa,t}return n=lr(n[0]%360*Da,n[1]*Da,n.length>2?n[2]*Da:0),t.invert=function(t){return t=n.invert(t[0]*Da,t[1]*Da),t[0]*=Pa,t[1]*=Pa,t},t},cr.invert=ar,ta.geo.circle=function(){function n(){var n="function"==typeof r?r.apply(this,arguments):r,t=lr(-n[0]*Da,-n[1]*Da,0).invert,u=[];return e(null,null,1,{point:function(n,e){u.push(n=t(n,e)),n[0]*=Pa,n[1]*=Pa}}),{type:"Polygon",coordinates:[u]}}var t,e,r=[0,0],u=6;return n.origin=function(t){return arguments.length?(r=t,n):r},n.angle=function(r){return arguments.length?(e=gr((t=+r)*Da,u*Da),n):t},n.precision=function(r){return arguments.length?(e=gr(t*Da,(u=+r)*Da),n):u},n.angle(90)},ta.geo.distance=function(n,t){var e,r=(t[0]-n[0])*Da,u=n[1]*Da,i=t[1]*Da,o=Math.sin(r),a=Math.cos(r),c=Math.sin(u),l=Math.cos(u),s=Math.sin(i),f=Math.cos(i);return Math.atan2(Math.sqrt((e=f*o)*e+(e=l*s-c*f*a)*e),c*s+l*f*a)},ta.geo.graticule=function(){function n(){return{type:"MultiLineString",coordinates:t()}}function t(){return ta.range(Math.ceil(i/d)*d,u,d).map(h).concat(ta.range(Math.ceil(l/m)*m,c,m).map(g)).concat(ta.range(Math.ceil(r/p)*p,e,p).filter(function(n){return ga(n%d)>Ca}).map(s)).concat(ta.range(Math.ceil(a/v)*v,o,v).filter(function(n){return ga(n%m)>Ca}).map(f))}var e,r,u,i,o,a,c,l,s,f,h,g,p=10,v=p,d=90,m=360,y=2.5;return n.lines=function(){return t().map(function(n){return{type:"LineString",coordinates:n}})},n.outline=function(){return{type:"Polygon",coordinates:[h(i).concat(g(c).slice(1),h(u).reverse().slice(1),g(l).reverse().slice(1))]}},n.extent=function(t){return arguments.length?n.majorExtent(t).minorExtent(t):n.minorExtent()},n.majorExtent=function(t){return arguments.length?(i=+t[0][0],u=+t[1][0],l=+t[0][1],c=+t[1][1],i>u&&(t=i,i=u,u=t),l>c&&(t=l,l=c,c=t),n.precision(y)):[[i,l],[u,c]]},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(y)):[[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],m=+t[1],n):[d,m]},n.minorStep=function(t){return arguments.length?(p=+t[0],v=+t[1],n):[p,v]},n.precision=function(t){return arguments.length?(y=+t,s=vr(a,o,90),f=dr(r,e,y),h=vr(l,c,90),g=dr(i,u,y),n):y},n.majorExtent([[-180,-90+Ca],[180,90-Ca]]).minorExtent([[-180,-80-Ca],[180,80+Ca]])},ta.geo.greatArc=function(){function n(){return{type:"LineString",coordinates:[t||r.apply(this,arguments),e||u.apply(this,arguments)]}}var t,e,r=mr,u=yr;return n.distance=function(){return ta.geo.distance(t||r.apply(this,arguments),e||u.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?(u=t,e="function"==typeof t?null:t,n):u},n.precision=function(){return arguments.length?n:0},n},ta.geo.interpolate=function(n,t){return Mr(n[0]*Da,n[1]*Da,t[0]*Da,t[1]*Da)},ta.geo.length=function(n){return Yc=0,ta.geo.stream(n,Zc),Yc};var Yc,Zc={sphere:b,point:b,lineStart:xr,lineEnd:b,polygonStart:b,polygonEnd:b},Vc=br(function(n){return Math.sqrt(2/(1+n))},function(n){return 2*Math.asin(n/2)});(ta.geo.azimuthalEqualArea=function(){return ur(Vc)}).raw=Vc;var Xc=br(function(n){var t=Math.acos(n);return t&&t/Math.sin(t)},y);(ta.geo.azimuthalEquidistant=function(){return ur(Xc)}).raw=Xc,(ta.geo.conicConformal=function(){return Ye(_r)}).raw=_r,(ta.geo.conicEquidistant=function(){return Ye(wr)}).raw=wr;var $c=br(function(n){return 1/n},Math.atan);(ta.geo.gnomonic=function(){return ur($c)}).raw=$c,Sr.invert=function(n,t){return[n,2*Math.atan(Math.exp(t))-Ra]},(ta.geo.mercator=function(){return kr(Sr)}).raw=Sr;var Bc=br(function(){return 1},Math.asin);(ta.geo.orthographic=function(){return ur(Bc)}).raw=Bc;var Wc=br(function(n){return 1/(1+n)},function(n){return 2*Math.atan(n)});(ta.geo.stereographic=function(){return ur(Wc)}).raw=Wc,Er.invert=function(n,t){return[-t,2*Math.atan(Math.exp(n))-Ra]},(ta.geo.transverseMercator=function(){var n=kr(Er),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=Er,ta.geom={},ta.geom.hull=function(n){function t(n){if(n.length<3)return[];var t,u=Et(e),i=Et(r),o=n.length,a=[],c=[];for(t=0;o>t;t++)a.push([+u.call(this,n[t],t),+i.call(this,n[t],t),t]);for(a.sort(zr),t=0;o>t;t++)c.push([a[t][0],-a[t][1]]);var l=Cr(a),s=Cr(c),f=s[0]===l[0],h=s[s.length-1]===l[l.length-1],g=[];for(t=l.length-1;t>=0;--t)g.push(n[a[l[t]][2]]);for(t=+f;t<s.length-h;++t)g.push(n[a[s[t]][2]]);return g}var e=Ar,r=Nr;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)},ta.geom.polygon=function(n){return ya(n,Jc),n};var Jc=ta.geom.polygon.prototype=[];Jc.area=function(){for(var n,t=-1,e=this.length,r=this[e-1],u=0;++t<e;)n=r,r=this[t],u+=n[1]*r[0]-n[0]*r[1];return.5*u},Jc.centroid=function(n){var t,e,r=-1,u=this.length,i=0,o=0,a=this[u-1];for(arguments.length||(n=-1/(6*this.area()));++r<u;)t=a,a=this[r],e=t[0]*a[1]-a[0]*t[1],i+=(t[0]+a[0])*e,o+=(t[1]+a[1])*e;return[i*n,o*n]},Jc.clip=function(n){for(var t,e,r,u,i,o,a=Tr(n),c=-1,l=this.length-Tr(this),s=this[l-1];++c<l;){for(t=n.slice(),n.length=0,u=this[c],i=t[(r=t.length-a)-1],e=-1;++e<r;)o=t[e],qr(o,s,u)?(qr(i,s,u)||n.push(Lr(i,o,s,u)),n.push(o)):qr(i,s,u)&&n.push(Lr(i,o,s,u)),i=o;a&&n.push(n[0]),s=u}return n};var Gc,Kc,Qc,nl,tl,el=[],rl=[];Or.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(Yr),t.length},Qr.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}},nu.prototype={insert:function(n,t){var e,r,u;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=uu(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?(u=r.R,u&&u.C?(e.C=u.C=!1,r.C=!0,n=r):(n===e.R&&(eu(this,e),n=e,e=n.U),e.C=!1,r.C=!0,ru(this,r))):(u=r.L,u&&u.C?(e.C=u.C=!1,r.C=!0,n=r):(n===e.L&&(ru(this,e),n=e,e=n.U),e.C=!1,r.C=!0,eu(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,u=n.U,i=n.L,o=n.R;if(e=i?o?uu(o):i:o,u?u.L===n?u.L=e:u.R=e:this._=e,i&&o?(r=e.C,e.C=n.C,e.L=i,i.U=e,e!==o?(u=e.U,e.U=n.U,n=e.R,u.L=n,e.R=o,o.U=e):(e.U=u,u=e,n=e.R)):(r=n.C,n=e),n&&(n.U=u),!r){if(n&&n.C)return void(n.C=!1);do{if(n===this._)break;if(n===u.L){if(t=u.R,t.C&&(t.C=!1,u.C=!0,eu(this,u),t=u.R),t.L&&t.L.C||t.R&&t.R.C){t.R&&t.R.C||(t.L.C=!1,t.C=!0,ru(this,t),t=u.R),t.C=u.C,u.C=t.R.C=!1,eu(this,u),n=this._;break}}else if(t=u.L,t.C&&(t.C=!1,u.C=!0,ru(this,u),t=u.L),t.L&&t.L.C||t.R&&t.R.C){t.L&&t.L.C||(t.R.C=!1,t.C=!0,eu(this,t),t=u.L),t.C=u.C,u.C=t.L.C=!1,ru(this,u),n=this._;break}t.C=!0,n=u,u=u.U}while(!n.C);n&&(n.C=!1)}}},ta.geom.voronoi=function(n){function t(n){var t=new Array(n.length),r=a[0][0],u=a[0][1],i=a[1][0],o=a[1][1];return iu(e(n),a).cells.forEach(function(e,a){var c=e.edges,l=e.site,s=t[a]=c.length?c.map(function(n){var t=n.start();return[t.x,t.y]}):l.x>=r&&l.x<=i&&l.y>=u&&l.y<=o?[[r,o],[i,o],[i,u],[r,u]]:[];s.point=n[a]}),t}function e(n){return n.map(function(n,t){return{x:Math.round(i(n,t)/Ca)*Ca,y:Math.round(o(n,t)/Ca)*Ca,i:t}})}var r=Ar,u=Nr,i=r,o=u,a=ul;return n?t(n):(t.links=function(n){return iu(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 iu(e(n)).cells.forEach(function(e,r){for(var u,i,o=e.site,a=e.edges.sort(Yr),c=-1,l=a.length,s=a[l-1].edge,f=s.l===o?s.r:s.l;++c<l;)u=s,i=f,s=a[c].edge,f=s.l===o?s.r:s.l,r<i.i&&r<f.i&&au(o,i,f)<0&&t.push([n[r],n[i.i],n[f.i]])}),t},t.x=function(n){return arguments.length?(i=Et(r=n),t):r},t.y=function(n){return arguments.length?(o=Et(u=n),t):u},t.clipExtent=function(n){return arguments.length?(a=null==n?ul:n,t):a===ul?null:a},t.size=function(n){return arguments.length?t.clipExtent(n&&[[0,0],n]):a===ul?null:a&&a[1]},t)};var ul=[[-1e6,-1e6],[1e6,1e6]];ta.geom.delaunay=function(n){return ta.geom.voronoi().triangles(n)},ta.geom.quadtree=function(n,t,e,r,u){function i(n){function i(n,t,e,r,u,i,o,a){if(!isNaN(e)&&!isNaN(r))if(n.leaf){var c=n.x,s=n.y;if(null!=c)if(ga(c-e)+ga(s-r)<.01)l(n,t,e,r,u,i,o,a);else{var f=n.point;n.x=n.y=n.point=null,l(n,f,c,s,u,i,o,a),l(n,t,e,r,u,i,o,a)}else n.x=e,n.y=r,n.point=t}else l(n,t,e,r,u,i,o,a)}function l(n,t,e,r,u,o,a,c){var l=.5*(u+a),s=.5*(o+c),f=e>=l,h=r>=s,g=h<<1|f;n.leaf=!1,n=n.nodes[g]||(n.nodes[g]=su()),f?u=l:a=l,h?o=s:c=s,i(n,t,e,r,u,o,a,c)}var s,f,h,g,p,v,d,m,y,M=Et(a),x=Et(c);if(null!=t)v=t,d=e,m=r,y=u;else if(m=y=-(v=d=1/0),f=[],h=[],p=n.length,o)for(g=0;p>g;++g)s=n[g],s.x<v&&(v=s.x),s.y<d&&(d=s.y),s.x>m&&(m=s.x),s.y>y&&(y=s.y),f.push(s.x),h.push(s.y);else for(g=0;p>g;++g){var b=+M(s=n[g],g),_=+x(s,g);v>b&&(v=b),d>_&&(d=_),b>m&&(m=b),_>y&&(y=_),f.push(b),h.push(_)}var w=m-v,S=y-d;w>S?y=d+w:m=v+S;var k=su();if(k.add=function(n){i(k,n,+M(n,++g),+x(n,g),v,d,m,y)},k.visit=function(n){fu(n,k,v,d,m,y)},k.find=function(n){return hu(k,n[0],n[1],v,d,m,y)},g=-1,null==t){for(;++g<p;)i(k,n[g],f[g],h[g],v,d,m,y);--g}else n.forEach(k.add);return f=h=n=s=null,k}var o,a=Ar,c=Nr;return(o=arguments.length)?(a=cu,c=lu,3===o&&(u=e,r=t,e=t=0),i(n)):(i.x=function(n){return arguments.length?(a=n,i):a},i.y=function(n){return arguments.length?(c=n,i):c},i.extent=function(n){return arguments.length?(null==n?t=e=r=u=null:(t=+n[0][0],e=+n[0][1],r=+n[1][0],u=+n[1][1]),i):null==t?null:[[t,e],[r,u]]},i.size=function(n){return arguments.length?(null==n?t=e=r=u=null:(t=e=0,r=+n[0],u=+n[1]),i):null==t?null:[r-t,u-e]},i)},ta.interpolateRgb=gu,ta.interpolateObject=pu,ta.interpolateNumber=vu,ta.interpolateString=du;var il=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,ol=new RegExp(il.source,"g");ta.interpolate=mu,ta.interpolators=[function(n,t){var e=typeof t;return("string"===e?Ga.has(t)||/^(#|rgb\(|hsl\()/.test(t)?gu:du:t instanceof ot?gu:Array.isArray(t)?yu:"object"===e&&isNaN(t)?pu:vu)(n,t)}],ta.interpolateArray=yu;var al=function(){return y},cl=ta.map({linear:al,poly:ku,quad:function(){return _u},cubic:function(){return wu},sin:function(){return Eu},exp:function(){return Au},circle:function(){return Nu},elastic:Cu,back:zu,bounce:function(){return qu}}),ll=ta.map({"in":y,out:xu,"in-out":bu,"out-in":function(n){return bu(xu(n))}});ta.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=cl.get(e)||al,r=ll.get(r)||y,Mu(r(e.apply(null,ea.call(arguments,1))))},ta.interpolateHcl=Lu,ta.interpolateHsl=Tu,ta.interpolateLab=Ru,ta.interpolateRound=Du,ta.transform=function(n){var t=ua.createElementNS(ta.ns.prefix.svg,"g");return(ta.transform=function(n){if(null!=n){t.setAttribute("transform",n);var e=t.transform.baseVal.consolidate()}return new Pu(e?e.matrix:sl)})(n)},Pu.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var sl={a:1,b:0,c:0,d:1,e:0,f:0};ta.interpolateTransform=Hu,ta.layout={},ta.layout.bundle=function(){return function(n){for(var t=[],e=-1,r=n.length;++e<r;)t.push(Yu(n[e]));return t}},ta.layout.chord=function(){function n(){var n,l,f,h,g,p={},v=[],d=ta.range(i),m=[];for(e=[],r=[],n=0,h=-1;++h<i;){for(l=0,g=-1;++g<i;)l+=u[h][g];v.push(l),m.push(ta.range(i)),n+=l}for(o&&d.sort(function(n,t){return o(v[n],v[t])}),a&&m.forEach(function(n,t){n.sort(function(n,e){return a(u[t][n],u[t][e])})}),n=(La-s*i)/n,l=0,h=-1;++h<i;){for(f=l,g=-1;++g<i;){var y=d[h],M=m[y][g],x=u[y][M],b=l,_=l+=x*n;p[y+"-"+M]={index:y,subindex:M,startAngle:b,endAngle:_,value:x}}r[y]={index:y,startAngle:f,endAngle:l,value:(l-f)/n},l+=s}for(h=-1;++h<i;)for(g=h-1;++g<i;){var w=p[h+"-"+g],S=p[g+"-"+h];(w.value||S.value)&&e.push(w.value<S.value?{source:S,target:w}:{source:w,target:S})}c&&t()}function t(){e.sort(function(n,t){return c((n.source.value+n.target.value)/2,(t.source.value+t.target.value)/2)})}var e,r,u,i,o,a,c,l={},s=0;return l.matrix=function(n){return arguments.length?(i=(u=n)&&u.length,e=r=null,l):u},l.padding=function(n){return arguments.length?(s=n,e=r=null,l):s},l.sortGroups=function(n){return arguments.length?(o=n,e=r=null,l):o},l.sortSubgroups=function(n){return arguments.length?(a=n,e=null,l):a},l.sortChords=function(n){return arguments.length?(c=n,e&&t(),l):c},l.chords=function(){return e||n(),e},l.groups=function(){return r||n(),r},l},ta.layout.force=function(){function n(n){return function(t,e,r,u){if(t.point!==n){var i=t.cx-n.x,o=t.cy-n.y,a=u-e,c=i*i+o*o;if(c>a*a/d){if(p>c){var l=t.charge/c;n.px-=i*l,n.py-=o*l}return!0}if(t.point&&c&&p>c){var l=t.pointCharge/c;n.px-=i*l,n.py-=o*l}}return!t.charge}}function t(n){n.px=ta.event.x,n.py=ta.event.y,a.resume()}var e,r,u,i,o,a={},c=ta.dispatch("start","tick","end"),l=[1,1],s=.9,f=fl,h=hl,g=-30,p=gl,v=.1,d=.64,m=[],M=[];return a.tick=function(){if((r*=.99)<.005)return c.end({type:"end",alpha:r=0}),!0;var t,e,a,f,h,p,d,y,x,b=m.length,_=M.length;for(e=0;_>e;++e)a=M[e],f=a.source,h=a.target,y=h.x-f.x,x=h.y-f.y,(p=y*y+x*x)&&(p=r*i[e]*((p=Math.sqrt(p))-u[e])/p,y*=p,x*=p,h.x-=y*(d=f.weight/(h.weight+f.weight)),h.y-=x*d,f.x+=y*(d=1-d),f.y+=x*d);if((d=r*v)&&(y=l[0]/2,x=l[1]/2,e=-1,d))for(;++e<b;)a=m[e],a.x+=(y-a.x)*d,a.y+=(x-a.y)*d;if(g)for(Ju(t=ta.geom.quadtree(m),r,o),e=-1;++e<b;)(a=m[e]).fixed||t.visit(n(a));for(e=-1;++e<b;)a=m[e],a.fixed?(a.x=a.px,a.y=a.py):(a.x-=(a.px-(a.px=a.x))*s,a.y-=(a.py-(a.py=a.y))*s);c.tick({type:"tick",alpha:r})},a.nodes=function(n){return arguments.length?(m=n,a):m},a.links=function(n){return arguments.length?(M=n,a):M},a.size=function(n){return arguments.length?(l=n,a):l},a.linkDistance=function(n){return arguments.length?(f="function"==typeof n?n:+n,a):f},a.distance=a.linkDistance,a.linkStrength=function(n){return arguments.length?(h="function"==typeof n?n:+n,a):h},a.friction=function(n){return arguments.length?(s=+n,a):s},a.charge=function(n){return arguments.length?(g="function"==typeof n?n:+n,a):g},a.chargeDistance=function(n){return arguments.length?(p=n*n,a):Math.sqrt(p)},a.gravity=function(n){return arguments.length?(v=+n,a):v},a.theta=function(n){return arguments.length?(d=n*n,a):Math.sqrt(d)},a.alpha=function(n){return arguments.length?(n=+n,r?r=n>0?n:0:n>0&&(c.start({type:"start",alpha:r=n}),ta.timer(a.tick)),a):r},a.start=function(){function n(n,r){if(!e){for(e=new Array(c),a=0;c>a;++a)e[a]=[];for(a=0;s>a;++a){var u=M[a];e[u.source.index].push(u.target),e[u.target.index].push(u.source)}}for(var i,o=e[t],a=-1,l=o.length;++a<l;)if(!isNaN(i=o[a][n]))return i;return Math.random()*r}var t,e,r,c=m.length,s=M.length,p=l[0],v=l[1];for(t=0;c>t;++t)(r=m[t]).index=t,r.weight=0;for(t=0;s>t;++t)r=M[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;c>t;++t)r=m[t],isNaN(r.x)&&(r.x=n("x",p)),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 f)for(t=0;s>t;++t)u[t]=+f.call(this,M[t],t);else for(t=0;s>t;++t)u[t]=f;if(i=[],"function"==typeof h)for(t=0;s>t;++t)i[t]=+h.call(this,M[t],t);else for(t=0;s>t;++t)i[t]=h;if(o=[],"function"==typeof g)for(t=0;c>t;++t)o[t]=+g.call(this,m[t],t);else for(t=0;c>t;++t)o[t]=g;return a.resume()},a.resume=function(){return a.alpha(.1)},a.stop=function(){return a.alpha(0)},a.drag=function(){return e||(e=ta.behavior.drag().origin(y).on("dragstart.force",Xu).on("drag.force",t).on("dragend.force",$u)),arguments.length?void this.on("mouseover.force",Bu).on("mouseout.force",Wu).call(e):e},ta.rebind(a,c,"on")};var fl=20,hl=1,gl=1/0;ta.layout.hierarchy=function(){function n(u){var i,o=[u],a=[];for(u.depth=0;null!=(i=o.pop());)if(a.push(i),(l=e.call(n,i,i.depth))&&(c=l.length)){for(var c,l,s;--c>=0;)o.push(s=l[c]),s.parent=i,s.depth=i.depth+1;r&&(i.value=0),i.children=l}else r&&(i.value=+r.call(n,i,i.depth)||0),delete i.children;return Qu(u,function(n){var e,u;t&&(e=n.children)&&e.sort(t),r&&(u=n.parent)&&(u.value+=n.value)}),a}var t=ei,e=ni,r=ti;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&&(Ku(t,function(n){n.children&&(n.value=0)}),Qu(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},ta.layout.partition=function(){function n(t,e,r,u){var i=t.children;if(t.x=e,t.y=t.depth*u,t.dx=r,t.dy=u,i&&(o=i.length)){var o,a,c,l=-1;for(r=t.value?r/t.value:0;++l<o;)n(a=i[l],e,c=a.value*r,u),e+=c}}function t(n){var e=n.children,r=0;if(e&&(u=e.length))for(var u,i=-1;++i<u;)r=Math.max(r,t(e[i]));return 1+r}function e(e,i){var o=r.call(this,e,i);return n(o[0],0,u[0],u[1]/t(o[0])),o}var r=ta.layout.hierarchy(),u=[1,1];return e.size=function(n){return arguments.length?(u=n,e):u},Gu(e,r)},ta.layout.pie=function(){function n(o){var a,c=o.length,l=o.map(function(e,r){return+t.call(n,e,r)}),s=+("function"==typeof r?r.apply(this,arguments):r),f=("function"==typeof u?u.apply(this,arguments):u)-s,h=Math.min(Math.abs(f)/c,+("function"==typeof i?i.apply(this,arguments):i)),g=h*(0>f?-1:1),p=(f-c*g)/ta.sum(l),v=ta.range(c),d=[];return null!=e&&v.sort(e===pl?function(n,t){return l[t]-l[n]}:function(n,t){return e(o[n],o[t])}),v.forEach(function(n){d[n]={data:o[n],value:a=l[n],startAngle:s,endAngle:s+=a*p+g,padAngle:h}}),d}var t=Number,e=pl,r=0,u=La,i=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?(u=t,n):u},n.padAngle=function(t){return arguments.length?(i=t,n):i},n};var pl={};ta.layout.stack=function(){function n(a,c){if(!(h=a.length))return a;var l=a.map(function(e,r){return t.call(n,e,r)}),s=l.map(function(t){return t.map(function(t,e){return[i.call(n,t,e),o.call(n,t,e)]})}),f=e.call(n,s,c);l=ta.permute(l,f),s=ta.permute(s,f);var h,g,p,v,d=r.call(n,s,c),m=l[0].length;for(p=0;m>p;++p)for(u.call(n,l[0][p],v=d[p],s[0][p][1]),g=1;h>g;++g)u.call(n,l[g][p],v+=s[g-1][p][1],s[g][p][1]);return a}var t=y,e=ai,r=ci,u=oi,i=ui,o=ii;return n.values=function(e){return arguments.length?(t=e,n):t},n.order=function(t){return arguments.length?(e="function"==typeof t?t:vl.get(t)||ai,n):e},n.offset=function(t){return arguments.length?(r="function"==typeof t?t:dl.get(t)||ci,n):r},n.x=function(t){return arguments.length?(i=t,n):i},n.y=function(t){return arguments.length?(o=t,n):o},n.out=function(t){return arguments.length?(u=t,n):u},n};var vl=ta.map({"inside-out":function(n){var t,e,r=n.length,u=n.map(li),i=n.map(si),o=ta.range(r).sort(function(n,t){return u[n]-u[t]}),a=0,c=0,l=[],s=[];for(t=0;r>t;++t)e=o[t],c>a?(a+=i[e],l.push(e)):(c+=i[e],s.push(e));return s.reverse().concat(l)},reverse:function(n){return ta.range(n.length).reverse()},"default":ai}),dl=ta.map({silhouette:function(n){var t,e,r,u=n.length,i=n[0].length,o=[],a=0,c=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];r>a&&(a=r),o.push(r)}for(e=0;i>e;++e)c[e]=(a-o[e])/2;return c},wiggle:function(n){var t,e,r,u,i,o,a,c,l,s=n.length,f=n[0],h=f.length,g=[];for(g[0]=c=l=0,e=1;h>e;++e){for(t=0,u=0;s>t;++t)u+=n[t][e][1];for(t=0,i=0,a=f[e][0]-f[e-1][0];s>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;i+=o*n[t][e][1]}g[e]=c-=u?i/u*a:0,l>c&&(l=c)}for(e=0;h>e;++e)g[e]-=l;return g},expand:function(n){var t,e,r,u=n.length,i=n[0].length,o=1/u,a=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];if(r)for(t=0;u>t;t++)n[t][e][1]/=r;else for(t=0;u>t;t++)n[t][e][1]=o}for(e=0;i>e;++e)a[e]=0;return a},zero:ci});ta.layout.histogram=function(){function n(n,i){for(var o,a,c=[],l=n.map(e,this),s=r.call(this,l,i),f=u.call(this,s,l,i),i=-1,h=l.length,g=f.length-1,p=t?1:1/h;++i<g;)o=c[i]=[],o.dx=f[i+1]-(o.x=f[i]),o.y=0;if(g>0)for(i=-1;++i<h;)a=l[i],a>=s[0]&&a<=s[1]&&(o=c[ta.bisect(f,a,1,g)-1],o.y+=p,o.push(n[i]));return c}var t=!0,e=Number,r=pi,u=hi;return n.value=function(t){return arguments.length?(e=t,n):e},n.range=function(t){return arguments.length?(r=Et(t),n):r},n.bins=function(t){return arguments.length?(u="number"==typeof t?function(n){return gi(n,t)}:Et(t),n):u},n.frequency=function(e){return arguments.length?(t=!!e,n):t},n},ta.layout.pack=function(){function n(n,i){var o=e.call(this,n,i),a=o[0],c=u[0],l=u[1],s=null==t?Math.sqrt:"function"==typeof t?t:function(){return t};if(a.x=a.y=0,Qu(a,function(n){n.r=+s(n.value)}),Qu(a,Mi),r){var f=r*(t?1:Math.max(2*a.r/c,2*a.r/l))/2;Qu(a,function(n){n.r+=f}),Qu(a,Mi),Qu(a,function(n){n.r-=f})}return _i(a,c/2,l/2,t?1:1/Math.max(2*a.r/c,2*a.r/l)),o}var t,e=ta.layout.hierarchy().sort(vi),r=0,u=[1,1];return n.size=function(t){return arguments.length?(u=t,n):u},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},Gu(n,e)},ta.layout.tree=function(){function n(n,u){var s=o.call(this,n,u),f=s[0],h=t(f);if(Qu(h,e),h.parent.m=-h.z,Ku(h,r),l)Ku(f,i);else{var g=f,p=f,v=f;Ku(f,function(n){n.x<g.x&&(g=n),n.x>p.x&&(p=n),n.depth>v.depth&&(v=n)});var d=a(g,p)/2-g.x,m=c[0]/(p.x+a(p,g)/2+d),y=c[1]/(v.depth||1);Ku(f,function(n){n.x=(n.x+d)*m,n.y=n.depth*y})}return s}function t(n){for(var t,e={A:null,children:[n]},r=[e];null!=(t=r.pop());)for(var u,i=t.children,o=0,a=i.length;a>o;++o)r.push((i[o]=u={_:i[o],parent:t,children:(u=i[o].children)&&u.slice()||[],A:null,a:null,z:0,m:0,c:0,s:0,t:null,i:o}).a=u);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){Ni(n);var i=(t[0].z+t[t.length-1].z)/2;r?(n.z=r.z+a(n._,r._),n.m=n.z-i):n.z=i}else r&&(n.z=r.z+a(n._,r._));n.parent.A=u(n,r,n.parent.A||e[0])}function r(n){n._.x=n.z+n.parent.m,n.m+=n.parent.m}function u(n,t,e){if(t){for(var r,u=n,i=n,o=t,c=u.parent.children[0],l=u.m,s=i.m,f=o.m,h=c.m;o=Ei(o),u=ki(u),o&&u;)c=ki(c),i=Ei(i),i.a=n,r=o.z+f-u.z-l+a(o._,u._),r>0&&(Ai(Ci(o,n,e),n,r),l+=r,s+=r),f+=o.m,l+=u.m,h+=c.m,s+=i.m;o&&!Ei(i)&&(i.t=o,i.m+=f-s),u&&!ki(c)&&(c.t=u,c.m+=l-h,e=n)}return e}function i(n){n.x*=c[0],n.y=n.depth*c[1]}var o=ta.layout.hierarchy().sort(null).value(null),a=Si,c=[1,1],l=null;return n.separation=function(t){return arguments.length?(a=t,n):a},n.size=function(t){return arguments.length?(l=null==(c=t)?i:null,n):l?null:c},n.nodeSize=function(t){return arguments.length?(l=null==(c=t)?null:i,n):l?c:null},Gu(n,o)},ta.layout.cluster=function(){function n(n,i){var o,a=t.call(this,n,i),c=a[0],l=0;Qu(c,function(n){var t=n.children;t&&t.length?(n.x=qi(t),n.y=zi(t)):(n.x=o?l+=e(n,o):0,n.y=0,o=n)});var s=Li(c),f=Ti(c),h=s.x-e(s,f)/2,g=f.x+e(f,s)/2;return Qu(c,u?function(n){n.x=(n.x-c.x)*r[0],n.y=(c.y-n.y)*r[1]}:function(n){n.x=(n.x-h)/(g-h)*r[0],n.y=(1-(c.y?n.y/c.y:1))*r[1]}),a}var t=ta.layout.hierarchy().sort(null).value(null),e=Si,r=[1,1],u=!1;return n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return arguments.length?(u=null==(r=t),n):u?null:r},n.nodeSize=function(t){return arguments.length?(u=null!=(r=t),n):u?r:null},Gu(n,t)},ta.layout.treemap=function(){function n(n,t){for(var e,r,u=-1,i=n.length;++u<i;)r=(e=n[u]).value*(0>t?0:t),e.area=isNaN(r)||0>=r?0:r}function t(e){var i=e.children;if(i&&i.length){var o,a,c,l=f(e),s=[],h=i.slice(),p=1/0,v="slice"===g?l.dx:"dice"===g?l.dy:"slice-dice"===g?1&e.depth?l.dy:l.dx:Math.min(l.dx,l.dy);for(n(h,l.dx*l.dy/e.value),s.area=0;(c=h.length)>0;)s.push(o=h[c-1]),s.area+=o.area,"squarify"!==g||(a=r(s,v))<=p?(h.pop(),p=a):(s.area-=s.pop().area,u(s,v,l,!1),v=Math.min(l.dx,l.dy),s.length=s.area=0,p=1/0);s.length&&(u(s,v,l,!0),s.length=s.area=0),i.forEach(t)}}function e(t){var r=t.children;if(r&&r.length){var i,o=f(t),a=r.slice(),c=[];for(n(a,o.dx*o.dy/t.value),c.area=0;i=a.pop();)c.push(i),c.area+=i.area,null!=i.z&&(u(c,i.z?o.dx:o.dy,o,!a.length),c.length=c.area=0);r.forEach(e)}}function r(n,t){for(var e,r=n.area,u=0,i=1/0,o=-1,a=n.length;++o<a;)(e=n[o].area)&&(i>e&&(i=e),e>u&&(u=e));return r*=r,t*=t,r?Math.max(t*u*p/r,r/(t*i*p)):1/0}function u(n,t,e,r){var u,i=-1,o=n.length,a=e.x,l=e.y,s=t?c(n.area/t):0;if(t==e.dx){for((r||s>e.dy)&&(s=e.dy);++i<o;)u=n[i],u.x=a,u.y=l,u.dy=s,a+=u.dx=Math.min(e.x+e.dx-a,s?c(u.area/s):0);u.z=!0,u.dx+=e.x+e.dx-a,e.y+=s,e.dy-=s}else{for((r||s>e.dx)&&(s=e.dx);++i<o;)u=n[i],u.x=a,u.y=l,u.dx=s,l+=u.dy=Math.min(e.y+e.dy-l,s?c(u.area/s):0);u.z=!1,u.dy+=e.y+e.dy-l,e.x+=s,e.dx-=s}}function i(r){var u=o||a(r),i=u[0];return i.x=0,i.y=0,i.dx=l[0],i.dy=l[1],o&&a.revalue(i),n([i],i.dx*i.dy/i.value),(o?e:t)(i),h&&(o=u),u}var o,a=ta.layout.hierarchy(),c=Math.round,l=[1,1],s=null,f=Ri,h=!1,g="squarify",p=.5*(1+Math.sqrt(5));
return i.size=function(n){return arguments.length?(l=n,i):l},i.padding=function(n){function t(t){var e=n.call(i,t,t.depth);return null==e?Ri(t):Di(t,"number"==typeof e?[e,e,e,e]:e)}function e(t){return Di(t,n)}if(!arguments.length)return s;var r;return f=null==(s=n)?Ri:"function"==(r=typeof n)?t:"number"===r?(n=[n,n,n,n],e):e,i},i.round=function(n){return arguments.length?(c=n?Math.round:Number,i):c!=Number},i.sticky=function(n){return arguments.length?(h=n,o=null,i):h},i.ratio=function(n){return arguments.length?(p=n,i):p},i.mode=function(n){return arguments.length?(g=n+"",i):g},Gu(i,a)},ta.random={normal:function(n,t){var e=arguments.length;return 2>e&&(t=1),1>e&&(n=0),function(){var e,r,u;do e=2*Math.random()-1,r=2*Math.random()-1,u=e*e+r*r;while(!u||u>1);return n+t*e*Math.sqrt(-2*Math.log(u)/u)}},logNormal:function(){var n=ta.random.normal.apply(ta,arguments);return function(){return Math.exp(n())}},bates:function(n){var t=ta.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}}},ta.scale={};var ml={floor:y,ceil:y};ta.scale.linear=function(){return Ii([0,1],[0,1],mu,!1)};var yl={s:1,g:1,p:1,r:1,e:1};ta.scale.log=function(){return Ji(ta.scale.linear().domain([0,1]),10,!0,[1,10])};var Ml=ta.format(".0e"),xl={floor:function(n){return-Math.ceil(-n)},ceil:function(n){return-Math.floor(-n)}};ta.scale.pow=function(){return Gi(ta.scale.linear(),1,[0,1])},ta.scale.sqrt=function(){return ta.scale.pow().exponent(.5)},ta.scale.ordinal=function(){return Qi([],{t:"range",a:[[]]})},ta.scale.category10=function(){return ta.scale.ordinal().range(bl)},ta.scale.category20=function(){return ta.scale.ordinal().range(_l)},ta.scale.category20b=function(){return ta.scale.ordinal().range(wl)},ta.scale.category20c=function(){return ta.scale.ordinal().range(Sl)};var bl=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map(Mt),_l=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map(Mt),wl=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map(Mt),Sl=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map(Mt);ta.scale.quantile=function(){return no([],[])},ta.scale.quantize=function(){return to(0,1,[0,1])},ta.scale.threshold=function(){return eo([.5],[0,1])},ta.scale.identity=function(){return ro([0,1])},ta.svg={},ta.svg.arc=function(){function n(){var n=Math.max(0,+e.apply(this,arguments)),l=Math.max(0,+r.apply(this,arguments)),s=o.apply(this,arguments)-Ra,f=a.apply(this,arguments)-Ra,h=Math.abs(f-s),g=s>f?0:1;if(n>l&&(p=l,l=n,n=p),h>=Ta)return t(l,g)+(n?t(n,1-g):"")+"Z";var p,v,d,m,y,M,x,b,_,w,S,k,E=0,A=0,N=[];if((m=(+c.apply(this,arguments)||0)/2)&&(d=i===kl?Math.sqrt(n*n+l*l):+i.apply(this,arguments),g||(A*=-1),l&&(A=tt(d/l*Math.sin(m))),n&&(E=tt(d/n*Math.sin(m)))),l){y=l*Math.cos(s+A),M=l*Math.sin(s+A),x=l*Math.cos(f-A),b=l*Math.sin(f-A);var C=Math.abs(f-s-2*A)<=qa?0:1;if(A&&so(y,M,x,b)===g^C){var z=(s+f)/2;y=l*Math.cos(z),M=l*Math.sin(z),x=b=null}}else y=M=0;if(n){_=n*Math.cos(f-E),w=n*Math.sin(f-E),S=n*Math.cos(s+E),k=n*Math.sin(s+E);var q=Math.abs(s-f+2*E)<=qa?0:1;if(E&&so(_,w,S,k)===1-g^q){var L=(s+f)/2;_=n*Math.cos(L),w=n*Math.sin(L),S=k=null}}else _=w=0;if((p=Math.min(Math.abs(l-n)/2,+u.apply(this,arguments)))>.001){v=l>n^g?0:1;var T=null==S?[_,w]:null==x?[y,M]:Lr([y,M],[S,k],[x,b],[_,w]),R=y-T[0],D=M-T[1],P=x-T[0],U=b-T[1],j=1/Math.sin(Math.acos((R*P+D*U)/(Math.sqrt(R*R+D*D)*Math.sqrt(P*P+U*U)))/2),F=Math.sqrt(T[0]*T[0]+T[1]*T[1]);if(null!=x){var H=Math.min(p,(l-F)/(j+1)),O=fo(null==S?[_,w]:[S,k],[y,M],l,H,g),I=fo([x,b],[_,w],l,H,g);p===H?N.push("M",O[0],"A",H,",",H," 0 0,",v," ",O[1],"A",l,",",l," 0 ",1-g^so(O[1][0],O[1][1],I[1][0],I[1][1]),",",g," ",I[1],"A",H,",",H," 0 0,",v," ",I[0]):N.push("M",O[0],"A",H,",",H," 0 1,",v," ",I[0])}else N.push("M",y,",",M);if(null!=S){var Y=Math.min(p,(n-F)/(j-1)),Z=fo([y,M],[S,k],n,-Y,g),V=fo([_,w],null==x?[y,M]:[x,b],n,-Y,g);p===Y?N.push("L",V[0],"A",Y,",",Y," 0 0,",v," ",V[1],"A",n,",",n," 0 ",g^so(V[1][0],V[1][1],Z[1][0],Z[1][1]),",",1-g," ",Z[1],"A",Y,",",Y," 0 0,",v," ",Z[0]):N.push("L",V[0],"A",Y,",",Y," 0 0,",v," ",Z[0])}else N.push("L",_,",",w)}else N.push("M",y,",",M),null!=x&&N.push("A",l,",",l," 0 ",C,",",g," ",x,",",b),N.push("L",_,",",w),null!=S&&N.push("A",n,",",n," 0 ",q,",",1-g," ",S,",",k);return N.push("Z"),N.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=io,r=oo,u=uo,i=kl,o=ao,a=co,c=lo;return n.innerRadius=function(t){return arguments.length?(e=Et(t),n):e},n.outerRadius=function(t){return arguments.length?(r=Et(t),n):r},n.cornerRadius=function(t){return arguments.length?(u=Et(t),n):u},n.padRadius=function(t){return arguments.length?(i=t==kl?kl:Et(t),n):i},n.startAngle=function(t){return arguments.length?(o=Et(t),n):o},n.endAngle=function(t){return arguments.length?(a=Et(t),n):a},n.padAngle=function(t){return arguments.length?(c=Et(t),n):c},n.centroid=function(){var n=(+e.apply(this,arguments)+ +r.apply(this,arguments))/2,t=(+o.apply(this,arguments)+ +a.apply(this,arguments))/2-Ra;return[Math.cos(t)*n,Math.sin(t)*n]},n};var kl="auto";ta.svg.line=function(){return ho(y)};var El=ta.map({linear:go,"linear-closed":po,step:vo,"step-before":mo,"step-after":yo,basis:So,"basis-open":ko,"basis-closed":Eo,bundle:Ao,cardinal:bo,"cardinal-open":Mo,"cardinal-closed":xo,monotone:To});El.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)});var Al=[0,2/3,1/3,0],Nl=[0,1/3,2/3,0],Cl=[0,1/6,2/3,1/6];ta.svg.line.radial=function(){var n=ho(Ro);return n.radius=n.x,delete n.x,n.angle=n.y,delete n.y,n},mo.reverse=yo,yo.reverse=mo,ta.svg.area=function(){return Do(y)},ta.svg.area.radial=function(){var n=Do(Ro);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},ta.svg.chord=function(){function n(n,a){var c=t(this,i,n,a),l=t(this,o,n,a);return"M"+c.p0+r(c.r,c.p1,c.a1-c.a0)+(e(c,l)?u(c.r,c.p1,c.r,c.p0):u(c.r,c.p1,l.r,l.p0)+r(l.r,l.p1,l.a1-l.a0)+u(l.r,l.p1,c.r,c.p0))+"Z"}function t(n,t,e,r){var u=t.call(n,e,r),i=a.call(n,u,r),o=c.call(n,u,r)-Ra,s=l.call(n,u,r)-Ra;return{r:i,a0:o,a1:s,p0:[i*Math.cos(o),i*Math.sin(o)],p1:[i*Math.cos(s),i*Math.sin(s)]}}function e(n,t){return n.a0==t.a0&&n.a1==t.a1}function r(n,t,e){return"A"+n+","+n+" 0 "+ +(e>qa)+",1 "+t}function u(n,t,e,r){return"Q 0,0 "+r}var i=mr,o=yr,a=Po,c=ao,l=co;return n.radius=function(t){return arguments.length?(a=Et(t),n):a},n.source=function(t){return arguments.length?(i=Et(t),n):i},n.target=function(t){return arguments.length?(o=Et(t),n):o},n.startAngle=function(t){return arguments.length?(c=Et(t),n):c},n.endAngle=function(t){return arguments.length?(l=Et(t),n):l},n},ta.svg.diagonal=function(){function n(n,u){var i=t.call(this,n,u),o=e.call(this,n,u),a=(i.y+o.y)/2,c=[i,{x:i.x,y:a},{x:o.x,y:a},o];return c=c.map(r),"M"+c[0]+"C"+c[1]+" "+c[2]+" "+c[3]}var t=mr,e=yr,r=Uo;return n.source=function(e){return arguments.length?(t=Et(e),n):t},n.target=function(t){return arguments.length?(e=Et(t),n):e},n.projection=function(t){return arguments.length?(r=t,n):r},n},ta.svg.diagonal.radial=function(){var n=ta.svg.diagonal(),t=Uo,e=n.projection;return n.projection=function(n){return arguments.length?e(jo(t=n)):t},n},ta.svg.symbol=function(){function n(n,r){return(zl.get(t.call(this,n,r))||Oo)(e.call(this,n,r))}var t=Ho,e=Fo;return n.type=function(e){return arguments.length?(t=Et(e),n):t},n.size=function(t){return arguments.length?(e=Et(t),n):e},n};var zl=ta.map({circle:Oo,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*Ll)),e=t*Ll;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/ql),e=t*ql/2;return"M0,"+e+"L"+t+","+-e+" "+-t+","+-e+"Z"},"triangle-up":function(n){var t=Math.sqrt(n/ql),e=t*ql/2;return"M0,"+-e+"L"+t+","+e+" "+-t+","+e+"Z"}});ta.svg.symbolTypes=zl.keys();var ql=Math.sqrt(3),Ll=Math.tan(30*Da);_a.transition=function(n){for(var t,e,r=Tl||++Ul,u=Xo(n),i=[],o=Rl||{time:Date.now(),ease:Su,delay:0,duration:250},a=-1,c=this.length;++a<c;){i.push(t=[]);for(var l=this[a],s=-1,f=l.length;++s<f;)(e=l[s])&&$o(e,s,u,r,o),t.push(e)}return Yo(i,u,r)},_a.interrupt=function(n){return this.each(null==n?Dl:Io(Xo(n)))};var Tl,Rl,Dl=Io(Xo()),Pl=[],Ul=0;Pl.call=_a.call,Pl.empty=_a.empty,Pl.node=_a.node,Pl.size=_a.size,ta.transition=function(n,t){return n&&n.transition?Tl?n.transition(t):n:ta.selection().transition(n)},ta.transition.prototype=Pl,Pl.select=function(n){var t,e,r,u=this.id,i=this.namespace,o=[];n=N(n);for(var a=-1,c=this.length;++a<c;){o.push(t=[]);for(var l=this[a],s=-1,f=l.length;++s<f;)(r=l[s])&&(e=n.call(r,r.__data__,s,a))?("__data__"in r&&(e.__data__=r.__data__),$o(e,s,i,u,r[i][u]),t.push(e)):t.push(null)}return Yo(o,i,u)},Pl.selectAll=function(n){var t,e,r,u,i,o=this.id,a=this.namespace,c=[];n=C(n);for(var l=-1,s=this.length;++l<s;)for(var f=this[l],h=-1,g=f.length;++h<g;)if(r=f[h]){i=r[a][o],e=n.call(r,r.__data__,h,l),c.push(t=[]);for(var p=-1,v=e.length;++p<v;)(u=e[p])&&$o(u,p,a,o,i),t.push(u)}return Yo(c,a,o)},Pl.filter=function(n){var t,e,r,u=[];"function"!=typeof n&&(n=O(n));for(var i=0,o=this.length;o>i;i++){u.push(t=[]);for(var e=this[i],a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return Yo(u,this.namespace,this.id)},Pl.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(u){u[r][e].tween.set(n,t)})},Pl.attr=function(n,t){function e(){this.removeAttribute(a)}function r(){this.removeAttributeNS(a.space,a.local)}function u(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 i(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?Hu:mu,a=ta.ns.qualify(n);return Zo(this,"attr."+n,t,a.local?i:u)},Pl.attrTween=function(n,t){function e(n,e){var r=t.call(this,n,e,this.getAttribute(u));return r&&function(n){this.setAttribute(u,r(n))}}function r(n,e){var r=t.call(this,n,e,this.getAttributeNS(u.space,u.local));return r&&function(n){this.setAttributeNS(u.space,u.local,r(n))}}var u=ta.ns.qualify(n);return this.tween("attr."+n,u.local?r:e)},Pl.style=function(n,e,r){function u(){this.style.removeProperty(n)}function i(e){return null==e?u:(e+="",function(){var u,i=t(this).getComputedStyle(this,null).getPropertyValue(n);return i!==e&&(u=mu(i,e),function(t){this.style.setProperty(n,u(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 Zo(this,"style."+n,e,i)},Pl.styleTween=function(n,e,r){function u(u,i){var o=e.call(this,u,i,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,u)},Pl.text=function(n){return Zo(this,"text",n,Vo)},Pl.remove=function(){var n=this.namespace;return this.each("end.transition",function(){var t;this[n].count<2&&(t=this.parentNode)&&t.removeChild(this)})},Pl.ease=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].ease:("function"!=typeof n&&(n=ta.ease.apply(ta,arguments)),Y(this,function(r){r[e][t].ease=n}))},Pl.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,u,i){r[e][t].delay=+n.call(r,r.__data__,u,i)}:(n=+n,function(r){r[e][t].delay=n}))},Pl.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,u,i){r[e][t].duration=Math.max(1,n.call(r,r.__data__,u,i))}:(n=Math.max(1,n),function(r){r[e][t].duration=n}))},Pl.each=function(n,t){var e=this.id,r=this.namespace;if(arguments.length<2){var u=Rl,i=Tl;try{Tl=e,Y(this,function(t,u,i){Rl=t[r][e],n.call(t,t.__data__,u,i)})}finally{Rl=u,Tl=i}}else Y(this,function(u){var i=u[r][e];(i.event||(i.event=ta.dispatch("start","end","interrupt"))).on(n,t)});return this},Pl.transition=function(){for(var n,t,e,r,u=this.id,i=++Ul,o=this.namespace,a=[],c=0,l=this.length;l>c;c++){a.push(n=[]);for(var t=this[c],s=0,f=t.length;f>s;s++)(e=t[s])&&(r=e[o][u],$o(e,s,o,i,{time:r.time,ease:r.ease,delay:r.delay+r.duration,duration:r.duration})),n.push(e)}return Yo(a,o,i)},ta.svg.axis=function(){function n(n){n.each(function(){var n,l=ta.select(this),s=this.__chart__||e,f=this.__chart__=e.copy(),h=null==c?f.ticks?f.ticks.apply(f,a):f.domain():c,g=null==t?f.tickFormat?f.tickFormat.apply(f,a):y:t,p=l.selectAll(".tick").data(h,f),v=p.enter().insert("g",".domain").attr("class","tick").style("opacity",Ca),d=ta.transition(p.exit()).style("opacity",Ca).remove(),m=ta.transition(p.order()).style("opacity",1),M=Math.max(u,0)+o,x=Ui(f),b=l.selectAll(".domain").data([0]),_=(b.enter().append("path").attr("class","domain"),ta.transition(b));v.append("line"),v.append("text");var w,S,k,E,A=v.select("line"),N=m.select("line"),C=p.select("text").text(g),z=v.select("text"),q=m.select("text"),L="top"===r||"left"===r?-1:1;if("bottom"===r||"top"===r?(n=Bo,w="x",k="y",S="x2",E="y2",C.attr("dy",0>L?"0em":".71em").style("text-anchor","middle"),_.attr("d","M"+x[0]+","+L*i+"V0H"+x[1]+"V"+L*i)):(n=Wo,w="y",k="x",S="y2",E="x2",C.attr("dy",".32em").style("text-anchor",0>L?"end":"start"),_.attr("d","M"+L*i+","+x[0]+"H0V"+x[1]+"H"+L*i)),A.attr(E,L*u),z.attr(k,L*M),N.attr(S,0).attr(E,L*u),q.attr(w,0).attr(k,L*M),f.rangeBand){var T=f,R=T.rangeBand()/2;s=f=function(n){return T(n)+R}}else s.rangeBand?s=f:d.call(n,f,s);v.call(n,s,f),m.call(n,f,f)})}var t,e=ta.scale.linear(),r=jl,u=6,i=6,o=3,a=[10],c=null;return n.scale=function(t){return arguments.length?(e=t,n):e},n.orient=function(t){return arguments.length?(r=t in Fl?t+"":jl,n):r},n.ticks=function(){return arguments.length?(a=arguments,n):a},n.tickValues=function(t){return arguments.length?(c=t,n):c},n.tickFormat=function(e){return arguments.length?(t=e,n):t},n.tickSize=function(t){var e=arguments.length;return e?(u=+t,i=+arguments[e-1],n):u},n.innerTickSize=function(t){return arguments.length?(u=+t,n):u},n.outerTickSize=function(t){return arguments.length?(i=+t,n):i},n.tickPadding=function(t){return arguments.length?(o=+t,n):o},n.tickSubdivide=function(){return arguments.length&&n},n};var jl="bottom",Fl={top:1,right:1,bottom:1,left:1};ta.svg.brush=function(){function n(t){t.each(function(){var t=ta.select(this).style("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush",i).on("touchstart.brush",i),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,y);a.exit().remove(),a.enter().append("g").attr("class",function(n){return"resize "+n}).style("cursor",function(n){return Hl[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 c,f=ta.transition(t),h=ta.transition(o);l&&(c=Ui(l),h.attr("x",c[0]).attr("width",c[1]-c[0]),r(f)),s&&(c=Ui(s),h.attr("y",c[0]).attr("height",c[1]-c[0]),u(f)),e(f)})}function e(n){n.selectAll(".resize").attr("transform",function(n){return"translate("+f[+/e$/.test(n)]+","+h[+/^s/.test(n)]+")"})}function r(n){n.select(".extent").attr("x",f[0]),n.selectAll(".extent,.n>rect,.s>rect").attr("width",f[1]-f[0])}function u(n){n.select(".extent").attr("y",h[0]),n.selectAll(".extent,.e>rect,.w>rect").attr("height",h[1]-h[0])}function i(){function i(){32==ta.event.keyCode&&(C||(M=null,q[0]-=f[1],q[1]-=h[1],C=2),S())}function v(){32==ta.event.keyCode&&2==C&&(q[0]+=f[1],q[1]+=h[1],C=0,S())}function d(){var n=ta.mouse(b),t=!1;x&&(n[0]+=x[0],n[1]+=x[1]),C||(ta.event.altKey?(M||(M=[(f[0]+f[1])/2,(h[0]+h[1])/2]),q[0]=f[+(n[0]<M[0])],q[1]=h[+(n[1]<M[1])]):M=null),A&&m(n,l,0)&&(r(k),t=!0),N&&m(n,s,1)&&(u(k),t=!0),t&&(e(k),w({type:"brush",mode:C?"move":"resize"}))}function m(n,t,e){var r,u,i=Ui(t),c=i[0],l=i[1],s=q[e],v=e?h:f,d=v[1]-v[0];return C&&(c-=s,l-=d+s),r=(e?p:g)?Math.max(c,Math.min(l,n[e])):n[e],C?u=(r+=s)+d:(M&&(s=Math.max(c,Math.min(l,2*M[e]-r))),r>s?(u=r,r=s):u=s),v[0]!=r||v[1]!=u?(e?a=null:o=null,v[0]=r,v[1]=u,!0):void 0}function y(){d(),k.style("pointer-events","all").selectAll(".resize").style("display",n.empty()?"none":null),ta.select("body").style("cursor",null),L.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,_=ta.select(ta.event.target),w=c.of(b,arguments),k=ta.select(b),E=_.datum(),A=!/^(n|s)$/.test(E)&&l,N=!/^(e|w)$/.test(E)&&s,C=_.classed("extent"),z=W(b),q=ta.mouse(b),L=ta.select(t(b)).on("keydown.brush",i).on("keyup.brush",v);if(ta.event.changedTouches?L.on("touchmove.brush",d).on("touchend.brush",y):L.on("mousemove.brush",d).on("mouseup.brush",y),k.interrupt().selectAll("*").interrupt(),C)q[0]=f[0]-q[0],q[1]=h[0]-q[1];else if(E){var T=+/w$/.test(E),R=+/^n/.test(E);x=[f[1-T]-q[0],h[1-R]-q[1]],q[0]=f[T],q[1]=h[R]}else ta.event.altKey&&(M=q.slice());k.style("pointer-events","none").selectAll(".resize").style("display",null),ta.select("body").style("cursor",_.style("cursor")),w({type:"brushstart"}),d()}var o,a,c=E(n,"brushstart","brush","brushend"),l=null,s=null,f=[0,0],h=[0,0],g=!0,p=!0,v=Ol[0];return n.event=function(n){n.each(function(){var n=c.of(this,arguments),t={x:f,y:h,i:o,j:a},e=this.__chart__||t;this.__chart__=t,Tl?ta.select(this).transition().each("start.brush",function(){o=e.i,a=e.j,f=e.x,h=e.y,n({type:"brushstart"})}).tween("brush:brush",function(){var e=yu(f,t.x),r=yu(h,t.y);return o=a=null,function(u){f=t.x=e(u),h=t.y=r(u),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?(l=t,v=Ol[!l<<1|!s],n):l},n.y=function(t){return arguments.length?(s=t,v=Ol[!l<<1|!s],n):s},n.clamp=function(t){return arguments.length?(l&&s?(g=!!t[0],p=!!t[1]):l?g=!!t:s&&(p=!!t),n):l&&s?[g,p]:l?g:s?p:null},n.extent=function(t){var e,r,u,i,c;return arguments.length?(l&&(e=t[0],r=t[1],s&&(e=e[0],r=r[0]),o=[e,r],l.invert&&(e=l(e),r=l(r)),e>r&&(c=e,e=r,r=c),(e!=f[0]||r!=f[1])&&(f=[e,r])),s&&(u=t[0],i=t[1],l&&(u=u[1],i=i[1]),a=[u,i],s.invert&&(u=s(u),i=s(i)),u>i&&(c=u,u=i,i=c),(u!=h[0]||i!=h[1])&&(h=[u,i])),n):(l&&(o?(e=o[0],r=o[1]):(e=f[0],r=f[1],l.invert&&(e=l.invert(e),r=l.invert(r)),e>r&&(c=e,e=r,r=c))),s&&(a?(u=a[0],i=a[1]):(u=h[0],i=h[1],s.invert&&(u=s.invert(u),i=s.invert(i)),u>i&&(c=u,u=i,i=c))),l&&s?[[e,u],[r,i]]:l?[e,r]:s&&[u,i])},n.clear=function(){return n.empty()||(f=[0,0],h=[0,0],o=a=null),n},n.empty=function(){return!!l&&f[0]==f[1]||!!s&&h[0]==h[1]},ta.rebind(n,c,"on")};var Hl={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Ol=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],Il=ac.format=gc.timeFormat,Yl=Il.utc,Zl=Yl("%Y-%m-%dT%H:%M:%S.%LZ");Il.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?Jo:Zl,Jo.parse=function(n){var t=new Date(n);return isNaN(t)?null:t},Jo.toString=Zl.toString,ac.second=Ft(function(n){return new cc(1e3*Math.floor(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return n.getSeconds()}),ac.seconds=ac.second.range,ac.seconds.utc=ac.second.utc.range,ac.minute=Ft(function(n){return new cc(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return n.getMinutes()}),ac.minutes=ac.minute.range,ac.minutes.utc=ac.minute.utc.range,ac.hour=Ft(function(n){var t=n.getTimezoneOffset()/60;return new cc(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return n.getHours()}),ac.hours=ac.hour.range,ac.hours.utc=ac.hour.utc.range,ac.month=Ft(function(n){return n=ac.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return n.getMonth()}),ac.months=ac.month.range,ac.months.utc=ac.month.utc.range;var Vl=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],Xl=[[ac.second,1],[ac.second,5],[ac.second,15],[ac.second,30],[ac.minute,1],[ac.minute,5],[ac.minute,15],[ac.minute,30],[ac.hour,1],[ac.hour,3],[ac.hour,6],[ac.hour,12],[ac.day,1],[ac.day,2],[ac.week,1],[ac.month,1],[ac.month,3],[ac.year,1]],$l=Il.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",Ne]]),Bl={range:function(n,t,e){return ta.range(Math.ceil(n/e)*e,+t,e).map(Ko)},floor:y,ceil:y};Xl.year=ac.year,ac.scale=function(){return Go(ta.scale.linear(),Xl,$l)};var Wl=Xl.map(function(n){return[n[0].utc,n[1]]}),Jl=Yl.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",Ne]]);Wl.year=ac.year.utc,ac.scale.utc=function(){return Go(ta.scale.linear(),Wl,Jl)},ta.text=At(function(n){return n.responseText}),ta.json=function(n,t){return Nt(n,"application/json",Qo,t)},ta.html=function(n,t){return Nt(n,"text/html",na,t)},ta.xml=At(function(n){return n.responseXML}),"function"==typeof define&&define.amd?define(ta):"object"==typeof module&&module.exports&&(module.exports=ta),this.d3=ta}();/*!
 * Bootstrap v3.3.4 (http://getbootstrap.com)
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 */
if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.4",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.4",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active"));a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.4",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.4",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=c(d),f={relatedTarget:this};e.hasClass("open")&&(e.trigger(b=a.Event("hide.bs.dropdown",f)),b.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f)))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.4",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('<div class="dropdown-backdrop"/>').insertAfter(a(this)).on("click",b);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger("shown.bs.dropdown",h)}return!1}},g.prototype.keydown=function(b){if(/(38|40|27|32)/.test(b.which)&&!/input|textarea/i.test(b.target.tagName)){var d=a(this);if(b.preventDefault(),b.stopPropagation(),!d.is(".disabled, :disabled")){var e=c(d),g=e.hasClass("open");if(!g&&27!=b.which||g&&27==b.which)return 27==b.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find('[role="menu"]'+h+', [role="listbox"]'+h);if(i.length){var j=i.index(b.target);38==b.which&&j>0&&j--,40==b.which&&j<i.length-1&&j++,~j||(j=0),i.eq(j).trigger("focus")}}}};var h=a.fn.dropdown;a.fn.dropdown=d,a.fn.dropdown.Constructor=g,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=h,this},a(document).on("click.bs.dropdown.data-api",b).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",f,g.prototype.toggle).on("keydown.bs.dropdown.data-api",f,g.prototype.keydown).on("keydown.bs.dropdown.data-api",'[role="menu"]',g.prototype.keydown).on("keydown.bs.dropdown.data-api",'[role="listbox"]',g.prototype.keydown)}(jQuery),+function(a){"use strict";function b(b,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},c.DEFAULTS,e.data(),"object"==typeof b&&b);f||e.data("bs.modal",f=new c(this,g)),"string"==typeof b?f[b](d):g.show&&f.show(d)})}var c=function(b,c){this.options=c,this.$body=a(document.body),this.$element=a(b),this.$dialog=this.$element.find(".modal-dialog"),this.$backdrop=null,this.isShown=null,this.originalBodyPad=null,this.scrollbarWidth=0,this.ignoreBackdropClick=!1,this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};c.VERSION="3.3.4",c.TRANSITION_DURATION=300,c.BACKDROP_TRANSITION_DURATION=150,c.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},c.prototype.toggle=function(a){return this.isShown?this.hide():this.show(a)},c.prototype.show=function(b){var d=this,e=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(e),this.isShown||e.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.setScrollbar(),this.$body.addClass("modal-open"),this.escape(),this.resize(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.$dialog.on("mousedown.dismiss.bs.modal",function(){d.$element.one("mouseup.dismiss.bs.modal",function(b){a(b.target).is(d.$element)&&(d.ignoreBackdropClick=!0)})}),this.backdrop(function(){var e=a.support.transition&&d.$element.hasClass("fade");d.$element.parent().length||d.$element.appendTo(d.$body),d.$element.show().scrollTop(0),d.adjustDialog(),e&&d.$element[0].offsetWidth,d.$element.addClass("in").attr("aria-hidden",!1),d.enforceFocus();var f=a.Event("shown.bs.modal",{relatedTarget:b});e?d.$dialog.one("bsTransitionEnd",function(){d.$element.trigger("focus").trigger(f)}).emulateTransitionEnd(c.TRANSITION_DURATION):d.$element.trigger("focus").trigger(f)}))},c.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),this.resize(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").attr("aria-hidden",!0).off("click.dismiss.bs.modal").off("mouseup.dismiss.bs.modal"),this.$dialog.off("mousedown.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",a.proxy(this.hideModal,this)).emulateTransitionEnd(c.TRANSITION_DURATION):this.hideModal())},c.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.trigger("focus")},this))},c.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keydown.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keydown.dismiss.bs.modal")},c.prototype.resize=function(){this.isShown?a(window).on("resize.bs.modal",a.proxy(this.handleUpdate,this)):a(window).off("resize.bs.modal")},c.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.$body.removeClass("modal-open"),a.resetAdjustments(),a.resetScrollbar(),a.$element.trigger("hidden.bs.modal")})},c.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},c.prototype.backdrop=function(b){var d=this,e=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var f=a.support.transition&&e;if(this.$backdrop=a('<div class="modal-backdrop '+e+'" />').appendTo(this.$body),this.$element.on("click.dismiss.bs.modal",a.proxy(function(a){return this.ignoreBackdropClick?void(this.ignoreBackdropClick=!1):void(a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus():this.hide()))},this)),f&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;f?this.$backdrop.one("bsTransitionEnd",b).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):b()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var g=function(){d.removeBackdrop(),b&&b()};a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",g).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):g()}else b&&b()},c.prototype.handleUpdate=function(){this.adjustDialog()},c.prototype.adjustDialog=function(){var a=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth<a,this.scrollbarWidth=this.measureScrollbar()},c.prototype.setScrollbar=function(){var a=parseInt(this.$body.css("padding-right")||0,10);this.originalBodyPad=document.body.style.paddingRight||"",this.bodyIsOverflowing&&this.$body.css("padding-right",a+this.scrollbarWidth)},c.prototype.resetScrollbar=function(){this.$body.css("padding-right",this.originalBodyPad)},c.prototype.measureScrollbar=function(){var a=document.createElement("div");a.className="modal-scrollbar-measure",this.$body.append(a);var b=a.offsetWidth-a.clientWidth;return this.$body[0].removeChild(a),b};var d=a.fn.modal;a.fn.modal=b,a.fn.modal.Constructor=c,a.fn.modal.noConflict=function(){return a.fn.modal=d,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(c){var d=a(this),e=d.attr("href"),f=a(d.attr("data-target")||e&&e.replace(/.*(?=#[^\s]+$)/,"")),g=f.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(e)&&e},f.data(),d.data());d.is("a")&&c.preventDefault(),f.one("show.bs.modal",function(a){a.isDefaultPrevented()||f.one("hidden.bs.modal",function(){d.is(":visible")&&d.trigger("focus")})}),b.call(f,g,this)})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.tooltip",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.type=null,this.options=null,this.enabled=null,this.timeout=null,this.hoverState=null,this.$element=null,this.init("tooltip",a,b)};c.VERSION="3.3.4",c.TRANSITION_DURATION=150,c.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(this.options.viewport.selector||this.options.viewport),this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c&&c.$tip&&c.$tip.is(":visible")?void(c.hoverState="in"):(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.options.container?a(this.options.container):this.$element.parent(),p=this.getPosition(o);h="bottom"==h&&k.bottom+m>p.bottom?"top":"top"==h&&k.top-m<p.top?"bottom":"right"==h&&k.right+l>p.width?"left":"left"==h&&k.left-l<p.left?"right":h,f.removeClass(n).addClass(h)}var q=this.getCalculatedOffset(h,k,l,m);this.applyPlacement(q,h);var r=function(){var a=e.hoverState;e.$element.trigger("shown.bs."+e.type),e.hoverState=null,"out"==a&&e.leave(e)};a.support.transition&&this.$tip.hasClass("fade")?f.one("bsTransitionEnd",r).emulateTransitionEnd(c.TRANSITION_DURATION):r()}},c.prototype.applyPlacement=function(b,c){var d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),b.top=b.top+g,b.left=b.left+h,a.offset.setOffset(d[0],a.extend({using:function(a){d.css({top:Math.round(a.top),left:Math.round(a.left)})}},b),0),d.addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;"top"==c&&j!=f&&(b.top=b.top+f-j);var k=this.getViewportAdjustedDelta(c,b,i,j);k.left?b.left+=k.left:b.top+=k.top;var l=/top|bottom/.test(c),m=l?2*k.left-e+i:2*k.top-f+j,n=l?"offsetWidth":"offsetHeight";d.offset(b),this.replaceArrow(m,d[0][n],l)},c.prototype.replaceArrow=function(a,b,c){this.arrow().css(c?"left":"top",50*(1-a/b)+"%").css(c?"top":"left","")},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},c.prototype.hide=function(b){function d(){"in"!=e.hoverState&&f.detach(),e.$element.removeAttr("aria-describedby").trigger("hidden.bs."+e.type),b&&b()}var e=this,f=a(this.$tip),g=a.Event("hide.bs."+this.type);return this.$element.trigger(g),g.isDefaultPrevented()?void 0:(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one("bsTransitionEnd",d).emulateTransitionEnd(c.TRANSITION_DURATION):d(),this.hoverState=null,this)},c.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},c.prototype.hasContent=function(){return this.getTitle()},c.prototype.getPosition=function(b){b=b||this.$element;var c=b[0],d="BODY"==c.tagName,e=c.getBoundingClientRect();null==e.width&&(e=a.extend({},e,{width:e.right-e.left,height:e.bottom-e.top}));var f=d?{top:0,left:0}:b.offset(),g={scroll:d?document.documentElement.scrollTop||document.body.scrollTop:b.scrollTop()},h=d?{width:a(window).width(),height:a(window).height()}:null;return a.extend({},e,g,h,f)},c.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},c.prototype.getViewportAdjustedDelta=function(a,b,c,d){var e={top:0,left:0};if(!this.$viewport)return e;var f=this.options.viewport&&this.options.viewport.padding||0,g=this.getPosition(this.$viewport);if(/right|left/.test(a)){var h=b.top-f-g.scroll,i=b.top+f-g.scroll+d;h<g.top?e.top=g.top-h:i>g.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;j<g.left?e.left=g.left-j:k>g.width&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type)})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.4",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.4",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b<e[0])return this.activeTarget=null,this.clear();for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(void 0===e[a+1]||b<e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,this.clear();var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.3.4",c.TRANSITION_DURATION=150,c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){
var e=c.find(".active:last a"),f=a.Event("hide.bs.tab",{relatedTarget:b[0]}),g=a.Event("show.bs.tab",{relatedTarget:e[0]});if(e.trigger(f),b.trigger(g),!g.isDefaultPrevented()&&!f.isDefaultPrevented()){var h=a(d);this.activate(b.closest("li"),c),this.activate(h,h.parent(),function(){e.trigger({type:"hidden.bs.tab",relatedTarget:b[0]}),b.trigger({type:"shown.bs.tab",relatedTarget:e[0]})})}}},c.prototype.activate=function(b,d,e){function f(){g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.4",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=a(document.body).height();"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery);/* nvd3 version 1.8.1 (https://github.com/novus/nvd3) 2015-06-17 */
!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),k.pointActive(function(){return!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}},focusMargin:{get:function(){return x},set:function(a){x.top=void 0!==a.top?a.top:x.top,x.right=void 0!==a.right?a.right:x.right,x.bottom=void 0!==a.bottom?a.bottom:x.bottom,x.left=void 0!==a.left?a.left:x.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),h.pointActive(function(){return!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}},focusMargin:{get:function(){return r},set:function(a){r.top=void 0!==a.top?a.top:r.top,r.right=void 0!==a.right?a.right:r.right,r.bottom=void 0!==a.bottom?a.bottom:r.bottom,r.left=void 0!==a.left?a.left:r.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(G){return E.reset(),G.each(function(b){var G=k-j.left-j.right,H=l-j.top-j.bottom;p=d3.select(this),a.utils.initSVG(p);var I=0;if(z&&b.length&&(z=[{values:b[0].values.map(function(a){return{x:a.x,y:0,series:a.series,size:.01}})}]),v){var J=d3.layout.stack().offset(w).values(function(a){return a.values}).y(r)(!b.length&&z?z:b);J.forEach(function(a,c){a.nonStackable?(b[c].nonStackableSeries=I++,J[c]=b[c]):c>0&&J[c-1].nonStackable&&J[c].values.map(function(a,b){a.y0-=J[c-1].values[b].y,a.y1=a.y0+a.y})}),b=J}b.forEach(function(a,b){a.values.forEach(function(c){c.series=b,c.key=a.key})}),v&&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 K=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,yErr:s(a,c)}})});m.domain(d||d3.merge(K).map(function(a){return a.x})).rangeBands(f||[0,G],C),n.domain(e||d3.extent(d3.merge(d3.merge(K).map(function(a){var c=a.y;v&&!b[a.idx].nonStackable&&(c=a.y>0?a.y1:a.y1+a.y);var d=a.yErr;return d?d.length?[c+d[0],c+d[1]]:(d=Math.abs(d),[c-d,c+d]):[c]})).concat(t))).range(g||[H,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 L=p.selectAll("g.nv-wrap.nv-multibar").data([b]),M=L.enter().append("g").attr("class","nvd3 nv-wrap nv-multibar"),N=M.append("defs"),O=M.append("g"),P=L.select("g");O.append("g").attr("class","nv-groups"),L.attr("transform","translate("+j.left+","+j.top+")"),N.append("clipPath").attr("id","nv-edge-clip-"+o).append("rect"),L.select("#nv-edge-clip-"+o+" rect").attr("width",G).attr("height",H),P.attr("clip-path",u?"url(#nv-edge-clip-"+o+")":"");var Q=L.select(".nv-groups").selectAll(".nv-group").data(function(a){return a},function(a,b){return b});Q.enter().append("g").style("stroke-opacity",1e-6).style("fill-opacity",1e-6);var R=E.transition(Q.exit().selectAll("g.nv-bar"),"multibarExit",Math.min(100,B)).attr("y",function(a){var c=i(0)||0;return v&&b[a.series]&&!b[a.series].nonStackable&&(c=i(a.y0)),c}).attr("height",0).remove();R.delay&&R.delay(function(a,b){var c=b*(B/(F+1))-b;return c}),Q.attr("class",function(a,b){return"nv-group nv-series-"+b}).classed("hover",function(a){return a.hover}).style("fill",function(a,b){return x(a,b)}).style("stroke",function(a,b){return x(a,b)}),Q.style("stroke-opacity",1).style("fill-opacity",.75);var S=Q.selectAll("g.nv-bar").data(function(a){return z&&!b.length?z.values:a.values});S.exit().remove();var T=S.enter().append("g").attr("class",function(a,b){return r(a,b)<0?"nv-bar negative":"nv-bar positive"}).attr("transform",function(a,c,d){var e=v&&!b[d].nonStackable?0:d*m.rangeBand()/b.length,f=i(v&&!b[d].nonStackable?a.y0:0)||0;return"translate("+e+","+f+")"});T.append("rect").attr("height",0).attr("width",function(a,c,d){return m.rangeBand()/(v&&!b[d].nonStackable?1:b.length)}).style("fill",function(a,b,c){return x(a,c,b)}).style("stroke",function(a,b,c){return x(a,c,b)}),S.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("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].values[0],0)&&(T.append("polyline"),S.select("polyline").attr("fill","none").attr("stroke",function(a,b,c){return y(a,c,b)}).attr("points",function(a,c){var d=s(a,c),e=.8*m.rangeBand()/(2*(v?1:b.length));d=d.length?d:[-Math.abs(d),Math.abs(d)],d=d.map(function(a){return n(a)-n(0)});var f=[[-e,d[0]],[e,d[0]],[0,d[0]],[0,d[1]],[-e,d[1]],[e,d[1]]];return f.map(function(a){return a.join(",")}).join(" ")}).attr("transform",function(a,c){var d=m.rangeBand()/(2*(v?1:b.length)),e=r(a,c)<0?n(r(a,c))-n(0):0;return"translate("+d+", "+e+")"})),S.attr("class",function(a,b){return r(a,b)<0?"nv-bar negative":"nv-bar positive"}),A&&(c||(c=b.map(function(){return!0})),S.select("rect").style("fill",function(a,b,d){return d3.rgb(A(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(A(a,b)).darker(c.map(function(a,b){return b}).filter(function(a,b){return!c[b]})[d]).toString()}));var U=S.watchTransition(E,"multibar",Math.min(250,B)).delay(function(a,c){return c*B/b[0].values.length});v?U.attr("transform",function(a,c,d){var e=0;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);var f=0;b[d].nonStackable&&(f=a.series*m.rangeBand()/b.length,b.length!==I&&(f=b[d].nonStackableSeries*m.rangeBand()/(2*I)));var g=f+m(q(a,c));return"translate("+g+","+e+")"}).select("rect").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("width",function(a,c,d){if(b[d].nonStackable){var e=m.rangeBand()/I;return b.length!==I&&(e=m.rangeBand()/(2*I)),e}return m.rangeBand()}):U.attr("transform",function(a,c){var d=a.series*m.rangeBand()/b.length+m(q(a,c)),e=r(a,c)<0?n(0):n(0)-n(r(a,c))<1?n(0)-1:n(r(a,c))||0;return"translate("+d+","+e+")"}).select("rect").attr("width",m.rangeBand()/b.length).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&&(F=b[0].values.length)}),E.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=function(a){return a.yErr},t=[0],u=!0,v=!1,w="zero",x=a.utils.defaultColor(),y=a.utils.defaultColor(),z=!1,A=null,B=500,C=.1,D=d3.dispatch("chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout","elementMousemove","renderEnd"),E=a.utils.renderWatch(D,B),F=0;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 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 t},set:function(a){t=a}},stacked:{get:function(){return v},set:function(a){v=a}},stackOffset:{get:function(){return w},set:function(a){w=a}},clipEdge:{get:function(){return u},set:function(a){u=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 z
},set:function(a){z=a}},groupSpacing:{get:function(){return C},set:function(a){C=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 B},set:function(a){B=a,E.reset(B)}},color:{get:function(){return x},set:function(b){x=a.utils.getColor(b)}},barColor:{get:function(){return A},set:function(b){A=b?a.utils.getColor(b):null}},errorBarColor:{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 F.reset(),m.each(function(b){var m=k-j.left-j.right,D=l-j.top-j.bottom;n=d3.select(this),a.utils.initSVG(n),x&&(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})}),x&&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 G=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,yErr:s(a,b)}})});o.domain(d||d3.merge(G).map(function(a){return a.x})).rangeBands(f||[0,D],B),p.domain(e||d3.extent(d3.merge(d3.merge(G).map(function(a){var b=a.y;x&&(b=a.y>0?a.y1+a.y:a.y1);var c=a.yErr;return c?c.length?[b+c[0],b+c[1]]:(c=Math.abs(c),[b-c,b+c]):[b]})).concat(t))),p.range(y&&!x?g||[p.domain()[0]<0?A:0,m-(p.domain()[1]>0?A:0)]:g||[0,m]),h=h||o,i=i||d3.scale.linear().domain(p.domain()).range([p(0),p(0)]);{var H=d3.select(this).selectAll("g.nv-wrap.nv-multibarHorizontal").data([b]),I=H.enter().append("g").attr("class","nvd3 nv-wrap nv-multibarHorizontal"),J=(I.append("defs"),I.append("g"));H.select("g")}J.append("g").attr("class","nv-groups"),H.attr("transform","translate("+j.left+","+j.top+")");var K=H.select(".nv-groups").selectAll(".nv-group").data(function(a){return a},function(a,b){return b});K.enter().append("g").style("stroke-opacity",1e-6).style("fill-opacity",1e-6),K.exit().watchTransition(F,"multibarhorizontal: exit groups").style("stroke-opacity",1e-6).style("fill-opacity",1e-6).remove(),K.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)}),K.watchTransition(F,"multibarhorizontal: groups").style("stroke-opacity",1).style("fill-opacity",.75);var L=K.selectAll("g.nv-bar").data(function(a){return a.values});L.exit().remove();var M=L.enter().append("g").attr("transform",function(a,c,d){return"translate("+i(x?a.y0:0)+","+(x?0:d*o.rangeBand()/b.length+o(q(a,c)))+")"});M.append("rect").attr("width",0).attr("height",o.rangeBand()/(x?1:b.length)),L.on("mouseover",function(a,b){d3.select(this).classed("hover",!0),E.elementMouseover({data:a,index:b,color:d3.select(this).style("fill")})}).on("mouseout",function(a,b){d3.select(this).classed("hover",!1),E.elementMouseout({data:a,index:b,color:d3.select(this).style("fill")})}).on("mouseout",function(a,b){E.elementMouseout({data:a,index:b,color:d3.select(this).style("fill")})}).on("mousemove",function(a,b){E.elementMousemove({data:a,index:b,color:d3.select(this).style("fill")})}).on("click",function(a,b){E.elementClick({data:a,index:b,color:d3.select(this).style("fill")}),d3.event.stopPropagation()}).on("dblclick",function(a,b){E.elementDblClick({data:a,index:b,color:d3.select(this).style("fill")}),d3.event.stopPropagation()}),s(b[0].values[0],0)&&(M.append("polyline"),L.select("polyline").attr("fill","none").attr("stroke",function(a,b,c){return w(a,c,b)}).attr("points",function(a,c){var d=s(a,c),e=.8*o.rangeBand()/(2*(x?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*(x?1:b.length));return"translate("+(r(a,c)<0?0:p(r(a,c))-p(0))+", "+d+")"})),M.append("text"),y&&!x?(L.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=C(r(a,b)),d=s(a,b);return void 0===d?c:d.length?c+"+"+C(Math.abs(d[1]))+"-"+C(Math.abs(d[0])):c+"±"+C(Math.abs(d))}),L.watchTransition(F,"multibarhorizontal: bars").select("text").attr("x",function(a,b){return r(a,b)<0?-4:p(r(a,b))-p(0)+4})):L.selectAll("text").text(""),z&&!x?(M.append("text").classed("nv-bar-label",!0),L.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)}),L.watchTransition(F,"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})):L.selectAll("text.nv-bar-label").text(""),L.attr("class",function(a,b){return r(a,b)<0?"nv-bar negative":"nv-bar positive"}),v&&(c||(c=b.map(function(){return!0})),L.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()})),x?L.watchTransition(F,"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()):L.watchTransition(F,"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()}),F.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=a.utils.defaultColor(),x=!1,y=!1,z=!1,A=60,B=.1,C=d3.format(",.2f"),D=250,E=d3.dispatch("chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout","elementMousemove","renderEnd"),F=a.utils.renderWatch(E,D);return b.dispatch=E,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 x},set:function(a){x=a}},showValues:{get:function(){return y},set:function(a){y=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 C},set:function(a){C=a}},valuePadding:{get:function(){return A},set:function(a){A=a}},groupSpacing:{get:function(){return B},set:function(a){B=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 D},set:function(a){D=a,F.reset(D)}},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}},errorBarColor:{get:function(){return w},set:function(b){w=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?B:A;a.value=a.point.x,a.series={value:a.point.y,color:a.point.color},D.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?B:A;a.value=a.point.x,a.series={value:a.point.y,color:a.point.color},D.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.seriesIndex].yAxis?B:A;a.point.x=x.x()(a.point),a.point.y=x.y()(a.point),D.duration(100).valueFormatter(function(a,c){return b.tickFormat()(a,c)}).data(a).position(a.pos).hidden(!1)}function E(a){var b=2===j[a.data.series].yAxis?B:A;a.value=v.x()(a.data),a.series={value:v.y()(a.data),color:a.color},D.duration(0).valueFormatter(function(a,c){return b.tickFormat()(a,c)}).data(a).hidden(!1)}var F=d3.select(this);a.utils.initSVG(F),b.update=function(){F.transition().call(b)},b.container=this;var G=a.utils.availableWidth(g,F,e),H=a.utils.availableHeight(h,F,e),I=j.filter(function(a){return"line"==a.type&&1==a.yAxis}),J=j.filter(function(a){return"line"==a.type&&2==a.yAxis}),K=j.filter(function(a){return"scatter"==a.type&&1==a.yAxis}),L=j.filter(function(a){return"scatter"==a.type&&2==a.yAxis}),M=j.filter(function(a){return"bar"==a.type&&1==a.yAxis}),N=j.filter(function(a){return"bar"==a.type&&2==a.yAxis}),O=j.filter(function(a){return"area"==a.type&&1==a.yAxis}),P=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,F),b;F.selectAll(".nv-noData").remove();var Q=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}})}),R=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(Q.concat(R)),function(a){return a.x})).range([0,G]);var S=F.selectAll("g.wrap.multiChart").data([j]),T=S.enter().append("g").attr("class","wrap nvd3 multiChart").append("g");T.append("g").attr("class","nv-x nv-axis"),T.append("g").attr("class","nv-y1 nv-axis"),T.append("g").attr("class","nv-y2 nv-axis"),T.append("g").attr("class","lines1Wrap"),T.append("g").attr("class","lines2Wrap"),T.append("g").attr("class","scatters1Wrap"),T.append("g").attr("class","scatters2Wrap"),T.append("g").attr("class","bars1Wrap"),T.append("g").attr("class","bars2Wrap"),T.append("g").attr("class","stack1Wrap"),T.append("g").attr("class","stack2Wrap"),T.append("g").attr("class","legendWrap");var U=S.select("g"),V=j.map(function(a,b){return j[b].color||f(a,b)});if(i){var W=C.align()?G/2:G,X=C.align()?W:0;C.width(W),C.color(V),U.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(C),e.top!=C.height()&&(e.top=C.height(),H=a.utils.availableHeight(h,F,e)),U.select(".legendWrap").attr("transform","translate("+X+","+-e.top+")")}r.width(G).height(H).interpolate(m).color(V.filter(function(a,b){return!j[b].disabled&&1==j[b].yAxis&&"line"==j[b].type})),s.width(G).height(H).interpolate(m).color(V.filter(function(a,b){return!j[b].disabled&&2==j[b].yAxis&&"line"==j[b].type})),t.width(G).height(H).color(V.filter(function(a,b){return!j[b].disabled&&1==j[b].yAxis&&"scatter"==j[b].type})),u.width(G).height(H).color(V.filter(function(a,b){return!j[b].disabled&&2==j[b].yAxis&&"scatter"==j[b].type})),v.width(G).height(H).color(V.filter(function(a,b){return!j[b].disabled&&1==j[b].yAxis&&"bar"==j[b].type})),w.width(G).height(H).color(V.filter(function(a,b){return!j[b].disabled&&2==j[b].yAxis&&"bar"==j[b].type})),x.width(G).height(H).color(V.filter(function(a,b){return!j[b].disabled&&1==j[b].yAxis&&"area"==j[b].type})),y.width(G).height(H).color(V.filter(function(a,b){return!j[b].disabled&&2==j[b].yAxis&&"area"==j[b].type})),U.attr("transform","translate("+e.left+","+e.top+")");var Y=U.select(".lines1Wrap").datum(I.filter(function(a){return!a.disabled})),Z=U.select(".scatters1Wrap").datum(K.filter(function(a){return!a.disabled})),$=U.select(".bars1Wrap").datum(M.filter(function(a){return!a.disabled})),_=U.select(".stack1Wrap").datum(O.filter(function(a){return!a.disabled})),ab=U.select(".lines2Wrap").datum(J.filter(function(a){return!a.disabled})),bb=U.select(".scatters2Wrap").datum(L.filter(function(a){return!a.disabled})),cb=U.select(".bars2Wrap").datum(N.filter(function(a){return!a.disabled})),db=U.select(".stack2Wrap").datum(P.filter(function(a){return!a.disabled})),eb=O.length?O.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}]):[],fb=P.length?P.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(Q).concat(eb),function(a){return a.y})).range([0,H]),q.domain(d||d3.extent(d3.merge(R).concat(fb),function(a){return a.y})).range([0,H]),r.yDomain(p.domain()),t.yDomain(p.domain()),v.yDomain(p.domain()),x.yDomain(p.domain()),s.yDomain(q.domain()),u.yDomain(q.domain()),w.yDomain(q.domain()),y.yDomain(q.domain()),O.length&&d3.transition(_).call(x),P.length&&d3.transition(db).call(y),M.length&&d3.transition($).call(v),N.length&&d3.transition(cb).call(w),I.length&&d3.transition(Y).call(r),J.length&&d3.transition(ab).call(s),K.length&&d3.transition(Z).call(t),L.length&&d3.transition(bb).call(u),z._ticks(a.utils.calcTicksX(G/100,j)).tickSize(-H,0),U.select(".nv-x.nv-axis").attr("transform","translate(0,"+H+")"),d3.transition(U.select(".nv-x.nv-axis")).call(z),A._ticks(a.utils.calcTicksY(H/36,j)).tickSize(-G,0),d3.transition(U.select(".nv-y1.nv-axis")).call(A),B._ticks(a.utils.calcTicksY(H/36,j)).tickSize(-G,0),d3.transition(U.select(".nv-y2.nv-axis")).call(B),U.select(".nv-y1.nv-axis").classed("nv-disabled",Q.length?!1:!0).attr("transform","translate("+o.range()[0]+",0)"),U.select(".nv-y2.nv-axis").classed("nv-disabled",R.length?!1:!0).attr("transform","translate("+o.range()[1]+",0)"),C.dispatch.on("stateChange",function(){b.update()}),r.dispatch.on("elementMouseover.tooltip",k),s.dispatch.on("elementMouseover.tooltip",k),r.dispatch.on("elementMouseout.tooltip",function(){D.hidden(!0)}),s.dispatch.on("elementMouseout.tooltip",function(){D.hidden(!0)}),t.dispatch.on("elementMouseover.tooltip",l),u.dispatch.on("elementMouseover.tooltip",l),t.dispatch.on("elementMouseout.tooltip",function(){D.hidden(!0)}),u.dispatch.on("elementMouseout.tooltip",function(){D.hidden(!0)}),x.dispatch.on("elementMouseover.tooltip",n),y.dispatch.on("elementMouseover.tooltip",n),x.dispatch.on("elementMouseout.tooltip",function(){D.hidden(!0)}),y.dispatch.on("elementMouseout.tooltip",function(){D.hidden(!0)}),v.dispatch.on("elementMouseover.tooltip",E),w.dispatch.on("elementMouseover.tooltip",E),v.dispatch.on("elementMouseout.tooltip",function(){D.hidden(!0)}),w.dispatch.on("elementMouseout.tooltip",function(){D.hidden(!0)}),v.dispatch.on("elementMousemove.tooltip",function(){D.position({top:d3.event.pageY,left:d3.event.pageX})()}),w.dispatch.on("elementMousemove.tooltip",function(){D.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.scatter().yScale(p),u=a.models.scatter().yScale(q),v=a.models.multiBar().stacked(!1).yScale(p),w=a.models.multiBar().stacked(!1).yScale(q),x=a.models.stackedArea().yScale(p),y=a.models.stackedArea().yScale(q),z=a.models.axis().scale(o).orient("bottom").tickPadding(5),A=a.models.axis().scale(p).orient("left"),B=a.models.axis().scale(q).orient("right"),C=a.models.legend().height(30),D=a.models.tooltip(),E=d3.dispatch();return b.dispatch=E,b.lines1=r,b.lines2=s,b.scatters1=t,b.scatters2=u,b.bars1=v,b.bars2=w,b.stack1=x,b.stack2=y,b.xAxis=z,b.yAxis1=A,b.yAxis2=B,b.tooltip=D,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 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 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),x.x(a),y.x(a)}},y:{get:function(){return l},set:function(a){l=a,r.y(a),s.y(a),t.y(a),u.y(a),x.y(a),y.y(a),v.y(a),w.y(a)}},useVoronoi:{get:function(){return n},set:function(a){n=a,r.useVoronoi(a),s.useVoronoi(a),x.useVoronoi(a),y.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-"+k+"-"+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-"+k+"-"+b}).append("svg:circle").attr("cx",function(a){return a[0]}).attr("cy",function(a){return a[1]}).attr("r",D));var o=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){o(a,L.elementClick)}).on("dblclick",function(a){o(a,L.elementDblClick)}).on("mouseover",function(a){o(a,L.elementMouseover)}).on("mouseout",function(a){o(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"}();/**
* @preserve HTML5 Shiv 3.7.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
*/
!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.2",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="<xyz></xyz>",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b)}(this,document);/*! Respond.js v1.4.2: min/max-width media query polyfill * Copyright 2013 Scott Jehl
 * Licensed under https://github.com/scottjehl/Respond/blob/master/LICENSE-MIT
 *  */

!function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='&shy;<style media="'+a+'"> #mq-test-1 { width: 42px; }</style>',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){u(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))};if(c.ajax=f,c.queue=d,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/,maxw:/\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var g,h,i,j=a.document,k=j.documentElement,l=[],m=[],n=[],o={},p=30,q=j.getElementsByTagName("head")[0]||k,r=j.getElementsByTagName("base")[0],s=q.getElementsByTagName("link"),t=function(){var a,b=j.createElement("div"),c=j.body,d=k.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=j.createElement("body"),c.style.background="none"),k.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&k.insertBefore(c,k.firstChild),a=b.offsetWidth,f?k.removeChild(c):c.removeChild(b),k.style.fontSize=d,e&&(c.style.fontSize=e),a=i=parseFloat(a)},u=function(b){var c="clientWidth",d=k[c],e="CSS1Compat"===j.compatMode&&d||j.body[c]||d,f={},o=s[s.length-1],r=(new Date).getTime();if(b&&g&&p>r-g)return a.clearTimeout(h),h=a.setTimeout(u,p),void 0;g=r;for(var v in l)if(l.hasOwnProperty(v)){var w=l[v],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?i||t():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?i||t():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(m[w.rules]))}for(var C in n)n.hasOwnProperty(C)&&n[C]&&n[C].parentNode===q&&q.removeChild(n[C]);n.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=j.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,q.insertBefore(E,o.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(j.createTextNode(F)),n.push(E)}},v=function(a,b,d){var e=a.replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var g=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},h=!f&&d;b.length&&(b+="/"),h&&(f=1);for(var i=0;f>i;i++){var j,k,n,o;h?(j=d,m.push(g(a))):(j=e[i].match(c.regex.findStyles)&&RegExp.$1,m.push(RegExp.$2&&g(RegExp.$2))),n=j.split(","),o=n.length;for(var p=0;o>p;p++)k=n[p],l.push({media:k.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:m.length-1,hasquery:k.indexOf("(")>-1,minw:k.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:k.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}u()},w=function(){if(d.length){var b=d.shift();f(b.href,function(c){v(c,b.href,b.media),o[b.href]=!0,a.setTimeout(function(){w()},0)})}},x=function(){for(var b=0;b<s.length;b++){var c=s[b],e=c.href,f=c.media,g=c.rel&&"stylesheet"===c.rel.toLowerCase();e&&g&&!o[e]&&(c.styleSheet&&c.styleSheet.rawCssText?(v(c.styleSheet.rawCssText,e,f),o[e]=!0):(!/^([a-zA-Z:]*\/\/)/.test(e)&&!r||e.replace(RegExp.$1,"").split("/")[0]===a.location.host)&&("//"===e.substring(0,2)&&(e=a.location.protocol+e),d.push({href:e,media:f})))}w()};x(),c.update=x,c.getEmValue=t,a.addEventListener?a.addEventListener("resize",b,!1):a.attachEvent&&a.attachEvent("onresize",b)}}(this);/*!

Holder - client side image placeholders
Version 2.7.1+6hydf
© 2015 Ivan Malopinsky - http://imsky.co

Site:     http://holderjs.com
Issues:   https://github.com/imsky/holder/issues
License:  http://opensource.org/licenses/MIT

*/
!function(a){if(a.document){var b=a.document;b.querySelectorAll||(b.querySelectorAll=function(c){var d,e=b.createElement("style"),f=[];for(b.documentElement.firstChild.appendChild(e),b._qsa=[],e.styleSheet.cssText=c+"{x-qsa:expression(document._qsa && document._qsa.push(this))}",a.scrollBy(0,0),e.parentNode.removeChild(e);b._qsa.length;)d=b._qsa.shift(),d.style.removeAttribute("x-qsa"),f.push(d);return b._qsa=null,f}),b.querySelector||(b.querySelector=function(a){var c=b.querySelectorAll(a);return c.length?c[0]:null}),b.getElementsByClassName||(b.getElementsByClassName=function(a){return a=String(a).replace(/^|\s+/g,"."),b.querySelectorAll(a)}),Object.keys||(Object.keys=function(a){if(a!==Object(a))throw TypeError("Object.keys called on non-object");var b,c=[];for(b in a)Object.prototype.hasOwnProperty.call(a,b)&&c.push(b);return c}),function(a){var b="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";a.atob=a.atob||function(a){a=String(a);var c,d=0,e=[],f=0,g=0;if(a=a.replace(/\s/g,""),a.length%4===0&&(a=a.replace(/=+$/,"")),a.length%4===1)throw Error("InvalidCharacterError");if(/[^+/0-9A-Za-z]/.test(a))throw Error("InvalidCharacterError");for(;d<a.length;)c=b.indexOf(a.charAt(d)),f=f<<6|c,g+=6,24===g&&(e.push(String.fromCharCode(f>>16&255)),e.push(String.fromCharCode(f>>8&255)),e.push(String.fromCharCode(255&f)),g=0,f=0),d+=1;return 12===g?(f>>=4,e.push(String.fromCharCode(255&f))):18===g&&(f>>=2,e.push(String.fromCharCode(f>>8&255)),e.push(String.fromCharCode(255&f))),e.join("")},a.btoa=a.btoa||function(a){a=String(a);var c,d,e,f,g,h,i,j=0,k=[];if(/[^\x00-\xFF]/.test(a))throw Error("InvalidCharacterError");for(;j<a.length;)c=a.charCodeAt(j++),d=a.charCodeAt(j++),e=a.charCodeAt(j++),f=c>>2,g=(3&c)<<4|d>>4,h=(15&d)<<2|e>>6,i=63&e,j===a.length+2?(h=64,i=64):j===a.length+1&&(i=64),k.push(b.charAt(f),b.charAt(g),b.charAt(h),b.charAt(i));return k.join("")}}(a),Object.prototype.hasOwnProperty||(Object.prototype.hasOwnProperty=function(a){var b=this.__proto__||this.constructor.prototype;return a in this&&(!(a in b)||b[a]!==this[a])}),function(){if("performance"in a==!1&&(a.performance={}),Date.now=Date.now||function(){return(new Date).getTime()},"now"in a.performance==!1){var b=Date.now();performance.timing&&performance.timing.navigationStart&&(b=performance.timing.navigationStart),a.performance.now=function(){return Date.now()-b}}}(),a.requestAnimationFrame||(a.webkitRequestAnimationFrame?!function(a){a.requestAnimationFrame=function(b){return webkitRequestAnimationFrame(function(){b(a.performance.now())})},a.cancelAnimationFrame=webkitCancelAnimationFrame}(a):a.mozRequestAnimationFrame?!function(a){a.requestAnimationFrame=function(b){return mozRequestAnimationFrame(function(){b(a.performance.now())})},a.cancelAnimationFrame=mozCancelAnimationFrame}(a):!function(a){a.requestAnimationFrame=function(b){return a.setTimeout(b,1e3/60)},a.cancelAnimationFrame=a.clearTimeout}(a))}}(this),function(a,b){"object"==typeof exports&&"object"==typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):"object"==typeof exports?exports.Holder=b():a.Holder=b()}(this,function(){return function(a){function b(d){if(c[d])return c[d].exports;var e=c[d]={exports:{},id:d,loaded:!1};return a[d].call(e.exports,e,e.exports,b),e.loaded=!0,e.exports}var c={};return b.m=a,b.c=c,b.p="",b(0)}([function(a,b,c){(function(b){function d(a,b,c,d){var f=e(c.substr(c.lastIndexOf(a.domain)),a);f&&h({mode:null,el:d,flags:f,engineSettings:b})}function e(a,b){var c={theme:B(J.settings.themes.gray,null),stylesheets:b.stylesheets,instanceOptions:b};return a.match(/([\d]+p?)x([\d]+p?)(?:\?|$)/)?f(a,c):g(a,c)}function f(a,b){var c=a.split("?"),d=c[0].split("/");b.holderURL=a;var e=d[1],f=e.match(/([\d]+p?)x([\d]+p?)/);if(!f)return!1;if(b.fluid=-1!==e.indexOf("p"),b.dimensions={width:f[1].replace("p","%"),height:f[2].replace("p","%")},2===c.length){var g=A.parse(c[1]);if(g.bg&&(b.theme.background=(-1===g.bg.indexOf("#")?"#":"")+g.bg),g.fg&&(b.theme.foreground=(-1===g.fg.indexOf("#")?"#":"")+g.fg),g.theme&&b.instanceOptions.themes.hasOwnProperty(g.theme)&&(b.theme=B(b.instanceOptions.themes[g.theme],null)),g.text&&(b.text=g.text),g.textmode&&(b.textmode=g.textmode),g.size&&(b.size=g.size),g.font&&(b.font=g.font),g.align&&(b.align=g.align),b.nowrap=z.truthy(g.nowrap),b.auto=z.truthy(g.auto),z.truthy(g.random)){J.vars.cache.themeKeys=J.vars.cache.themeKeys||Object.keys(b.instanceOptions.themes);var h=J.vars.cache.themeKeys[0|Math.random()*J.vars.cache.themeKeys.length];b.theme=B(b.instanceOptions.themes[h],null)}}return b}function g(a,b){var c=!1,d=String.fromCharCode(11),e=a.replace(/([^\\])\//g,"$1"+d).split(d),f=/%[0-9a-f]{2}/gi,g=b.instanceOptions;b.holderURL=[];for(var h=e.length,i=0;h>i;i++){var j=e[i];if(j.match(f))try{j=decodeURIComponent(j)}catch(k){j=e[i]}var l=!1;if(J.flags.dimensions.match(j))c=!0,b.dimensions=J.flags.dimensions.output(j),l=!0;else if(J.flags.fluid.match(j))c=!0,b.dimensions=J.flags.fluid.output(j),b.fluid=!0,l=!0;else if(J.flags.textmode.match(j))b.textmode=J.flags.textmode.output(j),l=!0;else if(J.flags.colors.match(j)){var m=J.flags.colors.output(j);b.theme=B(b.theme,m),l=!0}else if(g.themes[j])g.themes.hasOwnProperty(j)&&(b.theme=B(g.themes[j],null)),l=!0;else if(J.flags.font.match(j))b.font=J.flags.font.output(j),l=!0;else if(J.flags.auto.match(j))b.auto=!0,l=!0;else if(J.flags.text.match(j))b.text=J.flags.text.output(j),l=!0;else if(J.flags.size.match(j))b.size=J.flags.size.output(j),l=!0;else if(J.flags.random.match(j)){null==J.vars.cache.themeKeys&&(J.vars.cache.themeKeys=Object.keys(g.themes));var n=J.vars.cache.themeKeys[0|Math.random()*J.vars.cache.themeKeys.length];b.theme=B(g.themes[n],null),l=!0}l&&b.holderURL.push(j)}return b.holderURL.unshift(g.domain),b.holderURL=b.holderURL.join("/"),c?b:!1}function h(a){var b=a.mode,c=a.el,d=a.flags,e=a.engineSettings,f=d.dimensions,g=d.theme,h=f.width+"x"+f.height;if(b=null==b?d.fluid?"fluid":"image":b,null!=d.text&&(g.text=d.text,"object"===c.nodeName.toLowerCase())){for(var j=g.text.split("\\n"),k=0;k<j.length;k++)j[k]=z.encodeHtmlEntity(j[k]);g.text=j.join("\\n")}var n=d.holderURL,o=B(e,null);if(d.font&&(g.font=d.font,!o.noFontFallback&&"img"===c.nodeName.toLowerCase()&&J.setup.supportsCanvas&&"svg"===o.renderer&&(o=B(o,{renderer:"canvas"}))),d.font&&"canvas"==o.renderer&&(o.reRender=!0),"background"==b)null==c.getAttribute("data-background-src")&&r(c,{"data-background-src":n});else{var p={};p[J.vars.dataAttr]=n,r(c,p)}d.theme=g,c.holderData={flags:d,engineSettings:o},("image"==b||"fluid"==b)&&r(c,{alt:g.text?g.text+" ["+h+"]":h});var q={mode:b,el:c,holderSettings:{dimensions:f,theme:g,flags:d},engineSettings:o};"image"==b?("html"!=o.renderer&&d.auto||(c.style.width=f.width+"px",c.style.height=f.height+"px"),"html"==o.renderer?c.style.backgroundColor=g.background:(i(q),"exact"==d.textmode&&(c.holderData.resizeUpdate=!0,J.vars.resizableImages.push(c),l(c)))):"background"==b&&"html"!=o.renderer?i(q):"fluid"==b&&(c.holderData.resizeUpdate=!0,"%"==f.height.slice(-1)?c.style.height=f.height:null!=d.auto&&d.auto||(c.style.height=f.height+"px"),"%"==f.width.slice(-1)?c.style.width=f.width:null!=d.auto&&d.auto||(c.style.width=f.width+"px"),("inline"==c.style.display||""===c.style.display||"none"==c.style.display)&&(c.style.display="block"),m(c),"html"==o.renderer?c.style.backgroundColor=g.background:(J.vars.resizableImages.push(c),l(c)))}function i(a){function c(){var b=null;switch(h.renderer){case"canvas":b=L(k,a);break;case"svg":b=M(k,a);break;default:throw"Holder: invalid renderer: "+h.renderer}return b}var d=null,e=a.mode,f=a.holderSettings,g=a.el,h=a.engineSettings;switch(h.renderer){case"svg":if(!J.setup.supportsSVG)return;break;case"canvas":if(!J.setup.supportsCanvas)return;break;default:return}var i={width:f.dimensions.width,height:f.dimensions.height,theme:f.theme,flags:f.flags},k=j(i);if(d=c(),null==d)throw"Holder: couldn't render placeholder";"background"==e?(g.style.backgroundImage="url("+d+")",g.style.backgroundSize=i.width+"px "+i.height+"px"):("img"===g.nodeName.toLowerCase()?r(g,{src:d}):"object"===g.nodeName.toLowerCase()&&(r(g,{data:d}),r(g,{type:"image/svg+xml"})),h.reRender&&b.setTimeout(function(){var a=c();if(null==a)throw"Holder: couldn't render placeholder";"img"===g.nodeName.toLowerCase()?r(g,{src:a}):"object"===g.nodeName.toLowerCase()&&(r(g,{data:a}),r(g,{type:"image/svg+xml"}))},100)),r(g,{"data-holder-rendered":!0})}function j(a){function b(a,b,c,d){b.width=c,b.height=d,a.width=Math.max(a.width,b.width),a.height+=b.height}var c=J.defaults.size;switch(parseFloat(a.theme.size)?c=a.theme.size:parseFloat(a.flags.size)&&(c=a.flags.size),a.font={family:a.theme.font?a.theme.font:"Arial, Helvetica, Open Sans, sans-serif",size:k(a.width,a.height,c),units:a.theme.units?a.theme.units:J.defaults.units,weight:a.theme.fontweight?a.theme.fontweight:"bold"},a.text=a.theme.text||Math.floor(a.width)+"x"+Math.floor(a.height),a.noWrap=a.theme.nowrap||a.flags.nowrap,a.align=a.theme.align||a.flags.align||"center",a.flags.textmode){case"literal":a.text=a.flags.dimensions.width+"x"+a.flags.dimensions.height;break;case"exact":if(!a.flags.exactDimensions)break;a.text=Math.floor(a.flags.exactDimensions.width)+"x"+Math.floor(a.flags.exactDimensions.height)}var d=new y({width:a.width,height:a.height}),e=d.Shape,f=new e.Rect("holderBg",{fill:a.theme.background});f.resize(a.width,a.height),d.root.add(f);var g=new e.Group("holderTextGroup",{text:a.text,align:a.align,font:a.font,fill:a.theme.foreground});g.moveTo(null,null,1),d.root.add(g);var h=g.textPositionData=K(d);if(!h)throw"Holder: staging fallback not supported yet.";g.properties.leading=h.boundingBox.height;var i=null,j=null,l=a.width*J.setup.lineWrapRatio,m=l;if(h.lineCount>1){var n,o=0,p=0,q=0;j=new e.Group("line"+q),("left"===a.align||"right"===a.align)&&(m=a.width*(1-2*(1-J.setup.lineWrapRatio)));for(var r=0;r<h.words.length;r++){var s=h.words[r];i=new e.Text(s.text);var t="\\n"==s.text;!a.noWrap&&(o+s.width>=m||t===!0)&&(b(g,j,o,g.properties.leading),g.add(j),o=0,p+=g.properties.leading,q+=1,j=new e.Group("line"+q),j.y=p),t!==!0&&(i.moveTo(o,0),o+=h.spaceWidth+s.width,j.add(i))}if(b(g,j,o,g.properties.leading),g.add(j),"left"===a.align)g.moveTo(a.width-l,null,null);else if("right"===a.align){for(n in g.children)j=g.children[n],j.moveTo(a.width-j.width,null,null);g.moveTo(0-(a.width-l),null,null)}else{for(n in g.children)j=g.children[n],j.moveTo((g.width-j.width)/2,null,null);g.moveTo((a.width-g.width)/2,null,null)}g.moveTo(null,(a.height-g.height)/2,null),(a.height-g.height)/2<0&&g.moveTo(null,0,null)}else i=new e.Text(a.text),j=new e.Group("line0"),j.add(i),g.add(j),"left"===a.align?g.moveTo(a.width-l,null,null):"right"===a.align?g.moveTo(0-(a.width-l),null,null):g.moveTo((a.width-h.boundingBox.width)/2,null,null),g.moveTo(null,(a.height-h.boundingBox.height)/2,null);return d}function k(a,b,c){var d=parseInt(a,10),e=parseInt(b,10),f=Math.max(d,e),g=Math.min(d,e),h=.8*Math.min(g,f*J.defaults.scale);return Math.round(Math.max(c,h))}function l(a){var b;b=null==a||null==a.nodeType?J.vars.resizableImages:[a];for(var c=0,d=b.length;d>c;c++){var e=b[c];if(e.holderData){var f=e.holderData.flags,g=D(e);if(g){if(!e.holderData.resizeUpdate)continue;if(f.fluid&&f.auto){var h=e.holderData.fluidConfig;switch(h.mode){case"width":g.height=g.width/h.ratio;break;case"height":g.width=g.height*h.ratio}}var j={mode:"image",holderSettings:{dimensions:g,theme:f.theme,flags:f},el:e,engineSettings:e.holderData.engineSettings};"exact"==f.textmode&&(f.exactDimensions=g,j.holderSettings.dimensions=f.dimensions),i(j)}else p(e)}}}function m(a){if(a.holderData){var b=D(a);if(b){var c=a.holderData.flags,d={fluidHeight:"%"==c.dimensions.height.slice(-1),fluidWidth:"%"==c.dimensions.width.slice(-1),mode:null,initialDimensions:b};d.fluidWidth&&!d.fluidHeight?(d.mode="width",d.ratio=d.initialDimensions.width/parseFloat(c.dimensions.height)):!d.fluidWidth&&d.fluidHeight&&(d.mode="height",d.ratio=parseFloat(c.dimensions.width)/d.initialDimensions.height),a.holderData.fluidConfig=d}else p(a)}}function n(){for(var a,c=[],d=Object.keys(J.vars.invisibleImages),e=0,f=d.length;f>e;e++)a=J.vars.invisibleImages[d[e]],D(a)&&"img"==a.nodeName.toLowerCase()&&(c.push(a),delete J.vars.invisibleImages[d[e]]);c.length&&I.run({images:c}),b.requestAnimationFrame(n)}function o(){J.vars.visibilityCheckStarted||(b.requestAnimationFrame(n),J.vars.visibilityCheckStarted=!0)}function p(a){a.holderData.invisibleId||(J.vars.invisibleId+=1,J.vars.invisibleImages["i"+J.vars.invisibleId]=a,a.holderData.invisibleId=J.vars.invisibleId)}function q(a,b){return null==b?document.createElement(a):document.createElementNS(b,a)}function r(a,b){for(var c in b)a.setAttribute(c,b[c])}function s(a,b,c){var d,e;null==a?(a=q("svg",E),d=q("defs",E),e=q("style",E),r(e,{type:"text/css"}),d.appendChild(e),a.appendChild(d)):e=a.querySelector("style"),a.webkitMatchesSelector&&a.setAttribute("xmlns",E);for(var f=0;f<a.childNodes.length;f++)a.childNodes[f].nodeType===F&&a.removeChild(a.childNodes[f]);for(;e.childNodes.length;)e.removeChild(e.childNodes[0]);return r(a,{width:b,height:c,viewBox:"0 0 "+b+" "+c,preserveAspectRatio:"none"}),a}function t(a,c){if(b.XMLSerializer){var d=new XMLSerializer,e="",f=c.stylesheets;if(c.svgXMLStylesheet){for(var g=u(),h=f.length-1;h>=0;h--){var i=g.createProcessingInstruction("xml-stylesheet",'href="'+f[h]+'" rel="stylesheet"');g.insertBefore(i,g.firstChild)}g.removeChild(g.documentElement),e=d.serializeToString(g)}var j=d.serializeToString(a);return j=j.replace(/\&amp;(\#[0-9]{2,}\;)/g,"&$1"),e+j}}function u(){return b.DOMParser?(new DOMParser).parseFromString("<xml />","application/xml"):void 0}function v(a){J.vars.debounceTimer||a.call(this),J.vars.debounceTimer&&b.clearTimeout(J.vars.debounceTimer),J.vars.debounceTimer=b.setTimeout(function(){J.vars.debounceTimer=null,a.call(this)},J.setup.debounce)}function w(){v(function(){l(null)})}var x=c(1),y=c(2),z=c(3),A=c(4),B=z.extend,C=z.getNodeArray,D=z.dimensionCheck,E="http://www.w3.org/2000/svg",F=8,G="2.7.1",H="\nCreated with Holder.js "+G+".\nLearn more at http://holderjs.com\n(c) 2012-2015 Ivan Malopinsky - http://imsky.co\n",I={version:G,addTheme:function(a,b){return null!=a&&null!=b&&(J.settings.themes[a]=b),delete J.vars.cache.themeKeys,this},addImage:function(a,b){var c=document.querySelectorAll(b);if(c.length)for(var d=0,e=c.length;e>d;d++){var f=q("img"),g={};g[J.vars.dataAttr]=a,r(f,g),c[d].appendChild(f)}return this},setResizeUpdate:function(a,b){a.holderData&&(a.holderData.resizeUpdate=!!b,a.holderData.resizeUpdate&&l(a))},run:function(a){a=a||{};var c={},f=B(J.settings,a);J.vars.preempted=!0,J.vars.dataAttr=f.dataAttr||J.vars.dataAttr,c.renderer=f.renderer?f.renderer:J.setup.renderer,-1===J.setup.renderers.join(",").indexOf(c.renderer)&&(c.renderer=J.setup.supportsSVG?"svg":J.setup.supportsCanvas?"canvas":"html");var g=C(f.images),i=C(f.bgnodes),j=C(f.stylenodes),k=C(f.objects);c.stylesheets=[],c.svgXMLStylesheet=!0,c.noFontFallback=f.noFontFallback?f.noFontFallback:!1;for(var l=0;l<j.length;l++){var m=j[l];if(m.attributes.rel&&m.attributes.href&&"stylesheet"==m.attributes.rel.value){var n=m.attributes.href.value,o=q("a");o.href=n;var p=o.protocol+"//"+o.host+o.pathname+o.search;c.stylesheets.push(p)}}for(l=0;l<i.length;l++)if(b.getComputedStyle){var r=b.getComputedStyle(i[l],null).getPropertyValue("background-image"),s=i[l].getAttribute("data-background-src"),t=null;t=null==s?r:s;var u=null,v="?"+f.domain+"/";if(0===t.indexOf(v))u=t.slice(1);else if(-1!=t.indexOf(v)){var w=t.substr(t.indexOf(v)).slice(1),x=w.match(/([^\"]*)"?\)/);null!=x&&(u=x[1])}if(null!=u){var y=e(u,f);y&&h({mode:"background",el:i[l],flags:y,engineSettings:c})}}for(l=0;l<k.length;l++){var A=k[l],D={};try{D.data=A.getAttribute("data"),D.dataSrc=A.getAttribute(J.vars.dataAttr)}catch(E){}var F=null!=D.data&&0===D.data.indexOf(f.domain),G=null!=D.dataSrc&&0===D.dataSrc.indexOf(f.domain);F?d(f,c,D.data,A):G&&d(f,c,D.dataSrc,A)}for(l=0;l<g.length;l++){var H=g[l],I={};try{I.src=H.getAttribute("src"),I.dataSrc=H.getAttribute(J.vars.dataAttr),I.rendered=H.getAttribute("data-holder-rendered")}catch(E){}var K=null!=I.src,L=null!=I.dataSrc&&0===I.dataSrc.indexOf(f.domain),M=null!=I.rendered&&"true"==I.rendered;K?0===I.src.indexOf(f.domain)?d(f,c,I.src,H):L&&(M?d(f,c,I.dataSrc,H):!function(a,b,c,e,f){z.imageExists(a,function(a){a||d(b,c,e,f)})}(I.src,f,c,I.dataSrc,H)):L&&d(f,c,I.dataSrc,H)}return this}},J={settings:{domain:"holder.js",images:"img",objects:"object",bgnodes:"body .holderjs",stylenodes:"head link.holderjs",stylesheets:[],themes:{gray:{background:"#EEEEEE",foreground:"#AAAAAA"},social:{background:"#3a5a97",foreground:"#FFFFFF"},industrial:{background:"#434A52",foreground:"#C2F200"},sky:{background:"#0D8FDB",foreground:"#FFFFFF"},vine:{background:"#39DBAC",foreground:"#1E292C"},lava:{background:"#F8591A",foreground:"#1C2846"}}},defaults:{size:10,units:"pt",scale:1/16},flags:{dimensions:{regex:/^(\d+)x(\d+)$/,output:function(a){var b=this.regex.exec(a);return{width:+b[1],height:+b[2]}}},fluid:{regex:/^([0-9]+%?)x([0-9]+%?)$/,output:function(a){var b=this.regex.exec(a);return{width:b[1],height:b[2]}}},colors:{regex:/(?:#|\^)([0-9a-f]{3,})\:(?:#|\^)([0-9a-f]{3,})/i,output:function(a){var b=this.regex.exec(a);return{foreground:"#"+b[2],background:"#"+b[1]}}},text:{regex:/text\:(.*)/,output:function(a){return this.regex.exec(a)[1].replace("\\/","/")}},font:{regex:/font\:(.*)/,output:function(a){return this.regex.exec(a)[1]}},auto:{regex:/^auto$/},textmode:{regex:/textmode\:(.*)/,output:function(a){return this.regex.exec(a)[1]}},random:{regex:/^random$/},size:{regex:/size\:(\d+)/,output:function(a){return this.regex.exec(a)[1]}}}},K=function(){var a=null,b=null,c=null;return function(d){var e=d.root;if(J.setup.supportsSVG){var f=!1,g=function(a){return document.createTextNode(a)};(null==a||a.parentNode!==document.body)&&(f=!0),a=s(a,e.properties.width,e.properties.height),a.style.display="block",f&&(b=q("text",E),c=g(null),r(b,{x:0}),b.appendChild(c),a.appendChild(b),document.body.appendChild(a),a.style.visibility="hidden",a.style.position="absolute",a.style.top="-100%",a.style.left="-100%");var h=e.children.holderTextGroup,i=h.properties;r(b,{y:i.font.size,style:z.cssProps({"font-weight":i.font.weight,"font-size":i.font.size+i.font.units,"font-family":i.font.family})}),c.nodeValue=i.text;var j=b.getBBox(),k=Math.ceil(j.width/(e.properties.width*J.setup.lineWrapRatio)),l=i.text.split(" "),m=i.text.match(/\\n/g);k+=null==m?0:m.length,c.nodeValue=i.text.replace(/[ ]+/g,"");var n=b.getComputedTextLength(),o=j.width-n,p=Math.round(o/Math.max(1,l.length-1)),t=[];if(k>1){c.nodeValue="";for(var u=0;u<l.length;u++)if(0!==l[u].length){c.nodeValue=z.decodeHtmlEntity(l[u]);var v=b.getBBox();t.push({text:l[u],width:v.width})}}return a.style.display="none",{spaceWidth:p,lineCount:k,boundingBox:j,words:t}}return!1}}(),L=function(){var a=q("canvas"),b=null;return function(c){null==b&&(b=a.getContext("2d"));var d=c.root;a.width=J.dpr(d.properties.width),a.height=J.dpr(d.properties.height),b.textBaseline="middle",b.fillStyle=d.children.holderBg.properties.fill,b.fillRect(0,0,J.dpr(d.children.holderBg.width),J.dpr(d.children.holderBg.height));{var e=d.children.holderTextGroup;e.properties}b.font=e.properties.font.weight+" "+J.dpr(e.properties.font.size)+e.properties.font.units+" "+e.properties.font.family+", monospace",b.fillStyle=e.properties.fill;for(var f in e.children){var g=e.children[f];for(var h in g.children){var i=g.children[h],j=J.dpr(e.x+g.x+i.x),k=J.dpr(e.y+g.y+i.y+e.properties.leading/2);b.fillText(i.properties.text,j,k)}}return a.toDataURL("image/png")}}(),M=function(){if(b.XMLSerializer){var a=u(),c=s(null,0,0),d=q("rect",E);return c.appendChild(d),function(b,e){var f=b.root;s(c,f.properties.width,f.properties.height);for(var g=c.querySelectorAll("g"),h=0;h<g.length;h++)g[h].parentNode.removeChild(g[h]);var i=e.holderSettings.flags.holderURL,j="holder_"+(Number(new Date)+32768+(0|32768*Math.random())).toString(16),k=q("g",E),l=f.children.holderTextGroup,m=l.properties,n=q("g",E),o=l.textPositionData,p="#"+j+" text { "+z.cssProps({fill:m.fill,"font-weight":m.font.weight,"font-family":m.font.family+", monospace","font-size":m.font.size+m.font.units})+" } ",u=a.createComment("\nSource URL: "+i+H),v=a.createCDATASection(p),w=c.querySelector("style");r(k,{id:j}),c.insertBefore(u,c.firstChild),w.appendChild(v),k.appendChild(d),k.appendChild(n),c.appendChild(k),r(d,{width:f.children.holderBg.width,height:f.children.holderBg.height,fill:f.children.holderBg.properties.fill}),l.y+=.8*o.boundingBox.height;for(var x in l.children){var y=l.children[x];for(var A in y.children){var B=y.children[A],C=l.x+y.x+B.x,D=l.y+y.y+B.y,F=q("text",E),G=document.createTextNode(null);r(F,{x:C,y:D}),G.nodeValue=B.properties.text,F.appendChild(G),n.appendChild(F)}}var I=N(t(c,e.engineSettings),"background"===e.mode);return I}}}(),N=function(){var a="data:image/svg+xml;charset=UTF-8,",b="data:image/svg+xml;charset=UTF-8;base64,";return function(c,d){return d?b+btoa(unescape(encodeURIComponent(c))):a+encodeURIComponent(c)}}();for(var O in J.flags)J.flags.hasOwnProperty(O)&&(J.flags[O].match=function(a){return a.match(this.regex)});J.setup={renderer:"html",debounce:100,ratio:1,supportsCanvas:!1,supportsSVG:!1,lineWrapRatio:.9,renderers:["html","canvas","svg"]},J.dpr=function(a){return a*J.setup.ratio},J.vars={preempted:!1,resizableImages:[],invisibleImages:{},invisibleId:0,visibilityCheckStarted:!1,debounceTimer:null,cache:{},dataAttr:"data-src"},function(){var a=1,c=1,d=q("canvas"),e=null;d.getContext&&-1!=d.toDataURL("image/png").indexOf("data:image/png")&&(J.setup.renderer="canvas",e=d.getContext("2d"),J.setup.supportsCanvas=!0),J.setup.supportsCanvas&&(a=b.devicePixelRatio||1,c=e.webkitBackingStorePixelRatio||e.mozBackingStorePixelRatio||e.msBackingStorePixelRatio||e.oBackingStorePixelRatio||e.backingStorePixelRatio||1),J.setup.ratio=a/c,document.createElementNS&&document.createElementNS(E,"svg").createSVGRect&&(J.setup.renderer="svg",J.setup.supportsSVG=!0)}(),o(),x&&x(function(){J.vars.preempted||I.run(),b.addEventListener?(b.addEventListener("resize",w,!1),b.addEventListener("orientationchange",w,!1)):b.attachEvent("onresize",w),"object"==typeof b.Turbolinks&&b.document.addEventListener("page:change",function(){I.run()})}),a.exports=I}).call(b,function(){return this}())},function(a){function b(a){function b(a){if(!v){if(!g.body)return e(b);for(v=!0;a=w.shift();)e(a)}}function c(a){(t||a.type===i||g[m]===l)&&(d(),b())}function d(){t?(g[s](q,c,j),a[s](i,c,j)):(g[o](r,c),a[o](k,c))}function e(a,b){setTimeout(a,+b>=0?b:1)}function f(a){v?e(a):w.push(a)}null==document.readyState&&document.addEventListener&&(document.addEventListener("DOMContentLoaded",function y(){document.removeEventListener("DOMContentLoaded",y,!1),document.readyState="complete"},!1),document.readyState="loading");var g=a.document,h=g.documentElement,i="load",j=!1,k="on"+i,l="complete",m="readyState",n="attachEvent",o="detachEvent",p="addEventListener",q="DOMContentLoaded",r="onreadystatechange",s="removeEventListener",t=p in g,u=j,v=j,w=[];if(g[m]===l)e(b);else if(t)g[p](q,c,j),a[p](i,c,j);else{g[n](r,c),a[n](k,c);try{u=null==a.frameElement&&h}catch(x){}u&&u.doScroll&&!function z(){if(!v){try{u.doScroll("left")}catch(a){return e(z,50)}d(),b()}}()}return f.version="1.4.0",f.isReady=function(){return v},f}a.exports="undefined"!=typeof window&&b(window)},function(a,b,c){var d=c(5),e=function(a){function b(a,b){for(var c in b)a[c]=b[c];return a}var c=1,e=d.defclass({constructor:function(a){c++,this.parent=null,this.children={},this.id=c,this.name="n"+c,null!=a&&(this.name=a),this.x=0,this.y=0,this.z=0,this.width=0,this.height=0},resize:function(a,b){null!=a&&(this.width=a),null!=b&&(this.height=b)},moveTo:function(a,b,c){this.x=null!=a?a:this.x,this.y=null!=b?b:this.y,this.z=null!=c?c:this.z},add:function(a){var b=a.name;if(null!=this.children[b])throw"SceneGraph: child with that name already exists: "+b;this.children[b]=a,a.parent=this}}),f=d(e,function(b){this.constructor=function(){b.constructor.call(this,"root"),this.properties=a}}),g=d(e,function(a){function c(c,d){if(a.constructor.call(this,c),this.properties={fill:"#000"},null!=d)b(this.properties,d);else if(null!=c&&"string"!=typeof c)throw"SceneGraph: invalid node name"}this.Group=d.extend(this,{constructor:c,type:"group"}),this.Rect=d.extend(this,{constructor:c,type:"rect"}),this.Text=d.extend(this,{constructor:function(a){c.call(this),this.properties.text=a},type:"text"})}),h=new f;return this.Shape=g,this.root=h,this};a.exports=e},function(a,b){(function(a){b.extend=function(a,b){var c={};for(var d in a)a.hasOwnProperty(d)&&(c[d]=a[d]);if(null!=b)for(var e in b)b.hasOwnProperty(e)&&(c[e]=b[e]);return c},b.cssProps=function(a){var b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(c+":"+a[c]);return b.join(";")},b.encodeHtmlEntity=function(a){for(var b=[],c=0,d=a.length-1;d>=0;d--)c=a.charCodeAt(d),b.unshift(c>128?["&#",c,";"].join(""):a[d]);return b.join("")},b.getNodeArray=function(b){var c=null;return"string"==typeof b?c=document.querySelectorAll(b):a.NodeList&&b instanceof a.NodeList?c=b:a.Node&&b instanceof a.Node?c=[b]:a.HTMLCollection&&b instanceof a.HTMLCollection?c=b:b instanceof Array?c=b:null===b&&(c=[]),c},b.imageExists=function(a,b){var c=new Image;c.onerror=function(){b.call(this,!1)},c.onload=function(){b.call(this,!0)},c.src=a},b.decodeHtmlEntity=function(a){return a.replace(/&#(\d+);/g,function(a,b){return String.fromCharCode(b)})},b.dimensionCheck=function(a){var b={height:a.clientHeight,width:a.clientWidth};return b.height&&b.width?b:!1},b.truthy=function(a){return"string"==typeof a?"true"===a||"yes"===a||"1"===a||"on"===a||"✓"===a:!!a}}).call(b,function(){return this}())},function(a,b,c){var d=encodeURIComponent,e=decodeURIComponent,f=c(6),g=c(7),h=/(\w+)\[(\d+)\]/,i=/\w+\.\w+/;b.parse=function(a){if("string"!=typeof a)return{};if(a=f(a),""===a)return{};"?"===a.charAt(0)&&(a=a.slice(1));for(var b={},c=a.split("&"),d=0;d<c.length;d++){var g,j,k,l=c[d].split("="),m=e(l[0]);if(g=h.exec(m))b[g[1]]=b[g[1]]||[],b[g[1]][g[2]]=e(l[1]);else if(g=i.test(m)){for(g=m.split("."),j=b;g.length;)if(k=g.shift(),k.length){if(j[k]){if(j[k]&&"object"!=typeof j[k])break}else j[k]={};g.length||(j[k]=e(l[1])),j=j[k]}}else b[l[0]]=null==l[1]?"":e(l[1])}return b},b.stringify=function(a){if(!a)return"";var b=[];for(var c in a){var e=a[c];if("array"!=g(e))b.push(d(c)+"="+d(a[c]));else for(var f=0;f<e.length;++f)b.push(d(c+"["+f+"]")+"="+d(e[f]))}return b.join("&")}},function(a){var b=function(){},c=Array.prototype.slice,d=function(a,d){var e=b.prototype="function"==typeof a?a.prototype:a,f=new b,g=d.apply(f,c.call(arguments,2).concat(e));if("object"==typeof g)for(var h in g)f[h]=g[h];if(!f.hasOwnProperty("constructor"))return f;var i=f.constructor;return i.prototype=f,i};d.defclass=function(a){var b=a.constructor;return b.prototype=a,b},d.extend=function(a,b){return d(a,function(a){return this.uber=a,b})},a.exports=d},function(a,b){function c(a){return a.replace(/^\s*|\s*$/g,"")}b=a.exports=c,b.left=function(a){return a.replace(/^\s*/,"")},b.right=function(a){return a.replace(/\s*$/,"")}},function(a){var b=Object.prototype.toString;a.exports=function(a){switch(b.call(a)){case"[object Date]":return"date";case"[object RegExp]":return"regexp";case"[object Arguments]":return"arguments";case"[object Array]":return"array";case"[object Error]":return"error"}return null===a?"null":void 0===a?"undefined":a!==a?"nan":a&&1===a.nodeType?"element":(a=a.valueOf?a.valueOf():Object.prototype.valueOf.apply(a),typeof a)}}])}),function(a,b){b&&(Holder=a.Holder)}(this,"undefined"!=typeof Meteor&&"undefined"!=typeof Package);
/*! jQuery v1.11.3 | (c) 2005, 2015 jQuery Foundation, Inc. | jquery.org/license */
!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.3",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b="length"in a&&a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,aa=/[+~]/,ba=/'|\\/g,ca=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),da=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ea=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fa){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(ba,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+ra(o[l]);w=aa.test(a)&&pa(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",ea,!1):e.attachEvent&&e.attachEvent("onunload",ea)),p=!f(g),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\f]' msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?la(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ca,da),a[3]=(a[3]||a[4]||a[5]||"").replace(ca,da),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ca,da).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(ca,da),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return W.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(ca,da).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:oa(function(){return[0]}),last:oa(function(a,b){return[b-1]}),eq:oa(function(a,b,c){return[0>c?c+b:c]}),even:oa(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:oa(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:oa(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:oa(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=ma(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=na(b);function qa(){}qa.prototype=d.filters=d.pseudos,d.setFilters=new qa,g=ga.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=S.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=T.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(R," ")}),h=h.slice(c.length));for(g in d.filter)!(e=X[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?ga.error(a):z(a,i).slice(0)};function ra(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function sa(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function ta(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ua(a,b,c){for(var d=0,e=b.length;e>d;d++)ga(a,b[d],c);return c}function va(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wa(a,b,c,d,e,f){return d&&!d[u]&&(d=wa(d)),e&&!e[u]&&(e=wa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ua(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:va(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=va(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=va(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sa(function(a){return a===b},h,!0),l=sa(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sa(ta(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wa(i>1&&ta(m),i>1&&ra(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xa(a.slice(i,e)),f>e&&xa(a=a.slice(e)),f>e&&ra(a))}m.push(c)}return ta(m)}function ya(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=va(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&ga.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,ya(e,d)),f.selector=a}return f},i=ga.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ca,da),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ca,da),aa.test(j[0].type)&&pa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&ra(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,aa.test(a)&&pa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ja(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;

return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?m.queue(this[0],a):void 0===b?this:this.each(function(){var c=m.queue(this,a,b);m._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&m.dequeue(this,a)})},dequeue:function(a){return this.each(function(){m.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=m.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=m._data(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var S=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=["Top","Right","Bottom","Left"],U=function(a,b){return a=b||a,"none"===m.css(a,"display")||!m.contains(a.ownerDocument,a)},V=m.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===m.type(c)){e=!0;for(h in c)m.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,m.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(m(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav></:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="<textarea>x</textarea>",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="<input type='radio' checked='checked' name='t'/>",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function aa(){return!0}function ba(){return!1}function ca(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},fix:function(a){if(a[m.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=Z.test(e)?this.mouseHooks:Y.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new m.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=f.srcElement||y),3===a.target.nodeType&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,g.filter?g.filter(a,f):a},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button,g=b.fromElement;return null==a.pageX&&null!=b.clientX&&(d=a.target.ownerDocument||y,e=d.documentElement,c=d.body,a.pageX=b.clientX+(e&&e.scrollLeft||c&&c.scrollLeft||0)-(e&&e.clientLeft||c&&c.clientLeft||0),a.pageY=b.clientY+(e&&e.scrollTop||c&&c.scrollTop||0)-(e&&e.clientTop||c&&c.clientTop||0)),!a.relatedTarget&&g&&(a.relatedTarget=g===a.target?b.toElement:g),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==ca()&&this.focus)try{return this.focus(),!1}catch(a){}},delegateType:"focusin"},blur:{trigger:function(){return this===ca()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return m.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):void 0},_default:function(a){return m.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=m.extend(new m.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?m.event.trigger(e,null,b):m.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},m.removeEvent=y.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]===K&&(a[d]=null),a.detachEvent(d,c))},m.Event=function(a,b){return this instanceof m.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?aa:ba):this.type=a,b&&m.extend(this,b),this.timeStamp=a&&a.timeStamp||m.now(),void(this[m.expando]=!0)):new m.Event(a,b)},m.Event.prototype={isDefaultPrevented:ba,isPropagationStopped:ba,isImmediatePropagationStopped:ba,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=aa,a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=aa,a&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=aa,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},m.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){m.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!m.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),k.submitBubbles||(m.event.special.submit={setup:function(){return m.nodeName(this,"form")?!1:void m.event.add(this,"click._submit keypress._submit",function(a){var b=a.target,c=m.nodeName(b,"input")||m.nodeName(b,"button")?b.form:void 0;c&&!m._data(c,"submitBubbles")&&(m.event.add(c,"submit._submit",function(a){a._submit_bubble=!0}),m._data(c,"submitBubbles",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&m.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){return m.nodeName(this,"form")?!1:void m.event.remove(this,"._submit")}}),k.changeBubbles||(m.event.special.change={setup:function(){return X.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(m.event.add(this,"propertychange._change",function(a){"checked"===a.originalEvent.propertyName&&(this._just_changed=!0)}),m.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),m.event.simulate("change",this,a,!0)})),!1):void m.event.add(this,"beforeactivate._change",function(a){var b=a.target;X.test(b.nodeName)&&!m._data(b,"changeBubbles")&&(m.event.add(b,"change._change",function(a){!this.parentNode||a.isSimulated||a.isTrigger||m.event.simulate("change",this.parentNode,a,!0)}),m._data(b,"changeBubbles",!0))})},handle:function(a){var b=a.target;return this!==b||a.isSimulated||a.isTrigger||"radio"!==b.type&&"checkbox"!==b.type?a.handleObj.handler.apply(this,arguments):void 0},teardown:function(){return m.event.remove(this,"._change"),!X.test(this.nodeName)}}),k.focusinBubbles||m.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){m.event.simulate(b,a.target,m.event.fix(a),!0)};m.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=m._data(d,b);e||d.addEventListener(a,c,!0),m._data(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=m._data(d,b)-1;e?m._data(d,b,e):(d.removeEventListener(a,c,!0),m._removeData(d,b))}}}),m.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(f in a)this.on(f,b,c,a[f],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=ba;else if(!d)return this;return 1===e&&(g=d,d=function(a){return m().off(a),g.apply(this,arguments)},d.guid=g.guid||(g.guid=m.guid++)),this.each(function(){m.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,m(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=ba),this.each(function(){m.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){m.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?m.event.trigger(a,b,c,!0):void 0}});function da(a){var b=ea.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}var ea="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",fa=/ jQuery\d+="(?:null|\d+)"/g,ga=new RegExp("<(?:"+ea+")[\\s/>]","i"),ha=/^\s+/,ia=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,ja=/<([\w:]+)/,ka=/<tbody/i,la=/<|&#?\w+;/,ma=/<(?:script|style|link)/i,na=/checked\s*(?:[^=]|=\s*.checked.)/i,oa=/^$|\/(?:java|ecma)script/i,pa=/^true\/(.*)/,qa=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,ra={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:k.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},sa=da(y),ta=sa.appendChild(y.createElement("div"));ra.optgroup=ra.option,ra.tbody=ra.tfoot=ra.colgroup=ra.caption=ra.thead,ra.th=ra.td;function ua(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ua(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function va(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wa(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xa(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function ya(a){var b=pa.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function za(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Aa(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Ba(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xa(b).text=a.text,ya(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!ga.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(ta.innerHTML=a.outerHTML,ta.removeChild(f=ta.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ua(f),h=ua(a),g=0;null!=(e=h[g]);++g)d[g]&&Ba(e,d[g]);if(b)if(c)for(h=h||ua(a),d=d||ua(f),g=0;null!=(e=h[g]);g++)Aa(e,d[g]);else Aa(a,f);return d=ua(f,"script"),d.length>0&&za(d,!i&&ua(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=da(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(la.test(f)){h=h||o.appendChild(b.createElement("div")),i=(ja.exec(f)||["",""])[1].toLowerCase(),l=ra[i]||ra._default,h.innerHTML=l[1]+f.replace(ia,"<$1></$2>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&ha.test(f)&&p.push(b.createTextNode(ha.exec(f)[0])),!k.tbody){f="table"!==i||ka.test(f)?"<table>"!==l[1]||ka.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ua(p,"input"),va),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ua(o.appendChild(f),"script"),g&&za(h),c)){e=0;while(f=h[e++])oa.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wa(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wa(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ua(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&za(ua(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ua(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fa,""):void 0;if(!("string"!=typeof a||ma.test(a)||!k.htmlSerialize&&ga.test(a)||!k.leadingWhitespace&&ha.test(a)||ra[(ja.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ia,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ua(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ua(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&na.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ua(i,"script"),xa),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ua(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,ya),j=0;f>j;j++)d=g[j],oa.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qa,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Ca,Da={};function Ea(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fa(a){var b=y,c=Da[a];return c||(c=Ea(a,b),"none"!==c&&c||(Ca=(Ca||m("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=(Ca[0].contentWindow||Ca[0].contentDocument).document,b.write(),b.close(),c=Ea(a,b),Ca.detach()),Da[a]=c),c}!function(){var a;k.shrinkWrapBlocks=function(){if(null!=a)return a;a=!1;var b,c,d;return c=y.getElementsByTagName("body")[0],c&&c.style?(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:1px;width:1px;zoom:1",b.appendChild(y.createElement("div")).style.width="5px",a=3!==b.offsetWidth),c.removeChild(d),a):void 0}}();var Ga=/^margin/,Ha=new RegExp("^("+S+")(?!px)[a-z%]+$","i"),Ia,Ja,Ka=/^(top|right|bottom|left)$/;a.getComputedStyle?(Ia=function(b){return b.ownerDocument.defaultView.opener?b.ownerDocument.defaultView.getComputedStyle(b,null):a.getComputedStyle(b,null)},Ja=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ia(a),g=c?c.getPropertyValue(b)||c[b]:void 0,c&&(""!==g||m.contains(a.ownerDocument,a)||(g=m.style(a,b)),Ha.test(g)&&Ga.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0===g?g:g+""}):y.documentElement.currentStyle&&(Ia=function(a){return a.currentStyle},Ja=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ia(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Ha.test(g)&&!Ka.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left="fontSize"===b?"1em":g,g=h.pixelLeft+"px",h.left=d,f&&(e.left=f)),void 0===g?g:g+""||"auto"});function La(a,b){return{get:function(){var c=a();if(null!=c)return c?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d,e,f,g,h;if(b=y.createElement("div"),b.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",d=b.getElementsByTagName("a")[0],c=d&&d.style){c.cssText="float:left;opacity:.5",k.opacity="0.5"===c.opacity,k.cssFloat=!!c.cssFloat,b.style.backgroundClip="content-box",b.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===b.style.backgroundClip,k.boxSizing=""===c.boxSizing||""===c.MozBoxSizing||""===c.WebkitBoxSizing,m.extend(k,{reliableHiddenOffsets:function(){return null==g&&i(),g},boxSizingReliable:function(){return null==f&&i(),f},pixelPosition:function(){return null==e&&i(),e},reliableMarginRight:function(){return null==h&&i(),h}});function i(){var b,c,d,i;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),b.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",e=f=!1,h=!0,a.getComputedStyle&&(e="1%"!==(a.getComputedStyle(b,null)||{}).top,f="4px"===(a.getComputedStyle(b,null)||{width:"4px"}).width,i=b.appendChild(y.createElement("div")),i.style.cssText=b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",i.style.marginRight=i.style.width="0",b.style.width="1px",h=!parseFloat((a.getComputedStyle(i,null)||{}).marginRight),b.removeChild(i)),b.innerHTML="<table><tr><td></td><td>t</td></tr></table>",i=b.getElementsByTagName("td"),i[0].style.cssText="margin:0;border:0;padding:0;display:none",g=0===i[0].offsetHeight,g&&(i[0].style.display="",i[1].style.display="none",g=0===i[0].offsetHeight),c.removeChild(d))}}}(),m.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var Ma=/alpha\([^)]*\)/i,Na=/opacity\s*=\s*([^)]*)/,Oa=/^(none|table(?!-c[ea]).+)/,Pa=new RegExp("^("+S+")(.*)$","i"),Qa=new RegExp("^([+-])=("+S+")","i"),Ra={position:"absolute",visibility:"hidden",display:"block"},Sa={letterSpacing:"0",fontWeight:"400"},Ta=["Webkit","O","Moz","ms"];function Ua(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=Ta.length;while(e--)if(b=Ta[e]+c,b in a)return b;return d}function Va(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=m._data(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&U(d)&&(f[g]=m._data(d,"olddisplay",Fa(d.nodeName)))):(e=U(d),(c&&"none"!==c||!e)&&m._data(d,"olddisplay",e?c:m.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}function Wa(a,b,c){var d=Pa.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Xa(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=m.css(a,c+T[f],!0,e)),d?("content"===c&&(g-=m.css(a,"padding"+T[f],!0,e)),"margin"!==c&&(g-=m.css(a,"border"+T[f]+"Width",!0,e))):(g+=m.css(a,"padding"+T[f],!0,e),"padding"!==c&&(g+=m.css(a,"border"+T[f]+"Width",!0,e)));return g}function Ya(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=Ia(a),g=k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=Ja(a,b,f),(0>e||null==e)&&(e=a.style[b]),Ha.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Xa(a,b,c||(g?"border":"content"),d,f)+"px"}m.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Ja(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":k.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=m.camelCase(b),i=a.style;if(b=m.cssProps[h]||(m.cssProps[h]=Ua(i,h)),g=m.cssHooks[b]||m.cssHooks[h],void 0===c)return g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,"string"===f&&(e=Qa.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(m.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||m.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),!(g&&"set"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=m.camelCase(b);return b=m.cssProps[h]||(m.cssProps[h]=Ua(a.style,h)),g=m.cssHooks[b]||m.cssHooks[h],g&&"get"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Ja(a,b,d)),"normal"===f&&b in Sa&&(f=Sa[b]),""===c||c?(e=parseFloat(f),c===!0||m.isNumeric(e)?e||0:f):f}}),m.each(["height","width"],function(a,b){m.cssHooks[b]={get:function(a,c,d){return c?Oa.test(m.css(a,"display"))&&0===a.offsetWidth?m.swap(a,Ra,function(){return Ya(a,b,d)}):Ya(a,b,d):void 0},set:function(a,c,d){var e=d&&Ia(a);return Wa(a,c,d?Xa(a,b,d,k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,e),e):0)}}}),k.opacity||(m.cssHooks.opacity={get:function(a,b){return Na.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=m.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,(b>=1||""===b)&&""===m.trim(f.replace(Ma,""))&&c.removeAttribute&&(c.removeAttribute("filter"),""===b||d&&!d.filter)||(c.filter=Ma.test(f)?f.replace(Ma,e):f+" "+e)}}),m.cssHooks.marginRight=La(k.reliableMarginRight,function(a,b){return b?m.swap(a,{display:"inline-block"},Ja,[a,"marginRight"]):void 0}),m.each({margin:"",padding:"",border:"Width"},function(a,b){m.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+T[d]+b]=f[d]||f[d-2]||f[0];return e}},Ga.test(a)||(m.cssHooks[a+b].set=Wa)}),m.fn.extend({css:function(a,b){return V(this,function(a,b,c){var d,e,f={},g=0;if(m.isArray(b)){for(d=Ia(a),e=b.length;e>g;g++)f[b[g]]=m.css(a,b[g],!1,d);return f}return void 0!==c?m.style(a,b,c):m.css(a,b)},a,b,arguments.length>1)},show:function(){return Va(this,!0)},hide:function(){return Va(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){U(this)?m(this).show():m(this).hide()})}});function Za(a,b,c,d,e){
return new Za.prototype.init(a,b,c,d,e)}m.Tween=Za,Za.prototype={constructor:Za,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(m.cssNumber[c]?"":"px")},cur:function(){var a=Za.propHooks[this.prop];return a&&a.get?a.get(this):Za.propHooks._default.get(this)},run:function(a){var b,c=Za.propHooks[this.prop];return this.options.duration?this.pos=b=m.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Za.propHooks._default.set(this),this}},Za.prototype.init.prototype=Za.prototype,Za.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=m.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){m.fx.step[a.prop]?m.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[m.cssProps[a.prop]]||m.cssHooks[a.prop])?m.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Za.propHooks.scrollTop=Za.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},m.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},m.fx=Za.prototype.init,m.fx.step={};var $a,_a,ab=/^(?:toggle|show|hide)$/,bb=new RegExp("^(?:([+-])=|)("+S+")([a-z%]*)$","i"),cb=/queueHooks$/,db=[ib],eb={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=bb.exec(b),f=e&&e[3]||(m.cssNumber[a]?"":"px"),g=(m.cssNumber[a]||"px"!==f&&+d)&&bb.exec(m.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,m.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function fb(){return setTimeout(function(){$a=void 0}),$a=m.now()}function gb(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=T[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function hb(a,b,c){for(var d,e=(eb[b]||[]).concat(eb["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function ib(a,b,c){var d,e,f,g,h,i,j,l,n=this,o={},p=a.style,q=a.nodeType&&U(a),r=m._data(a,"fxshow");c.queue||(h=m._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,n.always(function(){n.always(function(){h.unqueued--,m.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=m.css(a,"display"),l="none"===j?m._data(a,"olddisplay")||Fa(a.nodeName):j,"inline"===l&&"none"===m.css(a,"float")&&(k.inlineBlockNeedsLayout&&"inline"!==Fa(a.nodeName)?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",k.shrinkWrapBlocks()||n.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],ab.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||m.style(a,d)}else j=void 0;if(m.isEmptyObject(o))"inline"===("none"===j?Fa(a.nodeName):j)&&(p.display=j);else{r?"hidden"in r&&(q=r.hidden):r=m._data(a,"fxshow",{}),f&&(r.hidden=!q),q?m(a).show():n.done(function(){m(a).hide()}),n.done(function(){var b;m._removeData(a,"fxshow");for(b in o)m.style(a,b,o[b])});for(d in o)g=hb(q?r[d]:0,d,n),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function jb(a,b){var c,d,e,f,g;for(c in a)if(d=m.camelCase(c),e=b[d],f=a[c],m.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=m.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kb(a,b,c){var d,e,f=0,g=db.length,h=m.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=$a||fb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:m.extend({},b),opts:m.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:$a||fb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=m.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jb(k,j.opts.specialEasing);g>f;f++)if(d=db[f].call(j,a,k,j.opts))return d;return m.map(k,hb,j),m.isFunction(j.opts.start)&&j.opts.start.call(a,j),m.fx.timer(m.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}m.Animation=m.extend(kb,{tweener:function(a,b){m.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],eb[c]=eb[c]||[],eb[c].unshift(b)},prefilter:function(a,b){b?db.unshift(a):db.push(a)}}),m.speed=function(a,b,c){var d=a&&"object"==typeof a?m.extend({},a):{complete:c||!c&&b||m.isFunction(a)&&a,duration:a,easing:c&&b||b&&!m.isFunction(b)&&b};return d.duration=m.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in m.fx.speeds?m.fx.speeds[d.duration]:m.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){m.isFunction(d.old)&&d.old.call(this),d.queue&&m.dequeue(this,d.queue)},d},m.fn.extend({fadeTo:function(a,b,c,d){return this.filter(U).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=m.isEmptyObject(a),f=m.speed(b,c,d),g=function(){var b=kb(this,m.extend({},a),f);(e||m._data(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=m.timers,g=m._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&cb.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&m.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=m._data(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=m.timers,g=d?d.length:0;for(c.finish=!0,m.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),m.each(["toggle","show","hide"],function(a,b){var c=m.fn[b];m.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(gb(b,!0),a,d,e)}}),m.each({slideDown:gb("show"),slideUp:gb("hide"),slideToggle:gb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){m.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),m.timers=[],m.fx.tick=function(){var a,b=m.timers,c=0;for($a=m.now();c<b.length;c++)a=b[c],a()||b[c]!==a||b.splice(c--,1);b.length||m.fx.stop(),$a=void 0},m.fx.timer=function(a){m.timers.push(a),a()?m.fx.start():m.timers.pop()},m.fx.interval=13,m.fx.start=function(){_a||(_a=setInterval(m.fx.tick,m.fx.interval))},m.fx.stop=function(){clearInterval(_a),_a=null},m.fx.speeds={slow:600,fast:200,_default:400},m.fn.delay=function(a,b){return a=m.fx?m.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a,b,c,d,e;b=y.createElement("div"),b.setAttribute("className","t"),b.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",d=b.getElementsByTagName("a")[0],c=y.createElement("select"),e=c.appendChild(y.createElement("option")),a=b.getElementsByTagName("input")[0],d.style.cssText="top:1px",k.getSetAttribute="t"!==b.className,k.style=/top/.test(d.getAttribute("style")),k.hrefNormalized="/a"===d.getAttribute("href"),k.checkOn=!!a.value,k.optSelected=e.selected,k.enctype=!!y.createElement("form").enctype,c.disabled=!0,k.optDisabled=!e.disabled,a=y.createElement("input"),a.setAttribute("value",""),k.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),k.radioValue="t"===a.value}();var lb=/\r/g;m.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=m.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,m(this).val()):a,null==e?e="":"number"==typeof e?e+="":m.isArray(e)&&(e=m.map(e,function(a){return null==a?"":a+""})),b=m.valHooks[this.type]||m.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=m.valHooks[e.type]||m.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(lb,""):null==c?"":c)}}}),m.extend({valHooks:{option:{get:function(a){var b=m.find.attr(a,"value");return null!=b?b:m.trim(m.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&m.nodeName(c.parentNode,"optgroup"))){if(b=m(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=m.makeArray(b),g=e.length;while(g--)if(d=e[g],m.inArray(m.valHooks.option.get(d),f)>=0)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),m.each(["radio","checkbox"],function(){m.valHooks[this]={set:function(a,b){return m.isArray(b)?a.checked=m.inArray(m(a).val(),b)>=0:void 0}},k.checkOn||(m.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var mb,nb,ob=m.expr.attrHandle,pb=/^(?:checked|selected)$/i,qb=k.getSetAttribute,rb=k.input;m.fn.extend({attr:function(a,b){return V(this,m.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){m.removeAttr(this,a)})}}),m.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===K?m.prop(a,b,c):(1===f&&m.isXMLDoc(a)||(b=b.toLowerCase(),d=m.attrHooks[b]||(m.expr.match.bool.test(b)?nb:mb)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=m.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void m.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=m.propFix[c]||c,m.expr.match.bool.test(c)?rb&&qb||!pb.test(c)?a[d]=!1:a[m.camelCase("default-"+c)]=a[d]=!1:m.attr(a,c,""),a.removeAttribute(qb?c:d)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&m.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),nb={set:function(a,b,c){return b===!1?m.removeAttr(a,c):rb&&qb||!pb.test(c)?a.setAttribute(!qb&&m.propFix[c]||c,c):a[m.camelCase("default-"+c)]=a[c]=!0,c}},m.each(m.expr.match.bool.source.match(/\w+/g),function(a,b){var c=ob[b]||m.find.attr;ob[b]=rb&&qb||!pb.test(b)?function(a,b,d){var e,f;return d||(f=ob[b],ob[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,ob[b]=f),e}:function(a,b,c){return c?void 0:a[m.camelCase("default-"+b)]?b.toLowerCase():null}}),rb&&qb||(m.attrHooks.value={set:function(a,b,c){return m.nodeName(a,"input")?void(a.defaultValue=b):mb&&mb.set(a,b,c)}}),qb||(mb={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+="","value"===c||b===a.getAttribute(c)?b:void 0}},ob.id=ob.name=ob.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&""!==d.value?d.value:null},m.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:mb.set},m.attrHooks.contenteditable={set:function(a,b,c){mb.set(a,""===b?!1:b,c)}},m.each(["width","height"],function(a,b){m.attrHooks[b]={set:function(a,c){return""===c?(a.setAttribute(b,"auto"),c):void 0}}})),k.style||(m.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+""}});var sb=/^(?:input|select|textarea|button|object)$/i,tb=/^(?:a|area)$/i;m.fn.extend({prop:function(a,b){return V(this,m.prop,a,b,arguments.length>1)},removeProp:function(a){return a=m.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),m.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!m.isXMLDoc(a),f&&(b=m.propFix[b]||b,e=m.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=m.find.attr(a,"tabindex");return b?parseInt(b,10):sb.test(a.nodeName)||tb.test(a.nodeName)&&a.href?0:-1}}}}),k.hrefNormalized||m.each(["href","src"],function(a,b){m.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),k.optSelected||(m.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}}),m.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){m.propFix[this.toLowerCase()]=this}),k.enctype||(m.propFix.enctype="encoding");var ub=/[\t\r\n\f]/g;m.fn.extend({addClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j="string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).addClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ub," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=m.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j=0===arguments.length||"string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).removeClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ub," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?m.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(m.isFunction(a)?function(c){m(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=m(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===K||"boolean"===c)&&(this.className&&m._data(this,"__className__",this.className),this.className=this.className||a===!1?"":m._data(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(ub," ").indexOf(b)>=0)return!0;return!1}}),m.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){m.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),m.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var vb=m.now(),wb=/\?/,xb=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;m.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+"");var c,d=null,e=m.trim(b+"");return e&&!m.trim(e.replace(xb,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,"")}))?Function("return "+e)():m.error("Invalid JSON: "+b)},m.parseXML=function(b){var c,d;if(!b||"string"!=typeof b)return null;try{a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName("parsererror").length||m.error("Invalid XML: "+b),c};var yb,zb,Ab=/#.*$/,Bb=/([?&])_=[^&]*/,Cb=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Db=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Eb=/^(?:GET|HEAD)$/,Fb=/^\/\//,Gb=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Hb={},Ib={},Jb="*/".concat("*");try{zb=location.href}catch(Kb){zb=y.createElement("a"),zb.href="",zb=zb.href}yb=Gb.exec(zb.toLowerCase())||[];function Lb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(m.isFunction(c))while(d=f[e++])"+"===d.charAt(0)?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Mb(a,b,c,d){var e={},f=a===Ib;function g(h){var i;return e[h]=!0,m.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Nb(a,b){var c,d,e=m.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&m.extend(!0,a,c),a}function Ob(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader("Content-Type"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+" "+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Pb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}m.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:zb,type:"GET",isLocal:Db.test(yb[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Jb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":m.parseJSON,"text xml":m.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Nb(Nb(a,m.ajaxSettings),b):Nb(m.ajaxSettings,a)},ajaxPrefilter:Lb(Hb),ajaxTransport:Lb(Ib),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=m.ajaxSetup({},b),l=k.context||k,n=k.context&&(l.nodeType||l.jquery)?m(l):m.event,o=m.Deferred(),p=m.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!j){j={};while(b=Cb.exec(f))j[b[1].toLowerCase()]=b[2]}b=j[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?f:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return i&&i.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||zb)+"").replace(Ab,"").replace(Fb,yb[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=m.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(c=Gb.exec(k.url.toLowerCase()),k.crossDomain=!(!c||c[1]===yb[1]&&c[2]===yb[2]&&(c[3]||("http:"===c[1]?"80":"443"))===(yb[3]||("http:"===yb[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=m.param(k.data,k.traditional)),Mb(Hb,k,b,v),2===t)return v;h=m.event&&k.global,h&&0===m.active++&&m.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!Eb.test(k.type),e=k.url,k.hasContent||(k.data&&(e=k.url+=(wb.test(e)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=Bb.test(e)?e.replace(Bb,"$1_="+vb++):e+(wb.test(e)?"&":"?")+"_="+vb++)),k.ifModified&&(m.lastModified[e]&&v.setRequestHeader("If-Modified-Since",m.lastModified[e]),m.etag[e]&&v.setRequestHeader("If-None-Match",m.etag[e])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+Jb+"; q=0.01":""):k.accepts["*"]);for(d in k.headers)v.setRequestHeader(d,k.headers[d]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(d in{success:1,error:1,complete:1})v[d](k[d]);if(i=Mb(Ib,k,b,v)){v.readyState=1,h&&n.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,i.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,c,d){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),i=void 0,f=d||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,c&&(u=Ob(k,v,c)),u=Pb(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(m.lastModified[e]=w),w=v.getResponseHeader("etag"),w&&(m.etag[e]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,h&&n.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),h&&(n.trigger("ajaxComplete",[v,k]),--m.active||m.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return m.get(a,b,c,"json")},getScript:function(a,b){return m.get(a,void 0,b,"script")}}),m.each(["get","post"],function(a,b){m[b]=function(a,c,d,e){return m.isFunction(c)&&(e=e||d,d=c,c=void 0),m.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),m._evalUrl=function(a){return m.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},m.fn.extend({wrapAll:function(a){if(m.isFunction(a))return this.each(function(b){m(this).wrapAll(a.call(this,b))});if(this[0]){var b=m(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return this.each(m.isFunction(a)?function(b){m(this).wrapInner(a.call(this,b))}:function(){var b=m(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=m.isFunction(a);return this.each(function(c){m(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){m.nodeName(this,"body")||m(this).replaceWith(this.childNodes)}).end()}}),m.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0||!k.reliableHiddenOffsets()&&"none"===(a.style&&a.style.display||m.css(a,"display"))},m.expr.filters.visible=function(a){return!m.expr.filters.hidden(a)};var Qb=/%20/g,Rb=/\[\]$/,Sb=/\r?\n/g,Tb=/^(?:submit|button|image|reset|file)$/i,Ub=/^(?:input|select|textarea|keygen)/i;function Vb(a,b,c,d){var e;if(m.isArray(b))m.each(b,function(b,e){c||Rb.test(a)?d(a,e):Vb(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==m.type(b))d(a,b);else for(e in b)Vb(a+"["+e+"]",b[e],c,d)}m.param=function(a,b){var c,d=[],e=function(a,b){b=m.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=m.ajaxSettings&&m.ajaxSettings.traditional),m.isArray(a)||a.jquery&&!m.isPlainObject(a))m.each(a,function(){e(this.name,this.value)});else for(c in a)Vb(c,a[c],b,e);return d.join("&").replace(Qb,"+")},m.fn.extend({serialize:function(){return m.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=m.prop(this,"elements");return a?m.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!m(this).is(":disabled")&&Ub.test(this.nodeName)&&!Tb.test(a)&&(this.checked||!W.test(a))}).map(function(a,b){var c=m(this).val();return null==c?null:m.isArray(c)?m.map(c,function(a){return{name:b.name,value:a.replace(Sb,"\r\n")}}):{name:b.name,value:c.replace(Sb,"\r\n")}}).get()}}),m.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return!this.isLocal&&/^(get|post|head|put|delete|options)$/i.test(this.type)&&Zb()||$b()}:Zb;var Wb=0,Xb={},Yb=m.ajaxSettings.xhr();a.attachEvent&&a.attachEvent("onunload",function(){for(var a in Xb)Xb[a](void 0,!0)}),k.cors=!!Yb&&"withCredentials"in Yb,Yb=k.ajax=!!Yb,Yb&&m.ajaxTransport(function(a){if(!a.crossDomain||k.cors){var b;return{send:function(c,d){var e,f=a.xhr(),g=++Wb;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)void 0!==c[e]&&f.setRequestHeader(e,c[e]+"");f.send(a.hasContent&&a.data||null),b=function(c,e){var h,i,j;if(b&&(e||4===f.readyState))if(delete Xb[g],b=void 0,f.onreadystatechange=m.noop,e)4!==f.readyState&&f.abort();else{j={},h=f.status,"string"==typeof f.responseText&&(j.text=f.responseText);try{i=f.statusText}catch(k){i=""}h||!a.isLocal||a.crossDomain?1223===h&&(h=204):h=j.text?200:404}j&&d(h,i,j,f.getAllResponseHeaders())},a.async?4===f.readyState?setTimeout(b):f.onreadystatechange=Xb[g]=b:b()},abort:function(){b&&b(void 0,!0)}}}});function Zb(){try{return new a.XMLHttpRequest}catch(b){}}function $b(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}m.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return m.globalEval(a),a}}}),m.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),m.ajaxTransport("script",function(a){if(a.crossDomain){var b,c=y.head||m("head")[0]||y.documentElement;return{send:function(d,e){b=y.createElement("script"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||e(200,"success"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var _b=[],ac=/(=)\?(?=&|$)|\?\?/;m.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=_b.pop()||m.expando+"_"+vb++;return this[a]=!0,a}}),m.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(ac.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&ac.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=m.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(ac,"$1"+e):b.jsonp!==!1&&(b.url+=(wb.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||m.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,_b.push(e)),g&&m.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),m.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||y;var d=u.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=m.buildFragment([a],b,e),e&&e.length&&m(e).remove(),m.merge([],d.childNodes))};var bc=m.fn.load;m.fn.load=function(a,b,c){if("string"!=typeof a&&bc)return bc.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=m.trim(a.slice(h,a.length)),a=a.slice(0,h)),m.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(f="POST"),g.length>0&&m.ajax({url:a,type:f,dataType:"html",data:b}).done(function(a){e=arguments,g.html(d?m("<div>").append(m.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,e||[a.responseText,b,a])}),this},m.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){m.fn[b]=function(a){return this.on(b,a)}}),m.expr.filters.animated=function(a){return m.grep(m.timers,function(b){return a===b.elem}).length};var cc=a.document.documentElement;function dc(a){return m.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}m.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=m.css(a,"position"),l=m(a),n={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=m.css(a,"top"),i=m.css(a,"left"),j=("absolute"===k||"fixed"===k)&&m.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),m.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(n.top=b.top-h.top+g),null!=b.left&&(n.left=b.left-h.left+e),"using"in b?b.using.call(a,n):l.css(n)}},m.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){m.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,m.contains(b,e)?(typeof e.getBoundingClientRect!==K&&(d=e.getBoundingClientRect()),c=dc(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===m.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),m.nodeName(a[0],"html")||(c=a.offset()),c.top+=m.css(a[0],"borderTopWidth",!0),c.left+=m.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-m.css(d,"marginTop",!0),left:b.left-c.left-m.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||cc;while(a&&!m.nodeName(a,"html")&&"static"===m.css(a,"position"))a=a.offsetParent;return a||cc})}}),m.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);m.fn[a]=function(d){return V(this,function(a,d,e){var f=dc(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?m(f).scrollLeft():e,c?e:m(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),m.each(["top","left"],function(a,b){m.cssHooks[b]=La(k.pixelPosition,function(a,c){return c?(c=Ja(a,b),Ha.test(c)?m(a).position()[b]+"px":c):void 0})}),m.each({Height:"height",Width:"width"},function(a,b){m.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){m.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return V(this,function(b,c,d){var e;return m.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?m.css(b,c,g):m.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),m.fn.size=function(){return this.length},m.fn.andSelf=m.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return m});var ec=a.jQuery,fc=a.$;return m.noConflict=function(b){return a.$===m&&(a.$=fc),b&&a.jQuery===m&&(a.jQuery=ec),m},typeof b===K&&(a.jQuery=a.$=m),m});
     <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>

       <div class="progress">
         <div class="progress-bar progress-bar-{{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>
     <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>

     <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>

<!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">
  <link href="{{path_to_root}}css/style.css" rel="stylesheet">
  <!--[if lt IE 9]>
  <script src="{{path_to_root}}js/html5shiv.min.js"></script>
  <script src="{{path_to_root}}js/respond.min.js"></script>
  <![endif]-->
 </head>
 <body>
  <header>
   <div class="container">
    <div class="row">
     <div class="col-md-12">
      <ol class="breadcrumb">
{{breadcrumbs}}
      </ol>
     </div>
    </div>
   </div>
  </header>
  <div class="container">
   <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>
   <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="http://github.com/sebastianbergmann/php-code-coverage" target="_top">PHP_CodeCoverage {{version}}</a> using <a href="{{runtime_link}}" target="_top">{{runtime_name}} {{runtime_version}}</a>{{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/bootstrap.min.js" type="text/javascript"></script>
  <script src="{{path_to_root}}js/holder.min.js" type="text/javascript"></script>
 </body>
</html>
wOFF     [     \                       FFTM  X      m*GDEF  t       D OS/2     E   `gkcmap      rڭcvt          (gasp         glyf    M  }]ohead  Q   4   6M/hhea  Q      $
Dhmtx  R  O  t `loca  S`  '  0omaxp  U        j name  U    ,post  WH  -  
Ѻ5webf  [x      TP       =    vu    vsxc`d``b	`b`d`d,` H J xc`fft!
B3.a0b	?@u"@aF$%
 1   x?hSAiSm߽44,qPK qXE](2	.ԩ] "ED
i]DԡZJ\8wwV"FpUԯ.Χ(gK4On;NR{g`'!PMUHEՠJʫ*Yq9c<U9!QIYׅ-KC+	դU)Q94JYp]Nq9.qyVV
n)9[{vVכ־FWb++{>׍a|*gQ,K<'<!ɣrYw֜βy<q9{-]c]oI!0l67͍{jG,OX^PdQ{,M4c(QBX m!K,YHa2}̘0BA)ؐF}΀,Q8'A5(>W@Ex̢D&Ud#&xMx<aa,l2<M026Π^P$Ґ6{,#ƞ{MwpB8H #67ad&'~95r
3w"[EtW:ӭ:$">2c5*.lN/h]GtT  (    xŽ	|յ0>wm#Ye[%Y-YR'rYjD% 	,@BKZjHڤ@b-R+nhK~룼$;h^fܹsn{ι˴0kb8Fd:%Lה"1AՔAY>,ؔ#pZ4؟5made ?Ȝy=I:C D(nIxL.1!P'JDtHj@L4Ph' )b)vHX,f1c\'cGu>1~t?!xT_q?qBF#L%Dћ"?Yǯj??8>NSkemAYDb4J);@jP$
'qh8`;aX6CF*dYc"'?hLV㗌,>ce3eVh =C~xC\((qb@4xK&hׁ4\2Ǳ6N1|-;jYu@jѫxi䊧mKٍDEwq3̷.cAw@4t.gkgr{~Wl~{lW2}276a2\6oz@$HSH gbtX70Ktc1,7BoLƏ66[,%iZ,l>TpKSGg\>#A#3Eyk6v;u3!ZI8M k?8CWq{`C*h>H1_skh)ojOO'
!~dXgB(0<kOYxeƧĭ5k=dϧ> +tC-o
Ǫ/_koܶs+fOztpu7-}d9	se \9.H4!0S\ ʱk2"?ip7\2zlްt=W\!KyOXimUnov6:2LZkAA^qCޔ	&PaFI0>&Q#FQl>A·q*OȦ_@27l,sf6p7ܩ?M1vA2]$j";vlk~va0gjzRD:gc6yw%g(þ#'uB#=_@?>FVb0a!aL4tXv:Fh9j^xތz}Wn}7}jΚiHitKSaXEEbbBQ1ftxFȮ-"dqA\~F`6i䁕+Ԣ^Ȳ}ש׆k&Ĺ<-\;g1>w00v^x 7l<y}So9-ۮ6kбl˴no庾i[u~¬o`j{i\C4,"iW8JoVbpwC!;'7D.v֏noZ-nePio4~LY/zmw_gϽR"tޠ&NoN)4MCG2\j8d-@>#Ot^5+xe.^]׼G8^ m(t1	sbfJ	%< 4H@e8C,5<(kc5YIA]|ךl6+=HVcbKՋB6i4#_|&>NvQk#pW=u7HɰR$[5싙g	%19}&@$&l=1RI}9#ςz??1z&ı_ac|PI[:u;l->k4GYm|Zw}HnR=-B~m.ِ	.Mz^,0%8EG**|sg|ozO֬0sz.WN^	yHk<J{nEh

TG~o]VṇznАzd,/)jl.w<w	?5*FqH|<f7[6Td?C8S'N
#0f2^~7:
mM	I`M:ӊHF9B:gSkozk#Sǫoc3A'ӹm׾iknZ-yZP=Uc'?&ȏKEul;><v3t{8-|'
ea~H94xA-@ybT4@0b#]DDljDSio:AgSP z:;-|yH"r{B{\5RLi6AAtM]taRKC!1CgC샂 +1EG!Xzٛnzv@x -#i^x*$)W=O\f[WX~V?`Lei::v4$?=Ra#c]8YFJb&'{%LCECf]^$/fߪM;À;	6CXV#X~F<	:vCcyBpLv1Fv#9
/8VF01_K?x>}#G7т\Wp!.@bwɡ+{o#ԍPQҮnī66
cZD(. u;nM}?vtxF{+`
="rPπlDV̶ ? Z@H䰅][35%O)\^ Z;>Ftf-IzӮ yu1uo<:oa:uqwykk ⋜}0?jvX+}VG$s
?26YI5c$Cfb!X*|F^$p7p55߶6[mjgl>*	KO&
 8ܝ:ǰokKm~oS-*4E}P/%k:e"1AJCAX8=	 LŢ>ܱav{|K.3:\Bxwbeb<n/NjNjOTQMէ g[
׼1J[H*d÷J(RY}ҘchC;ayh&Cq;7/SGny'^9wה[yF`4;upX_#6Qy'xCq/QP&Nt 4pԍqD2/عi=X܆DA<->>1ۿvH?f58%6$ɲ'pL^HXbpIVqnA8Kg'i!UzSEI5N=hpV?(E Vr?޴7Vڋɿ.O;p 4NRZm.O> MuL'j5`;MtAQܶMyV<`$m)yڳXDa:݁q1JFq15-l\3~X-2pFDe/f!2i:=h{%{t^*PBͽ]YD3jd*w|GLϽ}ˑk7Ç=06oz*zo1~Jw00SePw%#@BJB	%+	';%!&)Hq 7fqH.!Eǎf,9՚$9 H{~i	Z)O|!"D.KQa2
%2Wɂ\{*B{7,9.'ew U^W&$r9rcGBwll<ʷSQゅh! iѨvJ:Y?#_m4q[},EA{VПP|Dg?9MId?{)/	/\[ Jҏ[f4G>QK^m O -7w]<U3jƏ,:Yq~0/mŵ@CCFq<yxh\0=RgYd((_2a_{pMT*0UT!if$ԟ(WqRC:Pa3=b rK1'-{HʽH1'`kϯex$.h{܆`FzE0c5xfM䏾}߾SSK]Nf'pPιS`BmmHv94ሄ^m D	$,'܄ pWɭgdV/L;MZLꭵH>{,Θ쬷ΘQSolsɿh?A2q`5Z&*X1L5:6ς+O]uej%?ۼ&aW?{2[}W?JbΙk-\b7sIkf&Λfx~nO-9V~cW"ȗy)b\)2MrWf;MU7'[-c/.ؾuMl&.9) G!!W*	60Cф#qrqOKZOWq,8́/XpTȑg<>¤)[J8o`
;S\S%h~p|J˾F~K=E0NQX*8;D7Q1QC%*Eyy} UG?>I`>'6<+3IVgϮyOQ$WBvH	v[Ϗ	2+'ø6N߆<ɕ2S娚9X1\┣df>B~-t>W]pPrZ['+ƌl9]8qC!'@AAOuШ
!?M\JMͭfǞ)ߕ=w?AN>¼}jQ<ǏpǠ^(}1+2qF4RiHďITr8^!gm>'ڸhE`s̊ol!(9~o%#)~ƃj$@ՔLpGOa{߿fé)zؔY<~^cs潺ݴNRURTY%8Ks3qd]^QTb' zx)HFҩPmUZjQ&XƁo<0jYGz]$8c&hyݼwΞ{9^sf߹m[vӣ!(ZAsۧyB8RiԣBg6{UmtyW!bpǮdn/ŷʼ@v/%cxEn:4Y²,yZ-krcH&^ȩC'Ȯ'^T5r)((IJU&#݌!+YM.JEX^|Lw@ھZsgY洺\ xԟxyLCyo<QO$)W6m%݆r݆dս{ObpAE܀ʌgi~AO"mo*![TmdHT1$
	PԐ4^sfcA3,XAPbksY	yHhP+bW=};"Z&x<SySVY&=4&1J5u~,ӿzeg^QB\/Pʄ%+pre|Pn TcZ>?eV"_[Q/5Y |qI/\9diEBh$vwOL fpa,?HgHf2RbL
v	>USo^1/,ēvcYGmŨ~Amz?/40 yj̸pk2H
eERb/"M75ul[drC&Y͐&I
`!>p;J-b--.VM4>Fj/5σt5}>C*<'d?,cdGf2ҁ0w6Lh"fKζp;ǿ϶Pdc1EOi%Ř(DCWV2I)TiMF Tz0U S7VmBW6;nYZUzSTg>(hF"޽T뽷R]L۶|Lx[s,'NU|E<4)Rp*vU#g*gjə*=~܃ASēAJHw3@NurbwȀʌx}[`7ZtPlh	L.)NU}kq'vFQr׷{ˤS]ZL(@*Sf^+uPe_k#.8ɂ%ՠ,@TKх
t`ߑXAD;b|pA7}q2
@Y`~iԬK0jY(R~^ҧ8>=F"˜A[DqvQCX|ZsO<NǦcPI|։2ů1Q|FH\[Tk޽$3X5ˮAq_rv7@v2ˀi%m؊fP^{ovvyfVw4ew""Zd[TCʭ"ٛ!Cƛ#^
ZfR4x pVrSK\B]Q
B~#V*px^(o/`Dס.EOWTv6M^~Eyl/ѫǊlQ6Mq":}Hea-EY"z"ȏVKF58/7
tDn#D*'^IZ}pITmdL%7@C:FBy% KS<KReīsok|ȝr^su~wN_VP6;Y\\lmI"R
2 ts0^~
;gELc7"<^$g$ysL״$֠ D>	\/f.F;kPbdz7ԐeͶ-6bybaWjnh7YLF!4wssFCnh_0>MZ nC*#5/OUN\(3o@[7`Mg8xge;f\y|f֤ޑ]i5q5q&>'353kYꭑ=W7+΋yxIe<PhX	av׸"cJcoHOCu]L5kі]x~#;!)B58/PHF#0B(p}FstM|l)]tϼ&ݖ,㙗nt,h[Y4ݬ$wQג,@k`Dg]r|Y}VqwRC*9[oΝdX6&=}߰/*͏\ ˔)5gOlӦ}1:>OYǏs(p6[B/t爁*̠-n:<Ц)+ް~q_}oxt>LVFG@d9[<s/.<7sBdB'wXοZ鵣W՗>2?2ȳ8笞={fgcsCmre#E>45qo:JX^ioP,xf:/yn9VѥS7=u-\%KϦUv,ⳀZ=vkN*+_.ڊ֞iڃ=w@lmr>Oo,VԲɝz&:'45!9pI	0@I[PU""sInvR>A9t$3/|k8yiEc8E!Q\ۂ}%Af4s*A8A΀>D=5uwjnG z?2Q/I=fH4n]澀YmG"2PEHfvZn<PiA_q/PDտ	$$~%NyhrOdM\-m(@\#ƼNJO>a+ uJ*(%¢FPJW,$))}
B\_wV] 0TOCÊQ}5{Ho*;;葞rǨMc54S
: M7(kY:z`gpJstˉv'eG^~iD16dA @'N ֭<?Ғ9庳bɩEÁ:h{h0vۧQ~{"HGQkl<:ʛ^g/_iP>N.?f1bzJD V
o@7R@6<%IF0mj=[}Nۊ57pyv4@<mЭ9Tp?R70қQG[jzib~/)wC?	רa-/Cn.ĕHj63pKrhXIƎj
o19
f\~:-ѓK47BY̆y%DC~em@]%rs4T	G-Ug>HOpVB]{9&^6|m_PLLI7ǒi"'T	}? 4|[Fǭtu/_y;Z?HK0Wzc#)~.rĥ+B&JG0[.ΡrOk;VCoX K۝S߳rt:zX\xmJhxNh5K`;ydp.Ec4XD<-llip.^p:u/.Y[rl_4kz$~Dq]7/T_<菵4K$Ɩ &wS7|K^7MsMGhw㢴0]?fja5aiЦ6C2nof=)d^v	qNcԎl=u]?;f-E~nv}5%Oջd덿=Z%v nKu ̓*J#1hu1Hr	o}SZu=w;nϗU`FȶEn?߫k&l9YdgA8NSGD09MAK{ހK3݊ [_]%W4zۈu9\~n3~zirX3k`Psn=m]ԃJksT9deYN`}/]U#b;Rt,lh*#JB+
(iGx\}~IֳFv@Tu֭J

@-LwzYgw`wx-(d٢]F3_XcYmQԃWb-FK5d-0b球֨T+_Zxcj*`}|x~LF*S*oMتAT1p71?Rt>R'"Ey)oP7%$rvQeE+nzlVlFrkt''?R'ZCEIKy	ga0^}pE;Kq{T/?i"%1ޒb-Ծqƛ˵+ 8]rIڣV{dȪ͜\AQvOS]0.NX9svb?OE~FPU}o[YKrA̓U%7Dwqb/hAhPbQؓJB8I?I%=XtO;(PhLdS 'hݱ>|TV?,O"\`7.2>Dfmg;-C'u, zA`-ټ$xvck2[xp\cbl΀ihsivaÛM,gĨlMz7JvˑVRWϋNo4(-XB^Cl&Vnnn D4[k6N&}f3YQw@$U$(Ǫo:-ZG#&/}?N}ƥ7A!MhW>?iXprA١b?uϱι-h6;SB#/@ѿJ	
!%Q)Dq:{JI^ޑˡPY7UG(h?HmъvREH=N`P)QG9FMSMG@2E$Q
$s~TkN"9Ն8cF^"?+G٠
^*gUlFVxUpoC.XCƵ׵͉qK[k[K(l;ӡn %^Rj,$) 1n.G:Cf(,;ĴRF_~^;իD;6|/jGGSSGGӎļDzbR/X?Up14u$`[ߜH477I~~Irߙs#6+heW6@wK̸h6,	1C"=meA=@z	sls];kklr^"s青>&Մ-[{JiҴ9[ݵȩ-]dޢcAn۹g}ꒇ6hTɖ?3s^kLcY1Zn[bݴE߆դwk3f>fMDՠaD~}&@5ugnOȢ<'`&bӬ-6;X"d*awYvtLXָkU ߩa=HR_@+j2T*£%/͸oƤy19/7 ~7_o+$DүsIH:r		yiF:v(dO":omdM8;Z9uʩHCg\K/*ԙg*-I_ERqR'[f?GUAovb	A$e]/Կo?|ԐQm4G7G833+74z*)$݋JpDNj5pqeDf/>%gW{U:g,nlU\t'%E}͝uCꘒܻߺp}U+^b'o(5gVBIOEm>5yzg}AP-P/ޫ 6)x5/t;1p1L9Aܳ|)X]mkFEH/4}:,oLMo6]YM50u[yҫfVh?E-A_i﫝j.
6|5`#Z-svfqӟs͚>w7C{	A]Bz,iH'dv?`E
x,mz`F[2avhp%(̒ʂ5Ԧ;Gюh\y";|"ٝʖrxzsPHCTvP$ly}iyhvMCr)#x-.(t%fu(ۅeUUo
pqeˡ啗syi	Xk`>X@2P.2͌>n|,/4}?A&Jr+ɐCV]{Z0 -	A=
F$+%UZyޗٲRB)wT8(aRΣ*-sr5v!^tZ:/K,'F9=G< Cu"$-FS2(F
0Q+Xw,]=bh[qBQI;)"Ō926r?}lV=b[j4AzKkQ?T[%$KQ-l_@l/	&;차Dr?P_dE1~z^I~breufP/պ#E+S\G-R4	SSV俑;*`G*5'dL
~	5Fhb`
ꁜ4[b$~GNAX$~}[W}_z×6m&~O%j/r&|_Sy<-*Lϛ,JQzͤ𫷣|V|GVW~<mblB&̭jy\r='9Hf)ԅr	w!;;vsB7Ӏ'k*irb/K+ԔWRO h$!`1[r(a\TR"P?]Y;?хyKRXWOCzܩHjPn[忊;͇GqZ.A.*@/)WQHQUL2^$,T=Q (J~BIUPJ=WC@ﰉ8&~DWk[<Տ}."S<#A>z	
HE	YnH4r7P?99ߡ|O-5	%4	ǳO/4L_PsT>LQD(J8F+)jCb
Mu2Xc8$t}&<?9lW~ҿ͑n90A=&W=sԿ_V}?kU(mutE*
K%tZpJ BWP Al(ZLzFZ}/40lV	i%L^V`jpP5QVVkzX8^sţW4U*u}L8F  ~3B"I/.O
=7BJA KQ-|Vw|()8C%ʴTols7*rev٢6mǖ	CTpT'ǑpL!jRC4}aSm[%4a.첹},LB=:ݍ'bdm}VY,t;9	:\I5fDAuIFH2 @:2	!ԏj-@ٵG`vKcwIlar%lEs
rDeTib@d4BDHT. ]K*շs\mF::4vX<;r%6aꇷܥGѧ|gуhvqtJJKH^vgp.?뜸B0^q8|fS[tCxҔ׬fй
^FB
PiWFpRU
:̓D}فv}4z/F<P莣\U'c?4sJjj>@Qr-֤U_o6q7P1ˤ+rc6I
\ (*v24Uc(A ̣93]z;0'=*,e56Va,qh*P@wȬG/Oj|FIm	#Pz;Jwʎ}<zT t~`ȱGP%;?5((u#vՊI#9,?Gb4K]Qgԟ]E[phʯG+`Ęp?@>!}"
ҽr=CD5 62ZY  ?iA
T(EUJu;"}պ#LcӗVWO&CIԙu8*烞QaQ^*z(L|Jӏ^fp104~CUx*rV*N9π׳Pūsp_L3Z"}&rO|l~kC/Wj><SxMbSg(]J(Z#x\$OC68-f:{Sҳ蚨o4:)Wb"uiuh~d%BAM
sWH.gv%4v+=¿
SGϋjWHWu>[B{[uɶs;laziW߭\zC|\f te&ߕ+Bk/t
CM	/@S>Tm
G`v`?G(,zb"eAAi7QR<"iX:I܋(aV;4R]}^1vԵ7=p|[Jοeµ{)e#ief0KJq"*F#(GjJFhX#шݍk5ERP΋	^pCeoe:{6۬5͝sƙ8XK6V[=}V+hͧJlZZ5W;TeV-@HID<͙[)֐l^bXeNN"K]@b?.HH
gzXaْA}MOeXHNrڟW;htgttOyu3=*פؿCFGsh9JͽZ-k]L-~hii.49Qr5I,Vݓ^jf_},Q6?5NV
ޞˍYٜN%ezqƨ>ZNt1  a%= yhޙHJZ?	hvrk@mY`^insF\*|Lz!/?)(0
MS4(ȗh{-'ho7cCҞ?6'|ubգ@!bÙf{tz1UA?=@	t%䕉 iu[NiDGT@:p<(cXUm2ϱ7zOM^FϴYUfwGs#t:/~Os]Fݑ((^?L$SʽWzT>m'_d: 5Lh;H7WgzgZZb3{2d5Jj9c+\vqzDbbƶg "l@צpQBb S Q>+d	p%}L!cdwHopx(Tpxp# :dvQqdAQFdLKmPRpU?lzg-jPbGaR&^q>u8p&Ӯф`MGSܵaoWܛZaâٟݰV5Rs2NX	qGB	OKgBW)Sg\ӡl]z<߲o-_-AKMqӭ!æSigy۰]K;ST'kPqee7cZT{~*7b\H?jٵl3PоwT2jY; )lDueytOTjöUHXgɬ,WϢ^u![]vF|
QGh`(#	R'5XDQqM6gc'bu:'H(?yյ6~.e[n	*UyZst9R!GMM$xz$]{L<}4JZ~MVՕhy >@u+]2FqO8jѥWCQqrw.䄫ޥ\_y\On)IKGRHŁqI.
d+u@ϴ kŤ}9Tv6*xge7?ì}S-AUOMlJpժݧYwhi6\fAZc,rjFTMj8kO51TqW_n`7%KWsd0:`OXs$4?:SI1 W-Pr}²9.&P^f
8(WI``@5a}ziV pPԽ+:d\j"=aj)W$q{͜p)V|7hj$L֡9\ځn[ k{lG.mm~TEbȭm`
wnyP&:PLJY_pNWzVS׃]7Ed%i癬|EWM7rHB6`UGZ 9N2l2ɅHY(ŗiwݓ[`cZR;Yz=TrvH9c.ֲG6*p΅'[:/ҪXCYхMt-']n,{@cObIN.xNF9뛝NK[Xr=WmݏƦY+?sJgXuP%ȗV^[ W;Wxvi/XS3ȼ2ԩZ<F=0V[%R~ˌxysy?Θ(Oq_V-aQ*Q1	t$jDpRR~zǢp"]gw=%GVrt>f2/y?8M@Q*˄CXk?MzT y?ZYu׳)]͕1-a7j~
.d
'VztXK2k̹d?zzK.>,BZ`q'kHqy5j>a\C#H;#p7l4}IR7ފ0$=V#_.vs{g><c_Ogx5&?̠';zaa:zӑQFꉢ^MF 9&AEbٽ\|3gE}"+>h!Ab/p7=zmi%͟3)^Oj<_UNY63dsIr8EjU*33|v;OB@,,\cwd}6k.ukF9'26D]exGJK.׽}S$@t";2 ɩ *41_x7QbjX9Q;#{9eI
-奐br	B<9dpzIVQ:l+si#=T+R(MDC$
a̱	ONgj19gqXk}FdcG,&..^ɷwwc>E_]3U|t{Jf窂u_.\*W=}lNo+^Ṿ	vP>~sTjWz~_ogS}-DTd-TAaYf3,PATcmռ4g}mE$BwŪ8>9JW⁩O/9PJCXA{,@c,tEJTj9 8Q& HPl~K%ƞ1ѻ-eDzxNXuz.9}Mc&:Z5ә8%յսmomCB:l8~ܦEjTYHYvnV^IN]]CXkg#scSB$Ý=$k}cG&/z}_v6<7IVGGg*l\RXST)E%Yu~Q~>XЅ`9Wk*@_ՊpM]0*%a3X팁KM|{FԔ
췾d7[nlͬD@m8e cż#gHdd@~.jllɛeRcxE((	Km¼GXA7S@[l.%գnMDs]n_Q 5i?zGTG3T@e	i,r
O2<l+/,%m ۚXn|E]lí[m<|#z+5 7&\5S-{AE^tKM^rq]FmC%2vJ)W-}OM"`9l+=%"T'8zH3QҐѩYP~VزNi7ۛ ?w1 xc`d```d?oAePBYt?;"@.H cxc`d``
&]a A_x}SJAS<` b)6>@D"X\o!ι{,_oggg #JVYp>uC4&*<=$g9W@.0q- ;:pt"HUe5Vg([Ax9!޴EMߗ4N&ӞwjtԞeσLp>w>Gpfz`|^aż>)ooMg+RmRq,RJ1XTN7t{IE\F8Umb:fN&j9Y xc``ЂM/^0Kؘژ0=avcca>bĒĲk."/
I888qqpnǥ5w)^-8||||[5? JPKLpPa)"Z"WDmDWc3K O<H|D4$IjHfHN<"yK򝔙Toq[dd<u͑"G\$K
n
w(9(MSڡ̧l\|H
J4G&	{DԞQaQFs-5-/m.*]:otet;ti-һϧ_IA%C!u/Tf3V230f"a`䒩<fvf5fw̥'_ph8aeeayJ*j=wl$ll5}cgecw^>~/cLuNN+9K8;99/p>"k676-nܷ0h8)iʋK+ s9                  @ .    xڭNAwh
/"TD#J$rqr|!'O3XFާ0wY 1fg;73;3 xE0Cq=qX4GA$xZB8ڃ	Dw!IaSXw.0?oN؍gڍ@\A`sb
k`sݡ},0YaDȵȵMyFMvYdS20~>/qJG
i<#c0C~G9eeKvв[ڷ{&V(Ө1j1MZqr7,gKܥX0QY{
MYжz=a:[jEݢ	BZZ=ns`+o̏  xmUSgFB]9I$uw-J;mPwwwwwwwwlޕ]<3)e׿7R^VV_@$zГ^З~g `0m[czf`(323323s2s32 eD*954XXeXX14i++
kk	[[۲3Qfvd;1qgg&nLdOboa_c@`PpHhXxNDNdNarsgrgsrsrs	rsWrWsrs7r7srswrwsr OO//
oo	__??f,˺eݳYϬW;MelP68s䘉GE{RαM7nܺp;ڛZ[ݛƵ?ѵֵykx~yj?\3V+wE5=QMjzTӣ(vN؉k/셽d/Kd/Kdbbbbbbbbbbjjjjjjjjjj/r{^n/+v
;NaS)ԼffffffffnnnnnnnnnnaaaaaaaChQN-ܩ?C?C?C?C?݇C}>t݇C}C?C?C?C?vNjHMp[qn???????>>=<<<<<:::::::U>::::::::=;;;;;;;;;;;;}VhSo    TP  <?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata></metadata>
<defs>
<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
<font-face units-per-em="1200" ascent="960" descent="-240" />
<missing-glyph horiz-adv-x="500" />
<glyph horiz-adv-x="0" />
<glyph horiz-adv-x="400" />
<glyph unicode=" " />
<glyph unicode="*" d="M600 1100q15 0 34 -1.5t30 -3.5l11 -1q10 -2 17.5 -10.5t7.5 -18.5v-224l158 158q7 7 18 8t19 -6l106 -106q7 -8 6 -19t-8 -18l-158 -158h224q10 0 18.5 -7.5t10.5 -17.5q6 -41 6 -75q0 -15 -1.5 -34t-3.5 -30l-1 -11q-2 -10 -10.5 -17.5t-18.5 -7.5h-224l158 -158 q7 -7 8 -18t-6 -19l-106 -106q-8 -7 -19 -6t-18 8l-158 158v-224q0 -10 -7.5 -18.5t-17.5 -10.5q-41 -6 -75 -6q-15 0 -34 1.5t-30 3.5l-11 1q-10 2 -17.5 10.5t-7.5 18.5v224l-158 -158q-7 -7 -18 -8t-19 6l-106 106q-7 8 -6 19t8 18l158 158h-224q-10 0 -18.5 7.5 t-10.5 17.5q-6 41 -6 75q0 15 1.5 34t3.5 30l1 11q2 10 10.5 17.5t18.5 7.5h224l-158 158q-7 7 -8 18t6 19l106 106q8 7 19 6t18 -8l158 -158v224q0 10 7.5 18.5t17.5 10.5q41 6 75 6z" />
<glyph unicode="+" d="M450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-350h350q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-350v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v350h-350q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5 h350v350q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xa0;" />
<glyph unicode="&#xa5;" d="M825 1100h250q10 0 12.5 -5t-5.5 -13l-364 -364q-6 -6 -11 -18h268q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-100h275q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-174q0 -11 -7.5 -18.5t-18.5 -7.5h-148q-11 0 -18.5 7.5t-7.5 18.5v174 h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h125v100h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h118q-5 12 -11 18l-364 364q-8 8 -5.5 13t12.5 5h250q25 0 43 -18l164 -164q8 -8 18 -8t18 8l164 164q18 18 43 18z" />
<glyph unicode="&#x2000;" horiz-adv-x="650" />
<glyph unicode="&#x2001;" horiz-adv-x="1300" />
<glyph unicode="&#x2002;" horiz-adv-x="650" />
<glyph unicode="&#x2003;" horiz-adv-x="1300" />
<glyph unicode="&#x2004;" horiz-adv-x="433" />
<glyph unicode="&#x2005;" horiz-adv-x="325" />
<glyph unicode="&#x2006;" horiz-adv-x="216" />
<glyph unicode="&#x2007;" horiz-adv-x="216" />
<glyph unicode="&#x2008;" horiz-adv-x="162" />
<glyph unicode="&#x2009;" horiz-adv-x="260" />
<glyph unicode="&#x200a;" horiz-adv-x="72" />
<glyph unicode="&#x202f;" horiz-adv-x="260" />
<glyph unicode="&#x205f;" horiz-adv-x="325" />
<glyph unicode="&#x20ac;" d="M744 1198q242 0 354 -189q60 -104 66 -209h-181q0 45 -17.5 82.5t-43.5 61.5t-58 40.5t-60.5 24t-51.5 7.5q-19 0 -40.5 -5.5t-49.5 -20.5t-53 -38t-49 -62.5t-39 -89.5h379l-100 -100h-300q-6 -50 -6 -100h406l-100 -100h-300q9 -74 33 -132t52.5 -91t61.5 -54.5t59 -29 t47 -7.5q22 0 50.5 7.5t60.5 24.5t58 41t43.5 61t17.5 80h174q-30 -171 -128 -278q-107 -117 -274 -117q-206 0 -324 158q-36 48 -69 133t-45 204h-217l100 100h112q1 47 6 100h-218l100 100h134q20 87 51 153.5t62 103.5q117 141 297 141z" />
<glyph unicode="&#x20bd;" d="M428 1200h350q67 0 120 -13t86 -31t57 -49.5t35 -56.5t17 -64.5t6.5 -60.5t0.5 -57v-16.5v-16.5q0 -36 -0.5 -57t-6.5 -61t-17 -65t-35 -57t-57 -50.5t-86 -31.5t-120 -13h-178l-2 -100h288q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-138v-175q0 -11 -5.5 -18 t-15.5 -7h-149q-10 0 -17.5 7.5t-7.5 17.5v175h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v100h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v475q0 10 7.5 17.5t17.5 7.5zM600 1000v-300h203q64 0 86.5 33t22.5 119q0 84 -22.5 116t-86.5 32h-203z" />
<glyph unicode="&#x2212;" d="M250 700h800q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#x231b;" d="M1000 1200v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-50v-100q0 -91 -49.5 -165.5t-130.5 -109.5q81 -35 130.5 -109.5t49.5 -165.5v-150h50q21 0 35.5 -14.5t14.5 -35.5v-150h-800v150q0 21 14.5 35.5t35.5 14.5h50v150q0 91 49.5 165.5t130.5 109.5q-81 35 -130.5 109.5 t-49.5 165.5v100h-50q-21 0 -35.5 14.5t-14.5 35.5v150h800zM400 1000v-100q0 -60 32.5 -109.5t87.5 -73.5q28 -12 44 -37t16 -55t-16 -55t-44 -37q-55 -24 -87.5 -73.5t-32.5 -109.5v-150h400v150q0 60 -32.5 109.5t-87.5 73.5q-28 12 -44 37t-16 55t16 55t44 37 q55 24 87.5 73.5t32.5 109.5v100h-400z" />
<glyph unicode="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
<glyph unicode="&#x2601;" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -206.5q0 -121 -85 -207.5t-205 -86.5h-750q-79 0 -135.5 57t-56.5 137q0 69 42.5 122.5t108.5 67.5q-2 12 -2 37q0 153 108 260.5t260 107.5z" />
<glyph unicode="&#x26fa;" d="M774 1193.5q16 -9.5 20.5 -27t-5.5 -33.5l-136 -187l467 -746h30q20 0 35 -18.5t15 -39.5v-42h-1200v42q0 21 15 39.5t35 18.5h30l468 746l-135 183q-10 16 -5.5 34t20.5 28t34 5.5t28 -20.5l111 -148l112 150q9 16 27 20.5t34 -5zM600 200h377l-182 112l-195 534v-646z " />
<glyph unicode="&#x2709;" d="M25 1100h1150q10 0 12.5 -5t-5.5 -13l-564 -567q-8 -8 -18 -8t-18 8l-564 567q-8 8 -5.5 13t12.5 5zM18 882l264 -264q8 -8 8 -18t-8 -18l-264 -264q-8 -8 -13 -5.5t-5 12.5v550q0 10 5 12.5t13 -5.5zM918 618l264 264q8 8 13 5.5t5 -12.5v-550q0 -10 -5 -12.5t-13 5.5 l-264 264q-8 8 -8 18t8 18zM818 482l364 -364q8 -8 5.5 -13t-12.5 -5h-1150q-10 0 -12.5 5t5.5 13l364 364q8 8 18 8t18 -8l164 -164q8 -8 18 -8t18 8l164 164q8 8 18 8t18 -8z" />
<glyph unicode="&#x270f;" d="M1011 1210q19 0 33 -13l153 -153q13 -14 13 -33t-13 -33l-99 -92l-214 214l95 96q13 14 32 14zM1013 800l-615 -614l-214 214l614 614zM317 96l-333 -112l110 335z" />
<glyph unicode="&#xe001;" d="M700 650v-550h250q21 0 35.5 -14.5t14.5 -35.5v-50h-800v50q0 21 14.5 35.5t35.5 14.5h250v550l-500 550h1200z" />
<glyph unicode="&#xe002;" d="M368 1017l645 163q39 15 63 0t24 -49v-831q0 -55 -41.5 -95.5t-111.5 -63.5q-79 -25 -147 -4.5t-86 75t25.5 111.5t122.5 82q72 24 138 8v521l-600 -155v-606q0 -42 -44 -90t-109 -69q-79 -26 -147 -5.5t-86 75.5t25.5 111.5t122.5 82.5q72 24 138 7v639q0 38 14.5 59 t53.5 34z" />
<glyph unicode="&#xe003;" d="M500 1191q100 0 191 -39t156.5 -104.5t104.5 -156.5t39 -191l-1 -2l1 -5q0 -141 -78 -262l275 -274q23 -26 22.5 -44.5t-22.5 -42.5l-59 -58q-26 -20 -46.5 -20t-39.5 20l-275 274q-119 -77 -261 -77l-5 1l-2 -1q-100 0 -191 39t-156.5 104.5t-104.5 156.5t-39 191 t39 191t104.5 156.5t156.5 104.5t191 39zM500 1022q-88 0 -162 -43t-117 -117t-43 -162t43 -162t117 -117t162 -43t162 43t117 117t43 162t-43 162t-117 117t-162 43z" />
<glyph unicode="&#xe005;" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104z" />
<glyph unicode="&#xe006;" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429z" />
<glyph unicode="&#xe007;" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429zM477 700h-240l197 -142l-74 -226 l193 139l195 -140l-74 229l192 140h-234l-78 211z" />
<glyph unicode="&#xe008;" d="M600 1200q124 0 212 -88t88 -212v-250q0 -46 -31 -98t-69 -52v-75q0 -10 6 -21.5t15 -17.5l358 -230q9 -5 15 -16.5t6 -21.5v-93q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v93q0 10 6 21.5t15 16.5l358 230q9 6 15 17.5t6 21.5v75q-38 0 -69 52 t-31 98v250q0 124 88 212t212 88z" />
<glyph unicode="&#xe009;" d="M25 1100h1150q10 0 17.5 -7.5t7.5 -17.5v-1050q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v1050q0 10 7.5 17.5t17.5 7.5zM100 1000v-100h100v100h-100zM875 1000h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5t17.5 -7.5h550 q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM1000 1000v-100h100v100h-100zM100 800v-100h100v100h-100zM1000 800v-100h100v100h-100zM100 600v-100h100v100h-100zM1000 600v-100h100v100h-100zM875 500h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5 t17.5 -7.5h550q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM100 400v-100h100v100h-100zM1000 400v-100h100v100h-100zM100 200v-100h100v100h-100zM1000 200v-100h100v100h-100z" />
<glyph unicode="&#xe010;" d="M50 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM50 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe011;" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM850 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 700h200q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5 t35.5 14.5z" />
<glyph unicode="&#xe012;" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h700q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe013;" d="M465 477l571 571q8 8 18 8t17 -8l177 -177q8 -7 8 -17t-8 -18l-783 -784q-7 -8 -17.5 -8t-17.5 8l-384 384q-8 8 -8 18t8 17l177 177q7 8 17 8t18 -8l171 -171q7 -7 18 -7t18 7z" />
<glyph unicode="&#xe014;" d="M904 1083l178 -179q8 -8 8 -18.5t-8 -17.5l-267 -268l267 -268q8 -7 8 -17.5t-8 -18.5l-178 -178q-8 -8 -18.5 -8t-17.5 8l-268 267l-268 -267q-7 -8 -17.5 -8t-18.5 8l-178 178q-8 8 -8 18.5t8 17.5l267 268l-267 268q-8 7 -8 17.5t8 18.5l178 178q8 8 18.5 8t17.5 -8 l268 -267l268 268q7 7 17.5 7t18.5 -7z" />
<glyph unicode="&#xe015;" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM425 900h150q10 0 17.5 -7.5t7.5 -17.5v-75h75q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5 t-17.5 -7.5h-75v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-75q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v75q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe016;" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM325 800h350q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-350q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe017;" d="M550 1200h100q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM800 975v166q167 -62 272 -209.5t105 -331.5q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5 t-184.5 123t-123 184.5t-45.5 224q0 184 105 331.5t272 209.5v-166q-103 -55 -165 -155t-62 -220q0 -116 57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5q0 120 -62 220t-165 155z" />
<glyph unicode="&#xe018;" d="M1025 1200h150q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM725 800h150q10 0 17.5 -7.5t7.5 -17.5v-750q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v750 q0 10 7.5 17.5t17.5 7.5zM425 500h150q10 0 17.5 -7.5t7.5 -17.5v-450q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v450q0 10 7.5 17.5t17.5 7.5zM125 300h150q10 0 17.5 -7.5t7.5 -17.5v-250q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5 v250q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe019;" d="M600 1174q33 0 74 -5l38 -152l5 -1q49 -14 94 -39l5 -2l134 80q61 -48 104 -105l-80 -134l3 -5q25 -44 39 -93l1 -6l152 -38q5 -43 5 -73q0 -34 -5 -74l-152 -38l-1 -6q-15 -49 -39 -93l-3 -5l80 -134q-48 -61 -104 -105l-134 81l-5 -3q-44 -25 -94 -39l-5 -2l-38 -151 q-43 -5 -74 -5q-33 0 -74 5l-38 151l-5 2q-49 14 -94 39l-5 3l-134 -81q-60 48 -104 105l80 134l-3 5q-25 45 -38 93l-2 6l-151 38q-6 42 -6 74q0 33 6 73l151 38l2 6q13 48 38 93l3 5l-80 134q47 61 105 105l133 -80l5 2q45 25 94 39l5 1l38 152q43 5 74 5zM600 815 q-89 0 -152 -63t-63 -151.5t63 -151.5t152 -63t152 63t63 151.5t-63 151.5t-152 63z" />
<glyph unicode="&#xe020;" d="M500 1300h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-75h-1100v75q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5zM500 1200v-100h300v100h-300zM1100 900v-800q0 -41 -29.5 -70.5t-70.5 -29.5h-700q-41 0 -70.5 29.5t-29.5 70.5 v800h900zM300 800v-700h100v700h-100zM500 800v-700h100v700h-100zM700 800v-700h100v700h-100zM900 800v-700h100v700h-100z" />
<glyph unicode="&#xe021;" d="M18 618l620 608q8 7 18.5 7t17.5 -7l608 -608q8 -8 5.5 -13t-12.5 -5h-175v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v375h-300v-375q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v575h-175q-10 0 -12.5 5t5.5 13z" />
<glyph unicode="&#xe022;" d="M600 1200v-400q0 -41 29.5 -70.5t70.5 -29.5h300v-650q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5h450zM1000 800h-250q-21 0 -35.5 14.5t-14.5 35.5v250z" />
<glyph unicode="&#xe023;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h50q10 0 17.5 -7.5t7.5 -17.5v-275h175q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe024;" d="M1300 0h-538l-41 400h-242l-41 -400h-538l431 1200h209l-21 -300h162l-20 300h208zM515 800l-27 -300h224l-27 300h-170z" />
<glyph unicode="&#xe025;" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-450h191q20 0 25.5 -11.5t-7.5 -27.5l-327 -400q-13 -16 -32 -16t-32 16l-327 400q-13 16 -7.5 27.5t25.5 11.5h191v450q0 21 14.5 35.5t35.5 14.5zM1125 400h50q10 0 17.5 -7.5t7.5 -17.5v-350q0 -10 -7.5 -17.5t-17.5 -7.5 h-1050q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h50q10 0 17.5 -7.5t7.5 -17.5v-175h900v175q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe026;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -275q-13 -16 -32 -16t-32 16l-223 275q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z " />
<glyph unicode="&#xe027;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM632 914l223 -275q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5l223 275q13 16 32 16 t32 -16z" />
<glyph unicode="&#xe028;" d="M225 1200h750q10 0 19.5 -7t12.5 -17l186 -652q7 -24 7 -49v-425q0 -12 -4 -27t-9 -17q-12 -6 -37 -6h-1100q-12 0 -27 4t-17 8q-6 13 -6 38l1 425q0 25 7 49l185 652q3 10 12.5 17t19.5 7zM878 1000h-556q-10 0 -19 -7t-11 -18l-87 -450q-2 -11 4 -18t16 -7h150 q10 0 19.5 -7t11.5 -17l38 -152q2 -10 11.5 -17t19.5 -7h250q10 0 19.5 7t11.5 17l38 152q2 10 11.5 17t19.5 7h150q10 0 16 7t4 18l-87 450q-2 11 -11 18t-19 7z" />
<glyph unicode="&#xe029;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM540 820l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" />
<glyph unicode="&#xe030;" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-362q0 -10 -7.5 -17.5t-17.5 -7.5h-362q-11 0 -13 5.5t5 12.5l133 133q-109 76 -238 76q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5h150q0 -117 -45.5 -224 t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117z" />
<glyph unicode="&#xe031;" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-361q0 -11 -7.5 -18.5t-18.5 -7.5h-361q-11 0 -13 5.5t5 12.5l134 134q-110 75 -239 75q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5h-150q0 117 45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117zM1027 600h150 q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5q-192 0 -348 118l-134 -134q-7 -8 -12.5 -5.5t-5.5 12.5v360q0 11 7.5 18.5t18.5 7.5h360q10 0 12.5 -5.5t-5.5 -12.5l-133 -133q110 -76 240 -76q116 0 214.5 57t155.5 155.5t57 214.5z" />
<glyph unicode="&#xe032;" d="M125 1200h1050q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-1050q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM1075 1000h-850q-10 0 -17.5 -7.5t-7.5 -17.5v-850q0 -10 7.5 -17.5t17.5 -7.5h850q10 0 17.5 7.5t7.5 17.5v850 q0 10 -7.5 17.5t-17.5 7.5zM325 900h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 900h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 700h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 700h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 500h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 500h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 300h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 300h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe033;" d="M900 800v200q0 83 -58.5 141.5t-141.5 58.5h-300q-82 0 -141 -59t-59 -141v-200h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h900q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-100zM400 800v150q0 21 15 35.5t35 14.5h200 q20 0 35 -14.5t15 -35.5v-150h-300z" />
<glyph unicode="&#xe034;" d="M125 1100h50q10 0 17.5 -7.5t7.5 -17.5v-1075h-100v1075q0 10 7.5 17.5t17.5 7.5zM1075 1052q4 0 9 -2q16 -6 16 -23v-421q0 -6 -3 -12q-33 -59 -66.5 -99t-65.5 -58t-56.5 -24.5t-52.5 -6.5q-26 0 -57.5 6.5t-52.5 13.5t-60 21q-41 15 -63 22.5t-57.5 15t-65.5 7.5 q-85 0 -160 -57q-7 -5 -15 -5q-6 0 -11 3q-14 7 -14 22v438q22 55 82 98.5t119 46.5q23 2 43 0.5t43 -7t32.5 -8.5t38 -13t32.5 -11q41 -14 63.5 -21t57 -14t63.5 -7q103 0 183 87q7 8 18 8z" />
<glyph unicode="&#xe035;" d="M600 1175q116 0 227 -49.5t192.5 -131t131 -192.5t49.5 -227v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v300q0 127 -70.5 231.5t-184.5 161.5t-245 57t-245 -57t-184.5 -161.5t-70.5 -231.5v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50 q-10 0 -17.5 7.5t-7.5 17.5v300q0 116 49.5 227t131 192.5t192.5 131t227 49.5zM220 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460q0 8 6 14t14 6zM820 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460 q0 8 6 14t14 6z" />
<glyph unicode="&#xe036;" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM900 668l120 120q7 7 17 7t17 -7l34 -34q7 -7 7 -17t-7 -17l-120 -120l120 -120q7 -7 7 -17 t-7 -17l-34 -34q-7 -7 -17 -7t-17 7l-120 119l-120 -119q-7 -7 -17 -7t-17 7l-34 34q-7 7 -7 17t7 17l119 120l-119 120q-7 7 -7 17t7 17l34 34q7 8 17 8t17 -8z" />
<glyph unicode="&#xe037;" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6 l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238q-6 8 -4.5 18t9.5 17l29 22q7 5 15 5z" />
<glyph unicode="&#xe038;" d="M967 1004h3q11 -1 17 -10q135 -179 135 -396q0 -105 -34 -206.5t-98 -185.5q-7 -9 -17 -10h-3q-9 0 -16 6l-42 34q-8 6 -9 16t5 18q111 150 111 328q0 90 -29.5 176t-84.5 157q-6 9 -5 19t10 16l42 33q7 5 15 5zM321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5 t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238 q-6 8 -4.5 18.5t9.5 16.5l29 22q7 5 15 5z" />
<glyph unicode="&#xe039;" d="M500 900h100v-100h-100v-100h-400v-100h-100v600h500v-300zM1200 700h-200v-100h200v-200h-300v300h-200v300h-100v200h600v-500zM100 1100v-300h300v300h-300zM800 1100v-300h300v300h-300zM300 900h-100v100h100v-100zM1000 900h-100v100h100v-100zM300 500h200v-500 h-500v500h200v100h100v-100zM800 300h200v-100h-100v-100h-200v100h-100v100h100v200h-200v100h300v-300zM100 400v-300h300v300h-300zM300 200h-100v100h100v-100zM1200 200h-100v100h100v-100zM700 0h-100v100h100v-100zM1200 0h-300v100h300v-100z" />
<glyph unicode="&#xe040;" d="M100 200h-100v1000h100v-1000zM300 200h-100v1000h100v-1000zM700 200h-200v1000h200v-1000zM900 200h-100v1000h100v-1000zM1200 200h-200v1000h200v-1000zM400 0h-300v100h300v-100zM600 0h-100v91h100v-91zM800 0h-100v91h100v-91zM1100 0h-200v91h200v-91z" />
<glyph unicode="&#xe041;" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" />
<glyph unicode="&#xe042;" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM800 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-56 56l424 426l-700 700h150zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5 t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" />
<glyph unicode="&#xe043;" d="M300 1200h825q75 0 75 -75v-900q0 -25 -18 -43l-64 -64q-8 -8 -13 -5.5t-5 12.5v950q0 10 -7.5 17.5t-17.5 7.5h-700q-25 0 -43 -18l-64 -64q-8 -8 -5.5 -13t12.5 -5h700q10 0 17.5 -7.5t7.5 -17.5v-950q0 -10 -7.5 -17.5t-17.5 -7.5h-850q-10 0 -17.5 7.5t-7.5 17.5v975 q0 25 18 43l139 139q18 18 43 18z" />
<glyph unicode="&#xe044;" d="M250 1200h800q21 0 35.5 -14.5t14.5 -35.5v-1150l-450 444l-450 -445v1151q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe045;" d="M822 1200h-444q-11 0 -19 -7.5t-9 -17.5l-78 -301q-7 -24 7 -45l57 -108q6 -9 17.5 -15t21.5 -6h450q10 0 21.5 6t17.5 15l62 108q14 21 7 45l-83 301q-1 10 -9 17.5t-19 7.5zM1175 800h-150q-10 0 -21 -6.5t-15 -15.5l-78 -156q-4 -9 -15 -15.5t-21 -6.5h-550 q-10 0 -21 6.5t-15 15.5l-78 156q-4 9 -15 15.5t-21 6.5h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-650q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h750q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5 t7.5 17.5v650q0 10 -7.5 17.5t-17.5 7.5zM850 200h-500q-10 0 -19.5 -7t-11.5 -17l-38 -152q-2 -10 3.5 -17t15.5 -7h600q10 0 15.5 7t3.5 17l-38 152q-2 10 -11.5 17t-19.5 7z" />
<glyph unicode="&#xe046;" d="M500 1100h200q56 0 102.5 -20.5t72.5 -50t44 -59t25 -50.5l6 -20h150q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5h150q2 8 6.5 21.5t24 48t45 61t72 48t102.5 21.5zM900 800v-100 h100v100h-100zM600 730q-95 0 -162.5 -67.5t-67.5 -162.5t67.5 -162.5t162.5 -67.5t162.5 67.5t67.5 162.5t-67.5 162.5t-162.5 67.5zM600 603q43 0 73 -30t30 -73t-30 -73t-73 -30t-73 30t-30 73t30 73t73 30z" />
<glyph unicode="&#xe047;" d="M681 1199l385 -998q20 -50 60 -92q18 -19 36.5 -29.5t27.5 -11.5l10 -2v-66h-417v66q53 0 75 43.5t5 88.5l-82 222h-391q-58 -145 -92 -234q-11 -34 -6.5 -57t25.5 -37t46 -20t55 -6v-66h-365v66q56 24 84 52q12 12 25 30.5t20 31.5l7 13l399 1006h93zM416 521h340 l-162 457z" />
<glyph unicode="&#xe048;" d="M753 641q5 -1 14.5 -4.5t36 -15.5t50.5 -26.5t53.5 -40t50.5 -54.5t35.5 -70t14.5 -87q0 -67 -27.5 -125.5t-71.5 -97.5t-98.5 -66.5t-108.5 -40.5t-102 -13h-500v89q41 7 70.5 32.5t29.5 65.5v827q0 24 -0.5 34t-3.5 24t-8.5 19.5t-17 13.5t-28 12.5t-42.5 11.5v71 l471 -1q57 0 115.5 -20.5t108 -57t80.5 -94t31 -124.5q0 -51 -15.5 -96.5t-38 -74.5t-45 -50.5t-38.5 -30.5zM400 700h139q78 0 130.5 48.5t52.5 122.5q0 41 -8.5 70.5t-29.5 55.5t-62.5 39.5t-103.5 13.5h-118v-350zM400 200h216q80 0 121 50.5t41 130.5q0 90 -62.5 154.5 t-156.5 64.5h-159v-400z" />
<glyph unicode="&#xe049;" d="M877 1200l2 -57q-83 -19 -116 -45.5t-40 -66.5l-132 -839q-9 -49 13 -69t96 -26v-97h-500v97q186 16 200 98l173 832q3 17 3 30t-1.5 22.5t-9 17.5t-13.5 12.5t-21.5 10t-26 8.5t-33.5 10q-13 3 -19 5v57h425z" />
<glyph unicode="&#xe050;" d="M1300 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM175 1000h-75v-800h75l-125 -167l-125 167h75v800h-75l125 167z" />
<glyph unicode="&#xe051;" d="M1100 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-650q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v650h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM1167 50l-167 -125v75h-800v-75l-167 125l167 125v-75h800v75z" />
<glyph unicode="&#xe052;" d="M50 1100h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe053;" d="M250 1100h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM250 500h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe054;" d="M500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000 q-21 0 -35.5 14.5t-14.5 35.5zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5zM0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5z" />
<glyph unicode="&#xe055;" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe056;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 1100h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 800h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 500h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 500h800q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 200h800 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe057;" d="M400 0h-100v1100h100v-1100zM550 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM267 550l-167 -125v75h-200v100h200v75zM550 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe058;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM900 0h-100v1100h100v-1100zM50 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM1100 600h200v-100h-200v-75l-167 125l167 125v-75zM50 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe059;" d="M75 1000h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53v650q0 31 22 53t53 22zM1200 300l-300 300l300 300v-600z" />
<glyph unicode="&#xe060;" d="M44 1100h1112q18 0 31 -13t13 -31v-1012q0 -18 -13 -31t-31 -13h-1112q-18 0 -31 13t-13 31v1012q0 18 13 31t31 13zM100 1000v-737l247 182l298 -131l-74 156l293 318l236 -288v500h-1000zM342 884q56 0 95 -39t39 -94.5t-39 -95t-95 -39.5t-95 39.5t-39 95t39 94.5 t95 39z" />
<glyph unicode="&#xe062;" d="M648 1169q117 0 216 -60t156.5 -161t57.5 -218q0 -115 -70 -258q-69 -109 -158 -225.5t-143 -179.5l-54 -62q-9 8 -25.5 24.5t-63.5 67.5t-91 103t-98.5 128t-95.5 148q-60 132 -60 249q0 88 34 169.5t91.5 142t137 96.5t166.5 36zM652.5 974q-91.5 0 -156.5 -65 t-65 -157t65 -156.5t156.5 -64.5t156.5 64.5t65 156.5t-65 157t-156.5 65z" />
<glyph unicode="&#xe063;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 173v854q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57z" />
<glyph unicode="&#xe064;" d="M554 1295q21 -72 57.5 -143.5t76 -130t83 -118t82.5 -117t70 -116t49.5 -126t18.5 -136.5q0 -71 -25.5 -135t-68.5 -111t-99 -82t-118.5 -54t-125.5 -23q-84 5 -161.5 34t-139.5 78.5t-99 125t-37 164.5q0 69 18 136.5t49.5 126.5t69.5 116.5t81.5 117.5t83.5 119 t76.5 131t58.5 143zM344 710q-23 -33 -43.5 -70.5t-40.5 -102.5t-17 -123q1 -37 14.5 -69.5t30 -52t41 -37t38.5 -24.5t33 -15q21 -7 32 -1t13 22l6 34q2 10 -2.5 22t-13.5 19q-5 4 -14 12t-29.5 40.5t-32.5 73.5q-26 89 6 271q2 11 -6 11q-8 1 -15 -10z" />
<glyph unicode="&#xe065;" d="M1000 1013l108 115q2 1 5 2t13 2t20.5 -1t25 -9.5t28.5 -21.5q22 -22 27 -43t0 -32l-6 -10l-108 -115zM350 1100h400q50 0 105 -13l-187 -187h-368q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v182l200 200v-332 q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM1009 803l-362 -362l-161 -50l55 170l355 355z" />
<glyph unicode="&#xe066;" d="M350 1100h361q-164 -146 -216 -200h-195q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-103q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M824 1073l339 -301q8 -7 8 -17.5t-8 -17.5l-340 -306q-7 -6 -12.5 -4t-6.5 11v203q-26 1 -54.5 0t-78.5 -7.5t-92 -17.5t-86 -35t-70 -57q10 59 33 108t51.5 81.5t65 58.5t68.5 40.5t67 24.5t56 13.5t40 4.5v210q1 10 6.5 12.5t13.5 -4.5z" />
<glyph unicode="&#xe067;" d="M350 1100h350q60 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-219q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M643 639l395 395q7 7 17.5 7t17.5 -7l101 -101q7 -7 7 -17.5t-7 -17.5l-531 -532q-7 -7 -17.5 -7t-17.5 7l-248 248q-7 7 -7 17.5t7 17.5l101 101q7 7 17.5 7t17.5 -7l111 -111q8 -7 18 -7t18 7z" />
<glyph unicode="&#xe068;" d="M318 918l264 264q8 8 18 8t18 -8l260 -264q7 -8 4.5 -13t-12.5 -5h-170v-200h200v173q0 10 5 12t13 -5l264 -260q8 -7 8 -17.5t-8 -17.5l-264 -265q-8 -7 -13 -5t-5 12v173h-200v-200h170q10 0 12.5 -5t-4.5 -13l-260 -264q-8 -8 -18 -8t-18 8l-264 264q-8 8 -5.5 13 t12.5 5h175v200h-200v-173q0 -10 -5 -12t-13 5l-264 265q-8 7 -8 17.5t8 17.5l264 260q8 7 13 5t5 -12v-173h200v200h-175q-10 0 -12.5 5t5.5 13z" />
<glyph unicode="&#xe069;" d="M250 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe070;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5 t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe071;" d="M1200 1050v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-492 480q-15 14 -15 35t15 35l492 480q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25z" />
<glyph unicode="&#xe072;" d="M243 1074l814 -498q18 -11 18 -26t-18 -26l-814 -498q-18 -11 -30.5 -4t-12.5 28v1000q0 21 12.5 28t30.5 -4z" />
<glyph unicode="&#xe073;" d="M250 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM650 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800 q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe074;" d="M1100 950v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5z" />
<glyph unicode="&#xe075;" d="M500 612v438q0 21 10.5 25t25.5 -10l492 -480q15 -14 15 -35t-15 -35l-492 -480q-15 -14 -25.5 -10t-10.5 25v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10z" />
<glyph unicode="&#xe076;" d="M1048 1102l100 1q20 0 35 -14.5t15 -35.5l5 -1000q0 -21 -14.5 -35.5t-35.5 -14.5l-100 -1q-21 0 -35.5 14.5t-14.5 35.5l-2 437l-463 -454q-14 -15 -24.5 -10.5t-10.5 25.5l-2 437l-462 -455q-15 -14 -25.5 -9.5t-10.5 24.5l-5 1000q0 21 10.5 25.5t25.5 -10.5l466 -450 l-2 438q0 20 10.5 24.5t25.5 -9.5l466 -451l-2 438q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe077;" d="M850 1100h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10l464 -453v438q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe078;" d="M686 1081l501 -540q15 -15 10.5 -26t-26.5 -11h-1042q-22 0 -26.5 11t10.5 26l501 540q15 15 36 15t36 -15zM150 400h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe079;" d="M885 900l-352 -353l352 -353l-197 -198l-552 552l552 550z" />
<glyph unicode="&#xe080;" d="M1064 547l-551 -551l-198 198l353 353l-353 353l198 198z" />
<glyph unicode="&#xe081;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM650 900h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-150 q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5h150v-150q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v150h150q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-150v150q0 21 -14.5 35.5t-35.5 14.5z" />
<glyph unicode="&#xe082;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM850 700h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5 t35.5 -14.5h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5z" />
<glyph unicode="&#xe083;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM741.5 913q-12.5 0 -21.5 -9l-120 -120l-120 120q-9 9 -21.5 9 t-21.5 -9l-141 -141q-9 -9 -9 -21.5t9 -21.5l120 -120l-120 -120q-9 -9 -9 -21.5t9 -21.5l141 -141q9 -9 21.5 -9t21.5 9l120 120l120 -120q9 -9 21.5 -9t21.5 9l141 141q9 9 9 21.5t-9 21.5l-120 120l120 120q9 9 9 21.5t-9 21.5l-141 141q-9 9 -21.5 9z" />
<glyph unicode="&#xe084;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM546 623l-84 85q-7 7 -17.5 7t-18.5 -7l-139 -139q-7 -8 -7 -18t7 -18 l242 -241q7 -8 17.5 -8t17.5 8l375 375q7 7 7 17.5t-7 18.5l-139 139q-7 7 -17.5 7t-17.5 -7z" />
<glyph unicode="&#xe085;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM588 941q-29 0 -59 -5.5t-63 -20.5t-58 -38.5t-41.5 -63t-16.5 -89.5 q0 -25 20 -25h131q30 -5 35 11q6 20 20.5 28t45.5 8q20 0 31.5 -10.5t11.5 -28.5q0 -23 -7 -34t-26 -18q-1 0 -13.5 -4t-19.5 -7.5t-20 -10.5t-22 -17t-18.5 -24t-15.5 -35t-8 -46q-1 -8 5.5 -16.5t20.5 -8.5h173q7 0 22 8t35 28t37.5 48t29.5 74t12 100q0 47 -17 83 t-42.5 57t-59.5 34.5t-64 18t-59 4.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" />
<glyph unicode="&#xe086;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM675 1000h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5 t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5zM675 700h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h75v-200h-75q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h350q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5 t-17.5 7.5h-75v275q0 10 -7.5 17.5t-17.5 7.5z" />
<glyph unicode="&#xe087;" d="M525 1200h150q10 0 17.5 -7.5t7.5 -17.5v-194q103 -27 178.5 -102.5t102.5 -178.5h194q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-194q-27 -103 -102.5 -178.5t-178.5 -102.5v-194q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v194 q-103 27 -178.5 102.5t-102.5 178.5h-194q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h194q27 103 102.5 178.5t178.5 102.5v194q0 10 7.5 17.5t17.5 7.5zM700 893v-168q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v168q-68 -23 -119 -74 t-74 -119h168q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-168q23 -68 74 -119t119 -74v168q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-168q68 23 119 74t74 119h-168q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h168 q-23 68 -74 119t-119 74z" />
<glyph unicode="&#xe088;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM759 823l64 -64q7 -7 7 -17.5t-7 -17.5l-124 -124l124 -124q7 -7 7 -17.5t-7 -17.5l-64 -64q-7 -7 -17.5 -7t-17.5 7l-124 124l-124 -124q-7 -7 -17.5 -7t-17.5 7l-64 64 q-7 7 -7 17.5t7 17.5l124 124l-124 124q-7 7 -7 17.5t7 17.5l64 64q7 7 17.5 7t17.5 -7l124 -124l124 124q7 7 17.5 7t17.5 -7z" />
<glyph unicode="&#xe089;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM782 788l106 -106q7 -7 7 -17.5t-7 -17.5l-320 -321q-8 -7 -18 -7t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l197 197q7 7 17.5 7t17.5 -7z" />
<glyph unicode="&#xe090;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5q0 -120 65 -225 l587 587q-105 65 -225 65zM965 819l-584 -584q104 -62 219 -62q116 0 214.5 57t155.5 155.5t57 214.5q0 115 -62 219z" />
<glyph unicode="&#xe091;" d="M39 582l522 427q16 13 27.5 8t11.5 -26v-291h550q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-550v-291q0 -21 -11.5 -26t-27.5 8l-522 427q-16 13 -16 32t16 32z" />
<glyph unicode="&#xe092;" d="M639 1009l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291h-550q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h550v291q0 21 11.5 26t27.5 -8z" />
<glyph unicode="&#xe093;" d="M682 1161l427 -522q13 -16 8 -27.5t-26 -11.5h-291v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v550h-291q-21 0 -26 11.5t8 27.5l427 522q13 16 32 16t32 -16z" />
<glyph unicode="&#xe094;" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-550h291q21 0 26 -11.5t-8 -27.5l-427 -522q-13 -16 -32 -16t-32 16l-427 522q-13 16 -8 27.5t26 11.5h291v550q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe095;" d="M639 1109l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291q-94 -2 -182 -20t-170.5 -52t-147 -92.5t-100.5 -135.5q5 105 27 193.5t67.5 167t113 135t167 91.5t225.5 42v262q0 21 11.5 26t27.5 -8z" />
<glyph unicode="&#xe096;" d="M850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5zM350 0h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249 q8 7 18 7t18 -7l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5z" />
<glyph unicode="&#xe097;" d="M1014 1120l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249q8 7 18 7t18 -7zM250 600h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5z" />
<glyph unicode="&#xe101;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM704 900h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5 t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" />
<glyph unicode="&#xe102;" d="M260 1200q9 0 19 -2t15 -4l5 -2q22 -10 44 -23l196 -118q21 -13 36 -24q29 -21 37 -12q11 13 49 35l196 118q22 13 45 23q17 7 38 7q23 0 47 -16.5t37 -33.5l13 -16q14 -21 18 -45l25 -123l8 -44q1 -9 8.5 -14.5t17.5 -5.5h61q10 0 17.5 -7.5t7.5 -17.5v-50 q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 -7.5t-7.5 -17.5v-175h-400v300h-200v-300h-400v175q0 10 -7.5 17.5t-17.5 7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5h61q11 0 18 3t7 8q0 4 9 52l25 128q5 25 19 45q2 3 5 7t13.5 15t21.5 19.5t26.5 15.5 t29.5 7zM915 1079l-166 -162q-7 -7 -5 -12t12 -5h219q10 0 15 7t2 17l-51 149q-3 10 -11 12t-15 -6zM463 917l-177 157q-8 7 -16 5t-11 -12l-51 -143q-3 -10 2 -17t15 -7h231q11 0 12.5 5t-5.5 12zM500 0h-375q-10 0 -17.5 7.5t-7.5 17.5v375h400v-400zM1100 400v-375 q0 -10 -7.5 -17.5t-17.5 -7.5h-375v400h400z" />
<glyph unicode="&#xe103;" d="M1165 1190q8 3 21 -6.5t13 -17.5q-2 -178 -24.5 -323.5t-55.5 -245.5t-87 -174.5t-102.5 -118.5t-118 -68.5t-118.5 -33t-120 -4.5t-105 9.5t-90 16.5q-61 12 -78 11q-4 1 -12.5 0t-34 -14.5t-52.5 -40.5l-153 -153q-26 -24 -37 -14.5t-11 43.5q0 64 42 102q8 8 50.5 45 t66.5 58q19 17 35 47t13 61q-9 55 -10 102.5t7 111t37 130t78 129.5q39 51 80 88t89.5 63.5t94.5 45t113.5 36t129 31t157.5 37t182 47.5zM1116 1098q-8 9 -22.5 -3t-45.5 -50q-38 -47 -119 -103.5t-142 -89.5l-62 -33q-56 -30 -102 -57t-104 -68t-102.5 -80.5t-85.5 -91 t-64 -104.5q-24 -56 -31 -86t2 -32t31.5 17.5t55.5 59.5q25 30 94 75.5t125.5 77.5t147.5 81q70 37 118.5 69t102 79.5t99 111t86.5 148.5q22 50 24 60t-6 19z" />
<glyph unicode="&#xe104;" d="M653 1231q-39 -67 -54.5 -131t-10.5 -114.5t24.5 -96.5t47.5 -80t63.5 -62.5t68.5 -46.5t65 -30q-4 7 -17.5 35t-18.5 39.5t-17 39.5t-17 43t-13 42t-9.5 44.5t-2 42t4 43t13.5 39t23 38.5q96 -42 165 -107.5t105 -138t52 -156t13 -159t-19 -149.5q-13 -55 -44 -106.5 t-68 -87t-78.5 -64.5t-72.5 -45t-53 -22q-72 -22 -127 -11q-31 6 -13 19q6 3 17 7q13 5 32.5 21t41 44t38.5 63.5t21.5 81.5t-6.5 94.5t-50 107t-104 115.5q10 -104 -0.5 -189t-37 -140.5t-65 -93t-84 -52t-93.5 -11t-95 24.5q-80 36 -131.5 114t-53.5 171q-2 23 0 49.5 t4.5 52.5t13.5 56t27.5 60t46 64.5t69.5 68.5q-8 -53 -5 -102.5t17.5 -90t34 -68.5t44.5 -39t49 -2q31 13 38.5 36t-4.5 55t-29 64.5t-36 75t-26 75.5q-15 85 2 161.5t53.5 128.5t85.5 92.5t93.5 61t81.5 25.5z" />
<glyph unicode="&#xe105;" d="M600 1094q82 0 160.5 -22.5t140 -59t116.5 -82.5t94.5 -95t68 -95t42.5 -82.5t14 -57.5t-14 -57.5t-43 -82.5t-68.5 -95t-94.5 -95t-116.5 -82.5t-140 -59t-159.5 -22.5t-159.5 22.5t-140 59t-116.5 82.5t-94.5 95t-68.5 95t-43 82.5t-14 57.5t14 57.5t42.5 82.5t68 95 t94.5 95t116.5 82.5t140 59t160.5 22.5zM888 829q-15 15 -18 12t5 -22q25 -57 25 -119q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 59 23 114q8 19 4.5 22t-17.5 -12q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q22 -36 47 -71t70 -82t92.5 -81t113 -58.5t133.5 -24.5 t133.5 24t113 58.5t92.5 81.5t70 81.5t47 70.5q11 18 9 42.5t-14 41.5q-90 117 -163 189zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l35 34q14 15 12.5 33.5t-16.5 33.5q-44 44 -89 117q-11 18 -28 20t-32 -12z" />
<glyph unicode="&#xe106;" d="M592 0h-148l31 120q-91 20 -175.5 68.5t-143.5 106.5t-103.5 119t-66.5 110t-22 76q0 21 14 57.5t42.5 82.5t68 95t94.5 95t116.5 82.5t140 59t160.5 22.5q61 0 126 -15l32 121h148zM944 770l47 181q108 -85 176.5 -192t68.5 -159q0 -26 -19.5 -71t-59.5 -102t-93 -112 t-129 -104.5t-158 -75.5l46 173q77 49 136 117t97 131q11 18 9 42.5t-14 41.5q-54 70 -107 130zM310 824q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q18 -30 39 -60t57 -70.5t74 -73t90 -61t105 -41.5l41 154q-107 18 -178.5 101.5t-71.5 193.5q0 59 23 114q8 19 4.5 22 t-17.5 -12zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l12 11l22 86l-3 4q-44 44 -89 117q-11 18 -28 20t-32 -12z" />
<glyph unicode="&#xe107;" d="M-90 100l642 1066q20 31 48 28.5t48 -35.5l642 -1056q21 -32 7.5 -67.5t-50.5 -35.5h-1294q-37 0 -50.5 34t7.5 66zM155 200h345v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h345l-445 723zM496 700h208q20 0 32 -14.5t8 -34.5l-58 -252 q-4 -20 -21.5 -34.5t-37.5 -14.5h-54q-20 0 -37.5 14.5t-21.5 34.5l-58 252q-4 20 8 34.5t32 14.5z" />
<glyph unicode="&#xe108;" d="M650 1200q62 0 106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -93 100 -113v-64q0 -21 -13 -29t-32 1l-205 128l-205 -128q-19 -9 -32 -1t-13 29v64q0 20 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5v41 q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44z" />
<glyph unicode="&#xe109;" d="M850 1200h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-150h-1100v150q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-50h500v50q0 21 14.5 35.5t35.5 14.5zM1100 800v-750q0 -21 -14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v750h1100zM100 600v-100h100v100h-100zM300 600v-100h100v100h-100zM500 600v-100h100v100h-100zM700 600v-100h100v100h-100zM900 600v-100h100v100h-100zM100 400v-100h100v100h-100zM300 400v-100h100v100h-100zM500 400 v-100h100v100h-100zM700 400v-100h100v100h-100zM900 400v-100h100v100h-100zM100 200v-100h100v100h-100zM300 200v-100h100v100h-100zM500 200v-100h100v100h-100zM700 200v-100h100v100h-100zM900 200v-100h100v100h-100z" />
<glyph unicode="&#xe110;" d="M1135 1165l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-159l-600 -600h-291q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h209l600 600h241v150q0 21 10.5 25t24.5 -10zM522 819l-141 -141l-122 122h-209q-21 0 -35.5 14.5 t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h291zM1135 565l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-241l-181 181l141 141l122 -122h159v150q0 21 10.5 25t24.5 -10z" />
<glyph unicode="&#xe111;" d="M100 1100h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5z" />
<glyph unicode="&#xe112;" d="M150 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM850 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM1100 800v-300q0 -41 -3 -77.5t-15 -89.5t-32 -96t-58 -89t-89 -77t-129 -51t-174 -20t-174 20 t-129 51t-89 77t-58 89t-32 96t-15 89.5t-3 77.5v300h300v-250v-27v-42.5t1.5 -41t5 -38t10 -35t16.5 -30t25.5 -24.5t35 -19t46.5 -12t60 -4t60 4.5t46.5 12.5t35 19.5t25 25.5t17 30.5t10 35t5 38t2 40.5t-0.5 42v25v250h300z" />
<glyph unicode="&#xe113;" d="M1100 411l-198 -199l-353 353l-353 -353l-197 199l551 551z" />
<glyph unicode="&#xe114;" d="M1101 789l-550 -551l-551 551l198 199l353 -353l353 353z" />
<glyph unicode="&#xe115;" d="M404 1000h746q21 0 35.5 -14.5t14.5 -35.5v-551h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v401h-381zM135 984l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-400h385l215 -200h-750q-21 0 -35.5 14.5 t-14.5 35.5v550h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
<glyph unicode="&#xe116;" d="M56 1200h94q17 0 31 -11t18 -27l38 -162h896q24 0 39 -18.5t10 -42.5l-100 -475q-5 -21 -27 -42.5t-55 -21.5h-633l48 -200h535q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-50q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-300v-50 q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-31q-18 0 -32.5 10t-20.5 19l-5 10l-201 961h-54q-20 0 -35 14.5t-15 35.5t15 35.5t35 14.5z" />
<glyph unicode="&#xe117;" d="M1200 1000v-100h-1200v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500zM0 800h1200v-800h-1200v800z" />
<glyph unicode="&#xe118;" d="M200 800l-200 -400v600h200q0 41 29.5 70.5t70.5 29.5h300q42 0 71 -29.5t29 -70.5h500v-200h-1000zM1500 700l-300 -700h-1200l300 700h1200z" />
<glyph unicode="&#xe119;" d="M635 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-601h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v601h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
<glyph unicode="&#xe120;" d="M936 864l249 -229q14 -15 14 -35.5t-14 -35.5l-249 -229q-15 -15 -25.5 -10.5t-10.5 24.5v151h-600v-151q0 -20 -10.5 -24.5t-25.5 10.5l-249 229q-14 15 -14 35.5t14 35.5l249 229q15 15 25.5 10.5t10.5 -25.5v-149h600v149q0 21 10.5 25.5t25.5 -10.5z" />
<glyph unicode="&#xe121;" d="M1169 400l-172 732q-5 23 -23 45.5t-38 22.5h-672q-20 0 -38 -20t-23 -41l-172 -739h1138zM1100 300h-1000q-41 0 -70.5 -29.5t-29.5 -70.5v-100q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v100q0 41 -29.5 70.5t-70.5 29.5zM800 100v100h100v-100h-100 zM1000 100v100h100v-100h-100z" />
<glyph unicode="&#xe122;" d="M1150 1100q21 0 35.5 -14.5t14.5 -35.5v-850q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v850q0 21 14.5 35.5t35.5 14.5zM1000 200l-675 200h-38l47 -276q3 -16 -5.5 -20t-29.5 -4h-7h-84q-20 0 -34.5 14t-18.5 35q-55 337 -55 351v250v6q0 16 1 23.5t6.5 14 t17.5 6.5h200l675 250v-850zM0 750v-250q-4 0 -11 0.5t-24 6t-30 15t-24 30t-11 48.5v50q0 26 10.5 46t25 30t29 16t25.5 7z" />
<glyph unicode="&#xe123;" d="M553 1200h94q20 0 29 -10.5t3 -29.5l-18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q19 0 33 -14.5t14 -35t-13 -40.5t-31 -27q-8 -4 -23 -9.5t-65 -19.5t-103 -25t-132.5 -20t-158.5 -9q-57 0 -115 5t-104 12t-88.5 15.5t-73.5 17.5t-54.5 16t-35.5 12l-11 4 q-18 8 -31 28t-13 40.5t14 35t33 14.5h17l118 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3.5 32t28.5 13zM498 110q50 -6 102 -6q53 0 102 6q-12 -49 -39.5 -79.5t-62.5 -30.5t-63 30.5t-39 79.5z" />
<glyph unicode="&#xe124;" d="M800 946l224 78l-78 -224l234 -45l-180 -155l180 -155l-234 -45l78 -224l-224 78l-45 -234l-155 180l-155 -180l-45 234l-224 -78l78 224l-234 45l180 155l-180 155l234 45l-78 224l224 -78l45 234l155 -180l155 180z" />
<glyph unicode="&#xe125;" d="M650 1200h50q40 0 70 -40.5t30 -84.5v-150l-28 -125h328q40 0 70 -40.5t30 -84.5v-100q0 -45 -29 -74l-238 -344q-16 -24 -38 -40.5t-45 -16.5h-250q-7 0 -42 25t-66 50l-31 25h-61q-45 0 -72.5 18t-27.5 57v400q0 36 20 63l145 196l96 198q13 28 37.5 48t51.5 20z M650 1100l-100 -212l-150 -213v-375h100l136 -100h214l250 375v125h-450l50 225v175h-50zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe126;" d="M600 1100h250q23 0 45 -16.5t38 -40.5l238 -344q29 -29 29 -74v-100q0 -44 -30 -84.5t-70 -40.5h-328q28 -118 28 -125v-150q0 -44 -30 -84.5t-70 -40.5h-50q-27 0 -51.5 20t-37.5 48l-96 198l-145 196q-20 27 -20 63v400q0 39 27.5 57t72.5 18h61q124 100 139 100z M50 1000h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM636 1000l-136 -100h-100v-375l150 -213l100 -212h50v175l-50 225h450v125l-250 375h-214z" />
<glyph unicode="&#xe127;" d="M356 873l363 230q31 16 53 -6l110 -112q13 -13 13.5 -32t-11.5 -34l-84 -121h302q84 0 138 -38t54 -110t-55 -111t-139 -39h-106l-131 -339q-6 -21 -19.5 -41t-28.5 -20h-342q-7 0 -90 81t-83 94v525q0 17 14 35.5t28 28.5zM400 792v-503l100 -89h293l131 339 q6 21 19.5 41t28.5 20h203q21 0 30.5 25t0.5 50t-31 25h-456h-7h-6h-5.5t-6 0.5t-5 1.5t-5 2t-4 2.5t-4 4t-2.5 4.5q-12 25 5 47l146 183l-86 83zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500 q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe128;" d="M475 1103l366 -230q2 -1 6 -3.5t14 -10.5t18 -16.5t14.5 -20t6.5 -22.5v-525q0 -13 -86 -94t-93 -81h-342q-15 0 -28.5 20t-19.5 41l-131 339h-106q-85 0 -139.5 39t-54.5 111t54 110t138 38h302l-85 121q-11 15 -10.5 34t13.5 32l110 112q22 22 53 6zM370 945l146 -183 q17 -22 5 -47q-2 -2 -3.5 -4.5t-4 -4t-4 -2.5t-5 -2t-5 -1.5t-6 -0.5h-6h-6.5h-6h-475v-100h221q15 0 29 -20t20 -41l130 -339h294l106 89v503l-342 236zM1050 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5 v500q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe129;" d="M550 1294q72 0 111 -55t39 -139v-106l339 -131q21 -6 41 -19.5t20 -28.5v-342q0 -7 -81 -90t-94 -83h-525q-17 0 -35.5 14t-28.5 28l-9 14l-230 363q-16 31 6 53l112 110q13 13 32 13.5t34 -11.5l121 -84v302q0 84 38 138t110 54zM600 972v203q0 21 -25 30.5t-50 0.5 t-25 -31v-456v-7v-6v-5.5t-0.5 -6t-1.5 -5t-2 -5t-2.5 -4t-4 -4t-4.5 -2.5q-25 -12 -47 5l-183 146l-83 -86l236 -339h503l89 100v293l-339 131q-21 6 -41 19.5t-20 28.5zM450 200h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe130;" d="M350 1100h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5zM600 306v-106q0 -84 -39 -139t-111 -55t-110 54t-38 138v302l-121 -84q-15 -12 -34 -11.5t-32 13.5l-112 110 q-22 22 -6 53l230 363q1 2 3.5 6t10.5 13.5t16.5 17t20 13.5t22.5 6h525q13 0 94 -83t81 -90v-342q0 -15 -20 -28.5t-41 -19.5zM308 900l-236 -339l83 -86l183 146q22 17 47 5q2 -1 4.5 -2.5t4 -4t2.5 -4t2 -5t1.5 -5t0.5 -6v-5.5v-6v-7v-456q0 -22 25 -31t50 0.5t25 30.5 v203q0 15 20 28.5t41 19.5l339 131v293l-89 100h-503z" />
<glyph unicode="&#xe131;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM914 632l-275 223q-16 13 -27.5 8t-11.5 -26v-137h-275 q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h275v-137q0 -21 11.5 -26t27.5 8l275 223q16 13 16 32t-16 32z" />
<glyph unicode="&#xe132;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM561 855l-275 -223q-16 -13 -16 -32t16 -32l275 -223q16 -13 27.5 -8 t11.5 26v137h275q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5h-275v137q0 21 -11.5 26t-27.5 -8z" />
<glyph unicode="&#xe133;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM855 639l-223 275q-13 16 -32 16t-32 -16l-223 -275q-13 -16 -8 -27.5 t26 -11.5h137v-275q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v275h137q21 0 26 11.5t-8 27.5z" />
<glyph unicode="&#xe134;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM675 900h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-275h-137q-21 0 -26 -11.5 t8 -27.5l223 -275q13 -16 32 -16t32 16l223 275q13 16 8 27.5t-26 11.5h-137v275q0 10 -7.5 17.5t-17.5 7.5z" />
<glyph unicode="&#xe135;" d="M600 1176q116 0 222.5 -46t184 -123.5t123.5 -184t46 -222.5t-46 -222.5t-123.5 -184t-184 -123.5t-222.5 -46t-222.5 46t-184 123.5t-123.5 184t-46 222.5t46 222.5t123.5 184t184 123.5t222.5 46zM627 1101q-15 -12 -36.5 -20.5t-35.5 -12t-43 -8t-39 -6.5 q-15 -3 -45.5 0t-45.5 -2q-20 -7 -51.5 -26.5t-34.5 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -91t-29.5 -79q-9 -34 5 -93t8 -87q0 -9 17 -44.5t16 -59.5q12 0 23 -5t23.5 -15t19.5 -14q16 -8 33 -15t40.5 -15t34.5 -12q21 -9 52.5 -32t60 -38t57.5 -11 q7 -15 -3 -34t-22.5 -40t-9.5 -38q13 -21 23 -34.5t27.5 -27.5t36.5 -18q0 -7 -3.5 -16t-3.5 -14t5 -17q104 -2 221 112q30 29 46.5 47t34.5 49t21 63q-13 8 -37 8.5t-36 7.5q-15 7 -49.5 15t-51.5 19q-18 0 -41 -0.5t-43 -1.5t-42 -6.5t-38 -16.5q-51 -35 -66 -12 q-4 1 -3.5 25.5t0.5 25.5q-6 13 -26.5 17.5t-24.5 6.5q1 15 -0.5 30.5t-7 28t-18.5 11.5t-31 -21q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q7 -12 18 -24t21.5 -20.5t20 -15t15.5 -10.5l5 -3q2 12 7.5 30.5t8 34.5t-0.5 32q-3 18 3.5 29 t18 22.5t15.5 24.5q6 14 10.5 35t8 31t15.5 22.5t34 22.5q-6 18 10 36q8 0 24 -1.5t24.5 -1.5t20 4.5t20.5 15.5q-10 23 -31 42.5t-37.5 29.5t-49 27t-43.5 23q0 1 2 8t3 11.5t1.5 10.5t-1 9.5t-4.5 4.5q31 -13 58.5 -14.5t38.5 2.5l12 5q5 28 -9.5 46t-36.5 24t-50 15 t-41 20q-18 -4 -37 0zM613 994q0 -17 8 -42t17 -45t9 -23q-8 1 -39.5 5.5t-52.5 10t-37 16.5q3 11 16 29.5t16 25.5q10 -10 19 -10t14 6t13.5 14.5t16.5 12.5z" />
<glyph unicode="&#xe136;" d="M756 1157q164 92 306 -9l-259 -138l145 -232l251 126q6 -89 -34 -156.5t-117 -110.5q-60 -34 -127 -39.5t-126 16.5l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5t15 37.5l600 599q-34 101 5.5 201.5t135.5 154.5z" />
<glyph unicode="&#xe137;" horiz-adv-x="1220" d="M100 1196h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 1096h-200v-100h200v100zM100 796h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 696h-500v-100h500v100zM100 396h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 296h-300v-100h300v100z " />
<glyph unicode="&#xe138;" d="M150 1200h900q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM700 500v-300l-200 -200v500l-350 500h900z" />
<glyph unicode="&#xe139;" d="M500 1200h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5zM500 1100v-100h200v100h-200zM1200 400v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v200h1200z" />
<glyph unicode="&#xe140;" d="M50 1200h300q21 0 25 -10.5t-10 -24.5l-94 -94l199 -199q7 -8 7 -18t-7 -18l-106 -106q-8 -7 -18 -7t-18 7l-199 199l-94 -94q-14 -14 -24.5 -10t-10.5 25v300q0 21 14.5 35.5t35.5 14.5zM850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-199 -199q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l199 199l-94 94q-14 14 -10 24.5t25 10.5zM364 470l106 -106q7 -8 7 -18t-7 -18l-199 -199l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l199 199 q8 7 18 7t18 -7zM1071 271l94 94q14 14 24.5 10t10.5 -25v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -25 10.5t10 24.5l94 94l-199 199q-7 8 -7 18t7 18l106 106q8 7 18 7t18 -7z" />
<glyph unicode="&#xe141;" d="M596 1192q121 0 231.5 -47.5t190 -127t127 -190t47.5 -231.5t-47.5 -231.5t-127 -190.5t-190 -127t-231.5 -47t-231.5 47t-190.5 127t-127 190.5t-47 231.5t47 231.5t127 190t190.5 127t231.5 47.5zM596 1010q-112 0 -207.5 -55.5t-151 -151t-55.5 -207.5t55.5 -207.5 t151 -151t207.5 -55.5t207.5 55.5t151 151t55.5 207.5t-55.5 207.5t-151 151t-207.5 55.5zM454.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38.5 -16.5t-38.5 16.5t-16 39t16 38.5t38.5 16zM754.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38 -16.5q-14 0 -29 10l-55 -145 q17 -23 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 23 16 39t38.5 16zM345.5 709q22.5 0 38.5 -16t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16zM854.5 709q22.5 0 38.5 -16 t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16z" />
<glyph unicode="&#xe142;" d="M546 173l469 470q91 91 99 192q7 98 -52 175.5t-154 94.5q-22 4 -47 4q-34 0 -66.5 -10t-56.5 -23t-55.5 -38t-48 -41.5t-48.5 -47.5q-376 -375 -391 -390q-30 -27 -45 -41.5t-37.5 -41t-32 -46.5t-16 -47.5t-1.5 -56.5q9 -62 53.5 -95t99.5 -33q74 0 125 51l548 548 q36 36 20 75q-7 16 -21.5 26t-32.5 10q-26 0 -50 -23q-13 -12 -39 -38l-341 -338q-15 -15 -35.5 -15.5t-34.5 13.5t-14 34.5t14 34.5q327 333 361 367q35 35 67.5 51.5t78.5 16.5q14 0 29 -1q44 -8 74.5 -35.5t43.5 -68.5q14 -47 2 -96.5t-47 -84.5q-12 -11 -32 -32 t-79.5 -81t-114.5 -115t-124.5 -123.5t-123 -119.5t-96.5 -89t-57 -45q-56 -27 -120 -27q-70 0 -129 32t-93 89q-48 78 -35 173t81 163l511 511q71 72 111 96q91 55 198 55q80 0 152 -33q78 -36 129.5 -103t66.5 -154q17 -93 -11 -183.5t-94 -156.5l-482 -476 q-15 -15 -36 -16t-37 14t-17.5 34t14.5 35z" />
<glyph unicode="&#xe143;" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104zM896 972q-33 0 -64.5 -19t-56.5 -46t-47.5 -53.5t-43.5 -45.5t-37.5 -19t-36 19t-40 45.5t-43 53.5t-54 46t-65.5 19q-67 0 -122.5 -55.5t-55.5 -132.5q0 -23 13.5 -51t46 -65t57.5 -63t76 -75l22 -22q15 -14 44 -44t50.5 -51t46 -44t41 -35t23 -12 t23.5 12t42.5 36t46 44t52.5 52t44 43q4 4 12 13q43 41 63.5 62t52 55t46 55t26 46t11.5 44q0 79 -53 133.5t-120 54.5z" />
<glyph unicode="&#xe144;" d="M776.5 1214q93.5 0 159.5 -66l141 -141q66 -66 66 -160q0 -42 -28 -95.5t-62 -87.5l-29 -29q-31 53 -77 99l-18 18l95 95l-247 248l-389 -389l212 -212l-105 -106l-19 18l-141 141q-66 66 -66 159t66 159l283 283q65 66 158.5 66zM600 706l105 105q10 -8 19 -17l141 -141 q66 -66 66 -159t-66 -159l-283 -283q-66 -66 -159 -66t-159 66l-141 141q-66 66 -66 159.5t66 159.5l55 55q29 -55 75 -102l18 -17l-95 -95l247 -248l389 389z" />
<glyph unicode="&#xe145;" d="M603 1200q85 0 162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5v953q0 21 30 46.5t81 48t129 37.5t163 15zM300 1000v-700h600v700h-600zM600 254q-43 0 -73.5 -30.5t-30.5 -73.5t30.5 -73.5t73.5 -30.5t73.5 30.5 t30.5 73.5t-30.5 73.5t-73.5 30.5z" />
<glyph unicode="&#xe146;" d="M902 1185l283 -282q15 -15 15 -36t-14.5 -35.5t-35.5 -14.5t-35 15l-36 35l-279 -267v-300l-212 210l-308 -307l-280 -203l203 280l307 308l-210 212h300l267 279l-35 36q-15 14 -15 35t14.5 35.5t35.5 14.5t35 -15z" />
<glyph unicode="&#xe148;" d="M700 1248v-78q38 -5 72.5 -14.5t75.5 -31.5t71 -53.5t52 -84t24 -118.5h-159q-4 36 -10.5 59t-21 45t-40 35.5t-64.5 20.5v-307l64 -13q34 -7 64 -16.5t70 -32t67.5 -52.5t47.5 -80t20 -112q0 -139 -89 -224t-244 -97v-77h-100v79q-150 16 -237 103q-40 40 -52.5 93.5 t-15.5 139.5h139q5 -77 48.5 -126t117.5 -65v335l-27 8q-46 14 -79 26.5t-72 36t-63 52t-40 72.5t-16 98q0 70 25 126t67.5 92t94.5 57t110 27v77h100zM600 754v274q-29 -4 -50 -11t-42 -21.5t-31.5 -41.5t-10.5 -65q0 -29 7 -50.5t16.5 -34t28.5 -22.5t31.5 -14t37.5 -10 q9 -3 13 -4zM700 547v-310q22 2 42.5 6.5t45 15.5t41.5 27t29 42t12 59.5t-12.5 59.5t-38 44.5t-53 31t-66.5 24.5z" />
<glyph unicode="&#xe149;" d="M561 1197q84 0 160.5 -40t123.5 -109.5t47 -147.5h-153q0 40 -19.5 71.5t-49.5 48.5t-59.5 26t-55.5 9q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -26 13.5 -63t26.5 -61t37 -66q6 -9 9 -14h241v-100h-197q8 -50 -2.5 -115t-31.5 -95q-45 -62 -99 -112 q34 10 83 17.5t71 7.5q32 1 102 -16t104 -17q83 0 136 30l50 -147q-31 -19 -58 -30.5t-55 -15.5t-42 -4.5t-46 -0.5q-23 0 -76 17t-111 32.5t-96 11.5q-39 -3 -82 -16t-67 -25l-23 -11l-55 145q4 3 16 11t15.5 10.5t13 9t15.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221v100h166q-23 47 -44 104q-7 20 -12 41.5t-6 55.5t6 66.5t29.5 70.5t58.5 71q97 88 263 88z" />
<glyph unicode="&#xe150;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM935 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-900h-200v900h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
<glyph unicode="&#xe151;" d="M1000 700h-100v100h-100v-100h-100v500h300v-500zM400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM801 1100v-200h100v200h-100zM1000 350l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150z " />
<glyph unicode="&#xe152;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 1050l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150zM1000 0h-100v100h-100v-100h-100v500h300v-500zM801 400v-200h100v200h-100z " />
<glyph unicode="&#xe153;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 700h-100v400h-100v100h200v-500zM1100 0h-100v100h-200v400h300v-500zM901 400v-200h100v200h-100z" />
<glyph unicode="&#xe154;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1100 700h-100v100h-200v400h300v-500zM901 1100v-200h100v200h-100zM1000 0h-100v400h-100v100h200v-500z" />
<glyph unicode="&#xe155;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM900 1000h-200v200h200v-200zM1000 700h-300v200h300v-200zM1100 400h-400v200h400v-200zM1200 100h-500v200h500v-200z" />
<glyph unicode="&#xe156;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1200 1000h-500v200h500v-200zM1100 700h-400v200h400v-200zM1000 400h-300v200h300v-200zM900 100h-200v200h200v-200z" />
<glyph unicode="&#xe157;" d="M350 1100h400q162 0 256 -93.5t94 -256.5v-400q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5z" />
<glyph unicode="&#xe158;" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-163 0 -256.5 92.5t-93.5 257.5v400q0 163 94 256.5t256 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM440 770l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" />
<glyph unicode="&#xe159;" d="M350 1100h400q163 0 256.5 -94t93.5 -256v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 163 92.5 256.5t257.5 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM350 700h400q21 0 26.5 -12t-6.5 -28l-190 -253q-12 -17 -30 -17t-30 17l-190 253q-12 16 -6.5 28t26.5 12z" />
<glyph unicode="&#xe160;" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -163 -92.5 -256.5t-257.5 -93.5h-400q-163 0 -256.5 94t-93.5 256v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM580 693l190 -253q12 -16 6.5 -28t-26.5 -12h-400q-21 0 -26.5 12t6.5 28l190 253q12 17 30 17t30 -17z" />
<glyph unicode="&#xe161;" d="M550 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h450q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-450q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM338 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" />
<glyph unicode="&#xe162;" d="M793 1182l9 -9q8 -10 5 -27q-3 -11 -79 -225.5t-78 -221.5l300 1q24 0 32.5 -17.5t-5.5 -35.5q-1 0 -133.5 -155t-267 -312.5t-138.5 -162.5q-12 -15 -26 -15h-9l-9 8q-9 11 -4 32q2 9 42 123.5t79 224.5l39 110h-302q-23 0 -31 19q-10 21 6 41q75 86 209.5 237.5 t228 257t98.5 111.5q9 16 25 16h9z" />
<glyph unicode="&#xe163;" d="M350 1100h400q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-450q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h450q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400 q0 165 92.5 257.5t257.5 92.5zM938 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" />
<glyph unicode="&#xe164;" d="M750 1200h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -10.5 -25t-24.5 10l-109 109l-312 -312q-15 -15 -35.5 -15t-35.5 15l-141 141q-15 15 -15 35.5t15 35.5l312 312l-109 109q-14 14 -10 24.5t25 10.5zM456 900h-156q-41 0 -70.5 -29.5t-29.5 -70.5v-500 q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v148l200 200v-298q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5h300z" />
<glyph unicode="&#xe165;" d="M600 1186q119 0 227.5 -46.5t187 -125t125 -187t46.5 -227.5t-46.5 -227.5t-125 -187t-187 -125t-227.5 -46.5t-227.5 46.5t-187 125t-125 187t-46.5 227.5t46.5 227.5t125 187t187 125t227.5 46.5zM600 1022q-115 0 -212 -56.5t-153.5 -153.5t-56.5 -212t56.5 -212 t153.5 -153.5t212 -56.5t212 56.5t153.5 153.5t56.5 212t-56.5 212t-153.5 153.5t-212 56.5zM600 794q80 0 137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137t57 137t137 57z" />
<glyph unicode="&#xe166;" d="M450 1200h200q21 0 35.5 -14.5t14.5 -35.5v-350h245q20 0 25 -11t-9 -26l-383 -426q-14 -15 -33.5 -15t-32.5 15l-379 426q-13 15 -8.5 26t25.5 11h250v350q0 21 14.5 35.5t35.5 14.5zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" />
<glyph unicode="&#xe167;" d="M583 1182l378 -435q14 -15 9 -31t-26 -16h-244v-250q0 -20 -17 -35t-39 -15h-200q-20 0 -32 14.5t-12 35.5v250h-250q-20 0 -25.5 16.5t8.5 31.5l383 431q14 16 33.5 17t33.5 -14zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" />
<glyph unicode="&#xe168;" d="M396 723l369 369q7 7 17.5 7t17.5 -7l139 -139q7 -8 7 -18.5t-7 -17.5l-525 -525q-7 -8 -17.5 -8t-17.5 8l-292 291q-7 8 -7 18t7 18l139 139q8 7 18.5 7t17.5 -7zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50 h-100z" />
<glyph unicode="&#xe169;" d="M135 1023l142 142q14 14 35 14t35 -14l77 -77l-212 -212l-77 76q-14 15 -14 36t14 35zM655 855l210 210q14 14 24.5 10t10.5 -25l-2 -599q-1 -20 -15.5 -35t-35.5 -15l-597 -1q-21 0 -25 10.5t10 24.5l208 208l-154 155l212 212zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5 v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" />
<glyph unicode="&#xe170;" d="M350 1200l599 -2q20 -1 35 -15.5t15 -35.5l1 -597q0 -21 -10.5 -25t-24.5 10l-208 208l-155 -154l-212 212l155 154l-210 210q-14 14 -10 24.5t25 10.5zM524 512l-76 -77q-15 -14 -36 -14t-35 14l-142 142q-14 14 -14 35t14 35l77 77zM50 300h1000q21 0 35.5 -14.5 t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" />
<glyph unicode="&#xe171;" d="M1200 103l-483 276l-314 -399v423h-399l1196 796v-1096zM483 424v-230l683 953z" />
<glyph unicode="&#xe172;" d="M1100 1000v-850q0 -21 -14.5 -35.5t-35.5 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200z" />
<glyph unicode="&#xe173;" d="M1100 1000l-2 -149l-299 -299l-95 95q-9 9 -21.5 9t-21.5 -9l-149 -147h-312v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1132 638l106 -106q7 -7 7 -17.5t-7 -17.5l-420 -421q-8 -7 -18 -7 t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l297 297q7 7 17.5 7t17.5 -7z" />
<glyph unicode="&#xe174;" d="M1100 1000v-269l-103 -103l-134 134q-15 15 -33.5 16.5t-34.5 -12.5l-266 -266h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1202 572l70 -70q15 -15 15 -35.5t-15 -35.5l-131 -131 l131 -131q15 -15 15 -35.5t-15 -35.5l-70 -70q-15 -15 -35.5 -15t-35.5 15l-131 131l-131 -131q-15 -15 -35.5 -15t-35.5 15l-70 70q-15 15 -15 35.5t15 35.5l131 131l-131 131q-15 15 -15 35.5t15 35.5l70 70q15 15 35.5 15t35.5 -15l131 -131l131 131q15 15 35.5 15 t35.5 -15z" />
<glyph unicode="&#xe175;" d="M1100 1000v-300h-350q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM850 600h100q21 0 35.5 -14.5t14.5 -35.5v-250h150q21 0 25 -10.5t-10 -24.5 l-230 -230q-14 -14 -35 -14t-35 14l-230 230q-14 14 -10 24.5t25 10.5h150v250q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe176;" d="M1100 1000v-400l-165 165q-14 15 -35 15t-35 -15l-263 -265h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM935 565l230 -229q14 -15 10 -25.5t-25 -10.5h-150v-250q0 -20 -14.5 -35 t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35v250h-150q-21 0 -25 10.5t10 25.5l230 229q14 15 35 15t35 -15z" />
<glyph unicode="&#xe177;" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-150h-1200v150q0 21 14.5 35.5t35.5 14.5zM1200 800v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v550h1200zM100 500v-200h400v200h-400z" />
<glyph unicode="&#xe178;" d="M935 1165l248 -230q14 -14 14 -35t-14 -35l-248 -230q-14 -14 -24.5 -10t-10.5 25v150h-400v200h400v150q0 21 10.5 25t24.5 -10zM200 800h-50q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v-200zM400 800h-100v200h100v-200zM18 435l247 230 q14 14 24.5 10t10.5 -25v-150h400v-200h-400v-150q0 -21 -10.5 -25t-24.5 10l-247 230q-15 14 -15 35t15 35zM900 300h-100v200h100v-200zM1000 500h51q20 0 34.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-34.5 -14.5h-51v200z" />
<glyph unicode="&#xe179;" d="M862 1073l276 116q25 18 43.5 8t18.5 -41v-1106q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v397q-4 1 -11 5t-24 17.5t-30 29t-24 42t-11 56.5v359q0 31 18.5 65t43.5 52zM550 1200q22 0 34.5 -12.5t14.5 -24.5l1 -13v-450q0 -28 -10.5 -59.5 t-25 -56t-29 -45t-25.5 -31.5l-10 -11v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447q-4 4 -11 11.5t-24 30.5t-30 46t-24 55t-11 60v450q0 2 0.5 5.5t4 12t8.5 15t14.5 12t22.5 5.5q20 0 32.5 -12.5t14.5 -24.5l3 -13v-350h100v350v5.5t2.5 12 t7 15t15 12t25.5 5.5q23 0 35.5 -12.5t13.5 -24.5l1 -13v-350h100v350q0 2 0.5 5.5t3 12t7 15t15 12t24.5 5.5z" />
<glyph unicode="&#xe180;" d="M1200 1100v-56q-4 0 -11 -0.5t-24 -3t-30 -7.5t-24 -15t-11 -24v-888q0 -22 25 -34.5t50 -13.5l25 -2v-56h-400v56q75 0 87.5 6.5t12.5 43.5v394h-500v-394q0 -37 12.5 -43.5t87.5 -6.5v-56h-400v56q4 0 11 0.5t24 3t30 7.5t24 15t11 24v888q0 22 -25 34.5t-50 13.5 l-25 2v56h400v-56q-75 0 -87.5 -6.5t-12.5 -43.5v-394h500v394q0 37 -12.5 43.5t-87.5 6.5v56h400z" />
<glyph unicode="&#xe181;" d="M675 1000h375q21 0 35.5 -14.5t14.5 -35.5v-150h-105l-295 -98v98l-200 200h-400l100 100h375zM100 900h300q41 0 70.5 -29.5t29.5 -70.5v-500q0 -41 -29.5 -70.5t-70.5 -29.5h-300q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5zM100 800v-200h300v200 h-300zM1100 535l-400 -133v163l400 133v-163zM100 500v-200h300v200h-300zM1100 398v-248q0 -21 -14.5 -35.5t-35.5 -14.5h-375l-100 -100h-375l-100 100h400l200 200h105z" />
<glyph unicode="&#xe182;" d="M17 1007l162 162q17 17 40 14t37 -22l139 -194q14 -20 11 -44.5t-20 -41.5l-119 -118q102 -142 228 -268t267 -227l119 118q17 17 42.5 19t44.5 -12l192 -136q19 -14 22.5 -37.5t-13.5 -40.5l-163 -162q-3 -1 -9.5 -1t-29.5 2t-47.5 6t-62.5 14.5t-77.5 26.5t-90 42.5 t-101.5 60t-111 83t-119 108.5q-74 74 -133.5 150.5t-94.5 138.5t-60 119.5t-34.5 100t-15 74.5t-4.5 48z" />
<glyph unicode="&#xe183;" d="M600 1100q92 0 175 -10.5t141.5 -27t108.5 -36.5t81.5 -40t53.5 -37t31 -27l9 -10v-200q0 -21 -14.5 -33t-34.5 -9l-202 34q-20 3 -34.5 20t-14.5 38v146q-141 24 -300 24t-300 -24v-146q0 -21 -14.5 -38t-34.5 -20l-202 -34q-20 -3 -34.5 9t-14.5 33v200q3 4 9.5 10.5 t31 26t54 37.5t80.5 39.5t109 37.5t141 26.5t175 10.5zM600 795q56 0 97 -9.5t60 -23.5t30 -28t12 -24l1 -10v-50l365 -303q14 -15 24.5 -40t10.5 -45v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v212q0 20 10.5 45t24.5 40l365 303v50 q0 4 1 10.5t12 23t30 29t60 22.5t97 10z" />
<glyph unicode="&#xe184;" d="M1100 700l-200 -200h-600l-200 200v500h200v-200h200v200h200v-200h200v200h200v-500zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5 t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe185;" d="M700 1100h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-1000h300v1000q0 41 -29.5 70.5t-70.5 29.5zM1100 800h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-700h300v700q0 41 -29.5 70.5t-70.5 29.5zM400 0h-300v400q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-400z " />
<glyph unicode="&#xe186;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" />
<glyph unicode="&#xe187;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 300h-100v200h-100v-200h-100v500h100v-200h100v200h100v-500zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" />
<glyph unicode="&#xe188;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-300h200v-100h-300v500h300v-100zM900 700h-200v-300h200v-100h-300v500h300v-100z" />
<glyph unicode="&#xe189;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 400l-300 150l300 150v-300zM900 550l-300 -150v300z" />
<glyph unicode="&#xe190;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM900 300h-700v500h700v-500zM800 700h-130q-38 0 -66.5 -43t-28.5 -108t27 -107t68 -42h130v300zM300 700v-300 h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130z" />
<glyph unicode="&#xe191;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 300h-100v400h-100v100h200v-500z M700 300h-100v100h100v-100z" />
<glyph unicode="&#xe192;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM300 700h200v-400h-300v500h100v-100zM900 300h-100v400h-100v100h200v-500zM300 600v-200h100v200h-100z M700 300h-100v100h100v-100z" />
<glyph unicode="&#xe193;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 500l-199 -200h-100v50l199 200v150h-200v100h300v-300zM900 300h-100v400h-100v100h200v-500zM701 300h-100 v100h100v-100z" />
<glyph unicode="&#xe194;" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700h-300v-200h300v-100h-300l-100 100v200l100 100h300v-100z" />
<glyph unicode="&#xe195;" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700v-100l-50 -50l100 -100v-50h-100l-100 100h-150v-100h-100v400h300zM500 700v-100h200v100h-200z" />
<glyph unicode="&#xe197;" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -207t-85 -207t-205 -86.5h-128v250q0 21 -14.5 35.5t-35.5 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-250h-222q-80 0 -136 57.5t-56 136.5q0 69 43 122.5t108 67.5q-2 19 -2 37q0 100 49 185 t134 134t185 49zM525 500h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -244q-13 -16 -32 -16t-32 16l-223 244q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe198;" d="M502 1089q110 0 201 -59.5t135 -156.5q43 15 89 15q121 0 206 -86.5t86 -206.5q0 -99 -60 -181t-150 -110l-378 360q-13 16 -31.5 16t-31.5 -16l-381 -365h-9q-79 0 -135.5 57.5t-56.5 136.5q0 69 43 122.5t108 67.5q-2 19 -2 38q0 100 49 184.5t133.5 134t184.5 49.5z M632 467l223 -228q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5q199 204 223 228q19 19 31.5 19t32.5 -19z" />
<glyph unicode="&#xe199;" d="M700 100v100h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170l-270 -300h400v-100h-50q-21 0 -35.5 -14.5t-14.5 -35.5v-50h400v50q0 21 -14.5 35.5t-35.5 14.5h-50z" />
<glyph unicode="&#xe200;" d="M600 1179q94 0 167.5 -56.5t99.5 -145.5q89 -6 150.5 -71.5t61.5 -155.5q0 -61 -29.5 -112.5t-79.5 -82.5q9 -29 9 -55q0 -74 -52.5 -126.5t-126.5 -52.5q-55 0 -100 30v-251q21 0 35.5 -14.5t14.5 -35.5v-50h-300v50q0 21 14.5 35.5t35.5 14.5v251q-45 -30 -100 -30 q-74 0 -126.5 52.5t-52.5 126.5q0 18 4 38q-47 21 -75.5 65t-28.5 97q0 74 52.5 126.5t126.5 52.5q5 0 23 -2q0 2 -1 10t-1 13q0 116 81.5 197.5t197.5 81.5z" />
<glyph unicode="&#xe201;" d="M1010 1010q111 -111 150.5 -260.5t0 -299t-150.5 -260.5q-83 -83 -191.5 -126.5t-218.5 -43.5t-218.5 43.5t-191.5 126.5q-111 111 -150.5 260.5t0 299t150.5 260.5q83 83 191.5 126.5t218.5 43.5t218.5 -43.5t191.5 -126.5zM476 1065q-4 0 -8 -1q-121 -34 -209.5 -122.5 t-122.5 -209.5q-4 -12 2.5 -23t18.5 -14l36 -9q3 -1 7 -1q23 0 29 22q27 96 98 166q70 71 166 98q11 3 17.5 13.5t3.5 22.5l-9 35q-3 13 -14 19q-7 4 -15 4zM512 920q-4 0 -9 -2q-80 -24 -138.5 -82.5t-82.5 -138.5q-4 -13 2 -24t19 -14l34 -9q4 -1 8 -1q22 0 28 21 q18 58 58.5 98.5t97.5 58.5q12 3 18 13.5t3 21.5l-9 35q-3 12 -14 19q-7 4 -15 4zM719.5 719.5q-49.5 49.5 -119.5 49.5t-119.5 -49.5t-49.5 -119.5t49.5 -119.5t119.5 -49.5t119.5 49.5t49.5 119.5t-49.5 119.5zM855 551q-22 0 -28 -21q-18 -58 -58.5 -98.5t-98.5 -57.5 q-11 -4 -17 -14.5t-3 -21.5l9 -35q3 -12 14 -19q7 -4 15 -4q4 0 9 2q80 24 138.5 82.5t82.5 138.5q4 13 -2.5 24t-18.5 14l-34 9q-4 1 -8 1zM1000 515q-23 0 -29 -22q-27 -96 -98 -166q-70 -71 -166 -98q-11 -3 -17.5 -13.5t-3.5 -22.5l9 -35q3 -13 14 -19q7 -4 15 -4 q4 0 8 1q121 34 209.5 122.5t122.5 209.5q4 12 -2.5 23t-18.5 14l-36 9q-3 1 -7 1z" />
<glyph unicode="&#xe202;" d="M700 800h300v-380h-180v200h-340v-200h-380v755q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM700 300h162l-212 -212l-212 212h162v200h100v-200zM520 0h-395q-10 0 -17.5 7.5t-7.5 17.5v395zM1000 220v-195q0 -10 -7.5 -17.5t-17.5 -7.5h-195z" />
<glyph unicode="&#xe203;" d="M700 800h300v-520l-350 350l-550 -550v1095q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM862 200h-162v-200h-100v200h-162l212 212zM480 0h-355q-10 0 -17.5 7.5t-7.5 17.5v55h380v-80zM1000 80v-55q0 -10 -7.5 -17.5t-17.5 -7.5h-155v80h180z" />
<glyph unicode="&#xe204;" d="M1162 800h-162v-200h100l100 -100h-300v300h-162l212 212zM200 800h200q27 0 40 -2t29.5 -10.5t23.5 -30t7 -57.5h300v-100h-600l-200 -350v450h100q0 36 7 57.5t23.5 30t29.5 10.5t40 2zM800 400h240l-240 -400h-800l300 500h500v-100z" />
<glyph unicode="&#xe205;" d="M650 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM1000 850v150q41 0 70.5 -29.5t29.5 -70.5v-800 q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-1 0 -20 4l246 246l-326 326v324q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM412 250l-212 -212v162h-200v100h200v162z" />
<glyph unicode="&#xe206;" d="M450 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM800 850v150q41 0 70.5 -29.5t29.5 -70.5v-500 h-200v-300h200q0 -36 -7 -57.5t-23.5 -30t-29.5 -10.5t-40 -2h-600q-41 0 -70.5 29.5t-29.5 70.5v800q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM1212 250l-212 -212v162h-200v100h200v162z" />
<glyph unicode="&#xe209;" d="M658 1197l637 -1104q23 -38 7 -65.5t-60 -27.5h-1276q-44 0 -60 27.5t7 65.5l637 1104q22 39 54 39t54 -39zM704 800h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM500 300v-100h200 v100h-200z" />
<glyph unicode="&#xe210;" d="M425 1100h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM825 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM25 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5zM425 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5 v150q0 10 7.5 17.5t17.5 7.5zM25 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe211;" d="M700 1200h100v-200h-100v-100h350q62 0 86.5 -39.5t-3.5 -94.5l-66 -132q-41 -83 -81 -134h-772q-40 51 -81 134l-66 132q-28 55 -3.5 94.5t86.5 39.5h350v100h-100v200h100v100h200v-100zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100 h-950l138 100h-13q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe212;" d="M600 1300q40 0 68.5 -29.5t28.5 -70.5h-194q0 41 28.5 70.5t68.5 29.5zM443 1100h314q18 -37 18 -75q0 -8 -3 -25h328q41 0 44.5 -16.5t-30.5 -38.5l-175 -145h-678l-178 145q-34 22 -29 38.5t46 16.5h328q-3 17 -3 25q0 38 18 75zM250 700h700q21 0 35.5 -14.5 t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-150v-200l275 -200h-950l275 200v200h-150q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe213;" d="M600 1181q75 0 128 -53t53 -128t-53 -128t-128 -53t-128 53t-53 128t53 128t128 53zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13 l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe214;" d="M600 1300q47 0 92.5 -53.5t71 -123t25.5 -123.5q0 -78 -55.5 -133.5t-133.5 -55.5t-133.5 55.5t-55.5 133.5q0 62 34 143l144 -143l111 111l-163 163q34 26 63 26zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45 zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe215;" d="M600 1200l300 -161v-139h-300q0 -57 18.5 -108t50 -91.5t63 -72t70 -67.5t57.5 -61h-530q-60 83 -90.5 177.5t-30.5 178.5t33 164.5t87.5 139.5t126 96.5t145.5 41.5v-98zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100 h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe216;" d="M600 1300q41 0 70.5 -29.5t29.5 -70.5v-78q46 -26 73 -72t27 -100v-50h-400v50q0 54 27 100t73 72v78q0 41 29.5 70.5t70.5 29.5zM400 800h400q54 0 100 -27t72 -73h-172v-100h200v-100h-200v-100h200v-100h-200v-100h200q0 -83 -58.5 -141.5t-141.5 -58.5h-400 q-83 0 -141.5 58.5t-58.5 141.5v400q0 83 58.5 141.5t141.5 58.5z" />
<glyph unicode="&#xe218;" d="M150 1100h900q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM125 400h950q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-283l224 -224q13 -13 13 -31.5t-13 -32 t-31.5 -13.5t-31.5 13l-88 88h-524l-87 -88q-13 -13 -32 -13t-32 13.5t-13 32t13 31.5l224 224h-289q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM541 300l-100 -100h324l-100 100h-124z" />
<glyph unicode="&#xe219;" d="M200 1100h800q83 0 141.5 -58.5t58.5 -141.5v-200h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100v200q0 83 58.5 141.5t141.5 58.5zM100 600h1000q41 0 70.5 -29.5 t29.5 -70.5v-300h-1200v300q0 41 29.5 70.5t70.5 29.5zM300 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200zM1100 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200z" />
<glyph unicode="&#xe221;" d="M480 1165l682 -683q31 -31 31 -75.5t-31 -75.5l-131 -131h-481l-517 518q-32 31 -32 75.5t32 75.5l295 296q31 31 75.5 31t76.5 -31zM108 794l342 -342l303 304l-341 341zM250 100h800q21 0 35.5 -14.5t14.5 -35.5v-50h-900v50q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe223;" d="M1057 647l-189 506q-8 19 -27.5 33t-40.5 14h-400q-21 0 -40.5 -14t-27.5 -33l-189 -506q-8 -19 1.5 -33t30.5 -14h625v-150q0 -21 14.5 -35.5t35.5 -14.5t35.5 14.5t14.5 35.5v150h125q21 0 30.5 14t1.5 33zM897 0h-595v50q0 21 14.5 35.5t35.5 14.5h50v50 q0 21 14.5 35.5t35.5 14.5h48v300h200v-300h47q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-50z" />
<glyph unicode="&#xe224;" d="M900 800h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-375v591l-300 300v84q0 10 7.5 17.5t17.5 7.5h375v-400zM1200 900h-200v200zM400 600h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-650q-10 0 -17.5 7.5t-7.5 17.5v950q0 10 7.5 17.5t17.5 7.5h375v-400zM700 700h-200v200z " />
<glyph unicode="&#xe225;" d="M484 1095h195q75 0 146 -32.5t124 -86t89.5 -122.5t48.5 -142q18 -14 35 -20q31 -10 64.5 6.5t43.5 48.5q10 34 -15 71q-19 27 -9 43q5 8 12.5 11t19 -1t23.5 -16q41 -44 39 -105q-3 -63 -46 -106.5t-104 -43.5h-62q-7 -55 -35 -117t-56 -100l-39 -234q-3 -20 -20 -34.5 t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l12 70q-49 -14 -91 -14h-195q-24 0 -65 8l-11 -64q-3 -20 -20 -34.5t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l26 157q-84 74 -128 175l-159 53q-19 7 -33 26t-14 40v50q0 21 14.5 35.5t35.5 14.5h124q11 87 56 166l-111 95 q-16 14 -12.5 23.5t24.5 9.5h203q116 101 250 101zM675 1000h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h250q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5t-17.5 7.5z" />
<glyph unicode="&#xe226;" d="M641 900l423 247q19 8 42 2.5t37 -21.5l32 -38q14 -15 12.5 -36t-17.5 -34l-139 -120h-390zM50 1100h106q67 0 103 -17t66 -71l102 -212h823q21 0 35.5 -14.5t14.5 -35.5v-50q0 -21 -14 -40t-33 -26l-737 -132q-23 -4 -40 6t-26 25q-42 67 -100 67h-300q-62 0 -106 44 t-44 106v200q0 62 44 106t106 44zM173 928h-80q-19 0 -28 -14t-9 -35v-56q0 -51 42 -51h134q16 0 21.5 8t5.5 24q0 11 -16 45t-27 51q-18 28 -43 28zM550 727q-32 0 -54.5 -22.5t-22.5 -54.5t22.5 -54.5t54.5 -22.5t54.5 22.5t22.5 54.5t-22.5 54.5t-54.5 22.5zM130 389 l152 130q18 19 34 24t31 -3.5t24.5 -17.5t25.5 -28q28 -35 50.5 -51t48.5 -13l63 5l48 -179q13 -61 -3.5 -97.5t-67.5 -79.5l-80 -69q-47 -40 -109 -35.5t-103 51.5l-130 151q-40 47 -35.5 109.5t51.5 102.5zM380 377l-102 -88q-31 -27 2 -65l37 -43q13 -15 27.5 -19.5 t31.5 6.5l61 53q19 16 14 49q-2 20 -12 56t-17 45q-11 12 -19 14t-23 -8z" />
<glyph unicode="&#xe227;" d="M625 1200h150q10 0 17.5 -7.5t7.5 -17.5v-109q79 -33 131 -87.5t53 -128.5q1 -46 -15 -84.5t-39 -61t-46 -38t-39 -21.5l-17 -6q6 0 15 -1.5t35 -9t50 -17.5t53 -30t50 -45t35.5 -64t14.5 -84q0 -59 -11.5 -105.5t-28.5 -76.5t-44 -51t-49.5 -31.5t-54.5 -16t-49.5 -6.5 t-43.5 -1v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-100v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-175q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v600h-75q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5h175v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h100v75q0 10 7.5 17.5t17.5 7.5zM400 900v-200h263q28 0 48.5 10.5t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-263zM400 500v-200h363q28 0 48.5 10.5 t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-363z" />
<glyph unicode="&#xe230;" d="M212 1198h780q86 0 147 -61t61 -147v-416q0 -51 -18 -142.5t-36 -157.5l-18 -66q-29 -87 -93.5 -146.5t-146.5 -59.5h-572q-82 0 -147 59t-93 147q-8 28 -20 73t-32 143.5t-20 149.5v416q0 86 61 147t147 61zM600 1045q-70 0 -132.5 -11.5t-105.5 -30.5t-78.5 -41.5 t-57 -45t-36 -41t-20.5 -30.5l-6 -12l156 -243h560l156 243q-2 5 -6 12.5t-20 29.5t-36.5 42t-57 44.5t-79 42t-105 29.5t-132.5 12zM762 703h-157l195 261z" />
<glyph unicode="&#xe231;" d="M475 1300h150q103 0 189 -86t86 -189v-500q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" />
<glyph unicode="&#xe232;" d="M475 1300h96q0 -150 89.5 -239.5t239.5 -89.5v-446q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" />
<glyph unicode="&#xe233;" d="M1294 767l-638 -283l-378 170l-78 -60v-224l100 -150v-199l-150 148l-150 -149v200l100 150v250q0 4 -0.5 10.5t0 9.5t1 8t3 8t6.5 6l47 40l-147 65l642 283zM1000 380l-350 -166l-350 166v147l350 -165l350 165v-147z" />
<glyph unicode="&#xe234;" d="M250 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM650 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM1050 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" />
<glyph unicode="&#xe235;" d="M550 1100q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 700q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 300q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" />
<glyph unicode="&#xe236;" d="M125 1100h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM125 700h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM125 300h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
<glyph unicode="&#xe237;" d="M350 1200h500q162 0 256 -93.5t94 -256.5v-500q0 -165 -93.5 -257.5t-256.5 -92.5h-500q-165 0 -257.5 92.5t-92.5 257.5v500q0 165 92.5 257.5t257.5 92.5zM900 1000h-600q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h600q41 0 70.5 29.5 t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5zM350 900h500q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-500q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 14.5 35.5t35.5 14.5zM400 800v-200h400v200h-400z" />
<glyph unicode="&#xe238;" d="M150 1100h1000q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe239;" d="M650 1187q87 -67 118.5 -156t0 -178t-118.5 -155q-87 66 -118.5 155t0 178t118.5 156zM300 800q124 0 212 -88t88 -212q-124 0 -212 88t-88 212zM1000 800q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM300 500q124 0 212 -88t88 -212q-124 0 -212 88t-88 212z M1000 500q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM700 199v-144q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v142q40 -4 43 -4q17 0 57 6z" />
<glyph unicode="&#xe240;" d="M745 878l69 19q25 6 45 -12l298 -295q11 -11 15 -26.5t-2 -30.5q-5 -14 -18 -23.5t-28 -9.5h-8q1 0 1 -13q0 -29 -2 -56t-8.5 -62t-20 -63t-33 -53t-51 -39t-72.5 -14h-146q-184 0 -184 288q0 24 10 47q-20 4 -62 4t-63 -4q11 -24 11 -47q0 -288 -184 -288h-142 q-48 0 -84.5 21t-56 51t-32 71.5t-16 75t-3.5 68.5q0 13 2 13h-7q-15 0 -27.5 9.5t-18.5 23.5q-6 15 -2 30.5t15 25.5l298 296q20 18 46 11l76 -19q20 -5 30.5 -22.5t5.5 -37.5t-22.5 -31t-37.5 -5l-51 12l-182 -193h891l-182 193l-44 -12q-20 -5 -37.5 6t-22.5 31t6 37.5 t31 22.5z" />
<glyph unicode="&#xe241;" d="M1200 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM500 450h-25q0 15 -4 24.5t-9 14.5t-17 7.5t-20 3t-25 0.5h-100v-425q0 -11 12.5 -17.5t25.5 -7.5h12v-50h-200v50q50 0 50 25v425h-100q-17 0 -25 -0.5t-20 -3t-17 -7.5t-9 -14.5t-4 -24.5h-25v150h500v-150z" />
<glyph unicode="&#xe242;" d="M1000 300v50q-25 0 -55 32q-14 14 -25 31t-16 27l-4 11l-289 747h-69l-300 -754q-18 -35 -39 -56q-9 -9 -24.5 -18.5t-26.5 -14.5l-11 -5v-50h273v50q-49 0 -78.5 21.5t-11.5 67.5l69 176h293l61 -166q13 -34 -3.5 -66.5t-55.5 -32.5v-50h312zM412 691l134 342l121 -342 h-255zM1100 150v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5z" />
<glyph unicode="&#xe243;" d="M50 1200h1100q21 0 35.5 -14.5t14.5 -35.5v-1100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5zM611 1118h-70q-13 0 -18 -12l-299 -753q-17 -32 -35 -51q-18 -18 -56 -34q-12 -5 -12 -18v-50q0 -8 5.5 -14t14.5 -6 h273q8 0 14 6t6 14v50q0 8 -6 14t-14 6q-55 0 -71 23q-10 14 0 39l63 163h266l57 -153q11 -31 -6 -55q-12 -17 -36 -17q-8 0 -14 -6t-6 -14v-50q0 -8 6 -14t14 -6h313q8 0 14 6t6 14v50q0 7 -5.5 13t-13.5 7q-17 0 -42 25q-25 27 -40 63h-1l-288 748q-5 12 -19 12zM639 611 h-197l103 264z" />
<glyph unicode="&#xe244;" d="M1200 1100h-1200v100h1200v-100zM50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 1000h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM700 900v-300h300v300h-300z" />
<glyph unicode="&#xe245;" d="M50 1200h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 700h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM700 600v-300h300v300h-300zM1200 0h-1200v100h1200v-100z" />
<glyph unicode="&#xe246;" d="M50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-350h100v150q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-150h100v-100h-100v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v150h-100v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM700 700v-300h300v300h-300z" />
<glyph unicode="&#xe247;" d="M100 0h-100v1200h100v-1200zM250 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM300 1000v-300h300v300h-300zM250 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe248;" d="M600 1100h150q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-100h450q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h350v100h-150q-21 0 -35.5 14.5 t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h150v100h100v-100zM400 1000v-300h300v300h-300z" />
<glyph unicode="&#xe249;" d="M1200 0h-100v1200h100v-1200zM550 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM600 1000v-300h300v300h-300zM50 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
<glyph unicode="&#xe250;" d="M865 565l-494 -494q-23 -23 -41 -23q-14 0 -22 13.5t-8 38.5v1000q0 25 8 38.5t22 13.5q18 0 41 -23l494 -494q14 -14 14 -35t-14 -35z" />
<glyph unicode="&#xe251;" d="M335 635l494 494q29 29 50 20.5t21 -49.5v-1000q0 -41 -21 -49.5t-50 20.5l-494 494q-14 14 -14 35t14 35z" />
<glyph unicode="&#xe252;" d="M100 900h1000q41 0 49.5 -21t-20.5 -50l-494 -494q-14 -14 -35 -14t-35 14l-494 494q-29 29 -20.5 50t49.5 21z" />
<glyph unicode="&#xe253;" d="M635 865l494 -494q29 -29 20.5 -50t-49.5 -21h-1000q-41 0 -49.5 21t20.5 50l494 494q14 14 35 14t35 -14z" />
<glyph unicode="&#xe254;" d="M700 741v-182l-692 -323v221l413 193l-413 193v221zM1200 0h-800v200h800v-200z" />
<glyph unicode="&#xe255;" d="M1200 900h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300zM0 700h50q0 21 4 37t9.5 26.5t18 17.5t22 11t28.5 5.5t31 2t37 0.5h100v-550q0 -22 -25 -34.5t-50 -13.5l-25 -2v-100h400v100q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v550h100q25 0 37 -0.5t31 -2 t28.5 -5.5t22 -11t18 -17.5t9.5 -26.5t4 -37h50v300h-800v-300z" />
<glyph unicode="&#xe256;" d="M800 700h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-100v-550q0 -22 25 -34.5t50 -14.5l25 -1v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v550h-100q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h800v-300zM1100 200h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300z" />
<glyph unicode="&#xe257;" d="M701 1098h160q16 0 21 -11t-7 -23l-464 -464l464 -464q12 -12 7 -23t-21 -11h-160q-13 0 -23 9l-471 471q-7 8 -7 18t7 18l471 471q10 9 23 9z" />
<glyph unicode="&#xe258;" d="M339 1098h160q13 0 23 -9l471 -471q7 -8 7 -18t-7 -18l-471 -471q-10 -9 -23 -9h-160q-16 0 -21 11t7 23l464 464l-464 464q-12 12 -7 23t21 11z" />
<glyph unicode="&#xe259;" d="M1087 882q11 -5 11 -21v-160q0 -13 -9 -23l-471 -471q-8 -7 -18 -7t-18 7l-471 471q-9 10 -9 23v160q0 16 11 21t23 -7l464 -464l464 464q12 12 23 7z" />
<glyph unicode="&#xe260;" d="M618 993l471 -471q9 -10 9 -23v-160q0 -16 -11 -21t-23 7l-464 464l-464 -464q-12 -12 -23 -7t-11 21v160q0 13 9 23l471 471q8 7 18 7t18 -7z" />
<glyph unicode="&#xf8ff;" d="M1000 1200q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM450 1000h100q21 0 40 -14t26 -33l79 -194q5 1 16 3q34 6 54 9.5t60 7t65.5 1t61 -10t56.5 -23t42.5 -42t29 -64t5 -92t-19.5 -121.5q-1 -7 -3 -19.5t-11 -50t-20.5 -73t-32.5 -81.5t-46.5 -83t-64 -70 t-82.5 -50q-13 -5 -42 -5t-65.5 2.5t-47.5 2.5q-14 0 -49.5 -3.5t-63 -3.5t-43.5 7q-57 25 -104.5 78.5t-75 111.5t-46.5 112t-26 90l-7 35q-15 63 -18 115t4.5 88.5t26 64t39.5 43.5t52 25.5t58.5 13t62.5 2t59.5 -4.5t55.5 -8l-147 192q-12 18 -5.5 30t27.5 12z" />
<glyph unicode="&#x1f511;" d="M250 1200h600q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-500l-255 -178q-19 -9 -32 -1t-13 29v650h-150q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM400 1100v-100h300v100h-300z" />
<glyph unicode="&#x1f6aa;" d="M250 1200h750q39 0 69.5 -40.5t30.5 -84.5v-933l-700 -117v950l600 125h-700v-1000h-100v1025q0 23 15.5 49t34.5 26zM500 525v-100l100 20v100z" />
</font>
</defs></svg> N  AM                    LP                      ',                  ( G L Y P H I C O N S   H a l f l i n g s    R e g u l a r   x V e r s i o n   1 . 0 0 9 ; P S   0 0 1 . 0 0 9 ; h o t c o n v   1 . 0 . 7 0 ; m a k e o t f . l i b 2 . 5 . 5 8 3 2 9   8 G L Y P H I C O N S   H a l f l i n g s   R e g u l a r     BSGP                  M M F٣(uʌ<0DB/XN CC^rmR2skPJ"5+glW*iW/E4#ԣU~fUDĹJ1/!/s7k(hN8od$yq19@-HGS"Fjؠ6C3&W51BaQaRU/{* =@dh$1Tۗnc+cA	Zɀ@Qcal2>Km' CHMĬfBX,Ype
U*Ҕz
miO1nE.hx!aC
XTVR%|IHP5"bN=r/_R_%҄uzҘ52ġP)F7SqF{nia@Ds;}9⬥?źR{Tk;޵ǜU\NZQ-^s7f0S3A_n`W7Ppi!g/_pZ-=ץ~WZ#/4 KF ` z0|	Dѵ  &däIÏ;M{'ommI!wi9|H:ۧ{~qO, L]&J09/9&Y蓰{;'3`e @vHyDZ$ 3Dx28W Cx5xwB`$C$'ElyhԀDJ
$(pQAA܉A@'$hp0V0 `se$4$"t2=f4A{Tk0|rH`L&sh]A<`R'!1N;_t3# V*veF`E O${)W=p:F`22ړC^.ćG<<?~z>.pNe2ִ+Ysl:˼ܫu5tu^86ȄTmyQ%u~%~1rҘawߚ^_ZZa0!N`.uqYB\ᨀ[e:@J'Eہ,3ubj@pfeW9(	ޅ=lG7gj SM609OˑlBa݁<Bՙ(VRApf^+g9qMt]تpEr@]@VkV
ud^X R@?EY2]#Ǽ4JK'dPC|mmn#$+48u'e&[n[L%{BCDL:^!bƙ:&g3-3ubiLZڂWFSId6.k5Pl77UzT:NN.")['|U"AIvwptdk9嫫9 nDmq7I|6Kbc]MBABȪ _JTq  6@Fhd`GT:M7'L,IhFP	~j $¡ 3hA -S^چ-%qe~Qqln"i&Qe?FlK"As(3Y;"Let'Rz<MW!S3$rZ:b-^Ǆ/$QqJB'WdGAO`.(	o3B0ɑ1p((*o^ǪkJ`v[C|9=#AQ# 7;.]L:ϸcdiEsr6?}e@H- bƖC1;. v.ɾ$`T JW%BZI04^:kU,C^WVF`Fb(OO2<@Xu g~ɑW t&1\1L:φ"!P3/^ǰqw`IAD
)qCfO 02Y293Nfp\ Cah&6p`ځzgB
hRf ];]#pw_t(pq꿏ٷ,bdkRBT?22cFy2%Cn909E&#lT__Sлg)eh/ڷ+#:FGotk5Gbr;Cb˴:#ɜ	&  QCwmxlNqP)͐3f-v5Kh0AכjnSp	^HGFf H	 "%[ѻ @ p aα $$͂*_\@>M10{=)K%$C
9M4c	EotjVGD)l8,\w! %$3t		TBzҴ	iUJ[xgdBr$!eq"J>	)\~3(^R8#>bHG'7_fӫcκtD oAA߃(qB<``VΫ֘*buP4v@+.Qԥ$V@C0
RܐP[z:XH#es>?EWO>@I$|si
ES)0A?9ab,@K̩o&Q%ϞLu+
+H|Ɛ?NK4CnPt'OT.j5Ĵ8vw֜I&+`yScaO[#gQd[KI矗`ČLP	# )27aTi@c\ސ0nCpߖ運4͵x*RzYbT[\kUvHʈqp঄IIŗ)bB	XPNtz	2I== ;}bqjiކa#"	>11Ap1POOuxQ
Fϲ(h݄O'MDxLK$ȵh& 14SirHJPt DM;rM+
*ؗ5u2$f3K <PLrcI)^da>
%ѳb(@,2f,~"7R;E;HX(42Z' Tۿ2J+^!#oY~4-׃GW*!A0&8f{`W=DP8'= R g}iP>#4EBRY^4eN8V,[BĨD#X],LBsNC>+o^x
jC.4Ya_{eA2=r+ 9POA!!
}YPJeGn%x1/}RgHa^3- 5
|qSaWK{1al`I1Qf_yyCZ)L3X]W6@DMT<.uGK8DsбWr\7Z\V"ISd>CUjeD	3MtWcPӉ6#3QnቩJ\7#磱`؀K lV6&T	~l. <BP
*!zRZeљٷT#CLHW)DpYU#51{WJ4^f̼Zy6ӑT2d4H=BҊ}&݃,aPçv+:2~*0dɓփd	!"A+r HnsAڗUbHN6$.l};@iK \҂:vQE :,|Q Y0|%@ ܁qcdqh諹vCGV-(m1q89KFä
"2}Rrz,j^q\ݖ#p+`fl:kt5EOaIJP@psEj14;6/aH.ӰT XpLL8Fܚil1Y؊8%!/{霋Xb NxpPWcI9g*%:LuCAO%/œ(Y^?&I'uh[xQ$zҵŽ	߳(=V׀mU)lΠΒid㦈~fjGR{D%>@61`! ` wYk/a0A¹ԁYhdxk:f<WL4`8IYMBSlc-E҂'ڌ:,DƩ84)~2jǠiB(L|"a4,b8ԓi 94jWщ6*Tc4g̓UMbRE C5)jȴ 16pbƎHFxģ%4QCʈ	$9:M>Eao̟^<Iw Ygq7s[	-y1ع5aMKאRBYFq}8*Nt'.YbZvK
(]&ɜ(ՙ2:0oΏхPKiBH4UX,[$
0mXش f50VR8%ާDtUs`-BPzPsvI8z-t1DiB
"˶YTJ	.?07jLN[2tĮ̎ #6?E׻:ɞY;A&qSIR)ss
9*x0Bj)mHAhyЏhMm&4Ŋ4gV&tYOCS0Yd7MvNj)wA(o"͢[
E`7ezď-Q]6+Bca@^I:һ=sSnc	6OB4LGpBq/<zAC A~x06rihhIطON,:ok/{H,zЂgfȻz΀5FTrn/t``l*H6jTtG/x@P@(Ipe!`wv,:A쑜N 4}09zqC$r M`YQM䕫(|B!>>O	pwj A*@JC[h&3B Qbϩ8:%f~v/lS00a"<TX@&Jg3ϕHFoI8{:YTb(Pj<za{wXoa04 3lGȶN0>B8(f	uGoǚgyt_y~͔
%mL
!I$X<T+3dq
DMt2|fEV([]NdbD3Sp'RGmK<Tٰ }5iܷʹp#&jFZ'2%y9Q#2H]wA}vf%XӚ)X_S0t(-ⰓjHpӖv/詵,9w<`E
FagAٓЉt)le
;$9{C ()?pIFb3l[):drr]?Ֆ?BdiD7hJ:
U%n3aƬJ.>t0~ePz]UgН=_?.j#+`li	BM5 őGp7a
֒%Y[UG9@\bDY{{ED0
$Q+FvC`ݨ3Q	E\uC9![$l6DoDgG*+X!%#Cq?8ZUB)U@opgީZq89|uccAќW;@">Ph_9}.6V/O:3}ZS{:~ykcO6;OB=bV.	Rk
o^GV= }oI"+
]wFzϷ`<30h3]Rf859s`KM8
XUq<\ZOssM&j&	.%PBL~^Gˈ3pD:Z<\ǠiW̆"(:zX~0PG]8RQMNT qfW~!0R%Ց0xvGFy/F-wu/*+	\8@6c<L;c[ºnr	QS'oQuT{qҐ_ͿSdA*ð:m8Yuz2PBHh`lkpLLh
cEb6eۏ ҋ ?!>|*=VK@rx0G`%ryr[6Y37f**n%9df11ޢځ^']Rq. ,^%le#wWs56!=!q[ %Ԯ]5^:m5)?Vb|u7fw,:YeR%
[o gFAzFPx{dxíw8ٔ{{L> d2C LL,L,(mS$=|%֝lu&	ą83
NXx\VnJ[)Iw/鹻|GźYDH*Sp60cJ2@W%Ѧc_^$#*:G6n>D;~`9hXB UJB_вˈ%w'$v|#T<68KMϑ-5U+'B
ĪNbJOv'|+*Mk(d}C˱@q&aR%}
!VЃs3w2a2awHz/Q0F ]~;ä NDP
mK3xke_S!V&=v_PL9؃Yi
NU_)J69f*S	 1 7F|BR$y,Ʊ.&=uqsODBR=ɳeؽɇBH
2lu'h7^#S)Xi2..P e/@FK$](%|2Y1pC8tI11N//+\pjd WmI=߽YZxMЉP81/JG^U	,Pd1O^ypql2h$jvI%]V
. '[+WU8[D,߻-=[O

wE)3J&dقݶR¡S\. 5J$I&oHȳ~ lz>
Ux/Hu;?Gt{?;TH L|F8}{p:2t͆<LCA`ʘÇ득+'	oR0D?AClIZ1F?j᧴{^ EdGIT&#eJ}ɣ_m iA3K["oCTJEߞ4c$jݍbYnathY `YGei(a#psWi-1b,ʎTcmbhv9jh3t4@zKꙆfjĖ\$5P!hR$P
Mњ`CC^%2]uOsLTxpY!UƜ{' yL +lJ8 )@w$F5t4$,34aT&݄Ui+-಑-,{!/\ς'&S 0xkY0I)'~ ꫕j#m!-TQ`==KR,.isgI&jf-I(~o,i傌t&\`͞ҕ,YGܑuI(~[!2=h&I{8~4
j(*aATR?b0IKP
M^cYf3-Jcr;ruGuAT1?Q8Dpyy+c@6![ofZp ɲ`$Q!O 4|qiL^_ǀM+ƾQb#7ՃX5=qQ!im~uݢ	r(48zrY;*1yNk$9jip+q]giffԥ׾׻>aѧp65Y"LD.rVS_k]n&Hz~9æ
p$4ق'{&M\ΰч!qi (.h'BT|{I6cL.빍iI꫿\!;g`1j%C o3*60E؎]t.-%0YK_nft] *VFCtJT+\WZ8gF^
ޞf 5I=#6.@2z;W`B/ęQghjyJNAX3, K66ڲM0T@O{4kj|"ftџۄU<-a5b)^R8:ilKa6@!]buvΏ$	oU~:.Lte JξP
l$S[z~Rq39钺9Q/m"%ʤ7	5MKL鑧"IߏG	XTގXLFݧVjp^/Mgۻ{w
*9Oʈ<"aAq.M 2@mp^'wߕmkxO8$[&|YZy`2_|%r/J?QṈl3ÞKE$wvCha@U1M%0?1*$GZ{!|ʿ$ە-٪Ev;͓:`Bl˸쌧ɬoQ0&,F?^s,ch˕$Ecl0w`⏺ň@/r^l8cT3k@JݔuP&ʪNdJjTKi	*uX{tj~ɡ}i\BKenȵ|Nu#]@lCZ$iPa㸩t04y20s֪,Au!QBϖ^@Vsɑ\Za7쾉ш6-TrUu~1HJ(<αbRԖqiJ?eG *jVħ":Y);-Fd!HG~ux	cb6m)&;0dU?8X~12ۼtI x5{(z
'[ŃkZЅi,b1̇`(mHNeK/
[(#QGduT^m%!(7KgP=hϕkɐU+.[eC"GDΨ<*<h)` AU@O]hlf2!HF# QB=uȾ9fh;"R K3-(G	)PT],7ec
	F4hHs73ᖟ`RTwfͳ;6B>Ř9&܂?)\<&Ŏ5	LJu@Y,냲ھ_w0^17p޻*>D8_)$UźR!jOF>{t,-bP,m`D"/zA͔إQZG&U]xejxLwv~=)@B6?!;53/ps@tOZS7ؙnlxZ?Zja{6L412Qi&֥l]o=7ļ	ofЖrMEV@H/aD٦HlK5)Z	OE3IG'г;D'zl(E$.ٜ-WR'\w+)w3꺾 @%R).~9;].g+)%ȝk҉^NW>b1z:soD
K2w[|>9vWMFu`axchիU`*ʆe]OV'6xd?H]_rA+zdFH	ʋ<ǴkUsFzaH9- gvb=L/E).x9j%B)$AB	t b.bAEZRbH(Jya9Wj0fF'Xz$DQ6q`	o	i={#4FYH@J33i~tYТhkHP17YD"pĦ;'16fpu>FoDQin̒-@P# hj ނŀfC 7°T5HVXpklĭ]yXr)?ͺBNJB#9e &&_0=pZ6h)̗a b=(p);.N,W^*hԺCm}E7 i6aIvͲxp*Ac#4N&`)ĉHWey7jl oEh_n3 	jp?4p2WE'kT_&!ȖjVlHӻ_kɚʳaY s@[G"bYLܫXiCq8&zVaY{#I@2m!d[1	AƢnKeם/>dmuX:xʷ\pNl+H+ctSǶC[~3e}6 \,Ʉ|Yݧv]'|&M2 d dsx-((76aXm=ӊQ<$ Q\
qiH阇i'i$"{S*VwF/t<Q`ʒZ+pr)(.j鸫Ik5	<ʆˮ, kODTJ&^7ĪQve
&Z^4^sD+`WHb6 LW{ZZ @mqvɷ(D\+l0*V߇VmhƏ/S`|^\<-62N3"Tolre!H2pA ֛{ȼ/ udU2*2"c"p${y,饋&\m&`|x pCw#W9DIiіCKs燝S3,M;jB4P2if ɿbA]aid"i!aQhCNOY
xF$g9Z`WVBg#j\˂eG[.]0~X{2D?"3Bj,K~ b#0ɒLkc(6 
aE7λ/Վ%   ġR^JCϏZ+71XUO,}#-e٤43łt8Z7i<:i?FtFkCW'f0i<Xdj0W#ieC
zI7Bs.K  *VdDlj@%
܈Zsﮐsh̸%^
@8?N8gGgrXSAp4z*4,ít4GndS>fQCWUZ{S;Nx}H&* 9׸qU1 a`(M-aG}n̽0	pmcnɘ_\l}	 9FvHþkJZNO mZQҤ	aSf
)QC+2
d[	H"t*c*bڢq,#S#u'Ҭ:4asCDMF|ɸm_1L]Y\*X>tgDd@&[)8;<{8<+VG\H^aae-4sJA	\hM[\`#pD5Z97g;BWmqTXX%0 v&]E4]FIJ&S_4R0D+meY	gO+M{03v 'ͅft :;ر	Nn\ǔ^,)1laBZZ[		ZSUYh߆wS\/*?zQЋ`X4gr[CWG.Y0Q|RԃE[wy),ш$NK@c/b
-#ZIG$ƗtmH#)XwPZAD|SofTH)>M1b7ɆSuq
jK4[s	xL Ǣ]5!M!AdƧN><:ǻZ(8)e /W|b<T?% :@,-ecMP8umVg9H6}=5 AbĎ찁ΙV:_leɹ
v`0!$`GA"I;$^?Ke	O N(սYy5BwV%ju;)lFoa7xڸ4-% $ֹ/zskǘ(sh>DDŃtT7rur0Ң`ܴh55 S}4hrvalc!ZjB]xDbTxzYS6_)op>#@PS*bS\qƋxYfQ><"Y6IE r_7ҰVH! IrEL6!N q"'daqMvA%	vn<Eб;,w2pO%rXH`uI#/K;56LL.MI8q4Unrɡ"s9(@=}N)?S.r0L3m7VK HG/yQ2/WwF)d)sF7|vQ̴AIz`\䄛<>.;A/2ʲa8D$GWv#̏9k'o؟o@	(]gk+}/	(nqK(fƟиp23Yw pDdGq2$}KӯA"E&Ntg'Nes!Ю4qo}쿝S,ojr/sTMT&Qf\12h'&ctN'Tx7]2 ;G	ʅ|T++:%/ 1Tˀ<4͔˗	,0~!WO' :suҦن(^ﮎ)7 fmlҹ1ūtZhL06X"J҂
49 ֩B}ԭ``Ӓ	#Jn_F H|$OK=œi17o-Hqp[ɫ%%:Ɉi3۠G C LL4S:dBj|pYSDP>pv 5KLe{t0yEND$*;z5NBIgn.N|׶nRaSZJcH mXek;_6,yb0#ZAe|wGU1lLD7ÄVqt[xuEQULPBlZSh.1Q0Uٱ8Rip;{H#GON!?t>Q	|pkq!gT,j2sǍ4툊tjnƛ/IOE!ˋnF4M&1x$ew+vS
bm]e%8P
!s_06)Q2JB[t9'Ԝ,[f Æג]BB@r&Bs|QgOC1J D<Uμ(o!hKH 0qAV'pfy"Q
O2Zq#d"@bQ,w)P\b`x O)ޢdMC$[HoWަva4{Ǳ`525;Xao K;6%R(хx982rDc@وF<d(AN#FIzmEF=ƚSf
48<'j-'ǘ<Tb2vEtq3qODd_{`/hh`9_1hAY|/޷U-͕Ao("$r؆TPR;.-w>&LJiC`A^#X8tH?daĖTSTaH0@U)^e}Jb7%ܔ%:ƿ@ M+ysq LY00ÔGD	>ĩAW2I:F	32<k}[{*"Az0:@1A:ܤhXC񓓣98EUeu)[?mt-5r~JݪV2li)՞<ҳ?(D;)o  (XII$$)'i(*_E	K*4CkwkOIFfQ$8γ;(0+.99u$0t170fȦǒaO=T,m;n ˸Χc<90<_=g QV&B܀%f3`5F ݶ~`6d.2`?]}O0^AKN\Q(I	{p[Ꜫ4$6xP& :' 7u	&Rd'ʹ#{*WlDQ̎.*ZEc7|4Ղor\*
HX'#k?WRmP x$ٓ] ׄFK ~4;[Ҋh2Aɉf<Pdg)!b#Z?0o[EhX$SؾeN$=8Ш"^	VcFDxRXCX.:Fq,1)bB1+Q)_OyE	
nTp }1`#
ףd-֥#Oℚt:5Ћ/<b0'moqIBFW.\kc5ߦ-vT[͂ -4:dݗu[	8:P금BTUQ,F24lEO?Dk{1k6)R̘GI6Yp^U!A@{xg#^/	ETzĒʻ@:F'\Q6t,pT!i
N!dGB^
$@yn_uUCK_K62B|
^TmrLDgʿf)!-och}@o[rE] /iWJ8OgbӁFe(/EΠyOLB]IkTډabV

	2ց%bjg'2-6DJZe'	oBi2+]x;SP{{Jumf^L
S0~o-SEc*vl  pOm@ v	-SD;<UCYnA)pxO@iL7E`K\J`9U$	p'Տ3v+ n%lS}ANj0*׳48i%8P5c#T$F?$L~IQN_MC
TnL`)e|Ȑ!dܑ[sD\VogFG(1 OJB JFR%p3NP CS@pM vA f,- +HFt,wfA )y^Ƹ}N+s8Z$jNFi#lhP!9ge]ihfv'l!ynO]3 iяF	Pkc\
`@92zX;]۩i%[5p8Q cd\Lo;jP/ng[qBQP;,Ve3Pr'ط4Y 8[%c
^`	PjL>ʠq:6S]K"g[	ϑHB5VEqLJX{CB!PIq9Llxʪ7>֤]@!@9H!pə$	?)܎l/"́+@`}}:\	8zQgS+򒤿C}R:HUF\Xg/AZ%c1wlET wXZNhyf2D ø&vLq47z\iJyJ-kN3	-sJ5)V0N0d\ӛd0d-E[mf\UmxCR<(`ѕp4^!hQ `!l ~ƙ:JɠlW9˸ZXB=l)`jeVJUG!s1?Ƽ3Ê.}bIa6ʕt?SxZJ'p
i,.R2T`5 -R
BxrWHJPe#Bb|-[PEh(5Sfr/]IƊdE#OS39ӻ]eۮɹ.9_beM9b#e(- 0Ra9"U,%~X܀z۽{'6[@t[W%*.d'vR {h!AedCE}x=E[|B$7J* B- ,=k7[_-IJ5e̶{(	;WMw`~pAz 8f))(@	Īم<.a%N n@bz>%T*?lgbd<ĵw9Na8;<^*%y:tDҕZ<@0q4l\1 `/$IJ ғsN);:A;)$ו
Wwy%KrIv\bV\nd{6tv/~ *O
7U>8rAC<jE-j牷xs)D1Ì/qp**̸$ّ,Bȼpk	MhpK7U]h&-$鎻Y;q6wzW˄֭AhD^R"s5 fw+Q&/9ȂwNbz{Y>
]NEc,ߞ#BF:0/-EȾ׃F\I{tAZCORuki)ytkdN&vAP{P'>xƆ`.%,;:Կ:aFoTQ}v#ףQk's~z5hMQʒY>Cʍ iUNF#J0uC8k!
fv{E/IKIE>pyde	
ʾ=z:@7J|5g8x3O
3H1؄F.yfzWIMj[.w%i?҆Uf|}@+[8k7CxSEOޯp$Q+:<]K3T-y[Nz;y-HZY^.M *'h8A.N2rLB7:Or}CS˚S9Jq#WI}*8D!#	g#Y>8`
В?a2H,^'?^nhOƒi<Ya2+6aFa<!02]c:eKXX[UgOu5iyPcVT5RIA6OԸiC\QZMDƃB!X:\!^"{E Vax$P	\$DBBTFt~{O w 5a#`= gЁY2>MG-Gkè1TbL
`*ـVX
*xe§֊Z*c`VSbJU*6TK@zqPhg*ߔU(QU49L
cM*TR!R,BȅE*C|TzpF@4*텰جXbL. T2 y` Upb 
  T , %@` # ?@ t GLŞ S)ÿztϲFy׎   14 Lh   f  e(.)pK@\ Xe@ TbvhD&0-IbD	d@ ZD1@ Dyѧ CN|94Ӛ#Ncl;,`cX@(2$0"@-	 $B@ <$ А8p7Cb(@
PA@ F 0  tGORĲITySMW52\ToRKV0Ȏ(
-$!6wHGO  r~e~/]V~/P~7SzKFv`;`9v#
JBN,ӭ'  `  '`\LTApBs)r!
(
i`wOF2     Fl     \  F	 M                    ?FFTM ` r
$e6$t0  "Q?webfe5옏@?
 t,3+2qFYO&>bm5ZH$Y{H	jdՉ%٧y"+@]e{vNc)n?~?萤h _&iѝ?>^K v-cۍ12Ky,'n (3EwiB&Tlh0M҆dYrﲬnti]yurVXsjgMnәHW r2>iT`V7R(+o6'cB4ι㿚T	]a[Qd<3wq8,rTI80>E?*E痦#7'S	ocʷ_7&#*+)+4aA6cy٣f(bF$;{ YA1vP-tG"Cf- WԙuKְK#*K< (Z`٫[%YT{%Ɋ$s{oջvt"p4`ߩϤ}o`'ne>
G5s z_N
PKӦvmUɾ{z"3`lW#Ԑ^@+,ckoAOpnuzzJ)Υ1}O=xR`J`qUs/+kv1xljlEl\nDƶVjg{Zdz75!xm5o[u&1ڂHBkAqrR(\gh7Ҋy=HZUPh$8RgzgͭN: 1u$܅>R]"f7K^'3+E/^YU5]NB.ʋ8+͏8,|{M|Aua|a˅՝% 
lKGP,Nukc8mX@d̘?Y&{?P(G]Or-\LF9,&y8r3ܟ?p>~sDz1?\U5q=tzԒ&Znj%mM"}tkDwh-=mB76&:һqt"1:Еu;"K_/Jdc0l0'^B8VCzg[ ;d
Ybȃuu;@*}y|.'C>\g=9VŐ[o|g^>d
9
*E|A*M[[*mOQz?Pn?R)YoT&[U*5SMB[
oYDh{,}1<f&6h'ʥU#VED"TީAD9eB:%O Fun 7?%RG4"fgF꺁 a=-Qy+B,2օ5𙄌xnΪf*!l|GXQ ރUp
Eu @-Do.6YZ-&a>f? NN	]O/^;\JBEsJrĚ'g/B%o Cn7:|yKt&$s|wP\i]$Z@+Հ90x]r%+RUEm+ܰ;wu9/I77զQlu\yWN)8ܰvY*umm(	fEG8j#IRz#q߷	)Y$Лc_%m-{!0-`;公hyV]Hv!	ta\K[1{"j 6@3T0%Θ"ԙZIGS.ΣpӬS1eٓ؛Yv8d\BlSR)ӆ{Iӆ%>0Ўڦ\'cg2%4QD
0͒3B"MՎ&ۊhIڧRgMEI(5UD]}b8$8>X h"l΀j.%ۀHH-Iݸ#1C4Y7YݖVo>P]6O47f~ AJdYF.oy)	8l22e1H[t@!ȅ2\@5ٓ%Zkޒa@.`n3OFR(󅥶ZkLkF HWjYI5*6eSbk.5F,.N0ԙ|V||~N(	 4],Jp|~xeA5/ڻSvy?'_v|rXHQēB@=XB94TBBcHP+_YH#$`FB;+BPR4̼ t:t"ZEJ^!XǓq4_dTW(5܀IUŇAz@U6n.WGXHRK&'swMjʎ<3)`#F@F Ԣvob$x+u&}|X&[٪8F-E&/>/G.az^/})'x$O=<zoA9M؝&~3r3g'8ң\-MDzk5A
G9|1-! 87[,mRu|57
=X,aJ^tN4\fЄ]AzH^7F&k"LU>}>rBX(ۂT%JdhKPKTFaA3HHC[r;ad54lLkjG{8h~fR@9wB0zS'a7@@Nƹlbj3hNXF/es'DsQ<k^׼ZASOidSJxN4DK!	!٫vhA`EX -P:ѤC:WzSsdO:_`:taηБسIY4# *+<q no u
Ucwwx$dƿ}ρ949p*T:%GQ^a'ebl-*XL%*ź.ڊ\@pR$T*Khpm-/oS3Eto}жVoeJ`<$t	]g*Z6ql~E
S/iTtkǮWþ=?j GUUAJ`bˑGQAϫÖcWWSmgF&^ؘԡ6;C1:=ۈP`ڜVVE5"hOX~N3_5Ӂ]z-CWtԥӈe]\Vc#m[kuޗ_ʱ"sH<}xm0bxHqba3tfMT*]I
}(,M=	@JAd?§6PV[dVv4jߛlH\{MȘ\Y܁`9M`Db<;a#z<x",dgCi`c:I>jw}Jz^:V.:ڋ{ͼ(ȲBɦx<Db#"S{PHuN/{r6;wUsPО<XYsMxu\b s$x(/^|^*0j~m;#%JM4pQM׬::b\C2gf]zP8T UQbtCT>
p8+6g_2lΡ6H  ǆH:d<C6ؤ/6E:K"`kJ<Ƣ=v7N5`Jt\j6ͅ%˞7*'U4:X+\b E
afx}1+pB063rA$N~#d}פP7hH7bF§8P>BtGNmx@j	|{s9=wR/oDJs5z>;'xEq^r^=G?9AA_K%Dɮ:uikjkIeG՝#*)jm|t}`JZ؈H=4{g߁)qXMA,H71V"o,Y#hݨS_;a_ԗZ^cn4HE?}
ȝ٤=}BWvުUeh GF;@2S@f n2#fY:]JyH]-G׌wgv'|0e
_7Ґn+fٸY<(
?y%wm+j&&!c^u'b&hm6¤*2?AIƲ5FWؙ[ƜBUzIE!m:xheǮnz|]%mrUFگ1};!n F&gP;&$$F).tBQ3(C=Xes;iي@~NΡE	SRh\BeobTnΒju	g@'qQ딎nx.u6bVU&];!C_5*zɺmRQuqPZ0}mn^nOrT:U'h0nZp^R|DF_b\@mDE8 {oGM᠜q}Sd C,iܚE/Ë[d8],MCI_u,]Vc"pg@`"y),;B^el2'.(Ęy>-|hw;jՍiԽ_o|!@)ɢ=̌SPz*!z})|ƧT}jEtCZný*՞4ۆ׽[9Юݓz`Wmeo|j8j59@.EV/ZW@|f_\"${v/;a:Sei3TG*]ơ/h2C32$1}DNXt?Fϝ~n,Pj9.>ף{
9EN-v|3hCиE XT;P$=J-gݕigz~q(A<:h193N̽Q}CLWߧ׎~b"|4u}cy62[ \d,ҎճbkD%0Tx{=;Է(iLS13Nh/6?'E^~P{sZZKĞB{Dt&z)Uoa5Q3ȗr~
F]$<tm(}MB@[GxFh8 #},#uLaz(Qh4%xm`Uչ.Ev1a4_'/[d{FxI59D<&8VEFg芘#I䟍2S_]QqAn_Q>bޘ4g-0&E#ci8	vR/4rP7KsOWN3ՏvE\bqQ5ZڽVy5]h/	i)-/kNю#e)"P	{KSQx>a&<a,릌HEH]%,eDU~Wlڛ;cᘓ`? pMl.PW7٣./W#;Wd*:z;E2j9yASS8u;fY8m KѯԄԶ͡>,_g-mc<n]Ч-52cz7d PzVOPvfRRఓ9Z-dC`,at=k?v4#PBإ/[s.<a0e{&va~e8)fnyfBPLuIyH=S2"[(¼O@z*I@0#, I$QycўFaߞv"|Rܘ	'WFx?+aNMK`D/nf:XI8:H	IRm]K6i @UH*NoF;ᇏ"Wqd\Ѝ*C=#26x7<T
7yrU>-bH)ɺz '}׶w!rXZ	.:Vn;->:
6rUcs4kVW{#5ߑ0B`ܝ0u".QdB0Cr]#Q9lqN^ֳh~NU\ 16
~SnTl\THҲڛ-~G~)$oQ7-C}q%/avO|[q4~Bc-$N7<VHEi-RFGNM{"349[j<Wӭhln QҨډGcq@w/e qg<: a钷u_P`b{EI(OWGfEyABa_;O^DQ's`D#њi:Ѵ+Y{{p&\RagϞ0gTLi<'7?X1C
an0or1/Uo/?♯a_pHֱG촠8ݣ?3F0`%ϑ<
G]Խ8bl͏%-,)}%J:YjT;Ыȶ5Œ>6w{V餃.&(o*n<n9J
"aД+a/;7zDZη{tM	Mp	iؚkNPwؑͺH`T$23f0z;"]*Y,QWlSOrW$5]KVٻBܚIk|=&[58ER0ދGksSnnnuExKr}~m`G4u{=]6f ר
Bo&<ñc;2P$ǃ{mW_cª'B6Њ?$^z[CYݭjN~ۮ0t6/)-1:p$Dꥅȗ

,'yv nFTс['aMbJ]%&îlc6&IpFoi5'rr(qz6(5Eɢ՟l\Lk71Y4^)bٗ¦8yƏ
N=9zT^[T$dkQiK%6qfO|c8$ji^vr.QQR"YrĊkrK<QI"@R9/\&7Y}mgҊ7z6-Mu=,N3O\6aDAޮLd^r/.>
NeRi4!3R"4nbm-y[X."!QKE\N4gՠםaNp>k)90BZBs
yrer)vDtrv\v[>rJm
a̼~uՏ>rMZcB<`)\yt|ۍr'<>[Îh7Z8caI!p⢟̮ ,Gk5@`iwnО8pv *'O
A[.rhTpR?+;\*HsLqUf:ql-ć*6!h+ˬ {h- jgkMMP#:}{/VŶC]옙&[W$ګ^#4fWa\5躺M[6)T3~
:. Z`si(RQ|/`
il^L#f-;-C;_*{@EMCooÂ_7TrqzF%ׯ|U<Zo[TA='DPJ];,U9Qpk4~_C^qEŮbSGsY2NAu%SD hj	
y;9$ߴIAhEO}
g/+ Ճ5JY @Gf2Y/߼e߷|v/"p~刋T8OKr**4hi@Q3g"j:$;:f,dzȚԌ꺳u%ˣ}O&i2U,@kj%u?4NKmd?5ݓ;0Ye}sZ>EƫUs^ݜv{fQ<ĐVPTfͦ?mpP* &QG{cJEPe2)xP0AMɪZHj"׻"AC+zqmVzᖞU%C :@1W[y)J@ob%jA>)Nǀi$At`>?f0g H36p6D|M4N
 4JJڃ
jƇ\p38Я6pV?:$sDNƹ2n,HO\[ոK-)W~im?T:޺UeY-#dJe)Z5?$\dW<,Ɇ;ط5SոTT̄f(PYv=Q~DX*8辩s-	˨΀55XRl QCl|5{ӦT\t꼕+en۸Psl3UO[ZS3*,:ÛZLS'̵**@ı~xgno2-
 WV ;pZ9?~$6<QrbQ8&seEbQ,^|B碘VdV-(] .ˎ8/qhVnRQD*U(*1h1`؝QL{Uj`"o3 ܻVl:	jaFaE̞Zg1z2֠:AuZIf62tw+fDCL-}gZ0>҄xJ>\QA_Cihbl]64*A˯ɰqX7YX.-ոaɇVhiKgqNRĆN(r']%٘@3̀jZJ.;nm,S0xͻOF33ҧ<$'GE+}'1f3y5/&Z\RB7dm]8\3߂Ȫ@oT3eu^W@e7l!B,s1$Z&?dC (YЦSm>J"&pt܈P㇄BF4G5	t^Ć$j-a㠍g^ʐCAsT=kTS,|r9IBϘЬ'vG A@thQNj&T=xt;2]P|T-	LÞe1ݽWZŚ*MrH5?= o"9K5='k-*AE|	  qҔ_?\7%|M6f++S*}W _]3fmܮ˳m w!.R#鬪;qq71$ݙկ_iK&JάMemV5P0> Q5WHIh&4ҍIlE7}sm[cȾ|d^	%Uv1D>.T7*=tZ_㟾1Х:=0pZ6ҋNt (uƝ; B]$kڌ.{F*/UZN砦|oqKG;^侞9NexK\wh~ZpHb䉸[k8k.bX.QXpxYa^"#Bwnbum5F~>8bN:p4[gv^
BFUz)?60F8 /2C8>N8G%l%5FH{46h4%#7xoN t\'Ȩ E0#jNãVӹd?WlcW
žֵu-}22EN}#䵵2H^a3rqs-S3&f퇣fwl.=W8,cHjcTWנs90ZDMC2ZMdjt"8:g{.Ʊ1Fb618"yԦ>W9 V`jT򔔑<IMԱW'%f&\yZdkʹRyjw}Ѐ[8ԍbB 'd'mo'<|E5:ڋo>r,ni<TS>d qN.g+ SQ	KaB?_QE rjh>Eӛ;C׭7^q
`Ue#-;oJċԝ>);Jg׭9R;OgiI7}8Kہqjeؓ+ٗ'nϷk3eFρ0V#pMAzb^PVu~1uғwn	^.II_vdW[Q,+Lbćq9V}	ΏVw4qU3&jıHYb ttT7ρarBwP9?)uT/aA19kM
\Ps<Ta@<?M(.,'%?,%a~eU0/zQ(Ѹap:.6jdF@\V4{Ri8ɪnuFM_=Z8Hlsy5k%|(i9"6}ԋ~WK۟hYk\lRm&0b]g"ހD^ތjJ*)6-Ybh
Z=ޑA,(K#	OfJ:;I!6Yi&d%m86#QW_Av}?+G	cc*mg`>q+=[5͔?9W+^o^E8s)f2aQxi&	NE>"^Naa;f9]NE&	t^CLz'e8ZRs&67_ ãcyJ1@TZ?S D2
|POӌ\dR7zH9i Q#zrc.4GR4qx<2~Xhnੳ2auBNC +kX0aj5n>މe3vާ<>_uH:XR%~9!4oѼ 38? 1d#A&{A!i6/Xa㇤=W;|) g~?*悽 }ڧKt>5|E.AQ6(6

6є7 <9_Cf1Ўi8,V4$uti,.`v6r	PgFBɎ
tC3;,oÂx|	
/KMp1S_X.fV#U>Ȓ#B]AIVoІϵGTV1nr+OXS%³fOZ[_9P߰ {Gln%#hdwH= ye/W>,IP,*MV~ºK&eċM콣=)qFS"GTF*LX,h[wweWQEx?{^چExhiׂJH|^͓e*^Я.uxEb#;ԝ<]z]\wNhochqE=4Q17W̓lÕ6᧿HE_̣qyYR۫<x=cSXy!=08Ǘx?{}F_Ǡzktɱ7ڂ|t+am<xe$eɍ<[TX[ sV̋ާU*hSK=Fesw uYoٯnQ=NE:[(t]k|@ٿuZ\9{hvܕӆ.ڡsa$u+qw:#?eT3=л!pPL`:R;gʮFhaΐ;5Ie+bt06AW40ThJcc<&mJcc
OCnW?Nio](XЄ{Lz;g|Ǐ>9~l4sVy`Uߛ,#_u+DeM~hq벇#Yz$;5ͯ9$ z>
*jO$$O/xRtf-}*oɦ|3M;xިUl/.~XǎY4x3&x";$KI5dڭ~w[M9O%4Q}S^t@w[Y;-s;bwH-*imI-1e/~TNN.p)H$W~ƦO
(9,]gM6r+#%/swA$q4O>
d9}+$s?0a,>yڈs<=,c_*\D}2MT8/4g'ڦ8'}"C*\9#Y>z$7c[s|"$}	ymzQx 5%o$jkp)x-:И|?ofgFr2SZq}q	o,wyOgCF1l'L5T33yM92"s5uD6-JUbs
O)wR-2/5f<BQ4kꐭG	)%߼<dĪĞ32`a]S{K%\]3&pڸCո놶,^T7h5ulDxڷL'Dr6vշfc\gA@ ?	GFVAl,:i#~NUDV~7kK`!PMXR$#Tiihom՘<.8Um<3ES4ܫV9'bv{?VV3;U'֬1RV{Bi4CRhr6~ӖJP͎M7G -,NLo<ѣz2H&|$<{ڜK_mmS)>rϛf@=BFCB &'F}@&yubC?'S49+ÓCIî+f/RUCFu:C*}T:}{ݽⲷue[!>?ڸ"M
8gz0\HkZ:h~@+#Nfjyio!B	R'5>`[!T`mCIѝ}n
>W!M}Uav43)!kcȂm?	dwv!ה;Xϡۨ}8vt"Ӽ#kvXJ[l[ZݙMÀXC3l[TaVjʻѬ"œt:(<cZveQTqHi{銀Q埓'ÖiP￭mKAIBF
=Tᅽ(&TS?/؁A:ַОV(@wFa^]o]*99Ri_2vM`Pf{QYH#V7v7Ұq>@~uɘ׆Ax/xB3Ġtyb0nG`EDٍA:PwI7nW2ED<hD&Z	Π73&)LD4;7Ѵ?$k@""L&~1ʺf14ʱ|7Os}L1;?{1$w)1}0~7#E5`q&oow_鴊8Q1GɊ08hWe+\ԉRU?weOSxAU̞3|	=WAR
PtO%Q"1Yה!so%%^z_hn,{?"L5_D6+Sb<gfJ0b_x-;HW:GMiEeIuvJ]~mQHLKkhbA>}.(h"U]9Ih_V@GZ0C
pb:L3tN*N2!3Cayn.ɋW`̳}QBCi 8*{57O#aTBUoi0_^
ChrU}~rL 1z>..=%GGo EuPPsؘ޸8Pu&;*|i&Pbțh;[|y*cVhҼ(~_AqU2GIQ3`^v=@K'ЇZ#4sJ=:sY	sڥbyjS_E܃"@~>86#y[cSŬ#SJGZyvvSя扝pwaT/,
9'Jkv%%.~o[ 衧RBjSȀ*$'腁pçSu +9\_f+8u\,tpэkخJ0h(]NQvW786:ݣWcY_i>"R(e]6RA%U6&F]7@̳k3Xh?K Q2Bk[<o-[ s~0]T2hJqKv(32J//W,zd$2cAkP	K+Ec[QiEdVxR8B5a=:KQ\@V^;Kr	M{{#Cw}{^,$0Rc\oQѼץP$Yvp>?..KKAb65ke+]F<He";{wNyx/&f檄/XZ[7c%ŀ5dY_y"Ыߞ2\37
k\띲|FO 68nKzR"?/732:а>eWHU0Oק5e3Hco>l]02cH9{Z{sO!A,7?ŷ3 w俎A
Fj8B&8U$G $Y5FL5n1>q2.6e
+@/kb{(7i={l͍݂濦81g(%h/EfMҍt 5̼vgo ~ਜ਼WKi父UأݖwRSEFT%`=|*=1*SX^w)lfQH(YSSˌK1W]f7ך^&p@T'.%35zaTf6A5LX̡|L-ηTg{A)F."hjA;.~o%G#}&]׾c`ChH9xnNY lc\+v\EƧ1D9KX)2b.NWQש$/|6tð32ԛ7 2иyu0e)Nuh'd~xY >#b"k3:9v$ПC:)H>	զz;ed\jmfOa%9cKxۥ!k%HDn{Y"{n_}
)9=_/Z(>lYVgQ#߭:Qbw$zwٮ#U?|Ghz{o$wϜ)|Vh?ZV7%Go/׆E"KӲlp76 -z!l4n>$\zV?szqejQ]m^=^!lHB4sLi9}2^K5OB)Ov^~݀xrm\K&G^5CL}&FB]Kn3|sGjykObsܽaW?R6Jfh2	lBS\=jV*Y^˺^E)*\
rr(a@6nԌ?}dLgIvqNcaƮkmLcA!hdVwc=憖s_:җsLg>1*4-%&0Ub)Eܬ*b51	++;<`!qfM*,[/GK+{,>CLR%%c~'EGAG=h䟔8:IDN)W̻AF)ucw'qhXèL@a~6Pc2L"A2bU	&9A#QLO:E9kfKFb93tL$cˬpLz5dp۰>$`.~X= ?NͰ/LPNo0p b8AR4r Jj}Ӳ04ˋquۏAFP'HfXDIVTM7Lv\(N,/ʪnڮi^m?~	QUӲ04ˋquۏ b$tV&gϖr><y?f{紷 %~ZazW2sveW     @DDDD$""""bffff}X	O0cDDDDDZ6W08BI           .HW      
߈9 u*R*J^}:M$I$IFyџ_W<G<         pFFTMm*      GDEFD       OS/2gk  8   `cmapڭ    rcvt  (     gasp      glyf}]o    headM/     6hhea
D     $hmtx `    tlocao    0maxpj       name,    post5    
webfTP  T          =    vu    vs                           Z   2                          UKWN @     {                         ,   
       h     ,  
      h @  (   +   
 / _  "#%&&'	'	)9IY`iy	)9FIYiy	!'9IY`     *     / _  "#%&&'	' 0@P`bp 0@HP`p 	!#0@P`fbߵiY!     
 |vpjdc]WQKED                                                                                                                     5              *   +                            
      /   /      _   _                       "  "     #  #     %  %     &  &     &  &     '	  '	     '  '              	   !       &     )   0  0  9   :  @  I   D  P  Y   N  `  `   X  b  i   Y  p  y   a       k       u    	   }            )     0  9     @  F     H  I     P  Y     `  i     p  y                                  	  	                   !  !     #  '     0  9     @  I     P  Y  	  `  `                 
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           (      (  h    . /< 2< 2  /< 2< 23!%3#(@ (  d dLL [  27>32+&/#"&/.=/&6?#"&'&546?>;'.?654676X&
j

j
)"&
j

j
)L
j
)"&
j

j
)"&
j
        LL #  32!2#!+"&5!"&=463!46^^L^^     p  @L E  32!2+!2++"&=!"&?>;5!"&?>;&'&6;22?69

x
}
x
}
x
}
x
v
L
ddl
   d  ;  2#4.#"!!!!32>53#"'.'#7367#73>76p<#4@9+820{dd	09B49@4#bkv$Bdpd>uhi-K0!.O2d22dJtB+"0J+ku0wd/5dW%   {  L > G  !2+!2++"&=!"&?>;5!"&?>;4632654&#^CjB00BjC 
x



x
u
x
u@--@$?2O*$$*P2@%d
d
BVT@   L   !2#!"&=46        % A  +32!546;5467.=#"&=!54&'.467>=2cQQc22cQQc2A7  7AA7  7Ad[##[[##[dd<c2<2c<<c2<2c<d               1  ,A   2632#!"&5467&546n,,.xxOqUBAwaxyrPEk      d     32!546;'&>76!' 	
Pԇ
	 $
op	zy#%**%$	p       dL   # 7  !2"'&6&546	6'&4#!"&7622?62~




\l

lL
7

&




l    	     2'7'	&c_"fn&\`tfjpO          32!546;!22&&     L   %6.676.67646p'0SFO$WOHBXAO$WOHB"7Q)mr	*`)nq&*    	  )   2"'#'".4>"2>4&ȶNN;)wdNNrVVVVNdy%:MNȶ[VVV  d XD   >.54>0{xuX6Cy>>xC8ZvxyDH-Sv@9yUUy9@vS-H    ^{   62!2'%&7%&63 ao  ^{  "  62!2'%&7%&63#7'7#'JJN aod⋌       &  2##!"&=467%>="&=46X|>&	f	

	f	&>|.hK

]

]

Kh.|       L   # ' + / 3 7 G K O S W  !2#!"&54635)"3!2654&33535!3535!35!"3!2654&35!3535!35~


Ud

&
sdd dd d

&
d dd dL



ddd


^
ddddddddddd


^
ddddddddd      LL   / ?  !2#!"&546)2#!"&546!2#!"&546)2#!"&5462pmppmpLpppp  	    LL   / ? O _ o    32+"&=46!32+"&=46!32+"&=4632+"&=46!32+"&=46!32+"&=4632+"&=46!32+"&=46!32+"&=462Lpp     L   / ? O _  32+"&=46)2#!"&=4632+"&=46)2#!"&=4632+"&=46)2#!"&=462DDDLpp     & ,    	62"'&4?622;;  n nBB #  	"'	"/&47	&4?62	62;    % I   2"'#".4>"2>4&3232++"&=#"&=46;546ĳMN,mwbMMoXXXX
K

K

K

KMbyl+MMĳMXXX#
K

K

K

K
     % 5   2"'#".4>"2>4&!2#!"&=46ĳMN,mwbMMoXXXXX^


Mbyl+MMĳMXXX



        -  32+"&5465".5472>54&&dd[֛[ҧg|rr|p>ٸu֛[[u'>7xtrrtx  d     / ?  32+"&54632+"&54632+"&54632+"&=46


ޖ


ޖ


ޖ





~
p




>






       G O  27'#"/&/&'7'&/&54?6?'6776?6"264X!)&1-=+PP08,2&+!)&1-<,PP/:-1&+x~~~P09,1&+"(&1,=,QQ09-0&* !(&0-=,P~~~  d     ! % ) - 1  !2!2!5463!546!5#!"&53333333,);

;),,;)D);dddddddd;)d
KK
d);ddd);;) dDDDD       62++"&5!+"&5#"&l`





j`


w

?
  d      3!#!"&5463#"&=X;),Rp);vLp      0   2".4>"2>4&3232+"&546֛[[֛[[rrrr|2



[֛[[֛;rrr

2

^
          )#!3333))p,p,     d    /  3232"'&6;4632#!"&546;2!546&&T2



2
>p


^


      1   2".4>"2>4&3232"'&6;46֛[[֛[[rrrr|

&
[֛[[֛;rrr

        1   2".4>"2>4&%++"&5#"&762֛[[֛[[rrrr



&[֛[[֛;rrr

          9  !2#!"&'&547>!";2;26?>;26'.

W

&

&

W
tW
>



      '   2".4>"2>4&&546֛[[֛[[rrrr[֛[[֛;rrr]$    (  76#!"&?&#"2>53".4>32
mtrrr[֛[[u$
Lrrrtu֛[[֛[        5  76#!"&?&#"#4>323#"'&5463!232>ntr[u[uh
ntr$Krtu֛[u֛[v
hLr   
 d     / ? O _ o     !2#!"&546!"3!2654&32+"&=463!2#!"&=4632+"&=463!2#!"&=4632+"&=463!2#!"&=4632+"&=463!2#!"&=46}




R
2

2


>
2

2


>
2

2


>
2

2


>



~



R
d
2

2

2

2

2

2

2

2

2

2

2

2

2

2

2

2
        L  #  54&#!"#"3!2654&#!546;2uSRvd);;));;) SuvR;));;)X);  d  LL 	 7  32#462#".'.#"#"'&5>763276}2
d!C@1?*'),GUKx;(.9)-EgPL
3
0[;P$97WW       ! 1 A   2+"&54. +"&54>32+"&546!32+"&546ޣc
2

2
c*`ct

,rr

,tޣ44       G  9  %6'%&+"&546;2762"/"/&4?'&4?62A		

Xx"xx"xx"ww".


^
x"xx"ww"xx"       r  /  %6'%&+"&546;2%3"/.7654'&6?6A		


`Z	HN.


^
d		g~j       b  1 K  3#"/.7654&'&6?6%6'%&+"&546;2%3"/.7654'&6?6D@
	*o;7	*		


`Z	HN	iT	"ZG	!


^
d		g~j         	    ! % - ; ? C G K O  3#!#!#3!##5!!!!#53#533!3533##5#535#5!!#53#53#53!5!ddpddX,,ddddDdddd,D,ddddddd,dddXd,,d,,ddddddddd,dddddd    	             #  7#3#3#3#3#3!5!#53#53#53ddddddd,,dddd,Pdd[[[[[     
    	"'463&"260V
C;S;;S;V0
;;T;;       
   !  	"'463!"/	&"260V
08D;S;;S;V0
V08;;T;;     d   &  !2&54&#!"3!2#!"&54?6,9K@

D@



K|@

@

J

    L 
  !2	46 >>C          E U  !"3!26?6'.#"#!"&/.+";26=463!2;2654&!"3!26/.6DN9

>SV
N

N








&
X
&
l		l-
p				
v










       dL  ! ) 1  3232#!"&546;>35"264$2"&48]4$);;));;)	'3]dϾV<<V<L);;;));;)X);E5+ddF<V<<V     5     #  	!526/!3!567>?!(%	
_5,Ry:"	*28T2*BBW-ޑY".BB%Z     d   ' 2 ;  #!5>54.'52%32654.+32654&+50;*7Xml0);!9uc>--Ni*S>vPR}^3:R.CuN7Y3(;	G)IsC3[:+	1aJ);4ePZ     o   !56764.'&'5mSB	,J95(1(aaR@	9       % /  #4.+!52>5#"#!#3'3#72&2p"&2KK}}KK} dd	R ,১   ! % /  #4.+!52>5#"#!5!'7!5L2&2p"&2C১  vdd	 ,}KK}}KK     L   / ?  !2#!"&=46!2#!"&=46!2#!"&=46!2#!"&=462X LLdddddddd     L   / ?  !2#!"&=46!2#!"&=46!2#!"&=46!2#!"&=46DLDLLdddddddd     L   / ?  5463!2#!"&5463!2#!"&5463!2#!"&5463!2#!"&Xp Ldddddddd      L   / ?  !2#!"&=46!2#!"&=46!2#!"&=46!2#!"&=462LLLLLdddddddd     L   / ? O _ o   32+"&=46)2#!"&=4632+"&=46)2#!"&=4632+"&=46)2#!"&=4632+"&=46)2#!"&=462ddA ddA ddA ddA Ldddddddddddddddd    L   # * : J  !#;2+"&=46!2#!"&=465#535!2#!"&=46!2#!"&=46dddd,XLdddd}KdKdddd       L   # * : J  32+"&=46#3!2#!"&=463#'7!2#!"&=46!2#!"&=462ddgdd/ȧ,XLddLdddK}}dddd           !2#!"&546	K,,,,,,v,,,D,,     L     !2#!"&5467'2"&4,XJ*J%pNNpNLd>tNoOOo      6    2.'&54>"264usFE66	!^Xm)<Dsxusm?>!fhHuXyHÂ          2".4>"֛[[֛[[Ktrr[֛[[֛oVrr   u   5  .54>6?6&'.'&76#&*IOWN>%3Vp}?T|J$?LWPI)(!1		) HuwsuEG^F&:cYEvsxv!K:%A'#"
A)Y       l  * /  7>%!2!"3!26=7#!"&546	7l
l27);;));Ȼp87cs*
s;));;)2c     L  6  !#"3!2657#!"&546&'5&>75>^i4);;));ȹpS9dTX
.9I@F*L6;));;)g	0!;bA4
        L  5  !2!"3!26=7#!"&546	62"/&4?622^^<C);;));ȹpeeoL;));;)Eۥ3eeo    
 
 ;  	62+3546&=#32"'&6;5#'&47635#"&>


Ȫ



ȯ

ȭ



ȭ
	

    L   326'+"&546d0dLJJ       L #  3266''+"&5462d00dLJJJJ     3   ''&47660J*J     36   &546.2   d    32+"&546!32+"&546      dL   #!"&5463!2L         3   46&5&5460d * ;   O #  72#"&5&5&5464646dd12N:	9		>	=  ,  L   32+"&5&54646Rdd0L;;   d H    	#!"&762!2#!"&=46		*9Hdd  uJ   		u`((&    ;(J   	'	7(a#aa     3   2".4>#"#";;26=326=4&+54&֛[[֛[[}dd[֛[[֛dd           2".4>!"3!26=4&֛[[֛[[E[֛[[֛~dd     3   2".4>"'&"2?2?64/764/֛[[֛[[	xx				xx				xx				xx		[֛[[֛	xx				xx				xx				xx		     $   2".4>'&"2764/&"֛[[֛[[Tw[֛[[֛1Uw        ; K   2".4>";7>32";2>54.#";26=4&֛[[֛[[?<B2!(#"3D<:


[֛[[֛/O2*(8\6/H*	



       >   2".4>#";26=4&#";#"3!26=4&+4&֛[[֛[[





KK

^

K[֛[[֛V




2

2

2

      / _  3232++"&=.'#"&=46;>7546+"&=32+546;2>7#"&=46;.
g

g

g

g

Df

fD

Df

f
g

g

g

g
ͨ

fD

Df

fD

Df      ?   2".4>"2>4&"/"/&4?'&4?62762֛[[֛[[rrrr@||@||@||@||[֛[[֛;rrrZ@||@||@||@||        0   2".4>"2>4&"/&4?62762֛[[֛[[rrrrjjO[֛[[֛;rrr}jjO        !   2".4>"&32>54֛[[֛[[KtrAKihstr[֛[[֛;rtxiKA>rts      S   6!2#!'&4'
&F

&       S   	&5!"&=463!46
&U&U
##
      ]   	#!+"&5!"&762

&&
     ]   32!2"'&63!46&#
U&U
#
&     ]   	&5>746
^$,[~UU&U
#$DuMiqF
       +  !2/"/&4?'&6!"&546762R,^j^!^j^^j^P,^j^    I Igg  +  #!"&546762!2/"/&4?'&6j^^,^j^`j^,^^j^         /   2".4>#";2676&#";26=4&֛[[֛[[:#6#:1


[֛[[֛.



         I U a h o  276?67632;2+"!#!54&+"&=46;2654?67>;26/.'&;26!"&5)#!	&0
=

2
pp
2

=	


353


X

v	v
!{,	
2

,ԯ

2
0y





r
w
        + I  6.'&&&547>7>'.>7>&67>7>7>-BlabD8=3*U 	:1'Ra\{%&=>8\tYR-!q[Fak[)ȕX1"@&J<7_?3J5%#/D	&/q!!6ROg58<'([@1%@_U2  ] r O  .>7'&767>.'&'.'&>77>.'&>'
'8GB 

	`H >JS>H7'+"	NA
5M[`/Pg!;('2"&"IbYCe\D9$886#1%)*J7gG:  8G\au9hoK$]54<<E"5cQ8	.@AU!UhQ)     jF  ? Q   2".4>&"&5476&2>76&'&6?6&'&'.{nO9:On{{nO:9On{FZ2Z__Z2Z#		%8-#,-"F-I\b\I*I\b\I--I\b\I*I\b\I9>||;7Es1$F^D10E^E$1u$/D0"%,I       ' ; L  !#7.54>327377>76&'&%7.5476&6?'&'.P[vY,9On{R=A &/l'PjR.Mv&6QFZ*HLh5)k|#		%8-,-"xatzbI\b\I-yRU4Zrnc1?1FrEs1<QA9n;7p$/D0V,I        (  '6#!"&%!546;2!32+"&/&6Z8%%
Y

YCh:#6#:d*! GDK

K    d  (   2'%/&=47&=4674L|XkddkX>1)]@		@])1ES>       L  ' + / 3 7 ; ? C G K O S W [ _ c  3232!546;546;2!546#!"&5353353353353353533533533533535335335335335Rd22ddddddddddd|ddddddddd|ddddddddd2222pdddddddddddddddddddddddddddddd      w  % 7  &=#!"&=46;3546'#"&=463!&=#'73546oXz#z*dXzdM*z       L   !2#!#"&546d);;)d);;L;));,;)X);    d  L 	  ?  32!546!32!546".5!2>&54=(LffL(,'6B6'p)IjV\>((>\VjI),	+'%!	!%'*    L   	'L'a'    M   	7	Maa'a    Q d_  )  !232"/&6;!%+!!"&5#"&?62**p&      0  32!2#!!2+"&=!"&=#"&/#"&468^&d,!02**6%%+*2222	
*        L    !53463!2!!P;),);DPdd);;)     L    3463!2!!;),*:,P, pX);;)dD E  k   +32"/&6;#"&?62{**Y    Dk   &=!/&4?6!546X`)		)		        	   !  .#!"!"3!26=4&53353$`$-);;));;ddd-(d;)d);;)d);dddd    dL  # 1   2"&54%##"+"&'=454>;%".=4>7i**d]&/T7"LRQ)2(    J  f , 5  3232#"./.46;7>7'&6327"&)^Sz?vdjO9t\U>/v?zS$24517F8%M)(
()GM~ 1==      7'''7'7'7'77 N괴N--N괴N-N--N괴N--N괴    d ! - =  32!2+"&/#"&54?>335!7532+"&5462(<H(<,F=-7`1dd>2vddQ,}Q,d-!2$'$(ddw}        L   0 <  32#!+"&/&546;632+"&546!#35'!5X,<(<(21`7-=|dd_dd22L!-d,Qv,Q($'$dddԯ}w    dO  7 G  %6!2+#!"&5467!>;26&#!*.'&?'32+"&546dknT.TlnTj:d%8
	VOddip&yLN(%
H	YS(22S    dO  6 F  #!"&'#"&463!'&6?6*#!32!7%32+"&546njUmlT.UnJ	
%&jPddO(SNLy&pd(Y    a  L  7 G   2#!"&/&?>454&/!7%.!2#!"&=46ސNS(%
	p&y22SY(nTjknT.T8
	Vd%dd    - I  !26=4&#!""&5&/&7>3!2766=467%'^NLy&p(S22(SYLddjTnlT.TnkV	
8%d     %   2".4>%&!"3!7%64֛[[֛[[

[֛[[֛9



&      %   2".4>6=!26=4&#!54&֛[[֛[[%

[֛[[֛&



       %   2".4>&";;265326֛[[֛[[K&



[֛[[֛@

      %   2".4>#"#"276&+4&֛[[֛[[

&
[֛[[֛

          2".4>%&277>7.'.'"'&65.'6.'&767>'&>7>7&72267.'4>&'?6.'.'>72>՛\\՛\\d+:
=?1	""/?9#hu!$0E.(,3)(	 	
*!A7,8!?*

\՛\\՛	'"r"v	G
	.&*
r$> #1	
% *
	'"	$g2(	%
          67'"/&47&6PM<;+oX"O\e~Y+"n+We    `   # ' 7 ;  !2#!"&=46#3!2#!"&=46!!!2#!"&=46!!d);;));;);;));;);;));;,;)d);;)d);dd;)d);;)d);dd;)d);;)d);dd    d  L    !2#!"&46!|;**D      d   %  32!2!5#!463!54635#!"&=);,);;),;);));;)d;)pdd);d);dddD);;)         + A W  !2"/&546)2/"/&4?'&6#!"&54676276#!"&?'&4?622,^j^5,^j^/j^^^^j^j^,^j^&j^,^^^j          # ; C K   2".4>"2>4&$2"&4$2#"'"&546?&542"&4$2"&4ݟ__ݠ^^oooo--  - L-  73H3)z	-  - -  - _ݠ^^ݟWooo -!!-  -!
$33$ 1~ -  -  -  -  Z [  %676&'&#" 3276'.#"&47 7>32#"&'&6767632'."[v_"A0?! -	Y7J3$$)G"#A.,=#(wnkV8@Fv"0DG([kPHNg8B*[eb2!5(7>B3$$')M"#!7)/c#*xnfL@9NDH7!$W]B$&    d XD  D  >.54>"".#"2>767>54&0{xuX6Cy>>xC8Zvxy#!?2-*!')-?"CoA23:+1!"3)@+)?jDH-Sv@9yUUy9@vS-H-&65&&56&oM8J41<*.0(@	)*D*2Om  9w  .   2&/7'/&477"/&4?BB8"._{iBBi
	BBBBBB7._BB^*k"5._{jBBFi	BBBBBB77/_             2#!"&54>! "264d:;));<f>XV==V=.2G);;)3-D=V==V        	"/''!'&462*$3,#**#4$*    ' 	 2 @ K  #.'#5&'.'3'.54>75>4.&ER<,3'@"<P7(dW(WJ.BN0 2Uh:**&	h)1"37N,?iB$.,-<d>MOW(kVMbO/9X6FpH*M6&+	 4C4%    d f J  2#4.#"3#>36327#".'>7>'#53&'.>761T^'<;%T)-6"b "S5268 jt&'V7	0$ݦ
-$aPN(?",9J0*	d2>2
""
7Gd/9+DAL!X        32"/&6;3+##"&?62*Ȗ*,|       %  #5##!32"/&6;3353!57#5!ddd,*dc,dd|ddd        ! %  32"/&6;33!57#5!#5##!35*X,ddd,d,ddPddd    L      32"/&6;3##53#5#!35*Xdddd,d,dPdd     L      32"/&6;3#5#!35##53*d,ddd,ddd            32"/&6;3#53!5!!5!!5!*d,dpd,         32"/&6;3!5!!5!!5!#53* dpd,d,     LL    !2#!"&546!"3!2654&^pg);;));;Lp;));;));        LL   +  !2#!"&546!"3!2654&&546^pd);;));;oLp;));;));$        LL   +  !2#!"&546!"3!2654&!2"/&6^pg);;));;$Lp;));;));       LL   +  !2#!"&546!"3!2654&#!"&?62^pg);;));;p$Lp;));;));        L  5  !2#!"&=463!2654&#!"&=46&=#"&=46;546&p);;)>DLpd;));d&

     #  %2"+'&7>?!"'&76 6763	,			P''
K		
S#	nnV/       L  5  !2#!"3!2#!"&546&=#"&=46;546^>);;)pDLd;));d&

       1  !2/"/&47'&6#"3!26=7#!"&5463!m)8m);;));Ȼp,pm)8m;));;)֥       #   2".4>"2>4&2"&4ٝ]]ٝ]]qqqq{rrr]ٝ]]ٝGqqqsrrr      L   #  3232"'&6;46!2!54635
'	gdV^|d22       L   #  	++"&=#"&7>!2!54635Gz
"'gdM !d22     LK   "  	62"'&4?62!2!54635qgdq#d22     L 	  # '  762'&476#"&?'7!2!54635*MMК=gdML*Л:d22       L   # '  /'7'&6"/&4?!2!54635^WЛԛL*MgdКԚPM*MXd22      %	!	q3gq       dL    +!#"&546;!3#53LDdddp,     E   /  '&"!#"&546;!3#53"/&4?6262L_		Ȗdddj\jO)_		p,j[jO)       >  '.!#"&546;!3#53"/"/&4?'&4?62762Lg%dddFF))FF))gp,F))FF))F        /  !"!#"&546;!3#533232"/&6;546Ldddd*p,           /  '&"!#"&546;!3#53++"&=#"&?62L*ndddd*pp,    L 	    !2!546#!"&5!52LPdL&    }    - 1 ;  &=!5!546#"&=46;#5376!!/&4#5;2+p/22ddpddd33*ȖdȖ*yd     d    Q  %6+"&5.546%2+"&5.54>323<>3234>^%"%
"
d	d	1t5gD>?1)A..@^^  d  L 3  "!5265!3!52>54&/5!"!4&#5"2pKKp"2KKL8
88%v%88
x88%v%8       LL     $ ( 4  !2#5'!7!!2#!"&546!55%!5#!!'!73wipdw%,);;));;),p,ddibbd;));;));dfdd    &  767>".'.7.wfw3.1LOefx;JwF21vev/ 5Cc;J|sU@       L # A   2/.=& &=>2#!"&=46754>ud?,		1;ftpR&mm&L!(("

""""'$+ 

222/2!         '  !'3353353!2+!7#"&46!2!546LJLP*dd*22    d  L 	    #"!4&#"!4&!46;2d);,;gd);,;;)d);L;));;)D););;)      L    % )  !2#!"&546!#3!535#!#33||D|,dddL||||Dddd,ddd,     L    % )  !2#!"&546!#5##3353#33||D|dddddddddL||||Dddd,   L    #  !2#!"&546!#3!!#3!!||D|,,L||||Dddd     L      !2#!"&546!-||D|,L||||D,     L      )  !2#!"&546!!!#";32654&#||D|dDd&96))69&L||||DdVAAT,TAAV     L    % )  !2#!"&546!#3!535#!##53#53||D|,ddddL||||Dddd,dd   L     # '  !2#!"&546!3!3##5335#53||D|DdXddd,ddL||||Dpdd   L    " &  !2#!"&546!#575#5!##53#53||D|d,ddddL||||Dp2Ȗddd    	 	   %   2".4>"2>4&!!!'57!۞^^۞^^qqqql,dd,^۞^^۞Lqqqddd     	 	   ' +   2".4>"2>4&#'##!35۞^^۞^^qqqql2dddd,^۞^^۞Lqqqd2d2ddddd  A   6  2632+54&#!"#"&5467&54>3232"/&6;46n,,.xxPpVAbz

&
AwasOEkdb

    A  3  2632&"#"&5467&54>++"&5#"&76762n,+.yxZ%	OqVAb



AwaxchsOEkdc

    d  Lm   %5!33	33!#"!54&#Ԫ2dd,,Md22     y  7 /  2#"'2!54635#"&547.546324&546X^Y{;2	iJ7--7Ji/9iJqYZ=gJi22iJX5Jit    '   * B J b {  "&'&7>2"3276767>/&'&"327>7>/&'&&"267"327>76&/&"327>76&/&oOOoSSoOOoS=y"$GF`	Pu"Q9	ccccVQ:	Pu"GF`	y"$ooSWWSo++oSWW"y	`FG#uP	:Q#cccc:Q#uP	$`FG#"y	    d       "  !#5!!463!#53'353!"&5+,
?,dԢdu

 


     d   	    !  !	463!#5##5#7!"&=)+5,
?,>dԪ
|
 ^G
|d
77
P             #3!#732!!34>3!!ddԢ!,d!s, d,+$d$+pp       LL  2 9  3232#!"&=46;54652#!"'74633!265#535d22s);;);)X>,>XL2dd2;));FD);>XXԢd  d  L  6 =  3232#!"&=46;54652#3#!"&54633!265#535d22s);!);;)X>,>XL2dd2;)$+;) );>XXԢd          	#!"&762#";2676&35} ,, }@D:#6#:&77&P'L.dd    	    LL   / ? O _ o    32+"&=4632+"&=46!32+"&=4632+"&=46!32+"&=46!32+"&=4632+"&=46!32+"&=46!32+"&=46



























L



































         ) 3  3#!2!&/&63!5#5353!2+!7#"&46!2!546dd^>1B)(()B1>^dd>JLPdO7S33S7Odd|*dd*22         + 5   2#4!!2!'&63!&54!2+!%5#"&46!2!5460P9<:H)"Z"
)HJLP;))%&!!&**22        $ .   2"&432!65463!2+!7#"&46!2!546jjj."+''+#JLPjjj9:LkkL:9r*dd*22        , 6  2"&5477'632!65463!2+!7#"&46!2!546X/[3oo"o"."+''+#JLPk6NooN>Qo
9:LkkL:9r*dd*22         " ,  !!.54>7!2+!7#"&46!2!546X,%??M<=BmJJLP9fQ?HSTTvK~*dd*22      )   2!546754!2#3#3#3#!"&546/R;.6p6.d6\uSpSuu;)N\6226\N)G6.dddddSuuSSu   dLL  / 3  !2#!"&546!2#!"/!"&4?!"&=46!'|

%XW&
dDdLD
2
%XX%
2
ddd        L  # - 7  !2#4&+"#4&+"#546!2!46+"&=!+"&= Sud;));d;));du);P;ddLuS);;));;)Su;),);2222         	!&4762	!2!546  'YV/ |UYY(n0U22       !  /  .#!"3!26=326!546;546;33232!'p'q*}20/222,2          "  !#!5463!#5!#!"&5463!#5,

w,,
v

w, 
O,T



  dG F V  32676'&7>++"&?+"'+"&?&/.=46;67'&6;6#";26=4&KjIC


)V=>8'"d1*)"dT,|-otE


GAkI
! "%,=?W7|&F@Je5&2WO_e_
2

2
 ~ 	 $ 4 < R b  %6%32!2&'&#!"&=46#";2654&'&"2647>?&/&6%?6'.'.. +jCHf7"	*:>XXP* @--@- -?0!3P/|)(	)f!%=&*x"62&CX>>X83D-@--@ۂ
# =I+E(	//}X&+	5!H	     d  9 Q ` o  322#+"&=#+"&=#"&=46;#"&=46;546;23546!2>574.#!2>574.#q
Oh ..40:*"6-@#

d



KK



d))k))
m!mJ.M-(2N-;]<*K

KK

K

X

K

KK

"p
"      ) ,  !2#!"&'.546"!7.#Vz$RR(z }VG+0 )IU!zV`3BBWwvXZ3Vz&--%,(1#        32#!"&546+"&=ۖgT)>)TH66g)TT)g66         33#!"&546+"&=`T)>)TH66B)TT)g66         	%'5754&>?'	%5%Ndd/\^^<ǔȖ
(Ab   d      2"&4$2"&4$2"&4|XX|X|XX|X|XX|X X|XX|XX|XX|XX|XX|      L      2"&42"&42"&4|XX|XX|XX|XX|XX|XLX|XX|X|XX|X|XX|    d dLL   /  !2#!"&=46!2#!"&=46!2#!"&=46}

J



J



J
L



p



p



          / 3  !2#!"&546!"3!2654&!2#!"&546!5^);;)X);;G;));;)X);d,d     d dL ;  !2+32+32+32#!"&46;5#"&46;5#"&46;5#"&46222222222222L********   ,       *  .62"&%#462"&%#46"&=32W??WW??||||||*(CBB||||԰||||Ӑ    B  76+2+"47&"+".543#"&'&676/!'.6E*'?)
T0I'*L
#3{,#
n6F82 *<SC#
(#((#         % C  #4.+!52>5#"#!#4.+3#525#"#5!2&2p"&2D
d2d
 dd	R ,
W22
        L    0  5"'./#!5"&?!##!"&=463!2E	1;E%=!'y,2 "
#	22+."A2Vdd       G J  !2#!"&546#"3!26=4&#"'&?!#"3!26=4&'"'&'#&#2LFF&	7

?
99gLR 2222$         # '  !5!!2#!"&546)2#!"&546!PpmpG,Ld|pd,        # '  !2#!"&546!2#!"&546!!5!2pmpG,P|pd,d       d ' +  !235463!23##!"&=##!"&546!2dddpdp,d ,          '  3#3!2#!"&546!!2#!"&546dddpG,|dpd,p     d  L ' +  32+!2#!"&5463!5#"&546;53!X|^d,Lpdpdd,           '  !#3!2#!"&546!!2#!"&546ddvpG,|dpd,p  , 0o   	#"&54632a5*    A 2~   	6'&4O**{))*     2A~   !2"'&6d)***     2,~o   	#!"&762{))*a**       (  
  5-5!5!Lc        d  1  #3!35#5!34>;!5".5323!,P2&d2"d&2dd,dd dd	& ,      L % 1  #4.+!52>5#"#!#3!35#5! 2&d2p"d&2 ,, dd	& ,dd,dd    frJ   32	+"'&476
0

)
J00		  > fJ   32+"&7	&6S
)

0
J	))	   f Jr    "'&=46	4	))	w

)

0    f>J   	'	&=4762j	00	)

0

    =  :  #463267>"&#""'./.>'&6|Vd&O"(P3G*+*3M,:IG79_7&%*>7F1||5KmCKG\JBktl$#?hI7           !2+&5#"&546!5X,p	ddd     L    !2%!#4675'=DXDddQ,[u}4]dd    Mo__<     vs    vsQ               Q                 (         d     p          E              H    E   d {            	 d           & n    d  d  d  d        d   d                 d      5 d  !                   u       
         , d ;                     I      ] d       d  Q     E    J        a          d       d 9   ' d                                                d d        d 	 	 d y ' d d     d              d       d      d d   d,               d  ,A 2 2      > f f      * * * *   NNNNNNNNNNNNNN"~Fn2b\r bb	6			
(
L

0X*^h(T*v
8|t*<6`R.j(h6h^2Dl.vb F !2!v!"@""##"#8#z##$$0$^$$%4%`%&&~&'P''(4(p())*&*J*+
+z,,h,,---.(.f..//F/~//0>0011`112$2^223"3>3h344`445,556>6|677N7788B889
9J99::l::;;<<P<<=2=>:>>?(?n??@H@@AA~BBBCCBCvCCDD`DDEZEFFtFFG6GvGGHH2HNHjHHII8I^IIJJ.JR                 @ .                   	   j   	  ( |  	     	  L   	  8   	  x6  	  6  	    	 	   	  $  	  $4  	  $X  	  |  	  0  	 www.glyphicons.com C o p y r i g h t      2 0 1 4   b y   J a n   K o v a r i k .   A l l   r i g h t s   r e s e r v e d . G L Y P H I C O N S   H a l f l i n g s R e g u l a r 1 . 0 0 9 ; U K W N ; G L Y P H I C O N S H a l f l i n g s - R e g u l a r G L Y P H I C O N S   H a l f l i n g s   R e g u l a r V e r s i o n   1 . 0 0 9 ; P S   0 0 1 . 0 0 9 ; h o t c o n v   1 . 0 . 7 0 ; m a k e o t f . l i b 2 . 5 . 5 8 3 2 9 G L Y P H I C O N S H a l f l i n g s - R e g u l a r J a n   K o v a r i k J a n   K o v a r i k w w w . g l y p h i c o n s . c o m w w w . g l y p h i c o n s . c o m w w w . g l y p h i c o n s . c o m W e b f o n t   1 . 0 W e d   O c t   2 9   0 6 : 3 6 : 0 7   2 0 1 4 F o n t   S q u i r r e l          2                          	
  !"#$%&'()*+,-./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{|}~ 	
glyph1glyph2uni00A0uni2000uni2001uni2002uni2003uni2004uni2005uni2006uni2007uni2008uni2009uni200Auni202Funi205FEurouni20BDuni231Buni25FCuni2601uni26FAuni2709uni270FuniE001uniE002uniE003uniE005uniE006uniE007uniE008uniE009uniE010uniE011uniE012uniE013uniE014uniE015uniE016uniE017uniE018uniE019uniE020uniE021uniE022uniE023uniE024uniE025uniE026uniE027uniE028uniE029uniE030uniE031uniE032uniE033uniE034uniE035uniE036uniE037uniE038uniE039uniE040uniE041uniE042uniE043uniE044uniE045uniE046uniE047uniE048uniE049uniE050uniE051uniE052uniE053uniE054uniE055uniE056uniE057uniE058uniE059uniE060uniE062uniE063uniE064uniE065uniE066uniE067uniE068uniE069uniE070uniE071uniE072uniE073uniE074uniE075uniE076uniE077uniE078uniE079uniE080uniE081uniE082uniE083uniE084uniE085uniE086uniE087uniE088uniE089uniE090uniE091uniE092uniE093uniE094uniE095uniE096uniE097uniE101uniE102uniE103uniE104uniE105uniE106uniE107uniE108uniE109uniE110uniE111uniE112uniE113uniE114uniE115uniE116uniE117uniE118uniE119uniE120uniE121uniE122uniE123uniE124uniE125uniE126uniE127uniE128uniE129uniE130uniE131uniE132uniE133uniE134uniE135uniE136uniE137uniE138uniE139uniE140uniE141uniE142uniE143uniE144uniE145uniE146uniE148uniE149uniE150uniE151uniE152uniE153uniE154uniE155uniE156uniE157uniE158uniE159uniE160uniE161uniE162uniE163uniE164uniE165uniE166uniE167uniE168uniE169uniE170uniE171uniE172uniE173uniE174uniE175uniE176uniE177uniE178uniE179uniE180uniE181uniE182uniE183uniE184uniE185uniE186uniE187uniE188uniE189uniE190uniE191uniE192uniE193uniE194uniE195uniE197uniE198uniE199uniE200uniE201uniE202uniE203uniE204uniE205uniE206uniE209uniE210uniE211uniE212uniE213uniE214uniE215uniE216uniE218uniE219uniE221uniE223uniE224uniE225uniE226uniE227uniE230uniE231uniE232uniE233uniE234uniE235uniE236uniE237uniE238uniE239uniE240uniE241uniE242uniE243uniE244uniE245uniE246uniE247uniE248uniE249uniE250uniE251uniE252uniE253uniE254uniE255uniE256uniE257uniE258uniE259uniE260uniF8FFu1F511u1F6AA    TP  <!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">
  <link href="{{path_to_root}}css/style.css" rel="stylesheet">
  <!--[if lt IE 9]>
  <script src="{{path_to_root}}js/html5shiv.min.js"></script>
  <script src="{{path_to_root}}js/respond.min.js"></script>
  <![endif]-->
 </head>
 <body>
  <header>
   <div class="container">
    <div class="row">
     <div class="col-md-12">
      <ol class="breadcrumb">
{{breadcrumbs}}
      </ol>
     </div>
    </div>
   </div>
  </header>
  <div class="container">
   <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>
   <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="http://github.com/sebastianbergmann/php-code-coverage" target="_top">PHP_CodeCoverage {{version}}</a> using <a href="{{runtime_link}}" target="_top">{{runtime_name}} {{runtime_version}}</a>{{generator}} at {{date}}.</small>
    </p>
    <a title="Back to the top" id="toplink" href="#"><span class="glyphicon glyphicon-arrow-up"></span></a>
   </footer>
  </div>
  <script src="{{path_to_root}}js/jquery.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/holder.min.js" type="text/javascript"></script>
  <script type="text/javascript">
  $(function() {
   var $window   = $(window)
     , $top_link = $('#toplink')
     , $body     = $('body, html')
     , offset    = $('#code').offset().top;

   $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: 'hover'});
  });
  </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">
  <link href="{{path_to_root}}css/nv.d3.min.css" rel="stylesheet">
  <link href="{{path_to_root}}css/style.css" rel="stylesheet">
  <!--[if lt IE 9]>
  <script src="{{path_to_root}}js/html5shiv.min.js"></script>
  <script src="{{path_to_root}}js/respond.min.js"></script>
  <![endif]-->
 </head>
 <body>
  <header>
   <div class="container">
    <div class="row">
     <div class="col-md-12">
      <ol class="breadcrumb">
{{breadcrumbs}}
      </ol>
     </div>
    </div>
   </div>
  </header>
  <div class="container">
   <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="http://github.com/sebastianbergmann/php-code-coverage" target="_top">PHP_CodeCoverage {{version}}</a> using <a href="{{runtime_link}}" target="_top">{{runtime_name}} {{runtime_version}}</a>{{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/bootstrap.min.js" type="text/javascript"></script>
  <script src="{{path_to_root}}js/holder.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(key, y, e, 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(key, y, e, 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>
<?php










if (!defined('T_TRAIT')) {
define('T_TRAIT', 1001);
}

if (!defined('T_INSTEADOF')) {
define('T_INSTEADOF', 1002);
}

if (!defined('T_CALLABLE')) {
define('T_CALLABLE', 1003);
}

if (!defined('T_FINALLY')) {
define('T_FINALLY', 1004);
}

if (!defined('T_YIELD')) {
define('T_YIELD', 1005);
}







class PHP_CodeCoverage_Report_HTML_Renderer_File extends PHP_CodeCoverage_Report_HTML_Renderer
{



private $htmlspecialcharsFlags;










public function __construct($templatePath, $generator, $date, $lowUpperBound, $highLowerBound)
{
parent::__construct(
$templatePath,
$generator,
$date,
$lowUpperBound,
$highLowerBound
);

$this->htmlspecialcharsFlags = ENT_COMPAT;

if (PHP_VERSION_ID >= 50400 && defined('ENT_SUBSTITUTE')) {
$this->htmlspecialcharsFlags = $this->htmlspecialcharsFlags | ENT_HTML401 | ENT_SUBSTITUTE;
}
}





public function render(PHP_CodeCoverage_Report_Node_File $node, $file)
{
$template = new Text_Template($this->templatePath . 'file.html', '{{', '}}');

$template->setVar(
array(
'items' => $this->renderItems($node),
'lines' => $this->renderSource($node)
)
);

$this->setCommonTemplateVariables($template, $node);

$template->renderTo($file);
}





protected function renderItems(PHP_CodeCoverage_Report_Node_File $node)
{
$template = new Text_Template($this->templatePath . 'file_item.html', '{{', '}}');

$methodItemTemplate = new Text_Template(
$this->templatePath . 'method_item.html',
'{{',
'}}'
);

$items = $this->renderItemTemplate(
$template,
array(
'name' => 'Total',
'numClasses' => $node->getNumClassesAndTraits(),
'numTestedClasses' => $node->getNumTestedClassesAndTraits(),
'numMethods' => $node->getNumMethods(),
'numTestedMethods' => $node->getNumTestedMethods(),
'linesExecutedPercent' => $node->getLineExecutedPercent(false),
'linesExecutedPercentAsString' => $node->getLineExecutedPercent(),
'numExecutedLines' => $node->getNumExecutedLines(),
'numExecutableLines' => $node->getNumExecutableLines(),
'testedMethodsPercent' => $node->getTestedMethodsPercent(false),
'testedMethodsPercentAsString' => $node->getTestedMethodsPercent(),
'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)
{
if (empty($items)) {
return '';
}

$buffer = '';

foreach ($items as $name => $item) {
$numMethods = count($item['methods']);
$numTestedMethods = 0;

foreach ($item['methods'] as $method) {
if ($method['executedLines'] == $method['executableLines']) {
$numTestedMethods++;
}
}

$buffer .= $this->renderItemTemplate(
$template,
array(
'name' => $name,
'numClasses' => 1,
'numTestedClasses' => $numTestedMethods == $numMethods ? 1 : 0,
'numMethods' => $numMethods,
'numTestedMethods' => $numTestedMethods,
'linesExecutedPercent' => PHP_CodeCoverage_Util::percent(
$item['executedLines'],
$item['executableLines'],
false
),
'linesExecutedPercentAsString' => PHP_CodeCoverage_Util::percent(
$item['executedLines'],
$item['executableLines'],
true
),
'numExecutedLines' => $item['executedLines'],
'numExecutableLines' => $item['executableLines'],
'testedMethodsPercent' => PHP_CodeCoverage_Util::percent(
$numTestedMethods,
$numMethods,
false
),
'testedMethodsPercentAsString' => PHP_CodeCoverage_Util::percent(
$numTestedMethods,
$numMethods,
true
),
'testedClassesPercent' => PHP_CodeCoverage_Util::percent(
$numTestedMethods == $numMethods ? 1 : 0,
1,
false
),
'testedClassesPercentAsString' => PHP_CodeCoverage_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)
{
if (empty($functions)) {
return '';
}

$buffer = '';

foreach ($functions as $function) {
$buffer .= $this->renderFunctionOrMethodItem(
$template,
$function
);
}

return $buffer;
}





protected function renderFunctionOrMethodItem(Text_Template $template, array $item, $indent = '')
{
$numTestedItems = $item['executedLines'] == $item['executableLines'] ? 1 : 0;

return $this->renderItemTemplate(
$template,
array(
'name' => sprintf(
'%s<a href="#%d"><abbr title="%s">%s</abbr></a>',
$indent,
$item['startLine'],
htmlspecialchars($item['signature']),
isset($item['functionName']) ? $item['functionName'] : $item['methodName']
),
'numMethods' => 1,
'numTestedMethods' => $numTestedItems,
'linesExecutedPercent' => PHP_CodeCoverage_Util::percent(
$item['executedLines'],
$item['executableLines'],
false
),
'linesExecutedPercentAsString' => PHP_CodeCoverage_Util::percent(
$item['executedLines'],
$item['executableLines'],
true
),
'numExecutedLines' => $item['executedLines'],
'numExecutableLines' => $item['executableLines'],
'testedMethodsPercent' => PHP_CodeCoverage_Util::percent(
$numTestedItems,
1,
false
),
'testedMethodsPercentAsString' => PHP_CodeCoverage_Util::percent(
$numTestedItems,
1,
true
),
'crap' => $item['crap']
)
);
}





protected function renderSource(PHP_CodeCoverage_Report_Node_File $node)
{
$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 = count($coverageData[$i]);

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)
);
}

$popoverContent .= '</ul>';
$trClass = ' class="' . $lineCss . ' popin"';
}
}

if (!empty($popoverTitle)) {
$popover = sprintf(
' data-title="%s" data-content="%s" data-placement="bottom" data-html="true"',
$popoverTitle,
htmlspecialchars($popoverContent)
);
} else {
$popover = '';
}

$lines .= sprintf(
'     <tr%s%s><td><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)
{
$buffer = file_get_contents($file);
$tokens = token_get_all($buffer);
$result = array('');
$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)
);

$stringFlag = !$stringFlag;
} else {
$result[$i] .= sprintf(
'<span class="keyword">%s</span>',
htmlspecialchars($token)
);
}

continue;
}

list($token, $value) = $token;

$value = str_replace(
array("\t", ' '),
array('&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;
}
}
<?php









use SebastianBergmann\Environment\Runtime;






abstract class PHP_CodeCoverage_Report_HTML_Renderer
{



protected $templatePath;




protected $generator;




protected $date;




protected $lowUpperBound;




protected $highLowerBound;




protected $version;










public function __construct($templatePath, $generator, $date, $lowUpperBound, $highLowerBound)
{
$version = new SebastianBergmann\Version('2.2.4', dirname(dirname(dirname(dirname(__DIR__)))));

$this->templatePath = $templatePath;
$this->generator = $generator;
$this->date = $date;
$this->lowUpperBound = $lowUpperBound;
$this->highLowerBound = $highLowerBound;
$this->version = $version->getVersion();
}






protected function renderItemTemplate(Text_Template $template, array $data)
{
$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 = 'success';
$classesNumber = '0' . $numSeparator . '0';
$classesBar = $this->getCoverageBar(100);
}

if ($data['numMethods'] > 0) {
$methodsLevel = $this->getColorLevel($data['testedMethodsPercent']);

$methodsNumber = $data['numTestedMethods'] . $numSeparator .
$data['numMethods'];

$methodsBar = $this->getCoverageBar(
$data['testedMethodsPercent']
);
} else {
$methodsLevel = 'success';
$methodsNumber = '0' . $numSeparator . '0';
$methodsBar = $this->getCoverageBar(100);
$data['testedMethodsPercentAsString'] = '100.00%';
}

if ($data['numExecutableLines'] > 0) {
$linesLevel = $this->getColorLevel($data['linesExecutedPercent']);

$linesNumber = $data['numExecutedLines'] . $numSeparator .
$data['numExecutableLines'];

$linesBar = $this->getCoverageBar(
$data['linesExecutedPercent']
);
} else {
$linesLevel = 'success';
$linesNumber = '0' . $numSeparator . '0';
$linesBar = $this->getCoverageBar(100);
$data['linesExecutedPercentAsString'] = '100.00%';
}

$template->setVar(
array(
'icon' => isset($data['icon']) ? $data['icon'] : '',
'crap' => isset($data['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' => isset($data['testedClassesPercentAsString']) ? $data['testedClassesPercentAsString'] : '',
'classes_level' => $classesLevel,
'classes_number' => $classesNumber
)
);

return $template->render();
}





protected function setCommonTemplateVariables(Text_Template $template, PHP_CodeCoverage_Report_Node $node)
{
$runtime = new Runtime;

$template->setVar(
array(
'id' => $node->getId(),
'full_path' => $node->getPath(),
'path_to_root' => $this->getPathToRoot($node),
'breadcrumbs' => $this->getBreadcrumbs($node),
'date' => $this->date,
'version' => $this->version,
'runtime_name' => $runtime->getName(),
'runtime_version' => $runtime->getVersion(),
'runtime_link' => $runtime->getVendorUrl(),
'generator' => $this->generator,
'low_upper_bound' => $this->lowUpperBound,
'high_lower_bound' => $this->highLowerBound
)
);
}

protected function getBreadcrumbs(PHP_CodeCoverage_Report_Node $node)
{
$breadcrumbs = '';
$path = $node->getPathAsArray();
$pathToRoot = array();
$max = count($path);

if ($node instanceof PHP_CodeCoverage_Report_Node_File) {
$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(PHP_CodeCoverage_Report_Node $node)
{
$buffer = sprintf(
'        <li class="active">%s</li>' . "\n",
$node->getName()
);

if ($node instanceof PHP_CodeCoverage_Report_Node_Directory) {
$buffer .= '        <li>(<a href="dashboard.html">Dashboard</a>)</li>' . "\n";
}

return $buffer;
}

protected function getInactiveBreadcrumb(PHP_CodeCoverage_Report_Node $node, $pathToRoot)
{
return sprintf(
'        <li><a href="%sindex.html">%s</a></li>' . "\n",
$pathToRoot,
$node->getName()
);
}

protected function getPathToRoot(PHP_CodeCoverage_Report_Node $node)
{
$id = $node->getId();
$depth = substr_count($id, '/');

if ($id != 'index' &&
$node instanceof PHP_CodeCoverage_Report_Node_Directory) {
$depth++;
}

return str_repeat('../', $depth);
}

protected function getCoverageBar($percent)
{
$level = $this->getColorLevel($percent);

$template = new Text_Template(
$this->templatePath . 'coverage_bar.html',
'{{',
'}}'
);

$template->setVar(array('level' => $level, 'percent' => sprintf('%.2F', $percent)));

return $template->render();
}





protected function getColorLevel($percent)
{
if ($percent <= $this->lowUpperBound) {
return 'danger';
} elseif ($percent > $this->lowUpperBound &&
$percent < $this->highLowerBound) {
return 'warning';
} else {
return 'success';
}
}
}
<?php














abstract class PHP_CodeCoverage_Report_Node implements Countable
{



protected $name;




protected $path;




protected $pathArray;




protected $parent;




protected $id;







public function __construct($name, PHP_CodeCoverage_Report_Node $parent = null)
{
if (substr($name, -1) == '/') {
$name = substr($name, 0, -1);
}

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




public function getName()
{
return $this->name;
}




public function getId()
{
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()
{
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() . '/' . $this->name;
}
}

return $this->path;
}




public function getPathAsArray()
{
if ($this->pathArray === null) {
if ($this->parent === null) {
$this->pathArray = array();
} else {
$this->pathArray = $this->parent->getPathAsArray();
}

$this->pathArray[] = $this;
}

return $this->pathArray;
}




public function getParent()
{
return $this->parent;
}







public function getTestedClassesPercent($asString = true)
{
return PHP_CodeCoverage_Util::percent(
$this->getNumTestedClasses(),
$this->getNumClasses(),
$asString
);
}







public function getTestedTraitsPercent($asString = true)
{
return PHP_CodeCoverage_Util::percent(
$this->getNumTestedTraits(),
$this->getNumTraits(),
$asString
);
}








public function getTestedClassesAndTraitsPercent($asString = true)
{
return PHP_CodeCoverage_Util::percent(
$this->getNumTestedClassesAndTraits(),
$this->getNumClassesAndTraits(),
$asString
);
}







public function getTestedMethodsPercent($asString = true)
{
return PHP_CodeCoverage_Util::percent(
$this->getNumTestedMethods(),
$this->getNumMethods(),
$asString
);
}







public function getLineExecutedPercent($asString = true)
{
return PHP_CodeCoverage_Util::percent(
$this->getNumExecutedLines(),
$this->getNumExecutableLines(),
$asString
);
}







public function getNumClassesAndTraits()
{
return $this->getNumClasses() + $this->getNumTraits();
}







public function getNumTestedClassesAndTraits()
{
return $this->getNumTestedClasses() + $this->getNumTestedTraits();
}







public function getClassesAndTraits()
{
return array_merge($this->getClasses(), $this->getTraits());
}






abstract public function getClasses();






abstract public function getTraits();






abstract public function getFunctions();






abstract public function getLinesOfCode();






abstract public function getNumExecutableLines();






abstract public function getNumExecutedLines();






abstract public function getNumClasses();






abstract public function getNumTestedClasses();






abstract public function getNumTraits();






abstract public function getNumTestedTraits();






abstract public function getNumMethods();






abstract public function getNumTestedMethods();






abstract public function getNumFunctions();






abstract public function getNumTestedFunctions();
}
<?php
















class PHP_CodeCoverage_Report_Text
{
protected $lowUpperBound;
protected $highLowerBound;
protected $showUncoveredFiles;
protected $showOnlySummary;

protected $colors = array(
'green' => "\x1b[30;42m",
'yellow' => "\x1b[30;43m",
'red' => "\x1b[37;41m",
'header' => "\x1b[1;37;40m",
'reset' => "\x1b[0m",
'eol' => "\x1b[2K",
);

public function __construct($lowUpperBound, $highLowerBound, $showUncoveredFiles, $showOnlySummary)
{
$this->lowUpperBound = $lowUpperBound;
$this->highLowerBound = $highLowerBound;
$this->showUncoveredFiles = $showUncoveredFiles;
$this->showOnlySummary = $showOnlySummary;
}






public function process(PHP_CodeCoverage $coverage, $showColors = false)
{
$output = PHP_EOL . PHP_EOL;
$report = $coverage->getReport();
unset($coverage);

$colors = array(
'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'] = $this->colors['reset'];
$colors['header'] = $this->colors['header'];
$colors['eol'] = $this->colors['eol'];
}

$classes = sprintf(
'  Classes: %6s (%d/%d)',
PHP_CodeCoverage_Util::percent(
$report->getNumTestedClassesAndTraits(),
$report->getNumClassesAndTraits(),
true
),
$report->getNumTestedClassesAndTraits(),
$report->getNumClassesAndTraits()
);

$methods = sprintf(
'  Methods: %6s (%d/%d)',
PHP_CodeCoverage_Util::percent(
$report->getNumTestedMethods(),
$report->getNumMethods(),
true
),
$report->getNumTestedMethods(),
$report->getNumMethods()
);

$lines = sprintf(
'  Lines:   %6s (%d/%d)',
PHP_CodeCoverage_Util::percent(
$report->getNumExecutedLines(),
$report->getNumExecutableLines(),
true
),
$report->getNumExecutedLines(),
$report->getNumExecutableLines()
);

$padding = max(array_map('strlen', array($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 = array();

foreach ($report as $item) {
if (!$item instanceof PHP_CodeCoverage_Report_Node_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++;
}
}

if (!empty($class['package']['namespace'])) {
$namespace = '\\' . $class['package']['namespace'] . '::';
} elseif (!empty($class['package']['fullPackage'])) {
$namespace = '@' . $class['package']['fullPackage'] . '::';
} else {
$namespace = '';
}

$classCoverage[$namespace . $className] = array(
'namespace' => $namespace,
'className ' => $className,
'methodsCovered' => $coveredMethods,
'methodCount' => $classMethods,
'statementsCovered' => $coveredClassStatements,
'statementCount' => $classStatements,
);
}
}

ksort($classCoverage);

$methodColor = '';
$linesColor = '';
$resetColor = '';

foreach ($classCoverage as $fullQualifiedPath => $classInfo) {
if ($classInfo['statementsCovered'] != 0 ||
$this->showUncoveredFiles) {
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;
}

protected function getCoverageColor($numberOfCoveredElements, $totalNumberOfElements)
{
$coverage = PHP_CodeCoverage_Util::percent(
$numberOfCoveredElements,
$totalNumberOfElements
);

if ($coverage >= $this->highLowerBound) {
return $this->colors['green'];
} elseif ($coverage > $this->lowUpperBound) {
return $this->colors['yellow'];
}

return $this->colors['red'];
}

protected function printCoverageCounts($numberOfCoveredElements, $totalNumberOfElements, $presicion)
{
$format = '%' . $presicion . 's';

return PHP_CodeCoverage_Util::percent(
$numberOfCoveredElements,
$totalNumberOfElements,
true,
true
) .
' (' . sprintf($format, $numberOfCoveredElements) . '/' .
sprintf($format, $totalNumberOfElements) . ')';
}

private function format($color, $padding, $string)
{
$reset = $color ? $this->colors['reset'] : '';

return $color . str_pad($string, $padding) . $reset . PHP_EOL;
}
}
<?php














class PHP_CodeCoverage_Report_Clover
{






public function process(PHP_CodeCoverage $coverage, $target = null, $name = null)
{
$xmlDocument = new DOMDocument('1.0', 'UTF-8');
$xmlDocument->formatOutput = true;

$xmlCoverage = $xmlDocument->createElement('coverage');
$xmlCoverage->setAttribute('generated', (int) $_SERVER['REQUEST_TIME']);
$xmlDocument->appendChild($xmlCoverage);

$xmlProject = $xmlDocument->createElement('project');
$xmlProject->setAttribute('timestamp', (int) $_SERVER['REQUEST_TIME']);

if (is_string($name)) {
$xmlProject->setAttribute('name', $name);
}

$xmlCoverage->appendChild($xmlProject);

$packages = array();
$report = $coverage->getReport();
unset($coverage);

foreach ($report as $item) {
$namespace = 'global';

if (!$item instanceof PHP_CodeCoverage_Report_Node_File) {
continue;
}

$xmlFile = $xmlDocument->createElement('file');
$xmlFile->setAttribute('name', $item->getPath());

$classes = $item->getClassesAndTraits();
$coverage = $item->getCoverageData();
$lines = array();

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;
for ($i = $method['startLine'];
$i <= $method['endLine'];
$i++) {
if (isset($coverage[$i]) && ($coverage[$i] !== null)) {
$methodCount = max($methodCount, count($coverage[$i]));
}
}

$lines[$method['startLine']] = array(
'count' => $methodCount,
'crap' => $method['crap'],
'type' => 'method',
'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('methods', $classMethods);
$xmlMetrics->setAttribute('coveredmethods', $coveredMethods);
$xmlMetrics->setAttribute('conditionals', 0);
$xmlMetrics->setAttribute('coveredconditionals', 0);
$xmlMetrics->setAttribute('statements', $classStatements);
$xmlMetrics->setAttribute(
'coveredstatements',
$coveredClassStatements
);
$xmlMetrics->setAttribute(
'elements',
$classMethods +
$classStatements

);
$xmlMetrics->setAttribute(
'coveredelements',
$coveredMethods +
$coveredClassStatements

);
$xmlClass->appendChild($xmlMetrics);
}

foreach ($coverage as $line => $data) {
if ($data === null || isset($lines[$line])) {
continue;
}

$lines[$line] = array(
'count' => count($data), 'type' => 'stmt'
);
}

ksort($lines);

foreach ($lines as $line => $data) {
$xmlLine = $xmlDocument->createElement('line');
$xmlLine->setAttribute('num', $line);
$xmlLine->setAttribute('type', $data['type']);

if (isset($data['name'])) {
$xmlLine->setAttribute('name', $data['name']);
}

if (isset($data['crap'])) {
$xmlLine->setAttribute('crap', $data['crap']);
}

$xmlLine->setAttribute('count', $data['count']);
$xmlFile->appendChild($xmlLine);
}

$linesOfCode = $item->getLinesOfCode();

$xmlMetrics = $xmlDocument->createElement('metrics');
$xmlMetrics->setAttribute('loc', $linesOfCode['loc']);
$xmlMetrics->setAttribute('ncloc', $linesOfCode['ncloc']);
$xmlMetrics->setAttribute('classes', $item->getNumClassesAndTraits());
$xmlMetrics->setAttribute('methods', $item->getNumMethods());
$xmlMetrics->setAttribute(
'coveredmethods',
$item->getNumTestedMethods()
);
$xmlMetrics->setAttribute('conditionals', 0);
$xmlMetrics->setAttribute('coveredconditionals', 0);
$xmlMetrics->setAttribute(
'statements',
$item->getNumExecutableLines()
);
$xmlMetrics->setAttribute(
'coveredstatements',
$item->getNumExecutedLines()
);
$xmlMetrics->setAttribute(
'elements',
$item->getNumMethods() + $item->getNumExecutableLines()

);
$xmlMetrics->setAttribute(
'coveredelements',
$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', count($report));
$xmlMetrics->setAttribute('loc', $linesOfCode['loc']);
$xmlMetrics->setAttribute('ncloc', $linesOfCode['ncloc']);
$xmlMetrics->setAttribute(
'classes',
$report->getNumClassesAndTraits()
);
$xmlMetrics->setAttribute('methods', $report->getNumMethods());
$xmlMetrics->setAttribute(
'coveredmethods',
$report->getNumTestedMethods()
);
$xmlMetrics->setAttribute('conditionals', 0);
$xmlMetrics->setAttribute('coveredconditionals', 0);
$xmlMetrics->setAttribute(
'statements',
$report->getNumExecutableLines()
);
$xmlMetrics->setAttribute(
'coveredstatements',
$report->getNumExecutedLines()
);
$xmlMetrics->setAttribute(
'elements',
$report->getNumMethods() + $report->getNumExecutableLines()

);
$xmlMetrics->setAttribute(
'coveredelements',
$report->getNumTestedMethods() + $report->getNumExecutedLines()

);

$xmlProject->appendChild($xmlMetrics);

if ($target !== null) {
if (!is_dir(dirname($target))) {
mkdir(dirname($target), 0777, true);
}

return $xmlDocument->save($target);
} else {
return $xmlDocument->saveXML();
}
}
}
<?php












class PHP_CodeCoverage_Report_XML_Directory extends PHP_CodeCoverage_Report_XML_Node
{
}
<?php












class PHP_CodeCoverage_Report_XML_File_Report extends PHP_CodeCoverage_Report_XML_File
{
public function __construct($name)
{
$this->dom = new DOMDocument;
$this->dom->loadXML('<?xml version="1.0" ?><phpunit xmlns="http://schema.phpunit.de/coverage/1.0"><file /></phpunit>');

$this->contextNode = $this->dom->getElementsByTagNameNS(
'http://schema.phpunit.de/coverage/1.0',
'file'
)->item(0);

$this->setName($name);
}

private function setName($name)
{
$this->contextNode->setAttribute('name', $name);
}

public function asDom()
{
return $this->dom;
}

public function getFunctionObject($name)
{
$node = $this->contextNode->appendChild(
$this->dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'function'
)
);

return new PHP_CodeCoverage_Report_XML_File_Method($node, $name);
}

public function getClassObject($name)
{
return $this->getUnitObject('class', $name);
}

public function getTraitObject($name)
{
return $this->getUnitObject('trait', $name);
}

private function getUnitObject($tagName, $name)
{
$node = $this->contextNode->appendChild(
$this->dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
$tagName
)
);

return new PHP_CodeCoverage_Report_XML_File_Unit($node, $name);
}
}
<?php












class PHP_CodeCoverage_Report_XML_File_Unit
{



private $contextNode;

public function __construct(DOMElement $context, $name)
{
$this->contextNode = $context;

$this->setName($name);
}

private function setName($name)
{
$this->contextNode->setAttribute('name', $name);
}

public function setLines($start, $executable, $executed)
{
$this->contextNode->setAttribute('start', $start);
$this->contextNode->setAttribute('executable', $executable);
$this->contextNode->setAttribute('executed', $executed);
}

public function setCrap($crap)
{
$this->contextNode->setAttribute('crap', $crap);
}

public function setPackage($full, $package, $sub, $category)
{
$node = $this->contextNode->getElementsByTagNameNS(
'http://schema.phpunit.de/coverage/1.0',
'package'
)->item(0);

if (!$node) {
$node = $this->contextNode->appendChild(
$this->contextNode->ownerDocument->createElementNS(
'http://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($namespace)
{
$node = $this->contextNode->getElementsByTagNameNS(
'http://schema.phpunit.de/coverage/1.0',
'namespace'
)->item(0);

if (!$node) {
$node = $this->contextNode->appendChild(
$this->contextNode->ownerDocument->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'namespace'
)
);
}

$node->setAttribute('name', $namespace);
}

public function addMethod($name)
{
$node = $this->contextNode->appendChild(
$this->contextNode->ownerDocument->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'method'
)
);

return new PHP_CodeCoverage_Report_XML_File_Method($node, $name);
}
}
<?php












class PHP_CodeCoverage_Report_XML_File_Coverage
{



private $writer;




private $contextNode;




private $finalized = false;

public function __construct(DOMElement $context, $line)
{
$this->contextNode = $context;

$this->writer = new XMLWriter();
$this->writer->openMemory();
$this->writer->startElementNs(null, $context->nodeName, 'http://schema.phpunit.de/coverage/1.0');
$this->writer->writeAttribute('nr', $line);
}

public function addTest($test)
{
if ($this->finalized) {
throw new PHP_CodeCoverage_Exception('Coverage Report already finalized');
}

$this->writer->startElement('covered');
$this->writer->writeAttribute('by', $test);
$this->writer->endElement();
}

public function finalize()
{
$this->writer->endElement();

$fragment = $this->contextNode->ownerDocument->createDocumentFragment();
$fragment->appendXML($this->writer->outputMemory());

$this->contextNode->parentNode->replaceChild(
$fragment,
$this->contextNode
);

$this->finalized = true;
}
}
<?php












class PHP_CodeCoverage_Report_XML_File_Method
{



private $contextNode;

public function __construct(DOMElement $context, $name)
{
$this->contextNode = $context;

$this->setName($name);
}

private function setName($name)
{
$this->contextNode->setAttribute('name', $name);
}

public function setSignature($signature)
{
$this->contextNode->setAttribute('signature', $signature);
}

public function setLines($start, $end = null)
{
$this->contextNode->setAttribute('start', $start);

if ($end !== null) {
$this->contextNode->setAttribute('end', $end);
}
}

public function setTotals($executable, $executed, $coverage)
{
$this->contextNode->setAttribute('executable', $executable);
$this->contextNode->setAttribute('executed', $executed);
$this->contextNode->setAttribute('coverage', $coverage);
}

public function setCrap($crap)
{
$this->contextNode->setAttribute('crap', $crap);
}
}
<?php












class PHP_CodeCoverage_Report_XML_Node
{



private $dom;




private $contextNode;

public function __construct(DOMElement $context)
{
$this->setContextNode($context);
}

protected function setContextNode(DOMElement $context)
{
$this->dom = $context->ownerDocument;
$this->contextNode = $context;
}

public function getDom()
{
return $this->dom;
}

protected function getContextNode()
{
return $this->contextNode;
}

public function getTotals()
{
$totalsContainer = $this->getContextNode()->firstChild;

if (!$totalsContainer) {
$totalsContainer = $this->getContextNode()->appendChild(
$this->dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'totals'
)
);
}

return new PHP_CodeCoverage_Report_XML_Totals($totalsContainer);
}

public function addDirectory($name)
{
$dirNode = $this->getDom()->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'directory'
);

$dirNode->setAttribute('name', $name);
$this->getContextNode()->appendChild($dirNode);

return new PHP_CodeCoverage_Report_XML_Directory($dirNode);
}

public function addFile($name, $href)
{
$fileNode = $this->getDom()->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'file'
);

$fileNode->setAttribute('name', $name);
$fileNode->setAttribute('href', $href);
$this->getContextNode()->appendChild($fileNode);

return new PHP_CodeCoverage_Report_XML_File($fileNode);
}
}
<?php












class PHP_CodeCoverage_Report_XML_Project extends PHP_CodeCoverage_Report_XML_Node
{
public function __construct($name)
{
$this->init();
$this->setProjectName($name);
}

private function init()
{
$dom = new DOMDocument;
$dom->loadXML('<?xml version="1.0" ?><phpunit xmlns="http://schema.phpunit.de/coverage/1.0"><project/></phpunit>');

$this->setContextNode(
$dom->getElementsByTagNameNS(
'http://schema.phpunit.de/coverage/1.0',
'project'
)->item(0)
);
}

private function setProjectName($name)
{
$this->getContextNode()->setAttribute('name', $name);
}

public function getTests()
{
$testsNode = $this->getContextNode()->getElementsByTagNameNS(
'http://schema.phpunit.de/coverage/1.0',
'tests'
)->item(0);

if (!$testsNode) {
$testsNode = $this->getContextNode()->appendChild(
$this->getDom()->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'tests'
)
);
}

return new PHP_CodeCoverage_Report_XML_Tests($testsNode);
}

public function asDom()
{
return $this->getDom();
}
}
<?php












class PHP_CodeCoverage_Report_XML_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(
'http://schema.phpunit.de/coverage/1.0',
'lines'
);

$this->methodsNode = $dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'methods'
);

$this->functionsNode = $dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'functions'
);

$this->classesNode = $dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'classes'
);

$this->traitsNode = $dom->createElementNS(
'http://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()
{
return $this->container;
}

public function setNumLines($loc, $cloc, $ncloc, $executable, $executed)
{
$this->linesNode->setAttribute('total', $loc);
$this->linesNode->setAttribute('comments', $cloc);
$this->linesNode->setAttribute('code', $ncloc);
$this->linesNode->setAttribute('executable', $executable);
$this->linesNode->setAttribute('executed', $executed);
$this->linesNode->setAttribute(
'percent',
PHP_CodeCoverage_Util::percent($executed, $executable, true)
);
}

public function setNumClasses($count, $tested)
{
$this->classesNode->setAttribute('count', $count);
$this->classesNode->setAttribute('tested', $tested);
$this->classesNode->setAttribute(
'percent',
PHP_CodeCoverage_Util::percent($tested, $count, true)
);
}

public function setNumTraits($count, $tested)
{
$this->traitsNode->setAttribute('count', $count);
$this->traitsNode->setAttribute('tested', $tested);
$this->traitsNode->setAttribute(
'percent',
PHP_CodeCoverage_Util::percent($tested, $count, true)
);
}

public function setNumMethods($count, $tested)
{
$this->methodsNode->setAttribute('count', $count);
$this->methodsNode->setAttribute('tested', $tested);
$this->methodsNode->setAttribute(
'percent',
PHP_CodeCoverage_Util::percent($tested, $count, true)
);
}

public function setNumFunctions($count, $tested)
{
$this->functionsNode->setAttribute('count', $count);
$this->functionsNode->setAttribute('tested', $tested);
$this->functionsNode->setAttribute(
'percent',
PHP_CodeCoverage_Util::percent($tested, $count, true)
);
}
}
<?php












class PHP_CodeCoverage_Report_XML_Tests
{
private $contextNode;

private $codeMap = array(
0 => 'PASSED', 
 1 => 'SKIPPED', 
 2 => 'INCOMPLETE', 
 3 => 'FAILURE', 
 4 => 'ERROR', 
 5 => 'RISKY' 
 );

public function __construct(DOMElement $context)
{
$this->contextNode = $context;
}

public function addTest($test, array $result)
{
$node = $this->contextNode->appendChild(
$this->contextNode->ownerDocument->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'test'
)
);
$node->setAttribute('name', $test);
$node->setAttribute('size', $result['size']);
$node->setAttribute('result', (int) $result['status']);
$node->setAttribute('status', $this->codeMap[(int) $result['status']]);
}
}
<?php












class PHP_CodeCoverage_Report_XML_File
{



protected $dom;




protected $contextNode;

public function __construct(DOMElement $context)
{
$this->dom = $context->ownerDocument;
$this->contextNode = $context;
}

public function getTotals()
{
$totalsContainer = $this->contextNode->firstChild;

if (!$totalsContainer) {
$totalsContainer = $this->contextNode->appendChild(
$this->dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'totals'
)
);
}

return new PHP_CodeCoverage_Report_XML_Totals($totalsContainer);
}

public function getLineCoverage($line)
{
$coverage = $this->contextNode->getElementsByTagNameNS(
'http://schema.phpunit.de/coverage/1.0',
'coverage'
)->item(0);

if (!$coverage) {
$coverage = $this->contextNode->appendChild(
$this->dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'coverage'
)
);
}

$lineNode = $coverage->appendChild(
$this->dom->createElementNS(
'http://schema.phpunit.de/coverage/1.0',
'line'
)
);

return new PHP_CodeCoverage_Report_XML_File_Coverage($lineNode, $line);
}
}
<?php














class PHP_CodeCoverage_Report_HTML
{



private $templatePath;




private $generator;




private $lowUpperBound;




private $highLowerBound;








public function __construct($lowUpperBound = 50, $highLowerBound = 90, $generator = '')
{
$this->generator = $generator;
$this->highLowerBound = $highLowerBound;
$this->lowUpperBound = $lowUpperBound;

$this->templatePath = sprintf(
'%s%sHTML%sRenderer%sTemplate%s',
dirname(__FILE__),
DIRECTORY_SEPARATOR,
DIRECTORY_SEPARATOR,
DIRECTORY_SEPARATOR,
DIRECTORY_SEPARATOR
);
}





public function process(PHP_CodeCoverage $coverage, $target)
{
$target = $this->getDirectory($target);
$report = $coverage->getReport();
unset($coverage);

if (!isset($_SERVER['REQUEST_TIME'])) {
$_SERVER['REQUEST_TIME'] = time();
}

$date = date('D M j G:i:s T Y', $_SERVER['REQUEST_TIME']);

$dashboard = new PHP_CodeCoverage_Report_HTML_Renderer_Dashboard(
$this->templatePath,
$this->generator,
$date,
$this->lowUpperBound,
$this->highLowerBound
);

$directory = new PHP_CodeCoverage_Report_HTML_Renderer_Directory(
$this->templatePath,
$this->generator,
$date,
$this->lowUpperBound,
$this->highLowerBound
);

$file = new PHP_CodeCoverage_Report_HTML_Renderer_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 PHP_CodeCoverage_Report_Node_Directory) {
if (!file_exists($target . $id)) {
mkdir($target . $id, 0777, true);
}

$directory->render($node, $target . $id . '/index.html');
$dashboard->render($node, $target . $id . '/dashboard.html');
} else {
$dir = dirname($target . $id);

if (!file_exists($dir)) {
mkdir($dir, 0777, true);
}

$file->render($node, $target . $id . '.html');
}
}

$this->copyFiles($target);
}




private function copyFiles($target)
{
$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');

$dir = $this->getDirectory($target . 'fonts');
copy($this->templatePath . 'fonts/glyphicons-halflings-regular.eot', $dir . 'glyphicons-halflings-regular.eot');
copy($this->templatePath . 'fonts/glyphicons-halflings-regular.svg', $dir . 'glyphicons-halflings-regular.svg');
copy($this->templatePath . 'fonts/glyphicons-halflings-regular.ttf', $dir . 'glyphicons-halflings-regular.ttf');
copy($this->templatePath . 'fonts/glyphicons-halflings-regular.woff', $dir . 'glyphicons-halflings-regular.woff');
copy($this->templatePath . 'fonts/glyphicons-halflings-regular.woff2', $dir . 'glyphicons-halflings-regular.woff2');

$dir = $this->getDirectory($target . 'js');
copy($this->templatePath . 'js/bootstrap.min.js', $dir . 'bootstrap.min.js');
copy($this->templatePath . 'js/d3.min.js', $dir . 'd3.min.js');
copy($this->templatePath . 'js/holder.min.js', $dir . 'holder.min.js');
copy($this->templatePath . 'js/html5shiv.min.js', $dir . 'html5shiv.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/respond.min.js', $dir . 'respond.min.js');
}







private function getDirectory($directory)
{
if (substr($directory, -1, 1) != DIRECTORY_SEPARATOR) {
$directory .= DIRECTORY_SEPARATOR;
}

if (is_dir($directory)) {
return $directory;
}

if (@mkdir($directory, 0777, true)) {
return $directory;
}

throw new PHP_CodeCoverage_Exception(
sprintf(
'Directory "%s" does not exist.',
$directory
)
);
}
}
<?php












class PHP_CodeCoverage_Report_XML
{



private $target;




private $project;

public function process(PHP_CodeCoverage $coverage, $target)
{
if (substr($target, -1, 1) != DIRECTORY_SEPARATOR) {
$target .= DIRECTORY_SEPARATOR;
}

$this->target = $target;
$this->initTargetDirectory($target);

$report = $coverage->getReport();

$this->project = new PHP_CodeCoverage_Report_XML_Project(
$coverage->getReport()->getName()
);

$this->processTests($coverage->getTests());
$this->processDirectory($report, $this->project);

$index = $this->project->asDom();
$index->formatOutput = true;
$index->preserveWhiteSpace = false;
$index->save($target . '/index.xml');
}

private function initTargetDirectory($dir)
{
if (file_exists($dir)) {
if (!is_dir($dir)) {
throw new PHP_CodeCoverage_Exception(
"'$dir' exists but is not a directory."
);
}

if (!is_writable($dir)) {
throw new PHP_CodeCoverage_Exception(
"'$dir' exists but is not writable."
);
}
} elseif (!@mkdir($dir, 0777, true)) {
throw new PHP_CodeCoverage_Exception(
"'$dir' could not be created."
);
}
}

private function processDirectory(PHP_CodeCoverage_Report_Node_Directory $directory, PHP_CodeCoverage_Report_XML_Node $context)
{
$dirObject = $context->addDirectory($directory->getName());

$this->setTotals($directory, $dirObject->getTotals());

foreach ($directory as $node) {
if ($node instanceof PHP_CodeCoverage_Report_Node_Directory) {
$this->processDirectory($node, $dirObject);
continue;
}

if ($node instanceof PHP_CodeCoverage_Report_Node_File) {
$this->processFile($node, $dirObject);
continue;
}

throw new PHP_CodeCoverage_Exception(
'Unknown node type for XML report'
);
}
}

private function processFile(PHP_CodeCoverage_Report_Node_File $file, PHP_CodeCoverage_Report_XML_Directory $context)
{
$fileObject = $context->addFile(
$file->getName(),
$file->getId() . '.xml'
);

$this->setTotals($file, $fileObject->getTotals());

$fileReport = new PHP_CodeCoverage_Report_XML_File_Report(
$file->getName()
);

$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($line);

foreach ($tests as $test) {
$coverage->addTest($test);
}

$coverage->finalize();
}

$this->initTargetDirectory(
$this->target . dirname($file->getId()) . '/'
);

$fileDom = $fileReport->asDom();
$fileDom->formatOutput = true;
$fileDom->preserveWhiteSpace = false;
$fileDom->save($this->target . $file->getId() . '.xml');
}

private function processUnit($unit, PHP_CodeCoverage_Report_XML_File_Report $report)
{
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($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($method['startLine'], $method['endLine']);
$methodObject->setCrap($method['crap']);
$methodObject->setTotals(
$method['executableLines'],
$method['executedLines'],
$method['coverage']
);
}
}

private function processFunction($function, PHP_CodeCoverage_Report_XML_File_Report $report)
{
$functionObject = $report->getFunctionObject($function['functionName']);

$functionObject->setSignature($function['signature']);
$functionObject->setLines($function['startLine']);
$functionObject->setCrap($function['crap']);
$functionObject->setTotals($function['executableLines'], $function['executedLines'], $function['coverage']);
}

private function processTests(array $tests)
{
$testsObject = $this->project->getTests();

foreach ($tests as $test => $result) {
if ($test == 'UNCOVERED_FILES_FROM_WHITELIST') {
continue;
}

$testsObject->addTest($test, $result);
}
}

private function setTotals(PHP_CodeCoverage_Report_Node $node, PHP_CodeCoverage_Report_XML_Totals $totals)
{
$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()
);
}
}
<?php












class PHP_CodeCoverage_Report_Crap4j
{



private $threshold;




public function __construct($threshold = 30)
{
if (!is_int($threshold)) {
throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(
1,
'integer'
);
}

$this->threshold = $threshold;
}







public function process(PHP_CodeCoverage $coverage, $target = null, $name = null)
{
$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', (int) $_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 PHP_CodeCoverage_Report_Node_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', $this->roundValue($method['crap'])));
$methodNode->appendChild($document->createElement('complexity', $method['ccn']));
$methodNode->appendChild($document->createElement('coverage', $this->roundValue($method['coverage'])));
$methodNode->appendChild($document->createElement('crapLoad', round($crapLoad)));

$methodsNode->appendChild($methodNode);
}
}
}

$stats->appendChild($document->createElement('name', 'Method Crap Stats'));
$stats->appendChild($document->createElement('methodCount', $fullMethodCount));
$stats->appendChild($document->createElement('crapMethodCount', $fullCrapMethodCount));
$stats->appendChild($document->createElement('crapLoad', round($fullCrapLoad)));
$stats->appendChild($document->createElement('totalCrap', $fullCrap));

if ($fullMethodCount > 0) {
$crapMethodPercent = $this->roundValue((100 * $fullCrapMethodCount) / $fullMethodCount);
} else {
$crapMethodPercent = 0;
}

$stats->appendChild($document->createElement('crapMethodPercent', $crapMethodPercent));

$root->appendChild($stats);
$root->appendChild($methodsNode);

if ($target !== null) {
if (!is_dir(dirname($target))) {
mkdir(dirname($target), 0777, true);
}

return $document->save($target);
} else {
return $document->saveXML();
}
}







private function getCrapLoad($crapValue, $cyclomaticComplexity, $coveragePercent)
{
$crapLoad = 0;

if ($crapValue >= $this->threshold) {
$crapLoad += $cyclomaticComplexity * (1.0 - $coveragePercent / 100);
$crapLoad += $cyclomaticComplexity / $this->threshold;
}

return $crapLoad;
}





private function roundValue($value)
{
return round($value, 2);
}
}
<?php














class PHP_CodeCoverage_Util
{





public static function percent($a, $b, $asString = false, $fixedWidth = false)
{
if ($asString && $b == 0) {
return '';
}

if ($b > 0) {
$percent = ($a / $b) * 100;
} else {
$percent = 100;
}

if ($asString) {
if ($fixedWidth) {
return sprintf('%6.2F%%', $percent);
}

return sprintf('%01.2F%%', $percent);
} else {
return $percent;
}
}
}
<?php














class PHP_CodeCoverage_Exception_UnintentionallyCoveredCode extends PHP_CodeCoverage_Exception
{
}
<?php














class PHP_CodeCoverage_Exception extends RuntimeException
{
}
<?php















class PHP_CodeCoverage_Driver_Xdebug implements PHP_CodeCoverage_Driver
{



public function __construct()
{
if (!extension_loaded('xdebug')) {
throw new PHP_CodeCoverage_Exception('This driver requires Xdebug');
}

if (version_compare(phpversion('xdebug'), '2.2.0-dev', '>=') &&
!ini_get('xdebug.coverage_enable')) {
throw new PHP_CodeCoverage_Exception(
'xdebug.coverage_enable=On has to be set in php.ini'
);
}
}




public function start()
{
xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE);
}






public function stop()
{
$data = xdebug_get_code_coverage();
xdebug_stop_code_coverage();

return $this->cleanup($data);
}






private function cleanup(array $data)
{
foreach (array_keys($data) as $file) {
unset($data[$file][0]);

if ($file != 'xdebug://debug-eval' && file_exists($file)) {
$numLines = $this->getNumberOfLinesInFile($file);

foreach (array_keys($data[$file]) as $line) {
if (isset($data[$file][$line]) && $line > $numLines) {
unset($data[$file][$line]);
}
}
}
}

return $data;
}






private function getNumberOfLinesInFile($file)
{
$buffer = file_get_contents($file);
$lines = substr_count($buffer, "\n");

if (substr($buffer, -1) !== "\n") {
$lines++;
}

return $lines;
}
}
<?php















class PHP_CodeCoverage_Driver_PHPDBG implements PHP_CodeCoverage_Driver
{



public function __construct()
{
if (PHP_SAPI !== 'phpdbg') {
throw new PHP_CodeCoverage_Exception(
'This driver requires the PHPDBG SAPI'
);
}

if (!function_exists('phpdbg_start_oplog')) {
throw new PHP_CodeCoverage_Exception(
'This build of PHPDBG does not support code coverage'
);
}
}




public function start()
{
phpdbg_start_oplog();
}






public function stop()
{
static $fetchedLines = array();

$dbgData = phpdbg_end_oplog();

if ($fetchedLines == array()) {
$sourceLines = phpdbg_get_executable();
} else {
$newFiles = array_diff(
get_included_files(),
array_keys($fetchedLines)
);

if ($newFiles) {
$sourceLines = phpdbg_get_executable(
array('files' => $newFiles)
);
} else {
$sourceLines = array();
}
}

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)
{
foreach ($dbgData as $file => $coveredLines) {
foreach ($coveredLines as $lineNo => $numExecuted) {

 
 if (isset($sourceLines[$file][$lineNo])) {
$sourceLines[$file][$lineNo] = self::LINE_EXECUTED;
}
}
}

return $sourceLines;
}
}
<?php















class PHP_CodeCoverage_Driver_HHVM extends PHP_CodeCoverage_Driver_Xdebug
{



public function start()
{
xdebug_start_code_coverage();
}
}
<?php









use SebastianBergmann\Environment\Runtime;






class PHP_CodeCoverage
{



private $driver;




private $filter;




private $cacheTokens = false;




private $checkForUnintentionallyCoveredCode = false;




private $forceCoversAnnotation = false;




private $mapTestClassNameToCoveredClassName = false;




private $addUncoveredFilesFromWhitelist = true;




private $processUncoveredFilesFromWhitelist = false;




private $currentId;






private $data = array();




private $ignoredLines = array();




private $disableIgnoredLines = false;






private $tests = array();








public function __construct(PHP_CodeCoverage_Driver $driver = null, PHP_CodeCoverage_Filter $filter = null)
{
if ($driver === null) {
$driver = $this->selectDriver();
}

if ($filter === null) {
$filter = new PHP_CodeCoverage_Filter;
}

$this->driver = $driver;
$this->filter = $filter;
}








public function getReport()
{
$factory = new PHP_CodeCoverage_Report_Factory;

return $factory->create($this);
}




public function clear()
{
$this->currentId = null;
$this->data = array();
$this->tests = array();
}






public function filter()
{
return $this->filter;
}









public function getData($raw = false)
{
if (!$raw && $this->addUncoveredFilesFromWhitelist) {
$this->addUncoveredFilesFromWhitelist();
}


 
 if (!$raw && !$this->filter->hasWhitelist()) {
$this->applyListsFilter($this->data);
}

return $this->data;
}







public function setData(array $data)
{
$this->data = $data;
}







public function getTests()
{
return $this->tests;
}







public function setTests(array $tests)
{
$this->tests = $tests;
}








public function start($id, $clear = false)
{
if (!is_bool($clear)) {
throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(
1,
'boolean'
);
}

if ($clear) {
$this->clear();
}

$this->currentId = $id;

$this->driver->start();
}










public function stop($append = true, $linesToBeCovered = array(), array $linesToBeUsed = array())
{
if (!is_bool($append)) {
throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(
1,
'boolean'
);
}

if (!is_array($linesToBeCovered) && $linesToBeCovered !== false) {
throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(
2,
'array or false'
);
}

$data = $this->driver->stop();
$this->append($data, null, $append, $linesToBeCovered, $linesToBeUsed);

$this->currentId = null;

return $data;
}











public function append(array $data, $id = null, $append = true, $linesToBeCovered = array(), array $linesToBeUsed = array())
{
if ($id === null) {
$id = $this->currentId;
}

if ($id === null) {
throw new PHP_CodeCoverage_Exception;
}

$this->applyListsFilter($data);
$this->applyIgnoredLinesFilter($data);
$this->initializeFilesThatAreSeenTheFirstTime($data);

if (!$append) {
return;
}

if ($id != 'UNCOVERED_FILES_FROM_WHITELIST') {
$this->applyCoversAnnotationFilter(
$data,
$linesToBeCovered,
$linesToBeUsed
);
}

if (empty($data)) {
return;
}

$size = 'unknown';
$status = null;

if ($id instanceof PHPUnit_Framework_TestCase) {
$_size = $id->getSize();

if ($_size == PHPUnit_Util_Test::SMALL) {
$size = 'small';
} elseif ($_size == PHPUnit_Util_Test::MEDIUM) {
$size = 'medium';
} elseif ($_size == PHPUnit_Util_Test::LARGE) {
$size = 'large';
}

$status = $id->getStatus();
$id = get_class($id) . '::' . $id->getName();
} elseif ($id instanceof PHPUnit_Extensions_PhptTestCase) {
$size = 'large';
$id = $id->getName();
}

$this->tests[$id] = array('size' => $size, 'status' => $status);

foreach ($data as $file => $lines) {
if (!$this->filter->isFile($file)) {
continue;
}

foreach ($lines as $k => $v) {
if ($v == PHP_CodeCoverage_Driver::LINE_EXECUTED) {
if (empty($this->data[$file][$k]) || !in_array($id, $this->data[$file][$k])) {
$this->data[$file][$k][] = $id;
}
}
}
}
}






public function merge(PHP_CodeCoverage $that)
{
$this->filter->setBlacklistedFiles(
array_merge($this->filter->getBlacklistedFiles(), $that->filter()->getBlacklistedFiles())
);

$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;
}

foreach ($lines as $line => $data) {
if ($data !== null) {
if (!isset($this->data[$file][$line])) {
$this->data[$file][$line] = $data;
} else {
$this->data[$file][$line] = array_unique(
array_merge($this->data[$file][$line], $data)
);
}
}
}
}

$this->tests = array_merge($this->tests, $that->getTests());

}






public function setCacheTokens($flag)
{
if (!is_bool($flag)) {
throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(
1,
'boolean'
);
}

$this->cacheTokens = $flag;
}




public function getCacheTokens()
{
return $this->cacheTokens;
}






public function setCheckForUnintentionallyCoveredCode($flag)
{
if (!is_bool($flag)) {
throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(
1,
'boolean'
);
}

$this->checkForUnintentionallyCoveredCode = $flag;
}





public function setForceCoversAnnotation($flag)
{
if (!is_bool($flag)) {
throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(
1,
'boolean'
);
}

$this->forceCoversAnnotation = $flag;
}





public function setMapTestClassNameToCoveredClassName($flag)
{
if (!is_bool($flag)) {
throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(
1,
'boolean'
);
}

$this->mapTestClassNameToCoveredClassName = $flag;
}





public function setAddUncoveredFilesFromWhitelist($flag)
{
if (!is_bool($flag)) {
throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(
1,
'boolean'
);
}

$this->addUncoveredFilesFromWhitelist = $flag;
}





public function setProcessUncoveredFilesFromWhitelist($flag)
{
if (!is_bool($flag)) {
throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(
1,
'boolean'
);
}

$this->processUncoveredFilesFromWhitelist = $flag;
}





public function setDisableIgnoredLines($flag)
{
if (!is_bool($flag)) {
throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(
1,
'boolean'
);
}

$this->disableIgnoredLines = $flag;
}









private function applyCoversAnnotationFilter(array &$data, $linesToBeCovered, array $linesToBeUsed)
{
if ($linesToBeCovered === false ||
($this->forceCoversAnnotation && empty($linesToBeCovered))) {
$data = array();

return;
}

if (empty($linesToBeCovered)) {
return;
}

if ($this->checkForUnintentionallyCoveredCode) {
$this->performUnintentionallyCoveredCodeCheck(
$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 applyListsFilter(array &$data)
{
foreach (array_keys($data) as $filename) {
if ($this->filter->isFiltered($filename)) {
unset($data[$filename]);
}
}
}






private function applyIgnoredLinesFilter(array &$data)
{
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)
{
foreach ($data as $file => $lines) {
if ($this->filter->isFile($file) && !isset($this->data[$file])) {
$this->data[$file] = array();

foreach ($lines as $k => $v) {
$this->data[$file][$k] = $v == -2 ? null : array();
}
}
}
}




private function addUncoveredFilesFromWhitelist()
{
$data = array();
$uncoveredFiles = array_diff(
$this->filter->getWhitelist(),
array_keys($this->data)
);

foreach ($uncoveredFiles as $uncoveredFile) {
if (!file_exists($uncoveredFile)) {
continue;
}

if ($this->processUncoveredFilesFromWhitelist) {
$this->processUncoveredFileFromWhitelist(
$uncoveredFile,
$data,
$uncoveredFiles
);
} else {
$data[$uncoveredFile] = array();

$lines = count(file($uncoveredFile));

for ($i = 1; $i <= $lines; $i++) {
$data[$uncoveredFile][$i] = PHP_CodeCoverage_Driver::LINE_NOT_EXECUTED;
}
}
}

$this->append($data, 'UNCOVERED_FILES_FROM_WHITELIST');
}






private function processUncoveredFileFromWhitelist($uncoveredFile, array &$data, array $uncoveredFiles)
{
$this->driver->start();
include_once $uncoveredFile;
$coverage = $this->driver->stop();

foreach ($coverage as $file => $fileCoverage) {
if (!isset($data[$file]) &&
in_array($file, $uncoveredFiles)) {
foreach (array_keys($fileCoverage) as $key) {
if ($fileCoverage[$key] == PHP_CodeCoverage_Driver::LINE_EXECUTED) {
$fileCoverage[$key] = PHP_CodeCoverage_Driver::LINE_NOT_EXECUTED;
}
}

$data[$file] = $fileCoverage;
}
}
}









private function getLinesToBeIgnored($filename)
{
if (!is_string($filename)) {
throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory(
1,
'string'
);
}

if (!isset($this->ignoredLines[$filename])) {
$this->ignoredLines[$filename] = array();

if ($this->disableIgnoredLines) {
return $this->ignoredLines[$filename];
}

$ignore = false;
$stop = false;
$lines = file($filename);
$numLines = count($lines);

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);
}

$classes = array_merge($tokens->getClasses(), $tokens->getTraits());
$tokens = $tokens->tokens();

foreach ($tokens as $token) {
switch (get_class($token)) {
case 'PHP_Token_COMMENT':
case 'PHP_Token_DOC_COMMENT':
$_token = trim($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($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':
case 'PHP_Token_TRAIT':
case 'PHP_Token_CLASS':
case 'PHP_Token_FUNCTION':
$docblock = $token->getDocblock();

$this->ignoredLines[$filename][] = $token->getLine();

if (strpos($docblock, '@codeCoverageIgnore') || strpos($docblock, '@deprecated')) {
$endLine = $token->getEndLine();

for ($i = $token->getLine(); $i <= $endLine; $i++) {
$this->ignoredLines[$filename][] = $i;
}
} elseif ($token instanceof PHP_Token_INTERFACE ||
$token instanceof PHP_Token_TRAIT ||
$token instanceof PHP_Token_CLASS) {
if (empty($classes[$token->getName()]['methods'])) {
for ($i = $token->getLine();
$i <= $token->getEndLine();
$i++) {
$this->ignoredLines[$filename][] = $i;
}
} else {
$firstMethod = array_shift(
$classes[$token->getName()]['methods']
);

do {
$lastMethod = array_pop(
$classes[$token->getName()]['methods']
);
} while ($lastMethod !== null &&
substr($lastMethod['signature'], 0, 18) == 'anonymous function');

if ($lastMethod === null) {
$lastMethod = $firstMethod;
}

for ($i = $token->getLine();
$i < $firstMethod['startLine'];
$i++) {
$this->ignoredLines[$filename][] = $i;
}

for ($i = $token->getEndLine();
$i > $lastMethod['endLine'];
$i--) {
$this->ignoredLines[$filename][] = $i;
}
}
}
break;

case 'PHP_Token_NAMESPACE':
$this->ignoredLines[$filename][] = $token->getEndLine();


 case 'PHP_Token_OPEN_TAG':
case 'PHP_Token_CLOSE_TAG':
case 'PHP_Token_USE':
$this->ignoredLines[$filename][] = $token->getLine();
break;
}

if ($ignore) {
$this->ignoredLines[$filename][] = $token->getLine();

if ($stop) {
$ignore = false;
$stop = false;
}
}
}

$this->ignoredLines[$filename][] = $numLines + 1;

$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)
{
$allowedLines = $this->getAllowedLines(
$linesToBeCovered,
$linesToBeUsed
);

$message = '';

foreach ($data as $file => $_data) {
foreach ($_data as $line => $flag) {
if ($flag == 1 &&
(!isset($allowedLines[$file]) ||
!isset($allowedLines[$file][$line]))) {
$message .= sprintf(
'- %s:%d' . PHP_EOL,
$file,
$line
);
}
}
}

if (!empty($message)) {
throw new PHP_CodeCoverage_Exception_UnintentionallyCoveredCode(
$message
);
}
}







private function getAllowedLines(array $linesToBeCovered, array $linesToBeUsed)
{
$allowedLines = array();

foreach (array_keys($linesToBeCovered) as $file) {
if (!isset($allowedLines[$file])) {
$allowedLines[$file] = array();
}

$allowedLines[$file] = array_merge(
$allowedLines[$file],
$linesToBeCovered[$file]
);
}

foreach (array_keys($linesToBeUsed) as $file) {
if (!isset($allowedLines[$file])) {
$allowedLines[$file] = array();
}

$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()
{
$runtime = new Runtime;

if (!$runtime->canCollectCodeCoverage()) {
throw new PHP_CodeCoverage_Exception('No code coverage driver available');
}

if ($runtime->isHHVM()) {
return new PHP_CodeCoverage_Driver_HHVM;
} elseif ($runtime->isPHPDBG()) {
return new PHP_CodeCoverage_Driver_PHPDBG;
} else {
return new PHP_CodeCoverage_Driver_Xdebug;
}
}
}
<?php
$coverage->stop();

$writer = new PHP_CodeCoverage_Report_HTML;
$writer->process($coverage, '/tmp/coverage');
<?php
require_once 'PHP/CodeCoverage/Autoload.php';

$coverage = new PHP_CodeCoverage;
$filter = $coverage->filter();

$filter->addFileToBlacklist(__FILE__);
$filter->addFileToBlacklist(dirname(__FILE__) . '/auto_append.php');

$coverage->start($_SERVER['SCRIPT_FILENAME']);

    {modifier} function {reference}{method_name}({arguments_decl})
    {
        $arguments = array({arguments_call});
        $count     = func_num_args();

        if ($count > {arguments_count}) {
            $_arguments = func_get_args();

            for ($i = {arguments_count}; $i < $count; $i++) {
                $arguments[] = $_arguments[$i];
            }
        }

        $this->__phpunit_getInvocationMocker()->invoke(
          new PHPUnit_Framework_MockObject_Invocation_Object(
            '{class_name}', '{method_name}', $arguments, $this, {clone_arguments}
          )
        );

        return call_user_func_array(array($this->__phpunit_originalObject, "{method_name}"), $arguments);
    }
{prologue}class {class_name}
{
    use {trait_name};
}

    {modifier} function {reference}{method_name}({arguments_decl})
    {
        throw new PHPUnit_Framework_MockObject_BadMethodCallException;
    }
    public function __clone()
    {
        $this->__phpunit_invocationMocker = clone $this->__phpunit_getInvocationMocker();
    }
{prologue}{class_declaration}
{
    private $__phpunit_invocationMocker;
    private $__phpunit_originalObject;

{clone}{mocked_methods}
    public function expects(PHPUnit_Framework_MockObject_Matcher_Invocation $matcher)
    {
        return $this->__phpunit_getInvocationMocker()->expects($matcher);
    }
{method}
    public function __phpunit_setOriginalObject($originalObject)
    {
        $this->__phpunit_originalObject = $originalObject;
    }

    public function __phpunit_getInvocationMocker()
    {
        if ($this->__phpunit_invocationMocker === NULL) {
            $this->__phpunit_invocationMocker = new PHPUnit_Framework_MockObject_InvocationMocker;
        }

        return $this->__phpunit_invocationMocker;
    }

    public function __phpunit_hasMatchers()
    {
        return $this->__phpunit_getInvocationMocker()->hasMatchers();
    }

    public function __phpunit_verify()
    {
        $this->__phpunit_getInvocationMocker()->verify();
        $this->__phpunit_invocationMocker = NULL;
    }
}{epilogue}

    public function method()
    {
        $any = new PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount;
        $expects = $this->expects($any);
        return call_user_func_array(array($expects, 'method'), func_get_args());
    }

    {modifier} function {reference}{method_name}({arguments_decl})
    {
        $arguments = array({arguments_call});
        $count     = func_num_args();

        if ($count > {arguments_count}) {
            $_arguments = func_get_args();

            for ($i = {arguments_count}; $i < $count; $i++) {
                $arguments[] = $_arguments[$i];
            }
        }

        $result = $this->__phpunit_getInvocationMocker()->invoke(
          new PHPUnit_Framework_MockObject_Invocation_Object(
            '{class_name}', '{method_name}', $arguments, $this, {clone_arguments}
          )
        );

        return $result;
    }

    public function {method_name}({arguments})
    {
    }
{namespace}class {class_name} extends \SoapClient
{
    public function __construct($wsdl, array $options)
    {
        parent::__construct('{wsdl}', $options);
    }
{methods}}
    public function __clone()
    {
        $this->__phpunit_invocationMocker = clone $this->__phpunit_getInvocationMocker();
        parent::__clone();
    }
<?php
















interface PHPUnit_Framework_MockObject_Builder_Namespace
{






public function lookupId($id);











public function registerId($id, PHPUnit_Framework_MockObject_Builder_Match $builder);
}
<?php



















class PHPUnit_Framework_MockObject_Builder_InvocationMocker implements PHPUnit_Framework_MockObject_Builder_MethodNameMatch
{



protected $collection;




protected $matcher;





public function __construct(PHPUnit_Framework_MockObject_Stub_MatcherCollection $collection, PHPUnit_Framework_MockObject_Matcher_Invocation $invocationMatcher)
{
$this->collection = $collection;
$this->matcher = new PHPUnit_Framework_MockObject_Matcher(
$invocationMatcher
);

$this->collection->addMatcher($this->matcher);
}




public function getMatcher()
{
return $this->matcher;
}





public function id($id)
{
$this->collection->registerId($id, $this);

return $this;
}





public function will(PHPUnit_Framework_MockObject_Stub $stub)
{
$this->matcher->stub = $stub;

return $this;
}





public function willReturn($value)
{
$stub = new PHPUnit_Framework_MockObject_Stub_Return(
$value
);

return $this->will($stub);
}





public function willReturnMap(array $valueMap)
{
$stub = new PHPUnit_Framework_MockObject_Stub_ReturnValueMap(
$valueMap
);

return $this->will($stub);
}





public function willReturnArgument($argumentIndex)
{
$stub = new PHPUnit_Framework_MockObject_Stub_ReturnArgument(
$argumentIndex
);

return $this->will($stub);
}





public function willReturnCallback($callback)
{
$stub = new PHPUnit_Framework_MockObject_Stub_ReturnCallback(
$callback
);

return $this->will($stub);
}




public function willReturnSelf()
{
$stub = new PHPUnit_Framework_MockObject_Stub_ReturnSelf();

return $this->will($stub);
}





public function willReturnOnConsecutiveCalls()
{
$args = func_get_args();

$stub = new PHPUnit_Framework_MockObject_Stub_ConsecutiveCalls($args);

return $this->will($stub);
}





public function willThrowException(Exception $exception)
{
$stub = new PHPUnit_Framework_MockObject_Stub_Exception($exception);

return $this->will($stub);
}





public function after($id)
{
$this->matcher->afterMatchBuilderId = $id;

return $this;
}






private function canDefineParameters()
{
if ($this->matcher->methodNameMatcher === null) {
throw new PHPUnit_Framework_Exception(
'Method name matcher is not defined, cannot define parameter ' .
' matcher without one'
);
}

if ($this->matcher->parametersMatcher !== null) {
throw new PHPUnit_Framework_Exception(
'Parameter matcher is already defined, cannot redefine'
);
}
}





public function with()
{
$args = func_get_args();

$this->canDefineParameters();

$this->matcher->parametersMatcher = new PHPUnit_Framework_MockObject_Matcher_Parameters($args);

return $this;
}





public function withConsecutive()
{

$args = func_get_args();

$this->canDefineParameters();

$this->matcher->parametersMatcher =
new PHPUnit_Framework_MockObject_Matcher_ConsecutiveParameters($args);

return $this;
}




public function withAnyParameters()
{
$this->canDefineParameters();

$this->matcher->parametersMatcher = new PHPUnit_Framework_MockObject_Matcher_AnyParameters;

return $this;
}





public function method($constraint)
{
if ($this->matcher->methodNameMatcher !== null) {
throw new PHPUnit_Framework_Exception(
'Method name matcher is already defined, cannot redefine'
);
}

$this->matcher->methodNameMatcher = new PHPUnit_Framework_MockObject_Matcher_MethodName($constraint);

return $this;
}
}
<?php














interface PHPUnit_Framework_MockObject_Builder_Match extends PHPUnit_Framework_MockObject_Builder_Stub
{







public function after($id);
}
<?php



















interface PHPUnit_Framework_MockObject_Builder_Identity
{






public function id($id);
}
<?php














interface PHPUnit_Framework_MockObject_Builder_MethodNameMatch extends PHPUnit_Framework_MockObject_Builder_ParametersMatch
{









public function method($name);
}
<?php














interface PHPUnit_Framework_MockObject_Builder_Stub extends PHPUnit_Framework_MockObject_Builder_Identity
{







public function will(PHPUnit_Framework_MockObject_Stub $stub);
}
<?php














interface PHPUnit_Framework_MockObject_Builder_ParametersMatch extends PHPUnit_Framework_MockObject_Builder_Match
{

















public function with();












public function withAnyParameters();
}
<?php




















class PHPUnit_Framework_MockObject_Matcher implements PHPUnit_Framework_MockObject_Matcher_Invocation
{



public $invocationMatcher;




public $afterMatchBuilderId = null;




public $afterMatchBuilderIsInvoked = false;




public $methodNameMatcher = null;




public $parametersMatcher = null;




public $stub = null;




public function __construct(PHPUnit_Framework_MockObject_Matcher_Invocation $invocationMatcher)
{
$this->invocationMatcher = $invocationMatcher;
}




public function toString()
{
$list = array();

if ($this->invocationMatcher !== null) {
$list[] = $this->invocationMatcher->toString();
}

if ($this->methodNameMatcher !== null) {
$list[] = 'where ' . $this->methodNameMatcher->toString();
}

if ($this->parametersMatcher !== null) {
$list[] = 'and ' . $this->parametersMatcher->toString();
}

if ($this->afterMatchBuilderId !== null) {
$list[] = 'after ' . $this->afterMatchBuilderId;
}

if ($this->stub !== null) {
$list[] = 'will ' . $this->stub->toString();
}

return implode(' ', $list);
}





public function invoked(PHPUnit_Framework_MockObject_Invocation $invocation)
{
if ($this->invocationMatcher === null) {
throw new PHPUnit_Framework_Exception(
'No invocation matcher is set'
);
}

if ($this->methodNameMatcher === null) {
throw new PHPUnit_Framework_Exception('No method matcher is set');
}

if ($this->afterMatchBuilderId !== null) {
$builder = $invocation->object
->__phpunit_getInvocationMocker()
->lookupId($this->afterMatchBuilderId);

if (!$builder) {
throw new PHPUnit_Framework_Exception(
sprintf(
'No builder found for match builder identification <%s>',
$this->afterMatchBuilderId
)
);
}

$matcher = $builder->getMatcher();

if ($matcher && $matcher->invocationMatcher->hasBeenInvoked()) {
$this->afterMatchBuilderIsInvoked = true;
}
}

$this->invocationMatcher->invoked($invocation);

try {
if ($this->parametersMatcher !== null &&
!$this->parametersMatcher->matches($invocation)) {
$this->parametersMatcher->verify();
}
} catch (PHPUnit_Framework_ExpectationFailedException $e) {
throw new PHPUnit_Framework_ExpectationFailedException(
sprintf(
"Expectation failed for %s when %s\n%s",
$this->methodNameMatcher->toString(),
$this->invocationMatcher->toString(),
$e->getMessage()
),
$e->getComparisonFailure()
);
}

if ($this->stub) {
return $this->stub->invoke($invocation);
}

return;
}





public function matches(PHPUnit_Framework_MockObject_Invocation $invocation)
{
if ($this->afterMatchBuilderId !== null) {
$builder = $invocation->object
->__phpunit_getInvocationMocker()
->lookupId($this->afterMatchBuilderId);

if (!$builder) {
throw new PHPUnit_Framework_Exception(
sprintf(
'No builder found for match builder identification <%s>',
$this->afterMatchBuilderId
)
);
}

$matcher = $builder->getMatcher();

if (!$matcher) {
return false;
}

if (!$matcher->invocationMatcher->hasBeenInvoked()) {
return false;
}
}

if ($this->invocationMatcher === null) {
throw new PHPUnit_Framework_Exception(
'No invocation matcher is set'
);
}

if ($this->methodNameMatcher === null) {
throw new PHPUnit_Framework_Exception('No method matcher is set');
}

if (!$this->invocationMatcher->matches($invocation)) {
return false;
}

try {
if (!$this->methodNameMatcher->matches($invocation)) {
return false;
}
} catch (PHPUnit_Framework_ExpectationFailedException $e) {
throw new PHPUnit_Framework_ExpectationFailedException(
sprintf(
"Expectation failed for %s when %s\n%s",
$this->methodNameMatcher->toString(),
$this->invocationMatcher->toString(),
$e->getMessage()
),
$e->getComparisonFailure()
);
}

return true;
}





public function verify()
{
if ($this->invocationMatcher === null) {
throw new PHPUnit_Framework_Exception(
'No invocation matcher is set'
);
}

if ($this->methodNameMatcher === null) {
throw new PHPUnit_Framework_Exception('No method matcher is set');
}

try {
$this->invocationMatcher->verify();

if ($this->parametersMatcher === null) {
$this->parametersMatcher = new PHPUnit_Framework_MockObject_Matcher_AnyParameters;
}

$invocationIsAny = get_class($this->invocationMatcher) === 'PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount';
$invocationIsNever = get_class($this->invocationMatcher) === 'PHPUnit_Framework_MockObject_Matcher_InvokedCount' && $this->invocationMatcher->isNever();
if (!$invocationIsAny && !$invocationIsNever) {
$this->parametersMatcher->verify();
}
} catch (PHPUnit_Framework_ExpectationFailedException $e) {
throw new PHPUnit_Framework_ExpectationFailedException(
sprintf(
"Expectation failed for %s when %s.\n%s",
$this->methodNameMatcher->toString(),
$this->invocationMatcher->toString(),
PHPUnit_Framework_TestFailure::exceptionToString($e)
)
);
}
}




public function hasMatchers()
{
if ($this->invocationMatcher !== null &&
!$this->invocationMatcher instanceof PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount) {
return true;
}

return false;
}
}
<?php


















class PHPUnit_Framework_MockObject_InvocationMocker implements PHPUnit_Framework_MockObject_Stub_MatcherCollection, PHPUnit_Framework_MockObject_Invokable, PHPUnit_Framework_MockObject_Builder_Namespace
{



protected $matchers = array();




protected $builderMap = array();




public function addMatcher(PHPUnit_Framework_MockObject_Matcher_Invocation $matcher)
{
$this->matchers[] = $matcher;
}




public function hasMatchers()
{
foreach ($this->matchers as $matcher) {
if ($matcher->hasMatchers()) {
return true;
}
}

return false;
}





public function lookupId($id)
{
if (isset($this->builderMap[$id])) {
return $this->builderMap[$id];
}

return;
}






public function registerId($id, PHPUnit_Framework_MockObject_Builder_Match $builder)
{
if (isset($this->builderMap[$id])) {
throw new PHPUnit_Framework_Exception(
'Match builder with id <' . $id . '> is already registered.'
);
}

$this->builderMap[$id] = $builder;
}





public function expects(PHPUnit_Framework_MockObject_Matcher_Invocation $matcher)
{
return new PHPUnit_Framework_MockObject_Builder_InvocationMocker(
$this,
$matcher
);
}





public function invoke(PHPUnit_Framework_MockObject_Invocation $invocation)
{
$exception = null;
$hasReturnValue = false;

if (strtolower($invocation->methodName) == '__tostring') {
$returnValue = '';
} else {
$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;
}

return $returnValue;
}





public function matches(PHPUnit_Framework_MockObject_Invocation $invocation)
{
foreach ($this->matchers as $matcher) {
if (!$matcher->matches($invocation)) {
return false;
}
}

return true;
}




public function verify()
{
foreach ($this->matchers as $matcher) {
$matcher->verify();
}
}
}
<?php
















interface PHPUnit_Framework_MockObject_MockObject 
{







public function expects(PHPUnit_Framework_MockObject_Matcher_Invocation $matcher);





public function __phpunit_setOriginalObject($originalObject);




public function __phpunit_getInvocationMocker();







public function __phpunit_verify();
}
<?php















class PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount extends PHPUnit_Framework_MockObject_Matcher_InvokedRecorder
{



public function toString()
{
return 'invoked zero or more times';
}



public function verify()
{
}
}
<?php















class PHPUnit_Framework_MockObject_Matcher_InvokedAtLeastCount extends PHPUnit_Framework_MockObject_Matcher_InvokedRecorder
{



private $requiredInvocations;




public function __construct($requiredInvocations)
{
$this->requiredInvocations = $requiredInvocations;
}




public function toString()
{
return 'invoked at least ' . $this->requiredInvocations . ' times';
}







public function verify()
{
$count = $this->getInvocationCount();

if ($count < $this->requiredInvocations) {
throw new PHPUnit_Framework_ExpectationFailedException(
'Expected invocation at least ' . $this->requiredInvocations .
' times but it occured ' . $count . ' time(s).'
);
}
}
}
<?php



















class PHPUnit_Framework_MockObject_Matcher_InvokedCount extends PHPUnit_Framework_MockObject_Matcher_InvokedRecorder
{



protected $expectedCount;




public function __construct($expectedCount)
{
$this->expectedCount = $expectedCount;
}




public function isNever()
{
return $this->expectedCount == 0;
}




public function toString()
{
return 'invoked ' . $this->expectedCount . ' time(s)';
}





public function invoked(PHPUnit_Framework_MockObject_Invocation $invocation)
{
parent::invoked($invocation);

$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 PHPUnit_Framework_ExpectationFailedException($message);
}
}







public function verify()
{
$count = $this->getInvocationCount();

if ($count !== $this->expectedCount) {
throw new PHPUnit_Framework_ExpectationFailedException(
sprintf(
'Method was expected to be called %d times, ' .
'actually called %d times.',
$this->expectedCount,
$count
)
);
}
}
}
<?php



















abstract class PHPUnit_Framework_MockObject_Matcher_StatelessInvocation implements PHPUnit_Framework_MockObject_Matcher_Invocation
{
















public function invoked(PHPUnit_Framework_MockObject_Invocation $invocation)
{
}











public function verify()
{
}
}
<?php


















class PHPUnit_Framework_MockObject_Matcher_MethodName extends PHPUnit_Framework_MockObject_Matcher_StatelessInvocation
{



protected $constraint;





public function __construct($constraint)
{
if (!$constraint instanceof PHPUnit_Framework_Constraint) {
if (!is_string($constraint)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

$constraint = new PHPUnit_Framework_Constraint_IsEqual(
$constraint,
0,
10,
false,
true
);
}

$this->constraint = $constraint;
}




public function toString()
{
return 'method name ' . $this->constraint->toString();
}





public function matches(PHPUnit_Framework_MockObject_Invocation $invocation)
{
return $this->constraint->evaluate($invocation->methodName, '', true);
}
}
<?php


















abstract class PHPUnit_Framework_MockObject_Matcher_InvokedRecorder implements PHPUnit_Framework_MockObject_Matcher_Invocation
{



protected $invocations = array();




public function getInvocationCount()
{
return count($this->invocations);
}




public function getInvocations()
{
return $this->invocations;
}




public function hasBeenInvoked()
{
return count($this->invocations) > 0;
}




public function invoked(PHPUnit_Framework_MockObject_Invocation $invocation)
{
$this->invocations[] = $invocation;
}





public function matches(PHPUnit_Framework_MockObject_Invocation $invocation)
{
return true;
}
}
<?php















class PHPUnit_Framework_MockObject_Matcher_InvokedAtMostCount extends PHPUnit_Framework_MockObject_Matcher_InvokedRecorder
{



private $allowedInvocations;




public function __construct($allowedInvocations)
{
$this->allowedInvocations = $allowedInvocations;
}




public function toString()
{
return 'invoked at most ' . $this->allowedInvocations . ' times';
}







public function verify()
{
$count = $this->getInvocationCount();

if ($count > $this->allowedInvocations) {
throw new PHPUnit_Framework_ExpectationFailedException(
'Expected invocation at most ' . $this->allowedInvocations .
' times but it occured ' . $count . ' time(s).'
);
}
}
}
<?php



















class PHPUnit_Framework_MockObject_Matcher_ConsecutiveParameters extends PHPUnit_Framework_MockObject_Matcher_StatelessInvocation
{



private $_parameterGroups = array();




private $_invocations = array();




public function __construct(array $parameterGroups)
{
foreach ($parameterGroups as $index => $parameters) {
foreach ($parameters as $parameter) {
if (!($parameter instanceof \PHPUnit_Framework_Constraint)) {
$parameter = new \PHPUnit_Framework_Constraint_IsEqual($parameter);
}
$this->_parameterGroups[$index][] = $parameter;
}
}
}




public function toString()
{
$text = 'with consecutive parameters';

return $text;
}





public function matches(PHPUnit_Framework_MockObject_Invocation $invocation)
{
$this->_invocations[] = $invocation;
$callIndex = count($this->_invocations) - 1;
$this->verifyInvocation($invocation, $callIndex);

return false;
}

public function verify()
{
foreach ($this->_invocations as $callIndex => $invocation) {
$this->verifyInvocation($invocation, $callIndex);
}
}








private function verifyInvocation(PHPUnit_Framework_MockObject_Invocation $invocation, $callIndex)
{

if (isset($this->_parameterGroups[$callIndex])) {
$parameters = $this->_parameterGroups[$callIndex];
} else {

 return;
}

if ($invocation === null) {
throw new PHPUnit_Framework_ExpectationFailedException(
'Mocked method does not exist.'
);
}

if (count($invocation->parameters) < count($parameters)) {
throw new PHPUnit_Framework_ExpectationFailedException(
sprintf(
'Parameter count for invocation %s is too low.',
$invocation->toString()
)
);
}

foreach ($parameters as $i => $parameter) {
$parameter->evaluate(
$invocation->parameters[$i],
sprintf(
'Parameter %s for invocation #%d %s does not match expected ' .
'value.',
$i,
$callIndex,
$invocation->toString()
)
);
}
}
}
<?php















interface PHPUnit_Framework_MockObject_Matcher_Invocation extends PHPUnit_Framework_SelfDescribing, PHPUnit_Framework_MockObject_Verifiable
{
















public function invoked(PHPUnit_Framework_MockObject_Invocation $invocation);











public function matches(PHPUnit_Framework_MockObject_Invocation $invocation);
}
<?php

















class PHPUnit_Framework_MockObject_Matcher_InvokedAtLeastOnce extends PHPUnit_Framework_MockObject_Matcher_InvokedRecorder
{



public function toString()
{
return 'invoked at least once';
}







public function verify()
{
$count = $this->getInvocationCount();

if ($count < 1) {
throw new PHPUnit_Framework_ExpectationFailedException(
'Expected invocation at least once but it never occured.'
);
}
}
}
<?php


















class PHPUnit_Framework_MockObject_Matcher_Parameters extends PHPUnit_Framework_MockObject_Matcher_StatelessInvocation
{



protected $parameters = array();




protected $invocation;




public function __construct(array $parameters)
{
foreach ($parameters as $parameter) {
if (!($parameter instanceof PHPUnit_Framework_Constraint)) {
$parameter = new PHPUnit_Framework_Constraint_IsEqual(
$parameter
);
}

$this->parameters[] = $parameter;
}
}




public function toString()
{
$text = 'with parameter';

foreach ($this->parameters as $index => $parameter) {
if ($index > 0) {
$text .= ' and';
}

$text .= ' ' . $index . ' ' . $parameter->toString();
}

return $text;
}





public function matches(PHPUnit_Framework_MockObject_Invocation $invocation)
{
$this->invocation = $invocation;

return $this->verify();
}












public function verify()
{
if ($this->invocation === null) {
throw new PHPUnit_Framework_ExpectationFailedException(
'Mocked method does not exist.'
);
}

if (count($this->invocation->parameters) < count($this->parameters)) {
$message = 'Parameter count for invocation %s is too low.';


 
 
 
 if (count($this->parameters) === 1 &&
get_class($this->parameters[0]) === 'PHPUnit_Framework_Constraint_IsAnything') {
$message .= "\nTo allow 0 or more parameters with any value, omit ->with() or use ->withAnyParameters() instead.";
}

throw new PHPUnit_Framework_ExpectationFailedException(
sprintf($message, $this->invocation->toString())
);
}

foreach ($this->parameters as $i => $parameter) {
$parameter->evaluate(
$this->invocation->parameters[$i],
sprintf(
'Parameter %s for invocation %s does not match expected ' .
'value.',
$i,
$this->invocation->toString()
)
);
}

return true;
}
}
<?php














class PHPUnit_Framework_MockObject_Matcher_AnyParameters extends PHPUnit_Framework_MockObject_Matcher_StatelessInvocation
{



public function toString()
{
return 'with any parameters';
}





public function matches(PHPUnit_Framework_MockObject_Invocation $invocation)
{
return true;
}
}
<?php





















class PHPUnit_Framework_MockObject_Matcher_InvokedAtIndex implements PHPUnit_Framework_MockObject_Matcher_Invocation
{



protected $sequenceIndex;




protected $currentIndex = -1;




public function __construct($sequenceIndex)
{
$this->sequenceIndex = $sequenceIndex;
}




public function toString()
{
return 'invoked at sequence index ' . $this->sequenceIndex;
}





public function matches(PHPUnit_Framework_MockObject_Invocation $invocation)
{
$this->currentIndex++;

return $this->currentIndex == $this->sequenceIndex;
}




public function invoked(PHPUnit_Framework_MockObject_Invocation $invocation)
{
}







public function verify()
{
if ($this->currentIndex < $this->sequenceIndex) {
throw new PHPUnit_Framework_ExpectationFailedException(
sprintf(
'The expected invocation at index %s was never reached.',
$this->sequenceIndex
)
);
}
}
}
<?php














interface PHPUnit_Framework_MockObject_Invocation
{
}
<?php














class PHPUnit_Framework_MockObject_MockBuilder
{



private $testCase;




private $type;




private $methods = array();




private $mockClassName = '';




private $constructorArgs = array();




private $originalConstructor = true;




private $originalClone = true;




private $autoload = true;




private $cloneArguments = false;




private $callOriginalMethods = false;




private $proxyTarget = null;





public function __construct(PHPUnit_Framework_TestCase $testCase, $type)
{
$this->testCase = $testCase;
$this->type = $type;
}






public function getMock()
{
return $this->testCase->getMock(
$this->type,
$this->methods,
$this->constructorArgs,
$this->mockClassName,
$this->originalConstructor,
$this->originalClone,
$this->autoload,
$this->cloneArguments,
$this->callOriginalMethods,
$this->proxyTarget
);
}






public function getMockForAbstractClass()
{
return $this->testCase->getMockForAbstractClass(
$this->type,
$this->constructorArgs,
$this->mockClassName,
$this->originalConstructor,
$this->originalClone,
$this->autoload,
$this->methods,
$this->cloneArguments
);
}






public function getMockForTrait()
{
return $this->testCase->getMockForTrait(
$this->type,
$this->constructorArgs,
$this->mockClassName,
$this->originalConstructor,
$this->originalClone,
$this->autoload,
$this->methods,
$this->cloneArguments
);
}







public function setMethods($methods)
{
$this->methods = $methods;

return $this;
}







public function setConstructorArgs(array $args)
{
$this->constructorArgs = $args;

return $this;
}







public function setMockClassName($name)
{
$this->mockClassName = $name;

return $this;
}






public function disableOriginalConstructor()
{
$this->originalConstructor = false;

return $this;
}







public function enableOriginalConstructor()
{
$this->originalConstructor = true;

return $this;
}






public function disableOriginalClone()
{
$this->originalClone = false;

return $this;
}







public function enableOriginalClone()
{
$this->originalClone = true;

return $this;
}






public function disableAutoload()
{
$this->autoload = false;

return $this;
}







public function enableAutoload()
{
$this->autoload = true;

return $this;
}







public function disableArgumentCloning()
{
$this->cloneArguments = false;

return $this;
}







public function enableArgumentCloning()
{
$this->cloneArguments = true;

return $this;
}







public function enableProxyingToOriginalMethods()
{
$this->callOriginalMethods = true;

return $this;
}







public function disableProxyingToOriginalMethods()
{
$this->callOriginalMethods = false;
$this->proxyTarget = null;

return $this;
}








public function setProxyTarget($object)
{
$this->proxyTarget = $object;

return $this;
}
}
<?php









use Doctrine\Instantiator\Instantiator;
use Doctrine\Instantiator\Exception\InvalidArgumentException as InstantiatorInvalidArgumentException;
use Doctrine\Instantiator\Exception\UnexpectedValueException as InstantiatorUnexpectedValueException;

if (!function_exists('trait_exists')) {
function trait_exists($traitname, $autoload = true)
{
return false;
}
}






class PHPUnit_Framework_MockObject_Generator
{



private static $cache = array();




protected $blacklistedMethodNames = array(
'__CLASS__' => true,
'__DIR__' => true,
'__FILE__' => true,
'__FUNCTION__' => true,
'__LINE__' => true,
'__METHOD__' => true,
'__NAMESPACE__' => true,
'__TRAIT__' => true,
'__clone' => true,
'__halt_compiler' => true,
'abstract' => true,
'and' => true,
'array' => true,
'as' => true,
'break' => true,
'callable' => true,
'case' => true,
'catch' => true,
'class' => true,
'clone' => true,
'const' => true,
'continue' => true,
'declare' => true,
'default' => true,
'die' => true,
'do' => true,
'echo' => true,
'else' => true,
'elseif' => true,
'empty' => true,
'enddeclare' => true,
'endfor' => true,
'endforeach' => true,
'endif' => true,
'endswitch' => true,
'endwhile' => true,
'eval' => true,
'exit' => true,
'expects' => true,
'extends' => true,
'final' => true,
'for' => true,
'foreach' => true,
'function' => true,
'global' => true,
'goto' => true,
'if' => true,
'implements' => true,
'include' => true,
'include_once' => true,
'instanceof' => true,
'insteadof' => true,
'interface' => true,
'isset' => true,
'list' => true,
'namespace' => true,
'new' => true,
'or' => true,
'print' => true,
'private' => true,
'protected' => true,
'public' => true,
'require' => true,
'require_once' => true,
'return' => true,
'static' => true,
'switch' => true,
'throw' => true,
'trait' => true,
'try' => true,
'unset' => true,
'use' => true,
'var' => true,
'while' => true,
'xor' => true
);




















public function getMock($type, $methods = array(), array $arguments = array(), $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $cloneArguments = true, $callOriginalMethods = false, $proxyTarget = null)
{
if (!is_array($type) && !is_string($type)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'array or string');
}

if (!is_string($mockClassName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(4, 'string');
}

if (!is_array($methods) && !is_null($methods)) {
throw new InvalidArgumentException;
}

if ($type === 'Traversable' || $type === '\\Traversable') {
$type = 'Iterator';
}

if (is_array($type)) {
$type = array_unique(array_map(
function ($type) {
if ($type === 'Traversable' ||
$type === '\\Traversable' ||
$type === '\\Iterator') {
return 'Iterator';
}

return $type;
},
$type
));
}

if (null !== $methods) {
foreach ($methods as $method) {
if (!preg_match('~[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*~', $method)) {
throw new PHPUnit_Framework_Exception(
sprintf(
'Cannot stub or mock method with invalid name "%s"',
$method
)
);
}
}

if ($methods != array_unique($methods)) {
throw new PHPUnit_Framework_MockObject_RuntimeException(
sprintf(
'Cannot stub or mock using a method list that contains duplicates: "%s"',
implode(', ', $methods)
)
);
}
}

if ($mockClassName != '' && class_exists($mockClassName, false)) {
$reflect = new ReflectionClass($mockClassName);

if (!$reflect->implementsInterface('PHPUnit_Framework_MockObject_MockObject')) {
throw new PHPUnit_Framework_MockObject_RuntimeException(
sprintf(
'Class "%s" already exists.',
$mockClassName
)
);
}
}

$mock = $this->generate(
$type,
$methods,
$mockClassName,
$callOriginalClone,
$callAutoload,
$cloneArguments,
$callOriginalMethods
);

return $this->getObject(
$mock['code'],
$mock['mockClassName'],
$type,
$callOriginalConstructor,
$callAutoload,
$arguments,
$callOriginalMethods,
$proxyTarget
);
}












protected function getObject($code, $className, $type = '', $callOriginalConstructor = false, $callAutoload = false, array $arguments = array(), $callOriginalMethods = false, $proxyTarget = null)
{
$this->evalClass($code, $className);

if ($callOriginalConstructor &&
is_string($type) &&
!interface_exists($type, $callAutoload)) {
if (count($arguments) == 0) {
$object = new $className;
} else {
$class = new ReflectionClass($className);
$object = $class->newInstanceArgs($arguments);
}
} else {
try {
$instantiator = new Instantiator;
$object = $instantiator->instantiate($className);
} catch (InstantiatorUnexpectedValueException $exception) {
if ($exception->getPrevious()) {
$exception = $exception->getPrevious();
}

throw new PHPUnit_Framework_MockObject_RuntimeException(
$exception->getMessage()
);
} catch (InstantiatorInvalidArgumentException $exception) {
throw new PHPUnit_Framework_MockObject_RuntimeException(
$exception->getMessage()
);
}
}

if ($callOriginalMethods) {
if (!is_object($proxyTarget)) {
if (count($arguments) == 0) {
$proxyTarget = new $type;
} else {
$class = new ReflectionClass($type);
$proxyTarget = $class->newInstanceArgs($arguments);
}
}

$object->__phpunit_setOriginalObject($proxyTarget);
}

return $object;
}





protected function evalClass($code, $className)
{
if (!class_exists($className, false)) {
eval($code);
}
}



















public function getMockForAbstractClass($originalClassName, array $arguments = array(), $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $mockedMethods = array(), $cloneArguments = true)
{
if (!is_string($originalClassName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

if (!is_string($mockClassName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(3, 'string');
}

if (class_exists($originalClassName, $callAutoload) ||
interface_exists($originalClassName, $callAutoload)) {
$reflector = new ReflectionClass($originalClassName);
$methods = $mockedMethods;

foreach ($reflector->getMethods() as $method) {
if ($method->isAbstract() && !in_array($method->getName(), $methods)) {
$methods[] = $method->getName();
}
}

if (empty($methods)) {
$methods = null;
}

return $this->getMock(
$originalClassName,
$methods,
$arguments,
$mockClassName,
$callOriginalConstructor,
$callOriginalClone,
$callAutoload,
$cloneArguments
);
} else {
throw new PHPUnit_Framework_MockObject_RuntimeException(
sprintf('Class "%s" does not exist.', $originalClassName)
);
}
}



















public function getMockForTrait($traitName, array $arguments = array(), $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $mockedMethods = array(), $cloneArguments = true)
{
if (!is_string($traitName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

if (!is_string($mockClassName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(3, 'string');
}

if (!trait_exists($traitName, $callAutoload)) {
throw new PHPUnit_Framework_MockObject_RuntimeException(
sprintf(
'Trait "%s" does not exist.',
$traitName
)
);
}

$className = $this->generateClassName(
$traitName,
'',
'Trait_'
);

$templateDir = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'Generator' .
DIRECTORY_SEPARATOR;
$classTemplate = new Text_Template(
$templateDir . 'trait_class.tpl'
);

$classTemplate->setVar(
array(
'prologue' => 'abstract ',
'class_name' => $className['className'],
'trait_name' => $traitName
)
);

$this->evalClass(
$classTemplate->render(),
$className['className']
);

return $this->getMockForAbstractClass($className['className'], $arguments, $mockClassName, $callOriginalConstructor, $callOriginalClone, $callAutoload, $mockedMethods, $cloneArguments);
}















public function getObjectForTrait($traitName, array $arguments = array(), $traitClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true)
{
if (!is_string($traitName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}

if (!is_string($traitClassName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(3, 'string');
}

if (!trait_exists($traitName, $callAutoload)) {
throw new PHPUnit_Framework_MockObject_RuntimeException(
sprintf(
'Trait "%s" does not exist.',
$traitName
)
);
}

$className = $this->generateClassName(
$traitName,
$traitClassName,
'Trait_'
);

$templateDir = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'Generator' .
DIRECTORY_SEPARATOR;
$classTemplate = new Text_Template(
$templateDir . 'trait_class.tpl'
);

$classTemplate->setVar(
array(
'prologue' => '',
'class_name' => $className['className'],
'trait_name' => $traitName
)
);

return $this->getObject(
$classTemplate->render(),
$className['className']
);
}











public function generate($type, array $methods = null, $mockClassName = '', $callOriginalClone = true, $callAutoload = true, $cloneArguments = true, $callOriginalMethods = false)
{
if (is_array($type)) {
sort($type);
}

if ($mockClassName == '') {
$key = md5(
is_array($type) ? implode('_', $type) : $type .
serialize($methods) .
serialize($callOriginalClone) .
serialize($cloneArguments) .
serialize($callOriginalMethods)
);

if (isset(self::$cache[$key])) {
return self::$cache[$key];
}
}

$mock = $this->generateMock(
$type,
$methods,
$mockClassName,
$callOriginalClone,
$callAutoload,
$cloneArguments,
$callOriginalMethods
);

if (isset($key)) {
self::$cache[$key] = $mock;
}

return $mock;
}









public function generateClassFromWsdl($wsdlFile, $className, array $methods = array(), array $options = array())
{
if (!extension_loaded('soap')) {
throw new PHPUnit_Framework_MockObject_RuntimeException(
'The SOAP extension is required to generate a mock object from WSDL.'
);
}

$options = array_merge($options, array('cache_wsdl' => WSDL_CACHE_NONE));
$client = new SoapClient($wsdlFile, $options);
$_methods = array_unique($client->__getFunctions());
unset($client);

sort($_methods);

$templateDir = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'Generator' . DIRECTORY_SEPARATOR;
$methodTemplate = new Text_Template($templateDir . 'wsdl_method.tpl');
$methodsBuffer = '';

foreach ($_methods as $method) {
$nameStart = strpos($method, ' ') + 1;
$nameEnd = strpos($method, '(');
$name = substr($method, $nameStart, $nameEnd - $nameStart);

if (empty($methods) || in_array($name, $methods)) {
$args = explode(
',',
substr(
$method,
$nameEnd + 1,
strpos($method, ')') - $nameEnd - 1
)
);
$numArgs = count($args);

for ($i = 0; $i < $numArgs; $i++) {
$args[$i] = substr($args[$i], strpos($args[$i], '$'));
}

$methodTemplate->setVar(
array(
'method_name' => $name,
'arguments' => implode(', ', $args)
)
);

$methodsBuffer .= $methodTemplate->render();
}
}

$optionsBuffer = 'array(';

foreach ($options as $key => $value) {
$optionsBuffer .= $key . ' => ' . $value;
}

$optionsBuffer .= ')';

$classTemplate = new Text_Template($templateDir . 'wsdl_class.tpl');
$namespace = '';

if (strpos($className, '\\') !== false) {
$parts = explode('\\', $className);
$className = array_pop($parts);
$namespace = 'namespace ' . implode('\\', $parts) . ';' . "\n\n";
}

$classTemplate->setVar(
array(
'namespace' => $namespace,
'class_name' => $className,
'wsdl' => $wsdlFile,
'options' => $optionsBuffer,
'methods' => $methodsBuffer
)
);

return $classTemplate->render();
}












protected function generateMock($type, $methods, $mockClassName, $callOriginalClone, $callAutoload, $cloneArguments, $callOriginalMethods)
{
$templateDir = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'Generator' .
DIRECTORY_SEPARATOR;
$classTemplate = new Text_Template(
$templateDir . 'mocked_class.tpl'
);

$additionalInterfaces = array();
$cloneTemplate = '';
$isClass = false;
$isInterface = false;

$mockClassName = $this->generateClassName(
$type,
$mockClassName,
'Mock_'
);

if (is_array($type)) {
foreach ($type as $_type) {
if (!interface_exists($_type, $callAutoload)) {
throw new PHPUnit_Framework_Exception(
sprintf(
'Interface "%s" does not exist.',
$_type
)
);
}

$additionalInterfaces[] = $_type;

foreach ($this->getClassMethods($_type) as $method) {
if (in_array($method, $methods)) {
throw new PHPUnit_Framework_Exception(
sprintf(
'Duplicate method "%s" not allowed.',
$method
)
);
}

$methods[] = $method;
}
}
}

if (class_exists($mockClassName['fullClassName'], $callAutoload)) {
$isClass = true;
} else {
if (interface_exists($mockClassName['fullClassName'], $callAutoload)) {
$isInterface = true;
}
}

if (!class_exists($mockClassName['fullClassName'], $callAutoload) &&
!interface_exists($mockClassName['fullClassName'], $callAutoload)) {
$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}";
}

$cloneTemplate = new Text_Template(
$templateDir . 'mocked_clone.tpl'
);
} else {
$class = new ReflectionClass($mockClassName['fullClassName']);

if ($class->isFinal()) {
throw new PHPUnit_Framework_Exception(
sprintf(
'Class "%s" is declared "final" and cannot be mocked.',
$mockClassName['fullClassName']
)
);
}

if ($class->hasMethod('__clone')) {
$cloneMethod = $class->getMethod('__clone');

if (!$cloneMethod->isFinal()) {
if ($callOriginalClone && !$isInterface) {
$cloneTemplate = new Text_Template(
$templateDir . 'unmocked_clone.tpl'
);
} else {
$cloneTemplate = new Text_Template(
$templateDir . 'mocked_clone.tpl'
);
}
}
} else {
$cloneTemplate = new Text_Template(
$templateDir . 'mocked_clone.tpl'
);
}
}

if (is_object($cloneTemplate)) {
$cloneTemplate = $cloneTemplate->render();
}

if (is_array($methods) && empty($methods) &&
($isClass || $isInterface)) {
$methods = $this->getClassMethods($mockClassName['fullClassName']);
}

if (!is_array($methods)) {
$methods = array();
}

$mockedMethods = '';

if (isset($class)) {

 if ($isInterface && $class->implementsInterface('Traversable') &&
!$class->implementsInterface('Iterator') &&
!$class->implementsInterface('IteratorAggregate')) {
$additionalInterfaces[] = 'Iterator';
$methods = array_merge($methods, $this->getClassMethods('Iterator'));
}

foreach ($methods as $methodName) {
try {
$method = $class->getMethod($methodName);

if ($this->canMockMethod($method)) {
$mockedMethods .= $this->generateMockedMethodDefinitionFromExisting(
$templateDir,
$method,
$cloneArguments,
$callOriginalMethods
);
}
} catch (ReflectionException $e) {
$mockedMethods .= $this->generateMockedMethodDefinition(
$templateDir,
$mockClassName['fullClassName'],
$methodName,
$cloneArguments
);
}
}
} else {
foreach ($methods as $methodName) {
$mockedMethods .= $this->generateMockedMethodDefinition(
$templateDir,
$mockClassName['fullClassName'],
$methodName,
$cloneArguments
);
}
}

$method = '';

if (!in_array('method', $methods)) {
$methodTemplate = new Text_Template(
$templateDir . 'mocked_class_method.tpl'
);

$method = $methodTemplate->render();
}

$classTemplate->setVar(
array(
'prologue' => isset($prologue) ? $prologue : '',
'epilogue' => isset($epilogue) ? $epilogue : '',
'class_declaration' => $this->generateMockClassDeclaration(
$mockClassName,
$isInterface,
$additionalInterfaces
),
'clone' => $cloneTemplate,
'mock_class_name' => $mockClassName['className'],
'mocked_methods' => $mockedMethods,
'method' => $method
)
);

return array(
'code' => $classTemplate->render(),
'mockClassName' => $mockClassName['className']
);
}







protected function generateClassName($type, $className, $prefix)
{
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(microtime()), 0, 8);
} while (class_exists($className, false));
}

return array(
'className' => $className,
'originalClassName' => $type,
'fullClassName' => $fullClassName,
'namespaceName' => $namespaceName
);
}







protected function generateMockClassDeclaration(array $mockClassName, $isInterface, array $additionalInterfaces = array())
{
$buffer = 'class ';

$additionalInterfaces[] = 'PHPUnit_Framework_MockObject_MockObject';
$interfaces = implode(', ', $additionalInterfaces);

if ($isInterface) {
$buffer .= sprintf(
'%s implements %s',
$mockClassName['className'],
$interfaces
);

if (!in_array($mockClassName['originalClassName'], $additionalInterfaces)) {
$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;
}








protected function generateMockedMethodDefinitionFromExisting($templateDir, ReflectionMethod $method, $cloneArguments, $callOriginalMethods)
{
if ($method->isPrivate()) {
$modifier = 'private';
} elseif ($method->isProtected()) {
$modifier = 'protected';
} else {
$modifier = 'public';
}

if ($method->isStatic()) {
$modifier .= ' static';
}

if ($method->returnsReference()) {
$reference = '&';
} else {
$reference = '';
}

return $this->generateMockedMethodDefinition(
$templateDir,
$method->getDeclaringClass()->getName(),
$method->getName(),
$cloneArguments,
$modifier,
$this->getMethodParameters($method),
$this->getMethodParameters($method, true),
$reference,
$callOriginalMethods,
$method->isStatic()
);
}














protected function generateMockedMethodDefinition($templateDir, $className, $methodName, $cloneArguments = true, $modifier = 'public', $arguments_decl = '', $arguments_call = '', $reference = '', $callOriginalMethods = false, $static = false)
{
if ($static) {
$templateFile = 'mocked_static_method.tpl';
} else {
$templateFile = sprintf(
'%s_method.tpl',
$callOriginalMethods ? 'proxied' : 'mocked'
);
}

$template = new Text_Template($templateDir . $templateFile);

$template->setVar(
array(
'arguments_decl' => $arguments_decl,
'arguments_call' => $arguments_call,
'arguments_count' => !empty($arguments_call) ? count(explode(',', $arguments_call)) : 0,
'class_name' => $className,
'method_name' => $methodName,
'modifier' => $modifier,
'reference' => $reference,
'clone_arguments' => $cloneArguments ? 'TRUE' : 'FALSE'
)
);

return $template->render();
}





protected function canMockMethod(ReflectionMethod $method)
{
if ($method->isConstructor() ||
$method->isFinal() ||
$method->isPrivate() ||
isset($this->blacklistedMethodNames[$method->getName()])) {
return false;
}

return true;
}










protected function getMethodParameters(ReflectionMethod $method, $forCall = false)
{
$parameters = array();

foreach ($method->getParameters() as $i => $parameter) {
$name = '$' . $parameter->getName();




if ($name === '$' || $name === '$...') {
$name = '$arg' . $i;
}

if ($this->isVariadic($parameter)) {
if ($forCall) {
continue;
} else {
$name = '...' . $name;
}
}

$default = '';
$reference = '';
$typeDeclaration = '';

if (!$forCall) {
if ($this->hasType($parameter)) {
$typeDeclaration = (string) $parameter->getType() . ' ';
} elseif ($parameter->isArray()) {
$typeDeclaration = 'array ';
} elseif ((defined('HHVM_VERSION') || version_compare(PHP_VERSION, '5.4.0', '>='))
&& $parameter->isCallable()) {
$typeDeclaration = 'callable ';
} else {
try {
$class = $parameter->getClass();
} catch (ReflectionException $e) {
throw new PHPUnit_Framework_MockObject_RuntimeException(
sprintf(
'Cannot mock %s::%s() because a class or ' .
'interface used in the signature is not loaded',
$method->getDeclaringClass()->getName(),
$method->getName()
),
0,
$e
);
}

if ($class !== null) {
$typeDeclaration = $class->getName() . ' ';
}
}

if (!$this->isVariadic($parameter)) {
if ($parameter->isDefaultValueAvailable()) {
$value = $parameter->getDefaultValue();
$default = ' = ' . var_export($value, true);
} elseif ($parameter->isOptional()) {
$default = ' = null';
}
}
}

if ($parameter->isPassedByReference()) {
$reference = '&';
}

$parameters[] = $typeDeclaration . $reference . $name . $default;
}

return implode(', ', $parameters);
}






private function isVariadic(ReflectionParameter $parameter)
{
return method_exists('ReflectionParameter', 'isVariadic') && $parameter->isVariadic();
}






private function hasType(ReflectionParameter $parameter)
{
return method_exists('ReflectionParameter', 'hasType') && $parameter->hasType();
}






private function getClassMethods($className)
{
$class = new ReflectionClass($className);
$methods = array();

foreach ($class->getMethods() as $method) {
if (($method->isPublic() || $method->isAbstract()) && !in_array($method->getName(), $methods)) {
$methods[] = $method->getName();
}
}

return $methods;
}
}
<?php














interface PHPUnit_Framework_MockObject_Verifiable
{






public function verify();
}
<?php












class PHPUnit_Framework_MockObject_RuntimeException extends RuntimeException implements PHPUnit_Framework_MockObject_Exception
{
}
<?php














interface PHPUnit_Framework_MockObject_Exception
{
}
<?php












class PHPUnit_Framework_MockObject_BadMethodCallException extends BadMethodCallException implements PHPUnit_Framework_MockObject_Exception
{
}
<?php












class PHPUnit_Framework_MockObject_Stub_ReturnCallback implements PHPUnit_Framework_MockObject_Stub
{
protected $callback;

public function __construct($callback)
{
$this->callback = $callback;
}

public function invoke(PHPUnit_Framework_MockObject_Invocation $invocation)
{
return call_user_func_array($this->callback, $invocation->parameters);
}

public function toString()
{
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]
);
} else {
return 'return result of user defined callback ' . $this->callback .
' with the passed arguments';
}
}
}
<?php









use SebastianBergmann\Exporter\Exporter;






class PHPUnit_Framework_MockObject_Stub_Return implements PHPUnit_Framework_MockObject_Stub
{
protected $value;

public function __construct($value)
{
$this->value = $value;
}

public function invoke(PHPUnit_Framework_MockObject_Invocation $invocation)
{
return $this->value;
}

public function toString()
{
$exporter = new Exporter;

return sprintf(
'return user-specified value %s',
$exporter->export($this->value)
);
}
}
<?php














class PHPUnit_Framework_MockObject_Stub_ReturnArgument extends PHPUnit_Framework_MockObject_Stub_Return
{
protected $argumentIndex;

public function __construct($argumentIndex)
{
$this->argumentIndex = $argumentIndex;
}

public function invoke(PHPUnit_Framework_MockObject_Invocation $invocation)
{
if (isset($invocation->parameters[$this->argumentIndex])) {
return $invocation->parameters[$this->argumentIndex];
} else {
return;
}
}

public function toString()
{
return sprintf('return argument #%d', $this->argumentIndex);
}
}
<?php














class PHPUnit_Framework_MockObject_Stub_ReturnSelf implements PHPUnit_Framework_MockObject_Stub
{
public function invoke(PHPUnit_Framework_MockObject_Invocation $invocation)
{
if (!$invocation instanceof PHPUnit_Framework_MockObject_Invocation_Object) {
throw new PHPUnit_Framework_Exception(
'The current object can only be returned when mocking an ' .
'object, not a static class.'
);
}

return $invocation->object;
}

public function toString()
{
return 'return the current object';
}
}
<?php














class PHPUnit_Framework_MockObject_Stub_ReturnValueMap implements PHPUnit_Framework_MockObject_Stub
{
protected $valueMap;

public function __construct(array $valueMap)
{
$this->valueMap = $valueMap;
}

public function invoke(PHPUnit_Framework_MockObject_Invocation $invocation)
{
$parameterCount = count($invocation->parameters);

foreach ($this->valueMap as $map) {
if (!is_array($map) || $parameterCount != count($map) - 1) {
continue;
}

$return = array_pop($map);
if ($invocation->parameters === $map) {
return $return;
}
}

return;
}

public function toString()
{
return 'return value from a map';
}
}
<?php









use SebastianBergmann\Exporter\Exporter;






class PHPUnit_Framework_MockObject_Stub_ConsecutiveCalls implements PHPUnit_Framework_MockObject_Stub
{
protected $stack;
protected $value;

public function __construct($stack)
{
$this->stack = $stack;
}

public function invoke(PHPUnit_Framework_MockObject_Invocation $invocation)
{
$this->value = array_shift($this->stack);

if ($this->value instanceof PHPUnit_Framework_MockObject_Stub) {
$this->value = $this->value->invoke($invocation);
}

return $this->value;
}

public function toString()
{
$exporter = new Exporter;

return sprintf(
'return user-specified value %s',
$exporter->export($this->value)
);
}
}
<?php














interface PHPUnit_Framework_MockObject_Stub_MatcherCollection
{







public function addMatcher(PHPUnit_Framework_MockObject_Matcher_Invocation $matcher);
}
<?php









use SebastianBergmann\Exporter\Exporter;






class PHPUnit_Framework_MockObject_Stub_Exception implements PHPUnit_Framework_MockObject_Stub
{
protected $exception;

public function __construct(Exception $exception)
{
$this->exception = $exception;
}

public function invoke(PHPUnit_Framework_MockObject_Invocation $invocation)
{
throw $this->exception;
}

public function toString()
{
$exporter = new Exporter;

return sprintf(
'raise user-specified exception %s',
$exporter->export($this->exception)
);
}
}
<?php









use SebastianBergmann\Exporter\Exporter;






class PHPUnit_Framework_MockObject_Invocation_Static implements PHPUnit_Framework_MockObject_Invocation, PHPUnit_Framework_SelfDescribing
{



protected static $uncloneableExtensions = array(
'mysqli' => true,
'SQLite' => true,
'sqlite3' => true,
'tidy' => true,
'xmlwriter' => true,
'xsl' => true
);




protected static $uncloneableClasses = array(
'Closure',
'COMPersistHelper',
'IteratorIterator',
'RecursiveIteratorIterator',
'SplFileObject',
'PDORow',
'ZipArchive'
);




public $className;




public $methodName;




public $parameters;







public function __construct($className, $methodName, array $parameters, $cloneObjects = false)
{
$this->className = $className;
$this->methodName = $methodName;
$this->parameters = $parameters;

if (!$cloneObjects) {
return;
}

foreach ($this->parameters as $key => $value) {
if (is_object($value)) {
$this->parameters[$key] = $this->cloneObject($value);
}
}
}




public function toString()
{
$exporter = new Exporter;

return sprintf(
'%s::%s(%s)',
$this->className,
$this->methodName,
implode(
', ',
array_map(
array($exporter, 'shortenedExport'),
$this->parameters
)
)
);
}





protected function cloneObject($original)
{
$cloneable = null;
$object = new ReflectionObject($original);


 
 if ($object->isInternal() &&
isset(self::$uncloneableExtensions[$object->getExtensionName()])) {
$cloneable = false;
}

if ($cloneable === null) {
foreach (self::$uncloneableClasses as $class) {
if ($original instanceof $class) {
$cloneable = false;
break;
}
}
}

if ($cloneable === null && method_exists($object, 'isCloneable')) {
$cloneable = $object->isCloneable();
}

if ($cloneable === null && $object->hasMethod('__clone')) {
$method = $object->getMethod('__clone');
$cloneable = $method->isPublic();
}

if ($cloneable === null) {
$cloneable = true;
}

if ($cloneable) {
try {
return clone $original;
} catch (Exception $e) {
return $original;
}
} else {
return $original;
}
}
}
<?php














class PHPUnit_Framework_MockObject_Invocation_Object extends PHPUnit_Framework_MockObject_Invocation_Static
{



public $object;








public function __construct($className, $methodName, array $parameters, $object, $cloneObjects = false)
{
parent::__construct($className, $methodName, $parameters, $cloneObjects);
$this->object = $object;
}
}
<?php

















interface PHPUnit_Framework_MockObject_Invokable extends PHPUnit_Framework_MockObject_Verifiable
{








public function invoke(PHPUnit_Framework_MockObject_Invocation $invocation);








public function matches(PHPUnit_Framework_MockObject_Invocation $invocation);
}
<?php

















interface PHPUnit_Framework_MockObject_Stub extends PHPUnit_Framework_SelfDescribing
{









public function invoke(PHPUnit_Framework_MockObject_Invocation $invocation);
}
<?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;
}
}

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_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_', '', get_class($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 = array();
$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_', '', get_class($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_', '', get_class($tokens[$this->id]))
);
}
}
}


class PHP_Token_FUNCTION extends PHP_TokenWithScopeAndVisibility
{



protected $arguments;




protected $ccn;




protected $name;




protected $signature;




public function getArguments()
{
if ($this->arguments !== null) {
return $this->arguments;
}

$this->arguments = array();
$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();

for ($i = $this->id + 1; $i < count($tokens); $i++) {
if ($tokens[$i] instanceof PHP_Token_STRING) {
$this->name = (string)$tokens[$i];
break;
} elseif ($tokens[$i] instanceof PHP_Token_AMPERSAND &&
$tokens[$i+1] instanceof PHP_Token_STRING) {
$this->name = (string)$tokens[$i+1];
break;
} elseif ($tokens[$i] instanceof PHP_Token_OPEN_BRACKET) {
$this->name = 'anonymous function';
break;
}
}

if ($this->name != 'anonymous function') {
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 (get_class($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->getName() == 'anonymous function') {
$this->signature = 'anonymous function';
$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;
}
}

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 = array(
'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 = join($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
{



public function getName()
{
$next = $this->tokenStream[$this->id + 1];

if ($next instanceof PHP_Token_WHITESPACE) {
$next = $this->tokenStream[$this->id + 2];
}

if ($next instanceof PHP_Token_STRING) {
return (string) $next;
}

if ($next instanceof PHP_Token_OPEN_CURLY ||
$next instanceof PHP_Token_EXTENDS ||
$next instanceof PHP_Token_IMPLEMENTS) {
return 'anonymous class';
}
}
}

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_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_ASYNC extends PHP_Token {}
class PHP_Token_AWAIT extends PHP_Token {}
class PHP_Token_COMPILER_HALT_OFFSET extends PHP_Token {}
class PHP_Token_ENUM extends PHP_Token {}
class PHP_Token_EQUALS extends PHP_Token {}
class PHP_Token_IN extends PHP_Token {}
class PHP_Token_JOIN extends PHP_Token {}
class PHP_Token_LAMBDA_ARROW extends PHP_Token {}
class PHP_Token_LAMBDA_CP extends PHP_Token {}
class PHP_Token_LAMBDA_OP extends PHP_Token {}
class PHP_Token_ONUMBER extends PHP_Token {}
class PHP_Token_SHAPE extends PHP_Token {}
class PHP_Token_TYPE extends PHP_Token {}
class PHP_Token_TYPELIST_GT extends PHP_Token {}
class PHP_Token_TYPELIST_LT extends PHP_Token {}
class PHP_Token_WHERE extends PHP_Token {}
class PHP_Token_XHP_ATTRIBUTE extends PHP_Token {}
class PHP_Token_XHP_CATEGORY extends PHP_Token {}
class PHP_Token_XHP_CATEGORY_LABEL extends PHP_Token {}
class PHP_Token_XHP_CHILDREN extends PHP_Token {}
class PHP_Token_XHP_LABEL extends PHP_Token {}
class PHP_Token_XHP_REQUIRED extends PHP_Token {}
class PHP_Token_XHP_TAG_GT extends PHP_Token {}
class PHP_Token_XHP_TAG_LT extends PHP_Token {}
class PHP_Token_XHP_TEXT extends PHP_Token {}
<?php


















class PHP_Token_Stream implements ArrayAccess, Countable, SeekableIterator
{



protected static $customTokens = array(
'(' => '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 = array();




protected $position = 0;




protected $linesOfCode = array('loc' => 0, 'cloc' => 0, 'ncloc' => 0);




protected $classes;




protected $functions;




protected $includes;




protected $interfaces;




protected $traits;




protected $lineToFunctionMap = array();






public function __construct($sourceCode)
{
if (is_file($sourceCode)) {
$this->filename = $sourceCode;
$sourceCode = file_get_contents($sourceCode);
}

$this->scan($sourceCode);
}




public function __destruct()
{
$this->tokens = array();
}




public function __toString()
{
$buffer = '';

foreach ($this as $token) {
$buffer .= $token;
}

return $buffer;
}





public function getFilename()
{
return $this->filename;
}







protected function scan($sourceCode)
{
$line = 1;
$tokens = token_get_all($sourceCode);
$numTokens = count($tokens);

$lastNonWhitespaceTokenWasDoubleColon = false;

for ($i = 0; $i < $numTokens; ++$i) {
$token = $tokens[$i];
unset($tokens[$i]);

if (is_array($token)) {
$name = substr(token_name($token[0]), 2);
$text = $token[1];

if ($lastNonWhitespaceTokenWasDoubleColon && $name == 'CLASS') {
$name = 'CLASS_NAME_CONSTANT';
}

$tokenClass = 'PHP_Token_' . $name;
} else {
$text = $token;
$tokenClass = self::$customTokens[$token];
}

$this->tokens[] = new $tokenClass($text, $line, $this, $i);
$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;
}
}

$this->linesOfCode['loc'] = substr_count($sourceCode, "\n");
$this->linesOfCode['ncloc'] = $this->linesOfCode['loc'] -
$this->linesOfCode['cloc'];
}




public function count()
{
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 = array(
'require_once' => array(),
'require' => array(),
'include_once' => array(),
'include' => array()
);

foreach ($this->tokens as $token) {
switch (get_class($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 = array();
$this->classes = array();
$this->traits = array();
$this->functions = array();
$class = array();
$classEndLine = array();
$trait = false;
$traitEndLine = false;
$interface = false;
$interfaceEndLine = false;

foreach ($this->tokens as $token) {
switch (get_class($token)) {
case 'PHP_Token_HALT_COMPILER':
return;

case 'PHP_Token_INTERFACE':
$interface = $token->getName();
$interfaceEndLine = $token->getEndLine();

$this->interfaces[$interface] = array(
'methods' => array(),
'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 = array(
'methods' => array(),
'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 instanceof PHP_Token_CLASS) {
$class[] = $token->getName();
$classEndLine[] = $token->getEndLine();

if ($class[count($class)-1] != 'anonymous class') {
$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 = array(
'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) && $class[count($class)-1] != 'anonymous 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()
{
$this->position = 0;
}




public function valid()
{
return isset($this->tokens[$this->position]);
}




public function key()
{
return $this->position;
}




public function current()
{
return $this->tokens[$this->position];
}



public function next()
{
$this->position++;
}





public function offsetExists($offset)
{
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)
{
$this->tokens[$offset] = $value;
}





public function offsetUnset($offset)
{
if (!$this->offsetExists($offset)) {
throw new OutOfBoundsException(
sprintf(
'No token at position "%s"',
$offset
)
);
}

unset($this->tokens[$offset]);
}







public function seek($position)
{
$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


















class PHP_Token_Stream_CachingFactory
{



protected static $cache = array();





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 = array();
}
}
}
<?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








if (empty($argv[1])) {
echo "ERROR: You must provide a protocol file to parse.\n";
echo "Usage: php spec/parser.php amqp-rabbitmq-0.9.1.json.\n";
die(1);
}

$spec = file_get_contents(__DIR__ . "/" . $argv[1]);

$json_spec = json_decode($spec, true);

function to_camel_case($amqp_method)
{
$words = explode('-', $amqp_method);
$ret = array();
foreach ($words as $w) {
$ret[] = ucfirst($w);
}

return implode('', $ret);
}

function method_name($amqp_class, $amqp_method)
{
return $amqp_class . to_camel_case($amqp_method);
}

function to_snake_case($arg)
{
return str_replace('-', '_', $arg);
}

function addPhpDocParams($arguments)
{
$ret = array();
foreach ($arguments as $arg) {
$ret[] = ' * @param ' . translateType($arg) . ' $' . to_snake_case($arg['name']);
}

return implode("\n", $ret);
}

function translateType($argument)
{
$type = null;
if (array_key_exists('default-value', $argument)) {
$type = gettype($argument['default-value']);
} elseif (array_key_exists('type', $argument)) {
$type = $argument['type'];
}

switch ($type) {
case 'longstr':
case 'shortstr':
case 'string':
return 'string';
case 'short':
case 'long':
case 'longlong':
case 'integer':
case 'int':
return 'int';
case 'bit':
case 'boolean':
case 'bool':
return 'bool';
case 'array':
return 'array';
default:
return 'mixed';
}
}

function argument_default_val($arg)
{
return isset($arg['default-value']) ? " = " . default_value_to_string($arg['default-value']) : "";
}

function default_value_to_string($value)
{
if (is_array($value)) {
return 'array(' . implode(', ', array_map('default_value_to_string', $value)) . ')';
}

return var_export($value, true);
}

function indent($s, $level = 1, $chars = "    ")
{
if ($level > 0) {
$s = preg_replace('#(?:^|[\r\n]+)(?=[^\r\n])#', '$0' . str_repeat($chars, $level), $s);
}

return $s;
}

function add_method_arguments($arguments)
{
$ret = array();
foreach ($arguments as $arg) {
$ret[] = '$' . to_snake_case($arg['name']) . argument_default_val($arg);
}

return implode(", ", $ret);
}







function domain_to_type($domains, $domain)
{
foreach ($domains as $d) {
if ($d[0] == $domain) {
return $d[1];
}
}
throw new \Exception("Invalid domain: " . $domain);
}







function argument_type($domains, $arg)
{
return isset($arg['type']) ? $arg['type'] : domain_to_type($domains, $arg['domain']);
}

class ArgumentWriter
{
protected $bit_args = array();

public function call_write_argument($domains, $arg)
{
$a_type = argument_type($domains, $arg);
if ($a_type == 'bit') {
$this->bit_args[] = '$' . to_snake_case($arg['name']);
$ret = '';

} else {
$ret = $this->write_bits();

$a_name = '$' . to_snake_case($arg['name']);
$ret .= '$writer->write_' . $a_type . '(' . ($a_type === 'table' ? 'empty(' . $a_name . ') ? array() : ' : '') . $a_name . ");\n";
}

return $ret;
}


public function write_bits()
{
if (empty($this->bit_args)) {
return '';
}

$ret = '$writer->write_bits(array(' . implode(', ', $this->bit_args) . "));\n";
$this->bit_args = array();

return $ret;
}
}

function call_read_argument($domains, $arg)
{
return '$reader->read_' . argument_type($domains, $arg) . "();\n";
}

function protocol_version($json_spec)
{
if (isset($json_spec['revision'])) {
return $json_spec['major-version'] . $json_spec['minor-version'] . $json_spec['revision'];
} else {
return '0' . $json_spec['major-version'] . $json_spec['minor-version'];
}
}

function protocol_header($json_spec)
{
if (isset($json_spec['revision'])) {
$args = array(0, $json_spec['major-version'], $json_spec['minor-version'], $json_spec['revision']);

} else {
$args = array(1, 1, $json_spec['major-version'], $json_spec['minor-version']);
}

array_unshift($args, 'AMQP\x%02x\x%02x\x%02x\x%02x');

return '"' . call_user_func_array('sprintf', $args) . '"';
}

$argumentWriter = new ArgumentWriter();

$out = '<?php' . "\n\n";
$out .= '/* This file was autogenerated by spec/parser.php - Do not modify */' . "\n\n";
$out .= 'namespace PhpAmqpLib\Helper\Protocol;' . "\n\n";
$out .= 'use PhpAmqpLib\Wire\AMQPWriter;' . "\n";
$out .= 'use PhpAmqpLib\Wire\AMQPReader;' . "\n\n";
$out .= 'class Protocol' . protocol_version($json_spec) . "\n";
$out .= "{";

$methods = '';

foreach ($json_spec['classes'] as $c) {
foreach ($c['methods'] as $m) {
$methods .= "\n";

if ($m['id'] % 10 == 0) {
$methodBody = '$writer = new AMQPWriter();' . "\n";
foreach ($m['arguments'] as $arg) {
$methodBody .= $argumentWriter->call_write_argument($json_spec['domains'], $arg);
}
$methodBody .= $argumentWriter->write_bits();
$methodBody .= 'return array(' . $c['id'] . ", " . $m['id'] . ', $writer);';

$methods .= '/**' . "\n";
$methods .= addPhpDocParams($m['arguments']) . "\n";
$methods .= ' * @return array' . "\n";
$methods .= ' */' . "\n";
$methods .= 'public function ' . method_name($c['name'], $m['name']) . "(";
$methods .= add_method_arguments($m['arguments']);
$methods .= ")\n{\n";
$methods .= indent($methodBody) . "\n";
$methods .= "}\n";

} else {
$methodBody = '$response = array();' . "\n";
foreach ($m['arguments'] as $arg) {
$methodBody .= '$response[] = ' . call_read_argument($json_spec['domains'], $arg);
}
$methodBody .= 'return $response;';

$methods .= '/**' . "\n";
$methods .= ' * @param AMQPReader $reader' . "\n";
$methods .= ' * @return array' . "\n";
$methods .= ' */' . "\n";
$methods .= 'public static function ' . method_name($c['name'], $m['name'])
. '(AMQPReader $reader)' . "\n{\n";
$methods .= indent($methodBody) . "\n";
$methods .= "}\n";
}
}
}

$out .= indent(rtrim($methods)) . "\n";
$out .= "}\n";

file_put_contents(__DIR__ . '/../PhpAmqpLib/Helper/Protocol/Protocol' . protocol_version($json_spec) . '.php', $out);

function export_property($ret)
{
if (!is_array($ret)) {
return var_export($ret, true);
}

$code = '';
foreach ($ret as $key => $value) {
$code .= var_export($key, true) . ' => ' . export_property($value) . ",\n";
}

return "array(\n" . indent($code) . ")";
}

function frame_types($json_spec)
{
$ret = array();
foreach ($json_spec['constants'] as $c) {
if (mb_substr($c['name'], 0, 5, 'ASCII') == "FRAME") {
$ret[$c['value']] = $c['name'];
}
}

return export_property($ret);
}

function content_methods($json_spec)
{
$ret = array();
foreach ($json_spec['classes'] as $c) {
foreach ($c['methods'] as $m) {
if (isset($m['content']) && $m['content']) {
$ret[] = $c['id'] . "," . $m['id'];
}
}
}

return export_property($ret);
}

function close_methods($json_spec)
{
$ret = array();
foreach ($json_spec['classes'] as $c) {
foreach ($c['methods'] as $m) {
if ($m['name'] == 'close') {
$ret[] = $c['id'] . "," . $m['id'];
}
}
}

return export_property($ret);
}

function global_method_names($json_spec)
{
$ret = array();
foreach ($json_spec['classes'] as $c) {
foreach ($c['methods'] as $m) {
$ret[$c['id'] . "," . $m['id']] = ucfirst($c['name']) . '.' . to_snake_case($m['name']);
}
}

return export_property($ret);
}







function get_type_phpdoc($type, $variableName = null, $returnType = null)
{
$properties = "/**\n";
$properties .= " * @var " . $type;

if ($variableName != null) {
$properties .= " " . $variableName;
}
$properties .= "\n";

if ($returnType != null) {
$properties .= " * @return " . $returnType . "\n";
}

$properties .= " */\n";

return $properties;
}

$properties = get_type_phpdoc('string');
$properties .= 'public static $AMQP_PROTOCOL_HEADER = ' . protocol_header($json_spec) . ";\n\n";
$properties .= get_type_phpdoc('array');
$properties .= 'public static $FRAME_TYPES = ' . frame_types($json_spec) . ";\n\n";
$properties .= get_type_phpdoc('array');
$properties .= 'public static $CONTENT_METHODS = ' . content_methods($json_spec) . ";\n\n";
$properties .= get_type_phpdoc('array');
$properties .= 'public static $CLOSE_METHODS = ' . close_methods($json_spec) . ";\n\n";
$properties .= get_type_phpdoc('array');
$properties .= 'public static $GLOBAL_METHOD_NAMES = ' . global_method_names($json_spec) . ";\n";

$out = '<?php' . "\n\n";
$out .= '/* This file was autogenerated by spec/parser.php - Do not modify */' . "\n\n";
$out .= 'namespace PhpAmqpLib\Wire;' . "\n\n";
$out .= "class Constants" . protocol_version($json_spec) . "\n";
$out .= "{\n";
$out .= indent($properties);
$out .= "}\n";

file_put_contents(__DIR__ . '/../PhpAmqpLib/Wire/Constants' . protocol_version($json_spec) . '.php', $out);

function method_waits($json_spec)
{
$ret = array();
foreach ($json_spec['classes'] as $c) {
foreach ($c['methods'] as $m) {
$ret[$c['name'] . '.' . to_snake_case($m['name'])] = $c['id'] . "," . $m['id'];
}
}

return export_property($ret);
}

$classBody = '';
$classBody .= get_type_phpdoc('array');
$classBody .= "protected \$wait = " . method_waits($json_spec) . ";\n\n";
$classBody .= get_type_phpdoc('string', '$method', 'string');
$classBody .= 'public function get_wait($method)' . "\n{\n";
$classBody .= indent('return $this->wait[$method];') . "\n";
$classBody .= "}";

$out = '<?php' . "\n\n";
$out .= '/* This file was autogenerated by spec/parser.php - Do not modify */' . "\n\n";
$out .= 'namespace PhpAmqpLib\Helper\Protocol;' . "\n\n";
$out .= "class Wait" . protocol_version($json_spec) . "\n";
$out .= "{\n";
$out .= indent($classBody) . "\n";
$out .= "}\n";

file_put_contents(__DIR__ . '/../PhpAmqpLib/Helper/Protocol/Wait' . protocol_version($json_spec) . '.php', $out);

function method_map($json_spec)
{
$ret = array();

$special_map = array(
'60,30' => 'basic_cancel_from_server',
'60,80' => 'basic_ack_from_server',
'60,120' => 'basic_nack_from_server'
);

foreach ($json_spec['classes'] as $c) {
foreach ($c['methods'] as $m) {
if (isset($special_map[$c['id'] . ',' . $m['id']]) && protocol_version($json_spec) == '091') {
$ret[$c['id'] . "," . $m['id']] = $special_map[$c['id'] . ',' . $m['id']];
} else {
$ret[$c['id'] . "," . $m['id']] = $c['name'] . '_' . to_snake_case($m['name']);
}
}
}

return export_property($ret);
}

$classBody = '';
$classBody .= get_type_phpdoc('array');
$classBody .= 'protected $method_map = ' . method_map($json_spec) . ";\n\n";
$classBody .= get_type_phpdoc('string', '$method_sig', 'string');
$classBody .= 'public function get_method($method_sig)' . "\n{\n";
$classBody .= indent('return $this->method_map[$method_sig];') . "\n";
$classBody .= "}\n\n";
$classBody .= get_type_phpdoc('string', '$method_sig', 'bool');
$classBody .= 'public function valid_method($method_sig)' . "\n{\n";
$classBody .= indent('return array_key_exists($method_sig, $this->method_map);') . "\n";
$classBody .= "}";

$out = '<?php' . "\n\n";
$out .= '/* This file was autogenerated by spec/parser.php - Do not modify */' . "\n\n";
$out .= 'namespace PhpAmqpLib\Helper\Protocol;' . "\n\n";
$out .= "class MethodMap" . protocol_version($json_spec) . "\n";
$out .= "{\n";
$out .= indent($classBody) . "\n";
$out .= "}\n";

file_put_contents(__DIR__ . '/../PhpAmqpLib/Helper/Protocol/MethodMap' . protocol_version($json_spec) . '.php', $out);
<?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 saveBytes($bytes)
{
$fh = fopen('/tmp/bytes', 'wb');
fwrite($fh, $bytes);
fclose($fh);
}









public static function splitSecondsMicroseconds($number)
{
return array(floor($number), ($number - floor($number)) * 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;
}





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;

class DebugHelper
{



protected $debug;




protected $PROTOCOL_CONSTANTS_CLASS;




public function __construct($PROTOCOL_CONSTANTS_CLASS) {
$this->debug = defined('AMQP_DEBUG') ? AMQP_DEBUG : false;
$this->PROTOCOL_CONSTANTS_CLASS = $PROTOCOL_CONSTANTS_CLASS;
}




public function debug_msg($msg) {
if ($this->debug) {
$this->print_msg($msg);
}
}




public function debug_allowed_methods($allowed_methods) {
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) {
$protocolClass = $this->PROTOCOL_CONSTANTS_CLASS;
$this->debug_msg(sprintf(
$msg . ': %s',
MiscHelper::methodSig($method_sig),
$protocolClass::$GLOBAL_METHOD_NAMES[MiscHelper::methodSig($method_sig)]
));
}
}




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) {
echo $s . PHP_EOL;
}
}
<?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;

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;

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 = false, $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\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 = false, $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 = false, $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 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 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\Wire;

use PhpAmqpLib\Exception\AMQPInvalidArgumentException;
use PhpAmqpLib\Exception\AMQPOutOfBoundsException;
use PhpAmqpLib\Exception\AMQPRuntimeException;
use PhpAmqpLib\Exception\AMQPTimeoutException;
use PhpAmqpLib\Exception\AMQPIOWaitException;
use PhpAmqpLib\Helper\MiscHelper;
use PhpAmqpLib\Wire\IO\AbstractIO;






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;


protected $offset;


protected $bitcount;


protected $is64bits;


protected $timeout;


protected $bits;


protected $io;






public function __construct($str, AbstractIO $io = null, $timeout = 0)
{
parent::__construct();

$this->str = $str;
$this->str_length = mb_strlen($this->str, 'ASCII');
$this->io = $io;
$this->offset = 0;
$this->bitcount = $this->bits = 0;
$this->timeout = $timeout;
}











public function reuse($str)
{
$this->str = $str;
$this->str_length = mb_strlen($this->str, 'ASCII');
$this->offset = 0;
$this->bitcount = $this->bits = 0;
}




public function close()
{
if ($this->io) {
$this->io->close();
}
}





public function read($n)
{
$this->bitcount = $this->bits = 0;

return $this->rawread($n);
}









protected function wait()
{
if ($this->getTimeout() == 0) {
return null;
}


 list($sec, $usec) = MiscHelper::splitSecondsMicroseconds($this->getTimeout());
$result = $this->io->select($sec, $usec);

if ($result === false) {
throw new AMQPIOWaitException('A network error occured while awaiting for incoming data');
}

if ($result === 0) {
throw new AMQPTimeoutException(sprintf(
'The connection timed out after %s sec while awaiting incoming data',
$this->getTimeout()
));
}
}







protected function rawread($n)
{
if ($this->io) {
$this->wait();
$res = $this->io->read($n);
$this->offset += $n;

return $res;
}

if ($this->str_length < $n) {
throw new AMQPRuntimeException(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, mb_strlen($this->str, 'ASCII') - $n, 'ASCII');
$this->str_length -= $n;
$this->offset += $n;

return $res;
}




public function read_bit()
{
if (!$this->bitcount) {
$this->bits = ord($this->rawread(1));
$this->bitcount = 8;
}

$result = ($this->bits & 1) == 1;
$this->bits >>= 1;
$this->bitcount -= 1;

return $result;
}




public function read_octet()
{
$this->bitcount = $this->bits = 0;
list(, $res) = unpack('C', $this->rawread(1));

return $res;
}




public function read_signed_octet()
{
$this->bitcount = $this->bits = 0;
list(, $res) = unpack('c', $this->rawread(1));

return $res;
}




public function read_short()
{
$this->bitcount = $this->bits = 0;
list(, $res) = unpack('n', $this->rawread(2));

return $res;
}




public function read_signed_short()
{
$this->bitcount = $this->bits = 0;
list(, $res) = unpack('s', $this->correctEndianness($this->rawread(2)));

return $res;
}












public function read_php_int()
{
list(, $res) = unpack('N', $this->rawread(4));

if ($this->is64bits) {
return (int) sprintf('%u', $res);
}

return $res;
}







public function read_long()
{
$this->bitcount = $this->bits = 0;
list(, $res) = unpack('N', $this->rawread(4));

return !$this->is64bits && self::getLongMSB($res) ? sprintf('%u', $res) : $res;
}




private function read_signed_long()
{
$this->bitcount = $this->bits = 0;
list(, $res) = unpack('l', $this->correctEndianness($this->rawread(4)));

return $res;
}








public function read_longlong()
{
$this->bitcount = $this->bits = 0;

list(, $hi, $lo) = unpack('N2', $this->rawread(8));
$msb = self::getLongMSB($hi);

if (!$this->is64bits) {
if ($msb) {
$hi = sprintf('%u', $hi);
}
if (self::getLongMSB($lo)) {
$lo = sprintf('%u', $lo);
}
}

return bcadd($this->is64bits && !$msb ? $hi << 32 : bcmul($hi, '4294967296', 0), $lo, 0);
}




public function read_signed_longlong()
{
$this->bitcount = $this->bits = 0;

list(, $hi, $lo) = unpack('N2', $this->rawread(8));

if ($this->is64bits) {
return bcadd($hi << 32, $lo, 0);
} else {
return bcadd(bcmul($hi, '4294967296', 0), self::getLongMSB($lo) ? sprintf('%u', $lo) : $lo, 0);
}
}





private static function getLongMSB($longInt)
{
return (bool) ($longInt & 0x80000000);
}





public function read_shortstr()
{
$this->bitcount = $this->bits = 0;
list(, $slen) = unpack('C', $this->rawread(1));

return $this->rawread($slen);
}






public function read_longstr()
{
$this->bitcount = $this->bits = 0;
$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->bitcount = $this->bits = 0;
$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->bitcount = $this->bits = 0;


 $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->bitcount = $this->bits = 0;

switch ($fieldType) {
case AMQPAbstractCollection::T_INT_SHORTSHORT:

 
 $val = $this->read_signed_octet();
break;
case AMQPAbstractCollection::T_INT_SHORTSHORT_U:
$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->read_signed_long();
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->read_signed_long();
$val = new AMQPDecimal($n, $e);
break;
case AMQPAbstractCollection::T_TIMESTAMP:
$val = $this->read_timestamp();
break;
case AMQPAbstractCollection::T_BOOL:
$val = $this->read_octet();
break;
case AMQPAbstractCollection::T_STRING_SHORT:
$val = $this->read_shortstr();
break;
case AMQPAbstractCollection::T_STRING_LONG:
$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;
default:
throw new AMQPInvalidArgumentException(sprintf(
'Unsupported type "%s"',
$fieldType
));
}

return isset($val) ? $val : null;
}




protected function tell()
{
return $this->offset;
}






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




public function getTimeout()
{
return $this->timeout;
}
}
<?php
namespace PhpAmqpLib\Wire;

use PhpAmqpLib\Channel\AbstractChannel;
use PhpAmqpLib\Exception;





abstract class AMQPAbstractCollection implements \Iterator
{


 const PROTOCOL_080 = AbstractChannel::PROTOCOL_080;
const PROTOCOL_091 = AbstractChannel::PROTOCOL_091;
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;




private static $_protocol = null;






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_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'
);




private static $_types_rabbit = array(
self::T_INT_SHORTSHORT => 'b',
self::T_INT_SHORT => 's',
self::T_INT_LONG => 'I',
self::T_INT_LONGLONG => 'l',
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'
);




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(
'Attempted to add instance of ' . get_class($val) . ' representing type [' . $val->getType() . '] as mismatching type [' . $type . ']'
);
}
$type = $val->getType();
} elseif ($type) { 
 switch ($type) {
case self::T_ARRAY:
throw new Exception\AMQPInvalidArgumentException('Arrays must be passed as AMQPArray instance');
break;
case self::T_TABLE:
throw new Exception\AMQPInvalidArgumentException('Tables must be passed as AMQPTable instance');
break;
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;
}






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 \DateTime) {
$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(self::PROTOCOL_080)) {

 $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(
'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(self::PROTOCOL_080)) {

 $ev = $this->encodeString((string) $val);
} else {
$ev = array(self::T_INT_LONGLONG, $val);
}

return $ev;
}





protected function encodeFloat($val)
{
return static::encodeString((string) $val);
}





protected function encodeBool($val)
{
$val = (bool) $val;

return self::isProtocol(self::PROTOCOL_080) ? array(self::T_INT_LONG, (int) $val) : array(self::T_BOOL, $val);
}




protected function encodeVoid()
{
return self::isProtocol(self::PROTOCOL_080) ? $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 self::PROTOCOL_080:
$types = self::$_types_080;
break;
case self::PROTOCOL_091:
$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\AMQPInvalidArgumentException;
use PhpAmqpLib\Exception\AMQPOutOfBoundsException;

class AMQPWriter extends AbstractClient
{

protected $out;


protected $bits;


protected $bitcount;

public function __construct()
{
parent::__construct();

$this->out = '';
$this->bits = array();
$this->bitcount = 0;
}












private static function packBigEndian($x, $bytes)
{
if (($bytes <= 0) || ($bytes % 2)) {
throw new AMQPInvalidArgumentException(sprintf('Expected bytes count must be multiply of 2, %s given', $bytes));
}

$ox = $x; 
 $isNeg = false;

if (is_int($x)) {
if ($x < 0) {
$isNeg = true;
$x = abs($x);
}
} elseif (is_string($x)) {
if (!is_numeric($x)) {
throw new AMQPInvalidArgumentException(sprintf('Unknown numeric string format: %s', $x));
}
$x = preg_replace('/^-/', '', $x, 1, $isNeg);
} else {
throw new AMQPInvalidArgumentException('Only integer and numeric string values are supported');
}

if ($isNeg) {
$x = bcadd($x, -1, 0);
} 

$res = array();
for ($b = 0; $b < $bytes; $b += 2) {
$chnk = (int) bcmod($x, 65536);
$x = bcdiv($x, 65536, 0);
$res[] = pack('n', $isNeg ? ~$chnk : $chnk);
}

if ($x || ($isNeg && ($chnk & 0x8000))) {
throw new AMQPOutOfBoundsException(sprintf('Overflow detected while attempting to pack %s into %s bytes', $ox, $bytes));
}

return implode(array_reverse($res));
}

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);
array_push($this->bits, $last);
$this->bitcount += 1;

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 (!$this->is64bits && is_string($n)) {
$n = (float) $n;
}
$this->out .= pack('N', $n);

return $this;
}





private function write_signed_long($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 ($n < 0) {
throw new AMQPInvalidArgumentException('Longlong out of range: ' . $n);
}


 
 if (bcadd($n, -PHP_INT_MAX, 0) <= 0) {

 if ($this->is64bits) {
list($hi, $lo) = $this->splitIntoQuads($n);
} else {
$hi = 0;
$lo = $n;
} 
 $this->out .= pack('NN', $hi, $lo);
} else {
try {
$this->out .= self::packBigEndian($n, 8);
} catch (AMQPOutOfBoundsException $ex) {
throw new AMQPInvalidArgumentException('Longlong out of range: ' . $n, 0, $ex);
}
}

return $this;
}





public function write_signed_longlong($n)
{
if ((bcadd($n, PHP_INT_MAX, 0) >= -1) && (bcadd($n, -PHP_INT_MAX, 0) <= 0)) {
if ($this->is64bits) {
list($hi, $lo) = $this->splitIntoQuads($n);
} else {
$hi = $n < 0 ? -1 : 0;
$lo = $n;
} 
 $this->out .= pack('NN', $hi, $lo);
} elseif ($this->is64bits) {
throw new AMQPInvalidArgumentException('Signed longlong out of range: ' . $n);
} else {
if (bcadd($n, '-9223372036854775807', 0) > 0) {
throw new AMQPInvalidArgumentException('Signed longlong out of range: ' . $n);
}
try {

 $this->out .= self::packBigEndian($n, 8);
} catch (AMQPOutOfBoundsException $ex) {
throw new AMQPInvalidArgumentException('Signed longlong out of range: ' . $n, 0, $ex);
}
}

return $this;
}





private function splitIntoQuads($n)
{
$n = (int) $n;

return array($n >> 32, $n & 0x00000000ffffffff);
}









public function write_shortstr($s)
{
$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)
{
$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->write_value($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 AMQPWriter();
foreach ($d as $k => $va) {
list($ftype, $v) = $va;
$table_data->write_shortstr($k);
$table_data->write_value($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 write_value($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->write_signed_long($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->write_signed_long($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;
default:
throw new AMQPInvalidArgumentException(sprintf(
'Unsupported type "%s"',
$type
));
}
}
}
<?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;


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;


class AbstractClient
{




protected $is64bits;




protected $isLittleEndian;

public function __construct()
{
$this->is64bits = PHP_INT_SIZE == 8;

$tmp = unpack('S', "\x01\x00"); 
 $this->isLittleEndian = $tmp[1] == 1;
}







protected function correctEndianness($byteStr)
{
return $this->isLittleEndian ? strrev($byteStr) : $byteStr;
}
}
<?php



namespace PhpAmqpLib\Wire;

class Constants091
{



public static $AMQP_PROTOCOL_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;

use PhpAmqpLib\Channel\AMQPChannel;





abstract class GenericContent
{

public $delivery_info = array();


protected $prop_types;


private $properties = array();


private $serialized_properties;




protected static $propertyDefinitions = array(
'dummy' => 'shortstr'
);





public function __construct($properties, $propertyTypes = null)
{
$this->prop_types = self::$propertyDefinitions;

if (!empty($propertyTypes)) {
$this->prop_types = $propertyTypes;
}

if (!empty($properties)) {
$this->properties = array_intersect_key($properties, $this->prop_types);
}
}








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, $this->prop_types)) {
throw new \OutOfBoundsException(sprintf(
'No "%s" property',
$name
));
}

$this->properties[$name] = $value;
}











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 ($this->prop_types 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 ($this->prop_types 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\Wire;

class Constants080
{



public static $AMQP_PROTOCOL_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\AMQPOutOfBoundsException;












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()
{
return bcdiv($this->n, bcpow(10, $this->e));
}




public function getE()
{
return $this->e;
}




public function getN()
{
return $this->n;
}
}
<?php
namespace PhpAmqpLib\Wire\IO;

use PhpAmqpLib\Exception\AMQPIOException;
use PhpAmqpLib\Exception\AMQPRuntimeException;
use PhpAmqpLib\Helper\MiscHelper;

class SocketIO extends AbstractIO
{

protected $host;


protected $port;


protected $timeout;


private $sock;


private $keepalive;







public function __construct($host, $port, $timeout, $keepalive = false)
{
$this->host = $host;
$this->port = $port;
$this->timeout = $timeout;
$this->keepalive = $keepalive;
}






public function connect()
{
$this->sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

list($sec, $uSec) = MiscHelper::splitSecondsMicroseconds($this->timeout);
socket_set_option($this->sock, SOL_SOCKET, SO_RCVTIMEO, array('sec' => $sec, 'usec' => $uSec));
socket_set_option($this->sock, SOL_SOCKET, SO_SNDTIMEO, array('sec' => $sec, 'usec' => $uSec));

if (!socket_connect($this->sock, $this->host, $this->port)) {
$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();
}
}




public function getSocket()
{
return $this->sock;
}




public function reconnect()
{
$this->close();
$this->connect();
}







public function read($n)
{
$res = '';
$read = 0;

$buf = socket_read($this->sock, $n);
while ($read < $n && $buf !== '' && $buf !== false) {

 if (is_null($this->sock)) {
throw new AMQPRuntimeException(sprintf(
'Socket was null! Last SocketError was: %s',
socket_strerror(socket_last_error())
));
}

$read += mb_strlen($buf, 'ASCII');
$res .= $buf;
$buf = socket_read($this->sock, $n - $read);
}

if (mb_strlen($res, 'ASCII') != $n) {
throw new AMQPIOException(sprintf(
'Error reading data. Received %s instead of expected %s bytes',
mb_strlen($res, 'ASCII'),
$n
));
}

return $res;
}







public function write($data)
{
$len = mb_strlen($data, 'ASCII');

while (true) {

 if (is_null($this->sock)) {
throw new AMQPRuntimeException(sprintf(
'Socket was null! Last SocketError was: %s',
socket_strerror(socket_last_error())
));
}

$sent = socket_write($this->sock, $data, $len);
if ($sent === false) {
throw new AMQPIOException(sprintf(
'Error sending data. Last SocketError: %s',
socket_strerror(socket_last_error())
));
}


 if ($sent < $len) {

 
 $data = mb_substr($data, $sent, mb_strlen($data, 'ASCII') - $sent, 'ASCII');

 $len -= $sent;
} else {
break;
}
}
}

public function close()
{
if (is_resource($this->sock)) {
socket_close($this->sock);
}
$this->sock = null;
}






public function select($sec, $usec)
{
$read = array($this->sock);
$write = null;
$except = null;

return socket_select($read, $write, $except, $sec, $usec);
}




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);
}
}
<?php
namespace PhpAmqpLib\Wire\IO;

use PhpAmqpLib\Exception\AMQPIOException;
use PhpAmqpLib\Exception\AMQPRuntimeException;
use PhpAmqpLib\Exception\AMQPTimeoutException;
use PhpAmqpLib\Helper\MiscHelper;
use PhpAmqpLib\Wire\AMQPWriter;

class StreamIO extends AbstractIO
{

protected $protocol;


protected $host;


protected $port;


protected $connection_timeout;


protected $read_write_timeout;


protected $context;


protected $keepalive;


protected $heartbeat;


protected $last_read;


protected $last_write;


protected $last_error;


private $sock;


private $canSelectNull;


private $canDispatchPcntlSignal;










public function __construct(
$host,
$port,
$connection_timeout,
$read_write_timeout,
$context = null,
$keepalive = false,
$heartbeat = 0
) {
if ($heartbeat !== 0 && ($read_write_timeout < ($heartbeat * 2))) {
throw new \InvalidArgumentException('read_write_timeout must be at least 2x the heartbeat');
}

$this->protocol = 'tcp';
$this->host = $host;
$this->port = $port;
$this->connection_timeout = $connection_timeout;
$this->read_write_timeout = $read_write_timeout;
$this->context = $context;
$this->keepalive = $keepalive;
$this->heartbeat = $heartbeat;
$this->canSelectNull = true;
$this->canDispatchPcntlSignal = $this->isPcntlSignalEnabled();

if (is_null($this->context)) {
$this->context = stream_context_create();
} else {
$this->protocol = 'ssl';

 if (PHP_VERSION_ID < 50436) {
$this->canSelectNull = false;
}
}
}




private function isPcntlSignalEnabled()
{
return extension_loaded('pcntl')
&& function_exists('pcntl_signal_dispatch')
&& (defined('AMQP_WITHOUT_SIGNALS') ? !AMQP_WITHOUT_SIGNALS : true);
}







public function connect()
{
$errstr = $errno = null;

$remote = sprintf(
'%s://%s:%s',
$this->protocol,
$this->host,
$this->port
);

set_error_handler(array($this, 'error_handler'));

try {
$this->sock = stream_socket_client(
$remote,
$errno,
$errstr,
$this->connection_timeout,
STREAM_CLIENT_CONNECT,
$this->context
);
} catch (\ErrorException $e) {
restore_error_handler();
throw $e;
}

restore_error_handler();

if (false === $this->sock) {
throw new AMQPRuntimeException(
sprintf(
'Error Connecting to server(%s): %s ',
$errno,
$errstr
),
$errno
);
}

if (false === stream_socket_get_name($this->sock, true)) {
throw new AMQPRuntimeException(
sprintf(
'Connection refused: %s ',
$remote
)
);
}

list($sec, $uSec) = MiscHelper::splitSecondsMicroseconds($this->read_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, 1);
}

if ($this->keepalive) {
$this->enable_keepalive();
}
}




public function reconnect()
{
$this->close();
$this->connect();
}






public function read($len)
{
$read = 0;
$data = '';

while ($read < $len) {
$this->check_heartbeat();

if (!is_resource($this->sock) || feof($this->sock)) {
throw new AMQPRuntimeException('Broken pipe or closed connection');
}

set_error_handler(array($this, 'error_handler'));
try {
$buffer = fread($this->sock, ($len - $read));
} catch (\ErrorException $e) {
restore_error_handler();
throw $e;
}
restore_error_handler();

if ($buffer === false) {
throw new AMQPRuntimeException('Error receiving data');
}

if ($buffer === '') {
if ($this->canDispatchPcntlSignal) {

 if ($this->canSelectNull) {
$this->select(null, null);
pcntl_signal_dispatch();
} else {
usleep(100000);
pcntl_signal_dispatch();
}
}
continue;
}

$read += mb_strlen($buffer, 'ASCII');
$data .= $buffer;
}

if (mb_strlen($data, 'ASCII') !== $len) {
throw new AMQPRuntimeException(
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)
{
$written = 0;
$len = mb_strlen($data, 'ASCII');

while ($written < $len) {

if (!is_resource($this->sock)) {
throw new AMQPRuntimeException('Broken pipe or closed connection');
}

set_error_handler(array($this, 'error_handler'));

 
 
 
 
 
 
 try {
$buffer = fwrite($this->sock, $data, 8192);
} catch (\ErrorException $e) {
restore_error_handler();
throw $e;
}
restore_error_handler();

if ($buffer === false) {
throw new AMQPRuntimeException('Error sending data');
}

if ($buffer === 0 && feof($this->sock)) {
throw new AMQPRuntimeException('Broken pipe or closed connection');
}

if ($this->timed_out()) {
throw new AMQPTimeoutException('Error sending data. Socket connection timed out');
}

$written += $buffer;

if ($buffer > 0) {
$data = mb_substr($data, $buffer, mb_strlen($data, 'ASCII') - $buffer, 'ASCII');
}
}

$this->last_write = microtime(true);
}












public function error_handler($errno, $errstr, $errfile, $errline, $errcontext = null)
{
$this->last_error = compact('errno', 'errstr', 'errfile', 'errline', 'errcontext');


 if (strstr($errstr, 'Resource temporarily unavailable')) {

 return null;
}


 if (strstr($errstr, 'Interrupted system call')) {

 return null;
}


 throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
}




protected function check_heartbeat()
{

 if ($this->heartbeat !== 0 && $this->last_read && $this->last_write) {
$t = microtime(true);
$t_read = round($t - $this->last_read);
$t_write = round($t - $this->last_write);


 if (($this->heartbeat * 2) < $t_read) {
$this->reconnect();
}


 if (($this->heartbeat / 2) < $t_write) {
$this->write_heartbeat();
}
}
}




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());
}

public function close()
{
if (is_resource($this->sock)) {
fclose($this->sock);
}
$this->sock = null;
}




public function get_socket()
{
return $this->sock;
}




public function getSocket()
{
return $this->get_socket();
}






public function select($sec, $usec)
{
$read = array($this->sock);
$write = null;
$except = null;
$result = false;

set_error_handler(array($this, 'error_handler'));
try {
$result = stream_select($read, $write, $except, $sec, $usec);
} catch (\ErrorException $e) {
restore_error_handler();
throw $e;
}
restore_error_handler();

return $result;
}




protected function timed_out()
{

 $info = stream_get_meta_data($this->sock);

return $info['timed_out'];
}




protected function enable_keepalive()
{
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);
}




public function disableHeartbeat()
{
$this->heartbeat = 0;

return $this;
}
}
<?php
namespace PhpAmqpLib\Wire\IO;

abstract class AbstractIO
{




abstract public function read($n);





abstract public function write($data);




abstract public function close();






abstract public function select($sec, $usec);




abstract public function connect();




abstract public function reconnect();




abstract public function getSocket();
}
<?php
namespace PhpAmqpLib\Channel;

use PhpAmqpLib\Connection\AbstractConnection;
use PhpAmqpLib\Exception\AMQPOutOfBoundsException;
use PhpAmqpLib\Exception\AMQPOutOfRangeException;
use PhpAmqpLib\Exception\AMQPRuntimeException;
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\AMQPReader;

abstract class AbstractChannel
{
const PROTOCOL_080 = '0.8';
const PROTOCOL_091 = '0.9.1';

public static $PROTOCOL_CONSTANTS_CLASS;


protected $frame_queue;


protected $method_queue;


protected $auto_decode;


protected $amqp_protocol_header;


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 = $channel_id;
$connection->channels[$channel_id] = $this;
$this->frame_queue = array(); 
 $this->method_queue = array(); 
 $this->auto_decode = false;

$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 self::PROTOCOL_091:
self::$PROTOCOL_CONSTANTS_CLASS = 'PhpAmqpLib\Wire\Constants091';
$c = self::$PROTOCOL_CONSTANTS_CLASS;
$this->debug = new DebugHelper($c);
$this->amqp_protocol_header = $c::$AMQP_PROTOCOL_HEADER;
$this->protocolWriter = new Protocol091();
$this->waitHelper = new Wait091();
$this->methodMap = new MethodMap091();
break;
case self::PROTOCOL_080:
self::$PROTOCOL_CONSTANTS_CLASS = 'PhpAmqpLib\Wire\Constants080';
$c = self::$PROTOCOL_CONSTANTS_CLASS;
$this->debug = new DebugHelper($c);
$this->amqp_protocol_header = $c::$AMQP_PROTOCOL_HEADER;
$this->protocolWriter = new Protocol080();
$this->waitHelper = new Wait080();
$this->methodMap = new MethodMap080();
break;
default:
throw new AMQPRuntimeException(sprintf(
'Protocol: %s not implemented.',
$this->protocolVersion
));
}
}





public static function getProtocolVersion()
{
$protocol = defined('AMQP_PROTOCOL') ? AMQP_PROTOCOL : self::PROTOCOL_091;

 if (!in_array($protocol, array(self::PROTOCOL_080, self::PROTOCOL_091), 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 dispatch($method_sig, $args, $amqpMessage)
{
if (!$this->methodMap->valid_method($method_sig)) {
throw new AMQPRuntimeException(sprintf(
'Unknown AMQP method "%s"',
$method_sig
));
}

$amqp_method = $this->methodMap->get_method($method_sig);

if (!method_exists($this, $amqp_method)) {
throw new AMQPRuntimeException(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 AMQPRuntimeException('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'));


 $class_id = $this->wait_content_reader->read_short();
$weight = $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)
{
$bodyChunks = array();
$bodyReceivedBytes = 0;

$message = new AMQPMessage();
$message
->load_properties($propertyReader)
->setBodySize($contentReader->read_longlong());

while (bccomp($message->getBodySize(), $bodyReceivedBytes, 0) == 1) {
list($frame_type, $payload) = $this->next_frame();

$this->validate_body_frame($frame_type);
$bodyReceivedBytes = bcadd($bodyReceivedBytes, mb_strlen($payload, 'ASCII'), 0);

if (is_int($this->maxBodySize) && $bodyReceivedBytes > $this->maxBodySize ) {
$message->setIsTruncated(true);
continue;
}

$bodyChunks[] = $payload;
}

$message->setBody(implode('', $bodyChunks));

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']);
}


 while (true) {
list($frame_type, $payload) = $this->next_frame($timeout);

$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)) {
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) {
$protocolClass = self::$PROTOCOL_CONSTANTS_CLASS;
throw new AMQPRuntimeException(sprintf(
'Expecting %s, received frame type %s (%s)',
$expectedMessage,
$frameType,
$protocolClass::$FRAME_TYPES[$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)
{
$protocolClass = self::$PROTOCOL_CONSTANTS_CLASS;

return $allowed_methods == null
|| in_array($method_sig, $allowed_methods)
|| in_array($method_sig, $protocolClass::$CLOSE_METHODS);
}





protected function maybe_wait_for_content($method_sig)
{
$protocolClass = self::$PROTOCOL_CONSTANTS_CLASS;
$amqpMessage = null;

if (in_array($method_sig, $protocolClass::$CONTENT_METHODS)) {
$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\Exception\AMQPBasicCancelException;
use PhpAmqpLib\Exception\AMQPProtocolChannelException;
use PhpAmqpLib\Exception\AMQPRuntimeException;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Wire\AMQPReader;
use PhpAmqpLib\Wire\AMQPWriter;

class AMQPChannel extends AbstractChannel
{

public $callbacks = array();


protected $is_open = false;


protected $default_ticket;


protected $active;


protected $alerts;


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;






private $publish_cache_max_size;







public function __construct($connection, $channel_id = null, $auto_decode = true)
{
if ($channel_id == null) {
$channel_id = $connection->get_free_channel_id();
}

parent::__construct($connection, $channel_id);

$this->publish_cache = array();
$this->publish_cache_max_size = 100;

$this->debug->debug_msg('using channel_id: ' . $channel_id);

$this->default_ticket = 0;
$this->is_open = false;
$this->active = true; 
 $this->alerts = array();
$this->callbacks = array();
$this->auto_decode = $auto_decode;

try {
$this->x_open();
} catch (\Exception $e) {
$this->close();
throw $e;
}
}




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;
}












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))
{
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]
);

$this->send_method_frame(array($class_id, $method_id), $args);

return $this->wait(array(
$this->waitHelper->get_wait('channel.close_ok')
));
}





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($reader)
{
$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')
));
}




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')
));
}




protected function channel_open_ok($reader)
{
$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')
));
}







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 = null,
$ticket = null
) {
$arguments = $this->getArguments($arguments);
$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')
));
}





protected function exchange_declare_ok($reader)
{
}










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')
));
}






protected function exchange_delete_ok($reader)
{
}












public function exchange_bind(
$destination,
$source,
$routing_key = '',
$nowait = false,
$arguments = null,
$ticket = null
) {
$arguments = $this->getArguments($arguments);
$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')
));
}





protected function exchange_bind_ok($reader)
{
}











public function exchange_unbind($destination, $source, $routing_key = '', $arguments = null, $ticket = null)
{
$arguments = $this->getArguments($arguments);
$ticket = $this->getTicket($ticket);

list($class_id, $method_id, $args) = $this->protocolWriter->exchangeUnbind(
$ticket,
$destination,
$source,
$routing_key,
$arguments
);

$this->send_method_frame(array($class_id, $method_id), $args);

return $this->wait(array(
$this->waitHelper->get_wait('exchange.unbind_ok')
));
}






protected function exchange_unbind_ok($reader)
{
}












public function queue_bind($queue, $exchange, $routing_key = '', $nowait = false, $arguments = null, $ticket = null)
{
$arguments = $this->getArguments($arguments);
$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')
));
}






protected function queue_bind_ok($reader)
{
}











public function queue_unbind($queue, $exchange, $routing_key = '', $arguments = null, $ticket = null)
{
$arguments = $this->getArguments($arguments);
$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')
));
}





protected function queue_unbind_ok($reader)
{
}














public function queue_declare(
$queue = '',
$passive = false,
$durable = false,
$exclusive = false,
$auto_delete = true,
$nowait = false,
$arguments = null,
$ticket = null
) {
$arguments = $this->getArguments($arguments);
$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')
));
}







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')
));
}







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')
));
}







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)
{
$keys = array_reduce(
array_keys($messages),




function ($keys, $key) use ($value) {
if (bccomp($key, $value, 0) <= 0) {
$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')
));
}





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 basic_consume(
$queue = '',
$consumer_tag = '',
$no_local = false,
$no_ack = false,
$exclusive = false,
$nowait = false,
$callback = null,
$ticket = null,
$arguments = array()
) {
$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 == '0.9.1' ? $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')
));
}

$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->delivery_info = array(
'channel' => $this,
'consumer_tag' => $consumer_tag,
'delivery_tag' => $delivery_tag,
'redelivered' => $redelivered,
'exchange' => $exchange,
'routing_key' => $routing_key
);

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')
));
}






protected function basic_get_empty($reader)
{
}








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->delivery_info = array(
'delivery_tag' => $delivery_tag,
'redelivered' => $redelivered,
'exchange' => $exchange,
'routing_key' => $routing_key,
'message_count' => $message_count
);

return $message;
}









private function pre_publish($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
) {
$pkt = new AMQPWriter();
$pkt->write($this->pre_publish($exchange, $routing_key, $mandatory, $immediate, $ticket));

$this->connection->send_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 = bcadd($this->next_delivery_tag, '1', 0);
}
}









public function batch_basic_publish(
$msg,
$exchange = '',
$routing_key = '',
$mandatory = false,
$immediate = false,
$ticket = null
) {
$this->batch_messages[] = func_get_args();
}






public function publish_batch()
{
if (empty($this->batch_messages)) {
return null;
}


$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->pre_publish($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 = bcadd($this->next_delivery_tag, '1', 0);
}
}


 $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')
));
}





protected function basic_qos_ok($reader)
{
}







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')
));
}





protected function basic_recover_ok($reader)
{
}







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')
));
}





protected function tx_commit_ok($reader)
{
}






public function tx_rollback()
{
$this->send_method_frame(array(90, 30));

return $this->wait(array(
$this->waitHelper->get_wait('tx.rollback_ok')
));
}






protected function tx_rollback_ok($reader)
{
}








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')));
$this->next_delivery_tag = 1;
}






public function confirm_select_ok($reader)
{
}







public function wait_for_pending_acks($timeout = 0)
{
$functions = array(
$this->waitHelper->get_wait('basic.ack'),
$this->waitHelper->get_wait('basic.nack'),
);

while (count($this->published_messages) !== 0) {
if ($timeout > 0) {
$this->wait($functions, true, $timeout);
} else {
$this->wait($functions);
}
}
}






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'),
);

while (count($this->published_messages) !== 0) {
if ($timeout > 0) {
$this->wait($functions, true, $timeout);
} else {
$this->wait($functions);
}
}
}






public function tx_select()
{
$this->send_method_frame(array(90, 10));

return $this->wait(array(
$this->waitHelper->get_wait('tx.select_ok')
));
}





protected function tx_select_ok($reader)
{
}





protected function getArguments($arguments)
{
return (null === $arguments) ? array() : $arguments;
}





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)
{
if (!is_callable($callback)) {
throw new \InvalidArgumentException(sprintf(
'Given callback "%s" should be callable. %s type was given.',
$callback,
gettype($callback)
));
}

$this->basic_return_callback = $callback;
}







public function set_nack_handler($callback)
{
if (!is_callable($callback)) {
throw new \InvalidArgumentException(sprintf(
'Given callback "%s" should be callable. %s type was given.',
$callback,
gettype($callback)
));
}

$this->nack_handler = $callback;
}







public function set_ack_handler($callback)
{
if (!is_callable($callback)) {
throw new \InvalidArgumentException(sprintf(
'Given callback "%s" should be callable. %s type was given.',
$callback,
gettype($callback)
));
}

$this->ack_handler = $callback;
}
}
<?php
namespace PhpAmqpLib\Message;

use PhpAmqpLib\Wire\GenericContent;




class AMQPMessage extends GenericContent
{
const DELIVERY_MODE_NON_PERSISTENT = 1;
const DELIVERY_MODE_PERSISTENT = 2;


public $body;


public $body_size;


public $is_truncated = false;


public $content_encoding;


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);
parent::__construct($properties, static::$propertyDefinitions);
}




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;
}
}
<?php
namespace PhpAmqpLib\Exception;

class AMQPOutOfRangeException extends \OutOfRangeException implements AMQPExceptionInterface
{

}
<?php
namespace PhpAmqpLib\Exception;

class AMQPProtocolChannelException extends AMQPProtocolException
{
}
<?php
namespace PhpAmqpLib\Exception;

class AMQPIOWaitException extends AMQPRuntimeException
{
}
<?php
namespace PhpAmqpLib\Exception;




class AMQPConnectionException extends AMQPException
{
}
<?php
namespace PhpAmqpLib\Exception;

class AMQPRuntimeException extends \RuntimeException implements AMQPExceptionInterface
{
}
<?php
namespace PhpAmqpLib\Exception;




class AMQPChannelException extends AMQPException
{
}
<?php
namespace PhpAmqpLib\Exception;

interface AMQPExceptionInterface
{
}
<?php
namespace PhpAmqpLib\Exception;

class AMQPTimeoutException extends \RuntimeException implements AMQPExceptionInterface
{
}
<?php
namespace PhpAmqpLib\Exception;

class AMQPOutOfBoundsException extends \OutOfBoundsException implements AMQPExceptionInterface
{
}
<?php
namespace PhpAmqpLib\Exception;

class AMQPProtocolConnectionException extends AMQPProtocolException
{
}
<?php
namespace PhpAmqpLib\Exception;

class AMQPIOException extends \Exception implements AMQPExceptionInterface
{
}
<?php
namespace PhpAmqpLib\Exception;

class AMQPLogicException extends \LogicException implements AMQPExceptionInterface
{

}
<?php
namespace PhpAmqpLib\Exception;

class AMQPInvalidArgumentException extends \RuntimeException implements AMQPExceptionInterface
{
}
<?php
namespace PhpAmqpLib\Exception;

class AMQPBasicCancelException extends \Exception implements AMQPExceptionInterface
{

public $consumerTag;




public function __construct($consumerTag)
{
$this->consumerTag = $consumerTag;
}
}
<?php
namespace PhpAmqpLib\Exception;


use PhpAmqpLib\Channel\AbstractChannel;
use PhpAmqpLib\Helper\MiscHelper;

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;

$ms = MiscHelper::methodSig($method_sig);

$protocolClass = AbstractChannel::$PROTOCOL_CONSTANTS_CLASS;
$mn = isset($protocolClass::$GLOBAL_METHOD_NAMES[$ms])
? $protocolClass::$GLOBAL_METHOD_NAMES[$ms]
: $mn = '';

$this->args = array($reply_code, $reply_text, $method_sig, $mn);
}
}
<?php
namespace PhpAmqpLib\Exception;


use PhpAmqpLib\Channel\AbstractChannel;
use PhpAmqpLib\Helper\MiscHelper;




class AMQPException extends \Exception
{

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;

$ms = MiscHelper::methodSig($method_sig);
$protocolClass = AbstractChannel::$PROTOCOL_CONSTANTS_CLASS;
$mn = isset($protocolClass::$GLOBAL_METHOD_NAMES[$ms])
? $protocolClass::$GLOBAL_METHOD_NAMES[$ms]
: $mn = '';

$this->args = array($reply_code, $reply_text, $method_sig, $mn);
}
}
<?php

namespace PhpAmqpLib\Connection;




class AMQPLazySocketConnection extends AMQPSocketConnection
{





public function getSocket()
{
$this->connect();

return parent::getSocket();
}




public function channel($channel_id = null)
{
$this->connect();

return parent::channel($channel_id);
}




protected function getIO()
{
if (!$this->io) {
$this->connect();
}

return $this->io;
}






public function connectOnConstruct()
{
return false;
}
}<?php
namespace PhpAmqpLib\Connection;








class AMQPConnection extends AMQPStreamConnection
{
}
<?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',
$timeout = 3,
$keepalive = false
) {
$io = new SocketIO($host, $port, $timeout, $keepalive);

parent::__construct(
$user,
$password,
$vhost,
$insist,
$login_method,
$login_response,
$locale,
$io
);
}
}
<?php
namespace PhpAmqpLib\Connection;

class AMQPLazyConnection extends AMQPStreamConnection
{





public function getSocket()
{
$this->connect();

return parent::getSocket();
}




public function channel($channel_id = null)
{
$this->connect();

return parent::channel($channel_id);
}




protected function getIO()
{
if (!$this->io) {
$this->connect();
}

return $this->io;
}






public function connectOnConstruct()
{
return false;
}
}
<?php
namespace PhpAmqpLib\Connection;

class AMQPSSLConnection extends AMQPStreamConnection
{









public function __construct(
$host,
$port,
$user,
$password,
$vhost = '/',
$ssl_options = array(),
$options = array()
) {
$ssl_context = empty($ssl_options) ? null : $this->create_ssl_context($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'] : 3,
$ssl_context,
isset($options['keepalive']) ? $options['keepalive'] : false,
isset($options['heartbeat']) ? $options['heartbeat'] : 0
);
}





private function create_ssl_context($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;

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
) {
$io = new StreamIO(
$host,
$port,
$connection_timeout,
$read_write_timeout,
$context,
$keepalive,
$heartbeat
);

parent::__construct(
$user,
$password,
$vhost,
$insist,
$login_method,
$login_response,
$locale,
$io,
$heartbeat
);


 $this->construct_params = func_get_args();
}
}
<?php
namespace PhpAmqpLib\Connection;

use PhpAmqpLib\Channel\AMQPChannel;
use PhpAmqpLib\Channel\AbstractChannel;
use PhpAmqpLib\Exception\AMQPProtocolConnectionException;
use PhpAmqpLib\Exception\AMQPRuntimeException;
use PhpAmqpLib\Exception\AMQPTimeoutException;
use PhpAmqpLib\Wire\AMQPReader;
use PhpAmqpLib\Wire\AMQPTable;
use PhpAmqpLib\Wire\AMQPWriter;
use PhpAmqpLib\Wire\IO\AbstractIO;
use PhpAmqpLib\Wire\IO\SocketIO;
use PhpAmqpLib\Wire\IO\StreamIO;

class AbstractConnection extends AbstractChannel
{

public static $LIBRARY_PROPERTIES = array(
'product' => array('S', 'AMQPLib'),
'platform' => array('S', 'PHP'),
'version' => array('S', '2.6'),
'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 $sock;


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;








private $prepare_content_cache;


private $prepare_content_cache_max_size;













public function __construct(
$user,
$password,
$vhost = '/',
$insist = false,
$login_method = 'AMQPLAIN',
$login_response = null,
$locale = 'en_US',
AbstractIO $io,
$heartbeat = 0
) {

 $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->login_response = $login_response;
$this->locale = $locale;
$this->io = $io;
$this->heartbeat = $heartbeat;

if ($user && $password) {
$this->login_response = new AMQPWriter();
$this->login_response->write_table(array(
'LOGIN' => array('S', $user),
'PASSWORD' => array('S', $password)
));


 $responseValue = $this->login_response->getvalue();
$this->login_response = mb_substr($responseValue, 4, mb_strlen($responseValue, 'ASCII') - 4, 'ASCII');

} else {
$this->login_response = null;
}

$this->prepare_content_cache = array();
$this->prepare_content_cache_max_size = 100;


 if ($this->connectOnConstruct()) {
$this->connect();
}
}




protected function connect()
{
try {

 while (!$this->isConnected()) {

 $this->setIsConnected(true);


 $this->getIO()->connect();

$this->channels = array();

 parent::__construct($this, 0);

$this->input = new AMQPReader(null, $this->getIO());

$this->write($this->amqp_protocol_header);
$this->wait(array($this->waitHelper->get_wait('connection.start')));
$this->x_start_ok(self::$LIBRARY_PROPERTIES, $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')
));
}

$host = $this->x_open($this->vhost, '', $this->insist);
if (!$host) {
return null; 
 }

$this->setIsConnected(false);
$this->closeChannels();


 $this->close_socket();
}

} catch (\Exception $e) {

 $this->setIsConnected(false);
$this->closeChannels();
throw $e; 
 }
}





public function reconnect()
{

 $this->safeClose();

 $this->getIO()->reconnect();
$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 (isset($this->input) && $this->input) {
$this->close();
}
} catch (\Exception $e) {

 }
}






public function select($sec, $usec = 0)
{
return $this->getIO()->select($sec, $usec);
}







public function set_close_on_destruct($close = true)
{
$this->close_on_destruct = (bool) $close;
}

protected function close_input()
{
$this->debug->debug_msg('closing input');

if (!is_null($this->input)) {
$this->input->close();
$this->input = null;
}
}

protected function close_socket()
{
$this->debug->debug_msg('closing socket');

if (!is_null($this->getIO())) {
$this->getIO()->close();
}
}




public function write($data)
{
$this->debug->debug_hexdump($data);

try {
$this->getIO()->write($data);
} catch (AMQPRuntimeException $e) {
$this->setIsConnected(false);
throw $e;
}
}

protected function do_close()
{
$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 = null)
{
$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 = null)
{
$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 (is_null($this->input))
{
$this->setIsConnected(false);
throw new AMQPRuntimeException('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();
$class = self::$PROTOCOL_CONSTANTS_CLASS;
if (!array_key_exists($frame_type, $class::$FRAME_TYPES)) {
throw new AMQPRuntimeException('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) {
$this->input->setTimeout($currentTimeout);
throw $e;
}

$this->input->setTimeout($currentTimeout);

if ($ch != 0xCE) {
throw new AMQPRuntimeException(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) {
$now = time();
list($frame_type, $frame_channel, $payload) = $this->wait_frame($_timeout);

if ($frame_channel === 0 && $frame_type === 8) {

 if($_timeout > 0) {
$_timeout -= time() - $now;
if($_timeout <= 0) {

 throw new AMQPTimeoutException("Timeout waiting on channel");
}
}
continue;

} else {

if ($frame_channel == $channel_id) {
return array($frame_type, $payload);
}


 
 
 
 if (isset($this->channels[$frame_channel])) {
array_push($this->channels[$frame_channel]->frame_queue, array($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 ? $channel_id : $this->get_free_channel_id();
$ch = new AMQPChannel($this->connection, $channel_id);
$this->channels[$channel_id] = $ch;

return $ch;
}









public function close($reply_code = 0, $reply_text = '', $method_sig = array(0, 0))
{
if ($this->io instanceof StreamIO)
{
$this->io->disableHeartbeat();
}

if (!$this->protocolWriter || !$this->isConnected()) {
return null;
}

$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);

$this->setIsConnected(false);

return $this->wait(array(
$this->waitHelper->get_wait('connection.close_ok')
));
}





protected function connection_close(AMQPReader $reader)
{
$reply_code = $reader->read_short();
$reply_text = $reader->read_shortstr();
$class_id = $reader->read_short();
$method_id = $reader->read_short();

$this->x_close_ok();

throw new AMQPProtocolConnectionException($reply_code, $reply_text, array($class_id, $method_id));
}




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($args)
{
$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 == '0.8') {
$wait[] = $this->waitHelper->get_wait('connection.redirect');
}

return $this->wait($wait);
}






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)
{
$challenge = $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 = $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 getSocket()
{
return $this->io->getSocket();
}




protected function getIO()
{
return $this->io;
}






protected function connection_blocked(AMQPReader $args)
{

 $this->dispatch_to_handler($this->connection_block_handler, array($args->read_shortstr()));
}






protected function connection_unblocked(AMQPReader $args)
{

 $this->dispatch_to_handler($this->connection_unblock_handler, array());
}






public function set_connection_block_handler($callback)
{
$this->connection_block_handler = $callback;
}






public function set_connection_unblock_handler($callback)
{
$this->connection_unblock_handler = $callback;
}






public function isConnected()
{
return (bool) $this->is_connected;
}






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;
}
}
<?php



require_once __DIR__ . '/composer' . '/autoload_real.php';

return ComposerAutoloaderInitc4909e075a7b68a94b7e4489eb2bb42e::getLoader();
<?php









namespace SebastianBergmann\Diff;



class Chunk
{



private $start;




private $startRange;




private $end;



private $endRange;




private $lines;








public function __construct($start = 0, $startRange = 1, $end = 0, $endRange = 1, array $lines = array())
{
$this->start = (int) $start;
$this->startRange = (int) $startRange;
$this->end = (int) $end;
$this->endRange = (int) $endRange;
$this->lines = $lines;
}




public function getStart()
{
return $this->start;
}




public function getStartRange()
{
return $this->startRange;
}




public function getEnd()
{
return $this->end;
}




public function getEndRange()
{
return $this->endRange;
}




public function getLines()
{
return $this->lines;
}




public function setLines(array $lines)
{
$this->lines = $lines;
}
}
<?php









namespace SebastianBergmann\Diff\LCS;




class MemoryEfficientImplementation implements LongestCommonSubsequence
{








public function calculate(array $from, array $to)
{
$cFrom = count($from);
$cTo = count($to);

if ($cFrom == 0) {
return array();
} elseif ($cFrom == 1) {
if (in_array($from[0], $to)) {
return array($from[0]);
} else {
return array();
}
} else {
$i = intval($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)
{
$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









namespace SebastianBergmann\Diff\LCS;




interface LongestCommonSubsequence
{








public function calculate(array $from, array $to);
}
<?php









namespace SebastianBergmann\Diff\LCS;




class TimeEfficientImplementation implements LongestCommonSubsequence
{








public function calculate(array $from, array $to)
{
$common = array();
$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









namespace SebastianBergmann\Diff;



class Line
{
const ADDED = 1;
const REMOVED = 2;
const UNCHANGED = 3;




private $type;




private $content;





public function __construct($type = self::UNCHANGED, $content = '')
{
$this->type = $type;
$this->content = $content;
}




public function getContent()
{
return $this->content;
}




public function getType()
{
return $this->type;
}
}
<?php









namespace SebastianBergmann\Diff;

use SebastianBergmann\Diff\LCS\LongestCommonSubsequence;
use SebastianBergmann\Diff\LCS\TimeEfficientImplementation;
use SebastianBergmann\Diff\LCS\MemoryEfficientImplementation;




class Differ
{



private $header;




private $showNonDiffLines;




public function __construct($header = "--- Original\n+++ New\n", $showNonDiffLines = true)
{
$this->header = $header;
$this->showNonDiffLines = $showNonDiffLines;
}










public function diff($from, $to, LongestCommonSubsequence $lcs = null)
{
if (!is_array($from) && !is_string($from)) {
$from = (string) $from;
}

if (!is_array($to) && !is_string($to)) {
$to = (string) $to;
}

$buffer = $this->header;
$diff = $this->diffToArray($from, $to, $lcs);

$inOld = false;
$i = 0;
$old = array();

foreach ($diff as $line) {
if ($line[1] === 0 ) {
if ($inOld === false) {
$inOld = $i;
}
} elseif ($inOld !== false) {
if (($i - $inOld) > 5) {
$old[$inOld] = $i - 1;
}

$inOld = false;
}

++$i;
}

$start = isset($old[0]) ? $old[0] : 0;
$end = count($diff);

if ($tmp = array_search($end, $old)) {
$end = $tmp;
}

$newChunk = true;

for ($i = $start; $i < $end; $i++) {
if (isset($old[$i])) {
$buffer .= "\n";
$newChunk = true;
$i = $old[$i];
}

if ($newChunk) {
if ($this->showNonDiffLines === true) {
$buffer .= "@@ @@\n";
}
$newChunk = false;
}

if ($diff[$i][1] === 1 ) {
$buffer .= '+' . $diff[$i][0] . "\n";
} elseif ($diff[$i][1] === 2 ) {
$buffer .= '-' . $diff[$i][0] . "\n";
} elseif ($this->showNonDiffLines === true) {
$buffer .= ' ' . $diff[$i][0] . "\n";
}
}

return $buffer;
}


















public function diffToArray($from, $to, LongestCommonSubsequence $lcs = null)
{
preg_match_all('(\r\n|\r|\n)', $from, $fromMatches);
preg_match_all('(\r\n|\r|\n)', $to, $toMatches);

if (is_string($from)) {
$from = preg_split('(\r\n|\r|\n)', $from);
}

if (is_string($to)) {
$to = preg_split('(\r\n|\r|\n)', $to);
}

$start = array();
$end = array();
$fromLength = count($from);
$toLength = count($to);
$length = min($fromLength, $toLength);

for ($i = 0; $i < $length; ++$i) {
if ($from[$i] === $to[$i]) {
$start[] = $from[$i];
unset($from[$i], $to[$i]);
} else {
break;
}
}

$length -= $i;

for ($i = 1; $i < $length; ++$i) {
if ($from[$fromLength - $i] === $to[$toLength - $i]) {
array_unshift($end, $from[$fromLength - $i]);
unset($from[$fromLength - $i], $to[$toLength - $i]);
} else {
break;
}
}

if ($lcs === null) {
$lcs = $this->selectLcsImplementation($from, $to);
}

$common = $lcs->calculate(array_values($from), array_values($to));
$diff = array();

if (isset($fromMatches[0]) && $toMatches[0] &&
count($fromMatches[0]) === count($toMatches[0]) &&
$fromMatches[0] !== $toMatches[0]) {
$diff[] = array(
'#Warning: Strings contain different line endings!', 0
);
}

foreach ($start as $token) {
$diff[] = array($token, 0 );
}

reset($from);
reset($to);

foreach ($common as $token) {
while ((($fromToken = reset($from)) !== $token)) {
$diff[] = array(array_shift($from), 2 );
}

while ((($toToken = reset($to)) !== $token)) {
$diff[] = array(array_shift($to), 1 );
}

$diff[] = array($token, 0 );

array_shift($from);
array_shift($to);
}

while (($token = array_shift($from)) !== null) {
$diff[] = array($token, 2 );
}

while (($token = array_shift($to)) !== null) {
$diff[] = array($token, 1 );
}

foreach ($end as $token) {
$diff[] = array($token, 0 );
}

return $diff;
}







private function selectLcsImplementation(array $from, array $to)
{

 
 
 
 $memoryLimit = 100 * 1024 * 1024;

if ($this->calculateEstimatedFootprint($from, $to) > $memoryLimit) {
return new MemoryEfficientImplementation;
}

return new TimeEfficientImplementation;
}









private function calculateEstimatedFootprint(array $from, array $to)
{
$itemSize = PHP_INT_SIZE == 4 ? 76 : 144;

return $itemSize * pow(min(count($from), count($to)), 2);
}
}
<?php









namespace SebastianBergmann\Diff;




class Parser
{





public function parse($string)
{
$lines = preg_split('(\r\n|\r|\n)', $string);
$lineCount = count($lines);
$diffs = array();
$diff = null;
$collected = array();

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 = array();
}

$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 (count($collected) && ($diff !== null)) {
$this->parseFileDiff($diff, $collected);
$diffs[] = $diff;
}

return $diffs;
}





private function parseFileDiff(Diff $diff, array $lines)
{
$chunks = array();

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(
$match['start'],
isset($match['startrange']) ? max(1, $match['startrange']) : 1,
$match['end'],
isset($match['endrange']) ? max(1, $match['endrange']) : 1
);

$chunks[] = $chunk;
$diffLines = array();
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 (isset($chunk)) {
$chunk->setLines($diffLines);
}
}
}

$diff->setChunks($chunks);
}
}
<?php









namespace SebastianBergmann\Diff;



class Diff
{



private $from;




private $to;




private $chunks;






public function __construct($from, $to, array $chunks = array())
{
$this->from = $from;
$this->to = $to;
$this->chunks = $chunks;
}




public function getFrom()
{
return $this->from;
}




public function getTo()
{
return $this->to;
}




public function getChunks()
{
return $this->chunks;
}




public function setChunks(array $chunks)
{
$this->chunks = $chunks;
}
}
<?php









namespace SebastianBergmann\Comparator;




class Factory
{



private $comparators = array();




private static $instance;




public function __construct()
{
$this->register(new TypeComparator);
$this->register(new ScalarComparator);
$this->register(new NumericComparator);
$this->register(new DoubleComparator);
$this->register(new ArrayComparator);
$this->register(new ResourceComparator);
$this->register(new ObjectComparator);
$this->register(new ExceptionComparator);
$this->register(new SplObjectStorageComparator);
$this->register(new DOMNodeComparator);
$this->register(new MockObjectComparator);
$this->register(new DateTimeComparator);
}




public static function getInstance()
{
if (self::$instance === null) {
self::$instance = new self;
}

return self::$instance;
}








public function getComparatorFor($expected, $actual)
{
foreach ($this->comparators as $comparator) {
if ($comparator->accepts($expected, $actual)) {
return $comparator;
}
}
}











public function register(Comparator $comparator)
{
array_unshift($this->comparators, $comparator);

$comparator->setFactory($this);
}








public function unregister(Comparator $comparator)
{
foreach ($this->comparators as $key => $_comparator) {
if ($comparator === $_comparator) {
unset($this->comparators[$key]);
}
}
}
}
<?php









namespace SebastianBergmann\Comparator;




class MockObjectComparator extends ObjectComparator
{







public function accepts($expected, $actual)
{
return $expected 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 NumericComparator extends ScalarComparator
{







public function accepts($expected, $actual)
{

 
 return is_numeric($expected) && is_numeric($actual) &&
!(is_double($expected) || is_double($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) or 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;




class DoubleComparator extends NumericComparator
{





const EPSILON = 0.0000000001;








public function accepts($expected, $actual)
{
return (is_double($expected) || is_double($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;

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 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 = array())
{
if ($canonicalize) {
sort($expected);
sort($actual);
}

$remaining = $actual;
$expString = $actString = "Array (\n";
$equal = true;

foreach ($expected as $key => $value) {
unset($remaining[$key]);

if (!array_key_exists($key, $actual)) {
$expString .= 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);

$expString .= sprintf(
"    %s => %s\n",
$this->exporter->export($key),
$this->exporter->shortenedExport($value)
);
$actString .= sprintf(
"    %s => %s\n",
$this->exporter->export($key),
$this->exporter->shortenedExport($actual[$key])
);
} catch (ComparisonFailure $e) {
$expString .= sprintf(
"    %s => %s\n",
$this->exporter->export($key),
$e->getExpectedAsString()
? $this->indent($e->getExpectedAsString())
: $this->exporter->shortenedExport($e->getExpected())
);

$actString .= 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) {
$actString .= sprintf(
"    %s => %s\n",
$this->exporter->export($key),
$this->exporter->shortenedExport($value)
);

$equal = false;
}

$expString .= ')';
$actString .= ')';

if (!$equal) {
throw new ComparisonFailure(
$expected,
$actual,
$expString,
$actString,
false,
'Failed asserting that two arrays are equal.'
);
}
}

protected function indent($lines)
{
return trim(str_replace("\n", "\n    ", $lines));
}
}
<?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) {
if (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.'
);
}

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 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 = array())
{
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(array($actual, $expected), $processed, true) ||
in_array(array($expected, $actual), $processed, true)) {
return;
}

$processed[] = array($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;

use SebastianBergmann\Diff\Differ;




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("\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 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)
{
$delta = new \DateInterval(sprintf('PT%sS', abs($delta)));

$expectedLower = clone $expected;
$expectedUpper = clone $expected;

if ($actual < $expectedLower->sub($delta) ||
$actual > $expectedUpper->add($delta)) {
throw new ComparisonFailure(
$expected,
$actual,
$this->dateTimeToString($expected),
$this->dateTimeToString($actual),
false,
'Failed asserting that two DateTime objects are equal.'
);
}
}









protected function dateTimeToString($datetime)
{
$string = $datetime->format(\DateTime::ISO8601);

return $string ? $string : 'Invalid DateTimeInterface object';
}
}
<?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\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 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;

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)
{
$expectedAsString = $this->nodeToText($expected, true, $ignoreCase);
$actualAsString = $this->nodeToText($actual, true, $ignoreCase);

if ($expectedAsString !== $actualAsString) {
if ($expected instanceof DOMDocument) {
$type = 'documents';
} else {
$type = '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, $canonicalize, $ignoreCase)
{
if ($canonicalize) {
$document = new DOMDocument;
$document->loadXML($node->C14N());

$node = $document;
}

if ($node instanceof DOMDocument) {
$document = $node;
} else {
$document = $node->ownerDocument;
}

$document->formatOutput = true;
$document->normalizeDocument();

if ($node instanceof DOMDocument) {
$text = $node->saveXML();
} else {
$text = $document->saveXML($node);
}

if ($ignoreCase) {
$text = strtolower($text);
}

return $text;
}
}
<?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);
}

else if (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);
}

else if (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;
}

$this->arrays[] = &$array;

return count($this->arrays) - 1;
}





private function addObject($object)
{
if (!$this->objects->contains($object)) {
$this->objects->attach($object);
}

return spl_object_hash($object);
}





private function containsArray(array &$array)
{
$keys = array_keys($this->arrays, $array, true);
$hash = '_Key_' . microtime(true);

foreach ($keys as $key) {
$this->arrays[$key][$hash] = $hash;

if (isset($array[$hash]) && $array[$hash] === $hash) {
unset($this->arrays[$key][$hash]);

return $key;
}

unset($this->arrays[$key][$hash]);
}

return false;
}





private function containsObject($value)
{
if ($this->objects->contains($value)) {
return spl_object_hash($value);
}

return false;
}
}
<?php









namespace SebastianBergmann\RecursionContext;



interface Exception
{
}
<?php









namespace SebastianBergmann\RecursionContext;



final class InvalidArgumentException extends \InvalidArgumentException implements Exception
{
}
<?php









namespace SebastianBergmann\Environment;



class Console
{
const STDIN = 0;
const STDOUT = 1;
const STDERR = 2;









public function hasColorSupport()
{
if (DIRECTORY_SEPARATOR == '\\') {
return false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI') || 'xterm' === getenv('TERM');
}

if (!defined('STDOUT')) {
return false;
}

return $this->isInteractive(STDOUT);
}






public function getNumberOfColumns()
{
if (DIRECTORY_SEPARATOR == '\\') {
$columns = 80;

if (preg_match('/^(\d+)x\d+ \(\d+x(\d+)\)$/', trim(getenv('ANSICON')), $matches)) {
$columns = $matches[1];
} elseif (function_exists('proc_open')) {
$process = proc_open(
'mode CON',
array(
1 => array('pipe', 'w'),
2 => array('pipe', 'w')
),
$pipes,
null,
null,
array('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;
}

if (!$this->isInteractive(self::STDIN)) {
return 80;
}

if (preg_match('#\d+ (\d+)#', shell_exec('stty size'), $match) === 1) {
if ((int) $match[1] > 0) {
return (int) $match[1];
}
}

if (preg_match('#columns = (\d+);#', shell_exec('stty'), $match) === 1) {
if ((int) $match[1] > 0) {
return (int) $match[1];
}
}

return 80;
}








public function isInteractive($fileDescriptor = self::STDOUT)
{
return function_exists('posix_isatty') && @posix_isatty($fileDescriptor);
}
}
<?php









namespace SebastianBergmann\Environment;




class Runtime
{



private static $binary;







public function canCollectCodeCoverage()
{
return $this->hasXdebug() || $this->hasPHPDBGCodeCoverage();
}







public function getBinary()
{

 if (self::$binary === null && $this->isHHVM()) {
if ((self::$binary = getenv('PHP_BINARY')) === false) {
self::$binary = PHP_BINARY;
}

self::$binary = escapeshellarg(self::$binary) . ' --php';
}


 if (self::$binary === null && defined('PHP_BINARY')) {
self::$binary = escapeshellarg(PHP_BINARY);
}


 if (self::$binary === null) {
if (PHP_SAPI == 'cli' && isset($_SERVER['_'])) {
if (strpos($_SERVER['_'], 'phpunit') !== false) {
$file = file($_SERVER['_']);

if (strpos($file[0], ' ') !== false) {
$tmp = explode(' ', $file[0]);
self::$binary = escapeshellarg(trim($tmp[1]));
} else {
self::$binary = escapeshellarg(ltrim(trim($file[0]), '#!'));
}
} elseif (strpos(basename($_SERVER['_']), 'php') !== false) {
self::$binary = escapeshellarg($_SERVER['_']);
}
}
}

if (self::$binary === null) {
$possibleBinaryLocations = array(
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()
{
return $this->getName() . ' ' . $this->getVersion();
}




public function getName()
{
if ($this->isHHVM()) {
return 'HHVM';
} elseif ($this->isPHPDBG()) {
return 'PHPDBG';
} else {
return 'PHP';
}
}




public function getVendorUrl()
{
if ($this->isHHVM()) {
return 'http://hhvm.com/';
} else {
return 'http://php.net/';
}
}




public function getVersion()
{
if ($this->isHHVM()) {
return HHVM_VERSION;
} else {
return PHP_VERSION;
}
}






public function hasXdebug()
{
return ($this->isPHP() || $this->isHHVM()) && extension_loaded('xdebug');
}






public function isHHVM()
{
return defined('HHVM_VERSION');
}






public function isPHP()
{
return !$this->isHHVM() && !$this->isPHPDBG();
}






public function isPHPDBG()
{
return PHP_SAPI === 'phpdbg' && !$this->isHHVM();
}







public function hasPHPDBGCodeCoverage()
{
return $this->isPHPDBG() && function_exists('phpdbg_start_oplog');
}
}
<?php









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 = array();
$exporter = new self();

if (!$context) {
$context = new Context;
}

$context->add($data);

foreach ($data 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 = $this->export($value);

if (strlen($string) > 40) {
$string = substr($string, 0, 30) . '...' . substr($string, -7);
}

return str_replace("\n", '\n', $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 = 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 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;
}

$key = $processed->add($value);
$values = '';

if (count($value) > 0) {
foreach ($value 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);
}
}
<?php









namespace SebastianBergmann\GlobalState;



class RuntimeException extends \RuntimeException implements Exception
{
}
<?php









namespace SebastianBergmann\GlobalState;

use ReflectionClass;
use Serializable;




class Snapshot
{



private $blacklist;




private $globalVariables = array();




private $superGlobalArrays = array();




private $superGlobalVariables = array();




private $staticAttributes = array();




private $iniSettings = array();




private $includedFiles = array();




private $constants = array();




private $functions = array();




private $interfaces = array();




private $classes = array();




private $traits = array();















public function __construct(Blacklist $blacklist = null, $includeGlobalVariables = true, $includeStaticAttributes = true, $includeConstants = true, $includeFunctions = true, $includeClasses = true, $includeInterfaces = true, $includeTraits = true, $includeIniSettings = true, $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();
}

if (function_exists('get_declared_traits')) {
$this->traits = get_declared_traits();
}
}




public function blacklist()
{
return $this->blacklist;
}




public function globalVariables()
{
return $this->globalVariables;
}




public function superGlobalVariables()
{
return $this->superGlobalVariables;
}






public function superGlobalArrays()
{
return $this->superGlobalArrays;
}




public function staticAttributes()
{
return $this->staticAttributes;
}




public function iniSettings()
{
return $this->iniSettings;
}




public function includedFiles()
{
return $this->includedFiles;
}




public function constants()
{
return $this->constants;
}




public function functions()
{
return $this->functions;
}




public function interfaces()
{
return $this->interfaces;
}




public function classes()
{
return $this->classes;
}




public function traits()
{
return $this->traits;
}




private function snapshotConstants()
{
$constants = get_defined_constants(true);

if (isset($constants['user'])) {
$this->constants = $constants['user'];
}
}




private function snapshotFunctions()
{
$functions = get_defined_functions();

$this->functions = $functions['user'];
}




private function snapshotClasses()
{
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()
{
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()
{
$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($superGlobalArray)
{
$this->superGlobalVariables[$superGlobalArray] = array();

if (isset($GLOBALS[$superGlobalArray]) && is_array($GLOBALS[$superGlobalArray])) {
foreach ($GLOBALS[$superGlobalArray] as $key => $value) {
$this->superGlobalVariables[$superGlobalArray][$key] = unserialize(serialize($value));
}
}
}




private function snapshotStaticAttributes()
{
foreach ($this->classes as $className) {
$class = new ReflectionClass($className);
$snapshot = array();

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()
{
$this->superGlobalArrays = array(
'_ENV',
'_POST',
'_GET',
'_COOKIE',
'_SERVER',
'_FILES',
'_REQUEST'
);

if (ini_get('register_long_arrays') == '1') {
$this->superGlobalArrays = array_merge(
$this->superGlobalArrays,
array(
'HTTP_ENV_VARS',
'HTTP_POST_VARS',
'HTTP_GET_VARS',
'HTTP_COOKIE_VARS',
'HTTP_SERVER_VARS',
'HTTP_POST_FILES'
)
);
}
}






private function canBeSerialized($variable)
{
if (!is_object($variable)) {
return !is_resource($variable);
}

if ($variable instanceof \stdClass) {
return true;
}

$class = new ReflectionClass($variable);

do {
if ($class->isInternal()) {
return $variable instanceof Serializable;
}
} while ($class = $class->getParentClass());

return true;
}
}
<?php









namespace SebastianBergmann\GlobalState;




class CodeExporter
{




public function constants(Snapshot $snapshot)
{
$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 iniSettings(Snapshot $snapshot)
{
$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)
{
if (is_scalar($variable) || is_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)
{
$result = true;

foreach ($array as $element) {
if (is_array($element)) {
$result = self::arrayOnlyContainsScalars($element);
} elseif (!is_scalar($element) && !is_null($element)) {
$result = false;
}

if ($result === false) {
break;
}
}

return $result;
}
}
<?php









namespace SebastianBergmann\GlobalState;

use ReflectionProperty;




class Restorer
{







public function restoreFunctions(Snapshot $snapshot)
{
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)
{
$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 (isset($globalVariables[$key])) {
$GLOBALS[$key] = $globalVariables[$key];
} else {
unset($GLOBALS[$key]);
}
}
}
}






public function restoreStaticAttributes(Snapshot $snapshot)
{
$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, $superGlobalArray)
{
$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









namespace SebastianBergmann\GlobalState;

use ReflectionClass;




class Blacklist
{



private $globalVariables = array();




private $classes = array();




private $classNamePrefixes = array();




private $parentClasses = array();




private $interfaces = array();




private $staticAttributes = array();




public function addGlobalVariable($variableName)
{
$this->globalVariables[$variableName] = true;
}




public function addClass($className)
{
$this->classes[] = $className;
}




public function addSubclassesOf($className)
{
$this->parentClasses[] = $className;
}




public function addImplementorsOf($interfaceName)
{
$this->interfaces[] = $interfaceName;
}




public function addClassNamePrefix($classNamePrefix)
{
$this->classNamePrefixes[] = $classNamePrefix;
}





public function addStaticAttribute($className, $attributeName)
{
if (!isset($this->staticAttributes[$className])) {
$this->staticAttributes[$className] = array();
}

$this->staticAttributes[$className][$attributeName] = true;
}





public function isGlobalVariableBlacklisted($variableName)
{
return isset($this->globalVariables[$variableName]);
}






public function isStaticAttributeBlacklisted($className, $attributeName)
{
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









namespace SebastianBergmann\GlobalState;



interface Exception
{
}
<?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;
}

$dir = getcwd();
chdir($path);
$returnCode = 1;
$result = @exec('git describe --tags 2>&1', $output, $returnCode);
chdir($dir);

if ($returnCode !== 0) {
return false;
}

return $result;
}
}
<?php


















namespace Doctrine\Instantiator;






interface InstantiatorInterface
{







public function instantiate($className);
}
<?php


















namespace Doctrine\Instantiator;

use Closure;
use Doctrine\Instantiator\Exception\InvalidArgumentException;
use Doctrine\Instantiator\Exception\UnexpectedValueException;
use Exception;
use ReflectionClass;






final class Instantiator implements InstantiatorInterface
{





const SERIALIZATION_FORMAT_USE_UNSERIALIZER = 'C';
const SERIALIZATION_FORMAT_AVOID_UNSERIALIZER = 'O';




private static $cachedInstantiators = array();




private static $cachedCloneables = array();




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($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($className)
{
$reflectionClass = $this->getReflectionClass($className);

if ($this->isInstantiableViaReflection($reflectionClass)) {
return function () use ($reflectionClass) {
return $reflectionClass->newInstanceWithoutConstructor();
};
}

$serializedString = sprintf(
'%s:%d:"%s":0:{}',
$this->getSerializationFormat($reflectionClass),
strlen($className),
$className
);

$this->checkIfUnSerializationIsSupported($reflectionClass, $serializedString);

return function () use ($serializedString) {
return unserialize($serializedString);
};
}








private function getReflectionClass($className)
{
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, $serializedString)
{
set_error_handler(function ($code, $message, $file, $line) use ($reflectionClass, & $error) {
$error = UnexpectedValueException::fromUncleanUnSerialization(
$reflectionClass,
$message,
$code,
$file,
$line
);
});

$this->attemptInstantiationViaUnSerialization($reflectionClass, $serializedString);

restore_error_handler();

if ($error) {
throw $error;
}
}









private function attemptInstantiationViaUnSerialization(ReflectionClass $reflectionClass, $serializedString)
{
try {
unserialize($serializedString);
} catch (Exception $exception) {
restore_error_handler();

throw UnexpectedValueException::fromSerializationTriggeredException($reflectionClass, $exception);
}
}






private function isInstantiableViaReflection(ReflectionClass $reflectionClass)
{
if (\PHP_VERSION_ID >= 50600) {
return ! ($this->hasInternalAncestors($reflectionClass) && $reflectionClass->isFinal());
}

return \PHP_VERSION_ID >= 50400 && ! $this->hasInternalAncestors($reflectionClass);
}








private function hasInternalAncestors(ReflectionClass $reflectionClass)
{
do {
if ($reflectionClass->isInternal()) {
return true;
}
} while ($reflectionClass = $reflectionClass->getParentClass());

return false;
}













private function getSerializationFormat(ReflectionClass $reflectionClass)
{
if ($this->isPhpVersionWithBrokenSerializationFormat()
&& $reflectionClass->implementsInterface('Serializable')
) {
return self::SERIALIZATION_FORMAT_USE_UNSERIALIZER;
}

return self::SERIALIZATION_FORMAT_AVOID_UNSERIALIZER;
}






private function isPhpVersionWithBrokenSerializationFormat()
{
return PHP_VERSION_ID === 50429 || PHP_VERSION_ID === 50513;
}








private function isSafeToClone(ReflectionClass $reflection)
{
if (method_exists($reflection, 'isCloneable') && ! $reflection->isCloneable()) {
return false;
}


 return ! $reflection->hasMethod('__clone');
}
}
<?php


















namespace Doctrine\Instantiator\Exception;






interface ExceptionInterface
{
}
<?php


















namespace Doctrine\Instantiator\Exception;

use Exception;
use ReflectionClass;
use UnexpectedValueException as BaseUnexpectedValueException;






class UnexpectedValueException extends BaseUnexpectedValueException implements ExceptionInterface
{






public static function fromSerializationTriggeredException(ReflectionClass $reflectionClass, Exception $exception)
{
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,
$errorString,
$errorCode,
$errorFile,
$errorLine
) {
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;






class InvalidArgumentException extends BaseInvalidArgumentException implements ExceptionInterface
{





public static function fromNonExistingClass($className)
{
if (interface_exists($className)) {
return new self(sprintf('The provided type "%s" is an interface, and can not be instantiated', $className));
}

if (PHP_VERSION_ID >= 50400 && 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)
{
return new self(sprintf(
'The provided class "%s" is abstract, and can not be instantiated',
$reflectionClass->getName()
));
}
}
<?php

namespace DeepCopy\Reflection;

class ReflectionHelper
{











public static function getProperties(\ReflectionClass $ref)
{
$props = $ref->getProperties();
$propsArr = array();

foreach ($props as $prop) {
$f = $prop->getName();
$propsArr[$f] = $prop;
}

if ($parentClass = $ref->getParentClass()) {
$parentPropsArr = self::getProperties($parentClass);
if (count($parentPropsArr) > 0) {
$propsArr = array_merge($parentPropsArr, $propsArr);
}
}
return $propsArr;
}
}
<?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\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;




interface Matcher
{





public function matches($object, $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;

use ReflectionProperty;







class PropertyTypeMatcher implements Matcher
{



private $propertyType;




public function __construct($propertyType)
{
$this->propertyType = $propertyType;
}




public function matches($object, $property)
{
$reflectionProperty = new ReflectionProperty($object, $property);
$reflectionProperty->setAccessible(true);

return $reflectionProperty->getValue($object) instanceof $this->propertyType;
}
}
<?php
namespace DeepCopy\Exception;

class CloneException extends \UnexpectedValueException
{
} <?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;

interface TypeFilter
{




public function apply($element);
}
<?php

namespace DeepCopy\TypeFilter;

class ShallowCopyFilter implements TypeFilter
{



public function apply($element)
{
return clone $element;
}
}
<?php

namespace DeepCopy\Filter;




class KeepFilter implements Filter
{



public function apply($object, $property, $objectCopier)
{

 }
}
<?php

namespace DeepCopy\Filter;




interface Filter
{






public function apply($object, $property, $objectCopier);
}
<?php

namespace DeepCopy\Filter\Doctrine;

use DeepCopy\Filter\Filter;
use Doctrine\Common\Collections\ArrayCollection;

class DoctrineEmptyCollectionFilter implements Filter
{







public function apply($object, $property, $objectCopier)
{
$reflectionProperty = new \ReflectionProperty($object, $property);
$reflectionProperty->setAccessible(true);

$reflectionProperty->setValue($object, new ArrayCollection());
}
} <?php

namespace DeepCopy\Filter\Doctrine;

use DeepCopy\Filter\Filter;
use ReflectionProperty;




class DoctrineCollectionFilter implements Filter
{



public function apply($object, $property, $objectCopier)
{
$reflectionProperty = new ReflectionProperty($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;




class ReplaceFilter implements Filter
{



protected $callback;




public function __construct(callable $callable)
{
$this->callback = $callable;
}




public function apply($object, $property, $objectCopier)
{
$reflectionProperty = new \ReflectionProperty($object, $property);
$reflectionProperty->setAccessible(true);

$value = call_user_func($this->callback, $reflectionProperty->getValue($object));

$reflectionProperty->setValue($object, $value);
}
}
<?php

namespace DeepCopy\Filter;

use ReflectionProperty;




class SetNullFilter implements Filter
{



public function apply($object, $property, $objectCopier)
{
$reflectionProperty = new ReflectionProperty($object, $property);

$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue($object, null);
}
}
<?php

namespace DeepCopy;

use DeepCopy\Exception\CloneException;
use DeepCopy\Filter\Filter;
use DeepCopy\Matcher\Matcher;
use DeepCopy\TypeFilter\TypeFilter;
use DeepCopy\TypeMatcher\TypeMatcher;
use ReflectionProperty;
use DeepCopy\Reflection\ReflectionHelper;




class DeepCopy
{



private $hashMap = [];





private $filters = [];





private $typeFilters = [];

private $skipUncloneable = false;






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 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)
{
$copier = function($item) {
return $this->recursiveCopy($item);
};

return array_map($copier, $array);
}






private function copyObject($object)
{
$objectHash = spl_object_hash($object);

if (isset($this->hashMap[$objectHash])) {
return $this->hashMap[$objectHash];
}

$reflectedObject = new \ReflectionObject($object);

if (false === $isCloneable = $reflectedObject->isCloneable() and $this->skipUncloneable) {
$this->hashMap[$objectHash] = $object;
return $object;
}

if (false === $isCloneable) {
throw new CloneException(sprintf(
'Class "%s" is not cloneable.',
$object->getName()
));
}

$newObject = clone $object;
$this->hashMap[$objectHash] = $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);
$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;
}
}
PNG

   IHDR    ^   :D   sRGB    gAMA  a   	pHYs    od  *$IDATx^ɯee`~#b
82&BL88@84!N1LҌT&0F#*^>{jWm~ȭ}Z9i   *3|  P     Tg  :'   >  	  @uO   3|  P     Tg  :'   >  	  @uO   3|  P     Tg  :'   >  	  @uO   3|  P     Tg  :'U}_z>jI| $(OܿoIMr:hOg}&	 Вu@XIUNt/rmjYu TO?T}F `+D3|R+ -Yu TO>DD%\ ᓪ4\t h: Wf*M'W4 Z >+r$@Kb@4'Ui: Вu@XIU]裏$A4 Z >JMr:hOtrE%\ ᓪ"Jh: d+D3|R+ -Yu T>@D%\ ᓪ4\t h: Wf*M'W4 Z >+r׿$A4 Z >JMr:hO?OIMr:hOtrE%\ ᓪtꪵN:i=r_MVߟ}ٵ38c5;?'"D3|RUWg9\ێ% -e\}cC_efMgpT8^{M2V|Ή=ZIU]{Fwyg{z(G?Ѣq~탟3h: m~ᵳ:k%]wQ]y)СCGm*D3|RU<Ӌh;Ｕ{8.C4 ZʶXUr_JxŶ%CCjXIU]{wG~S)M߬Jy?/{4 ZʶXEgO3]?3e}7 >*[Lzť4]#NM2V߷3Q.}W >*Slt4N Ru{ ϩ >+rg?٢	WZ|7pyc@K[|2|<xppڱ ᓪ25D߸.6h: e߳fȕ{*Ɛs=w=6yh: e/.-k >*KLʃ.õ^{6>itN4 Zʰ{hm >*ClG&%9>v?O4F뀨<x{u TÇ~MСCە"o$<v Ru@D/^xᅋWr뭷n2D3|RU,7rIv%Ksmh: Y >+rғ̹{64SO]{nh: h˥gy憯s-n >*l6W\qņFdj,ǋ@K뀖Z;];mTf観j.- -EZ3Y ᓪ"WȚ{Cx饗[΍7޸]v.S4 Z\Ko<xppXIUMg_sn3'|r5/M"-๕ >+r͛3'`nR.[t8p`p,t h)jТdu Tt6~(⋃+ˍg+-" -Ejkßa, ᓪf|ds;cj R:vO]fȕ7nΖo펗Cmh@/0mh: ߗzn5!F?Q߳EfpFq	mɵ@K/ɜ>+rL)|K_Z4m&_sYom Ru@^=NC~ڱ ᓪZ79~4 Z >+r	@Kb@4'Ui: Вu@XIUNh: d+D3|RUW^}UIMr:hOtrE%\ ᓪ"wAIMr:hOtrE%\ ᓪ4\t h: Wf8p@D%\ ᓪ4\t h: WfȽ+  -Yu T䊦@Kb@4'Ui: Вu@XIU]{%A4 Z >JMr:hOK/$	 Вu@XIUNh: d+D3|R+ -Yu T_|QD%\ ᓪ4\t h: WfȽ  -Yu T䊦@Kb@4'UuE矗t h: Wf*M'W4 Z >+r-sgq)g,?ПՎ@C=vN >j'vI'޽{3lgܵk׎@C=vJo:Yvb|^/%oɐ_.ܦe SZz6R(Y.C۴bZM?񢐗&S2 Њuc>in+ϕW^(_ɘ~?MzNSzh饥:MƔ5K~O~2MXВ;|>={x}?{;?9Q `3J,=ul.:;Q&'VNyR\)cަw (]-u fdʙha9:VHgw Nl*g٭ 
Sedݻ^Kp?\s5G>
 馛};<r 90|2JS*U2Dw}(L)G\~N Ma:uBQ71>v'	 P\@4Sed4pw _NyPtk9]'1ÜeE S{\3OFax  |D35Oқ`=x 9`S|;ǿ?b$5}_< KM~3Ws?t>I˥&u}x. sǍv+d$%hpW_&ᓔdr69?܂98>IǑ\ L;2pv|,d$7o'0EN4G:dr)Yw0|#x ΕPpx)p5cLyq1󼇝b,rn54n ƨy-_Ef %+'aܧZiw>rgϞ=G>v10|{xL2 cPu:S:sr&4\=9 c?XZ΀:n!3'Maȓm*p	 d6ĕPdb2 9+N;;L&Oq?b[< 80ږ[qIKl<ٶ(nNIur vg21|Re7 DrM<'I5eqG彼m7EOp-rk:{=Q JwJ<gf
-' Ђnr-7έ~? j~ʭ>'Кᓕrfm<Z=`3D1|2
x8*@=5hJ<=v<UrњsmQ8	v'DҒۡh D'WҌSj[y5>vL lVl3f? ^NgAЂm)<1z[4w޹l#cUNt 8;s1!pe5>gǦ~p<TN_ZYmVɖlih' CAݻwrr?/5>4OMe i_ͪ>gp8(9?tjON4ndyt/|9=_eX8߽{|)'/8l;OB{<nl`'^tOH}jtf뿙x9
92SO)._ ̇Wcᓣ鎂{:t9#N>٠oRǮLМH9 Q|}Ľlᓅ~!TSǾ0M;Ux+>6:PUǮ{.l)8KV>Yqp;~-8'`ʎ O-g'?ls\.*8Z0^baJwa={lN&>!?DY3e_*(1|T$+f*ا EfSsgb\0.Ox35QCk:zSS>b3|Όт 1hj`sF<͎V\#hv>gVLi6e\xS(g?6Yfl!hɾC={|{>'4O%K b9D4g>'k6lK$O/d`4s42>Q jrL'-XΓsƓme_ m6LY>><>'edUxz @}eQ[|#91ٕ}%: ze1adVn9!^Ȍ toad<>'400&: z6ȘF۷G2Dh6Q3*a9}	u{([u(a9G9;Oؙ~uc.e17j3e_.q'l+H
<>G ӓmgνL+g!G*Oؼ3L9BS߿Xj=]ϑqfsf\XNsDb., r]}=cO׿3޳haN\5=>̕ S)	\\39G|;-};Ga܎3\kG:ׁ0oC(C(̑𙘧| +g|m
q2|&ld̍op4㌛3BOO\`Nr ú2wg2;lG_`[o݁5⪀q1|&R^8.s0en런q;x>qylKn)rlq395e_r0v7wl+lKnpl_wI\. ;S:Խ:0V+P`k^C>9kQn \`lo_J[q0|r40F7z;ӿo<ȓ|A<V;	
V*7g gh2pz.0ay>bP{s2|6ԿÓmP
Zو1Ж#@F+<*W gxxooh:<g@_? J- \m1geμ@2pv{~x᳢}-vru@G<H{Y?3@:YIJBXa޽
(X
e<hA/ȩ܆S^Fhb>OԂZ.g?<܇bݎɶVJ7xzu/6+
!P\0e^^%nk"{<sIP0.nvZ']`cܢ|wmx0>Coн',UgܢnZvP4tͥr\X끲0u ƭ׶X=uor뭷z Lr)0X`'빻z`u[]bSvHHa7Y0~W2XsKl#%lJ>(rVywʒ/|u[tu,NKp+_X!ttן)t;r{qi,u}ĥ62UW]Xj>7;#}n7eG-˥{8ki0cIw6KmN
za= s@;gܤK.dإ)G;U^R]R ߉e`g|$Maz{H(`0|nB}kׅV^w} 7:ַe="U/˓gk׮/~>@+CR^_.1Z%>'`aOhehDh2|ј'5 W К+5gIDh̓+j QԂ\QhMȕ`Q{`Ԁ\QZ@kj@Dր&租~*	>Ԣ@ WZSr%>gyRrE Z+jY|$H<E-Ԁ\%rGcԀ\QZ@kj@D 1Oj@DQrE-55 W"k@?ј'5 W К+59Dh̓+j QԂ\QhMȕd裏$A"w4I5(jAJd0|(;@ WZSr%>gyRrE Z+jY~$H<E-Ԁ\%rGcԀ\QZ@kj@Dր&| 	1Oj@DQrE-55 W"ksFј'5 W К+59Dh̓+j QԂ\QhMȕd׿%	1Oj@DQrE-55 W"ksFј'5 W К+5S$rGcԀ\QZ@kj@D 1Oj@DQrE-55 W"kχzhNRN9唵_/s"w4i5xꪫk@ɯ5(ug8{w~NYZ}>{M?m|c3͘yCX3<s̆1_'c DւV}~+,>FYSϏD RɘyCxG@N;m^%s]x2O5}~Lu 4>{ｴy;y睷on;N!:4mDhj@;Ｓ}oX5駟>@ZP>|xڰu]wvW^ym"kZ@k5v[m4o.S"w4i5dlwzen%j Q"kA>߯,_J?KEZ%@dh2|is/~eG|7JG.;61Oc̭ցn!j Q"kA>oo8R,5*jEր}~u >wД;,7r˫:[om&s-PYjv?vj*ZThX"ky,ʡkvFD. 9Z@kQ5EcMrow}s]{~vmdJ<e_{lpD Jd-?OYt<xppQh-du >ٔl8b<iٳgھ}Ȱ5tQY~ݹKUɾ@dh2|뭳f)ڮ))GC˖(2t'wG\=wRR DւL}K j}=g5kJ[M9}裏~݌јXJ)z袋Q_P?@knJQYfQX끌}>K41-X#w4\bS.ٽ{gvM7o> ډ3Z*e]d@dh2|##YS`)+_?Sb҄JրrrSnJjrDa޺}oh>_/nm[.?HD2lug)S߇ܮy+"k׮5ٶ0oݾ7_Nd8xEg@> TIzYN3g=ܳovCoaG[˒izʽc6?F\o\rvS@Z}\gy?fV-z CZ"ksMiyNƴyrt~Ik5+wQY"SO=v/>#nUɾ@d0|)wSO=u_.C"w4<<K¬{5ISX>_rpD|msZG-`ư@dh2|k^)7X7X/v1-RˏR_g5J3Dy'7ݼ@ZвkUɾc5æ|:?c1Ocg5s i,u@ Jd-h_|vZdhR"k@᳜ΚktR.M);vY1OcO<Ć[R_bpQYZvYZdhT"ksM/߰SCeI<,ˑ_|qp~.Ji5(v_^f<KZ%@d0|n)-	F&rGcPJ-/㽮0ӟtԶ%˵ck"k@I>?:YM^fHvRvƇ~xgJ<t)%jL Yj~ڡZdRϏD wr^1Oc˹_9眳+~lQYjK'sY>?:Ytt֔7N#Y1OcJdK_?e@ZPϗKs?lʢ5Zd8VVZ"k9%rGcԀ\QZ@kj@Dր&gZ1Oj@DQrE-55 W"ksFј'5 W К+59Dh̓+j QԂ\QhMȕd,7J|"w4I5(jAJd0|(;@ WZSr%4><(	1Oj@DQrE-55 W"ksFј'5 W К+59Dh̓+j QԂ\QhMȕd<p$H<E-Ԁ\%rGcԀ\QZ@kj@Dր&+"	1Oj@DQrE-55 W"ksFј'5 W К+59Dh̓+j QԂ\QhMȕd|%A"w4I5(jAJd0|(;@ WZSr%4>_z%IyRrE Z+jY3J<E-Ԁ\%rGcԀ\QZ@kj@Dր&/(	1Oj@DQrE-55 W"ksFј'5 W К+5/HDh̓+j QԂ\QhMȕ`Q"w4I5(jAJdh2|> ;@ WZSr%>gyRrE Z+jY+;4I| Z%>j`a"v4ih6J|Z$>59ꫯ>/*Ԁ|jA@Kj@`#hCK͇KѠ3J\ ֆCdO   	  @uO   3|  P     Tg  :'   >  	  @uO   3|  P     Tg  :'   >  	  @uO   3|  P     Tg  :'   >  	  @uO   3|  P     Tg  :'   >  	  @uO   *[[{-    IENDB`PNG

   IHDR       N`   sRGB    gAMA  a   	pHYs    od  6NIDATx^۫g}?)-aBK#B/ze(C;QA
QBo4z5rXTn<D:jH5s4χ=;Yg<k^FٳY	   d`   $+   !X  
  @HV   B2       d`   $+   !X  
  @HV   B2       d`   $+   !X  
  @HV   B2       d`   $+\z0 PBI@tVI (!׃~ :+t񫯾 Ѩ (: Vhb_JhT d+J1Ut'8 e+J1]a/$@ԜE Za`*V4* J Za`0~  %YĊu 0RF+ %YĊu 0RF+ %YĊu 0RLW?3	
b:VX)F
b:VX)+~F@Ib@+QŊF@Ib@+QŊF@Ib@+O>DD$XVѨbE$XV
,QPu@X
+hTQPu@X
+hTQPu@X
+t> Ѩ (: Vhb4XѨ (: VhbJhT d+J1UhT d+J17[oum۶_WZF@IQo';w~~ӟfFhb4W^yeE{۶
"s?k53J:VX)&bZokE'zvQPRu?\=Z
+to*k]j.<#i! %E[̫9sfr%L7^ݾ}m~ӧOخThb5_^sUWM{iB4* JWߗ}ۥ<SmSrmX
+tk*FKtСEF@I,msr?Ӛ7|3ݢc@+Q'o2ym9EF@Ir|.>uTvE:VX)&RZoMTѭDHys3߳X
+t1=䠕r-pzkّ~
"jg;'OnX
+DjTɹVp~hT ePGY?X
+t1#BG@ʥw'zhT eP7^$]X
+DiTIz5\3m(wu׊m}-Mg3Ѩ ():fsrX
+DhTMh\n?Lh4* Jgյ~RV
3g??5ӧOgK|}vQPRu@ꫧ?/n[2J1z2XBRxemhT T{PGVShb.|YcH.ɱcǲ?7Z4* J(eĻvZsz5b@+SQ77|DjFkE뀒׿䢋.~owYqnZVݨ֓ЍhѨ (:d=+ Za`09[`=n6wo>/.R4* J(ۧ\q'Of Za`j_.~7M./ҲKvQPRu@>;n Za`0rG̋/)=rIٳg'FF@I%{nX&Zhbj5lBGnZfFbhT Tk裏. Za`Zj==f3{7zҨ (:`+X
+t1;ZwY3vk˚V:{QPRuՍ&=gY{u 0RLF{汕Asqm1F@I57tӲo4V87+t1]>)ҝ/x<_%z2.w嶭
Jӽw_LOgE:VX)tQPu@X
+t1"QPu@X
+hTQPu@X
+hTQPu@X
+tԩS  %YĊu 0RF+ %YĊu 0RLWO<)QPu@X
+hTQPu@X
+hTQPu@X
+tĉ  %YĊu 0RF+ %YĊu 0RLW?.QPu@X
+hTQPu@X
+hTQPu@X
+tرc  %YĊu 0RF+ %YĊu 0RLW=*QPu@X
+hTQPu@X
+hTQPu@X
+tȑ#  %YĊu 0RF+ %YĊu 0RLW>,QPu@X
+hTQPu@X
+t^ Ѩ (: Vhb4XѨ (: VhbX2vܹ3kϚEG\Zt 3RLH.:wd۶m;vd=Bҟ-oߞEG\ZtRome,__tJUvۊB9RH&BsϞ=mJ JY: Ԯ^&BsKnhTFoo=MD@)u JU{7-&bofo|c!͢QPRm5^zjꭹm"&Y˿gYtʠ9sfzݻ~]vҟ=7|g
 G=뮛^}ճ_q32I'B7 iha02jwT2imU:ڝ%NGZs4v4X{.!\BsС~ @<0<v9xg`y&}( 4ԃi0>V@v<e_ LdTufXiVID$ `";+MKJ[~_ ?lq뀤[fXiW:K `#sIkYV3Kc<| PB++Ms=|1mC|<~J3w<|1Jvj5h~1, {8=4O`,\]R)0dVYg Ơt{>ca`%4GT >4v|_/f`%,XO`\I>?1tVBQ˙h drW?L4Cc`%G
7}, Wl+*+鷛> UCCd`%,n +Z1Т7{X	}}; ̙3+v}l++yb8c@2Vg'WX2+U98  5ie~&X&PXqw@-,Hq-2RMwSYl "rt_p,6-2R+˲(  Sr-3R\O.A jvrObX)ʙ\@mn	ǙmZd`E>P[sX)"F.C!kT۳hsV/tTkT{=U XʚVNA%A OL,ǖήv?& 0o-}tOlCTV6xr0 1':+o U<cH]xa ̓̕uJGF* 'D$"+sտWEk lE*+W)]׭<ۂ̍{UU 6UVh̅3s?Qxg[-KMVݫ2w};o|&+[pFjT &+ʦ97|Z``eOrttzǎK!fܟLMV6E`V4jW4+8yr0 2uj1!)uê'K{ˁJt"ݻgR[Hy"8iT ?pa|*}ktO*;:βSuq"}ħ# r3X9'xx9NhP5䃵tG=`}ZJy+߫zrRc{rsI1ִE0/>Z+ ä^i_II2oVVpyĽ'MOx
ng3<9`8מQFZ Z``eO~e+? S
f`eʥ̃ r[z[˘'+K z"0[ ;i-ΰ})V.芊 2)̛}y1\l#`̓KN[u,BkTHf3#)n`?{"Y֑@Jq@Lnݠ$g,RcJ*sP_:խYVX4,ȤFI=w}x}2HjPLM.?Y.jsv2Hנ<<9!HhPDϜ9s ,D=:ڔXGߠ<\PVhE5N䂨ҙU^ X4tCl:`ѥ}4) 0i E"Kh^;rO+\ 8i.,:@!xy"-޿ٯu4(Z'lWhQTփBX#i+ #n-'^e`GSi'lMVuӾ 6ցp:Cxr0R/g`!UOf\- q8C8G*OX3,L?ڸT *!c`m3P+ IwrK{ڠU3)+PW]1SX '5K$:Ua`m#KdZr_qpX},Q> cӿE"0Fk#<~ǕX9+ G`96`l*4҇V=~ϓ1q;urv1Pg<V_}r `ۂEҐq0XJ62OUhxA@-ϭBe`#ؘ4/h]z}]wmA>H&k0>h9.mAy݉'~K`k҃ϐ_iδJk|AZ=9hM:`հt 8W)5 */-_% ؚ}a'u<9h+`|Z3AiH`,Z,#@\X+ߧ8	"s.k@YTsXtd`-}*P#@$޽YZ#;PGjPKu\kA@]iH횔w58xyL[߿p
*PݻOCL+PuZ@(N\4){Nk+>W?`@L@ĔnJKW=e`]t_'A\%^@+@&,Z+ݰaoS>sb1.37I`6z/D`z"8xmqyL9C|vy:;h2c`݂ҁZY@{rޙArWGXc`݂nqvj0t)}CRa`5@Z:xmKϭ1nAʚ~C` fT|Ow@'繻rz<&u;eоwVݿ;x훽bz&utGRSҍ٩At HtYwДXˀYziA ߓX7=ܳTKB;>ǩu`Xr[ou끲Нy?鲝8鲁tY!ІyMMLΚtq_2[/=~(	_K:ڒoڕ>2ٳ&]إzоs<@M=cM Ò>CT?@b= `=Pu|[Z9ge@@=oz F }zb륗^:ܹs}__f@)}˃rb~(?#~~(?Ȋ_}H;'âĊ@-jAJ5_Js2,j@ԢĊZ@ij@P#Mqix≳[0j@ԢĊZ@ij@P_|Hv~`QԀXQE-ԀXiXGvNE5ZԂXQ(Mj@? iadXԀXQE-ԀXiXGvNE5ZԂXQ(MjuiadXԀXQE-ԀXiX?3	vNE5ZԂXQ(MjuiadXԀXQE-ԀXiX?S	vNE5ZԂXQ(MjuiadXԀXQE-ԀXiXGvNE5ZԂXQ(Mj@O> iadXԀXQE-ԀXiXGvNE5ZԂXQ(Mj@? iadXԀXQE-ԀXiXGvNE5ZԂXQ(MjuiadXԀXQE-ԀXiX?#	vNE5ZԂXQ(MjuiadXԀXQE-ԀXiX?C	vNE5ZԂXQ(MjuiadXԀXQE-ԀXiX{y'۶mP?ɯ~ϋvNVnlHя~Qf-(Nvܙ?OS:jլkeQ}>zhX?ݙ֓~nĴs2,-Ԁټ+6\eNĨRiPZ0EV@5VYJKCk;'Bg#k/ٟ)j Ԭ%f~UƤfg}:B(>aSOMwj[oe_m#aikv:e/8BPf-Xt?sK.Yw߽b}-ۦfP(fHYtoPlȏ<HvHiadXZ)do1]R,@:/dKYRrQ(fHYtoP^<&ofv\;ځsDJ;'B]n6Ce5ZjւEwygYf6?ϼPZ>bhX{J#VX)zm2ҜSNe]-oˀ"5ZjւEBxԜyD-Z5DoPX5('z=꺞kfFRX׻;jժ%|uP|`M7:G~xWNxvr-O~&RZ95p:*gJ jY'-TO<nQ(Vkׁj6[vdFhZ9iݻ'|g]ȶ5Zjւh}_wn6Z@ij@>_PmdK?t5]s_7;޽{{RKj5ZjւH}7ͲkJQu``6tis=I|i8MCjV뮻ni\}l(u]5Zjւ(}~vyQ(Fԁj4-윴#].ޱcǲe]6y\j Ԭ"ojԀh}>RhXI9ݎ٤{[?.r~E$)Qk@eRA1Lݾ/}ޚ\}~?ݶTJQ"hu``%t;N:-v~ 65.fEgak5fb}/_.:5|a5E-5 Jwjsx<ӝ+XzRn\?cCevNꫯ.ݻ{[1?NT@vC@-5kA>K۵kצQ(Fցj4ٝp_:-윴Kv~Jo_5on;R']tҽj>lvQ(V#ׁj4.;v,]s_zRϧ\Yk@F2{;nW;j Ԭ|[Z@ij@>PyǦ;SjdV}ݷlg<zhviaݻwxͬ5 ݏ?{Pns套^ZvnW;j Ԭ%|~%PZPϷPZ^f/5ؘs2,-Ԁٳ'9JPf-(gwEZ@i5k@>JhXiyG'NnK&픹aiˎnkHwܑ.B jYJ"5]V-Ձj4niَ.m%-K5 e9r$m?~6RCJG`}~v1}XMQ(fHYtoPlqL;'BHIOݳgϲZ٣)靳/Vl)j Ԭ󳵣@Z@i5k@"|uP|`M/#"IځyϏvN%=!5 V,ogתjլ][- k/[%hiadXZ{rO?YѢPKZ>?{Fc`e,jր̻ϷXZt<j<yΕ)~fԴs2,-ԀՒ.⋳5ZjւEtw7iOg"PZZ[- HɰPZ+jB(>kƥ~Z95 V jQbE-45 VZ֑aQbE VJSb``iZ95 V jQbE-45 VZtCO;'âĊ@-jAJ5:Ҵs2,j@ԢĊZ@ij@P'O iadXԀXQE-ԀXiXGvNE5ZԂXQ(MjuiadXԀXQE-ԀXiXO8!ɰPZ+jB04-+j P+-Ԁ%@Z95 V jQbE-45 VZ֑aQbE VJSb``iZ95 V jQbE-45 VZcǎIs2,j@ԢĊZ@ij@P#M;'âĊ@-jAJ5zQ	vNE5ZԂXQ(MjuiadXԀXQE-ԀXiXGvNE5ZԂXQ(Mj@ȑ# -+j P+- HɰPZ+jB(>>|XaQbE VJSb``iZ95 V jQbE-45 VZ^{MaQbE VJSb``iZ95 V jQbE-45 VZV;'Ò~ J퇭fǎ]ve~" ydXrԏ@iٟd۶m??ܹ3MKQ(%ID֜nm(IZgϞ5&ݮ@IUJRjh?^Vo~sZd=/TX8 mdrԋ@-?''}ek!jC+  9sf{e·~믿> l `<89$C 6
 0g޽{g[:g[6
  j:˚t5}`  gζ^veKpnV ^}եa;ۺj  A{(Ӯ]Y   yX *
X *
X 
  xX 
1 8X 
`  
`  
`l  
`,  
`  
`  8X +p1 W Ca`  
 0`^
 0^
 0^
 02^
 0B^
 0b^Df` 92 +ph  ,8@V  V
 +  
&+  k
+  8@iV  +p  lW %X 4
 x(V  +py3 07^̓ 
`  ,W [e` `,+  ExQV  
`#  8zX +ps1 PW 1 PW 9V  

 @8^$V  B

 @h^e`  <q2 q1 0 $3 42 <a2 0^b` `P
  y
 `y
 y
 hx
 x
 (yg` `6
-c` `
RxWE2 WAj3 @Ϲ^wM.
  '0{]1 *V{Nt	18V  8W<Kҝy
  kH_J{&ַjw/kz-V  XEGP|ߜѲ`k  4a4=)ݷ]<t?+  U]zMϗ^{}O"0 PUnXj)Ν; V  JJ$V  /RJ$V  2Jqix≳[P / >Ґ`` *kX
 @U݀KX
 @UX1 b`%+  Uug}&b`%+  UXcJ$V  O?TJ$V  2ƊH  Te`+X >	+X +V"1 PU7 } V"1 P5VDb` *kX
 @U݀GIX
 @UX1 ? 1 b`%+  UEXoɶm۲я~駟ϜgDb` n@W^ܹ3;P}/srYϾ{_*V"1 PUu3k/ٟep͡J$V  J}ɵ^bhꪫ&o֊_~gZO>b۔Gms̙%\6b`%+  UX۷lP\mP߿nvO=t?/dlWyH  TH^̞-Mo6КC-wygzw/<mYSNe[dDb` Z0^v)o:+گh+X :{v\g?WK,fF֍WDb` n@Jṕa:g+tllvH  TUk`[W^9y7ەHxNەH  THRI^s5v]wݕR1 j工߿lDb` *ʤ{j{.:V"1 PU7 9sXkn3gnX
 @U'=)ꫯvH  THAD.ɝs?>sugYs-*V"1 PU5oW\qԩSJ_ڵkg{衇-*V"1 PUu^g2gy֛ٟg`e  TH͒9}3imwK.hs|vM?nm4V"1 PU5Y\09zhv2{iɓ'cm۷O~_f[TDb` n@J΋/h8O86G}t)wqǲ_liso3X
 @U5֔ni: 3GnOLYms \"V"1 PU5=wϞ=!jP./~bmx1 )=lV}u=I3<]f/>WYÇg֢c`%+  UEX{r\~Ǐgl;ng."V"1 PU7 Ks$]{gʔ[O<iP=vX{JJ$V  89V"1 PU7 H~Db` *kX
 @UX1 ԩS V"1 P5VDb` n@:yH  Te`+X +V"1 PU7 8qBJ$V  2ƊH  THǏ 1 b`%+  UXcJ$V  cǎIX
 @UX1 ѣ V"1 P5VDb` *kX
 @U݀t	+X +V"1 PU7 >|XJ$V  2ƊH  THH  Te`+X $VD`` ܰ$c`%+  vm+&
 @8x  s	+X  
  @HV   B2       d`   $+   !X  
  @HV   B2       d`   $+   !X  
  @HV   B2       d`   $+   !X  
  @HV   B2       d`   $+   M&X&Nk6    IENDB`PNG

   IHDR    ]   ݽ   sRGB    gAMA  a   	pHYs    od  IDATx^ݹoTqҦB2NED("҄%R2U@$+$&
Q5+P@J ?\YHk̽g&S*  $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $sP J(@H
իWA(@( !)ܗ/_ $
W/ÇG~[O $ aIPPDBRϟ?'BBIPPDB+ QgψPPDB+ QӧOPPDB+ QD
E $  QD
E $c  QD
E $QBBIa>z8E $QBBIa>|8E $QBBIaÆʔ)S6mZԩSTBBIa>x@.Νtuuehپ}{XPPDBrO5g1cFBBIa޿_*wޭ,[,+/2+G?G! QZgϞ..Zr W^PPDBRݓʮ]۶m[M!f'OF?{(@( !I o߾]3gNMݹs'$J1CBIxѬ͛7?+\) Qm*Qɺu벢oߺu'j>O! QVo+|9ZBBIa=49r$+V_7ڟ#._\CBIJh_.]֭[8g}qPPDBR?5/u8~xkf{9 Q5vڵqV8+cǎE
(@HR)@dɒg8ˍ7j.uPPDBRvs:D3}ŋ_[(@( !I ׬Y-f޽ѯ- QPeboV\BBIa=6rPܹ3_=S(@( !I ?WX=&3gTfΜ}-[y
E $k/ ӧOה؞={bN/^};K(@( !{/cq%h $X.Ǝ+ '5
(@H
^<-wMyƊ[LDY@X $cǎׁcL+ Q]n۬2k֬>qIך?~ab
(@HZ"
{ePPDB+ QD
E ${U  QD
E ${  QD
E $QBBIaڻCBIPPDBR.]"BBIPPDB+ QH $
W(@( !)ܡ!  QD
E $QBBIa $
W(@( !)܁  QD
E ${  QD
E $̞=3OѾ؟: PԩS+SLtvvFC{ﱣ#% JcƍofO>ￏ!7oξŋGig (@F
𫯾J=vx~(@F___ӳ~L>1Vw}3Ďiu(@xGuww|TǼy߻_("0l'S@3 D/<{gΟ?=]|G
S-'Of?ϦMF>
rvޝ{YA#^(	{X6v	~6$Zg@(@w|WjæDR-i?[x4YQH^jcg(
IKX|Hd3Ҋ/V@j(@$HpV PDRR9^E(@$CBϊ"
~PH9>EJ(@^72RAԸ59lB
(@'8
bx}eGlBQ(v26m
r@YP(^<FQ(YCeg(ʆD) Q
leL(@T{3eABZ~";>'΃ !g"3ᑏ:(@H^T
u {~PBB
:g|v|X( !͞Nah`g(Pp:G% \cǧvBx6+3Qp+?Mzo(@Ďre+;<s(wJ+{GH9p/^Qp݃el
.,{kag(<  
cgZ
/(@gibg(< Qv|{D!&vh ڎG;C{{{G>
B	|h=
m@İ.P
mÎO%\ ڂD[. x+=+?[#V@Qh9vaX+h'
-ŎOLmbag(ZDKPagAQh	v|V t{8D#;Cr:L ]|h6ZD:.4
 5h%JXh`ځuf 0^v+DCx^P4Ĥ;Ea(@L
;>Q4vQ &h	c'<ɯᑏoGbB	ɢ 1nsW/l(06
®;xgk4<@(0:
o뮠
c
سPlX(@Pdúeg(FCbT
r Žcg(ކ`g(B;>Q6\h(@dobg(b(@d;(*!z Gdy`%kZÚ׺"]`xRU
0QAx?PJ<A`z(WBF&{@-vL;>8vLDQ.;>7寎|eF&34-`_xRr`+=+pE;>agh(bWΡޑL(+V|Z>`ɰh.X2DT`gh9Q%O^>`	whM}8e2C	ˍ}	o/
P;Ӏb?'&
P@bY# ܃F	_x	.
P6O7 Ez(@<43T\;>{zzF>
(@]h@:ad.{J0ܺ;(D8Y츏 C(<;\t"_~a'P;Cţ ?Q";>rg~኎=#]<
Ёp3<RػIأGa筽]A߯ˠţ ?Co^}Cxh%{ ];px`#wy{$.e |?g!\-X+W֜!О	e]g"Phy,P>v^˚绝(X>
 ;?2hq$pܹHWWWD\-@֟Z켷.\1j(@Ҵ [.W^Q] ]/_$+3$'>>|x43WTgtx8H}؂hf 
4] _Qs :(@pT?t1|EuP.~b.gϞQ]@+3@ >}JDuC3WTg H.f 
4] _Q :(@pT?t1|EuHǏ.~b IQ]@+3@ =zDDuC3WTg H.f |!q] _Q i8:(L2eB6mZԩSѯ9fXٰaCtXx.o]I(]
3>ΝtuuEX@(EU?t)̀|z7Vf̘Q~zkz.ͯ-EUnݺ=.]v]=ST?t) ݻw+˖-9-̈́gϾ,Qa 
ELZOG]
3~\,0zq^:޽{nsњEqO[c<EuC0;9/A%rq:(/|
xpΝKvիcG۷+s̑3lQ(@
}?۶m[%?&5 ]vk9-܅Vnܸ=.ueo߾1a|yĉqe [=r&W\)twwWz{{+_H;Qhٽ <Yvm9{;[T?|MaO:SZgݻ[tiZ*z\:(%_]29~xz/VvVzV~ar<~~֭[Ǖ)3lQ)@I]ˠ5ļy*wyP:3@ /?N&vҥKѯ)}"V3`2%d
_v%{VF?q&E~V )
vk: ,6v\,?C{FΟ?_?ޠ},?pc%%Kdʕ+Ǖ)3lQ)@1:{I~O^_XܹiӦFxk֬9@(%M>rqmp	kbæzg@]ǎ?ܲeK:Uk<-Z+@{A{Ѳs y?v^_zgݷ_ű9s2sٳ'z\Q`h_B3f@U<U3@ 8pf^|9z\,v4qŊDuC8}tͳ΁l޼9z 
Ei 뚅o=by.`?`|@,! [`3?oQ]Х0,{5XuF?|XOQh/8-?#=EuC1OE(]*~moQ]Х0cǎ>Zϟ_}+ ]vykEآžר.~R.}Κ5+z[y IQ] ]vm] _Q i8:(@pT?t1|EuHn] _Q i8:] _Q i8:(@pT?t1|EuH)>:(@pT?t1|EuHQ,)>:(@pT?t1|EuP.~b.@⣺+3$GuC3WTgtQ]@+3$GuC3WTgtQ]@+3@ .~b IQ] ].\ +3$GuC3WTgt_Q[[ 
4-jb Y17n|/HZ]i
8G!).   NQ $Q $Q $Q $Q $Q $Q $Q $Q $Q $Q $Q $Q $Q $Q $Q $Q $Q $Q $Q $Q $Q $Q $Q $Q $Q $Q $Q $Q $Q $Q $Q $Q U*uW    IENDB`PNG

   IHDR  {  h      sRGB    gAMA  a   	pHYs    od  /IDATx^ۏmYY7V 	jh҉	7+!rabl AnLnJ@0!^4!!4ghQ0
&Ч{Ms>_c9kQU֚c̱'yfUWZo9f]w   p=  	{      $  H    0 a  `@  =  	{      $  H    0 a  `@  =  	{      $  H    0 a  `@  =  	{      $  H    0 a  `@  =  	{      $  H  ǐg P=Tk0}j վǐJSO~:(M9*s@;C*M?4y d{IqҥU}|2Uv=Tʏ~#A#}Z 怾Ўǐ4J`N怾ЎǐJS:(M9*s@;C*M9*s@;C*M9*s@;C*M?4y d{I4y d{492#1$M92#1$M92#1TJ`N怾Ўǐ4J`N怾ЎǐJSw:(M9*s@;C*M9*s@;C*M9*s@;C*M;4y d{I4y d{4o۪92#1$M92#17׼5]wa=O<?]n)0^mo\}i~N2#1To->_Ӹ7W]Ji ̩9`:j_c2#1F}7|K_nSsG:UghGcH|\T}_?xK^rؘU뮻Sos<7]wqd?^zvs9a!7}s2^}ݫF򗿼9K(M96lkmyYooRGVۦjp2#1To,M<MysHS{{i ̩9`}kԶ_BWv.s@;CoR_WWfci ̩9`[ëG.|衇{&iMh`ˣr)M94lk>{|.ЎǐJSɂ߾jz?|>#SOs@>;aʕ+v]v=SߤNkmvcK(M92޿2?Ri*&~	5=?o|^< seh%=(s@;CoRYxՌ7^M/G[7&zZߵ9gRM~Ӛy%'۽կi4y jNUv=T#<}?&viO|]0|ы^zwm,s@;CoRM9xԶK}_>rIV< sj=ؿRv=TJ.e>ig'?<@V< sj=̽ϥ7tӑwm2#1M~zի^u1zj'&Zs?O}s˥m[9a!nT(Y[o~J`N-9g{ЎǐJSw}9o}nSi ̩0}}o>rJuehGcH-5e/{YuZ}=rv=&Zs׃Y?-ЎǐJS+>i|;*r-͑˗/W4y jc^zVv=ԪoZFK<vz?ΤEi ̩#_BKR&I;O^?r{S9`%^SЎǐJS*?H#v'իW4={P< sj1z~Vﬕ|9GR&iy睫{ϳS4y b|$1TrCO-gٟUֿۤÿS۶ui i9`?S	{Ǫ]9a!ɥ0's@_ehGcHwվ4y d{I4y d{I4y d{4zHuP< s2Uv=U< s2Uv=Tʕ+WT0's@_ehGcH|_0's@_ehGcH|_0's@_ehGcH\|YuP< s2Uv=U< s2Uv=Tʃ>:(M9*s@;C*M9*s@;C*M9*s@;C*MP&}9a!i}&}9a!rJ`N怾Ўǐ4J`N怾Ўǐ4J`N怾ЎǐJST0's@_ehGcH|_0's@_ehGcH{ｪ92#1$M92#1T/J`N怾Ўǐ4J`N怾ЎǐJSn馃o*cv]< svUO{nᆃ믿	OxBu?{l'1Zu^wuOyS{]&jmTBSOzғS+>wJ<0?a׾&U6=_y-T `.go?_>8_>tZys}{[zsTf$˿|//~	{]4Hvm r PTK]`aY>j/!~?S'7.];VMwwX;s=?=j4y 4_~m/_:ܿ/mmvg?>~y>^0aGY{_{}?|_8x;qWep4|,-oy=g}{WfRYC-uCQa%~ ʁ؄׽uJ@ʁl`>0SBj 'JѵX*;r0G`)J[?U*ǳ]`7<M؃3J-wey#eK,|ʾk첯NhZ|jg"sM>˴%dQpŨ? ˔	9,9U>mZj?6	{DJ#dg-D$$eߺ:or[sM-@cۄ=@tY<5 ,S*'6zMd~H]vZ-$)҄Q;rSVvHY༲O)7PI9m]K\٭^lTc.Jއ<= l@uvٯd3g*KǡaN](;MdTvTqTeI.˾tN"#;ҸɎvX k}]7W.[aqdϸ'ӁaA؃JNk_M}n=ԔF]0x%`Mvٹ%ryNvjUYgT:<@~;Y=d	x,	3%_'e eJ@IXˁ̲U>m)ԔW}!1	{0owܔ ˒``qK*ɾW~'K'O;Yd`v !'7P)+/F&O ]`/#Ks/>oSW~O	0TN[gWngx	{3V)r2g@Sn:r^-X/=Zvr46Sh(vdv:mIJ+RLco%#~q4	 g*>:i8VSp'Z-Yf	{rv*;;ϳsV`3L٭Ryuv'+/_	x.c#챗NʎN-;ټ?Tmr6ؾ=;JnWvr`ߔuv9Xt`rjӼ/t{%,`;)A9tT:gI/oNco$XcYCQvH`Ǧ7Pd]w67'<^sµ)^ȎC| "kze;7P9jgKc/#ٱ؁쎳lή@%p\xgqa=g=ټ2xh)}?uv	v_Xg=	p-aMi2]*ӃN
v9uvۓq/nbǰaj+T~[l[tz([g;y-=Z%9{);FɿQ%TV]Yg'IsNi'Vy,2 lrШVuvn\{<|L{٤d +AL% $إ?lT#	{%Gx$GyAyO9 7J9^yYg*ʾ3ZKNxr{#;CrԷ?9j_AƗ@0i첝]{<X6a!8s娽Rn:j~Uxy<eX(eE28!0$`wN[gy+.;oox=-a2pп+Y}kvnUnq/X,g+gCtz@([gק<9Z.V^ƺ|bMq-O2m`~e]i:;?paEʎ+1aK \Q:;~%t^{1XgR %#C~i7P)@eJuXe.;1,_^\g*s~︀WGc13+CLvp#LylspTN[g*˔7{
&=ٟe-LT*'XNqe)Nކ}a?MٕXglwo%ѽ>e2aͨrjuv*ٍC$5gzS9p9<]gw\Oj}|h:슰G+;dj7(`ޖ `4?0'a.e'Xfg>24C<Pi7P6	1Lq/hAأ;PI2(AKe]ʜves"Ks9.ВGwb*RܸvTTI/艰GWrS\ByMo:;7P/;ykύ<grHأYgކr=Ö@vvT>*KF хڬ]uЕ!6=C&T_9czUyKɁh.XY)sMe@ٙVEF TrU5tq^eYSztq./7Ps:;9.@@;BأrYUvJ+Ù!wYg~ݴTc*<'r``9S0"af2eGg'Yy+g<Ƨ@%$z玀a&.;ݼQ@;3Le&7P<k	|̥>tU78rI_}^yKyN"OcVdx
.s_l.AP&s|# {hz&;h7Jm /eHdgQ^P'12 fGm̶Rڭ7YgWn1<zyn' Eveh>y}ruvƧ7P1s^y嵼\< 6#s9_vvRF9k`5mu\Aٳ 8a`X@/VuvlK^y><5ؙНawN2\qTMBam '٩3an* IYgL幘aˀvGc'ʙ	~BBL,G3y}%g@Tޟ`uɮW;,Kcr	X.]Ck*y:A5^e-幚랇 تwO9U3ZԆR0<t(d=fHѷQ(7fQn6YgWnbs;.祀a P7y4jK	@=!\M__*~	{\X2dp^8tq./7PΎ<1{\H٥b?^\soۦ6JB.8<k$<s`y=.$m"my^Z3vVN4?g<1{ΛntYgLAO<AZk	{K!od-eJ+NJ?]gIhW;\Ep/a3Q24X<<0mT]<< q&9sQ^_X2@Em.evYKiFX$3~X2_CuvWoo X2D8AorIZ.d]*e>,u?HBУre@5J\ӫbx DTy`Wmr<OsP"Slܟ 4'[kyeiU>A8!pCoV ̥rIJse g!q\V(gm+2Ğtuv6J^s^༄=_bJPzTZ=rְ|?m)︿x lGU9ʜAy`&NJlc^xp'<< vA$jΆՆRXekKxn9E9~s
]8Z%N6ύM*s[.9')v6[`n+RParYY.d]l`70adh=u-מ߄=M^dhgdd]'	~ٮuv2=띟@iք=|O]YgTvrP`wI}]^^?yx Fc*7ήvRX٥ۥˀ2<yLk<	{{ΙuvDOtI (gBI/{{l)o<L:n2]gd/0aNxy_>oDޞJ@(L PI7PIuv	vX} !g%!S<FT>mrveS7_^9XR{= J^Cz0aod)N5!ChM%%dXgׇ<yl{Sjg< F'$2pȥa9:T<^*P(<NRxyM' G_M1@Ze\?Mz\f>Dd'o	veq.UnBC4{< B2ۑ>a-vÇRXO7}9}9kΒO_c<#ن(2Lv:;O|8 OuD3]gwTy9R#ٕWxeu p:ao`>Ax%؝tTYg`g$y_;]	x6- G3u]dh6Tǲp^	xppzsEL92$..7kئ'yM΢'5L( l7 ^E]~Mev	vJv-<>:.ף !d_"d(<:rJ9/gKZ? 7ze$s2ITr zo	;>?< 苰7|9T]>:;"ο#\!לa_xEy; {XuvAqZcyPM^*@?ei7PMPy'-Am-,eΰx ao2|+o*e/z~y=5\<Y 蛰9j!+w9;8[/Gm0,er6로9k8) "-DZɠ'08.á@]	wy=Uyyge3zw95 ,e{߽:w9e@3
M^+s^y;M2P  2%T#y;@dثT\P9^y{K9K?4yfv+# @_(pN$,&+.h)tRۿ}irwJ,%~`HAg~gV_ YٝnU^w	^ymu=}=t)qA|`{+GK#c\Nn2%0Zg4k=zjg׃^*sz~n<g`?	{[R??Wn}p,O	vЇs&}}??ytU3;Ｓ<  //jT`z]?{csdT^B; 0%u\yRuvnce%إw__9?Ӄk 2=nƃٟf+#_7pկS\jϿӟ  P9{WW/zڐzӞV=̥[r'=I{~V= ־F kdڜܜn5|Xݶu>%  m~ʠJ 6=*ǥKV+z@_ @CG*Gi}  m{jecnz@_ @C217= aOzM  hCS;/s*=  :?PA}  m{jecnz@_ @C217= aOzM  hCS;/s*=  :}{SA}  m{jecnz@_ @C~217= aOzM  hCS;/s*=  :};QA}  m{jecnz@_ @Co۪217= aOzM  hCkT3ăOկszI׼RwWK 6{ַ~An*u{,s[BX7xc5_??~K 6FuZR31%it&鷺/UfO @Co~G>n7mzW^nSz@_K^#q=s5g  hCkT	{a﮻nSz@;X/nK aFȀ|]b6=A-9k\}=T  hCkT	{!O؃k|3b>Cm~zֳ  hCkTA{ӛT~9J 6{A}h5=?\ݮV~sTz̭pҥk8`~Sn7J Іר{uF ~]r]Oec[^-o9O{z6g=س ^Za/+ݴ^W>'zz+ېW<ȣ=v/~W?mVn aQMY+}}򓟬~ˠ6$%%M_/}KT= s7VyXn aQ]$쥖4 ئ\K9yM<=x;qM=@ `.C	2LT=կS屨}JS[{Fғ= רa/k^ZnZCY>e屘~Jn{'\{B|`5|͇P]aw]z)/|pu|y4\Ԟ+qE/Z}߷zkuJ 6Fu;wtMˠǶ};\W\׽ȟcUZw @^HKM'?<@uʠ6+9rCu?w'>QZ?K7] ?m}ݫ-a/qַu	{uʠǶRa?uӳ	iN~O}SW_|gu֥ @^h[쬟?gzYJ ^.q._\ݮVszVe/{Yu^ʠܖ>9+w>0!׿z(=  E+_#C^.ݪmKz@j3|w_uiM/N]z  !53zKR=涄ʝuo#^gS/rͶ=  mǋ{KS>W~OecnKrZۤ  $^h^{okV=涄^wyg~\=y;x_ ^.ǡki/S5{-s[B8r3?77  hCS;/s*=  :e-j_=Uz  !쩝A}  m{jecnz@_ @C]:վzM  hCS;/s*=  :]rEuP=Uz  !쩝A}  m{jecnz@_ @C˗/ʠJ 6=217= ރ>:(s*=  ˠJ 6=217= <:(s*=  ˠJ 6{zM  hCS;/s*=  ˠJ 6{wzM  hCS;/s*=  :{ｪ217= aOzM  hc/~QuP=Uz  !쩝A}  mT_ec.j_z  KSAԞ} 0!^k_kն`Nz@ 얰I ڛw%Q[yڕ  7a  `{      $  H    0 a  `@  =  	{      $  H    0 a  `@  =  	{      $  H    0 a  `@  =  	{      $  H    0 a  `@  =  	{      $  ($    IENDB`<?php

namespace GuzzleHttp\Psr7;

use InvalidArgumentException;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\UriInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UploadedFileInterface;















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,
$protocolVersion = '1.1',
array $serverParams = []
) {
$this->serverParams = $serverParams;

parent::__construct($method, $uri, $headers, $body, $protocolVersion);
}








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 = function_exists('getallheaders') ? getallheaders() : [];
$uri = self::getUriFromGlobals();
$body = 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));
}






public static function getUriFromGlobals() {
$uri = new Uri('');

if (isset($_SERVER['HTTPS'])) {
$uri = $uri->withScheme($_SERVER['HTTPS'] == 'on' ? 'https' : 'http');
}

if (isset($_SERVER['HTTP_HOST'])) {
$uri = $uri->withHost($_SERVER['HTTP_HOST']);
} elseif (isset($_SERVER['SERVER_NAME'])) {
$uri = $uri->withHost($_SERVER['SERVER_NAME']);
}

if (isset($_SERVER['SERVER_PORT'])) {
$uri = $uri->withPort($_SERVER['SERVER_PORT']);
}

if (isset($_SERVER['REQUEST_URI'])) {
$uri = $uri->withPath(current(explode('?', $_SERVER['REQUEST_URI'])));
}

if (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 === isset($this->attributes[$attribute])) {
return clone $this;
}

$new = clone $this;
unset($new->attributes[$attribute]);

return $new;
}
}
<?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;





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 copy_to_string($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 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 {
copy_to_stream(
$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 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 % 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\ResponseInterface;




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->statusCode = (int) $status;

if ($body !== null) {
$this->stream = stream_for($body);
}

$this->setHeaders($headers);
if (!$reason && isset(self::$phrases[$this->statusCode])) {
$this->reasonPhrase = self::$phrases[$status];
} 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 = '')
{
$new = clone $this;
$new->statusCode = (int) $code;
if (!$reasonPhrase && isset(self::$phrases[$new->statusCode])) {
$reasonPhrase = self::$phrases[$new->statusCode];
}
$new->reasonPhrase = $reasonPhrase;
return $new;
}
}
<?php


if (!function_exists('GuzzleHttp\Psr7\str')) {
require __DIR__ . '/functions.php';
}
<?php
namespace GuzzleHttp\Psr7;

use Psr\Http\Message\UriInterface;







class Uri implements UriInterface
{
private static $schemes = [
'http' => 80,
'https' => 443,
];

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 != null) {
$parts = parse_url($uri);
if ($parts === false) {
throw new \InvalidArgumentException("Unable to parse URI: $uri");
}
$this->applyParts($parts);
}
}

public function __toString()
{
return self::createUriString(
$this->scheme,
$this->getAuthority(),
$this->getPath(),
$this->query,
$this->fragment
);
}









public static function removeDotSegments($path)
{
static $noopPaths = ['' => true, '/' => true, '*' => true];
static $ignoreSegments = ['.' => true, '..' => true];

if (isset($noopPaths[$path])) {
return $path;
}

$results = [];
$segments = explode('/', $path);
foreach ($segments as $segment) {
if ($segment == '..') {
array_pop($results);
} elseif (!isset($ignoreSegments[$segment])) {
$results[] = $segment;
}
}

$newPath = implode('/', $results);

 if (substr($path, 0, 1) === '/' &&
substr($newPath, 0, 1) !== '/'
) {
$newPath = '/' . $newPath;
}


 if ($newPath != '/' && isset($ignoreSegments[end($segments)])) {
$newPath .= '/';
}

return $newPath;
}









public static function resolve(UriInterface $base, $rel)
{
if ($rel === null || $rel === '') {
return $base;
}

if (!($rel instanceof UriInterface)) {
$rel = new self($rel);
}


 if ($rel->getScheme()) {
return $rel->withPath(static::removeDotSegments($rel->getPath()));
}

$relParts = [
'scheme' => $rel->getScheme(),
'authority' => $rel->getAuthority(),
'path' => $rel->getPath(),
'query' => $rel->getQuery(),
'fragment' => $rel->getFragment()
];

$parts = [
'scheme' => $base->getScheme(),
'authority' => $base->getAuthority(),
'path' => $base->getPath(),
'query' => $base->getQuery(),
'fragment' => $base->getFragment()
];

if (!empty($relParts['authority'])) {
$parts['authority'] = $relParts['authority'];
$parts['path'] = self::removeDotSegments($relParts['path']);
$parts['query'] = $relParts['query'];
$parts['fragment'] = $relParts['fragment'];
} elseif (!empty($relParts['path'])) {
if (substr($relParts['path'], 0, 1) == '/') {
$parts['path'] = self::removeDotSegments($relParts['path']);
$parts['query'] = $relParts['query'];
$parts['fragment'] = $relParts['fragment'];
} else {
if (!empty($parts['authority']) && empty($parts['path'])) {
$mergedPath = '/';
} else {
$mergedPath = substr($parts['path'], 0, strrpos($parts['path'], '/') + 1);
}
$parts['path'] = self::removeDotSegments($mergedPath . $relParts['path']);
$parts['query'] = $relParts['query'];
$parts['fragment'] = $relParts['fragment'];
}
} elseif (!empty($relParts['query'])) {
$parts['query'] = $relParts['query'];
} elseif ($relParts['fragment'] != null) {
$parts['fragment'] = $relParts['fragment'];
}

return new self(self::createUriString(
$parts['scheme'],
$parts['authority'],
$parts['path'],
$parts['query'],
$parts['fragment']
));
}














public static function withoutQueryValue(UriInterface $uri, $key)
{
$current = $uri->getQuery();
if (!$current) {
return $uri;
}

$result = [];
foreach (explode('&', $current) as $part) {
if (explode('=', $part)[0] !== $key) {
$result[] = $part;
};
}

return $uri->withQuery(implode('&', $result));
}















public static function withQueryValue(UriInterface $uri, $key, $value)
{
$current = $uri->getQuery();
$key = strtr($key, self::$replaceQuery);

if (!$current) {
$result = [];
} else {
$result = [];
foreach (explode('&', $current) as $part) {
if (explode('=', $part)[0] !== $key) {
$result[] = $part;
};
}
}

if ($value !== null) {
$result[] = $key . '=' . strtr($value, self::$replaceQuery);
} else {
$result[] = $key;
}

return $uri->withQuery(implode('&', $result));
}








public static function fromParts(array $parts)
{
$uri = new self();
$uri->applyParts($parts);
return $uri;
}

public function getScheme()
{
return $this->scheme;
}

public function getAuthority()
{
if (empty($this->host)) {
return '';
}

$authority = $this->host;
if (!empty($this->userInfo)) {
$authority = $this->userInfo . '@' . $authority;
}

if ($this->isNonStandardPort($this->scheme, $this->host, $this->port)) {
$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 == null ? '' : $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->port = $new->filterPort($new->scheme, $new->host, $new->port);
return $new;
}

public function withUserInfo($user, $password = null)
{
$info = $user;
if ($password) {
$info .= ':' . $password;
}

if ($this->userInfo === $info) {
return $this;
}

$new = clone $this;
$new->userInfo = $info;
return $new;
}

public function withHost($host)
{
if ($this->host === $host) {
return $this;
}

$new = clone $this;
$new->host = $host;
return $new;
}

public function withPort($port)
{
$port = $this->filterPort($this->scheme, $this->host, $port);

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

$new = clone $this;
$new->port = $port;
return $new;
}

public function withPath($path)
{
if (!is_string($path)) {
throw new \InvalidArgumentException(
'Invalid path provided; must be a string'
);
}

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

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

$new = clone $this;
$new->path = $path;
return $new;
}

public function withQuery($query)
{
if (!is_string($query) && !method_exists($query, '__toString')) {
throw new \InvalidArgumentException(
'Query string must be a string'
);
}

$query = (string) $query;
if (substr($query, 0, 1) === '?') {
$query = substr($query, 1);
}

$query = $this->filterQueryAndFragment($query);

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

$new = clone $this;
$new->query = $query;
return $new;
}

public function withFragment($fragment)
{
if (substr($fragment, 0, 1) === '#') {
$fragment = substr($fragment, 1);
}

$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']) ? $parts['user'] : '';
$this->host = isset($parts['host']) ? $parts['host'] : '';
$this->port = !empty($parts['port'])
? $this->filterPort($this->scheme, $this->host, $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 .= ':' . $parts['pass'];
}
}











private static function createUriString($scheme, $authority, $path, $query, $fragment)
{
$uri = '';

if (!empty($scheme)) {
$uri .= $scheme . ':';
}

$hierPart = '';

if (!empty($authority)) {
if (!empty($scheme)) {
$hierPart .= '//';
}
$hierPart .= $authority;
}

if ($path != null) {

 if ($hierPart && substr($path, 0, 1) !== '/') {
$hierPart .= '/';
}
$hierPart .= $path;
}

$uri .= $hierPart;

if ($query != null) {
$uri .= '?' . $query;
}

if ($fragment != null) {
$uri .= '#' . $fragment;
}

return $uri;
}









private static function isNonStandardPort($scheme, $host, $port)
{
if (!$scheme && $port) {
return true;
}

if (!$host || !$port) {
return false;
}

return !isset(self::$schemes[$scheme]) || $port !== self::$schemes[$scheme];
}






private function filterScheme($scheme)
{
$scheme = strtolower($scheme);
$scheme = rtrim($scheme, ':/');

return $scheme;
}










private function filterPort($scheme, $host, $port)
{
if (null !== $port) {
$port = (int) $port;
if (1 > $port || 0xffff < $port) {
throw new \InvalidArgumentException(
sprintf('Invalid port: %d. Must be between 1 and 65535', $port)
);
}
}

return $this->isNonStandardPort($scheme, $host, $port) ? $port : null;
}








private function filterPath($path)
{
return preg_replace_callback(
'/(?:[^' . self::$charUnreserved . self::$charSubDelims . ':@\/%]+|%(?![A-Fa-f0-9]{2}))/',
[$this, 'rawurlencodeMatchZero'],
$path
);
}








private function filterQueryAndFragment($str)
{
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]);
}
}
<?php
namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;






class Stream implements StreamInterface
{
private $stream;
private $size;
private $seekable;
private $readable;
private $writable;
private $uri;
private $customMetadata;


private static $readWriteHash = [
'read' => [
'r' => true, 'w+' => true, 'r+' => true, 'x+' => true, 'c+' => true,
'rb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true,
'c+b' => true, 'rt' => true, 'w+t' => true, 'r+t' => true,
'x+t' => true, 'c+t' => true, 'a+' => true
],
'write' => [
'w' => true, 'w+' => true, 'rw' => true, 'r+' => true, 'x+' => true,
'c+' => true, 'wb' => true, 'w+b' => true, 'r+b' => true,
'x+b' => true, 'c+b' => true, 'w+t' => true, 'r+t' => true,
'x+t' => true, 'c+t' => true, 'a' => true, 'a+' => true
]
];















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 = isset(self::$readWriteHash['read'][$meta['mode']]);
$this->writable = isset(self::$readWriteHash['write'][$meta['mode']]);
$this->uri = $this->getMetadata('uri');
}

public function __get($name)
{
if ($name == 'stream') {
throw new \RuntimeException('The stream is detached');
}

throw new \BadMethodCallException('No value for ' . $name);
}




public function __destruct()
{
$this->close();
}

public function __toString()
{
try {
$this->seek(0);
return (string) stream_get_contents($this->stream);
} catch (\Exception $e) {
return '';
}
}

public function getContents()
{
$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()
{
return !$this->stream || feof($this->stream);
}

public function tell()
{
$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)
{
if (!$this->seekable) {
throw new \RuntimeException('Stream is not seekable');
} elseif (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 (!$this->readable) {
throw new \RuntimeException('Cannot read from non-readable stream');
}

return fread($this->stream, $length);
}

public function write($string)
{
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 MultipartStream implements StreamInterface
{
use StreamDecoratorTrait;

private $boundary;













public function __construct(array $elements = [], $boundary = null)
{
$this->boundary = $boundary ?: uniqid();
$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(stream_for("--{$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'] = stream_for($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(stream_for($this->getHeaders($headers)));
$stream->addStream($body);
$stream->addStream(stream_for("\r\n"));
}




private function createElement($name, $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_from_filename($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;

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, 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_stat()
{
static $modeMap = [
'r' => 33060,
'r+' => 33206,
'w' => 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
];
}
}
<?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 = 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 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 copy_to_string($this);
} catch (\Exception $e) {
return '';
}
}

public function close()
{
$this->detach();
}

public function detach()
{
$this->tellPos = false;
$this->source = 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
namespace GuzzleHttp\Psr7;

use Psr\Http\Message\StreamInterface;




trait MessageTrait
{

private $headers = [];


private $headerLines = [];


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->headerLines;
}

public function hasHeader($header)
{
return isset($this->headers[strtolower($header)]);
}

public function getHeader($header)
{
$name = strtolower($header);
return isset($this->headers[$name]) ? $this->headers[$name] : [];
}

public function getHeaderLine($header)
{
return implode(', ', $this->getHeader($header));
}

public function withHeader($header, $value)
{
$new = clone $this;
$header = trim($header);
$name = strtolower($header);

if (!is_array($value)) {
$new->headers[$name] = [trim($value)];
} else {
$new->headers[$name] = $value;
foreach ($new->headers[$name] as &$v) {
$v = trim($v);
}
}


 foreach (array_keys($new->headerLines) as $key) {
if (strtolower($key) === $name) {
unset($new->headerLines[$key]);
}
}


 $new->headerLines[$header] = $new->headers[$name];

return $new;
}

public function withAddedHeader($header, $value)
{
if (!$this->hasHeader($header)) {
return $this->withHeader($header, $value);
}

$new = clone $this;
$new->headers[strtolower($header)][] = $value;
$new->headerLines[$header][] = $value;
return $new;
}

public function withoutHeader($header)
{
if (!$this->hasHeader($header)) {
return $this;
}

$new = clone $this;
$name = strtolower($header);
unset($new->headers[$name]);

foreach (array_keys($new->headerLines) as $key) {
if (strtolower($key) === $name) {
unset($new->headerLines[$key]);
}
}

return $new;
}

public function getBody()
{
if (!$this->stream) {
$this->stream = stream_for('');
}

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->headerLines = $this->headers = [];
foreach ($headers as $header => $value) {
$header = trim($header);
$name = strtolower($header);
if (!is_array($value)) {
$value = trim($value);
$this->headers[$name][] = $value;
$this->headerLines[$header][] = $value;
} else {
foreach ($value as $v) {
$v = trim($v);
$this->headers[$name][] = $v;
$this->headerLines[$header][] = $v;
}
}
}
}
}
<?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 {
withHeader as protected withParentHeader;
}


private $method;


private $requestTarget;


private $uri;










public function __construct(
$method,
$uri,
array $headers = [],
$body = null,
$protocolVersion = '1.1'
) {
if (is_string($uri)) {
$uri = new Uri($uri);
} elseif (!($uri instanceof UriInterface)) {
throw new \InvalidArgumentException(
'URI must be a string or Psr\Http\Message\UriInterface'
);
}

$this->method = strtoupper($method);
$this->uri = $uri;
$this->setHeaders($headers);
$this->protocol = $protocolVersion;

$host = $uri->getHost();
if ($host && !$this->hasHeader('Host')) {
$this->updateHostFromUri($host);
}

if ($body) {
$this->stream = stream_for($body);
}
}

public function getRequestTarget()
{
if ($this->requestTarget !== null) {
return $this->requestTarget;
}

$target = $this->uri->getPath();
if ($target == null) {
$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)
{
$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) {
if ($host = $uri->getHost()) {
$new->updateHostFromUri($host);
}
}

return $new;
}

public function withHeader($header, $value)
{

$newInstance = $this->withParentHeader($header, $value);
return $newInstance;
}

private function updateHostFromUri($host)
{

 
 if ($port = $this->uri->getPort()) {
$host .= ':' . $port;
}

$this->headerLines = ['Host' => [$host]] + $this->headerLines;
$this->headers = ['host' => [$host]] + $this->headers;
}
}
<?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 stream_for(try_fopen($this->filename, $this->mode));
}
}
<?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(fopen('php://temp', 'r+'));
}

public function getSize()
{
return max($this->stream->getSize(), $this->remoteStream->getSize());
}

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']);
copy_to_stream($this, $target);

return $this->tell();
}
}
<?php
namespace GuzzleHttp\Psr7;

use Psr\Http\Message\MessageInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UriInterface;








function str(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) {
$msg .= "\r\n{$name}: " . implode(', ', $values);
}

return "{$msg}\r\n\r\n" . $message->getBody();
}













function uri_for($uri)
{
if ($uri instanceof UriInterface) {
return $uri;
} elseif (is_string($uri)) {
return new Uri($uri);
}

throw new \InvalidArgumentException('URI must be a string or UriInterface');
}














function stream_for($resource = '', array $options = [])
{
if (is_scalar($resource)) {
$stream = fopen('php://temp', 'r+');
if ($resource !== '') {
fwrite($stream, $resource);
fseek($stream, 0);
}
return new Stream($stream, $options);
}

switch (gettype($resource)) {
case 'resource':
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 stream_for((string) $resource, $options);
}
break;
case 'NULL':
return new Stream(fopen('php://temp', 'r+'), $options);
}

if (is_callable($resource)) {
return new PumpStream($resource, $options);
}

throw new \InvalidArgumentException('Invalid resource type: ' . gettype($resource));
}











function parse_header($header)
{
static $trimmed = "\"'  \n\t\r";
$params = $matches = [];

foreach (normalize_header($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;
}









function normalize_header($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;
}


















function modify_request(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 = _caseless_remove($changes['remove_headers'], $headers);
}

if (!empty($changes['set_headers'])) {
$headers = _caseless_remove(array_keys($changes['set_headers']), $headers);
$headers = $changes['set_headers'] + $headers;
}

if (isset($changes['query'])) {
$uri = $uri->withQuery($changes['query']);
}

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()
);
}











function rewind_body(MessageInterface $message)
{
$body = $message->getBody();

if ($body->tell()) {
$body->rewind();
}
}













function try_fopen($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]
));
});

$handle = fopen($filename, $mode);
restore_error_handler();

if ($ex) {

throw $ex;
}

return $handle;
}











function copy_to_string(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;
}












function copy_to_stream(
StreamInterface $source,
StreamInterface $dest,
$maxLen = -1
) {
if ($maxLen === -1) {
while (!$source->eof()) {
if (!$dest->write($source->read(1048576))) {
break;
}
}
return;
}

$bytes = 0;
while (!$source->eof()) {
$buf = $source->read($maxLen - $bytes);
if (!($len = strlen($buf))) {
break;
}
$bytes += $len;
$dest->write($buf);
if ($bytes == $maxLen) {
break;
}
}
}











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;
}









function readline(StreamInterface $stream, $maxLength = null)
{
$buffer = '';
$size = 0;

while (!$stream->eof()) {

 if (null == ($byte = $stream->read(1))) {
return $buffer;
}
$buffer .= $byte;

 if ($byte == PHP_EOL || ++$size == $maxLength - 1) {
break;
}
}

return $buffer;
}








function parse_request($message)
{
$data = _parse_message($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] === '/' ? _parse_request_uri($parts[1], $data['headers']) : $parts[1],
$data['headers'],
$data['body'],
$version
);

return $matches[1] === '/' ? $request : $request->withRequestTarget($parts[1]);
}








function parse_response($message)
{
$data = _parse_message($message);
if (!preg_match('/^HTTP\/.* [0-9]{3} .*/', $data['start-line'])) {
throw new \InvalidArgumentException('Invalid response string');
}
$parts = explode(' ', $data['start-line'], 3);

return new Response(
$parts[1],
$data['headers'],
$data['body'],
explode('/', $parts[0])[1],
isset($parts[2]) ? $parts[2] : null
);
}














function parse_query($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;
}














function build_query(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) : '';
}








function mimetype_from_filename($filename)
{
return mimetype_from_extension(pathinfo($filename, PATHINFO_EXTENSION));
}









function mimetype_from_extension($extension)
{
static $mimetypes = [
'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',
'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',
'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;
}













function _parse_message($message)
{
if (!$message) {
throw new \InvalidArgumentException('Invalid message');
}


 $lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE);
$result = ['start-line' => array_shift($lines), 'headers' => [], 'body' => ''];
array_shift($lines);

for ($i = 0, $totalLines = count($lines); $i < $totalLines; $i += 2) {
$line = $lines[$i];

 if (empty($line)) {
if ($i < $totalLines - 1) {
$result['body'] = implode('', array_slice($lines, $i + 2));
}
break;
}
if (strpos($line, ':')) {
$parts = explode(':', $line, 2);
$key = trim($parts[0]);
$value = isset($parts[1]) ? trim($parts[1]) : '';
$result['headers'][$key][] = $value;
}
}

return $result;
}










function _parse_request_uri($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, '/');
}


function _caseless_remove($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;
}
<?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\StreamInterface;






class AppendStream implements StreamInterface
{

private $streams = [];

private $seekable = true;
private $current = 0;
private $pos = 0;
private $detached = false;





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 copy_to_string($this);
}






public function close()
{
$this->pos = $this->current = 0;

foreach ($this->streams as $stream) {
$stream->close();
}

$this->streams = [];
}






public function detach()
{
$this->close();
$this->detached = true;
}

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\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();
}

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 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 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\Ring\Future;

use GuzzleHttp\Ring\Exception\CancelledFutureAccessException;
use GuzzleHttp\Ring\Exception\RingException;
use React\Promise\PromiseInterface;




trait BaseFutureTrait
{

private $waitfn;


private $cancelfn;


private $wrappedPromise;


private $error;


private $result;

private $isRealized = false;











public function __construct(
PromiseInterface $promise,
callable $wait = null,
callable $cancel = null
) {
$this->wrappedPromise = $promise;
$this->waitfn = $wait;
$this->cancelfn = $cancel;
}

public function wait()
{
if (!$this->isRealized) {
$this->addShadow();
if (!$this->isRealized && $this->waitfn) {
$this->invokeWait();
}
if (!$this->isRealized) {
$this->error = new RingException('Waiting did not resolve future');
}
}

if ($this->error) {
throw $this->error;
}

return $this->result;
}

public function promise()
{
return $this->wrappedPromise;
}

public function then(
callable $onFulfilled = null,
callable $onRejected = null,
callable $onProgress = null
) {
return $this->wrappedPromise->then($onFulfilled, $onRejected, $onProgress);
}

public function cancel()
{
if (!$this->isRealized) {
$cancelfn = $this->cancelfn;
$this->waitfn = $this->cancelfn = null;
$this->isRealized = true;
$this->error = new CancelledFutureAccessException();
if ($cancelfn) {
$cancelfn($this);
}
}
}

private function addShadow()
{

 
 $this->wrappedPromise->then(
function ($value) {
$this->isRealized = true;
$this->result = $value;
$this->waitfn = $this->cancelfn = null;
},
function ($error) {
$this->isRealized = true;
$this->error = $error;
$this->waitfn = $this->cancelfn = null;
}
);
}

private function invokeWait()
{
try {
$wait = $this->waitfn;
$this->waitfn = null;
$wait();
} catch (\Exception $e) {

 $this->error = $e;
$this->isRealized = true;
}
}
}
<?php
namespace GuzzleHttp\Ring\Future;




interface FutureArrayInterface extends
FutureInterface,
\ArrayAccess,
\Countable,
\IteratorAggregate {};
<?php
namespace GuzzleHttp\Ring\Future;






class FutureValue implements FutureInterface
{
use BaseFutureTrait;
}
<?php
namespace GuzzleHttp\Ring\Future;




class FutureArray implements FutureArrayInterface
{
use MagicFutureTrait;

public function offsetExists($offset)
{
return isset($this->_value[$offset]);
}

public function offsetGet($offset)
{
return $this->_value[$offset];
}

public function offsetSet($offset, $value)
{
$this->_value[$offset] = $value;
}

public function offsetUnset($offset)
{
unset($this->_value[$offset]);
}

public function count()
{
return count($this->_value);
}

public function getIterator()
{
return new \ArrayIterator($this->_value);
}
}
<?php
namespace GuzzleHttp\Ring\Future;

use React\Promise\FulfilledPromise;
use React\Promise\RejectedPromise;




class CompletedFutureValue implements FutureInterface
{
protected $result;
protected $error;

private $cachedPromise;






public function __construct($result, \Exception $e = null)
{
$this->result = $result;
$this->error = $e;
}

public function wait()
{
if ($this->error) {
throw $this->error;
}

return $this->result;
}

public function cancel() {}

public function promise()
{
if (!$this->cachedPromise) {
$this->cachedPromise = $this->error
? new RejectedPromise($this->error)
: new FulfilledPromise($this->result);
}

return $this->cachedPromise;
}

public function then(
callable $onFulfilled = null,
callable $onRejected = null,
callable $onProgress = null
) {
return $this->promise()->then($onFulfilled, $onRejected, $onProgress);
}
}
<?php
namespace GuzzleHttp\Ring\Future;








trait MagicFutureTrait
{
use BaseFutureTrait;










public function __get($name)
{
if ($name !== '_value') {
throw new \RuntimeException("Class has no {$name} property");
}

return $this->_value = $this->wait();
}
}
<?php
namespace GuzzleHttp\Ring\Future;




class CompletedFutureArray extends CompletedFutureValue implements FutureArrayInterface
{
public function __construct(array $result)
{
parent::__construct($result);
}

public function offsetExists($offset)
{
return isset($this->result[$offset]);
}

public function offsetGet($offset)
{
return $this->result[$offset];
}

public function offsetSet($offset, $value)
{
$this->result[$offset] = $value;
}

public function offsetUnset($offset)
{
unset($this->result[$offset]);
}

public function count()
{
return count($this->result);
}

public function getIterator()
{
return new \ArrayIterator($this->result);
}
}
<?php
namespace GuzzleHttp\Ring\Future;

use React\Promise\PromiseInterface;
use React\Promise\PromisorInterface;













interface FutureInterface extends PromiseInterface, PromisorInterface
{













public function wait();




public function cancel();
}
<?php
namespace GuzzleHttp\Ring\Client;

use GuzzleHttp\Ring\Core;
use GuzzleHttp\Ring\Future\CompletedFutureArray;
use GuzzleHttp\Ring\Future\FutureArrayInterface;




class MockHandler
{

private $result;








public function __construct($result)
{
$this->result = $result;
}

public function __invoke(array $request)
{
Core::doSleep($request);
$response = is_callable($this->result)
? call_user_func($this->result, $request)
: $this->result;

if (is_array($response)) {
$response = new CompletedFutureArray($response + [
'status' => null,
'body' => null,
'headers' => [],
'reason' => null,
'effective_url' => null,
]);
} elseif (!$response instanceof FutureArrayInterface) {
throw new \InvalidArgumentException(
'Response must be an array or FutureArrayInterface. Found '
. Core::describeType($request)
);
}

return $response;
}
}
<?php
namespace GuzzleHttp\Ring\Client;

use GuzzleHttp\Ring\Core;
use GuzzleHttp\Ring\Exception\ConnectException;
use GuzzleHttp\Ring\Exception\RingException;
use GuzzleHttp\Stream\LazyOpenStream;
use GuzzleHttp\Stream\StreamInterface;




class CurlFactory
{











public function __invoke(array $request, $handle = null)
{
$headers = [];
$options = $this->getDefaultOptions($request, $headers);
$this->applyMethod($request, $options);

if (isset($request['client'])) {
$this->applyHandlerOptions($request, $options);
}

$this->applyHeaders($request, $options);
unset($options['_headers']);


 if (isset($request['client']['curl'])) {
$options = $this->applyCustomCurlOptions(
$request['client']['curl'],
$options
);
}

if (!$handle) {
$handle = curl_init();
}

$body = $this->getOutputBody($request, $options);
curl_setopt_array($handle, $options);

return [$handle, &$headers, $body];
}












public static function createResponse(
callable $handler,
array $request,
array $response,
array $headers,
$body
) {
if (isset($response['transfer_stats']['url'])) {
$response['effective_url'] = $response['transfer_stats']['url'];
}

if (!empty($headers)) {
$startLine = explode(' ', array_shift($headers), 3);
$headerList = Core::headersFromLines($headers);
$response['headers'] = $headerList;
$response['version'] = isset($startLine[0]) ? substr($startLine[0], 5) : null;
$response['status'] = isset($startLine[1]) ? (int) $startLine[1] : null;
$response['reason'] = isset($startLine[2]) ? $startLine[2] : null;
$response['body'] = $body;
Core::rewindBody($response);
}

return !empty($response['curl']['errno']) || !isset($response['status'])
? self::createErrorResponse($handler, $request, $response)
: $response;
}

private static function createErrorResponse(
callable $handler,
array $request,
array $response
) {
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 (!isset($response['err_message'])
&& (empty($response['curl']['errno'])
|| $response['curl']['errno'] == 65)
) {
return self::retryFailedRewind($handler, $request, $response);
}

$message = isset($response['err_message'])
? $response['err_message']
: sprintf('cURL error %s: %s',
$response['curl']['errno'],
isset($response['curl']['error'])
? $response['curl']['error']
: 'See http://curl.haxx.se/libcurl/c/libcurl-errors.html');

$error = isset($response['curl']['errno'])
&& isset($connectionErrors[$response['curl']['errno']])
? new ConnectException($message)
: new RingException($message);

return $response + [
'status' => null,
'reason' => null,
'body' => null,
'headers' => [],
'error' => $error,
];
}

private function getOutputBody(array $request, array &$options)
{

 if (isset($options[CURLOPT_WRITEFUNCTION])) {
return $request['client']['save_to'];
}

if (isset($options[CURLOPT_FILE])) {
return $options[CURLOPT_FILE];
}

if ($request['http_method'] != 'HEAD') {

 return $options[CURLOPT_FILE] = fopen('php://temp', 'w+');
}

return null;
}

private function getDefaultOptions(array $request, array &$headers)
{
$url = Core::url($request);
$startingResponse = false;

$options = [
'_headers' => $request['headers'],
CURLOPT_CUSTOMREQUEST => $request['http_method'],
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => false,
CURLOPT_HEADER => false,
CURLOPT_CONNECTTIMEOUT => 150,
CURLOPT_HEADERFUNCTION => function ($ch, $h) use (&$headers, &$startingResponse) {
$value = trim($h);
if ($value === '') {
$startingResponse = true;
} elseif ($startingResponse) {
$startingResponse = false;
$headers = [$value];
} else {
$headers[] = $value;
}
return strlen($h);
},
];

if (isset($request['version'])) {
if ($request['version'] == 2.0) {
$options[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_2_0;
} else if ($request['version'] == 1.1) {
$options[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
} else {
$options[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_0;
}
}

if (defined('CURLOPT_PROTOCOLS')) {
$options[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS;
}

return $options;
}

private function applyMethod(array $request, array &$options)
{
if (isset($request['body'])) {
$this->applyBody($request, $options);
return;
}

switch ($request['http_method']) {
case 'PUT':
case 'POST':

 if (!Core::hasHeader($request, 'Content-Length')) {
$options[CURLOPT_HTTPHEADER][] = 'Content-Length: 0';
}
break;
case 'HEAD':
$options[CURLOPT_NOBODY] = true;
unset(
$options[CURLOPT_WRITEFUNCTION],
$options[CURLOPT_READFUNCTION],
$options[CURLOPT_FILE],
$options[CURLOPT_INFILE]
);
}
}

private function applyBody(array $request, array &$options)
{
$contentLength = Core::firstHeader($request, 'Content-Length');
$size = $contentLength !== null ? (int) $contentLength : null;


 
 if (($size !== null && $size < 1000000) ||
isset($request['client']['curl']['body_as_string']) ||
is_string($request['body'])
) {
$options[CURLOPT_POSTFIELDS] = Core::body($request);

 $this->removeHeader('Content-Length', $options);
$this->removeHeader('Transfer-Encoding', $options);
} else {
$options[CURLOPT_UPLOAD] = true;
if ($size !== null) {

 $options[CURLOPT_INFILESIZE] = $size;
$this->removeHeader('Content-Length', $options);
}
$this->addStreamingBody($request, $options);
}


 if (!Core::hasHeader($request, 'Expect')) {
$options[CURLOPT_HTTPHEADER][] = 'Expect:';
}


 if (!Core::hasHeader($request, 'Content-Type')) {
$options[CURLOPT_HTTPHEADER][] = 'Content-Type:';
}
}

private function addStreamingBody(array $request, array &$options)
{
$body = $request['body'];

if ($body instanceof StreamInterface) {
$options[CURLOPT_READFUNCTION] = function ($ch, $fd, $length) use ($body) {
return (string) $body->read($length);
};
if (!isset($options[CURLOPT_INFILESIZE])) {
if ($size = $body->getSize()) {
$options[CURLOPT_INFILESIZE] = $size;
}
}
} elseif (is_resource($body)) {
$options[CURLOPT_INFILE] = $body;
} elseif ($body instanceof \Iterator) {
$buf = '';
$options[CURLOPT_READFUNCTION] = function ($ch, $fd, $length) use ($body, &$buf) {
if ($body->valid()) {
$buf .= $body->current();
$body->next();
}
$result = (string) substr($buf, 0, $length);
$buf = substr($buf, $length);
return $result;
};
} else {
throw new \InvalidArgumentException('Invalid request body provided');
}
}

private function applyHeaders(array $request, array &$options)
{
foreach ($options['_headers'] as $name => $values) {
foreach ($values as $value) {
$options[CURLOPT_HTTPHEADER][] = "$name: $value";
}
}


 if (!Core::hasHeader($request, 'Accept')) {
$options[CURLOPT_HTTPHEADER][] = 'Accept:';
}
}












private function applyCustomCurlOptions(array $config, array $options)
{
$curlOptions = [];
foreach ($config as $key => $value) {
if (is_int($key)) {
$curlOptions[$key] = $value;
}
}

return $curlOptions + $options;
}







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(array $request, array &$options)
{
foreach ($request['client'] as $key => $value) {
switch ($key) {

 case 'verify':

if ($value === false) {
unset($options[CURLOPT_CAINFO]);
$options[CURLOPT_SSL_VERIFYHOST] = 0;
$options[CURLOPT_SSL_VERIFYPEER] = false;
continue;
}

$options[CURLOPT_SSL_VERIFYHOST] = 2;
$options[CURLOPT_SSL_VERIFYPEER] = true;

if (is_string($value)) {
$options[CURLOPT_CAINFO] = $value;
if (!file_exists($value)) {
throw new \InvalidArgumentException(
"SSL CA bundle not found: $value"
);
}
}
break;

case 'decode_content':

if ($value === false) {
continue;
}

$accept = Core::firstHeader($request, 'Accept-Encoding');
if ($accept) {
$options[CURLOPT_ENCODING] = $accept;
} else {
$options[CURLOPT_ENCODING] = '';

 $options[CURLOPT_HTTPHEADER][] = 'Accept-Encoding:';
}
break;

case 'save_to':

if (is_string($value)) {
if (!is_dir(dirname($value))) {
throw new \RuntimeException(sprintf(
'Directory %s does not exist for save_to value of %s',
dirname($value),
$value
));
}
$value = new LazyOpenStream($value, 'w+');
}

if ($value instanceof StreamInterface) {
$options[CURLOPT_WRITEFUNCTION] =
function ($ch, $write) use ($value) {
return $value->write($write);
};
} elseif (is_resource($value)) {
$options[CURLOPT_FILE] = $value;
} else {
throw new \InvalidArgumentException('save_to must be a '
. 'GuzzleHttp\Stream\StreamInterface or resource');
}
break;

case 'timeout':

if (defined('CURLOPT_TIMEOUT_MS')) {
$options[CURLOPT_TIMEOUT_MS] = $value * 1000;
} else {
$options[CURLOPT_TIMEOUT] = $value;
}
break;

case 'connect_timeout':

if (defined('CURLOPT_CONNECTTIMEOUT_MS')) {
$options[CURLOPT_CONNECTTIMEOUT_MS] = $value * 1000;
} else {
$options[CURLOPT_CONNECTTIMEOUT] = $value;
}
break;

case 'proxy':

if (!is_array($value)) {
$options[CURLOPT_PROXY] = $value;
} elseif (isset($request['scheme'])) {
$scheme = $request['scheme'];
if (isset($value[$scheme])) {
$options[CURLOPT_PROXY] = $value[$scheme];
}
}
break;

case 'cert':

if (is_array($value)) {
$options[CURLOPT_SSLCERTPASSWD] = $value[1];
$value = $value[0];
}

if (!file_exists($value)) {
throw new \InvalidArgumentException(
"SSL certificate not found: {$value}"
);
}

$options[CURLOPT_SSLCERT] = $value;
break;

case 'ssl_key':

if (is_array($value)) {
$options[CURLOPT_SSLKEYPASSWD] = $value[1];
$value = $value[0];
}

if (!file_exists($value)) {
throw new \InvalidArgumentException(
"SSL private key not found: {$value}"
);
}

$options[CURLOPT_SSLKEY] = $value;
break;

case 'progress':

if (!is_callable($value)) {
throw new \InvalidArgumentException(
'progress client option must be callable'
);
}

$options[CURLOPT_NOPROGRESS] = false;
$options[CURLOPT_PROGRESSFUNCTION] =
function () use ($value) {
$args = func_get_args();

 if (is_resource($args[0])) {
array_shift($args);
}
call_user_func_array($value, $args);
};
break;

case 'debug':

if ($value) {
$options[CURLOPT_STDERR] = Core::getDebugResource($value);
$options[CURLOPT_VERBOSE] = true;
}
break;
}
}
}










private static function retryFailedRewind(
callable $handler,
array $request,
array $response
) {

 
 if (!isset($request['body'])) {
$response['err_message'] = 'No response was received for a request '
. 'with no body. This could mean that you are saturating your '
. 'network.';
return self::createErrorResponse($handler, $request, $response);
}

if (!Core::rewindBody($request)) {
$response['err_message'] = 'The connection unexpectedly failed '
. 'without providing an error. The request would have been '
. 'retried, but attempting to rewind the request body failed.';
return self::createErrorResponse($handler, $request, $response);
}


 if (!isset($request['curl']['retries'])) {
$request['curl']['retries'] = 1;
} elseif ($request['curl']['retries'] == 2) {
$response['err_message'] = 'The cURL request was retried 3 times '
. 'and did no succeed. 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::createErrorResponse($handler, $request, $response);
} else {
$request['curl']['retries']++;
}

return $handler($request);
}
}
<?php
namespace GuzzleHttp\Ring\Client;




class ClientUtils
{














public static function getDefaultCaBundle()
{
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',

 '/usr/local/etc/openssl/cert.pem',

 '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(self::CA_ERR);
}

const CA_ERR = "
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.";
}
<?php
namespace GuzzleHttp\Ring\Client;







class Middleware
{












public static function wrapFuture(
callable $default,
callable $future
) {
return function (array $request) use ($default, $future) {
return empty($request['client']['future'])
? $default($request)
: $future($request);
};
}














public static function wrapStreaming(
callable $default,
callable $streaming
) {
return function (array $request) use ($default, $streaming) {
return empty($request['client']['stream'])
? $default($request)
: $streaming($request);
};
}
}
<?php
namespace GuzzleHttp\Ring\Client;

use GuzzleHttp\Ring\Core;
use GuzzleHttp\Ring\Exception\ConnectException;
use GuzzleHttp\Ring\Exception\RingException;
use GuzzleHttp\Ring\Future\CompletedFutureArray;
use GuzzleHttp\Stream\InflateStream;
use GuzzleHttp\Stream\StreamInterface;
use GuzzleHttp\Stream\Stream;
use GuzzleHttp\Stream\Utils;




class StreamHandler
{
private $options;
private $lastHeaders;

public function __construct(array $options = [])
{
$this->options = $options;
}

public function __invoke(array $request)
{
$url = Core::url($request);
Core::doSleep($request);

try {

 $request = Core::removeHeader($request, 'Expect');
$stream = $this->createStream($url, $request);
return $this->createResponse($request, $url, $stream);
} catch (RingException $e) {
return $this->createErrorResponse($url, $e);
}
}

private function createResponse(array $request, $url, $stream)
{
$hdrs = $this->lastHeaders;
$this->lastHeaders = null;
$parts = explode(' ', array_shift($hdrs), 3);
$response = [
'version' => substr($parts[0], 5),
'status' => $parts[1],
'reason' => isset($parts[2]) ? $parts[2] : null,
'headers' => Core::headersFromLines($hdrs),
'effective_url' => $url,
];

$stream = $this->checkDecode($request, $response, $stream);


 if (empty($request['client']['stream'])) {
$dest = isset($request['client']['save_to'])
? $request['client']['save_to']
: fopen('php://temp', 'r+');
$stream = $this->drain($stream, $dest);
}

$response['body'] = $stream;

return new CompletedFutureArray($response);
}

private function checkDecode(array $request, array $response, $stream)
{

 if (!empty($request['client']['decode_content'])) {
switch (Core::firstHeader($response, 'Content-Encoding', true)) {
case 'gzip':
case 'deflate':
$stream = new InflateStream(Stream::factory($stream));
break;
}
}

return $stream;
}










private function drain($stream, $dest)
{
if (is_resource($stream)) {
if (!is_resource($dest)) {
$stream = Stream::factory($stream);
} else {
stream_copy_to_stream($stream, $dest);
fclose($stream);
rewind($dest);
return $dest;
}
}


 $dest = is_string($dest)
? new Stream(Utils::open($dest, 'r+'))
: Stream::factory($dest);

Utils::copyToStream($stream, $dest);
$dest->seek(0);
$stream->close();

return $dest;
}









private function createErrorResponse($url, RingException $e)
{

 $message = $e->getMessage();


 if (strpos($message, 'getaddrinfo') 
 || strpos($message, 'Connection refused')
) {
$e = new ConnectException($e->getMessage(), 0, $e);
}

return new CompletedFutureArray([
'status' => null,
'body' => null,
'headers' => [],
'effective_url' => $url,
'error' => $e
]);
}









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 RingException(trim($message));
}

return $resource;
}

private function createStream($url, array $request)
{
static $methods;
if (!$methods) {
$methods = array_flip(get_class_methods(__CLASS__));
}


 
 if ((!isset($request['version']) || $request['version'] == '1.1')
&& !Core::hasHeader($request, 'Connection')
) {
$request['headers']['Connection'] = ['close'];
}


 if (!isset($request['client']['verify'])) {
$request['client']['verify'] = true;
}

$params = [];
$options = $this->getDefaultOptions($request);

if (isset($request['client'])) {
foreach ($request['client'] as $key => $value) {
$method = "add_{$key}";
if (isset($methods[$method])) {
$this->{$method}($request, $options, $value, $params);
}
}
}

return $this->createStreamResource(
$url,
$request,
$options,
$this->createContext($request, $options, $params)
);
}

private function getDefaultOptions(array $request)
{
$headers = "";
foreach ($request['headers'] as $name => $value) {
foreach ((array) $value as $val) {
$headers .= "$name: $val\r\n";
}
}

$context = [
'http' => [
'method' => $request['http_method'],
'header' => $headers,
'protocol_version' => isset($request['version']) ? $request['version'] : 1.1,
'ignore_errors' => true,
'follow_location' => 0,
],
];

$body = Core::body($request);
if (isset($body)) {
$context['http']['content'] = $body;

 if (!Core::hasHeader($request, 'Content-Type')) {
$context['http']['header'] .= "Content-Type:\r\n";
}
}

$context['http']['header'] = rtrim($context['http']['header']);

return $context;
}

private function add_proxy(array $request, &$options, $value, &$params)
{
if (!is_array($value)) {
$options['http']['proxy'] = $value;
} else {
$scheme = isset($request['scheme']) ? $request['scheme'] : 'http';
if (isset($value[$scheme])) {
$options['http']['proxy'] = $value[$scheme];
}
}
}

private function add_timeout(array $request, &$options, $value, &$params)
{
$options['http']['timeout'] = $value;
}

private function add_verify(array $request, &$options, $value, &$params)
{
if ($value === true) {

 
 if (PHP_VERSION_ID < 50600) {
$options['ssl']['cafile'] = ClientUtils::getDefaultCaBundle();
}
} elseif (is_string($value)) {
$options['ssl']['cafile'] = $value;
if (!file_exists($value)) {
throw new RingException("SSL CA bundle not found: $value");
}
} elseif ($value === false) {
$options['ssl']['verify_peer'] = false;
$options['ssl']['allow_self_signed'] = true;
return;
} else {
throw new RingException('Invalid verify request option');
}

$options['ssl']['verify_peer'] = true;
$options['ssl']['allow_self_signed'] = false;
}

private function add_cert(array $request, &$options, $value, &$params)
{
if (is_array($value)) {
$options['ssl']['passphrase'] = $value[1];
$value = $value[0];
}

if (!file_exists($value)) {
throw new RingException("SSL certificate not found: {$value}");
}

$options['ssl']['local_cert'] = $value;
}

private function add_progress(array $request, &$options, $value, &$params)
{
$fn = function ($code, $_1, $_2, $_3, $transferred, $total) use ($value) {
if ($code == STREAM_NOTIFY_PROGRESS) {
$value($total, $transferred, null, null);
}
};


 $params['notification'] = isset($params['notification'])
? Core::callArray([$params['notification'], $fn])
: $fn;
}

private function add_debug(array $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 = Core::getDebugResource($value);
$ident = $request['http_method'] . ' ' . Core::url($request);
$fn = 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");
};


 $params['notification'] = isset($params['notification'])
? Core::callArray([$params['notification'], $fn])
: $fn;
}

private function applyCustomOptions(array $request, array &$options)
{
if (!isset($request['client']['stream_context'])) {
return;
}

if (!is_array($request['client']['stream_context'])) {
throw new RingException('stream_context must be an array');
}

$options = array_replace_recursive(
$options,
$request['client']['stream_context']
);
}

private function createContext(array $request, array $options, array $params)
{
$this->applyCustomOptions($request, $options);
return $this->createResource(
function () use ($request, $options, $params) {
return stream_context_create($options, $params);
},
$request,
$options
);
}

private function createStreamResource(
$url,
array $request,
array $options,
$context
) {
return $this->createResource(
function () use ($url, $context) {
if (false === strpos($url, 'http')) {
trigger_error("URL is invalid: {$url}", E_USER_WARNING);
return null;
}
$resource = fopen($url, 'r', null, $context);
$this->lastHeaders = $http_response_header;
return $resource;
},
$request,
$options
);
}
}
<?php
namespace GuzzleHttp\Ring\Client;

use GuzzleHttp\Ring\Future\CompletedFutureArray;
use GuzzleHttp\Ring\Core;










class CurlHandler
{

private $factory;


private $handles = [];


private $ownedHandles = [];


private $maxHandles;











public function __construct(array $options = [])
{
$this->handles = $this->ownedHandles = [];
$this->factory = isset($options['handle_factory'])
? $options['handle_factory']
: new CurlFactory();
$this->maxHandles = isset($options['max_handles'])
? $options['max_handles']
: 5;
}

public function __destruct()
{
foreach ($this->handles as $handle) {
if (is_resource($handle)) {
curl_close($handle);
}
}
}






public function __invoke(array $request)
{
return new CompletedFutureArray(
$this->_invokeAsArray($request)
);
}








public function _invokeAsArray(array $request)
{
$factory = $this->factory;


 $result = $factory($request, $this->checkoutEasyHandle());
$h = $result[0];
$hd =& $result[1];
$bd = $result[2];
Core::doSleep($request);
curl_exec($h);
$response = ['transfer_stats' => curl_getinfo($h)];
$response['curl']['error'] = curl_error($h);
$response['curl']['errno'] = curl_errno($h);
$response['transfer_stats'] = array_merge($response['transfer_stats'], $response['curl']);
$this->releaseEasyHandle($h);

return CurlFactory::createResponse([$this, '_invokeAsArray'], $request, $response, $hd, $bd);
}

private function checkoutEasyHandle()
{

 if (false !== ($key = array_search(false, $this->ownedHandles, true))) {
$this->ownedHandles[$key] = true;
return $this->handles[$key];
}


 $handle = curl_init();
$id = (int) $handle;
$this->handles[$id] = $handle;
$this->ownedHandles[$id] = true;

return $handle;
}

private function releaseEasyHandle($handle)
{
$id = (int) $handle;
if (count($this->ownedHandles) > $this->maxHandles) {
curl_close($this->handles[$id]);
unset($this->handles[$id], $this->ownedHandles[$id]);
} else {

 static $unsetValues = [
CURLOPT_HEADERFUNCTION => null,
CURLOPT_WRITEFUNCTION => null,
CURLOPT_READFUNCTION => null,
CURLOPT_PROGRESSFUNCTION => null,
];
curl_setopt_array($handle, $unsetValues);
curl_reset($handle);
$this->ownedHandles[$id] = false;
}
}
}
<?php
namespace GuzzleHttp\Ring\Client;

use GuzzleHttp\Ring\Future\FutureArray;
use React\Promise\Deferred;













class CurlMultiHandler
{

private $factory;
private $selectTimeout;
private $active;
private $handles = [];
private $delays = [];
private $maxHandles;
















public function __construct(array $options = [])
{
if (isset($options['mh'])) {
$this->_mh = $options['mh'];
}
$this->factory = isset($options['handle_factory'])
? $options['handle_factory'] : new CurlFactory();
$this->selectTimeout = isset($options['select_timeout'])
? $options['select_timeout'] : 1;
$this->maxHandles = isset($options['max_handles'])
? $options['max_handles'] : 100;
}

public function __get($name)
{
if ($name === '_mh') {
return $this->_mh = curl_multi_init();
}

throw new \BadMethodCallException();
}

public function __destruct()
{

 if ($this->handles) {
$this->execute();
}

if (isset($this->_mh)) {
curl_multi_close($this->_mh);
unset($this->_mh);
}
}

public function __invoke(array $request)
{
$factory = $this->factory;
$result = $factory($request);
$entry = [
'request' => $request,
'response' => [],
'handle' => $result[0],
'headers' => &$result[1],
'body' => $result[2],
'deferred' => new Deferred(),
];

$id = (int) $result[0];

$future = new FutureArray(
$entry['deferred']->promise(),
[$this, 'execute'],
function () use ($id) {
return $this->cancel($id);
}
);

$this->addRequest($entry);


 if (count($this->handles) >= $this->maxHandles) {
$this->execute();
}

return $future;
}




public function execute()
{
do {

if ($this->active &&
curl_multi_select($this->_mh, $this->selectTimeout) === -1
) {

 
 usleep(250);
}


 if ($this->delays) {
$this->addDelays();
}

do {
$mrc = curl_multi_exec($this->_mh, $this->active);
} while ($mrc === CURLM_CALL_MULTI_PERFORM);

$this->processMessages();


 if (!$this->active && $this->delays) {
usleep(500);
}

} while ($this->active || $this->handles);
}

private function addRequest(array &$entry)
{
$id = (int) $entry['handle'];
$this->handles[$id] = $entry;


 
 if (isset($entry['request']['client']['delay'])) {
$this->delays[$id] = microtime(true) + ($entry['request']['client']['delay'] / 1000);
} elseif (empty($entry['request']['future'])) {
curl_multi_add_handle($this->_mh, $entry['handle']);
} else {
curl_multi_add_handle($this->_mh, $entry['handle']);

 if ($entry['request']['future'] !== 'lazy') {
do {
$mrc = curl_multi_exec($this->_mh, $this->active);
} while ($mrc === CURLM_CALL_MULTI_PERFORM);
$this->processMessages();
}
}
}

private function removeProcessed($id)
{
if (isset($this->handles[$id])) {
curl_multi_remove_handle(
$this->_mh,
$this->handles[$id]['handle']
);
curl_close($this->handles[$id]['handle']);
unset($this->handles[$id], $this->delays[$id]);
}
}








private function cancel($id)
{

 if (!isset($this->handles[$id])) {
return false;
}

$handle = $this->handles[$id]['handle'];
unset($this->delays[$id], $this->handles[$id]);
curl_multi_remove_handle($this->_mh, $handle);
curl_close($handle);

return true;
}

private function addDelays()
{
$currentTime = microtime(true);

foreach ($this->delays as $id => $delay) {
if ($currentTime >= $delay) {
unset($this->delays[$id]);
curl_multi_add_handle(
$this->_mh,
$this->handles[$id]['handle']
);
}
}
}

private function processMessages()
{
while ($done = curl_multi_info_read($this->_mh)) {
$id = (int) $done['handle'];

if (!isset($this->handles[$id])) {

 continue;
}

$entry = $this->handles[$id];
$entry['response']['transfer_stats'] = curl_getinfo($done['handle']);

if ($done['result'] !== CURLM_OK) {
$entry['response']['curl']['errno'] = $done['result'];
if (function_exists('curl_strerror')) {
$entry['response']['curl']['error'] = curl_strerror($done['result']);
}
}

$result = CurlFactory::createResponse(
$this,
$entry['request'],
$entry['response'],
$entry['headers'],
$entry['body']
);

$this->removeProcessed($id);
$entry['deferred']->resolve($result);
}
}
}
<?php
namespace GuzzleHttp\Ring;

use GuzzleHttp\Stream\StreamInterface;
use GuzzleHttp\Ring\Future\FutureArrayInterface;
use GuzzleHttp\Ring\Future\FutureArray;




class Core
{








public static function callArray(array $functions)
{
return function () use ($functions) {
$args = func_get_args();
foreach ($functions as $fn) {
call_user_func_array($fn, $args);
}
};
}












public static function headerLines($message, $header)
{
$result = [];

if (!empty($message['headers'])) {
foreach ($message['headers'] as $name => $value) {
if (!strcasecmp($name, $header)) {
$result = array_merge($result, $value);
}
}
}

return $result;
}













public static function header($message, $header)
{
$match = self::headerLines($message, $header);
return $match ? implode(', ', $match) : null;
}











public static function firstHeader($message, $header)
{
if (!empty($message['headers'])) {
foreach ($message['headers'] as $name => $value) {
if (!strcasecmp($name, $header)) {

 $pos = strpos($value[0], ',');
return $pos ? substr($value[0], 0, $pos) : $value[0];
}
}
}

return null;
}









public static function hasHeader($message, $header)
{
if (!empty($message['headers'])) {
foreach ($message['headers'] as $name => $value) {
if (!strcasecmp($name, $header)) {
return true;
}
}
}

return false;
}








public static function headersFromLines($lines)
{
$headers = [];

foreach ($lines as $line) {
$parts = explode(':', $line, 2);
$headers[trim($parts[0])][] = isset($parts[1])
? trim($parts[1])
: null;
}

return $headers;
}









public static function removeHeader(array $message, $header)
{
if (isset($message['headers'])) {
foreach (array_keys($message['headers']) as $key) {
if (!strcasecmp($header, $key)) {
unset($message['headers'][$key]);
}
}
}

return $message;
}










public static function setHeader(array $message, $header, array $value)
{
$message = self::removeHeader($message, $header);
$message['headers'][$header] = $value;

return $message;
}













public static function url(array $request)
{
if (isset($request['url'])) {
return $request['url'];
}

$uri = (isset($request['scheme'])
? $request['scheme'] : 'http') . '://';

if ($host = self::header($request, 'host')) {
$uri .= $host;
} else {
throw new \InvalidArgumentException('No Host header was provided');
}

if (isset($request['uri'])) {
$uri .= $request['uri'];
}

if (isset($request['query_string'])) {
$uri .= '?' . $request['query_string'];
}

return $uri;
}









public static function body($message)
{
if (!isset($message['body'])) {
return null;
}

if ($message['body'] instanceof StreamInterface) {
return (string) $message['body'];
}

switch (gettype($message['body'])) {
case 'string':
return $message['body'];
case 'resource':
return stream_get_contents($message['body']);
case 'object':
if ($message['body'] instanceof \Iterator) {
return implode('', iterator_to_array($message['body']));
} elseif (method_exists($message['body'], '__toString')) {
return (string) $message['body'];
}
default:
throw new \InvalidArgumentException('Invalid request body: '
. self::describeType($message['body']));
}
}








public static function rewindBody($message)
{
if ($message['body'] instanceof StreamInterface) {
return $message['body']->seek(0);
}

if ($message['body'] instanceof \Generator) {
return false;
}

if ($message['body'] instanceof \Iterator) {
$message['body']->rewind();
return true;
}

if (is_resource($message['body'])) {
return rewind($message['body']);
}

return is_string($message['body'])
|| (is_object($message['body'])
&& method_exists($message['body'], '__toString'));
}









public static function describeType($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()));
}
}










public static function doSleep(array $request)
{
if (isset($request['client']['delay'])) {
usleep($request['client']['delay'] * 1000);
}
}












public static function proxy(
FutureArrayInterface $future,
callable $onFulfilled = null,
callable $onRejected = null,
callable $onProgress = null
) {
return new FutureArray(
$future->then($onFulfilled, $onRejected, $onProgress),
[$future, 'wait'],
[$future, 'cancel']
);
}








public static function getDebugResource($value = null)
{
if (is_resource($value)) {
return $value;
} elseif (defined('STDOUT')) {
return STDOUT;
} else {
return fopen('php://output', 'w');
}
}
}
<?php
namespace GuzzleHttp\Ring\Exception;

class RingException extends \RuntimeException {};
<?php
namespace GuzzleHttp\Ring\Exception;




interface CancelledException {}
<?php
namespace GuzzleHttp\Ring\Exception;




class ConnectException extends RingException {}
<?php
namespace GuzzleHttp\Ring\Exception;

class CancelledFutureAccessException extends RingException implements CancelledException {}
<?php
namespace GuzzleHttp\Stream;



















class AsyncReadStream implements StreamInterface
{
use StreamDecoratorTrait;


private $drain;


private $pump;


private $hwm;


private $needsDrain;


private $size;




























public function __construct(
StreamInterface $buffer,
array $config = []
) {
if (!$buffer->isReadable() || !$buffer->isWritable()) {
throw new \InvalidArgumentException(
'Buffer must be readable and writable'
);
}

if (isset($config['size'])) {
$this->size = $config['size'];
}

static $callables = ['pump', 'drain'];
foreach ($callables as $check) {
if (isset($config[$check])) {
if (!is_callable($config[$check])) {
throw new \InvalidArgumentException(
$check . ' must be callable'
);
}
$this->{$check} = $config[$check];
}
}

$this->hwm = $buffer->getMetadata('hwm');


 if ($this->hwm === null) {
$this->drain = null;
}

$this->stream = $buffer;
}





























public static function create(array $options = [])
{
$maxBuffer = isset($options['max_buffer'])
? $options['max_buffer']
: null;

if ($maxBuffer === 0) {
$buffer = new NullStream();
} elseif (isset($options['buffer'])) {
$buffer = $options['buffer'];
} else {
$hwm = isset($options['hwm']) ? $options['hwm'] : 16384;
$buffer = new BufferStream($hwm);
}

if ($maxBuffer > 0) {
$buffer = new DroppingStream($buffer, $options['max_buffer']);
}


 if (isset($options['write'])) {
$onWrite = $options['write'];
$buffer = FnStream::decorate($buffer, [
'write' => function ($string) use ($buffer, $onWrite) {
$result = $buffer->write($string);
$onWrite($buffer, $string);
return $result;
}
]);
}

return [$buffer, new self($buffer, $options)];
}

public function getSize()
{
return $this->size;
}

public function isWritable()
{
return false;
}

public function write($string)
{
return false;
}

public function read($length)
{
if (!$this->needsDrain && $this->drain) {
$this->needsDrain = $this->stream->getSize() >= $this->hwm;
}

$result = $this->stream->read($length);


 if ($this->needsDrain && $this->stream->getSize() === 0) {
$this->needsDrain = false;
$drainFn = $this->drain;
$drainFn($this->stream);
}

$resultLen = strlen($result);


 
 if ($this->pump && $resultLen < $length) {
$pumpFn = $this->pump;
$result .= $pumpFn($length - $resultLen);
}

return $result;
}
}
<?php
namespace GuzzleHttp\Stream;





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 false;
}


 if (strlen($string) < $diff) {
return $this->stream->write($string);
}

$this->stream->write(substr($string, 0, $diff));

return false;
}
}
<?php
namespace GuzzleHttp\Stream;
use GuzzleHttp\Stream\Exception\CannotAttachException;





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 {
$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(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 attach($stream)
{
throw new CannotAttachException();
}

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 seek($offset, $whence = SEEK_SET)
{
return $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('createStream() not implemented in '
. get_class($this));
}
}
<?php
namespace GuzzleHttp\Stream;

use GuzzleHttp\Stream\Exception\SeekException;




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;
}

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

return $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) {
return false;
}

$offset += $this->offset;

if ($this->limit !== -1) {
if ($offset > $this->offset + $this->limit) {
$offset = $this->offset + $this->limit;
}
}

return $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->seek($offset)) {
if ($current > $offset) {
throw new SeekException($this, $offset);
} else {
$this->stream->read($offset - $current);
}
}
}

$this->offset = $offset;

return $this;
}









public function setLimit($limit)
{
$this->limit = $limit;

return $this;
}

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));
} else {
return false;
}
}
}
<?php
namespace GuzzleHttp\Stream;




interface StreamInterface
{








public function __toString();




public function close();













public function detach();
















public function attach($stream);






public function getSize();






public function tell();






public function eof();






public function isSeekable();















public function seek($offset, $whence = SEEK_SET);






public function isWritable();










public function write($string);






public function isReadable();










public function read($length);








public function getContents();















public function getMetadata($key = null);
}
<?php
namespace GuzzleHttp\Stream;




class Stream implements StreamInterface
{
private $stream;
private $size;
private $seekable;
private $readable;
private $writable;
private $uri;
private $customMetadata;


private static $readWriteHash = [
'read' => [
'r' => true, 'w+' => true, 'r+' => true, 'x+' => true, 'c+' => true,
'rb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true,
'c+b' => true, 'rt' => true, 'w+t' => true, 'r+t' => true,
'x+t' => true, 'c+t' => true, 'a+' => true
],
'write' => [
'w' => true, 'w+' => true, 'rw' => true, 'r+' => true, 'x+' => true,
'c+' => true, 'wb' => true, 'w+b' => true, 'r+b' => true,
'x+b' => true, 'c+b' => true, 'w+t' => true, 'r+t' => true,
'x+t' => true, 'c+t' => true, 'a' => true, 'a+' => true
]
];













public static function factory($resource = '', array $options = [])
{
$type = gettype($resource);

if ($type == 'string') {
$stream = fopen('php://temp', 'r+');
if ($resource !== '') {
fwrite($stream, $resource);
fseek($stream, 0);
}
return new self($stream, $options);
}

if ($type == 'resource') {
return new self($resource, $options);
}

if ($resource instanceof StreamInterface) {
return $resource;
}

if ($type == 'object' && method_exists($resource, '__toString')) {
return self::factory((string) $resource, $options);
}

if (is_callable($resource)) {
return new PumpStream($resource, $options);
}

if ($resource instanceof \Iterator) {
return new PumpStream(function () use ($resource) {
if (!$resource->valid()) {
return false;
}
$result = $resource->current();
$resource->next();
return $result;
}, $options);
}

throw new \InvalidArgumentException('Invalid resource type: ' . $type);
}















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->attach($stream);
}




public function __destruct()
{
$this->close();
}

public function __toString()
{
if (!$this->stream) {
return '';
}

$this->seek(0);

return (string) stream_get_contents($this->stream);
}

public function getContents()
{
return $this->stream ? stream_get_contents($this->stream) : '';
}

public function close()
{
if (is_resource($this->stream)) {
fclose($this->stream);
}

$this->detach();
}

public function detach()
{
$result = $this->stream;
$this->stream = $this->size = $this->uri = null;
$this->readable = $this->writable = $this->seekable = false;

return $result;
}

public function attach($stream)
{
$this->stream = $stream;
$meta = stream_get_meta_data($this->stream);
$this->seekable = $meta['seekable'];
$this->readable = isset(self::$readWriteHash['read'][$meta['mode']]);
$this->writable = isset(self::$readWriteHash['write'][$meta['mode']]);
$this->uri = $this->getMetadata('uri');
}

public function getSize()
{
if ($this->size !== null) {
return $this->size;
}

if (!$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()
{
return !$this->stream || feof($this->stream);
}

public function tell()
{
return $this->stream ? ftell($this->stream) : false;
}

public function setSize($size)
{
$this->size = $size;

return $this;
}

public function seek($offset, $whence = SEEK_SET)
{
return $this->seekable
? fseek($this->stream, $offset, $whence) === 0
: false;
}

public function read($length)
{
return $this->readable ? fread($this->stream, $length) : false;
}

public function write($string)
{

 $this->size = null;

return $this->writable ? fwrite($this->stream, $string) : false;
}

public function getMetadata($key = null)
{
if (!$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\Stream;












class InflateStream implements StreamInterface
{
use StreamDecoratorTrait;

public function __construct(StreamInterface $stream)
{

 $stream = new LimitStream($stream, -1, 10);
$resource = GuzzleStreamWrapper::getResource($stream);
stream_filter_append($resource, 'zlib.inflate', STREAM_FILTER_READ);
$this->stream = new Stream($resource);
}
}
<?php
namespace GuzzleHttp\Stream;

use GuzzleHttp\Stream\Exception\CannotAttachException;











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()
{
return Utils::copyToString($this);
}

public function close()
{
$this->detach();
}

public function detach()
{
$this->tellPos = false;
$this->source = null;
}

public function attach($stream)
{
throw new CannotAttachException();
}

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 seek($offset, $whence = SEEK_SET)
{
return false;
}

public function isWritable()
{
return false;
}

public function write($string)
{
return false;
}

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
namespace GuzzleHttp\Stream;

use GuzzleHttp\Stream\Exception\SeekException;





class Utils
{












public static function open($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]
));
});

$handle = fopen($filename, $mode);
restore_error_handler();

if ($ex) {

throw $ex;
}

return $handle;
}










public static function copyToString(StreamInterface $stream, $maxLen = -1)
{
$buffer = '';

if ($maxLen === -1) {
while (!$stream->eof()) {
$buf = $stream->read(1048576);
if ($buf === false) {
break;
}
$buffer .= $buf;
}
return $buffer;
}

$len = 0;
while (!$stream->eof() && $len < $maxLen) {
$buf = $stream->read($maxLen - $len);
if ($buf === false) {
break;
}
$buffer .= $buf;
$len = strlen($buffer);
}

return $buffer;
}










public static function copyToStream(
StreamInterface $source,
StreamInterface $dest,
$maxLen = -1
) {
if ($maxLen === -1) {
while (!$source->eof()) {
if (!$dest->write($source->read(1048576))) {
break;
}
}
return;
}

$bytes = 0;
while (!$source->eof()) {
$buf = $source->read($maxLen - $bytes);
if (!($len = strlen($buf))) {
break;
}
$bytes += $len;
$dest->write($buf);
if ($bytes == $maxLen) {
break;
}
}
}











public static function hash(
StreamInterface $stream,
$algo,
$rawOutput = false
) {
$pos = $stream->tell();

if ($pos > 0 && !$stream->seek(0)) {
throw new SeekException($stream);
}

$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 readline(StreamInterface $stream, $maxLength = null)
{
$buffer = '';
$size = 0;

while (!$stream->eof()) {
if (false === ($byte = $stream->read(1))) {
return $buffer;
}
$buffer .= $byte;

 if ($byte == PHP_EOL || ++$size == $maxLength - 1) {
break;
}
}

return $buffer;
}













public static function create($resource, array $options = [])
{
return Stream::factory($resource, $options);
}
}
<?php
namespace GuzzleHttp\Stream;





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 Stream::factory(Utils::open($this->filename, $this->mode));
}
}
<?php
namespace GuzzleHttp\Stream;

use GuzzleHttp\Stream\Exception\SeekException;





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(fopen('php://temp', 'r+'));
}

public function getSize()
{
return max($this->stream->getSize(), $this->remoteStream->getSize());
}






public function seek($offset, $whence = SEEK_SET)
{
if ($whence == SEEK_SET) {
$byte = $offset;
} elseif ($whence == SEEK_CUR) {
$byte = $offset + $this->tell();
} else {
return false;
}


 if ($byte > $this->stream->getSize()) {
throw new SeekException(
$this,
$byte,
sprintf('Cannot seek to byte %d when the buffered stream only'
. ' contains %d bytes', $byte, $this->stream->getSize())
);
}

return $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();
}
}
<?php
namespace GuzzleHttp\Stream;








interface MetadataStreamInterface extends StreamInterface {}
<?php
namespace GuzzleHttp\Stream;
use GuzzleHttp\Stream\Exception\CannotAttachException;




class NullStream implements StreamInterface
{
public function __toString()
{
return '';
}

public function getContents()
{
return '';
}

public function close() {}

public function detach() {}

public function attach($stream)
{
throw new CannotAttachException();
}

public function getSize()
{
return 0;
}

public function isReadable()
{
return true;
}

public function isWritable()
{
return true;
}

public function isSeekable()
{
return true;
}

public function eof()
{
return true;
}

public function tell()
{
return 0;
}

public function seek($offset, $whence = SEEK_SET)
{
return false;
}

public function read($length)
{
return false;
}

public function write($string)
{
return strlen($string);
}

public function getMetadata($key = null)
{
return $key ? null : [];
}
}
<?php
namespace GuzzleHttp\Stream\Exception;

use GuzzleHttp\Stream\StreamInterface;




class SeekException extends \RuntimeException
{
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\Stream\Exception;

class CannotAttachException extends \RuntimeException {}
<?php
namespace GuzzleHttp\Stream;




class GuzzleStreamWrapper
{

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, 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)
{
return $this->stream->seek($offset, $whence);
}

public function stream_stat()
{
static $modeMap = [
'r' => 33060,
'r+' => 33206,
'w' => 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
];
}
}
<?php
namespace GuzzleHttp\Stream;




class NoSeekStream implements StreamInterface
{
use StreamDecoratorTrait;

public function seek($offset, $whence = SEEK_SET)
{
return false;
}

public function isSeekable()
{
return false;
}

public function attach($stream)
{
$this->stream->attach($stream);
}
}
<?php
namespace GuzzleHttp\Stream;

use GuzzleHttp\Stream\Exception\CannotAttachException;






class AppendStream implements StreamInterface
{

private $streams = [];

private $seekable = true;
private $current = 0;
private $pos = 0;
private $detached = false;





public function __construct(array $streams = [])
{
foreach ($streams as $stream) {
$this->addStream($stream);
}
}

public function __toString()
{
try {
$this->seek(0);
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;

foreach ($this->streams as $stream) {
$stream->close();
}

$this->streams = [];
}






public function detach()
{
$this->close();
$this->detached = true;
}

public function attach($stream)
{
throw new CannotAttachException();
}

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 seek($offset, $whence = SEEK_SET)
{
if (!$this->seekable || $whence !== SEEK_SET) {
return false;
}

$success = true;
$this->pos = $this->current = 0;


 foreach ($this->streams as $stream) {
if (!$stream->seek(0)) {
$success = false;
}
}

if (!$success) {
return false;
}


 while ($this->pos < $offset && !$this->eof()) {
$this->read(min(8096, $offset - $this->pos));
}

return $this->pos == $offset;
}






public function read($length)
{
$buffer = '';
$total = count($this->streams) - 1;
$remaining = $length;

while ($remaining > 0) {

 if ($this->streams[$this->current]->eof()) {
if ($this->current == $total) {
break;
}
$this->current++;
}
$buffer .= $this->streams[$this->current]->read($remaining);
$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)
{
return false;
}

public function getMetadata($key = null)
{
return $key ? null : [];
}
}
<?php
namespace GuzzleHttp\Stream;

use GuzzleHttp\Stream\Exception\CannotAttachException;











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();
}

public function attach($stream)
{
throw new CannotAttachException();
}

public function getSize()
{
return strlen($this->buffer);
}

public function isReadable()
{
return true;
}

public function isWritable()
{
return true;
}

public function isSeekable()
{
return false;
}

public function seek($offset, $whence = SEEK_SET)
{
return false;
}

public function eof()
{
return strlen($this->buffer) === 0;
}

public function tell()
{
return false;
}




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\Stream;







class FnStream implements StreamInterface
{

private $methods;


private static $slots = ['__toString', 'close', 'detach', 'attach',
'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 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 attach($stream)
{
return call_user_func($this->_fn_attach, $stream);
}

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 seek($offset, $whence = SEEK_SET)
{
return 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;





class Mimetypes
{

protected static $instance;


protected $mimetypes = array(
'3dml' => 'text/vnd.in3d.3dml',
'3g2' => 'video/3gpp2',
'3gp' => 'video/3gpp',
'7z' => 'application/x-7z-compressed',
'aab' => 'application/x-authorware-bin',
'aac' => 'audio/x-aac',
'aam' => 'application/x-authorware-map',
'aas' => 'application/x-authorware-seg',
'abw' => 'application/x-abiword',
'ac' => 'application/pkix-attr-cert',
'acc' => 'application/vnd.americandynamics.acc',
'ace' => 'application/x-ace-compressed',
'acu' => 'application/vnd.acucobol',
'acutc' => 'application/vnd.acucorp',
'adp' => 'audio/adpcm',
'aep' => 'application/vnd.audiograph',
'afm' => 'application/x-font-type1',
'afp' => 'application/vnd.ibm.modcap',
'ahead' => 'application/vnd.ahead.space',
'ai' => 'application/postscript',
'aif' => 'audio/x-aiff',
'aifc' => 'audio/x-aiff',
'aiff' => 'audio/x-aiff',
'air' => 'application/vnd.adobe.air-application-installer-package+zip',
'ait' => 'application/vnd.dvb.ait',
'ami' => 'application/vnd.amiga.ami',
'apk' => 'application/vnd.android.package-archive',
'application' => 'application/x-ms-application',
'apr' => 'application/vnd.lotus-approach',
'asa' => 'text/plain',
'asax' => 'application/octet-stream',
'asc' => 'application/pgp-signature',
'ascx' => 'text/plain',
'asf' => 'video/x-ms-asf',
'ashx' => 'text/plain',
'asm' => 'text/x-asm',
'asmx' => 'text/plain',
'aso' => 'application/vnd.accpac.simply.aso',
'asp' => 'text/plain',
'aspx' => 'text/plain',
'asx' => 'video/x-ms-asf',
'atc' => 'application/vnd.acucorp',
'atom' => 'application/atom+xml',
'atomcat' => 'application/atomcat+xml',
'atomsvc' => 'application/atomsvc+xml',
'atx' => 'application/vnd.antix.game-component',
'au' => 'audio/basic',
'avi' => 'video/x-msvideo',
'aw' => 'application/applixware',
'axd' => 'text/plain',
'azf' => 'application/vnd.airzip.filesecure.azf',
'azs' => 'application/vnd.airzip.filesecure.azs',
'azw' => 'application/vnd.amazon.ebook',
'bat' => 'application/x-msdownload',
'bcpio' => 'application/x-bcpio',
'bdf' => 'application/x-font-bdf',
'bdm' => 'application/vnd.syncml.dm+wbxml',
'bed' => 'application/vnd.realvnc.bed',
'bh2' => 'application/vnd.fujitsu.oasysprs',
'bin' => 'application/octet-stream',
'bmi' => 'application/vnd.bmi',
'bmp' => 'image/bmp',
'book' => 'application/vnd.framemaker',
'box' => 'application/vnd.previewsystems.box',
'boz' => 'application/x-bzip2',
'bpk' => 'application/octet-stream',
'btif' => 'image/prs.btif',
'bz' => 'application/x-bzip',
'bz2' => 'application/x-bzip2',
'c' => 'text/x-c',
'c11amc' => 'application/vnd.cluetrust.cartomobile-config',
'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg',
'c4d' => 'application/vnd.clonk.c4group',
'c4f' => 'application/vnd.clonk.c4group',
'c4g' => 'application/vnd.clonk.c4group',
'c4p' => 'application/vnd.clonk.c4group',
'c4u' => 'application/vnd.clonk.c4group',
'cab' => 'application/vnd.ms-cab-compressed',
'car' => 'application/vnd.curl.car',
'cat' => 'application/vnd.ms-pki.seccat',
'cc' => 'text/x-c',
'cct' => 'application/x-director',
'ccxml' => 'application/ccxml+xml',
'cdbcmsg' => 'application/vnd.contact.cmsg',
'cdf' => 'application/x-netcdf',
'cdkey' => 'application/vnd.mediastation.cdkey',
'cdmia' => 'application/cdmi-capability',
'cdmic' => 'application/cdmi-container',
'cdmid' => 'application/cdmi-domain',
'cdmio' => 'application/cdmi-object',
'cdmiq' => 'application/cdmi-queue',
'cdx' => 'chemical/x-cdx',
'cdxml' => 'application/vnd.chemdraw+xml',
'cdy' => 'application/vnd.cinderella',
'cer' => 'application/pkix-cert',
'cfc' => 'application/x-coldfusion',
'cfm' => 'application/x-coldfusion',
'cgm' => 'image/cgm',
'chat' => 'application/x-chat',
'chm' => 'application/vnd.ms-htmlhelp',
'chrt' => 'application/vnd.kde.kchart',
'cif' => 'chemical/x-cif',
'cii' => 'application/vnd.anser-web-certificate-issue-initiation',
'cil' => 'application/vnd.ms-artgalry',
'cla' => 'application/vnd.claymore',
'class' => 'application/java-vm',
'clkk' => 'application/vnd.crick.clicker.keyboard',
'clkp' => 'application/vnd.crick.clicker.palette',
'clkt' => 'application/vnd.crick.clicker.template',
'clkw' => 'application/vnd.crick.clicker.wordbank',
'clkx' => 'application/vnd.crick.clicker',
'clp' => 'application/x-msclip',
'cmc' => 'application/vnd.cosmocaller',
'cmdf' => 'chemical/x-cmdf',
'cml' => 'chemical/x-cml',
'cmp' => 'application/vnd.yellowriver-custom-menu',
'cmx' => 'image/x-cmx',
'cod' => 'application/vnd.rim.cod',
'com' => 'application/x-msdownload',
'conf' => 'text/plain',
'cpio' => 'application/x-cpio',
'cpp' => 'text/x-c',
'cpt' => 'application/mac-compactpro',
'crd' => 'application/x-mscardfile',
'crl' => 'application/pkix-crl',
'crt' => 'application/x-x509-ca-cert',
'cryptonote' => 'application/vnd.rig.cryptonote',
'cs' => 'text/plain',
'csh' => 'application/x-csh',
'csml' => 'chemical/x-csml',
'csp' => 'application/vnd.commonspace',
'css' => 'text/css',
'cst' => 'application/x-director',
'csv' => 'text/csv',
'cu' => 'application/cu-seeme',
'curl' => 'text/vnd.curl',
'cww' => 'application/prs.cww',
'cxt' => 'application/x-director',
'cxx' => 'text/x-c',
'dae' => 'model/vnd.collada+xml',
'daf' => 'application/vnd.mobius.daf',
'dataless' => 'application/vnd.fdsn.seed',
'davmount' => 'application/davmount+xml',
'dcr' => 'application/x-director',
'dcurl' => 'text/vnd.curl.dcurl',
'dd2' => 'application/vnd.oma.dd2+xml',
'ddd' => 'application/vnd.fujixerox.ddd',
'deb' => 'application/x-debian-package',
'def' => 'text/plain',
'deploy' => 'application/octet-stream',
'der' => 'application/x-x509-ca-cert',
'dfac' => 'application/vnd.dreamfactory',
'dic' => 'text/x-c',
'dir' => 'application/x-director',
'dis' => 'application/vnd.mobius.dis',
'dist' => 'application/octet-stream',
'distz' => 'application/octet-stream',
'djv' => 'image/vnd.djvu',
'djvu' => 'image/vnd.djvu',
'dll' => 'application/x-msdownload',
'dmg' => 'application/octet-stream',
'dms' => 'application/octet-stream',
'dna' => 'application/vnd.dna',
'doc' => 'application/msword',
'docm' => 'application/vnd.ms-word.document.macroenabled.12',
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'dot' => 'application/msword',
'dotm' => 'application/vnd.ms-word.template.macroenabled.12',
'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
'dp' => 'application/vnd.osgi.dp',
'dpg' => 'application/vnd.dpgraph',
'dra' => 'audio/vnd.dra',
'dsc' => 'text/prs.lines.tag',
'dssc' => 'application/dssc+der',
'dtb' => 'application/x-dtbook+xml',
'dtd' => 'application/xml-dtd',
'dts' => 'audio/vnd.dts',
'dtshd' => 'audio/vnd.dts.hd',
'dump' => 'application/octet-stream',
'dvi' => 'application/x-dvi',
'dwf' => 'model/vnd.dwf',
'dwg' => 'image/vnd.dwg',
'dxf' => 'image/vnd.dxf',
'dxp' => 'application/vnd.spotfire.dxp',
'dxr' => 'application/x-director',
'ecelp4800' => 'audio/vnd.nuera.ecelp4800',
'ecelp7470' => 'audio/vnd.nuera.ecelp7470',
'ecelp9600' => 'audio/vnd.nuera.ecelp9600',
'ecma' => 'application/ecmascript',
'edm' => 'application/vnd.novadigm.edm',
'edx' => 'application/vnd.novadigm.edx',
'efif' => 'application/vnd.picsel',
'ei6' => 'application/vnd.pg.osasli',
'elc' => 'application/octet-stream',
'eml' => 'message/rfc822',
'emma' => 'application/emma+xml',
'eol' => 'audio/vnd.digital-winds',
'eot' => 'application/vnd.ms-fontobject',
'eps' => 'application/postscript',
'epub' => 'application/epub+zip',
'es3' => 'application/vnd.eszigno3+xml',
'esf' => 'application/vnd.epson.esf',
'et3' => 'application/vnd.eszigno3+xml',
'etx' => 'text/x-setext',
'exe' => 'application/x-msdownload',
'exi' => 'application/exi',
'ext' => 'application/vnd.novadigm.ext',
'ez' => 'application/andrew-inset',
'ez2' => 'application/vnd.ezpix-album',
'ez3' => 'application/vnd.ezpix-package',
'f' => 'text/x-fortran',
'f4v' => 'video/x-f4v',
'f77' => 'text/x-fortran',
'f90' => 'text/x-fortran',
'fbs' => 'image/vnd.fastbidsheet',
'fcs' => 'application/vnd.isac.fcs',
'fdf' => 'application/vnd.fdf',
'fe_launch' => 'application/vnd.denovo.fcselayout-link',
'fg5' => 'application/vnd.fujitsu.oasysgp',
'fgd' => 'application/x-director',
'fh' => 'image/x-freehand',
'fh4' => 'image/x-freehand',
'fh5' => 'image/x-freehand',
'fh7' => 'image/x-freehand',
'fhc' => 'image/x-freehand',
'fig' => 'application/x-xfig',
'fli' => 'video/x-fli',
'flo' => 'application/vnd.micrografx.flo',
'flv' => 'video/x-flv',
'flw' => 'application/vnd.kde.kivio',
'flx' => 'text/vnd.fmi.flexstor',
'fly' => 'text/vnd.fly',
'fm' => 'application/vnd.framemaker',
'fnc' => 'application/vnd.frogans.fnc',
'for' => 'text/x-fortran',
'fpx' => 'image/vnd.fpx',
'frame' => 'application/vnd.framemaker',
'fsc' => 'application/vnd.fsc.weblaunch',
'fst' => 'image/vnd.fst',
'ftc' => 'application/vnd.fluxtime.clip',
'fti' => 'application/vnd.anser-web-funds-transfer-initiation',
'fvt' => 'video/vnd.fvt',
'fxp' => 'application/vnd.adobe.fxp',
'fxpl' => 'application/vnd.adobe.fxp',
'fzs' => 'application/vnd.fuzzysheet',
'g2w' => 'application/vnd.geoplan',
'g3' => 'image/g3fax',
'g3w' => 'application/vnd.geospace',
'gac' => 'application/vnd.groove-account',
'gdl' => 'model/vnd.gdl',
'geo' => 'application/vnd.dynageo',
'gex' => 'application/vnd.geometry-explorer',
'ggb' => 'application/vnd.geogebra.file',
'ggt' => 'application/vnd.geogebra.tool',
'ghf' => 'application/vnd.groove-help',
'gif' => 'image/gif',
'gim' => 'application/vnd.groove-identity-message',
'gmx' => 'application/vnd.gmx',
'gnumeric' => 'application/x-gnumeric',
'gph' => 'application/vnd.flographit',
'gqf' => 'application/vnd.grafeq',
'gqs' => 'application/vnd.grafeq',
'gram' => 'application/srgs',
'gre' => 'application/vnd.geometry-explorer',
'grv' => 'application/vnd.groove-injector',
'grxml' => 'application/srgs+xml',
'gsf' => 'application/x-font-ghostscript',
'gtar' => 'application/x-gtar',
'gtm' => 'application/vnd.groove-tool-message',
'gtw' => 'model/vnd.gtw',
'gv' => 'text/vnd.graphviz',
'gxt' => 'application/vnd.geonext',
'h' => 'text/x-c',
'h261' => 'video/h261',
'h263' => 'video/h263',
'h264' => 'video/h264',
'hal' => 'application/vnd.hal+xml',
'hbci' => 'application/vnd.hbci',
'hdf' => 'application/x-hdf',
'hh' => 'text/x-c',
'hlp' => 'application/winhlp',
'hpgl' => 'application/vnd.hp-hpgl',
'hpid' => 'application/vnd.hp-hpid',
'hps' => 'application/vnd.hp-hps',
'hqx' => 'application/mac-binhex40',
'hta' => 'application/octet-stream',
'htc' => 'text/html',
'htke' => 'application/vnd.kenameaapp',
'htm' => 'text/html',
'html' => 'text/html',
'hvd' => 'application/vnd.yamaha.hv-dic',
'hvp' => 'application/vnd.yamaha.hv-voice',
'hvs' => 'application/vnd.yamaha.hv-script',
'i2g' => 'application/vnd.intergeo',
'icc' => 'application/vnd.iccprofile',
'ice' => 'x-conference/x-cooltalk',
'icm' => 'application/vnd.iccprofile',
'ico' => 'image/x-icon',
'ics' => 'text/calendar',
'ief' => 'image/ief',
'ifb' => 'text/calendar',
'ifm' => 'application/vnd.shana.informed.formdata',
'iges' => 'model/iges',
'igl' => 'application/vnd.igloader',
'igm' => 'application/vnd.insors.igm',
'igs' => 'model/iges',
'igx' => 'application/vnd.micrografx.igx',
'iif' => 'application/vnd.shana.informed.interchange',
'imp' => 'application/vnd.accpac.simply.imp',
'ims' => 'application/vnd.ms-ims',
'in' => 'text/plain',
'ini' => 'text/plain',
'ipfix' => 'application/ipfix',
'ipk' => 'application/vnd.shana.informed.package',
'irm' => 'application/vnd.ibm.rights-management',
'irp' => 'application/vnd.irepository.package+xml',
'iso' => 'application/octet-stream',
'itp' => 'application/vnd.shana.informed.formtemplate',
'ivp' => 'application/vnd.immervision-ivp',
'ivu' => 'application/vnd.immervision-ivu',
'jad' => 'text/vnd.sun.j2me.app-descriptor',
'jam' => 'application/vnd.jam',
'jar' => 'application/java-archive',
'java' => 'text/x-java-source',
'jisp' => 'application/vnd.jisp',
'jlt' => 'application/vnd.hp-jlyt',
'jnlp' => 'application/x-java-jnlp-file',
'joda' => 'application/vnd.joost.joda-archive',
'jpe' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'jpg' => 'image/jpeg',
'jpgm' => 'video/jpm',
'jpgv' => 'video/jpeg',
'jpm' => 'video/jpm',
'js' => 'text/javascript',
'json' => 'application/json',
'kar' => 'audio/midi',
'karbon' => 'application/vnd.kde.karbon',
'kfo' => 'application/vnd.kde.kformula',
'kia' => 'application/vnd.kidspiration',
'kml' => 'application/vnd.google-earth.kml+xml',
'kmz' => 'application/vnd.google-earth.kmz',
'kne' => 'application/vnd.kinar',
'knp' => 'application/vnd.kinar',
'kon' => 'application/vnd.kde.kontour',
'kpr' => 'application/vnd.kde.kpresenter',
'kpt' => 'application/vnd.kde.kpresenter',
'ksp' => 'application/vnd.kde.kspread',
'ktr' => 'application/vnd.kahootz',
'ktx' => 'image/ktx',
'ktz' => 'application/vnd.kahootz',
'kwd' => 'application/vnd.kde.kword',
'kwt' => 'application/vnd.kde.kword',
'lasxml' => 'application/vnd.las.las+xml',
'latex' => 'application/x-latex',
'lbd' => 'application/vnd.llamagraphics.life-balance.desktop',
'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml',
'les' => 'application/vnd.hhe.lesson-player',
'lha' => 'application/octet-stream',
'link66' => 'application/vnd.route66.link66+xml',
'list' => 'text/plain',
'list3820' => 'application/vnd.ibm.modcap',
'listafp' => 'application/vnd.ibm.modcap',
'log' => 'text/plain',
'lostxml' => 'application/lost+xml',
'lrf' => 'application/octet-stream',
'lrm' => 'application/vnd.ms-lrm',
'ltf' => 'application/vnd.frogans.ltf',
'lvp' => 'audio/vnd.lucent.voice',
'lwp' => 'application/vnd.lotus-wordpro',
'lzh' => 'application/octet-stream',
'm13' => 'application/x-msmediaview',
'm14' => 'application/x-msmediaview',
'm1v' => 'video/mpeg',
'm21' => 'application/mp21',
'm2a' => 'audio/mpeg',
'm2v' => 'video/mpeg',
'm3a' => 'audio/mpeg',
'm3u' => 'audio/x-mpegurl',
'm3u8' => 'application/vnd.apple.mpegurl',
'm4a' => 'audio/mp4',
'm4u' => 'video/vnd.mpegurl',
'm4v' => 'video/mp4',
'ma' => 'application/mathematica',
'mads' => 'application/mads+xml',
'mag' => 'application/vnd.ecowin.chart',
'maker' => 'application/vnd.framemaker',
'man' => 'text/troff',
'mathml' => 'application/mathml+xml',
'mb' => 'application/mathematica',
'mbk' => 'application/vnd.mobius.mbk',
'mbox' => 'application/mbox',
'mc1' => 'application/vnd.medcalcdata',
'mcd' => 'application/vnd.mcd',
'mcurl' => 'text/vnd.curl.mcurl',
'mdb' => 'application/x-msaccess',
'mdi' => 'image/vnd.ms-modi',
'me' => 'text/troff',
'mesh' => 'model/mesh',
'meta4' => 'application/metalink4+xml',
'mets' => 'application/mets+xml',
'mfm' => 'application/vnd.mfmp',
'mgp' => 'application/vnd.osgeo.mapguide.package',
'mgz' => 'application/vnd.proteus.magazine',
'mid' => 'audio/midi',
'midi' => 'audio/midi',
'mif' => 'application/vnd.mif',
'mime' => 'message/rfc822',
'mj2' => 'video/mj2',
'mjp2' => 'video/mj2',
'mlp' => 'application/vnd.dolby.mlp',
'mmd' => 'application/vnd.chipnuts.karaoke-mmd',
'mmf' => 'application/vnd.smaf',
'mmr' => 'image/vnd.fujixerox.edmics-mmr',
'mny' => 'application/x-msmoney',
'mobi' => 'application/x-mobipocket-ebook',
'mods' => 'application/mods+xml',
'mov' => 'video/quicktime',
'movie' => 'video/x-sgi-movie',
'mp2' => 'audio/mpeg',
'mp21' => 'application/mp21',
'mp2a' => 'audio/mpeg',
'mp3' => 'audio/mpeg',
'mp4' => 'video/mp4',
'mp4a' => 'audio/mp4',
'mp4s' => 'application/mp4',
'mp4v' => 'video/mp4',
'mpc' => 'application/vnd.mophun.certificate',
'mpe' => 'video/mpeg',
'mpeg' => 'video/mpeg',
'mpg' => 'video/mpeg',
'mpg4' => 'video/mp4',
'mpga' => 'audio/mpeg',
'mpkg' => 'application/vnd.apple.installer+xml',
'mpm' => 'application/vnd.blueice.multipass',
'mpn' => 'application/vnd.mophun.application',
'mpp' => 'application/vnd.ms-project',
'mpt' => 'application/vnd.ms-project',
'mpy' => 'application/vnd.ibm.minipay',
'mqy' => 'application/vnd.mobius.mqy',
'mrc' => 'application/marc',
'mrcx' => 'application/marcxml+xml',
'ms' => 'text/troff',
'mscml' => 'application/mediaservercontrol+xml',
'mseed' => 'application/vnd.fdsn.mseed',
'mseq' => 'application/vnd.mseq',
'msf' => 'application/vnd.epson.msf',
'msh' => 'model/mesh',
'msi' => 'application/x-msdownload',
'msl' => 'application/vnd.mobius.msl',
'msty' => 'application/vnd.muvee.style',
'mts' => 'model/vnd.mts',
'mus' => 'application/vnd.musician',
'musicxml' => 'application/vnd.recordare.musicxml+xml',
'mvb' => 'application/x-msmediaview',
'mwf' => 'application/vnd.mfer',
'mxf' => 'application/mxf',
'mxl' => 'application/vnd.recordare.musicxml',
'mxml' => 'application/xv+xml',
'mxs' => 'application/vnd.triscape.mxs',
'mxu' => 'video/vnd.mpegurl',
'n-gage' => 'application/vnd.nokia.n-gage.symbian.install',
'n3' => 'text/n3',
'nb' => 'application/mathematica',
'nbp' => 'application/vnd.wolfram.player',
'nc' => 'application/x-netcdf',
'ncx' => 'application/x-dtbncx+xml',
'ngdat' => 'application/vnd.nokia.n-gage.data',
'nlu' => 'application/vnd.neurolanguage.nlu',
'nml' => 'application/vnd.enliven',
'nnd' => 'application/vnd.noblenet-directory',
'nns' => 'application/vnd.noblenet-sealer',
'nnw' => 'application/vnd.noblenet-web',
'npx' => 'image/vnd.net-fpx',
'nsf' => 'application/vnd.lotus-notes',
'oa2' => 'application/vnd.fujitsu.oasys2',
'oa3' => 'application/vnd.fujitsu.oasys3',
'oas' => 'application/vnd.fujitsu.oasys',
'obd' => 'application/x-msbinder',
'oda' => 'application/oda',
'odb' => 'application/vnd.oasis.opendocument.database',
'odc' => 'application/vnd.oasis.opendocument.chart',
'odf' => 'application/vnd.oasis.opendocument.formula',
'odft' => 'application/vnd.oasis.opendocument.formula-template',
'odg' => 'application/vnd.oasis.opendocument.graphics',
'odi' => 'application/vnd.oasis.opendocument.image',
'odm' => 'application/vnd.oasis.opendocument.text-master',
'odp' => 'application/vnd.oasis.opendocument.presentation',
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
'odt' => 'application/vnd.oasis.opendocument.text',
'oga' => 'audio/ogg',
'ogg' => 'audio/ogg',
'ogv' => 'video/ogg',
'ogx' => 'application/ogg',
'onepkg' => 'application/onenote',
'onetmp' => 'application/onenote',
'onetoc' => 'application/onenote',
'onetoc2' => 'application/onenote',
'opf' => 'application/oebps-package+xml',
'oprc' => 'application/vnd.palm',
'org' => 'application/vnd.lotus-organizer',
'osf' => 'application/vnd.yamaha.openscoreformat',
'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml',
'otc' => 'application/vnd.oasis.opendocument.chart-template',
'otf' => 'application/x-font-otf',
'otg' => 'application/vnd.oasis.opendocument.graphics-template',
'oth' => 'application/vnd.oasis.opendocument.text-web',
'oti' => 'application/vnd.oasis.opendocument.image-template',
'otp' => 'application/vnd.oasis.opendocument.presentation-template',
'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
'ott' => 'application/vnd.oasis.opendocument.text-template',
'oxt' => 'application/vnd.openofficeorg.extension',
'p' => 'text/x-pascal',
'p10' => 'application/pkcs10',
'p12' => 'application/x-pkcs12',
'p7b' => 'application/x-pkcs7-certificates',
'p7c' => 'application/pkcs7-mime',
'p7m' => 'application/pkcs7-mime',
'p7r' => 'application/x-pkcs7-certreqresp',
'p7s' => 'application/pkcs7-signature',
'p8' => 'application/pkcs8',
'pas' => 'text/x-pascal',
'paw' => 'application/vnd.pawaafile',
'pbd' => 'application/vnd.powerbuilder6',
'pbm' => 'image/x-portable-bitmap',
'pcf' => 'application/x-font-pcf',
'pcl' => 'application/vnd.hp-pcl',
'pclxl' => 'application/vnd.hp-pclxl',
'pct' => 'image/x-pict',
'pcurl' => 'application/vnd.curl.pcurl',
'pcx' => 'image/x-pcx',
'pdb' => 'application/vnd.palm',
'pdf' => 'application/pdf',
'pfa' => 'application/x-font-type1',
'pfb' => 'application/x-font-type1',
'pfm' => 'application/x-font-type1',
'pfr' => 'application/font-tdpfr',
'pfx' => 'application/x-pkcs12',
'pgm' => 'image/x-portable-graymap',
'pgn' => 'application/x-chess-pgn',
'pgp' => 'application/pgp-encrypted',
'php' => 'text/x-php',
'phps' => 'application/x-httpd-phps',
'pic' => 'image/x-pict',
'pkg' => 'application/octet-stream',
'pki' => 'application/pkixcmp',
'pkipath' => 'application/pkix-pkipath',
'plb' => 'application/vnd.3gpp.pic-bw-large',
'plc' => 'application/vnd.mobius.plc',
'plf' => 'application/vnd.pocketlearn',
'pls' => 'application/pls+xml',
'pml' => 'application/vnd.ctc-posml',
'png' => 'image/png',
'pnm' => 'image/x-portable-anymap',
'portpkg' => 'application/vnd.macports.portpkg',
'pot' => 'application/vnd.ms-powerpoint',
'potm' => 'application/vnd.ms-powerpoint.template.macroenabled.12',
'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
'ppam' => 'application/vnd.ms-powerpoint.addin.macroenabled.12',
'ppd' => 'application/vnd.cups-ppd',
'ppm' => 'image/x-portable-pixmap',
'pps' => 'application/vnd.ms-powerpoint',
'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroenabled.12',
'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
'ppt' => 'application/vnd.ms-powerpoint',
'pptm' => 'application/vnd.ms-powerpoint.presentation.macroenabled.12',
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'pqa' => 'application/vnd.palm',
'prc' => 'application/x-mobipocket-ebook',
'pre' => 'application/vnd.lotus-freelance',
'prf' => 'application/pics-rules',
'ps' => 'application/postscript',
'psb' => 'application/vnd.3gpp.pic-bw-small',
'psd' => 'image/vnd.adobe.photoshop',
'psf' => 'application/x-font-linux-psf',
'pskcxml' => 'application/pskc+xml',
'ptid' => 'application/vnd.pvi.ptid1',
'pub' => 'application/x-mspublisher',
'pvb' => 'application/vnd.3gpp.pic-bw-var',
'pwn' => 'application/vnd.3m.post-it-notes',
'pya' => 'audio/vnd.ms-playready.media.pya',
'pyv' => 'video/vnd.ms-playready.media.pyv',
'qam' => 'application/vnd.epson.quickanime',
'qbo' => 'application/vnd.intu.qbo',
'qfx' => 'application/vnd.intu.qfx',
'qps' => 'application/vnd.publishare-delta-tree',
'qt' => 'video/quicktime',
'qwd' => 'application/vnd.quark.quarkxpress',
'qwt' => 'application/vnd.quark.quarkxpress',
'qxb' => 'application/vnd.quark.quarkxpress',
'qxd' => 'application/vnd.quark.quarkxpress',
'qxl' => 'application/vnd.quark.quarkxpress',
'qxt' => 'application/vnd.quark.quarkxpress',
'ra' => 'audio/x-pn-realaudio',
'ram' => 'audio/x-pn-realaudio',
'rar' => 'application/x-rar-compressed',
'ras' => 'image/x-cmu-raster',
'rb' => 'text/plain',
'rcprofile' => 'application/vnd.ipunplugged.rcprofile',
'rdf' => 'application/rdf+xml',
'rdz' => 'application/vnd.data-vision.rdz',
'rep' => 'application/vnd.businessobjects',
'res' => 'application/x-dtbresource+xml',
'resx' => 'text/xml',
'rgb' => 'image/x-rgb',
'rif' => 'application/reginfo+xml',
'rip' => 'audio/vnd.rip',
'rl' => 'application/resource-lists+xml',
'rlc' => 'image/vnd.fujixerox.edmics-rlc',
'rld' => 'application/resource-lists-diff+xml',
'rm' => 'application/vnd.rn-realmedia',
'rmi' => 'audio/midi',
'rmp' => 'audio/x-pn-realaudio-plugin',
'rms' => 'application/vnd.jcp.javame.midlet-rms',
'rnc' => 'application/relax-ng-compact-syntax',
'roff' => 'text/troff',
'rp9' => 'application/vnd.cloanto.rp9',
'rpss' => 'application/vnd.nokia.radio-presets',
'rpst' => 'application/vnd.nokia.radio-preset',
'rq' => 'application/sparql-query',
'rs' => 'application/rls-services+xml',
'rsd' => 'application/rsd+xml',
'rss' => 'application/rss+xml',
'rtf' => 'application/rtf',
'rtx' => 'text/richtext',
's' => 'text/x-asm',
'saf' => 'application/vnd.yamaha.smaf-audio',
'sbml' => 'application/sbml+xml',
'sc' => 'application/vnd.ibm.secure-container',
'scd' => 'application/x-msschedule',
'scm' => 'application/vnd.lotus-screencam',
'scq' => 'application/scvp-cv-request',
'scs' => 'application/scvp-cv-response',
'scurl' => 'text/vnd.curl.scurl',
'sda' => 'application/vnd.stardivision.draw',
'sdc' => 'application/vnd.stardivision.calc',
'sdd' => 'application/vnd.stardivision.impress',
'sdkd' => 'application/vnd.solent.sdkm+xml',
'sdkm' => 'application/vnd.solent.sdkm+xml',
'sdp' => 'application/sdp',
'sdw' => 'application/vnd.stardivision.writer',
'see' => 'application/vnd.seemail',
'seed' => 'application/vnd.fdsn.seed',
'sema' => 'application/vnd.sema',
'semd' => 'application/vnd.semd',
'semf' => 'application/vnd.semf',
'ser' => 'application/java-serialized-object',
'setpay' => 'application/set-payment-initiation',
'setreg' => 'application/set-registration-initiation',
'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data',
'sfs' => 'application/vnd.spotfire.sfs',
'sgl' => 'application/vnd.stardivision.writer-global',
'sgm' => 'text/sgml',
'sgml' => 'text/sgml',
'sh' => 'application/x-sh',
'shar' => 'application/x-shar',
'shf' => 'application/shf+xml',
'sig' => 'application/pgp-signature',
'silo' => 'model/mesh',
'sis' => 'application/vnd.symbian.install',
'sisx' => 'application/vnd.symbian.install',
'sit' => 'application/x-stuffit',
'sitx' => 'application/x-stuffitx',
'skd' => 'application/vnd.koan',
'skm' => 'application/vnd.koan',
'skp' => 'application/vnd.koan',
'skt' => 'application/vnd.koan',
'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12',
'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
'slt' => 'application/vnd.epson.salt',
'sm' => 'application/vnd.stepmania.stepchart',
'smf' => 'application/vnd.stardivision.math',
'smi' => 'application/smil+xml',
'smil' => 'application/smil+xml',
'snd' => 'audio/basic',
'snf' => 'application/x-font-snf',
'so' => 'application/octet-stream',
'spc' => 'application/x-pkcs7-certificates',
'spf' => 'application/vnd.yamaha.smaf-phrase',
'spl' => 'application/x-futuresplash',
'spot' => 'text/vnd.in3d.spot',
'spp' => 'application/scvp-vp-response',
'spq' => 'application/scvp-vp-request',
'spx' => 'audio/ogg',
'src' => 'application/x-wais-source',
'sru' => 'application/sru+xml',
'srx' => 'application/sparql-results+xml',
'sse' => 'application/vnd.kodak-descriptor',
'ssf' => 'application/vnd.epson.ssf',
'ssml' => 'application/ssml+xml',
'st' => 'application/vnd.sailingtracker.track',
'stc' => 'application/vnd.sun.xml.calc.template',
'std' => 'application/vnd.sun.xml.draw.template',
'stf' => 'application/vnd.wt.stf',
'sti' => 'application/vnd.sun.xml.impress.template',
'stk' => 'application/hyperstudio',
'stl' => 'application/vnd.ms-pki.stl',
'str' => 'application/vnd.pg.format',
'stw' => 'application/vnd.sun.xml.writer.template',
'sub' => 'image/vnd.dvb.subtitle',
'sus' => 'application/vnd.sus-calendar',
'susp' => 'application/vnd.sus-calendar',
'sv4cpio' => 'application/x-sv4cpio',
'sv4crc' => 'application/x-sv4crc',
'svc' => 'application/vnd.dvb.service',
'svd' => 'application/vnd.svd',
'svg' => 'image/svg+xml',
'svgz' => 'image/svg+xml',
'swa' => 'application/x-director',
'swf' => 'application/x-shockwave-flash',
'swi' => 'application/vnd.aristanetworks.swi',
'sxc' => 'application/vnd.sun.xml.calc',
'sxd' => 'application/vnd.sun.xml.draw',
'sxg' => 'application/vnd.sun.xml.writer.global',
'sxi' => 'application/vnd.sun.xml.impress',
'sxm' => 'application/vnd.sun.xml.math',
'sxw' => 'application/vnd.sun.xml.writer',
't' => 'text/troff',
'tao' => 'application/vnd.tao.intent-module-archive',
'tar' => 'application/x-tar',
'tcap' => 'application/vnd.3gpp2.tcap',
'tcl' => 'application/x-tcl',
'teacher' => 'application/vnd.smart.teacher',
'tei' => 'application/tei+xml',
'teicorpus' => 'application/tei+xml',
'tex' => 'application/x-tex',
'texi' => 'application/x-texinfo',
'texinfo' => 'application/x-texinfo',
'text' => 'text/plain',
'tfi' => 'application/thraud+xml',
'tfm' => 'application/x-tex-tfm',
'thmx' => 'application/vnd.ms-officetheme',
'tif' => 'image/tiff',
'tiff' => 'image/tiff',
'tmo' => 'application/vnd.tmobile-livetv',
'torrent' => 'application/x-bittorrent',
'tpl' => 'application/vnd.groove-tool-template',
'tpt' => 'application/vnd.trid.tpt',
'tr' => 'text/troff',
'tra' => 'application/vnd.trueapp',
'trm' => 'application/x-msterminal',
'tsd' => 'application/timestamped-data',
'tsv' => 'text/tab-separated-values',
'ttc' => 'application/x-font-ttf',
'ttf' => 'application/x-font-ttf',
'ttl' => 'text/turtle',
'twd' => 'application/vnd.simtech-mindmapper',
'twds' => 'application/vnd.simtech-mindmapper',
'txd' => 'application/vnd.genomatix.tuxedo',
'txf' => 'application/vnd.mobius.txf',
'txt' => 'text/plain',
'u32' => 'application/x-authorware-bin',
'udeb' => 'application/x-debian-package',
'ufd' => 'application/vnd.ufdl',
'ufdl' => 'application/vnd.ufdl',
'umj' => 'application/vnd.umajin',
'unityweb' => 'application/vnd.unity',
'uoml' => 'application/vnd.uoml+xml',
'uri' => 'text/uri-list',
'uris' => 'text/uri-list',
'urls' => 'text/uri-list',
'ustar' => 'application/x-ustar',
'utz' => 'application/vnd.uiq.theme',
'uu' => 'text/x-uuencode',
'uva' => 'audio/vnd.dece.audio',
'uvd' => 'application/vnd.dece.data',
'uvf' => 'application/vnd.dece.data',
'uvg' => 'image/vnd.dece.graphic',
'uvh' => 'video/vnd.dece.hd',
'uvi' => 'image/vnd.dece.graphic',
'uvm' => 'video/vnd.dece.mobile',
'uvp' => 'video/vnd.dece.pd',
'uvs' => 'video/vnd.dece.sd',
'uvt' => 'application/vnd.dece.ttml+xml',
'uvu' => 'video/vnd.uvvu.mp4',
'uvv' => 'video/vnd.dece.video',
'uvva' => 'audio/vnd.dece.audio',
'uvvd' => 'application/vnd.dece.data',
'uvvf' => 'application/vnd.dece.data',
'uvvg' => 'image/vnd.dece.graphic',
'uvvh' => 'video/vnd.dece.hd',
'uvvi' => 'image/vnd.dece.graphic',
'uvvm' => 'video/vnd.dece.mobile',
'uvvp' => 'video/vnd.dece.pd',
'uvvs' => 'video/vnd.dece.sd',
'uvvt' => 'application/vnd.dece.ttml+xml',
'uvvu' => 'video/vnd.uvvu.mp4',
'uvvv' => 'video/vnd.dece.video',
'uvvx' => 'application/vnd.dece.unspecified',
'uvx' => 'application/vnd.dece.unspecified',
'vcd' => 'application/x-cdlink',
'vcf' => 'text/x-vcard',
'vcg' => 'application/vnd.groove-vcard',
'vcs' => 'text/x-vcalendar',
'vcx' => 'application/vnd.vcx',
'vis' => 'application/vnd.visionary',
'viv' => 'video/vnd.vivo',
'vor' => 'application/vnd.stardivision.writer',
'vox' => 'application/x-authorware-bin',
'vrml' => 'model/vrml',
'vsd' => 'application/vnd.visio',
'vsf' => 'application/vnd.vsf',
'vss' => 'application/vnd.visio',
'vst' => 'application/vnd.visio',
'vsw' => 'application/vnd.visio',
'vtu' => 'model/vnd.vtu',
'vxml' => 'application/voicexml+xml',
'w3d' => 'application/x-director',
'wad' => 'application/x-doom',
'wav' => 'audio/x-wav',
'wax' => 'audio/x-ms-wax',
'wbmp' => 'image/vnd.wap.wbmp',
'wbs' => 'application/vnd.criticaltools.wbs+xml',
'wbxml' => 'application/vnd.wap.wbxml',
'wcm' => 'application/vnd.ms-works',
'wdb' => 'application/vnd.ms-works',
'weba' => 'audio/webm',
'webm' => 'video/webm',
'webp' => 'image/webp',
'wg' => 'application/vnd.pmi.widget',
'wgt' => 'application/widget',
'wks' => 'application/vnd.ms-works',
'wm' => 'video/x-ms-wm',
'wma' => 'audio/x-ms-wma',
'wmd' => 'application/x-ms-wmd',
'wmf' => 'application/x-msmetafile',
'wml' => 'text/vnd.wap.wml',
'wmlc' => 'application/vnd.wap.wmlc',
'wmls' => 'text/vnd.wap.wmlscript',
'wmlsc' => 'application/vnd.wap.wmlscriptc',
'wmv' => 'video/x-ms-wmv',
'wmx' => 'video/x-ms-wmx',
'wmz' => 'application/x-ms-wmz',
'woff' => 'application/x-font-woff',
'wpd' => 'application/vnd.wordperfect',
'wpl' => 'application/vnd.ms-wpl',
'wps' => 'application/vnd.ms-works',
'wqd' => 'application/vnd.wqd',
'wri' => 'application/x-mswrite',
'wrl' => 'model/vrml',
'wsdl' => 'application/wsdl+xml',
'wspolicy' => 'application/wspolicy+xml',
'wtb' => 'application/vnd.webturbo',
'wvx' => 'video/x-ms-wvx',
'x32' => 'application/x-authorware-bin',
'x3d' => 'application/vnd.hzn-3d-crossword',
'xap' => 'application/x-silverlight-app',
'xar' => 'application/vnd.xara',
'xbap' => 'application/x-ms-xbap',
'xbd' => 'application/vnd.fujixerox.docuworks.binder',
'xbm' => 'image/x-xbitmap',
'xdf' => 'application/xcap-diff+xml',
'xdm' => 'application/vnd.syncml.dm+xml',
'xdp' => 'application/vnd.adobe.xdp+xml',
'xdssc' => 'application/dssc+xml',
'xdw' => 'application/vnd.fujixerox.docuworks',
'xenc' => 'application/xenc+xml',
'xer' => 'application/patch-ops-error+xml',
'xfdf' => 'application/vnd.adobe.xfdf',
'xfdl' => 'application/vnd.xfdl',
'xht' => 'application/xhtml+xml',
'xhtml' => 'application/xhtml+xml',
'xhvml' => 'application/xv+xml',
'xif' => 'image/vnd.xiff',
'xla' => 'application/vnd.ms-excel',
'xlam' => 'application/vnd.ms-excel.addin.macroenabled.12',
'xlc' => 'application/vnd.ms-excel',
'xlm' => 'application/vnd.ms-excel',
'xls' => 'application/vnd.ms-excel',
'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroenabled.12',
'xlsm' => 'application/vnd.ms-excel.sheet.macroenabled.12',
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'xlt' => 'application/vnd.ms-excel',
'xltm' => 'application/vnd.ms-excel.template.macroenabled.12',
'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
'xlw' => 'application/vnd.ms-excel',
'xml' => 'application/xml',
'xo' => 'application/vnd.olpc-sugar',
'xop' => 'application/xop+xml',
'xpi' => 'application/x-xpinstall',
'xpm' => 'image/x-xpixmap',
'xpr' => 'application/vnd.is-xpr',
'xps' => 'application/vnd.ms-xpsdocument',
'xpw' => 'application/vnd.intercon.formnet',
'xpx' => 'application/vnd.intercon.formnet',
'xsl' => 'application/xml',
'xslt' => 'application/xslt+xml',
'xsm' => 'application/vnd.syncml+xml',
'xspf' => 'application/xspf+xml',
'xul' => 'application/vnd.mozilla.xul+xml',
'xvm' => 'application/xv+xml',
'xvml' => 'application/xv+xml',
'xwd' => 'image/x-xwindowdump',
'xyz' => 'chemical/x-xyz',
'yaml' => 'text/yaml',
'yang' => 'application/yang',
'yin' => 'application/yin+xml',
'yml' => 'text/yaml',
'zaz' => 'application/vnd.zzazz.deck+xml',
'zip' => 'application/zip',
'zir' => 'application/vnd.zul',
'zirz' => 'application/vnd.zul',
'zmm' => 'application/vnd.handheld-entertainment+xml'
);







public static function getInstance()
{
if (!self::$instance) {
self::$instance = new self();
}

return self::$instance;
}









public function fromExtension($extension)
{
$extension = strtolower($extension);

return isset($this->mimetypes[$extension])
? $this->mimetypes[$extension]
: null;
}








public function fromFilename($filename)
{
return $this->fromExtension(pathinfo($filename, PATHINFO_EXTENSION));
}
}
<?php
namespace GuzzleHttp;

use GuzzleHttp\Message\MessageFactoryInterface;
use GuzzleHttp\Message\RequestInterface;
use GuzzleHttp\Event\ProgressEvent;
use GuzzleHttp\Message\Request;
use GuzzleHttp\Ring\Core;
use GuzzleHttp\Stream\Stream;
use GuzzleHttp\Exception\RequestException;




class RingBridge
{











public static function createRingRequest(RequestInterface $request)
{
$options = $request->getConfig()->toArray();
$url = $request->getUrl();

 $qs = ($pos = strpos($url, '?')) ? substr($url, $pos + 1) : null;

return [
'scheme' => $request->getScheme(),
'http_method' => $request->getMethod(),
'url' => $url,
'uri' => $request->getPath(),
'headers' => $request->getHeaders(),
'body' => $request->getBody(),
'version' => $request->getProtocolVersion(),
'client' => $options,
'query_string' => $qs,
'future' => isset($options['future']) ? $options['future'] : false
];
}








public static function prepareRingRequest(Transaction $trans)
{

 $trans->exception = null;
$request = self::createRingRequest($trans->request);


 if ($trans->request->getEmitter()->hasListeners('progress')) {
$emitter = $trans->request->getEmitter();
$request['client']['progress'] = function ($a, $b, $c, $d) use ($trans, $emitter) {
$emitter->emit('progress', new ProgressEvent($trans, $a, $b, $c, $d));
};
}

return $request;
}










public static function completeRingResponse(
Transaction $trans,
array $response,
MessageFactoryInterface $messageFactory
) {
$trans->state = 'complete';
$trans->transferInfo = isset($response['transfer_stats'])
? $response['transfer_stats'] : [];

if (!empty($response['status'])) {
$options = [];
if (isset($response['version'])) {
$options['protocol_version'] = $response['version'];
}
if (isset($response['reason'])) {
$options['reason_phrase'] = $response['reason'];
}
$trans->response = $messageFactory->createResponse(
$response['status'],
isset($response['headers']) ? $response['headers'] : [],
isset($response['body']) ? $response['body'] : null,
$options
);
if (isset($response['effective_url'])) {
$trans->response->setEffectiveUrl($response['effective_url']);
}
} elseif (empty($response['error'])) {

 $response['error'] = self::getNoRingResponseException($trans->request);
}

if (isset($response['error'])) {
$trans->state = 'error';
$trans->exception = $response['error'];
}
}









public static function fromRingRequest(array $request)
{
$options = [];
if (isset($request['version'])) {
$options['protocol_version'] = $request['version'];
}

if (!isset($request['http_method'])) {
throw new \InvalidArgumentException('No http_method');
}

return new Request(
$request['http_method'],
Core::url($request),
isset($request['headers']) ? $request['headers'] : [],
isset($request['body']) ? Stream::factory($request['body']) : null,
$options
);
}









public static function getNoRingResponseException(RequestInterface $request)
{
$message = <<<EOT
Sending the request did not return a response, exception, or populate the
transaction with a response. This is most likely due to an incorrectly
implemented RingPHP handler. If you are simply trying to mock responses,
then it is recommended to use the GuzzleHttp\Ring\Client\MockHandler.
EOT;
return new RequestException($message, $request);
}
}
<?php
namespace GuzzleHttp;

use GuzzleHttp\Event\HasEmitterInterface;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Message\RequestInterface;
use GuzzleHttp\Message\ResponseInterface;




interface ClientInterface extends HasEmitterInterface
{
const VERSION = '5.3.0';















public function createRequest($method, $url = null, array $options = []);










public function get($url = null, $options = []);










public function head($url = null, array $options = []);










public function delete($url = null, array $options = []);










public function put($url = null, array $options = []);










public function patch($url = null, array $options = []);










public function post($url = null, array $options = []);










public function options($url = null, array $options = []);










public function send(RequestInterface $request);











public function getDefaultOption($keyOrPath = null);











public function setDefaultOption($keyOrPath, $value);






public function getBaseUrl();
}
<?php
namespace GuzzleHttp;

use GuzzleHttp\Event\BeforeEvent;
use GuzzleHttp\Event\RequestEvents;
use GuzzleHttp\Message\RequestInterface;
use GuzzleHttp\Message\ResponseInterface;
use GuzzleHttp\Ring\Core;
use GuzzleHttp\Ring\Future\FutureInterface;
use GuzzleHttp\Event\ListenerAttacherTrait;
use GuzzleHttp\Event\EndEvent;
use React\Promise\Deferred;
use React\Promise\FulfilledPromise;
use React\Promise\PromiseInterface;
use React\Promise\RejectedPromise;


















class Pool implements FutureInterface
{
use ListenerAttacherTrait;


private $client;


private $iter;


private $deferred;


private $promise;

private $waitQueue = [];
private $eventListeners = [];
private $poolSize;
private $isRealized = false;






















public function __construct(
ClientInterface $client,
$requests,
array $options = []
) {
$this->client = $client;
$this->iter = $this->coerceIterable($requests);
$this->deferred = new Deferred();
$this->promise = $this->deferred->promise();
$this->poolSize = isset($options['pool_size'])
? $options['pool_size'] : 25;
$this->eventListeners = $this->prepareListeners(
$options,
['before', 'complete', 'error', 'end']
);
}

















public static function batch(
ClientInterface $client,
$requests,
array $options = []
) {
$hash = new \SplObjectStorage();
foreach ($requests as $request) {
$hash->attach($request);
}


 
 (new self($client, $requests, RequestEvents::convertEventArray(
$options,
['end'],
[
'priority' => RequestEvents::LATE,
'fn' => function (EndEvent $e) use ($hash) {
$hash[$e->getRequest()] = $e->getException()
? $e->getException()
: $e->getResponse();
}
]
)))->wait();

return new BatchResults($hash);
}









public static function send(
ClientInterface $client,
$requests,
array $options = []
) {
$pool = new self($client, $requests, $options);
$pool->wait();
}

private function getPoolSize()
{
return is_callable($this->poolSize)
? call_user_func($this->poolSize, count($this->waitQueue))
: $this->poolSize;
}




private function addNextRequests()
{
$limit = max($this->getPoolSize() - count($this->waitQueue), 0);
while ($limit--) {
if (!$this->addNextRequest()) {
break;
}
}
}

public function wait()
{
if ($this->isRealized) {
return false;
}


 $this->addNextRequests();


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


 while ($response = array_pop($this->waitQueue)) {
try {
$response->wait();
} catch (\Exception $e) {

 }
$this->addNextRequests();
}


 $this->isRealized = true;
$this->waitQueue = $this->eventListeners = [];
$this->client = $this->iter = null;
$this->deferred->resolve(true);

return true;
}










public function cancel()
{
if ($this->isRealized) {
return false;
}

$success = $this->isRealized = true;
foreach ($this->waitQueue as $response) {
if (!$response->cancel()) {
$success = false;
}
}

return $success;
}







public function then(
callable $onFulfilled = null,
callable $onRejected = null,
callable $onProgress = null
) {
return $this->promise->then($onFulfilled, $onRejected, $onProgress);
}

public function promise()
{
return $this->promise;
}

private function coerceIterable($requests)
{
if ($requests instanceof \Iterator) {
return $requests;
} elseif (is_array($requests)) {
return new \ArrayIterator($requests);
}

throw new \InvalidArgumentException('Expected Iterator or array. '
. 'Found ' . Core::describeType($requests));
}





private function addNextRequest()
{
add_next:

if ($this->isRealized || !$this->iter || !$this->iter->valid()) {
return false;
}

$request = $this->iter->current();
$this->iter->next();

if (!($request instanceof RequestInterface)) {
throw new \InvalidArgumentException(sprintf(
'All requests in the provided iterator must implement '
. 'RequestInterface. Found %s',
Core::describeType($request)
));
}


 $request->getConfig()->set('future', 'lazy');
$hash = spl_object_hash($request);
$this->attachListeners($request, $this->eventListeners);
$request->getEmitter()->on('before', [$this, '_trackRetries'], RequestEvents::EARLY);
$response = $this->client->send($request);
$this->waitQueue[$hash] = $response;
$promise = $response->promise();


 if ($promise instanceof FulfilledPromise
|| $promise instanceof RejectedPromise
) {
try {
$this->finishResponse($request, $response->wait(), $hash);
} catch (\Exception $e) {
$this->finishResponse($request, $e, $hash);
}
goto add_next;
}


 $thenFn = function ($value) use ($request, $hash) {
$this->finishResponse($request, $value, $hash);
if (!$request->getConfig()->get('_pool_retries')) {
$this->addNextRequests();
}
};

$promise->then($thenFn, $thenFn);

return true;
}

public function _trackRetries(BeforeEvent $e)
{
$e->getRequest()->getConfig()->set('_pool_retries', $e->getRetryCount());
}

private function finishResponse($request, $value, $hash)
{
unset($this->waitQueue[$hash]);
$result = $value instanceof ResponseInterface
? ['request' => $request, 'response' => $value, 'error' => null]
: ['request' => $request, 'response' => null, 'error' => $value];
$this->deferred->notify($result);
}
}
<?php
namespace GuzzleHttp;

use GuzzleHttp\Message\RequestInterface;
use GuzzleHttp\Message\ResponseInterface;







class Transaction
{





public $client;






public $request;








public $response;









public $exception;









public $transferInfo = [];






public $retries = 0;






public $state;







public $future;








public $_transitionCount = 0;






public function __construct(
ClientInterface $client,
RequestInterface $request,
$future = false
) {
$this->client = $client;
$this->request = $request;
$this->_future = $future;
}
}
<?php
namespace GuzzleHttp;

use GuzzleHttp\Ring\Core;




class Url
{
private $scheme;
private $host;
private $port;
private $username;
private $password;
private $path = '';
private $fragment;
private static $defaultPorts = ['http' => 80, 'https' => 443, 'ftp' => 21];
private static $pathPattern = '/[^a-zA-Z0-9\-\._~!\$&\'\(\)\*\+,;=%:@\/]+|%(?![A-Fa-f0-9]{2})/';
private static $queryPattern = '/[^a-zA-Z0-9\-\._~!\$\'\(\)\*\+,;%:@\/\?=&]+|%(?![A-Fa-f0-9]{2})/';

private $query;









public static function fromString($url)
{
static $defaults = ['scheme' => null, 'host' => null,
'path' => null, 'port' => null, 'query' => null,
'user' => null, 'pass' => null, 'fragment' => null];

if (false === ($parts = parse_url($url))) {
throw new \InvalidArgumentException('Unable to parse malformed '
. 'url: ' . $url);
}

$parts += $defaults;


 if ($parts['query'] || 0 !== strlen($parts['query'])) {
$parts['query'] = Query::fromString($parts['query']);
}

return new static($parts['scheme'], $parts['host'], $parts['user'],
$parts['pass'], $parts['port'], $parts['path'], $parts['query'],
$parts['fragment']);
}









public static function buildUrl(array $parts)
{
$url = $scheme = '';

if (!empty($parts['scheme'])) {
$scheme = $parts['scheme'];
$url .= $scheme . ':';
}

if (!empty($parts['host'])) {
$url .= '//';
if (isset($parts['user'])) {
$url .= $parts['user'];
if (isset($parts['pass'])) {
$url .= ':' . $parts['pass'];
}
$url .= '@';
}

$url .= $parts['host'];


 if (isset($parts['port']) &&
(!isset(self::$defaultPorts[$scheme]) ||
$parts['port'] != self::$defaultPorts[$scheme])
) {
$url .= ':' . $parts['port'];
}
}


 if (isset($parts['path']) && strlen($parts['path'])) {

 
 if (!empty($parts['host']) && $parts['path'][0] != '/') {
$url .= '/';
}
$url .= $parts['path'];
}


 if (isset($parts['query'])) {
$queryStr = (string) $parts['query'];
if ($queryStr || $queryStr === '0') {
$url .= '?' . $queryStr;
}
}


 if (isset($parts['fragment'])) {
$url .= '#' . $parts['fragment'];
}

return $url;
}













public function __construct(
$scheme,
$host,
$username = null,
$password = null,
$port = null,
$path = null,
$query = null,
$fragment = null
) {
$this->scheme = strtolower($scheme);
$this->host = $host;
$this->port = $port;
$this->username = $username;
$this->password = $password;
$this->fragment = $fragment;

if ($query) {
$this->setQuery($query);
}

$this->setPath($path);
}




public function __clone()
{
if ($this->query instanceof Query) {
$this->query = clone $this->query;
}
}






public function __toString()
{
return static::buildUrl($this->getParts());
}






public function getParts()
{
return array(
'scheme' => $this->scheme,
'user' => $this->username,
'pass' => $this->password,
'host' => $this->host,
'port' => $this->port,
'path' => $this->path,
'query' => $this->query,
'fragment' => $this->fragment,
);
}








public function setHost($host)
{
if (strpos($host, ':') === false) {
$this->host = $host;
} else {
list($host, $port) = explode(':', $host);
$this->host = $host;
$this->setPort($port);
}
}






public function getHost()
{
return $this->host;
}






public function setScheme($scheme)
{

 if ($this->port
&& isset(self::$defaultPorts[$this->scheme])
&& self::$defaultPorts[$this->scheme] == $this->port
) {
$this->port = null;
}

$this->scheme = strtolower($scheme);
}






public function getScheme()
{
return $this->scheme;
}






public function setPort($port)
{
$this->port = $port;
}









public function getPort()
{
if ($this->port) {
return $this->port;
} elseif (isset(self::$defaultPorts[$this->scheme])) {
return self::$defaultPorts[$this->scheme];
}

return null;
}








public function setPath($path)
{
$this->path = self::encodePath($path);
}





public function removeDotSegments()
{
static $noopPaths = ['' => true, '/' => true, '*' => true];
static $ignoreSegments = ['.' => true, '..' => true];

if (isset($noopPaths[$this->path])) {
return;
}

$results = [];
$segments = $this->getPathSegments();
foreach ($segments as $segment) {
if ($segment == '..') {
array_pop($results);
} elseif (!isset($ignoreSegments[$segment])) {
$results[] = $segment;
}
}

$newPath = implode('/', $results);


 if (substr($this->path, 0, 1) === '/' &&
substr($newPath, 0, 1) !== '/'
) {
$newPath = '/' . $newPath;
}


 if ($newPath != '/' && isset($ignoreSegments[end($segments)])) {
$newPath .= '/';
}

$this->path = $newPath;
}






public function addPath($relativePath)
{
if ($relativePath != '/' &&
is_string($relativePath) &&
strlen($relativePath) > 0
) {

 if ($relativePath[0] !== '/' &&
substr($this->path, -1, 1) !== '/'
) {
$relativePath = '/' . $relativePath;
}

$this->setPath($this->path . $relativePath);
}
}






public function getPath()
{
return $this->path;
}






public function getPathSegments()
{
return explode('/', $this->path);
}






public function setPassword($password)
{
$this->password = $password;
}






public function getPassword()
{
return $this->password;
}






public function setUsername($username)
{
$this->username = $username;
}






public function getUsername()
{
return $this->username;
}






public function getQuery()
{

 if (!$this->query instanceof Query) {
$this->query = $this->query === null
? new Query()
: Query::fromString($this->query);
}

return $this->query;
}
















public function setQuery($query, $rawString = false)
{
if ($query instanceof Query) {
$this->query = $query;
} elseif (is_string($query)) {
if (!$rawString) {
$this->query = Query::fromString($query);
} else {

 $this->query = preg_replace_callback(
self::$queryPattern,
[__CLASS__, 'encodeMatch'],
$query
);
}

} elseif (is_array($query)) {
$this->query = new Query($query);
} else {
throw new \InvalidArgumentException('Query must be a Query, '
. 'array, or string. Got ' . Core::describeType($query));
}
}






public function getFragment()
{
return $this->fragment;
}






public function setFragment($fragment)
{
$this->fragment = $fragment;
}






public function isAbsolute()
{
return $this->scheme && $this->host;
}












public function combine($url)
{
$url = static::fromString($url);


 if (!$this->isAbsolute() && $url->isAbsolute()) {
$url = $url->combine($this);
}

$parts = $url->getParts();


 if ($parts['scheme']) {
return clone $url;
}


 if ($parts['host']) {
return new static(
$this->scheme,
$parts['host'],
$parts['user'],
$parts['pass'],
$parts['port'],
$parts['path'],
$parts['query'] instanceof Query
? clone $parts['query']
: $parts['query'],
$parts['fragment']
);
}

if (!$parts['path'] && $parts['path'] !== '0') {

 $path = $this->path ?: '';
$query = $parts['query'] ?: $this->query;
} else {
$query = $parts['query'];
if ($parts['path'][0] == '/' || !$this->path) {

 $path = $parts['path'];
} else {

 
 
 $path = substr($this->path, 0, strrpos($this->path, '/') + 1) . $parts['path'];
}
}

$result = new self(
$this->scheme,
$this->host,
$this->username,
$this->password,
$this->port,
$path,
$query instanceof Query ? clone $query : $query,
$parts['fragment']
);

if ($path) {
$result->removeDotSegments();
}

return $result;
}









public static function encodePath($path)
{
static $cb = [__CLASS__, 'encodeMatch'];
return preg_replace_callback(self::$pathPattern, $cb, $path);
}

private static function encodeMatch(array $match)
{
return rawurlencode($match[0]);
}
}
<?php
namespace GuzzleHttp\Subscriber;

use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Cookie\CookieJarInterface;
use GuzzleHttp\Event\BeforeEvent;
use GuzzleHttp\Event\CompleteEvent;
use GuzzleHttp\Event\RequestEvents;
use GuzzleHttp\Event\SubscriberInterface;




class Cookie implements SubscriberInterface
{

private $cookieJar;




public function __construct(CookieJarInterface $cookieJar = null)
{
$this->cookieJar = $cookieJar ?: new CookieJar();
}

public function getEvents()
{

 return [
'before' => ['onBefore'],
'complete' => ['onComplete', RequestEvents::REDIRECT_RESPONSE + 10]
];
}






public function getCookieJar()
{
return $this->cookieJar;
}

public function onBefore(BeforeEvent $event)
{
$this->cookieJar->addCookieHeader($event->getRequest());
}

public function onComplete(CompleteEvent $event)
{
$this->cookieJar->extractCookies(
$event->getRequest(),
$event->getResponse()
);
}
}
<?php
namespace GuzzleHttp\Subscriber;

use GuzzleHttp\Event\RequestEvents;
use GuzzleHttp\Event\SubscriberInterface;
use GuzzleHttp\Event\BeforeEvent;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Message\MessageFactory;
use GuzzleHttp\Message\ResponseInterface;
use GuzzleHttp\Stream\StreamInterface;





class Mock implements SubscriberInterface, \Countable
{

private $queue = [];


private $readBodies;


private $factory;






public function __construct(array $items = [], $readBodies = true)
{
$this->factory = new MessageFactory();
$this->readBodies = $readBodies;
$this->addMultiple($items);
}

public function getEvents()
{

 return ['before' => ['onBefore', RequestEvents::SIGN_REQUEST - 10]];
}




public function onBefore(BeforeEvent $event)
{
if (!$item = array_shift($this->queue)) {
throw new \OutOfBoundsException('Mock queue is empty');
} elseif ($item instanceof RequestException) {
throw $item;
}


 $request = $event->getRequest();
if ($this->readBodies && $request->getBody()) {
while (!$request->getBody()->eof()) {
$request->getBody()->read(8096);
}
}

$saveTo = $event->getRequest()->getConfig()->get('save_to');

if (null !== $saveTo) {
$body = $item->getBody();

if (is_resource($saveTo)) {
fwrite($saveTo, $body);
} elseif (is_string($saveTo)) {
file_put_contents($saveTo, $body);
} elseif ($saveTo instanceof StreamInterface) {
$saveTo->write($body);
}
}

$event->intercept($item);
}

public function count()
{
return count($this->queue);
}









public function addResponse($response)
{
if (is_string($response)) {
$response = file_exists($response)
? $this->factory->fromMessage(file_get_contents($response))
: $this->factory->fromMessage($response);
} elseif (!($response instanceof ResponseInterface)) {
throw new \InvalidArgumentException('Response must a message '
. 'string, response object, or path to a file');
}

$this->queue[] = $response;

return $this;
}








public function addException(RequestException $e)
{
$this->queue[] = $e;

return $this;
}






public function addMultiple(array $items)
{
foreach ($items as $item) {
if ($item instanceof RequestException) {
$this->addException($item);
} else {
$this->addResponse($item);
}
}
}




public function clearQueue()
{
$this->queue = [];
}
}
<?php
namespace GuzzleHttp\Subscriber;

use GuzzleHttp\Event\CompleteEvent;
use GuzzleHttp\Event\RequestEvents;
use GuzzleHttp\Event\SubscriberInterface;
use GuzzleHttp\Exception\RequestException;




class HttpError implements SubscriberInterface
{
public function getEvents()
{
return ['complete' => ['onComplete', RequestEvents::VERIFY_RESPONSE]];
}







public function onComplete(CompleteEvent $event)
{
$code = (string) $event->getResponse()->getStatusCode();

 if ($code[0] >= 4) {
throw RequestException::create(
$event->getRequest(),
$event->getResponse()
);
}
}
}
<?php
namespace GuzzleHttp\Subscriber;

use GuzzleHttp\Event\CompleteEvent;
use GuzzleHttp\Event\RequestEvents;
use GuzzleHttp\Event\SubscriberInterface;
use GuzzleHttp\Exception\BadResponseException;
use GuzzleHttp\Exception\CouldNotRewindStreamException;
use GuzzleHttp\Exception\TooManyRedirectsException;
use GuzzleHttp\Message\RequestInterface;
use GuzzleHttp\Message\ResponseInterface;
use GuzzleHttp\Url;




















class Redirect implements SubscriberInterface
{
public function getEvents()
{
return ['complete' => ['onComplete', RequestEvents::REDIRECT_RESPONSE]];
}







public static function rewindEntityBody(RequestInterface $redirectRequest)
{

 if ($body = $redirectRequest->getBody()) {

 
 if ($body->tell() && !$body->seek(0)) {
throw new CouldNotRewindStreamException(
'Unable to rewind the non-seekable request body after redirecting',
$redirectRequest
);
}
}
}







public function onComplete(CompleteEvent $event)
{
$response = $event->getResponse();

if (substr($response->getStatusCode(), 0, 1) != '3'
|| !$response->hasHeader('Location')
) {
return;
}

$request = $event->getRequest();
$config = $request->getConfig();


 if ($redirectCount = $config['redirect_count']) {
$config['redirect_count'] = ++$redirectCount;
} else {
$config['redirect_scheme'] = $request->getScheme();
$config['redirect_count'] = $redirectCount = 1;
}

$max = $config->getPath('redirect/max') ?: 5;

if ($redirectCount > $max) {
throw new TooManyRedirectsException(
"Will not follow more than {$redirectCount} redirects",
$request
);
}

$this->modifyRedirectRequest($request, $response);
$event->retry();
}

private function modifyRedirectRequest(
RequestInterface $request,
ResponseInterface $response
) {
$config = $request->getConfig();
$protocols = $config->getPath('redirect/protocols') ?: ['http', 'https'];


 
 
 $statusCode = $response->getStatusCode();
if ($statusCode == 303 ||
($statusCode <= 302 && $request->getBody() && !$config->getPath('redirect/strict'))
) {
$request->setMethod('GET');
$request->setBody(null);
}

$previousUrl = $request->getUrl();
$this->setRedirectUrl($request, $response, $protocols);
$this->rewindEntityBody($request);


 
 if ($config->getPath('redirect/referer')
&& ($request->getScheme() == 'https' || $request->getScheme() == $config['redirect_scheme'])
) {
$url = Url::fromString($previousUrl);
$url->setUsername(null);
$url->setPassword(null);
$request->setHeader('Referer', (string) $url);
} else {
$request->removeHeader('Referer');
}
}








private function setRedirectUrl(
RequestInterface $request,
ResponseInterface $response,
array $protocols
) {
$location = $response->getHeader('Location');
$location = Url::fromString($location);


 if (!$location->isAbsolute()) {
$originalUrl = Url::fromString($request->getUrl());

 
 $originalUrl->getQuery()->clear();
$location = $originalUrl->combine($location);
}


 if (!in_array($location->getScheme(), $protocols)) {
throw new BadResponseException(
sprintf(
'Redirect URL, %s, does not use one of the allowed redirect protocols: %s',
$location,
implode(', ', $protocols)
),
$request,
$response
);
}

$request->setUrl($location);
}
}
<?php
namespace GuzzleHttp\Subscriber;

use GuzzleHttp\Event\CompleteEvent;
use GuzzleHttp\Event\ErrorEvent;
use GuzzleHttp\Event\RequestEvents;
use GuzzleHttp\Event\SubscriberInterface;
use GuzzleHttp\Message\RequestInterface;
use GuzzleHttp\Message\ResponseInterface;




class History implements SubscriberInterface, \IteratorAggregate, \Countable
{

private $limit;


private $transactions = [];

public function __construct($limit = 10)
{
$this->limit = $limit;
}

public function getEvents()
{
return [
'complete' => ['onComplete', RequestEvents::EARLY],
'error' => ['onError', RequestEvents::EARLY],
];
}






public function __toString()
{
$lines = array();
foreach ($this->transactions as $entry) {
$response = isset($entry['response']) ? $entry['response'] : '';
$lines[] = '> ' . trim($entry['sent_request'])
. "\n\n< " . trim($response) . "\n";
}

return implode("\n", $lines);
}

public function onComplete(CompleteEvent $event)
{
$this->add($event->getRequest(), $event->getResponse());
}

public function onError(ErrorEvent $event)
{

 
 if (!$event->getResponse()) {
$this->add($event->getRequest());
}
}











public function getIterator()
{
return new \ArrayIterator($this->transactions);
}
















public function getRequests($asSent = false)
{
return array_map(function ($t) use ($asSent) {
return $asSent ? $t['sent_request'] : $t['request'];
}, $this->transactions);
}






public function count()
{
return count($this->transactions);
}
















public function getLastRequest($asSent = false)
{
return $asSent
? end($this->transactions)['sent_request']
: end($this->transactions)['request'];
}






public function getLastResponse()
{
return end($this->transactions)['response'];
}




public function clear()
{
$this->transactions = array();
}







private function add(
RequestInterface $request,
ResponseInterface $response = null
) {
$this->transactions[] = [
'request' => $request,
'sent_request' => clone $request,
'response' => $response
];
if (count($this->transactions) > $this->limit) {
array_shift($this->transactions);
}
}
}
<?php
namespace GuzzleHttp\Subscriber;

use GuzzleHttp\Event\BeforeEvent;
use GuzzleHttp\Event\RequestEvents;
use GuzzleHttp\Event\SubscriberInterface;
use GuzzleHttp\Message\AppliesHeadersInterface;
use GuzzleHttp\Message\RequestInterface;
use GuzzleHttp\Mimetypes;
use GuzzleHttp\Stream\StreamInterface;













class Prepare implements SubscriberInterface
{
public function getEvents()
{
return ['before' => ['onBefore', RequestEvents::PREPARE_REQUEST]];
}

public function onBefore(BeforeEvent $event)
{
$request = $event->getRequest();


 
 if (!($body = $request->getBody())) {
return;
}

$this->addContentLength($request, $body);

if ($body instanceof AppliesHeadersInterface) {

 $body->applyRequestHeaders($request);
} elseif (!$request->hasHeader('Content-Type')) {
$this->addContentType($request, $body);
}

$this->addExpectHeader($request, $body);
}

private function addContentType(
RequestInterface $request,
StreamInterface $body
) {
if (!($uri = $body->getMetadata('uri'))) {
return;
}


 
 if ($contentType = Mimetypes::getInstance()->fromFilename($uri)) {
$request->setHeader('Content-Type', $contentType);
}
}

private function addContentLength(
RequestInterface $request,
StreamInterface $body
) {

 
 
 if ($request->hasHeader('Content-Length')) {

 $request->removeHeader('Transfer-Encoding');
return;
}

if ($request->hasHeader('Transfer-Encoding')) {
return;
}

if (null !== ($size = $body->getSize())) {
$request->setHeader('Content-Length', $size);
$request->removeHeader('Transfer-Encoding');
} elseif ('1.1' == $request->getProtocolVersion()) {

 
 $request->setHeader('Transfer-Encoding', 'chunked');
$request->removeHeader('Content-Length');
}
}

private function addExpectHeader(
RequestInterface $request,
StreamInterface $body
) {

 if ($request->hasHeader('Expect')) {
return;
}

$expect = $request->getConfig()['expect'];


 if ($expect === false || $request->getProtocolVersion() !== '1.1') {
return;
}


 if ($expect === true) {
$request->setHeader('Expect', '100-Continue');
return;
}


 if ($expect === null) {
$expect = 1048576;
}


 
 $size = $body->getSize();
if ($size === null || $size >= (int) $expect || !$body->isSeekable()) {
$request->setHeader('Expect', '100-Continue');
}
}
}
<?php
namespace GuzzleHttp;

use GuzzleHttp\Event\HasEmitterTrait;
use GuzzleHttp\Message\MessageFactory;
use GuzzleHttp\Message\MessageFactoryInterface;
use GuzzleHttp\Message\RequestInterface;
use GuzzleHttp\Message\FutureResponse;
use GuzzleHttp\Ring\Core;
use GuzzleHttp\Ring\Future\FutureInterface;
use GuzzleHttp\Exception\RequestException;
use React\Promise\FulfilledPromise;
use React\Promise\RejectedPromise;




class Client implements ClientInterface
{
use HasEmitterTrait;


private $messageFactory;


private $baseUrl;


private $defaults;


private $fsm;


































public function __construct(array $config = [])
{
$this->configureBaseUrl($config);
$this->configureDefaults($config);

if (isset($config['emitter'])) {
$this->emitter = $config['emitter'];
}

$this->messageFactory = isset($config['message_factory'])
? $config['message_factory']
: new MessageFactory();

if (isset($config['fsm'])) {
$this->fsm = $config['fsm'];
} else {
if (isset($config['handler'])) {
$handler = $config['handler'];
} elseif (isset($config['adapter'])) {
$handler = $config['adapter'];
} else {
$handler = Utils::getDefaultHandler();
}
$this->fsm = new RequestFsm($handler, $this->messageFactory);
}
}

public function getDefaultOption($keyOrPath = null)
{
return $keyOrPath === null
? $this->defaults
: Utils::getPath($this->defaults, $keyOrPath);
}

public function setDefaultOption($keyOrPath, $value)
{
Utils::setPath($this->defaults, $keyOrPath, $value);
}

public function getBaseUrl()
{
return (string) $this->baseUrl;
}

public function createRequest($method, $url = null, array $options = [])
{
$options = $this->mergeDefaults($options);

 $options['config']['emitter'] = clone $this->getEmitter();
$url = $url || (is_string($url) && strlen($url))
? $this->buildUrl($url)
: (string) $this->baseUrl;

return $this->messageFactory->createRequest($method, $url, $options);
}

public function get($url = null, $options = [])
{
return $this->send($this->createRequest('GET', $url, $options));
}

public function head($url = null, array $options = [])
{
return $this->send($this->createRequest('HEAD', $url, $options));
}

public function delete($url = null, array $options = [])
{
return $this->send($this->createRequest('DELETE', $url, $options));
}

public function put($url = null, array $options = [])
{
return $this->send($this->createRequest('PUT', $url, $options));
}

public function patch($url = null, array $options = [])
{
return $this->send($this->createRequest('PATCH', $url, $options));
}

public function post($url = null, array $options = [])
{
return $this->send($this->createRequest('POST', $url, $options));
}

public function options($url = null, array $options = [])
{
return $this->send($this->createRequest('OPTIONS', $url, $options));
}

public function send(RequestInterface $request)
{
$isFuture = $request->getConfig()->get('future');
$trans = new Transaction($this, $request, $isFuture);
$fn = $this->fsm;

try {
$fn($trans);
if ($isFuture) {

 return $trans->response instanceof FutureInterface
? $trans->response
: new FutureResponse(new FulfilledPromise($trans->response));
}

 
 
 while ($trans->response instanceof FutureInterface) {
$trans->response = $trans->response->wait();
}
return $trans->response;
} catch (\Exception $e) {
if ($isFuture) {

 return new FutureResponse(new RejectedPromise($e));
}
throw RequestException::wrapException($trans->request, $e);
}
}






protected function getDefaultOptions()
{
$settings = [
'allow_redirects' => true,
'exceptions' => true,
'decode_content' => true,
'verify' => true
];


 if ($proxy = getenv('HTTP_PROXY')) {
$settings['proxy']['http'] = $proxy;
}

if ($proxy = getenv('HTTPS_PROXY')) {
$settings['proxy']['https'] = $proxy;
}

return $settings;
}









private function buildUrl($url)
{

 if (!is_array($url)) {
return strpos($url, '://')
? (string) $url
: (string) $this->baseUrl->combine($url);
}

if (!isset($url[1])) {
throw new \InvalidArgumentException('You must provide a hash of '
. 'varname options in the second element of a URL array.');
}


 if (strpos($url[0], '://')) {
return Utils::uriTemplate($url[0], $url[1]);
}


 return (string) $this->baseUrl->combine(
Utils::uriTemplate($url[0], $url[1])
);
}

private function configureBaseUrl(&$config)
{
if (!isset($config['base_url'])) {
$this->baseUrl = new Url('', '');
} elseif (!is_array($config['base_url'])) {
$this->baseUrl = Url::fromString($config['base_url']);
} elseif (count($config['base_url']) < 2) {
throw new \InvalidArgumentException('You must provide a hash of '
. 'varname options in the second element of a base_url array.');
} else {
$this->baseUrl = Url::fromString(
Utils::uriTemplate(
$config['base_url'][0],
$config['base_url'][1]
)
);
$config['base_url'] = (string) $this->baseUrl;
}
}

private function configureDefaults($config)
{
if (!isset($config['defaults'])) {
$this->defaults = $this->getDefaultOptions();
} else {
$this->defaults = array_replace(
$this->getDefaultOptions(),
$config['defaults']
);
}


 if (!isset($this->defaults['headers'])) {
$this->defaults['headers'] = [
'User-Agent' => Utils::getDefaultUserAgent()
];
} elseif (!Core::hasHeader($this->defaults, 'User-Agent')) {

 $this->defaults['headers']['User-Agent'] = Utils::getDefaultUserAgent();
}
}








private function mergeDefaults($options)
{
$defaults = $this->defaults;


 
 if (!empty($defaults['headers']) && !empty($options['headers'])) {

 $lkeys = [];
foreach (array_keys($options['headers']) as $k) {
$lkeys[strtolower($k)] = true;
}

 foreach ($defaults['headers'] as $key => $value) {
if (!isset($lkeys[strtolower($key)])) {
$options['headers'][$key] = $value;
}
}

 unset($defaults['headers']);
}

$result = array_replace_recursive($defaults, $options);
foreach ($options as $k => $v) {
if ($v === null) {
unset($result[$k]);
}
}

return $result;
}





public function sendAll($requests, array $options = [])
{
Pool::send($this, $requests, $options);
}




public static function getDefaultHandler()
{
return Utils::getDefaultHandler();
}




public static function getDefaultUserAgent()
{
return Utils::getDefaultUserAgent();
}
}
<?php
namespace GuzzleHttp;











class BatchResults implements \Countable, \IteratorAggregate, \ArrayAccess
{
private $hash;




public function __construct(\SplObjectStorage $hash)
{
$this->hash = $hash;
}






public function getKeys()
{
return iterator_to_array($this->hash);
}









public function getResult($forObject)
{
return isset($this->hash[$forObject]) ? $this->hash[$forObject] : null;
}






public function getSuccessful()
{
$results = [];
foreach ($this->hash as $key) {
if (!($this->hash[$key] instanceof \Exception)) {
$results[] = $this->hash[$key];
}
}

return $results;
}






public function getFailures()
{
$results = [];
foreach ($this->hash as $key) {
if ($this->hash[$key] instanceof \Exception) {
$results[] = $this->hash[$key];
}
}

return $results;
}






public function getIterator()
{
$results = [];
foreach ($this->hash as $key) {
$results[] = $this->hash[$key];
}

return new \ArrayIterator($results);
}






public function count()
{
return count($this->hash);
}








public function offsetExists($key)
{
return $key < count($this->hash);
}








public function offsetGet($key)
{
$i = -1;
foreach ($this->hash as $obj) {
if ($key === ++$i) {
return $this->hash[$obj];
}
}

return null;
}

public function offsetUnset($key)
{
throw new \RuntimeException('Not implemented');
}

public function offsetSet($key, $value)
{
throw new \RuntimeException('Not implemented');
}
}
<?php
namespace GuzzleHttp;




class Collection implements
\ArrayAccess,
\IteratorAggregate,
\Countable,
ToArrayInterface
{
use HasDataTrait;




public function __construct(array $data = [])
{
$this->data = $data;
}












public static function fromConfig(
array $config = [],
array $defaults = [],
array $required = []
) {
$data = $config + $defaults;

if ($missing = array_diff($required, array_keys($data))) {
throw new \InvalidArgumentException(
'Config is missing the following keys: ' .
implode(', ', $missing));
}

return new self($data);
}




public function clear()
{
$this->data = [];
}








public function get($key)
{
return isset($this->data[$key]) ? $this->data[$key] : null;
}







public function set($key, $value)
{
$this->data[$key] = $value;
}









public function add($key, $value)
{
if (!array_key_exists($key, $this->data)) {
$this->data[$key] = $value;
} elseif (is_array($this->data[$key])) {
$this->data[$key][] = $value;
} else {
$this->data[$key] = array($this->data[$key], $value);
}
}






public function remove($key)
{
unset($this->data[$key]);
}






public function getKeys()
{
return array_keys($this->data);
}








public function hasKey($key)
{
return array_key_exists($key, $this->data);
}









public function hasValue($value)
{
return array_search($value, $this->data, true);
}






public function replace(array $data)
{
$this->data = $data;
}






public function merge($data)
{
foreach ($data as $key => $value) {
$this->add($key, $value);
}
}







public function overwriteWith($data)
{
if (is_array($data)) {
$this->data = $data + $this->data;
} elseif ($data instanceof Collection) {
$this->data = $data->toArray() + $this->data;
} else {
foreach ($data as $key => $value) {
$this->data[$key] = $value;
}
}
}

















public function map(callable $closure, array $context = [])
{
$collection = new static();
foreach ($this as $key => $value) {
$collection[$key] = $closure($key, $value, $context);
}

return $collection;
}














public function filter(callable $closure)
{
$collection = new static();
foreach ($this->data as $key => $value) {
if ($closure($key, $value)) {
$collection[$key] = $value;
}
}

return $collection;
}
}
<?php
namespace GuzzleHttp;











class QueryParser
{
private $duplicates;
private $numericIndices;








public function parseInto(Query $query, $str, $urlEncoding = true)
{
if ($str === '') {
return;
}

$result = [];
$this->duplicates = false;
$this->numericIndices = true;
$decoder = self::getDecoder($urlEncoding);

foreach (explode('&', $str) as $kvp) {

$parts = explode('=', $kvp, 2);
$key = $decoder($parts[0]);
$value = isset($parts[1]) ? $decoder($parts[1]) : null;


 if (strpos($key, '[') !== false) {
$this->parsePhpValue($key, $value, $result);
continue;
}

if (!isset($result[$key])) {
$result[$key] = $value;
} else {
$this->duplicates = true;
if (!is_array($result[$key])) {
$result[$key] = [$result[$key]];
}
$result[$key][] = $value;
}
}

$query->replace($result);

if (!$this->numericIndices) {
$query->setAggregator(Query::phpAggregator(false));
} elseif ($this->duplicates) {
$query->setAggregator(Query::duplicateAggregator());
}
}








private static function getDecoder($type)
{
if ($type === true) {
return function ($value) {
return rawurldecode(str_replace('+', ' ', $value));
};
} elseif ($type == Query::RFC3986) {
return 'rawurldecode';
} elseif ($type == Query::RFC1738) {
return 'urldecode';
} else {
return function ($str) { return $str; };
}
}








private function parsePhpValue($key, $value, array &$result)
{
$node =& $result;
$keyBuffer = '';

for ($i = 0, $t = strlen($key); $i < $t; $i++) {
switch ($key[$i]) {
case '[':
if ($keyBuffer) {
$this->prepareNode($node, $keyBuffer);
$node =& $node[$keyBuffer];
$keyBuffer = '';
}
break;
case ']':
$k = $this->cleanKey($node, $keyBuffer);
$this->prepareNode($node, $k);
$node =& $node[$k];
$keyBuffer = '';
break;
default:
$keyBuffer .= $key[$i];
break;
}
}

if (isset($node)) {
$this->duplicates = true;
$node[] = $value;
} else {
$node = $value;
}
}









private function prepareNode(&$node, $key)
{
if (!isset($node[$key])) {
$node[$key] = null;
} elseif (!is_array($node[$key])) {
$node[$key] = [$node[$key]];
}
}




private function cleanKey($node, $key)
{
if ($key === '') {
$key = $node ? (string) count($node) : 0;

 
 $this->numericIndices = false;
}

return $key;
}
}
<?php
namespace GuzzleHttp;

use GuzzleHttp\Event\BeforeEvent;
use GuzzleHttp\Event\ErrorEvent;
use GuzzleHttp\Event\CompleteEvent;
use GuzzleHttp\Event\EndEvent;
use GuzzleHttp\Exception\StateException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Message\FutureResponse;
use GuzzleHttp\Message\MessageFactoryInterface;
use GuzzleHttp\Ring\Future\FutureInterface;




class RequestFsm
{
private $handler;
private $mf;
private $maxTransitions;

public function __construct(
callable $handler,
MessageFactoryInterface $messageFactory,
$maxTransitions = 200
) {
$this->mf = $messageFactory;
$this->maxTransitions = $maxTransitions;
$this->handler = $handler;
}









public function __invoke(Transaction $trans)
{
$trans->_transitionCount = 0;

if (!$trans->state) {
$trans->state = 'before';
}

transition:

if (++$trans->_transitionCount > $this->maxTransitions) {
throw new StateException("Too many state transitions were "
. "encountered ({$trans->_transitionCount}). This likely "
. "means that a combination of event listeners are in an "
. "infinite loop.");
}

switch ($trans->state) {
case 'before': goto before;
case 'complete': goto complete;
case 'error': goto error;
case 'retry': goto retry;
case 'send': goto send;
case 'end': goto end;
default: throw new StateException("Invalid state: {$trans->state}");
}

before: {
try {
$trans->request->getEmitter()->emit('before', new BeforeEvent($trans));
$trans->state = 'send';
if ((bool) $trans->response) {
$trans->state = 'complete';
}
} catch (\Exception $e) {
$trans->state = 'error';
$trans->exception = $e;
}
goto transition;
}

complete: {
try {
if ($trans->response instanceof FutureInterface) {

 
 return;
}
$trans->state = 'end';
$trans->response->setEffectiveUrl($trans->request->getUrl());
$trans->request->getEmitter()->emit('complete', new CompleteEvent($trans));
} catch (\Exception $e) {
$trans->state = 'error';
$trans->exception = $e;
}
goto transition;
}

error: {
try {

 $trans->exception = RequestException::wrapException(
$trans->request, $trans->exception
);
$trans->state = 'end';
$trans->request->getEmitter()->emit('error', new ErrorEvent($trans));

 if (!$trans->exception && $trans->state !== 'retry') {
$trans->state = 'complete';
}
} catch (\Exception $e) {
$trans->state = 'end';
$trans->exception = $e;
}
goto transition;
}

retry: {
$trans->retries++;
$trans->response = null;
$trans->exception = null;
$trans->state = 'before';
goto transition;
}

send: {
$fn = $this->handler;
$trans->response = FutureResponse::proxy(
$fn(RingBridge::prepareRingRequest($trans)),
function ($value) use ($trans) {
RingBridge::completeRingResponse($trans, $value, $this->mf, $this);
$this($trans);
return $trans->response;
}
);
return;
}

end: {
$trans->request->getEmitter()->emit('end', new EndEvent($trans));

 
 if ($trans->exception) {
if (!($trans->exception instanceof RequestException)) {
$trans->exception = RequestException::wrapException(
$trans->request, $trans->exception
);
}
throw $trans->exception;
}
}
}
}
<?php
namespace GuzzleHttp\Message;

use GuzzleHttp\Exception\ParseException;
use GuzzleHttp\Exception\XmlParseException;
use GuzzleHttp\Stream\StreamInterface;
use GuzzleHttp\Utils;




class Response extends AbstractMessage implements ResponseInterface
{

private static $statusTexts = [
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',
226 => 'IM Used',
300 => 'Multiple Choices',
301 => 'Moved Permanently',
302 => 'Found',
303 => 'See Other',
304 => 'Not Modified',
305 => 'Use Proxy',
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',
422 => 'Unprocessable Entity',
423 => 'Locked',
424 => 'Failed Dependency',
425 => 'Reserved for WebDAV advanced collections expired proposal',
426 => 'Upgrade required',
428 => 'Precondition Required',
429 => 'Too Many Requests',
431 => 'Request Header Fields Too Large',
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 (Experimental)',
507 => 'Insufficient Storage',
508 => 'Loop Detected',
510 => 'Not Extended',
511 => 'Network Authentication Required',
];


private $reasonPhrase;


private $statusCode;


private $effectiveUrl;









public function __construct(
$statusCode,
array $headers = [],
StreamInterface $body = null,
array $options = []
) {
$this->statusCode = (int) $statusCode;
$this->handleOptions($options);


 if (!$this->reasonPhrase &&
isset(self::$statusTexts[$this->statusCode])
) {
$this->reasonPhrase = self::$statusTexts[$this->statusCode];
}

if ($headers) {
$this->setHeaders($headers);
}

if ($body) {
$this->setBody($body);
}
}

public function getStatusCode()
{
return $this->statusCode;
}

public function setStatusCode($code)
{
return $this->statusCode = (int) $code;
}

public function getReasonPhrase()
{
return $this->reasonPhrase;
}

public function setReasonPhrase($phrase)
{
return $this->reasonPhrase = $phrase;
}

public function json(array $config = [])
{
try {
return Utils::jsonDecode(
(string) $this->getBody(),
isset($config['object']) ? !$config['object'] : true,
512,
isset($config['big_int_strings']) ? JSON_BIGINT_AS_STRING : 0
);
} catch (\InvalidArgumentException $e) {
throw new ParseException(
$e->getMessage(),
$this
);
}
}

public function xml(array $config = [])
{
$disableEntities = libxml_disable_entity_loader(true);
$internalErrors = libxml_use_internal_errors(true);

try {

 $xml = new \SimpleXMLElement(
(string) $this->getBody() ?: '<root />',
isset($config['libxml_options']) ? $config['libxml_options'] : LIBXML_NONET,
false,
isset($config['ns']) ? $config['ns'] : '',
isset($config['ns_is_prefix']) ? $config['ns_is_prefix'] : false
);
libxml_disable_entity_loader($disableEntities);
libxml_use_internal_errors($internalErrors);
} catch (\Exception $e) {
libxml_disable_entity_loader($disableEntities);
libxml_use_internal_errors($internalErrors);
throw new XmlParseException(
'Unable to parse response body into XML: ' . $e->getMessage(),
$this,
$e,
(libxml_get_last_error()) ?: null
);
}

return $xml;
}

public function getEffectiveUrl()
{
return $this->effectiveUrl;
}

public function setEffectiveUrl($url)
{
$this->effectiveUrl = $url;
}







protected function handleOptions(array &$options = [])
{
parent::handleOptions($options);
if (isset($options['reason_phrase'])) {
$this->reasonPhrase = $options['reason_phrase'];
}
}
}
<?php
namespace GuzzleHttp\Message;

use GuzzleHttp\Event\HasEmitterInterface;
use GuzzleHttp\Query;




interface RequestInterface extends MessageInterface, HasEmitterInterface
{










public function setUrl($url);






public function getUrl();







public function getResource();







public function getQuery();






public function setQuery($query);






public function getMethod();






public function setMethod($method);






public function getScheme();






public function setScheme($scheme);






public function getPort();








public function setPort($port);






public function getHost();










public function setHost($host);






public function getPath();






public function setPath($path);






public function getConfig();
}
<?php
namespace GuzzleHttp\Message;

use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Cookie\CookieJarInterface;
use GuzzleHttp\Event\ListenerAttacherTrait;
use GuzzleHttp\Post\PostBody;
use GuzzleHttp\Post\PostFile;
use GuzzleHttp\Post\PostFileInterface;
use GuzzleHttp\Query;
use GuzzleHttp\Stream\Stream;
use GuzzleHttp\Subscriber\Cookie;
use GuzzleHttp\Subscriber\HttpError;
use GuzzleHttp\Subscriber\Redirect;
use GuzzleHttp\Url;
use \InvalidArgumentException as Iae;




class MessageFactory implements MessageFactoryInterface
{
use ListenerAttacherTrait;


private $errorPlugin;


private $redirectPlugin;


private $customOptions;


private static $configMap = [
'connect_timeout' => 1, 'timeout' => 1, 'verify' => 1, 'ssl_key' => 1,
'cert' => 1, 'proxy' => 1, 'debug' => 1, 'save_to' => 1, 'stream' => 1,
'expect' => 1, 'future' => 1
];


private static $defaultRedirect = [
'max' => 5,
'strict' => false,
'referer' => false,
'protocols' => ['http', 'https']
];







public function __construct(array $customOptions = [])
{
$this->errorPlugin = new HttpError();
$this->redirectPlugin = new Redirect();
$this->customOptions = $customOptions;
}

public function createResponse(
$statusCode,
array $headers = [],
$body = null,
array $options = []
) {
if (null !== $body) {
$body = Stream::factory($body);
}

return new Response($statusCode, $headers, $body, $options);
}

public function createRequest($method, $url, array $options = [])
{

 
 if (isset($options['version'])) {
$options['config']['protocol_version'] = $options['version'];
unset($options['version']);
}

$request = new Request($method, $url, [], null,
isset($options['config']) ? $options['config'] : []);

unset($options['config']);


 if ($method == 'POST'
&& !isset($options['body'])
&& !isset($options['json'])
) {
$options['body'] = [];
}

if ($options) {
$this->applyOptions($request, $options);
}

return $request;
}









public function fromMessage($message)
{
static $parser;
if (!$parser) {
$parser = new MessageParser();
}


 if (strtoupper(substr($message, 0, 4)) == 'HTTP') {
$data = $parser->parseResponse($message);
return $this->createResponse(
$data['code'],
$data['headers'],
$data['body'] === '' ? null : $data['body'],
$data
);
}


 if (!($data = ($parser->parseRequest($message)))) {
throw new \InvalidArgumentException('Unable to parse request');
}

return $this->createRequest(
$data['method'],
Url::buildUrl($data['request_url']),
[
'headers' => $data['headers'],
'body' => $data['body'] === '' ? null : $data['body'],
'config' => [
'protocol_version' => $data['protocol_version']
]
]
);
}








protected function addPostData(RequestInterface $request, array $body)
{
static $fields = ['string' => true, 'array' => true, 'NULL' => true,
'boolean' => true, 'double' => true, 'integer' => true];

$post = new PostBody();
foreach ($body as $key => $value) {
if (isset($fields[gettype($value)])) {
$post->setField($key, $value);
} elseif ($value instanceof PostFileInterface) {
$post->addFile($value);
} else {
$post->addFile(new PostFile($key, $value));
}
}

if ($request->getHeader('Content-Type') == 'multipart/form-data') {
$post->forceMultipartUpload(true);
}

$request->setBody($post);
}

protected function applyOptions(
RequestInterface $request,
array $options = []
) {
$config = $request->getConfig();
$emitter = $request->getEmitter();

foreach ($options as $key => $value) {

if (isset(self::$configMap[$key])) {
$config[$key] = $value;
continue;
}

switch ($key) {

case 'allow_redirects':

if ($value === false) {
continue;
}

if ($value === true) {
$value = self::$defaultRedirect;
} elseif (!is_array($value)) {
throw new Iae('allow_redirects must be true, false, or array');
} else {

 $value += self::$defaultRedirect;
}

$config['redirect'] = $value;
$emitter->attach($this->redirectPlugin);
break;

case 'decode_content':

if ($value === false) {
continue;
}

$config['decode_content'] = true;
if ($value !== true) {
$request->setHeader('Accept-Encoding', $value);
}
break;

case 'headers':

if (!is_array($value)) {
throw new Iae('header value must be an array');
}
foreach ($value as $k => $v) {
$request->setHeader($k, $v);
}
break;

case 'exceptions':

if ($value === true) {
$emitter->attach($this->errorPlugin);
}
break;

case 'body':

if (is_array($value)) {
$this->addPostData($request, $value);
} elseif ($value !== null) {
$request->setBody(Stream::factory($value));
}
break;

case 'auth':

if (!$value) {
continue;
}

if (is_array($value)) {
$type = isset($value[2]) ? strtolower($value[2]) : 'basic';
} else {
$type = strtolower($value);
}

$config['auth'] = $value;

if ($type == 'basic') {
$request->setHeader(
'Authorization',
'Basic ' . base64_encode("$value[0]:$value[1]")
);
} elseif ($type == 'digest') {

 $config->setPath('curl/' . CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
$config->setPath('curl/' . CURLOPT_USERPWD, "$value[0]:$value[1]");
}
break;

case 'query':

if ($value instanceof Query) {
$original = $request->getQuery();

 
 
 $value->overwriteWith($original->toArray());
$request->setQuery($value);
} elseif (is_array($value)) {

 $query = $request->getQuery();
foreach ($value as $k => $v) {
if (!isset($query[$k])) {
$query[$k] = $v;
}
}
} else {
throw new Iae('query must be an array or Query object');
}
break;

case 'cookies':

if ($value === true) {
static $cookie = null;
if (!$cookie) {
$cookie = new Cookie();
}
$emitter->attach($cookie);
} elseif (is_array($value)) {
$emitter->attach(
new Cookie(CookieJar::fromArray($value, $request->getHost()))
);
} elseif ($value instanceof CookieJarInterface) {
$emitter->attach(new Cookie($value));
} elseif ($value !== false) {
throw new Iae('cookies must be an array, true, or CookieJarInterface');
}
break;

case 'events':

if (!is_array($value)) {
throw new Iae('events must be an array');
}

$this->attachListeners($request,
$this->prepareListeners(
$value,
['before', 'complete', 'error', 'progress', 'end']
)
);
break;

case 'subscribers':

if (!is_array($value)) {
throw new Iae('subscribers must be an array');
}

foreach ($value as $subscribers) {
$emitter->attach($subscribers);
}
break;

case 'json':

$request->setBody(Stream::factory(json_encode($value)));
if (!$request->hasHeader('Content-Type')) {
$request->setHeader('Content-Type', 'application/json');
}
break;

default:


 if (isset($this->customOptions[$key])) {
$fn = $this->customOptions[$key];
$fn($request, $value);
continue;
}

throw new Iae("No method can handle the {$key} config key");
}
}
}
}
<?php
namespace GuzzleHttp\Message;

use GuzzleHttp\Stream\StreamInterface;

abstract class AbstractMessage implements MessageInterface
{

private $headers = [];


private $headerNames = [];


private $body;


private $protocolVersion = '1.1';

public function __toString()
{
return static::getStartLineAndHeaders($this)
. "\r\n\r\n" . $this->getBody();
}

public function getProtocolVersion()
{
return $this->protocolVersion;
}

public function getBody()
{
return $this->body;
}

public function setBody(StreamInterface $body = null)
{
if ($body === null) {

 $this->removeHeader('Content-Length');
$this->removeHeader('Transfer-Encoding');
}

$this->body = $body;
}

public function addHeader($header, $value)
{
if (is_array($value)) {
$current = array_merge($this->getHeaderAsArray($header), $value);
} else {
$current = $this->getHeaderAsArray($header);
$current[] = (string) $value;
}

$this->setHeader($header, $current);
}

public function addHeaders(array $headers)
{
foreach ($headers as $name => $header) {
$this->addHeader($name, $header);
}
}

public function getHeader($header)
{
$name = strtolower($header);
return isset($this->headers[$name])
? implode(', ', $this->headers[$name])
: '';
}

public function getHeaderAsArray($header)
{
$name = strtolower($header);
return isset($this->headers[$name]) ? $this->headers[$name] : [];
}

public function getHeaders()
{
$headers = [];
foreach ($this->headers as $name => $values) {
$headers[$this->headerNames[$name]] = $values;
}

return $headers;
}

public function setHeader($header, $value)
{
$header = trim($header);
$name = strtolower($header);
$this->headerNames[$name] = $header;

if (is_array($value)) {
foreach ($value as &$v) {
$v = trim($v);
}
$this->headers[$name] = $value;
} else {
$this->headers[$name] = [trim($value)];
}
}

public function setHeaders(array $headers)
{
$this->headers = $this->headerNames = [];
foreach ($headers as $key => $value) {
$this->setHeader($key, $value);
}
}

public function hasHeader($header)
{
return isset($this->headers[strtolower($header)]);
}

public function removeHeader($header)
{
$name = strtolower($header);
unset($this->headers[$name], $this->headerNames[$name]);
}












public static function parseHeader(MessageInterface $message, $header)
{
static $trimmed = "\"'  \n\t\r";
$params = $matches = [];

foreach (self::normalizeHeader($message, $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 normalizeHeader(MessageInterface $message, $header)
{
$h = $message->getHeaderAsArray($header);
for ($i = 0, $total = count($h); $i < $total; $i++) {
if (strpos($h[$i], ',') === false) {
continue;
}
foreach (preg_split('/,(?=([^"]*"[^"]*")*[^"]*$)/', $h[$i]) as $v) {
$h[] = trim($v);
}
unset($h[$i]);
}

return $h;
}








public static function getStartLineAndHeaders(MessageInterface $message)
{
return static::getStartLine($message)
. self::getHeadersAsString($message);
}








public static function getHeadersAsString(MessageInterface $message)
{
$result = '';
foreach ($message->getHeaders() as $name => $values) {
$result .= "\r\n{$name}: " . implode(', ', $values);
}

return $result;
}









public static function getStartLine(MessageInterface $message)
{
if ($message instanceof RequestInterface) {
return trim($message->getMethod() . ' '
. $message->getResource())
. ' HTTP/' . $message->getProtocolVersion();
} elseif ($message instanceof ResponseInterface) {
return 'HTTP/' . $message->getProtocolVersion() . ' '
. $message->getStatusCode() . ' '
. $message->getReasonPhrase();
} else {
throw new \InvalidArgumentException('Unknown message type');
}
}









protected function handleOptions(array &$options)
{
if (isset($options['protocol_version'])) {
$this->protocolVersion = $options['protocol_version'];
}
}
}
<?php
namespace GuzzleHttp\Message;

use GuzzleHttp\Collection;
use GuzzleHttp\Event\HasEmitterTrait;
use GuzzleHttp\Subscriber\Prepare;
use GuzzleHttp\Url;




class Request extends AbstractMessage implements RequestInterface
{
use HasEmitterTrait;


private $url;


private $method;


private $transferOptions;











public function __construct(
$method,
$url,
$headers = [],
$body = null,
array $options = []
) {
$this->setUrl($url);
$this->method = strtoupper($method);
$this->handleOptions($options);
$this->transferOptions = new Collection($options);
$this->addPrepareEvent();

if ($body !== null) {
$this->setBody($body);
}

if ($headers) {
foreach ($headers as $key => $value) {
$this->addHeader($key, $value);
}
}
}

public function __clone()
{
if ($this->emitter) {
$this->emitter = clone $this->emitter;
}
$this->transferOptions = clone $this->transferOptions;
$this->url = clone $this->url;
}

public function setUrl($url)
{
$this->url = $url instanceof Url ? $url : Url::fromString($url);
$this->updateHostHeaderFromUrl();
}

public function getUrl()
{
return (string) $this->url;
}

public function setQuery($query)
{
$this->url->setQuery($query);
}

public function getQuery()
{
return $this->url->getQuery();
}

public function setMethod($method)
{
$this->method = strtoupper($method);
}

public function getMethod()
{
return $this->method;
}

public function getScheme()
{
return $this->url->getScheme();
}

public function setScheme($scheme)
{
$this->url->setScheme($scheme);
}

public function getPort()
{
return $this->url->getPort();
}

public function setPort($port)
{
$this->url->setPort($port);
$this->updateHostHeaderFromUrl();
}

public function getHost()
{
return $this->url->getHost();
}

public function setHost($host)
{
$this->url->setHost($host);
$this->updateHostHeaderFromUrl();
}

public function getPath()
{
return '/' . ltrim($this->url->getPath(), '/');
}

public function setPath($path)
{
$this->url->setPath($path);
}

public function getResource()
{
$resource = $this->getPath();
if ($query = (string) $this->url->getQuery()) {
$resource .= '?' . $query;
}

return $resource;
}

public function getConfig()
{
return $this->transferOptions;
}

protected function handleOptions(array &$options)
{
parent::handleOptions($options);

 
 if (isset($options['emitter'])) {
$this->emitter = $options['emitter'];
unset($options['emitter']);
}
}





private function addPrepareEvent()
{
static $subscriber;
if (!$subscriber) {
$subscriber = new Prepare();
}

$this->getEmitter()->attach($subscriber);
}

private function updateHostHeaderFromUrl()
{
$port = $this->url->getPort();
$scheme = $this->url->getScheme();
if ($host = $this->url->getHost()) {
if (($port == 80 && $scheme == 'http') ||
($port == 443 && $scheme == 'https')
) {
$this->setHeader('Host', $host);
} else {
$this->setHeader('Host', "{$host}:{$port}");
}
}
}
}
<?php
namespace GuzzleHttp\Message;




interface ResponseInterface extends MessageInterface
{








public function getStatusCode();






public function setStatusCode($code);












public function getReasonPhrase();









public function setReasonPhrase($phrase);







public function getEffectiveUrl();







public function setEffectiveUrl($url);





















public function json(array $config = []);
























public function xml(array $config = []);
}
<?php
namespace GuzzleHttp\Message;

use GuzzleHttp\Url;




interface MessageFactoryInterface
{













public function createResponse(
$statusCode,
array $headers = [],
$body = null,
array $options = []
);








































public function createRequest($method, $url, array $options = []);
}
<?php
namespace GuzzleHttp\Message;

use GuzzleHttp\Stream\StreamInterface;




interface MessageInterface
{





public function __toString();






public function getProtocolVersion();









public function setBody(StreamInterface $body = null);






public function getBody();














public function getHeaders();








public function getHeader($header);








public function getHeaderAsArray($header);










public function hasHeader($header);






public function removeHeader($header);








public function addHeader($header, $value);












public function addHeaders(array $headers);










public function setHeader($header, $value);










public function setHeaders(array $headers);
}
<?php
namespace GuzzleHttp\Message;












interface AppliesHeadersInterface
{






public function applyRequestHeaders(RequestInterface $request);
}
<?php
namespace GuzzleHttp\Message;




class MessageParser
{







public function parseRequest($message)
{
if (!($parts = $this->parseMessage($message))) {
return false;
}


 if (isset($parts['start_line'][2])) {
$startParts = explode('/', $parts['start_line'][2]);
$protocol = strtoupper($startParts[0]);
$version = isset($startParts[1]) ? $startParts[1] : '1.1';
} else {
$protocol = 'HTTP';
$version = '1.1';
}

$parsed = [
'method' => strtoupper($parts['start_line'][0]),
'protocol' => $protocol,
'protocol_version' => $version,
'headers' => $parts['headers'],
'body' => $parts['body']
];

$parsed['request_url'] = $this->getUrlPartsFromMessage(
(isset($parts['start_line'][1]) ? $parts['start_line'][1] : ''), $parsed);

return $parsed;
}








public function parseResponse($message)
{
if (!($parts = $this->parseMessage($message))) {
return false;
}

list($protocol, $version) = explode('/', trim($parts['start_line'][0]));

return [
'protocol' => $protocol,
'protocol_version' => $version,
'code' => $parts['start_line'][1],
'reason_phrase' => isset($parts['start_line'][2]) ? $parts['start_line'][2] : '',
'headers' => $parts['headers'],
'body' => $parts['body']
];
}








private function parseMessage($message)
{
if (!$message) {
return false;
}

$startLine = null;
$headers = [];
$body = '';


 $lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE);
for ($i = 0, $totalLines = count($lines); $i < $totalLines; $i += 2) {

$line = $lines[$i];


 if (empty($line)) {
if ($i < $totalLines - 1) {
$body = implode('', array_slice($lines, $i + 2));
}
break;
}


 if (!$startLine) {
$startLine = explode(' ', $line, 3);
} elseif (strpos($line, ':')) {
$parts = explode(':', $line, 2);
$key = trim($parts[0]);
$value = isset($parts[1]) ? trim($parts[1]) : '';
if (!isset($headers[$key])) {
$headers[$key] = $value;
} elseif (!is_array($headers[$key])) {
$headers[$key] = [$headers[$key], $value];
} else {
$headers[$key][] = $value;
}
}
}

return [
'start_line' => $startLine,
'headers' => $headers,
'body' => $body
];
}









private function getUrlPartsFromMessage($requestUrl, array $parts)
{

 $urlParts = ['path' => $requestUrl, 'scheme' => 'http'];


 if (isset($parts['headers']['Host'])) {
$urlParts['host'] = $parts['headers']['Host'];
} elseif (isset($parts['headers']['host'])) {
$urlParts['host'] = $parts['headers']['host'];
} else {
$urlParts['host'] = null;
}

if (false === strpos($urlParts['host'], ':')) {
$urlParts['port'] = '';
} else {
$hostParts = explode(':', $urlParts['host']);
$urlParts['host'] = trim($hostParts[0]);
$urlParts['port'] = (int) trim($hostParts[1]);
if ($urlParts['port'] == 443) {
$urlParts['scheme'] = 'https';
}
}


 $path = $urlParts['path'];
$qpos = strpos($path, '?');
if ($qpos) {
$urlParts['query'] = substr($path, $qpos + 1);
$urlParts['path'] = substr($path, 0, $qpos);
} else {
$urlParts['query'] = '';
}

return $urlParts;
}
}
<?php
namespace GuzzleHttp\Message;

use GuzzleHttp\Ring\Future\MagicFutureTrait;
use GuzzleHttp\Ring\Future\FutureInterface;
use GuzzleHttp\Stream\StreamInterface;















class FutureResponse implements ResponseInterface, FutureInterface
{
use MagicFutureTrait;











public static function proxy(
FutureInterface $future,
callable $onFulfilled = null,
callable $onRejected = null,
callable $onProgress = null
) {
return new FutureResponse(
$future->then($onFulfilled, $onRejected, $onProgress),
[$future, 'wait'],
[$future, 'cancel']
);
}

public function getStatusCode()
{
return $this->_value->getStatusCode();
}

public function setStatusCode($code)
{
$this->_value->setStatusCode($code);
}

public function getReasonPhrase()
{
return $this->_value->getReasonPhrase();
}

public function setReasonPhrase($phrase)
{
$this->_value->setReasonPhrase($phrase);
}

public function getEffectiveUrl()
{
return $this->_value->getEffectiveUrl();
}

public function setEffectiveUrl($url)
{
$this->_value->setEffectiveUrl($url);
}

public function json(array $config = [])
{
return $this->_value->json($config);
}

public function xml(array $config = [])
{
return $this->_value->xml($config);
}

public function __toString()
{
try {
return $this->_value->__toString();
} catch (\Exception $e) {
trigger_error($e->getMessage(), E_USER_WARNING);
return '';
}
}

public function getProtocolVersion()
{
return $this->_value->getProtocolVersion();
}

public function setBody(StreamInterface $body = null)
{
$this->_value->setBody($body);
}

public function getBody()
{
return $this->_value->getBody();
}

public function getHeaders()
{
return $this->_value->getHeaders();
}

public function getHeader($header)
{
return $this->_value->getHeader($header);
}

public function getHeaderAsArray($header)
{
return $this->_value->getHeaderAsArray($header);
}

public function hasHeader($header)
{
return $this->_value->hasHeader($header);
}

public function removeHeader($header)
{
$this->_value->removeHeader($header);
}

public function addHeader($header, $value)
{
$this->_value->addHeader($header, $value);
}

public function addHeaders(array $headers)
{
$this->_value->addHeaders($headers);
}

public function setHeader($header, $value)
{
$this->_value->setHeader($header, $value);
}

public function setHeaders(array $headers)
{
$this->_value->setHeaders($headers);
}
}
<?php
namespace GuzzleHttp;

use GuzzleHttp\Ring\Client\CurlHandler;
use GuzzleHttp\Ring\Client\CurlMultiHandler;
use GuzzleHttp\Ring\Client\StreamHandler;
use GuzzleHttp\Ring\Client\Middleware;




final class Utils
{

















public static function getPath($data, $path)
{
$path = explode('/', $path);

while (null !== ($part = array_shift($path))) {
if (!is_array($data) || !isset($data[$part])) {
return null;
}
$data = $data[$part];
}

return $data;
}























public static function setPath(&$data, $path, $value)
{
$queue = explode('/', $path);

 if (count($queue) === 1) {
$data[$path] = $value;
return;
}

$current =& $data;
while (null !== ($key = array_shift($queue))) {
if (!is_array($current)) {
throw new \RuntimeException("Trying to setPath {$path}, but "
. "{$key} is set and is not an array");
} elseif (!$queue) {
if ($key == '[]') {
$current[] = $value;
} else {
$current[$key] = $value;
}
} elseif (isset($current[$key])) {
$current =& $current[$key];
} else {
$current[$key] = [];
$current =& $current[$key];
}
}
}









public static function uriTemplate($template, array $variables)
{
if (function_exists('\\uri_template')) {
return \uri_template($template, $variables);
}

static $uriTemplate;
if (!$uriTemplate) {
$uriTemplate = new UriTemplate();
}

return $uriTemplate->expand($template, $variables);
}















public static function jsonDecode($json, $assoc = false, $depth = 512, $options = 0)
{
static $jsonErrors = [
JSON_ERROR_DEPTH => 'JSON_ERROR_DEPTH - Maximum stack depth exceeded',
JSON_ERROR_STATE_MISMATCH => 'JSON_ERROR_STATE_MISMATCH - Underflow or the modes mismatch',
JSON_ERROR_CTRL_CHAR => 'JSON_ERROR_CTRL_CHAR - Unexpected control character found',
JSON_ERROR_SYNTAX => 'JSON_ERROR_SYNTAX - Syntax error, malformed JSON',
JSON_ERROR_UTF8 => 'JSON_ERROR_UTF8 - Malformed UTF-8 characters, possibly incorrectly encoded'
];

$data = \json_decode($json, $assoc, $depth, $options);

if (JSON_ERROR_NONE !== json_last_error()) {
$last = json_last_error();
throw new \InvalidArgumentException(
'Unable to parse JSON data: '
. (isset($jsonErrors[$last])
? $jsonErrors[$last]
: 'Unknown error')
);
}

return $data;
}






public static function getDefaultUserAgent()
{
static $defaultAgent = '';
if (!$defaultAgent) {
$defaultAgent = 'Guzzle/' . ClientInterface::VERSION;
if (extension_loaded('curl')) {
$defaultAgent .= ' curl/' . curl_version()['version'];
}
$defaultAgent .= ' PHP/' . PHP_VERSION;
}

return $defaultAgent;
}






public static function getDefaultHandler()
{
$default = $future = null;

if (extension_loaded('curl')) {
$config = [
'select_timeout' => getenv('GUZZLE_CURL_SELECT_TIMEOUT') ?: 1
];
if ($maxHandles = getenv('GUZZLE_CURL_MAX_HANDLES')) {
$config['max_handles'] = $maxHandles;
}
if (function_exists('curl_reset')) {
$default = new CurlHandler();
$future = new CurlMultiHandler($config);
} else {
$default = new CurlMultiHandler($config);
}
}

if (ini_get('allow_url_fopen')) {
$default = !$default
? new StreamHandler()
: Middleware::wrapStreaming($default, new StreamHandler());
} elseif (!$default) {
throw new \RuntimeException('Guzzle requires cURL, the '
. 'allow_url_fopen ini setting, or a custom HTTP handler.');
}

return $future ? Middleware::wrapFuture($default, $future) : $default;
}
}
<?php
namespace GuzzleHttp\Exception;

use GuzzleHttp\Message\RequestInterface;
use GuzzleHttp\Message\ResponseInterface;
use GuzzleHttp\Ring\Exception\ConnectException;
use GuzzleHttp\Exception\ConnectException as HttpConnectException;
use GuzzleHttp\Ring\Future\FutureInterface;




class RequestException extends TransferException
{

private $request;


private $response;

public function __construct(
$message,
RequestInterface $request,
ResponseInterface $response = null,
\Exception $previous = null
) {

 $code = $response && !($response instanceof FutureInterface)
? $response->getStatusCode()
: 0;
parent::__construct($message, $code, $previous);
$this->request = $request;
$this->response = $response;
}









public static function wrapException(RequestInterface $request, \Exception $e)
{
if ($e instanceof RequestException) {
return $e;
} elseif ($e instanceof ConnectException) {
return new HttpConnectException($e->getMessage(), $request, null, $e);
} else {
return new RequestException($e->getMessage(), $request, null, $e);
}
}










public static function create(
RequestInterface $request,
ResponseInterface $response = null,
\Exception $previous = null
) {
if (!$response) {
return new self('Error completing request', $request, null, $previous);
}

$level = floor($response->getStatusCode() / 100);
if ($level == '4') {
$label = 'Client error response';
$className = __NAMESPACE__ . '\\ClientException';
} elseif ($level == '5') {
$label = 'Server error response';
$className = __NAMESPACE__ . '\\ServerException';
} else {
$label = 'Unsuccessful response';
$className = __CLASS__;
}

$message = $label . ' [url] ' . $request->getUrl()
. ' [status code] ' . $response->getStatusCode()
. ' [reason phrase] ' . $response->getReasonPhrase();

return new $className($message, $request, $response, $previous);
}






public function getRequest()
{
return $this->request;
}






public function getResponse()
{
return $this->response;
}






public function hasResponse()
{
return $this->response !== null;
}
}
<?php
namespace GuzzleHttp\Exception;

class TransferException extends \RuntimeException {}
<?php
namespace GuzzleHttp\Exception;




class ClientException extends BadResponseException {}
<?php
namespace GuzzleHttp\Exception;

class StateException extends TransferException {};
<?php
namespace GuzzleHttp\Exception;

class CouldNotRewindStreamException extends RequestException {}
<?php
namespace GuzzleHttp\Exception;




class ServerException extends BadResponseException {}
<?php
namespace GuzzleHttp\Exception;

use GuzzleHttp\Message\ResponseInterface;




class ParseException extends TransferException
{

private $response;

public function __construct(
$message = '',
ResponseInterface $response = null,
\Exception $previous = null
) {
parent::__construct($message, 0, $previous);
$this->response = $response;
}





public function getResponse()
{
return $this->response;
}
}
<?php
namespace GuzzleHttp\Exception;

class ConnectException extends RequestException {}
<?php

namespace GuzzleHttp\Exception;

use GuzzleHttp\Message\ResponseInterface;




class XmlParseException extends ParseException
{

protected $error;

public function __construct(
$message = '',
ResponseInterface $response = null,
\Exception $previous = null,
\LibXMLError $error = null
) {
parent::__construct($message, $response, $previous);
$this->error = $error;
}






public function getError()
{
return $this->error;
}
}
<?php
namespace GuzzleHttp\Exception;

class TooManyRedirectsException extends RequestException {}
<?php
namespace GuzzleHttp\Exception;




class BadResponseException extends RequestException {}
<?php
namespace GuzzleHttp;





trait HasDataTrait
{

protected $data = [];

public function getIterator()
{
return new \ArrayIterator($this->data);
}

public function offsetGet($offset)
{
return isset($this->data[$offset]) ? $this->data[$offset] : null;
}

public function offsetSet($offset, $value)
{
$this->data[$offset] = $value;
}

public function offsetExists($offset)
{
return isset($this->data[$offset]);
}

public function offsetUnset($offset)
{
unset($this->data[$offset]);
}

public function toArray()
{
return $this->data;
}

public function count()
{
return count($this->data);
}









public function getPath($path)
{
return Utils::getPath($this->data, $path);
}











public function setPath($path, $value)
{
Utils::setPath($this->data, $path, $value);
}
}
<?php
namespace GuzzleHttp\Cookie;

use GuzzleHttp\Message\RequestInterface;
use GuzzleHttp\Message\ResponseInterface;
use GuzzleHttp\ToArrayInterface;




class CookieJar implements CookieJarInterface, ToArrayInterface
{

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)
{
if (substr($value, 0, 1) !== '"' &&
substr($value, -1, 1) !== '"' &&
strpbrk($value, ';,')
) {
$value = '"' . $value . '"';
}

return $value;
}

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 ($path, $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)
{

 $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->getHeaderAsArray('Set-Cookie')) {
foreach ($cookieHeader as $cookie) {
$sc = SetCookie::fromString($cookie);
if (!$sc->getDomain()) {
$sc->setDomain($request->getHost());
}
$this->setCookie($sc);
}
}
}

public function addCookieHeader(RequestInterface $request)
{
$values = [];
$scheme = $request->getScheme();
$host = $request->getHost();
$path = $request->getPath();

foreach ($this->cookies as $cookie) {
if ($cookie->matchesPath($path) &&
$cookie->matchesDomain($host) &&
!$cookie->isExpired() &&
(!$cookie->getSecure() || $scheme == 'https')
) {
$values[] = $cookie->getName() . '='
. self::getCookieValue($cookie->getValue());
}
}

if ($values) {
$request->setHeader('Cookie', implode('; ', $values));
}
}







private function removeCookieIfEmpty(SetCookie $cookie)
{
$cookieValue = $cookie->getValue();
if ($cookieValue === null || $cookieValue === '') {
$this->clear(
$cookie->getDomain(),
$cookie->getPath(),
$cookie->getName()
);
}
}
}
<?php
namespace GuzzleHttp\Cookie;

use GuzzleHttp\ToArrayInterface;




class SetCookie implements ToArrayInterface
{

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) || !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($path)
{
return !$this->getPath() || 0 === stripos($path, $this->getPath());
}








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) . '$/i', $domain);
}






public function isExpired()
{
return $this->getExpires() && 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("/[=,; \t\r\n\013\014]/", $name)) {
return "Cookie name must not cannot invalid characters: =,; \\t\\r\\n\\013\\014";
}


 $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 GuzzleHttp\Utils;




class FileCookieJar extends CookieJar
{

private $filename;








public function __construct($cookieFile)
{
$this->filename = $cookieFile;

if (file_exists($cookieFile)) {
$this->load($cookieFile);
}
}




public function __destruct()
{
$this->save($this->filename);
}







public function save($filename)
{
$json = [];
foreach ($this as $cookie) {
if ($cookie->getExpires() && !$cookie->getDiscard()) {
$json[] = $cookie->toArray();
}
}

if (false === file_put_contents($filename, json_encode($json))) {

 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}");

 }

$data = Utils::jsonDecode($json, true);
if (is_array($data)) {
foreach (Utils::jsonDecode($json, true) as $cookie) {
$this->setCookie(new SetCookie($cookie));
}
} elseif (strlen($data)) {
throw new \RuntimeException("Invalid cookie file: {$filename}");
}
}
}
<?php
namespace GuzzleHttp\Cookie;

use GuzzleHttp\Utils;




class SessionCookieJar extends CookieJar
{

private $sessionKey;






public function __construct($sessionKey)
{
$this->sessionKey = $sessionKey;
$this->load();
}




public function __destruct()
{
$this->save();
}




public function save()
{
$json = [];
foreach ($this as $cookie) {
if ($cookie->getExpires() && !$cookie->getDiscard()) {
$json[] = $cookie->toArray();
}
}

$_SESSION[$this->sessionKey] = json_encode($json);
}




protected function load()
{
$cookieJar = isset($_SESSION[$this->sessionKey])
? $_SESSION[$this->sessionKey]
: null;

$data = Utils::jsonDecode($cookieJar, 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;

use GuzzleHttp\Message\RequestInterface;
use GuzzleHttp\Message\ResponseInterface;











interface CookieJarInterface extends \Countable, \IteratorAggregate
{








public function addCookieHeader(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();
}
<?php
namespace GuzzleHttp\Event;









interface SubscriberInterface
{



















public function getEvents();
}
<?php
namespace GuzzleHttp\Event;

use GuzzleHttp\Message\ResponseInterface;








class BeforeEvent extends AbstractRequestEvent
{





public function intercept(ResponseInterface $response)
{
$this->transaction->response = $response;
$this->transaction->exception = null;
$this->stopPropagation();
}
}
<?php
namespace GuzzleHttp\Event;

use GuzzleHttp\Transaction;












class ProgressEvent extends AbstractRequestEvent
{

public $downloadSize;


public $downloaded;


public $uploadSize;


public $uploaded;








public function __construct(
Transaction $transaction,
$downloadSize,
$downloaded,
$uploadSize,
$uploaded
) {
parent::__construct($transaction);
$this->downloadSize = $downloadSize;
$this->downloaded = $downloaded;
$this->uploadSize = $uploadSize;
$this->uploaded = $uploaded;
}
}
<?php
namespace GuzzleHttp\Event;




interface HasEmitterInterface
{





public function getEmitter();
}
<?php
namespace GuzzleHttp\Event;











class EndEvent extends AbstractTransferEvent
{








public function getException()
{
return $this->transaction->exception;
}
}
<?php
namespace GuzzleHttp\Event;

use GuzzleHttp\Message\ResponseInterface;
use GuzzleHttp\Ring\Future\FutureInterface;




abstract class AbstractTransferEvent extends AbstractRequestEvent
{









public function getTransferInfo($name = null)
{
if (!$name) {
return $this->transaction->transferInfo;
}

return isset($this->transaction->transferInfo[$name])
? $this->transaction->transferInfo[$name]
: null;
}






public function hasResponse()
{
return !($this->transaction->response instanceof FutureInterface);
}






public function getResponse()
{
return $this->hasResponse() ? $this->transaction->response : null;
}






public function intercept(ResponseInterface $response)
{
$this->transaction->response = $response;
$this->transaction->exception = null;
$this->stopPropagation();
}
}
<?php
namespace GuzzleHttp\Event;




abstract class AbstractEvent implements EventInterface
{
private $propagationStopped = false;

public function isPropagationStopped()
{
return $this->propagationStopped;
}

public function stopPropagation()
{
$this->propagationStopped = true;
}
}
<?php
namespace GuzzleHttp\Event;

use GuzzleHttp\Exception\RequestException;











class ErrorEvent extends AbstractRetryableEvent
{





public function getException()
{
return $this->transaction->exception;
}
}
<?php
namespace GuzzleHttp\Event;
















class Emitter implements EmitterInterface
{

private $listeners = [];


private $sorted = [];

public function on($eventName, callable $listener, $priority = 0)
{
if ($priority === 'first') {
$priority = isset($this->listeners[$eventName])
? max(array_keys($this->listeners[$eventName])) + 1
: 1;
} elseif ($priority === 'last') {
$priority = isset($this->listeners[$eventName])
? min(array_keys($this->listeners[$eventName])) - 1
: -1;
}

$this->listeners[$eventName][$priority][] = $listener;
unset($this->sorted[$eventName]);
}

public function once($eventName, callable $listener, $priority = 0)
{
$onceListener = function (
EventInterface $event,
$eventName
) use (&$onceListener, $eventName, $listener, $priority) {
$this->removeListener($eventName, $onceListener);
$listener($event, $eventName);
};

$this->on($eventName, $onceListener, $priority);
}

public function removeListener($eventName, callable $listener)
{
if (empty($this->listeners[$eventName])) {
return;
}

foreach ($this->listeners[$eventName] as $priority => $listeners) {
if (false !== ($key = array_search($listener, $listeners, true))) {
unset(
$this->listeners[$eventName][$priority][$key],
$this->sorted[$eventName]
);
}
}
}

public function listeners($eventName = null)
{

 if ($eventName === null) {
foreach (array_keys($this->listeners) as $eventName) {
if (empty($this->sorted[$eventName])) {
$this->listeners($eventName);
}
}
return $this->sorted;
}


 if (empty($this->sorted[$eventName])) {
$this->sorted[$eventName] = [];
if (isset($this->listeners[$eventName])) {
krsort($this->listeners[$eventName], SORT_NUMERIC);
foreach ($this->listeners[$eventName] as $listeners) {
foreach ($listeners as $listener) {
$this->sorted[$eventName][] = $listener;
}
}
}
}

return $this->sorted[$eventName];
}

public function hasListeners($eventName)
{
return !empty($this->listeners[$eventName]);
}

public function emit($eventName, EventInterface $event)
{
if (isset($this->listeners[$eventName])) {
foreach ($this->listeners($eventName) as $listener) {
$listener($event, $eventName);
if ($event->isPropagationStopped()) {
break;
}
}
}

return $event;
}

public function attach(SubscriberInterface $subscriber)
{
foreach ($subscriber->getEvents() as $eventName => $listeners) {
if (is_array($listeners[0])) {
foreach ($listeners as $listener) {
$this->on(
$eventName,
[$subscriber, $listener[0]],
isset($listener[1]) ? $listener[1] : 0
);
}
} else {
$this->on(
$eventName,
[$subscriber, $listeners[0]],
isset($listeners[1]) ? $listeners[1] : 0
);
}
}
}

public function detach(SubscriberInterface $subscriber)
{
foreach ($subscriber->getEvents() as $eventName => $listener) {
$this->removeListener($eventName, [$subscriber, $listener[0]]);
}
}
}
<?php
namespace GuzzleHttp\Event;











class CompleteEvent extends AbstractRetryableEvent {}
<?php
namespace GuzzleHttp\Event;




trait HasEmitterTrait
{

private $emitter;

public function getEmitter()
{
if (!$this->emitter) {
$this->emitter = new Emitter();
}

return $this->emitter;
}
}
<?php
namespace GuzzleHttp\Event;




class AbstractRetryableEvent extends AbstractTransferEvent
{



















public function retry($afterDelay = 0)
{

 
 $this->transaction->state = 'retry';

if ($afterDelay) {
$this->transaction->request->getConfig()->set('delay', $afterDelay);
}

$this->stopPropagation();
}
}
<?php
namespace GuzzleHttp\Event;




final class RequestEvents
{

 const EARLY = 10000;
const LATE = -10000;


 const PREPARE_REQUEST = -100;
const SIGN_REQUEST = -10000;


 const VERIFY_RESPONSE = 100;
const REDIRECT_RESPONSE = 200;













public static function convertEventArray(
array $options,
array $events,
$handler
) {
foreach ($events as $name) {
if (!isset($options[$name])) {
$options[$name] = [$handler];
} elseif (is_callable($options[$name])) {
$options[$name] = [$options[$name], $handler];
} elseif (is_array($options[$name])) {
if (isset($options[$name]['fn'])) {
$options[$name] = [$options[$name], $handler];
} else {
$options[$name][] = $handler;
}
} else {
throw new \InvalidArgumentException('Invalid event format');
}
}

return $options;
}
}
<?php
namespace GuzzleHttp\Event;

use GuzzleHttp\Transaction;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Message\RequestInterface;




abstract class AbstractRequestEvent extends AbstractEvent
{

protected $transaction;




public function __construct(Transaction $transaction)
{
$this->transaction = $transaction;
}






public function getClient()
{
return $this->transaction->client;
}






public function getRequest()
{
return $this->transaction->request;
}






public function getRetryCount()
{
return $this->transaction->retries;
}




public function getTransaction()
{
return $this->transaction;
}
}
<?php
namespace GuzzleHttp\Event;




interface EmitterInterface
{













public function on($eventName, callable $listener, $priority = 0);










public function once($eventName, callable $listener, $priority = 0);







public function removeListener($eventName, callable $listener);














public function listeners($eventName = null);








public function hasListeners($eventName);












public function emit($eventName, EventInterface $event);









public function attach(SubscriberInterface $subscriber);






public function detach(SubscriberInterface $subscriber);
}
<?php
namespace GuzzleHttp\Event;






trait ListenerAttacherTrait
{









private function attachListeners(HasEmitterInterface $object, array $listeners)
{
$emitter = $object->getEmitter();
foreach ($listeners as $el) {
if ($el['once']) {
$emitter->once($el['name'], $el['fn'], $el['priority']);
} else {
$emitter->on($el['name'], $el['fn'], $el['priority']);
}
}
}












private function prepareListeners(array $source, array $events)
{
$listeners = [];
foreach ($events as $name) {
if (isset($source[$name])) {
$this->buildListener($name, $source[$name], $listeners);
}
}

return $listeners;
}












private function buildListener($name, $data, &$listeners)
{
static $defaults = ['priority' => 0, 'once' => false];


 if (is_callable($data)) {
$data = ['fn' => $data];
}


 if (isset($data['fn'])) {
$data['name'] = $name;
$listeners[] = $data + $defaults;
} elseif (is_array($data)) {
foreach ($data as $listenerData) {
$this->buildListener($name, $listenerData, $listeners);
}
} else {
throw new \InvalidArgumentException('Each event listener must be a '
. 'callable or an associative array containing a "fn" key.');
}
}
}
<?php
namespace GuzzleHttp\Event;





interface EventInterface
{






public function isPropagationStopped();





public function stopPropagation();
}
<?php
namespace GuzzleHttp;




interface ToArrayInterface
{





public function toArray();
}
<?php
namespace GuzzleHttp;




class Query extends Collection
{
const RFC3986 = 'RFC3986';
const RFC1738 = 'RFC1738';


private $encoding = 'rawurlencode';

private $aggregator;




















public static function fromString($query, $urlEncoding = true)
{
static $qp;
if (!$qp) {
$qp = new QueryParser();
}

$q = new static();

if ($urlEncoding !== true) {
$q->setEncodingType($urlEncoding);
}

$qp->parseInto($q, $query, $urlEncoding);

return $q;
}






public function __toString()
{
if (!$this->data) {
return '';
}


 static $defaultAggregator;

if (!$this->aggregator) {
if (!$defaultAggregator) {
$defaultAggregator = self::phpAggregator();
}
$this->aggregator = $defaultAggregator;
}

$result = '';
$aggregator = $this->aggregator;
$encoder = $this->encoding;

foreach ($aggregator($this->data) as $key => $values) {
foreach ($values as $value) {
if ($result) {
$result .= '&';
}
$result .= $encoder($key);
if ($value !== null) {
$result .= '=' . $encoder($value);
}
}
}

return $result;
}













public function setAggregator(callable $aggregator)
{
$this->aggregator = $aggregator;
}








public function setEncodingType($type)
{
switch ($type) {
case self::RFC3986:
$this->encoding = 'rawurlencode';
break;
case self::RFC1738:
$this->encoding = 'urlencode';
break;
case false:
$this->encoding = function ($v) { return $v; };
break;
default:
throw new \InvalidArgumentException('Invalid URL encoding type');
}
}









public static function duplicateAggregator()
{
return function (array $data) {
return self::walkQuery($data, '', function ($key, $prefix) {
return is_int($key) ? $prefix : "{$prefix}[{$key}]";
});
};
}










public static function phpAggregator($numericIndices = true)
{
return function (array $data) use ($numericIndices) {
return self::walkQuery(
$data,
'',
function ($key, $prefix) use ($numericIndices) {
return !$numericIndices && is_int($key)
? "{$prefix}[]"
: "{$prefix}[{$key}]";
}
);
};
}











public static function walkQuery(array $query, $keyPrefix, callable $prefixer)
{
$result = [];
foreach ($query as $key => $value) {
if ($keyPrefix) {
$key = $prefixer($key, $keyPrefix);
}
if (is_array($value)) {
$result += self::walkQuery($value, $key, $prefixer);
} elseif (isset($result[$key])) {
$result[$key][] = $value;
} else {
$result[$key] = array($value);
}
}

return $result;
}
}
<?php
namespace GuzzleHttp;






class UriTemplate
{

private $template;


private $variables;


private static $operatorHash = array(
'' => array('prefix' => '', 'joiner' => ',', 'query' => false),
'+' => array('prefix' => '', 'joiner' => ',', 'query' => false),
'#' => array('prefix' => '#', 'joiner' => ',', 'query' => false),
'.' => array('prefix' => '.', 'joiner' => '.', 'query' => false),
'/' => array('prefix' => '/', 'joiner' => '/', 'query' => false),
';' => array('prefix' => ';', 'joiner' => ';', 'query' => true),
'?' => array('prefix' => '?', 'joiner' => '&', 'query' => true),
'&' => array('prefix' => '&', 'joiner' => '&', 'query' => true)
);


private static $delims = array(':', '/', '?', '#', '[', ']', '@', '!', '$',
'&', '\'', '(', ')', '*', '+', ',', ';', '=');


private static $delimsPct = array('%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 = array();

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 = array();
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 = array('+' => '%20', '%7e' => '~');

$replacements = array();
$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 = array();
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\Post;

use GuzzleHttp\Message\RequestInterface;
use GuzzleHttp\Stream\Exception\CannotAttachException;
use GuzzleHttp\Stream\StreamInterface;
use GuzzleHttp\Stream\Stream;
use GuzzleHttp\Query;





class PostBody implements PostBodyInterface
{

private $body;


private $aggregator;

private $fields = [];


private $files = [];
private $forceMultipart = false;
private $detached = false;






public function applyRequestHeaders(RequestInterface $request)
{
if ($this->files || $this->forceMultipart) {
$request->setHeader(
'Content-Type',
'multipart/form-data; boundary=' . $this->getBody()->getBoundary()
);
} elseif ($this->fields && !$request->hasHeader('Content-Type')) {
$request->setHeader(
'Content-Type',
'application/x-www-form-urlencoded'
);
}

if ($size = $this->getSize()) {
$request->setHeader('Content-Length', $size);
}
}

public function forceMultipartUpload($force)
{
$this->forceMultipart = $force;
}

public function setAggregator(callable $aggregator)
{
$this->aggregator = $aggregator;
}

public function setField($name, $value)
{
$this->fields[$name] = $value;
$this->mutate();
}

public function replaceFields(array $fields)
{
$this->fields = $fields;
$this->mutate();
}

public function getField($name)
{
return isset($this->fields[$name]) ? $this->fields[$name] : null;
}

public function removeField($name)
{
unset($this->fields[$name]);
$this->mutate();
}

public function getFields($asString = false)
{
if (!$asString) {
return $this->fields;
}

$query = new Query($this->fields);
$query->setEncodingType(Query::RFC1738);
$query->setAggregator($this->getAggregator());

return (string) $query;
}

public function hasField($name)
{
return isset($this->fields[$name]);
}

public function getFile($name)
{
foreach ($this->files as $file) {
if ($file->getName() == $name) {
return $file;
}
}

return null;
}

public function getFiles()
{
return $this->files;
}

public function addFile(PostFileInterface $file)
{
$this->files[] = $file;
$this->mutate();
}

public function clearFiles()
{
$this->files = [];
$this->mutate();
}






public function count()
{
return count($this->files) + count($this->fields);
}

public function __toString()
{
return (string) $this->getBody();
}

public function getContents($maxLength = -1)
{
return $this->getBody()->getContents();
}

public function close()
{
$this->detach();
}

public function detach()
{
$this->detached = true;
$this->fields = $this->files = [];

if ($this->body) {
$this->body->close();
$this->body = null;
}
}

public function attach($stream)
{
throw new CannotAttachException();
}

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

public function tell()
{
return $this->body ? $this->body->tell() : 0;
}

public function isSeekable()
{
return true;
}

public function isReadable()
{
return true;
}

public function isWritable()
{
return false;
}

public function getSize()
{
return $this->getBody()->getSize();
}

public function seek($offset, $whence = SEEK_SET)
{
return $this->getBody()->seek($offset, $whence);
}

public function read($length)
{
return $this->getBody()->read($length);
}

public function write($string)
{
return false;
}

public function getMetadata($key = null)
{
return $key ? null : [];
}







private function getBody()
{
if ($this->body) {
return $this->body;
} elseif ($this->files || $this->forceMultipart) {
return $this->body = $this->createMultipart();
} elseif ($this->fields) {
return $this->body = $this->createUrlEncoded();
} else {
return $this->body = Stream::factory();
}
}






final protected function getAggregator()
{
if (!$this->aggregator) {
$this->aggregator = Query::phpAggregator();
}

return $this->aggregator;
}






private function createMultipart()
{

 return new MultipartBody(
call_user_func($this->getAggregator(), $this->fields),
$this->files
);
}






private function createUrlEncoded()
{
return Stream::factory($this->getFields(true));
}




private function mutate()
{
$this->body = null;
}
}
<?php
namespace GuzzleHttp\Post;

use GuzzleHttp\Stream\AppendStream;
use GuzzleHttp\Stream\Stream;
use GuzzleHttp\Stream\StreamDecoratorTrait;
use GuzzleHttp\Stream\StreamInterface;




class MultipartBody implements StreamInterface
{
use StreamDecoratorTrait;

private $boundary;








public function __construct(
array $fields = [],
array $files = [],
$boundary = null
) {
$this->boundary = $boundary ?: uniqid();
$this->stream = $this->createStream($fields, $files);
}






public function getBoundary()
{
return $this->boundary;
}

public function isWritable()
{
return false;
}




private function getFieldString($name, $value)
{
return sprintf(
"--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n",
$this->boundary,
$name,
$value
);
}




private function getFileHeaders(PostFileInterface $file)
{
$headers = '';
foreach ($file->getHeaders() as $key => $value) {
$headers .= "{$key}: {$value}\r\n";
}

return "--{$this->boundary}\r\n" . trim($headers) . "\r\n\r\n";
}




protected function createStream(array $fields, array $files)
{
$stream = new AppendStream();

foreach ($fields as $name => $fieldValues) {
foreach ((array) $fieldValues as $value) {
$stream->addStream(
Stream::factory($this->getFieldString($name, $value))
);
}
}

foreach ($files as $file) {

if (!$file instanceof PostFileInterface) {
throw new \InvalidArgumentException('All POST fields must '
. 'implement PostFieldInterface');
}

$stream->addStream(
Stream::factory($this->getFileHeaders($file))
);
$stream->addStream($file->getContent());
$stream->addStream(Stream::factory("\r\n"));
}


 $stream->addStream(Stream::factory("--{$this->boundary}--\r\n"));

return $stream;
}
}
<?php
namespace GuzzleHttp\Post;

use GuzzleHttp\Message\AppliesHeadersInterface;
use GuzzleHttp\Stream\StreamInterface;





interface PostBodyInterface extends StreamInterface, \Countable, AppliesHeadersInterface
{






public function setField($name, $value);










public function setAggregator(callable $aggregator);







public function forceMultipartUpload($force);






public function replaceFields(array $fields);








public function getField($name);






public function removeField($name);









public function getFields($asString = false);








public function hasField($name);






public function getFiles();








public function getFile($name);






public function addFile(PostFileInterface $file);




public function clearFiles();
}
<?php
namespace GuzzleHttp\Post;

use GuzzleHttp\Mimetypes;
use GuzzleHttp\Stream\StreamInterface;
use GuzzleHttp\Stream\Stream;




class PostFile implements PostFileInterface
{
private $name;
private $filename;
private $content;
private $headers = [];









public function __construct(
$name,
$content,
$filename = null,
array $headers = []
) {
$this->headers = $headers;
$this->name = $name;
$this->prepareContent($content);
$this->prepareFilename($filename);
$this->prepareDefaultHeaders();
}

public function getName()
{
return $this->name;
}

public function getFilename()
{
return $this->filename;
}

public function getContent()
{
return $this->content;
}

public function getHeaders()
{
return $this->headers;
}






private function prepareContent($content)
{
$this->content = $content;

if (!($this->content instanceof StreamInterface)) {
$this->content = Stream::factory($this->content);
} elseif ($this->content instanceof MultipartBody) {
if (!$this->hasHeader('Content-Disposition')) {
$disposition = 'form-data; name="' . $this->name .'"';
$this->headers['Content-Disposition'] = $disposition;
}

if (!$this->hasHeader('Content-Type')) {
$this->headers['Content-Type'] = sprintf(
"multipart/form-data; boundary=%s",
$this->content->getBoundary()
);
}
}
}






private function prepareFilename($filename)
{
$this->filename = $filename;

if (!$this->filename) {
$this->filename = $this->content->getMetadata('uri');
}

if (!$this->filename || substr($this->filename, 0, 6) === 'php://') {
$this->filename = $this->name;
}
}




private function prepareDefaultHeaders()
{

 if (!$this->hasHeader('Content-Disposition')) {
$this->headers['Content-Disposition'] = sprintf(
'form-data; name="%s"; filename="%s"',
$this->name,
basename($this->filename)
);
}


 if (!$this->hasHeader('Content-Type')) {
$this->headers['Content-Type'] = Mimetypes::getInstance()
->fromFilename($this->filename) ?: 'text/plain';
}
}








private function hasHeader($name)
{
return isset(array_change_key_case($this->headers)[strtolower($name)]);
}
}
<?php
namespace GuzzleHttp\Post;

use GuzzleHttp\Stream\StreamInterface;




interface PostFileInterface
{





public function getName();






public function getFilename();






public function getContent();









public function getHeaders();
}
<?php
require __DIR__ . '/artifacts/Burgomaster.php';

$stageDirectory = __DIR__ . '/artifacts/staging';
$projectRoot = __DIR__ . '/../';
$packager = new \Burgomaster($stageDirectory, $projectRoot);



foreach (['README.md', 'LICENSE'] as $file) {
$packager->deepCopy($file, $file);
}


$packager->recursiveCopy('src', 'GuzzleHttp', ['php']);
$packager->recursiveCopy('vendor/react/promise/src', 'React/Promise');
$packager->recursiveCopy('vendor/guzzlehttp/ringphp/src', 'GuzzleHttp/Ring');
$packager->recursiveCopy('vendor/guzzlehttp/streams/src', 'GuzzleHttp/Stream');
$packager->createAutoloader(['React/Promise/functions.php']);
$packager->createPhar(__DIR__ . '/artifacts/guzzle.phar');
$packager->createZip(__DIR__ . '/artifacts/guzzle.zip');
PNG

   IHDR         &   bKGD ̿   	pHYs    gR   tIME,B  IDAT8˕Ke x4ljsNƊQD"^nџ0.#X/x6EZ3_[f:<GQUˇ_ϏIR)`T2	Tf޲f#MI(ڶ݇LZ8I4ex<Ng8$c|REG6vAboj1cvmInK##Un%cpZxW'lǭe@Ky	#2P$$,;bD_Cr%<o{4)W 4o{QRY	sVeM5ee'>[,j6/K,p.|zRHzG-qpْJ|'73^	g	kY)q,5$1פQf9wtwB%92:<hgKa}Z.YrWkii>"R2qZ5qK.@A9/.%=ryb"	]|pUgxKM_S.nUZ(3i;4gŐrs>4^^ܰ`nN}YI5vPk.	ÞguXW~01ɤc
tYP0i8hRz$k$+1u[ᴣn1fL[6h7D؈jgeg(=    IENDB`PNG

   IHDR  _     d`   	pHYs    gR  @ IDATx]U7>2s$ɤM
		@ʄŒO,iև=}C'
P$**F;If#$Ap{.뜻koQ9y	%@^Wv-/K@^柃KH |π]%@^yK /3 =Bw@^y	oK /΀=e^y	%Wg /8+3 |y	%@^柁KH |π]%@^yK /3 =Bw@^y	lto߾];.ɟ@^y	TJ*`63#G<Ҟh,Nܞo"JCokit_ULQ>4OMMM)hm5uCthry:r[KYLSlzЯB5IK$u\dRWSkSJVbnϪGSWX1򽣬=P N9arz`S6UBg4dN7G!Y2cUNW*b=m5m9UEΟ",\	ǆt&U8j˒jzqaAr"S.*@%o:ʙffM:6ץ	;獳ǖnʦ"ZNmHMye
bj#M6A(ߕ+W
]]'葈).H-뮾B&Aa.K"qw˒ۥDhEY%uױb'*P(KĥNĢpe@
GRJ%a]өIQV
cS2jGH{PNt6\m+jQ<IDRs!4n^E|uNBN&RKS [ݻ[?:kְ>DljYXM9<Lb?P(VvvlS U_8x(_Jxʯ5m97(sNB:]2L(Ȱ~X$ϑM>ۼ=x-&$&1m+\kl)sbs3Y&1s-f6\eŃTb('0.,N"S]͉xLKETI"1g3g*%2u9#+3Υܶ_0EYt] ަ<n=-<='Gڠ\m%T*lKDA$MjmԩS]ZNh,3L%2[ i(.:Ɍ3YB]AݰZ(x!g\i7==~T_WkU81ekudjx7J]|6%7[  =`K-lJ!֥M_Au1>xz#n٧ښsic$)ur-Ͷ8(2*v\v΅@JPEZfߺe˖YJ6uVB-Q;.D>9B?@/{D
'@J_]$7 ,H_粒	#cy.Xh,vŬf(
3wߣ+{Ju莥(JX;6X޼H-\=EMn[r3i_R	wZIRTJc%;$j*ӣJj3}*!r˪d̽.[U9UHRB_2MFj\&qK@KQ+Qiޒ:[͝rOr;tCu%̧*XT3v'إ55_xIݣ|_(kMqKRдj[,ܫHPNᔘsĭEI'z|X_]X^Mߘ"uU\!r)Em#)+޳9&4ltrJ45XBK+RyP&;G2Xj$c[ht?lI3{',u(|r/4}z'<uUmi?:b[ͱpb¼,6^=
->(hIbu,ha^li2wI:
HLmQ).ĤfAEBɍ?u+OZ?py82G?MŴ8@A7Neݽ,EâZ&gӹe*Mi|nqxumh%WaMئ!}ѭH 2;aDӱrZ֋nO;&	@/Ux`Oa;>aQT"(#KF0'dEzDg+
3I~&$tղW{+.L
fW/Zaߒ" &hjL=$}
N
7hsrtrX0:">ؤi֏-;ߛ6]oC.|{Bpmem;BTG+JK.Q&'ki+,.Bi̏xC&ww6}mY9hBqR͍DX%m/wM#r[H2%O4gfb{HM\5#(m󑞀u>!m z7"JՈ^sIzxvm$nA?wՎ9īXy	8hG:eRKH'`.OnёX!M\гᖲCG"|c*&nMp~{)qh݊4,̊ܦTBQ
$JIKtn=^nNM/~K_*X-0BHS(΂Rqa_]`~aロ_u0)	zv.ZW,,w#ȋc<X, SؕhV,?d4kp=*Q_.Y^%z$v0FSV~%gbQ5[wIq`x\9	s?ᠯK,P7S]W5Gy%ϣS_:&%0z4얧[%gg2[f\$P}K'z 1-2>f9"es@ȬYPY;a?%pILZ	K#k;}BRا 26il#uuٱ;^q~בsTMȦd+TZ|g2{Sv^""%J}!&|`Sl]mm,[z!&\9#E26w't*!X|n%T"0k=7g%mkaXͪFG3QlֶJKnȘzA!F܊q6{c8Mp$ҌE|֬}G%galC1^0
{CI{9QD/ǜ봗Sz\R"f>'ݱ'9quuQ^zM2 
 um>}D	3Zn?+V8w sdfdzww?l6I"(ӭ|^*x*姖B=/Cܶ;ndSM3.庺cp#7o|:߶MN?~B0={`'ԄY¥ԢSs^mxSO1luσօD@ǣʧ<y;][bwAۅ`ROm|7fWV.1L#P^u@]|	]f 4`6.GC>(/<x_Ufg `ƳTaǸisJ
ʪ,Ӿ	XʩMXrzG>CeU&B|Ol+[|p]WHǗ>zſ 7iM*vw\^i2jNqL[{\5Ý1No8%p:3Y#J*e2wұDgG6:]x?x|2hF?mOrB2R='r
ԃaBAXm'D&oв>g= \N(CI2ȗ1(Ndf&rg{;(j	I֖׌y0mqFGs^&;
\DmJGBYX蟂Y@q3:-;P\܊7u[tTo6BmfyWMCMfܚ:tYXtb@vY&2K&͗/!'E<0m2[i'54,fDsh$y{OK*{ｗd~.r,\Cn)nǧLJJN#>/Z2@`TY䉳-S	tkP	%ޛl'n1?& lwRULvN/jD%؋M&-О0vw2yMF蹰xˡe3YT]YR5L6ߖgCqlthJ]*Dj+=h&M:=V̥SN}e%YsOSE?׬eNTu]uO4]/JOVO<SBIzp倫j
/}1bbSXv#FIWźMeΘ𑐇ˆWzhBI(){P0c-	m]uf5?ع^;"گd=gwjX_xn6[:֜SRr҅mk^gNu!YHܲy4jˇ?Pq#cl`ފ@#W(k@<^h~ho6>`*a(oS=0rZsCvHɚB,q1͇֦͝݋Ս:4#ķY"Ht
|evݤ]1%[86d@SNF20md@:D	m3:xUX\R7PU gCS3Xv%jnE>%fVzg7"S,=Pucs}0INZSuy(|mϮoGRľQnwz+Ql2%566
疗ZǏu䳓TR96VV%z	pf!W\FvyKlx:TiBUnM}FC6z2UOjeQQv"ʮv4s
6SզO-*M3l-Ų9T#r3vmd |ahԬe(nϸre+M\xqӲa!2ێ!YUiSm_vC62}zr ]^-	{BZ
+^4+dE-U\}eskЖdآB).c7X>	`&^f)*
_BH0A^bL/NJM
^I,40$Uܹy=V=N(?dr ztd05wKa&Ajq0vӆX"坥patm{\KKgr$azAHʁns¯zy/r=frUEAp?8k%pƠff	&	~P[PU͒ ɢJ\]l3=H4j-o}	\9i1oF6{T1?Ĺ^I|nqNzot֛IXj,?LByA׷y]"t/bMh	uBmPiZCIQY}e3D$]\ 1=ܲ׃σbjZlF0<.f߯i] 9sAXXF?h021sv&Xݫ$.Uܣ}P%]5'2kf.QYyFk(ekO&h|<RAj%"9&'*vꎱ~ݵ]C_mufk+B"].&}W)3`ߊoc?5e}+XoE\ !},>S>]٣ti)LY*0v?8$ gZt{LJ&FҪtQ;)axܜPگSH~	&	Ir݇w.Mx)Ms־؅ӷa]H 'wrpfRvNǐ%~$ NZT䡉Ζ12@?4Ww\Ud=XH"QΜ4왰o[ecs;hJ	5!]l.|'	6W^Bf2TxNky{tnJm@HQ(	IB#s^ߕ$R{ Q?lµ'IY 6[?>_:cE~!X!YjfKpMM/2^$d =V<2k^gN`ޑq:G#?.5kL61ZՏZ1Ǌ#.6:"@a8?2je48θ&G,)ýae4 v{=0`s=nYrv/*/.+ϳ_@6['M5*#*a	49.snRKb)Q k5PwƮ熃;6,^n_g㜏bs>Z_XzYQ1-<Љ{*c}!HI#ߤ=@CO͉_s46<|/Ձ[AM\p7n͒[7&A?DD5.md~׬Lskz%![_M|}]6e`+"@W"e,nn}d&2Y.>G{naji
%$|C;f*r>a1vƒ?88-w],WMu-f80a=RW &mWBQSwK[b[d#(4؟Yv3%cm 'GJlwY?B"Pp|t٭ڞ͖\yήWӰ_PaA3cP5:ǒ3a!/
(8>a_֓ցFBL&]lra%4"JX%[oCGiÑ0@Bxo2yݽ4>ͧB~2ւʒ@<
<`y>mAm_ZU®v2s闣C_]ߙA;ǐX. 7)wWT"6c_7WŖL	8v[+Dul}pwN_5X-<ӴNW3nIϖUVā 0ѹsg~-RD6tmSJV8xǕ`uH8,3"&LmhN( `i|!-M2h4fҀ{hI[jSm퉚W{7|~WCM(PYwy	=p1BAq#~$0әWVv|Un}G̔q_̮m_?[UJ넨>{U:WX~
G8%Xw׃k37c-p93_lqY@;SFۗa⏥qnHMiBpvmh̯ 9c*,ɟ#(H]uUԏ,	9-w
Ua#	T.߰/^d>SAѤȊE@S>ĽTu~E]gIP,s?rl	UsG]2j	g@C' $!浘W^sONNU[c*5MʐK;""ٟ;ԊGk%ԴU}T&03٥KA2P4V&!B!Y9>ZKݸMm:P [/}C\by諃F	4.hyAn88ņL87DFj# nƼV}+B5ʨ 8p|nSMM&L<9+뻤$5A+L	:u,ͦ߆{BOKwrP!wX_{Vv֊ز;1;{٠;խ;0XŊuN*lg4	lTtq@vvt48r~웰 _0eE?e 6BܰXQs_~cWUDf*ŞUm	.ms*?$Foeuni[<ʃ߰}K;|*$ދ9y=pnʖwaSaLxfp{tNQe@_w8iP~(JXjm*Mee fYrMY`}vCv("jUx	cH:[⥾<.lr+PvE-K̴B!M%5%<;7FƳߦ\}4eťrաZ}̇;Vb]Ilf\U^lEPN{Ft(`~=+X=Dm^o5lad"}8~ɦ/w8&n)ic/XeYx#@ц*%R)RުY,nv,#QahlY3fTj*aB?hCwv<Pu}epl37܂'["$K:kYٛ@v'{nndy9	-/H?%.G_}ܕgdAe2rn1]c9NrZY*Z%Ke|[
Ȕ
|Le5O^i7Af1-TFPdW}G4mM+[
۝-ȹekHrp29J;(LvB1x{1"+{:?7lqueM2''1WqV4k*--/@"on
ZM\Oå_wD6)">%C	~XɝX82S[%@OgV-T6gơȮ7zoad\c_wޓT.a/d[<ԏS5dxJD>q]{z@qNVْ='r#k7-#geH7/OOw_6fT[ȿK)|_<#.D~xޔlPm$[xX_vg.ϘVV|mgu=W +e"LJj$cȼ?x(Yx;U&Sm-榦ϯ80 nQDA🏀5.(<s}|swil([dI05Z֎J!(c{&x]*+fp:Aefzr4k:NtVأcA*3C*'w~af3}G0_L13=Ǘ.՜65-jJF$Tײ};cbvC y*u{x=b+qHz~uWrbŐh{.5V5`(0/G?bi;t䉣DO1YG]&q@:WSفO1o?y	}8eWbr9U "y%U5/{ٲ:5z dYYLo 7'Ɩm7×<hmJ5!fEej1z=TS˾z'IR#J	 bpEB/Q0D?7lA;/Ja{L@/%[`ݠlqRDvzSBSsS,U&)5$g55K|;4	D[/,:)pƋLq#ֶԡhָE~O쾔6PY[j8!46Q&e}~H@ђ=7}z#_bhPukI@}Q=XXÈ<j]C'ѶtuXܜZ@=}{Moq=}Ů2<Qd	-$G*ˏ,jâBG{O\հH83hhe}ps\o
fTĸlow\}QH8=;gvYz<ը:UW |XN~oly	Kkm5~ݴ[n6 &ΆdIrYĎ*-ԁMrFV[}J#c_ ;V>-Qp@ghHein#XlVݫ^;}{˺QAbnӴx9r@#v0bM!c@oPoyG"ؼXW-V.S*%+1$.A/SN-삽=<iT2WT[BThB$`,K;L&҂qA͓]޾dgZ
&/Q|a߄$!2EwpjF;ºλ"f"Q AZ9Sx%)|QKYC,rih07TfGF'Ou}tQK
m}Vp5@?)5[{z0ޒb$k/dPHTq	!W	@ Ҵ̙,\`y yKoxg$p,pZr>+t]$nǳ9XEo6|*nj]¸<.
		(Ԍe`9mKO؎1Ԉԗn1T'o+&N}@HYn1-DǦ\:)#P),f՚vmy0X*Ax@/EGR7'S"D15L\CTe% D0^PDp0ҹ,sIX9M hpxUBR(2^-iLcwDMgnpՎg'R=y"E5[2 [%Y\+-*DS2ƃià*LO.HFMfY6ie^*ܱ#f~y瀺bo4k}Erë^/_bX:uCT|WyK!n)9)#y=tҌ
'\vy	LXpY q$9rٻ]3@G%p,ߑWN,C8~mnfC%Ml3 ?lAitḠU{z~5NA_y[m-+_/'O%`,Gc2D=tEX|B=Wƛ%x^7HhU!:)v$x4XA.Ӛ	m#b")d*Pj~XXc5ruaSѭ(:ӶW<̎s1&H_GJӭџ}ߜғ\1]TTD7/!,jJH"Q[F}9fJ#B"(
\غz$Q6sUɋ$1^mBet>A587LwcX4ȗ8Wjȗ Z=6oz:W}C(ȏS'GX<,r2ys%~pa\6Į\Iq{slw~,J+_Ѹr|楶؅jݰ-_\? I*sR3a˝vwQ	Yj233?kY?tMFqf5WȆd`hɊ:eVCc/óU+SɡS3;%J+jgIOdJgT禕È3?4uUIܵ=9tFY09VI
"l?JEo7w䱥{o"`DhIkJڕ
!qCQ,5KqY }S<Xv]`(#^'
jܺzIvñ@ž{~<YigMgHڎ%y7Uo!9vzǼ2Kmqi|<nR`[ɨj%aug{>GcJ+_gUoyQRL(;F,IrO@P:`kKT[rqHGteVred{8t"ӭVdrm:)/]"7-E`hN'ոfaTq/V@`(߅hN<ﻏ{WQLGd@2yr*uXROHu:yta1w֣鿥=I.>giχUVH5PƮ[=U5o8pTZ׊e.TuwA85--;,rŕEx]Fd=;%pʕXU-1{=~nMkI"`3	_-ĶxM*e$:[32}J<k}R>}|՞U0|
aD%K)˥r`$hʽw)JV;`1V[qO.HZfoWM?yC83&]},
*N.JBSEKbߝR+T]mn
Lrct6Bni:\JH*3'EB֏-mcϏD	J	c݂)/t(k@^AE2E!줊ך@`دזBME^UKl8T]]=M)ݔe=r84>I:`uyWH:D^3
aMl>xQs?z|aLftWO\iCRLe3(N
3drkvĝDc4*Qa;ͽ^(Uo?*mugc:NuInb c\i8b`J%N}2/gνuߧ\d1cZw `{s{:VE9[j?f;F9uMM	x!_[8k1pU󭧙 JF(P=V/ ecRw?7o^^bݝC(?˯XćH0Awpxrh\%ylCPEtT2y7ji99\"9/<VNff	>[;w+~_`K?=u]wUe_,\VT'}sw#L/8nM66iy>8nAJnɞT?Vڎ_͝CaRPL`,ӻ5JxF;!ԩxEdLrk e+! a*ص	+ +E@z`% F_UHWxUc|۳׊6՝]]Z: Y ugq b7`Wo.
nfZ9xVzPkð9
w;N<ȟ\PtbE鬛)W_9W$zS  `'64XLyY.ǣemH^la1LSɠnҚkuCQƦ>XD+CũnYS}Ej+҈5C`(@[r}Uh['Ǫ"7kd 1;I>}7R Y D?3pw=,@ɖB05{w:F{[*AvwyV~VQ4:!93  Nј蠖(to%
t]wyk_;g4 3C;&<i`[|WI*'
&PdS^&	|~-˦𫜬>p[OL@?hr3_~w.L,Fp9l8gf,uQq9&a"(,ܛm-d%~mP&m}}D:}j^0$nՊֹer&z^@A՟){xG/8Pc2os((LmJ۶P#ޠqUp4|SOig>ؘH[rCJ2E}ږt	+q#stE	AV.#7Zl'5t\^Ge'mn8D`	SKP3AyPЁm.5zXѥ2ںwt	9zDDQ!UȺ<ssld+V0Ś/^>k1}5E"uѫ]MX`J.!s 5|?[J
NU(J_em}Ͳq<fAX-Q`PS^u'v3܊ġA{*3%@뫉e|.+WaFO9>2/0\^^Aj"%i9>o?\ףVI/oT~/Q;+ni̶^5⊽Aj1J;J!Q/UXݼ	}[/"OZN\m}x헃/7)ҵEMOu:5v؆R*0},\Ȃ<1"ٯ97/2dwМfBV]QY?AOOSlgNiiH[$̌+nFt"vzC83Sru<f+|iFM=xE{_,/~2ꎹ4}\P]u"vj9)J3		kt[ʁ]Ka;ry]wK̞JM#KH2FJ3ǿ@;t<)|[w-&EqJ-DbDK:[ېS`}xCV:8C9a Lc:druF2=3wS}NEldbU#@	6׹ 	+(W5wPU3%:BU=NNvs>7!vq-hSuUA2P}e^N{ׄ!Yne3ɗꊎ߸غt'"%nI:7YDRLﺬ<d5Ѽ_+EK^h͔yI;9޶2h`O	Y.{%%;v5PRr:G@i˄dy˜RAY;C=rI'?vz]j纾+@V]ۻsA}MTSuy59`c=
)i}}/2T3X"OW.guwZ5eo/ vB"sܥ|.hTT[uUF=26ROjle:y`A	{(s[4<P^=3U哸K9ʃ0ψ9?~2$P ֺeb/ȥ`ͤ	$/
9Ww|ǋ\HA W5?{9t	*)1 %k{Ф6u\0z;rؗ"/d՟go~QױfE*^<-  @ IDATUD(¾:
gʕp$i.G7#WDh.4;Cy[3Qil4wey fknPZhJd~l-yq0'ɨ͒$&26Gk[	R5|?Jm+_9/yy]xM.wpl V(#iMpȐDoO'7JU$%B<ke,D
z1i=8BR]WR'+rX6N_N±1T THݬ0e/![%xFOs얢i\jusfC
Dt2GY%W_4^WP#N|+x璩o#hJSAT.zq
|ttK(6N]8$2å'+).Q0WA٠ducVՏ>0{FW{zeg'I6	8JEzMvͶX#/WrJwT$By1!?OV|aYOo_|8bs	&mMœ+{"9p4gJ_m0L}'-aPVΞ: ->tWW>\H`XV@ͱ{n9-75]D,ow (S8SY(rw\ٽqCZUע̴2)pu($N&;X-:;vy-? --=H5復ɖ<yUy?(iOE떡"[Qnzxqwt0*^g Fȃ\zv>
(ήɀU?xJ й҈dH_(q TdS܆y7>Gj}MɄ,̨{
K?R\9;V(eUqO4+mV4{wٲv$QAWe$0mRwtIat-cXF̈́&W!0p4&S@cni<4-.~\Q9o!
C)u,}2rGmʺ~MIv5\PSӇ65qKҊގu6Jtud%Խԋl#rhR_[дd4>_Pox<3EbW)G6J!+>B@ˡ
k"L㟠DmJ7D6-QXXL@޻#~=.C-3a"AӲo)\1O)@" i GiRl܏@GZ+6o?SF#LV~g9CJfːE&.$uҚp`4HŖKZI+fd;ѩL%qi8Փ[a@G?K5e @iɮhIIfK2{U{mYx3I.08=;wPDQAS^I!vvj$pvmuE$	0?Q&rwr)X7{C/Rf"㍋%ikQ4_dML Ԁx?P((_gE>kwoi>od,Eb$?6(%iKz|"d1YxH!fٿcs%UݘN˱3Ο/ٶ"&C(53s8	JNN^^DS@c"EӑDQ>v@i$N#H	?tS(rYVK~d(_dY-7G^{"+MLWΎy4ȩb	m>_ݹs.ZpbG7Ea2:wP9īQ}ގBUу$)eh;Dі)Bx:)~檫ͬKND}r߼gj;jhI$3w&{~.ڲ(>md.,8b9eam:A;vnF:tb'fC|n%]h>N@JNd+߳5Orۓ%O>="㴱ٕH`:3;S'=:!с]advu\x{V2{^6aPX;os|9f!I(]
rH}}O-]gIpHVyxUŇ--Q!#\IeΏ9w-ǖH6jJd;]<x<Tk3iVrݲܮoH౗F l*Je;Z]]Y1XVB_=GҜo;q	p߸kf;Ccm|
jG,]2 Z_)`^]Dl឴m1!ъ"ilv@hb݉?kk*ԽեmyưvtOmG)y&QpεNc϶Ùڽ}P=}8H,vd
0&O.<x/ۦ/ atyHV~(,WؾҥKsGopNѿ|=58f{MRrjf-Ӛ2n{9
!2RYRv[Yz^N&W%_*PwtkvǙ%E((ӹ}2TP8&rk=7BS	bA,AЊSk=jmj}um}Z*2AB27әRI߃Sͽ眻ZIP	̄4D%]vnҢڍ.siaO~s!GS1)xl'ݪZ>ayRY9sɦxm{WО7(cJ`DoPysgGPk1.gVzR9` WI]Mh5ԟ>䮫N*sMcw hF`=NHU_n[,e˧Yr=K^EE๧k?詀H_ޟYzRTRĳ~ ,ϯxAݺqSx=?)㰚܌Q`6Ix6Z3{fMEAVk?1[Zm?~槩3N۰t%Ce{-³&q"&`>AmM/,m<Fzr:^brV_-$pwkL~8SV|NOOԇYb1ZPĳ&]`´/7-ҟN[v%%9Oj[P]Au޸4wÜbDmp߶H;g4ܻ<r]IV4,M$`}][|a;,kr}#<
Gx}xՀ
e#u`wk 2U&3jkokD=vU8}? VY6"Db}	noCyS%W2UY0vL$TלkLLݝgjwԟmHv
56s8MyA>xꕘD<p#y:T,ȴlO>19Ty'\duJQ!2>}E7d-[i/;v[[<@=v[fޑfX'`ƔdӸ4$egbQ֢`XνP'it_B}oZ]^֋$&8)kP 1u7ܞfZi[^9Ub'ý_={{=p!}^>	+0V9vwH)ue"Vjە>bX#[N_1ȣK=H=[#mmqlk=aUg
ˉ$& $Ga?(.Xy% E|Rlofԋsf0,)m]Es.uMųl(qU4TCKmWsa%v99[Iq=EP<Ik[n%晝~`I}lx~qLfjP_3x0 ,AfPGQYZGLуBAUPwxvˌ67(gr>fOOs"%ҀR!OƤ $.
]B`8=L+ELEU<
KTH3
(ji7bl-)ߤpM
p5Ö sZ8JO%S9Sz{NpTsK$=}) 7
i9cffY&p{˄ˈ|agmRO4I$-h[^UeJNvsg/>T!@HdHp&odz1Owt\`S#]aum_G@'*R<ymr۔))A9ʟx5coInOP(}guK/~P ^,D,b5˳?/-+e~}?UTTVV8aMaAU|BB	;ArϠD؃/5|jUW9hiLG|MV=yLOenB_PJ>>g#MLdpqo))=naE㊄%g@WB<HRjxuqI-	9<nRcz"%'-}=/P[ RCʡ&*G&>g*gXo<b~N89s$H([>ԜZsk줺.Ǚ`/5zKHwz$a`\K?wc_)_tW<*\زG}~=pgmI*B5ww,.8 LZIqt#!W`"b'cgZ	 AM?T:>[D$+42"8ZEl^pguLJ:ս+%J{?OVzo񰙋ϠOB!_jG\I֌wfV>UV{Q%b&',>v|p!YYT?'UI{,tǹ g:<5H%o|>bnGsY1ＪYpljm6AϕYP
bV:pGw^z?Ak?y1'T8=C,ꄲ4(M%rH	SkL~eU&cex |?É"+S̖3@ީM	oK.Uԣ3xrc¨AHڿL.k=B6Gs7%\^F'?
|Ѷ{m{PM-[2)bvSn{0'f1)$lUWh&gq-tUVՊPvCXQfmK
Ԗo D+*0`bŪaQSn(	8Wi,ߩ5yfpƱ#}]]̰m025Ev騳؄\OVy$ӓŻ)ڻUr/2خ{Q8_WQdg[usTB/w?{,^)}c~='avs|wNS|7b6ƊTg{-VHH?8UUmWDa*KFi}w.̙2@֙GBFU{R?ޏuwyR),,^Pz*kW38P璊s@ܬorY|n66 +c6[5!κU^o[他x:RzW
{JɃ)Bt>T8aYKI[\-g <bf'k*dI][d֬2:<8lcQ u$i?>duޔEv$͐IFq/fgN	'C[7
CLPdzQlRI"y#ǐi$Tqv3"45Cl^%K MdC{/X $d6@'+7gƙdJJGA֑%kƞ)q*{6k%.N҂@ejK"s[m|mÑn7Foڙ\r<`R/ػl\Q۟<ckW;3ºϹ8qHl3PxMƌ~q6eMr}Y-{_O+OS=O>M͛c&_P^@-bhvl6"Aa|܂'儲tm~wd]7oHɾA<ts
.>;H6fdvȜ4$1l:>xl1{ܯ~LhUD:䂖
pK~h_8#޻EH}5AX`\얋f$}J;cgF	82~%&k1R:5 ONHkDl+(NZ|
\vM1]nVUeݞX4xh]jթ4I~;Fѿ[AeU9bs=~BxΣ%K3ϽC;>v8yxZe듼WCk_MsI]y&
2s=vF ~2im4=q"Jw-!ij-NCPȊ&|V%Z޾Y$5kST䵴J߱Wc_	W]2V#ePZ3_Vens+(Z*]N>@-V;-߷"W9
?h8pn8uXQ#<td}WW0&vڼvtuM=~<t`Xv3^S.A!SIY۹e wP&wշd:\hjP">#- hR\)~wcϘ4(+nmC	˴PVTT9j2BSRgvtn(hy\3Hrbu#9Pd횜'+cF	|kf#:{e7gwIIQ4ϧ]z+ߒ$~}Q~@d3
I2	:
Ba%%QBۭbN@~|
wϿsPπ2328_-LtI4RI:5Jk~ii\2.rb}T(Y*?a!<i? 5 G]:Q#?ZL*؋mK#+&4Ί(^υ\*xEJWoBk_yNOx5pYqCq6I JL6i:"Ҝ eZ+v'\!.y96X)[n/,uu;)vnw :*P󀮶ou\jߔ	8(Y3A0(__ŏauaMڛ iܪN1M2"]޲Ex?{]GT"QKyr%npfy}
]&y	HطuD `4!
|Cvv)׃GBmfen9307 uBMm))&{tvʐvp<	'>UQΚ. v v5uwg&&xVŲ6'$BY@Bhkp/w$jO⾙D;YTYRC #y<FwmΝ<=i.sX`LfB2y)LFd<-COEwUC Bd{uzK;*0fz{8ja%։G9xڡIT6í
99Bq`u8,˟ǫ*xZ(	,w粇|LNU|y3<%ᖴj,x:*:vqH%UIӥ3ekt]%_ƳB#|*"ٵȫ[yײGʰtnsew( wnn6POX&E&S3Tx2n0@	SeDGׇu}<FIdS⤉G-8lX0мif/0PzZmf.	e+.ӃG>qKA66;2˱ۣ>:_ 8,źw+|5.)ZdBD8.1h8s|_.oxz#jDb TT>LkL$U:=ꓞ};ɖIx}fXT؄xLlV9U{l,aNx&9݆ >ۥI!LXЩ>L\|?*˥9$u>Mu}b*޺61Lq>܏0X9_U_ OoKQd6y3/mB8 oٴw/]XQd1ϱ~-{X]	F0E9pF%sON
V?ۧxg"#3+P6+f"s5Y斜NdwDb[-c2T6ݵ+(x۲)	tufJ@"v3g/KQ-
KTV
f]؟C?v]*6o3\Pz+Vü05;3<_]>rCp9vL.pqM_ߢ.M=/OEM}z9}=>re<mmiqt"篼iՠ9S|VNLfQCmD%
TW	_qWښEg-a
v}dmyI)Ǖ3gڪ_W%&5mu޺ػ(CޟϏ)='?sznՙm#Fˁؓ'v2EvnjZw(l:HC(\iHh|_G	yNT@r*EQW?]S~OINK2-י9p 6CuF#{dmow6%moc֬Y:NU]Xt}D"%SĀM1]W8))<ɞWT$
@kU8b%_\`(L6]˚:)q*\5DgwozhhAi8<XqnuuY硸.ZR˺* @¥	_εE˜2dʹnE1Φ{UqIGeev:^Hp+JoNxBe	E9UUr+b7us2Vד!FrYq\Uv[wY iF=YHxQ9|gkH**sZ\x|ӳV 41u*TjEڹu&-XGn+5x@jǑM޵.^*{?z%08ݖE W5O}	 e .RD^ObJʛhenw]i#;-p8Ԋ&= :EM!_SxPU/{A۞ԝJOVR{-\eE%5ĳ?gΫ pal(qkIm.= hwVeVfrmU"\[~}fp$!tiiFӦs<L㎭-JÇj5uK,(?jzoYuC-.Wt˛M" )wr;oѥ}#!bv'ʊt6ǢYͽeTب?rR<K(ZP`/Ey8),X9%3?h9X9YˣMHEv!Ogh)d8}?/'Ċ	E(ߘZ29
$HA*;ܘZ<ZĶqVCT+ư{3;ե++*2=1:D(ωN(2@cp2ҤrS:剟m>@g{ҪT^OSnX.L24I-MYg>|[o</ى5,ff6^7E:yڦ`<g@G"O}*5_rL6:un]Eb3fSK,,bO֦)c|uW;O/<e 
Zci\~~-϶LSV Rlőhu# أN[[P+j[i-6<94a<.}{;
%@Qy|)** s?zn"3Dwlx!=N%^)-MXX's@QˢaTӝ e_-5]Sdg	f檸n4WM4uT4y{?go=) 
׶Z#J	ūM{!)|LX^_rA:dSY.3$ƭDx/P-7=<yiLNYƼPfYYƂj\jj>3OX>\Xiж% WD7`& ?.X1t~yA)K-.o͑TTFfFmif:+}?G&]>ᗤ~1646fv\	T&^ݽMiﲋ4ʊ6͆2hrl﹟l[= (=@GG $eiH>~?nSt!1T>x؀𫇪\H5Kx6~mڂDJsb뻰@:~)_zr^)T''YHD\ޕ.4Ό6q8΅iIEqY:nvg)hIcJ)H9 PG}O+'
;(iӦi\?xS(Bԧ{0V~|(qBAä1iߓY δ
Jat<8r地n#C?Woa~$vXYGv|^ΒemS'hW|3QY9C(=D?yL$fLXtlĖb&eeFmCRgjpLƷ*\Rj3 H{wX܀e:Nri2[y[ ࢣT	BTXu;oZii&"`	On2sqҥp- {6>^Yk1[Swe<x+f s3R=vn}˗/7Jg:N )98"ғ3VgZ_hBY	$CP!cUh|\sժ!+)sیeЍu!@R2{dXφҖ-/k
' B _|h]l.Txmx}ܑVVR$Kfqn(gC4e$/|jhSV֬mmTTGqW&L/.m'dH	%=B,뷊fo]')a53!u&&nThXe4H}
tt0I ?`N!٤mY*))U2Q5QU6X[@O"<!SyyfɳsTHգ^&k tZ=G,tm洑~tᄂAƣ!eoBaFn8SU6;g`K&S 6kD|
c%XPI$vx; R2wyqyry=M{UNurӎnS-ql]&ٜTz 2!N֔A*E6\ídԸyG2dfTΛ`^Jիu7߁I0YM!`` VXG}t.6Iy#vX%1فŅ
lX`,צ\3eO\q6B~)>)|U=tM:<ҧjc	nʡPxCϤ9F)qK|	?Wng(^vT{,0bLYeEM]˞ӻMSUC4s^>t">r,ǎ1lJF1c=nypjWDϲR/qOrGz?PPDyA7Y='4=s;D()S3;V0_J<d8ޝm/6:yP/n|%L1ida~9QUqUȔ)\]HI!T3\J:V_`!JLA_=g4jCl<o甼r6nJh$TmVV{̋,PFb0CKhq'yWb'{]X޾-ܯ;Tۛ]QS%;ԘlҤ'+Olrf,my9PpzΆ߭w]7pdh?Vĸnk8eJCuۯRjL誓6[%IcUe)v`~WXԛak<Mvt9i-VOUף}>^Y7x+3x ݄|XLOy%$%(N5U-sSCD VpxCK#W+*F7{Q7̼D:/} ggwÚ+y>h-T5!ކOV^p5T)"]	p/wDZ~.Υҿ r1ҡ\齻k<vOؿ_ON:7x%~4弔˅SNޒ7L}ڈIPsLb_c\{_݀^ሔdBg@UfY%uxzC<)n}_$4ޏp%/e;]x%@PeR7$YS#h-m5˧z"sQykm.,%*Iki՗QLg˲a_j^,KgTe-0K^*	_G-//#	\l݊K
`y䳜a1+y(c!ʔaC+VTg/f*I5)nL6|>mXP:Km<>?e,!6/ݿ$Mմ_9'%]\>gi@'YK& ZXA1ȳyj8<捽a>帿|&5\r0C?ˮTŌ齞"AYK҇]g*ZJ׹^}\¥<%Kp2:mVү8ZJlNrs}-?Ao/c.K5:KQp`{h!0ލ.T+.3>4('$`aqPw7&MO[\L\Sd!
?A;ewV.fͼvvTM(}{:ѹDsRȢы֎'-go[E|u̗}UT:>< KÜL-~=^YCk{{n'嫇64seT17pLw䰢0ӱso}i|Gc4T竾hߑ:`#9)TgSBІMO^uUH<Et1;b
k}yVy غ0D 2%{"ʗͺ\btjb>M|ŖXSU/Y{H)½R zjgcpJ&9dzwm~"rՠ&&#>R%߽{kMyÖiܹ~IE ܙ(ر6c$  !S&9abdVaau]S4ё-jW'(IxN	/ˉM[|clJWhW>,Yu-=]H@ދ,;WfwZ{"Uvme2W/\U	x/`7L)N>A."voaT Gf0H/#kղwWL:N퐒$+a[YAn3u\
V37: 5,1^TP ~5(kRBEɹQQ{Qx	03IcmH@,SB7ȏis
*NxEP|ۺHW|Q)I_`,+~.whsG!¥ٹ-<pLu[Ǹ25zôOKMBIOm{oeȀcfB
u5v]0 zPFI]~S^h)Y2rTĂbn@rOj(s"ǿJ֗Yx-.Lz=e$489ﶟA̆(2ht XA;)eRG*h-g\㲬Y 7C玽I$TiK&Ot#X,}rI(Z]:FWT(Rx;q޻G;MKRkU*3ɀ2њ9 S	qZU;~da&QĠ}m?$
OXEtR_3i	V_tE=#^zI!0lDVGjŨyxBAMPX G~oWkB dىK-[e~ng^vQewv{Jyi]6-+~FEDLs?ߋ6-𶗃w\ZU[qPPTXy
Y0s^Ҙ^Z-7T8+̊pLs]sVs2I+z٤Pʚn/WP弨4wFdʹLçIYyslpZ<מٳp_|4`U[.Be\Ew#PXT赖_X
迾()ЗWetĚ_Xϴu0M@ 0m$=o[CAoNYSa@>1Wم/>0GRAhG}=M=vNg,*RExp{=;% 0WrKz[ZP5Pą-]xZM|  @ IDATU+yzM+|Of8 zؽS~NF
YJ,)r_}n5W!f,(er^DkJ|$I	b.Ty(\bq_j G'y/ 7f8}lv&Uj{5㞧`Yce˶ݟ)|e^@sWAk++)O46)0=%Q/VC>L/B7RK͜ʳAH3$@Wn[֦7}*Yׯo-yE",]6BϒޕҢ+kg+-M-bp\?2>G?b
{SmSUč^u
2h@LT|*qTdno}!	'W*'6! JNZf\B
ؙ/(|t&"@iPGZw%sf[XyEhE㽆!ȸ-Gq י@49c(ғI<ǿXW-78L;NY@re/[NCPB&9|,L*l1@{`T"ÅM/LG&6c0gޏ~	xq8m}2HJE)?4[:ۛEqM-C\MX?YcYZ
q2cCU0HX_&fK%VȥC\^i޹{A+'tjK	",.U$P @ރ\7ݺj[x&4!]sDZZen&>v'$2cBK'LU(2	\?k_mYbC{ޖtIe{ǧ\tAVim7+*=NY
k[**EFR$UQ g;Wf~KnuMr:I/yE9iêێUn gZH@ˑ
Q6kyZkµ]2rOٙQ*m#`7ObMZ1˲7ò:iI@fǔ 	YU3uwr}Cmq@xV=`=S5Md\/\;zUL6WZvqzThKr mwUj6
dʹvo(ۙ k^^^paObG\jEVj/G4̓/k}-bŐ5\fąEH.]DmSVb{z9}5}O+k)g63/f	8pH\*|x7Z]*\}p"d(f?ݽM[Ufy=vEd#ϭW g87xPR/]ڏ9MbMd+@ۍ6:6SGO.:sicoFhRxVJ\rc/%@B/\5u33^}pd>NĺGv9t">4EJH2\ 7k<4٦e;d&`w{<*]<k~xEuׄpsj>m<e""
}~x=|~j0}/曑/yMBiJ =J30\TQNCm.5mR=~r<gUTZUrJkJRdp7f>1 ">WCp|&`q~kkG?aPBqHX)ܵl7d¸\K
aQGE2Io;¥= #RB
'˱eߟ0ETz
uTGvUQk+=3D=jPAx=pkE="!/( RmP֦G`kNGլ#aEQҶHrv0U
RT%ag_clq1RAC4)ZR=ΪiW#7Ƈ{:nx	Է)Y+"Ja~PڊΛS_=BG<P{r[yhO&PNK͝:_\?`vjJ'mSu63|מWܵ=n(ZV>}N~<kTJ[|4&Mti{NgRo]r?{yQ={5
Ze2Q74:k]4*$QwmvҮ]:m+2ONKDcu[;+***'iG#bZ`DB1Kk%Z\o9g]:v %0ǅnk31upOc7Lu8C7{pwdh
.x/N,M݇TU v[wd&pB`tׅ	gOW:q	Y(䪁sr#7ٔ~Ɵ1P	׻2+x8]jඹ6mqqP}W,<;tfmUIK̠[7?*ʪ!Ms'k:?_@:/,ozkeUEߟC?Zl[1l!z;K~W#S:,7ҶE1Kt-LՍN&ĳ3#{퉥+ ln$S;4G<6UV*{dhYt1w{D))@<,C׊[$H@"gEVlvv#m.eg.MrWWWp`)%Sx><Ll[nڢPr#5E7͌h#wʾ9ky_
ۗu4QkKK\F'ʿ://Ѿn^*=xN̋W(p'{:="W\I/B]%>.립ݡ(똲k>AVQVn\r)N0u#b{$Dt;(*w:	n-x	45$aY \2e-Fm~[N m@KICQ
"xw P"q '$)ҋKEm5P߫_x*\'}o"
N}I@ʄ0Mok{ܔb	RoYZrx"(?xK$"|=RB|/|n<;t4+c={/d*-k75>CZcY՛;:K
&\9bGT(f0IH`@rnt߽ʞbk$Nn@nNXN*uh-nJ,^w26ޅ*VJJ-H;ݤᏋFnȦtt=P75L;	0{6$߮*h0߬/꺃w>n>*cmӇmpp{}W>~'q*2 Cج/_Ew8D@Mk'iNYLC{{Zn#'GFKLsXu8WbٶAX5\0D75%W<4BxƎIHMT}R>$O>_o
[}fSI``[K9pqgbK<MpT/o=Y?1:b{=>x0H9Yմ=BDjCڊ&M{JeإCH	46.HΔ5k/|\Vٹv%{Dd))m<}|y2wkamEk{OcS#sv=Eo)	켬F`53ǖ{I3*=^dS c&=w8w
F&u}4@ǻ#CY=ZϼtHYt=B,ˑ<WD7 `5CWL)xᨮk!AsXmxtٯ|wQm?rZY99gĞI&~8,nsE,[|^wJl.	mOQp:dD$Az%Ѵp9=	jCHأc|pn~V}e|Hv}@ VBÉ!`'ɈX ^IRaP8L3,#١seͻ58D|bB0.xEB3#ʦH1c]o3Y4 j AŶwthg<%<t]AtSLzKjH$I}ʳ+NX|%ʿs_KPrJKF]:}6"WtՈgL*mio#ZԦ	.~LoK\ym08VJT]ou) ڷ7@OEm)*AǢyТB@&FHY$_Siq]'J*gV~TvEwΓs{ܮkGaVLnuT!`=wi{\2gxQ3Tρ.[X|#?QܔTd-tGH}n7j~oXjP/55er}GDxp"wTj:l8:H1p ?R?=@eN霠}0s[ E@{#QUFW;/1ٝlj|tI`FAOհ#dL9N"O B^|x8nh)%C
[\las1J:H$g"t_׍P3`{l=Xzj:YKE}*7``os>r|^9	4euu|ުUǹ'PRu$=qku?J8pG=,A;e"t=NQrק0RUAy$5~˖7QT >c!?3	4>.qaqFPtt?/sL;ݰ]pЎJ缄y^ȡNiDn_ VpZہەub;c#׼Lqq?cͅF|JUI{,/ /p6/WOMkVZɟZTsu.kzMoi{^6s`\NNBO̸|[.)ߕN?ھ&'xP8Xe$6bĔ/,fzm","2 ߁A4+׻厴vFST'km1`.7ZZLä㼞$v]l}x\{_s8:/HʂV>]Fa/TH+y!F$Liv~Hr9N Da^=M94_2mY̓Ųq?]# ԿJQ=3}A]жUIqbfYjP@|I?ܟ	c#<d" ;?Ҧ^v{>) !\7W*+nDJoE]_\	1Ley'qڶO%E<uTH?wC#|nﮜ2_g,aBYgώX),s@<2c}T*̲rr(Y؛B0_D@Ko=O8o_He%kf",EԯV2xx-$q0t(|s٧E
ky%kY1KWRzRMdvZJof\8qрT\}7Mb19\.e2n}ٳicKनoU0; Dap-FEW;1>}j&5
TAdgzګmɀhLTu{=|ܿCe(CoHxuA "$-e)>NE
!3N8b$Qvx*,KEW@<7)f/甖UU{NQy~ E9;H	=vn.Uvwިn^4/vF!#t{ֲo8yhu&_9LDCz_Yc0c@,3x?2"{xtM~YB9'2]]!#XX~(#>2S&4L[ݖR%l6K=fX*CeyyiWENŲK@rEfETyv PZ瘲PvV|W"Tه&4׌|}t~XC 0xëLlG N̪MQ6!̴5력~&q903k
Dvtt&ހU^=r|1{A~N&RF1kv _MPN-Zņ;Q8׾xs-ӹ|sЮVhqxyr_huc}|ཟK[[3eZWյ\?]8iRf؃H~9J5-ɨVb¹@8}rU.[yU&%;r?U%\uBSz if#FH](!N!qT;Yn$7"nN!cLN2m/̟%DNm~z=`oSn{ r!nIǲ##{Fu)p=`-S'*%b^Ps8]S(=I+;ίTL~ڶFa !VJާ5.b'tsY}[pYVz?RL)
tǠɼG~`'XrRd7n{d݁S_㽺"T|k]ik7c^I㐷ugѥd(1F҈m\.2DִHÖHk`/`p崱`Vǽ9ikD3'#/N|i^g+UX/spBY=|tX76dt%ɸb+(P$͉"(Yv6&aGR3KB1vy)z8^51aݩYeeԓD&@\dz_w%(o^55IpK`>
>pWnfƧoZH'!bn[Uqr-5k;C"|ۗe%EmLU]I,J<O=¤R	&#gXg.]pkV!w[a*_ڰa`kq8uܑs{-`0놁8RI?䎤.s I~,#<7(4|)|PZlƷ[ãG|uȞ >V5[q~!Qvڳ{YgJb2f$w=.bCْZ(!6 AQy?L l	x8WczʚY 	%vlչY8fb*h)ڴ!_){H=R=z~`͙*!h8_GB{E:qNBa/0q8-u,9qؖ:ROZwY*8@n0ryA%㲬ӜuQq<R;E	=h~Įs>xN#z;csP.p7@sY}b]v#Bϰ	nm0rl~RM.(.X7r<3D!~j#װpwޗ{[F<VN  gm81s.Pi0|TPC*-{2qw1&i7EOzQH㫁t@2Bn?k((1)Ȇ6oBJNES]$,Gn-SA;sU0;ηTн='Ӵ茕>.e%jHz2v-g"*t>7@-*gp,SaO;V)XR^mݗ*POVUd_8&cȂsJKJ'S߂pCX!@WAGwL3qF^</}2TIPK!+$?կe'';|uM==ԡ8t=Ye!	#
֐xzM$GV CͺkwڜX7#lP'ױu'#~ӓ^7\y^;q#%|zg0lt#Qn +B~DފMwf, ~)Σ|AEѬOvxf_b `{l19BB|1 wy^ߔ&|iùκl̸{ٲ(42a6C_<w3ׅl?4K}x-L	q!߳e;Er5y%	`||
eLPhO --!DRpöN>nz@v$--85DZO><AӍMbr|
3* fVU\w6x|1"|M`/!Hg8{`]Fu\ˎ@jy	I̪.݌9)$gc5yW6p7jdS	l>13Tzzm^ڬ^]=
ܗ97K,y7I?X"Ⳝ_))%g!</~LZbJ_=b=nV jx8|iYQh޷cEH<cvlLyə2M-?Y-aUnNd֍m/<lժUYR]m:r00Dix?̹x:EUdcsw;+I*ovK9 +]٬׼:v~MԨaq+iơPHff3vú~d\*ʢc3c͠cOl=c$hd?#E{OE)j1puf
B4??{wDoYF|L#:g~MdXN㈽dpklpёoCJ2aFٚdRHdX}kԗ}s?jߖXx$6Rk,!vmO^AFۂSaSK_jn6Y'H):q9H5 .!+Bm%vٟ~Lpd
U&-#`ZŬdC~ACke{S84Trc1?`yApPJ~x~$x.
p+ӎ12埞x@Nqj1q(M
mi@a^X6@O,;1Ճ˞P1fZ:uwz;('݆4Rh3xHEYLe2DA:Кһˀ* >$d:Ԣ' 8wI1<rQoA"wE.8	UrQ&sJvtȂu\AWs]EEc"ٟľ79Y{]yXyJ@{,l=+BET!'NfOsI͙;1IxI2*,FlDaƗdPf|jk\M*2Mrw6GȀ]d9Y[(/5C+dGX<$JRMDHF|hڢ>f2ܥLX噂Ap/AZPFD
{l{Ig7{v=xBJʜg<n/q B<0;uuM!SQW_ *S@ax(/@F|*9LҔL'<5+?||҉m`tܙd{%){[4RE ͳ]%g[UD6'[vӚb)	<SlNGoYL9\?[.?Y2>C]ΐߗۢ'=!t"|~b`cOzCfB[ʡwH'đ坝!nRg`z"2g]FOf̟S_~b_;hŨa fa/{:RQd}6ߍ-"v;Yu{[>A%}wEQ-c{Ţ6O%7vᤡCS1q'4&ПOѤ϶D4h%6qޞSQkFô;T.K?d/V"^΢F)(o[V26>#?~n{`<;/V"}+Z3iM M>|@8ؘX#3õ͛,ǝH8G8l:Rg%0$VNZU	WuT;3#/x}f9;:/k\R[\opOiP?nǻO|ʮm&;ǑU3H0CĄyZ}}IZ0oEefO*d>l>urAE9%RxLEM-k0trmmݛ|i':#8"k/>I?zXJm'MpF{ oH"/5D f<ϺWdv[/p(ou'<>;LyI=JgcJ;4bImRׇ1_"&ƺ9<?P 
:/7HI\_lx+){AJp~Qjbg@\D<|8Tt}ϮH-[ a)F=s$k8FMi~Æk'fQ(36) U}l:1Sb:
q"5P
)KֻxյtmX%&'*!.6}[Sjڿ1T}e1ESǏGϛ7i5CE5zĺWOƺ3lpu16a'79Xi ȿ7hPratm;.`bK@јϜ
oHJ![VCP#lm3b|)Oڑ*&u]2(Ī%طbQϧ[fPG]sW4AoeX(R4$cFaa$wDl/F.Hf&лS|ӷid@b#0`Vy|b5/,6/꘤sEliLլ%s$֭	ܒdV."5c;kn,+];v]Ea?`8ӵn}Z`HojF9.g&Iߐ˚4._>M-	4GRXFPT(ĽByȥ]Re#~w8 I '\9XKTtg팺|wXHPlʩ-X%Ĵ.AB&xU, 9`Wrobsε9$@milOc>WbI0'pգwN;||Pmyϔ>NWK[$xt.pdM!qYjG*Prvf=aqn۰'~:K9y̸ZslIJ78r^"OrLl=G);!ǐ_')P@mT5׶E0%SYFxLa[HfYtO!^c}e;
dV`7DDӻcAM9#?=pL1bٶ]7;Ycք^6f;'z	PF>; .ZV$R8T\osX
j%/:7#*ȻKi(I7ϩۛxp_$	}o[?/tb:i⑯GMmPLNF==Q3펈҈:4E-xq,ZSkǯV),ȁގswA}7̕l@9XwC2],sa7kb{˨c"s]pBʀӧ>Os=NtS9ފh@T?FP߸S
J3Y涭;LF'ך8KN_y)ݙ],tsu&ΦBAMWğAkX-.?Ska u\3	l]u;`[0\{QI8zu˒v Ht0Q/ ୉kwc1?R#A1|9yZjEBQ%N-A[5|jsZ7	Η6~EGbVG1E/_j?e|
}YƪN2A<3rZ3";ngX%ֳ3gxLS\2%nmv},kC̚3.\:P/_K*}.3<8v~Biԩ<CG^-WWʕt{P̏bEe<}Եb-k1%N{zgOIHK_JR7kϸ[ri1UOE4V#}ke[Ϣڱc]4,D;s"M;DWwxR{+`޼G
V=mpOAbwO#/eXXa%eD~7KdXwOϨ]4nzestˉc56鱃5	'Md9hb;Ů4sRY|-a9,?)ɚ\Xޥ$<;(eH4_H!:~'"sqo)7pA4s+)778iR{a˦Mk?e˫êq306cfZaȏy~xɗ~VXhNC־H*hp BV1F5kN[Tҏrek"\x)Zђ)˛ShSᆫ3'`b;4Sѵ"i ͟?"DKCZaW>Gn=u!۷dz	KA_B\jֶnm{m;qgBP >AwB_U ށucZH"{e-|?-=Dd5N7oM_7$0@+MAǝ;l3%5բ}n`k4_Vk゜br۶]29^b̌5'ST4F!k|&11f;нYg/@{N&Ǌ-} YS7vu71 [_ye/H5=e.!|_l/rram6_]7Y~#rC]qTIp77d5R+I	A8d3/?slMM>u9+I춌ҺpsF],{dH)vb*=mDѳgˁRN		H$;B@>eV<3>U D!kt)ݒLwӥ@cgXyVIZq$B9V+LwM!	_op8Q~G@u'~UWBpq$"*x]ZPo*1>6ZwZց8àG(P:/ck9,GBbDC&?71&%j
9.R{OtJW*3ʃuy4MݺÆK4[ .C_5A-y^3}8l̥RVn2=b=U0מ]_GvLbqy>~W0u~mEdRNb5	lE{'-ks"0s`Yѝk|r鉥<'O -T2ݹpapЗSQж}T7WP?J،,e!^i; 11ty4XC=xC+}Tn%SekaP3d!+I菓`~IFoy
!pTjD.~5r,IسUڀ>3r聉gI5Rl^SjC3e @®ѕoQ]x(\ȩX?K(0P:0/c__S
9G`أN8*צgMrƥMN-M'%
#^*T0PѶEz5^bͿ*DpzDOcG -&vhia&	ӽQN*+%532q윓`J`~QI~p}my5ƟW䣒bp'sAif8A	f_5kvލkF4*<^vF2wz8Km4Bgz
rY3^>pMB'^[d|HVʱjF\_o?xN{ݍ^Ǵ/s/ 7N*L
T8yB:G4(`i>c0~O[X69n|[g_ȫiɍ-v]ͳ@K~6LBSGN)7*vMmed9=:Y-)v~$u5JEIcτyk|ҥvLj]+rlo"$y0F޵kǪU>
ϣ\desɻ3<d	H|1ke1,E;5]!:m9oGr?)b㲽H֖$!dez@u_v[_EW| 2ojY_a.++ˣ4Q(7yqM^2YHwTPR9zy_eEPx#NS o i]ƶgd9;"Ǫ帷@kw944'Zֶhl,r<Cveup\%m2ol;K!@o<uXap-hH@ss͆GCl-{V7͍G. 뗚fQ	^cSG}U{y4>ߏa|e"WŌ)*xv㙂ܢ53+57YQ
]^;}4NܨYm=[64= CK(!̽OӨ4EAMEDQ˚yE9&URW2nN\7P#0%kF	5ˍ84Y.GW7m:_oCOg3doSa)HL7PGM;غV0;$ZXRF8!ђ헣Qο:B4-Hj3+[0|m'%G}EcKFqHp:c VXƹ 4cBC**oz0lȶl
h#,2Brei7lPw$r&}tJMa}O`0]u0
wCP-c9FAƶ ]⎜Xߑbì3X9Ԉ#k
O`mKS=oq/o]QsOūK3ٔ޿%KE"e5Ulzw  @ IDAT^ag}(XZȄ%]=h1&Ǵ2F)uvҸ9$N)˲O]g]L?<],v-Ei[o<֞1l7L):ٯC@΄.C^l(fPX}5QP|NП8쮻ĳIuEwlDC9~63$fS&JaR޳ut`JM/u8w5LQ\ApT[Iu^mi$	,wh빫 =m-+lO=~畦ŋs[Y Z}4b,+/
a=\Qro
	VHL0hCOHG6/I%47`y(-t..}t<v׺u60hvJv_in=%Κ^'Ŏcy.R
l6܉$3xx@!ȘGwvwGcod'DG׌=ֈK塣Xj@&ݐ5mQg6-9Ll7:/ DsJg؞RkRd9x"u'_2類MQz;r|?fe{%R&u^ϵ$앮a&:2g9>bBq	Fr<)&gcT]S!N`{tu²BWM>F3^Iz$N2
?*n.%g:I	Z|jX\@=
U#A& 3#x`5ٕv˰ ͚wak+"8!hߧb1/2?ə gwBmY'Mܘ H!30[['^y-0% #l zJ[Fm/r]=*'h.
xGM6Ç{j&/lf'x%HR@-||	^Y?Hzۓ0܄ F!@r"#UKѶQ$i9~d{wo6߅S>sG${Ko<@<Á{U$w1ٟc0o|)]L*?K?zNat#&wʮ?Kttx#FM9v
jrahY<v)Ͽc]s0/!(%aΰ\{񘃵KS)
$k9NiۋBj.kP\8lVQ(<گ\z؛&4D#*и1`P	UM>Jz	 mNv;AlaMtR-QϺ;[ʹ==Cf|y[;:@Ìmv|L-Hۓb9I6]'i3V2-F`ZEmӆўYHvꑖX},^儊'3ѥFw6`vuAeٟ6i=.4_#
w,H4g-rg.4'B~JCU2ןTpB .sM@gxdclǽJZrQç{^J7z=E
5%ϑ{T%OdxK3k;_8a356:%e}-(pobh1T
F6pxe^9mHpH5몙'r9 ]"iP/' gTH"4,xwX{Yu4\[V/&]6}l
nY'L20w-[I7 zbS퍷-5K;r҈]'ӷc&C0]3a?AuC;t]ImvTaRf 9	fa(97v[-'}߾~1TYt,Ǒ(gMi1N./<Hv
)W1CZ/&|pyW|ʣO!h!Ի.hv"uoIF(Ӹl(]aӃmffl M=nhoX>'-ȬvcG*WHʠgSYqpYQ9Fg4-NF 1t;gVXm ,ڽ~eǚNk%?37[
ޛAhx! GV+L;ҹ5()w$!%b0Yؕл	6dI<f:?י݉T'{Z_
Ox!pZQm|$l
|	ZxE'bi:4@ض#UW
ӿ6tr/5rYlg@}(ڶ򼮲b7pnPkyKiͫؒN7D7uʈ1-5#36{n)0gĮ{aݽT5w%EcSOr>ﵮWTzoKNw91~Vڪ.QE1PbcѤY0kue}Q^'qa=jOO
\;طvQl^[䗴9D˅þ$)̥;g-W7hptư닄J} 2Du=efJ.-T<~컲^(dh"{FIֱ~v2bu޻PR,^)eM/=8БT#'h%S>mȩ`HGzfaҰw? /^|Y*ʕvءjp4^ѼH"ߎ.aƪK="J;&A9!t+qƽ4w{ࠇ?kjj3~J	Lӄ+gY%٨Rc*)4ŞҺSO{g$ۙ,l {W9iq<w	VôoX)v
6	zdƪ6we[=x=+!wXrG +++MCXnW<E/"E;(	5Zkf:>s"𩖂ʶ0YLQ7jI+2/ĘrϤĶ~N4c&1r
on\eq1}	 .H,xf/=k.$lZStk{|n!qỚsm,؀HHxEGJP^B zs
NӐ8e
Yz,YHvaLe`ċD2S2k׍{dkK;%wm-b?^?غ$L.mo*Ϳ<d&.k5>%ߕB+ٞ#nLfO
\XVR6D,6ϸHB$%a~	uX#e9[W1%N85il5a2U1sOϝ/2f=<d"jRc%,d&i;nMx3iOȵXA{~B7cw:4,Fo{P+~	W͙`J'J=GI)<H5#2@-7ab;NMX*#78P̔cjjBRTGy<r7g8[:rx%~5P5Ͷ&T57Sڜ`<R= p-B ȥۉs'1ͥ k
+ڰȣZqUĘ=fZI(eooVn8>^qEx[{?+P~"1%e9{q*[Ce-+ȇHPJYqfY@.#<j߱?oK#9&N<`#"u̙9x^Xڬ@⎀XRЮ[.w+o,d02OKI?KyY.il׃!VKkp{Ȅ/m4ロVJ8r5[A<cyjWwOcBA,T"1ҙe[8s&A7<w:;xm*P--q̤a8v˒P5"˞fTg+kdu'WP?¢.\{iɞɾQgrŵWvЦN@90C'3h?h,/xiizas{(1B:Tٶ(:Ȼ^U@z=VpѰů#H$/G f=Li¶:c~N ;#3b\L3)wd6dw}Vm|lwDquUd2" 7(5N>:#n1D*/,^btFev IZ	1WQ6֚N$ǖ՝
XSw8w"X:,AǴ^XT>@8R@=>v,iRÁY|aF#Ⱥ?=rp쉵?.}F$F3WS՟k\Յr8LxK8SM$tz67sc"MMGL"Y*8Rvyx'>1(q_F?)e@vo9dΐ嵮^rSjC`T۪,.ϔĄhwQe1L2})ab?rweBwA*hEWjWc
z(uX=re_}4ϒiANӧknVj/<4~_4`1"d' 3TN.cI&G (KIY^Յ:<u:9!]0nqNCsfo>lo0J[!,@2?M؎;=?Բ}[)KR4|+Lf*Q7̮/{o-2T%$:|L5O&'ƐG'kEc0J-4ǃפ97a Є-K3dx[ܛX#T4?=h>e[=|of\\XNZ'r9.o)2i3u]OdГ] >?5Ѡ&oGDJ<@_3`sxL8X aB
-D3}agn?dkl!8/(L	][XKXW՛FH"YLG:{:f֌@u1-V9<C*|_;Ȥ4g#iPLlss/*9u\X&QQ?Yb0|J2~६Kρ
HΝ(7Ifgښi#Q^sxoBhLID])4;td[z2_QEɗ!Jz\pgčw&R2 D<~11dMF<Im$4@kq*/w;Žp0Є92XH9-tR<j>S-b<Gqjhjw7LVH\0U"ZZ?V把>1\TDƤ}7B8FDd;-2n:&PH`ЉG#xE)ҟ(#ـp"6	X7g]ݛ):4trL42E 1ٹ'I}i&0u4mTf;˼vU7gN*^[	n9JFOxzgUq1B?r|dw;0'UwnS\G̼-xewKoDN jZAujZ VdSk4ՒJH|zR|3]J<
ndfBD=9A<ՎLgMg}%QhRio}W%so(x籅v?M*	\`&@n䶌`/tԽK-"38>\wgGʲߕa.W[lN?Nw6;DZݗ99\Ь/-Ջ
œnq]+;mF1Nxtae`C>6I"lq}7YֱIqh	:I[Q/5Ma>T6\;463\[A#
?F%>F{e$ZhWOH3Bf`GDn	،aT8דm{x"'ã!B{,큝N+u/R6+2ل-=JKy=O}t_#`jL1tŷj8YG&I/S.>#cؙ/ooK791ͽ@ht^M랉68ˏ*?p8}35sA*4]"BqnLd EvWbZ-lPTCmtk?NKZ-fɘP"0]"&\=v,tqeW'4748EClJGxdWyw7$oGE?jvYNp0Um3.d8ҝ͸۟ٳqG=[9g yb9%@%0P6lpu8ņ}!(C1#%t#,a
l*30IbE ^؉~܂?h}Dwfj/?Gj+Ff1/IĜĵ^~?(to}xVb:~̎AD l$nnt%AHCJ-B2yC*^92,E&P-+w0\7 !
 xBgeaɷ|;;s9h[<+w+"kM\f>{}S,|O@;ج`\ՀɁ^~8/])V-rUL1ŲS@a+;lJ
KW:rjȣz>~-_W<^ue׍anL#>&o Kg0e0E+Y}xC.{[zJqVg;'gE^5ɇA=3`%[D?Em} Q"{ uǟa6M{-q`f pg#DZgD50[`	C@ `yFCDwjb$О9D1h$:J.j|;
zl*e{ew;B?J}eh$vh^:@/7g?<8]bbe63AX'tjq8/66GvԝKAmM4dS޾ot&W_"H6RQ	bQ2+ CЀM@gvlp9/W6|1o{`qpQHlq;uU^{{Wv)rrFo<(~d<邫de{kMSj%his `ڢ;Ո؟: >zTwz+ᛃ.!Ɏ-Y6; lkzHiDҦwYa#<1E3֮m"9K;|Μ9=!;pB;@+V=E%xF2\\eX pj~4_ַo Ivzs< [ly]@H{9^'@t|RN@0uCʚKf&!2l6ԗrٲ<h_gZIQ0vYi8`7v eˠOld[Ue5JMEOc֊힢DiSލiVP7'M	Ai!A%:ael<gY3TS^98$Si.퇖4q~7a1G Sۀս99
z9-'y|@=C HFeoƩ,sA!Dzg=ȇOxgԎ\<RWwвD{nnaeh巭S,?٠d)"a;iv"9fx. ^⯁9ÿ;գFr@X`:TYM)ꓠU,+XWC~BaYS"ܲeaAΠ㮸g+~2F2Tgb駡L8O{'~lVGɝ>.ӪL:6QwW,A'51̝x
&mbI2f=76nc^o2X4G1Zir@pƲĐ6UM˨$ew#Lu*faz@LZ*m[IL>CBv
;F4>ձ{T~Ch=KPxeG|QLipv@£9|DʡUֶ56MKE_%뜑ᰥ.ڢފ=ͪ`N`YI׊X
w1 ԅڹr,@xnWSic[@^d;)OO=d+ƏuESėV-u|?bgo/[٬~G!IO7pYЃƤsf1;]i("/n=ǡG
%ˮH\</8F}lz3FձWTrd<fX1ldgOM_ؕ>ePauPh<1wyvmɗO14:M'1J,þ_޻-hn^~``S% _6 oIM%fr"p4OvG%70 j謇6;	᥿uO
#|ggTZ|6g '<mnjFxcj͆t
lIFlϹE6B	еlL=cCwN*eVZ#DpҁWQ ^;M>
č䝑(Ҏ5~׻&u.D ]_vd%hD`πvk8a!83dߕ%!,_.BF"RNqC'N;	
i@2E{Acخe^
d`_;-Yk)^.E'ږZ@
XtqgK쪪tϝ窺5RLB @B` A1QDEA@EhmlnEā" aH2O2U*5ߺC-*}I|s39kֿs(2މ0&5Jx=F?	w"kr]/98[D~O<9F㐼v	E>d{I7n,DVTpL+}~\;`-u]TΝ{i|ŀ2,6 vNpɵוi89$ʢ#iȘH&h_Zuk1 ˟`X_TP¯Xt/\XzÙcT8R+RuV5,ëͳVx;0yA$ .PC.nۄDb|VQ"FuNu`^Ae5i8HfXM؂Rr}/; A'T{9qbCz"eu6cQkw;b_iD_`?Z20C kO7)_<d FjJ>hZ'<)@n?xÈ[\:LƞWx뛤%U+u5[M଱#ŤF@	sG
<бtwwK9rHGm3Ő#xVmx3P<Յk\բ>Q&77셮.kb^w?[+d޼v|_F͘6k==7%]Ariʄgj^	`gNeɍV
JFO2ɿv+3%K&cڎ^]*I\V2U6h^.:^TI3lQ2@\y~k]qE4Y*;Ie?F%]`=AP|Yuav6*2S{_SCi!s,`{u?p~xZ9?'HN`QB`܎@]Nt)VB¢ 9ºԵ|?slh۱׶y.M3߯?A֓9a ᥪkѢ<4[CJBxm{eZj}dZ"s~ Tu` CNnnk;K9;hj%MAOyG^>+g̞?Eۼ2[4v1.)'Ǥ&+g_	皳ma'׈>	[%h6i>s!,oq1ZbiUwӡ>4&$_Zl%\խGC@H(rZ5L`d7'|dν O1S7tM]ݤltjjO.-s[|)2b2Qآewzwڍpq*P
|~J-S]2SSg[mTR486mԫ(9nKd8eg;qKhnDgO)=HhK.Ʋ"YF7=h]oV4U/	 a `V2䕸|3lVt]>dI T[j&Jms!	n8~yqYBXu'oNgwlri&EN}}bʉLغd_$Y  Awf @ED͸S2!O2~`Sބ2
,V܈Qq3T׿2t? Wg2ATol8ؑۺDjGrE*=*Hz/`_~KjsjuR|*H5"qPb%3@ڧ 1-"ʃT&ܟ]xz="Қ/{l9iiώh|+~jqEi-/ܘȻ`6d|P-1̀Jأk'1ȣk'[,0*7j"*PfYQqW<,p5SxWxdRK@rwb߭RA#apaZ,Z䁙nRM$>_#q3bczcZk( {@Y1l26¾S\s6Lt!3;'U%b1ŎV˰p;ϣ"I5 !$UEeM +Z#	Y;;<}0pn	NxM5{T[
-V6_Sެ~ %e{| C*<1T4f߈J'Kb*C$o	KK6;G=D-eEn6 >Avl4;aֽ7ƆrnG*rAG5bs)䦿{ jX6}?EO"n?)yL-Dk*@i-=,-˖!>'ag [mҘ兾(w <2pN9ljc__3־*?[]:Q?|ldF^̲&I\m1nX#Pn1S!F%Ԑ9$P$$Ǧi.-m'kt4x)*WY{nt n"4q=H;oEAXZL~GuN׮jv7?vqWjdE
m8+@h493и'EL"yS=3@[Q<~_au#4%Y$x|nAݿI/m'|yB#!|m<Fuv4I˻͕e,i,܇w;vJ`I8_f4fp !x̳oG4tA179<ܓZ=3X㖃q/^ǣ""j;^ 	|Ќ3X(жO [lw	{}h¸8.C,@-jLW!w w@ڪ2tSEz]<vAثLY1JLXBi8 :DH6oM؝y<.4-hemL,lMV._fILްC#te@?<cb "@kd6owʵb#i<A3dNUKc3#r"Ix!9QN%3 \i|P<łS.ןbW.ܭP4Sov%01J~WZ3ϣZ55U=获C1jj<-?/$IA+K7mvdPM8VffCo?Y2SE0ou:^^8H$kipplבfu}.:ݩ/:P]cWtA/d6CnZnf|=1+~ILLhm]ӉzR\)PL9OB 6d9aѱ2ݶn±N2cyf'|;iqu554QL{3!$W&-?J6 :̰;"l3\iľ}A>>X;.@:cU;wkfu'=h$B4V`7J2\c*։
ILTxc'ˬ"՜z|-DBUa_
ҳ'yS\+FS'iXFAtH)kjHN.^P?WMO+ߥefj a	EtDPyz281@-x@^fD/LMa{y(]'l@,kd9zW-~ss>#D{q9>wRI9P>gq}qq]\;_qr'W_3Ab9JZ9G!fL˸dƙ@X}B"g-Y(g c4w*%♸  v^d@R?Z'ΰ^+d4<CY0Kcly*`+	Oi܀gyηntͽj 6@تΗʄD| m-kgzIa{NW=o?;%LQ$hV"_[s7[˳wR2>^B>7yδXQ<˴{(bހs +0!-Ɵ/py]8O#n, vLDMzq7d{K4ۖ􌊐џ},N>E{SާVϟ1 BvLϡAu/CqĆTy3C^4wh 52ML<P]Isz	Bp 7I_^4?ۀD&+dPToq5J׃~2XmA{:&-(O1x Qd Gi|}Qre+g"i9W[_.U?+ns"VKN@goLEwbq@'<Զ~f1I0XP]]e!BnOIf}dӦrAB҉Hha~(V ?K޻7t@yGg%}g,: $IĎ?0G琉ɮDi|3콦%T*Z1s4Bj^K
^w!chxlnW[l8Ay Wdnw2wcd{>zpǽ-5%OEYZ$z	E}93z*Xxܵѩ!oI+&ٯ!<ǻӞkHj'>_F-ӴR2RPc͙mc&aHu	z@BU-٘"LkkECAI1MZj`;dQ]^ƛ*kj gY	mFŰUkh- 1$1w\P70KU!4I4`q.r܍\JE4G̴Qy+[@7PF*&1,юuFմT'OZ(pML^(t3(u-=`l[ʞ#ԓ\&s<>T4S><πlC6}p0*_.~GC\ޭ7	:sHؕ`LNZdTxQk~ N:yAO-Oo;<4^!bK_jȽ@oʉ{ݢHoUZSMtoYH;ʕ~}~AxO&b7[u'=s~o{@0][7q.WGGS>\T#L_&Sn_zO͕C]g {C}:|U$u|i`e&WfSOz.TݸQ^*Z֗1en1B NtJ:$P0qnp'ݗzW&)yg5Xư@g%<?{ⶕ#=ۣɁ{|-$V)G㣇mوiNLYwv']b>>{rrlڞUzN`{?T kN^\ ќ~V/O
\ 5>%۔f=ڀ6<gH0Ԥ?,^͂fGDXhtG؁lpDi,IRu~ӟִS.>yb>ج 韙sX2<+غ5/ph6^<sʑnwAsF'ʮ,	uGAgq+p8$3}X8qmt^tjU9azVT4_Eb8:O#ވ[##I+ 8!"96;Ku5s80?HZurՊP,oMU$+:/Y*Ҁ[<C
`I@<cM|ފ>T6t珥iar84G\޷DV'3qH-!զK:6GG`ЯŨ9@ Д~DJil>AM2f!]U@U~x߻EIVS1@P͐رҸw%< )b mfx,vP&"ID6mK]v(FxjU !lW&oA`umBT243W
VLkuKLNe2.mz>1o.{-3A7)LJ{53BM$FG_¶1*I-fZnĴ]tml<@{)ηdYsuH濨V  @ IDAT]nP֜ȡvbw&x^^gO|fBjP	JףCG(yRP[Z(`8,XL5L40SwK<Zǖګsͩ4%xn,^B99wm|RuSsi͜5Czjj!ש!^+|I O:0Y i??U857j?p!/fh<N'Dl)`n{$iv.zeI!(˧-<V+j|`87P!`.{rC{~ k},IMG+H7Bnd|ԁe(wPba[YrSSEMA"s*
(q${ܹ"݋D4xϋh?M==xSmo!}cVt,Y,/ÖtZ\M\㍤׷c0n2J%EԶ|p%lf}XӵВyffUx7D|Lb8꩘;,c}(ʞ;i{7fѶc颃fPGMW0BmLH38gӦۛI`!?69ϛ8i&sadLxC%d+á2 O"qa.R'[޵-$3EeE)R; `ُJ][w]>^@(IHfDYCMW'ZrZʝFk?u=.^O,jT>Dj9	s03; ݍΟRiȼ"_{ 2L[D;XbFlqG [v黻}IgDCOg^6[-~uTl`pzbiWU0[o|)lWʜM%V,Ԡ$ 	4c,Yg(L`}i[qz WA-ce!`r";;e dLmNv~SAq:bRd9oWp)WTP it<Y~=pME%fDO
`[3֠dc]Ǭ;-/dm?M:752c!<(έYٸ(H!Iu5 ꯰Ɨv$^Ca۷%{ṭs9G賊w>I ͞u+2ÙpѠv u*c0HiM;TU㟢QhI^K:B<譧CRnL5TvAqL(]MI(_[B~y,5bw\v)NR<T5 ۹!怠,i`YbՉJFf,	tX{jvZ%5xП%xT T%D0R,p)XNann:36R,mr'r5.Bf%'Z(#'HOV^PAƻC9*oص蜱\)[KhOG
Ndpm[:oK^yדk:R^WvZ\YWGٓN#F>Yނ[R5QX]\2KsҖ8
lw-e|$KqШ0+j1n{^eۘCl?w1ēܨ[qoWa55PnLduff/3j1^ya:!y}*a

k$~%AÏS	g 9ůKSX*!<3JߵFX~'4Ը.ﹱfcos h8!
[yB꽜~fj%Kj߳bdv%|0-$'(~쳩e0Һiթ'B,*NSSm}ld qxKWEv6$TQC2xR,d%H֐ؖnCu)WX;	F8.)$;d:K:Ɗv|'B)7۩ntH)XGY_HQUx(Ey<.RuHsvO=$Erc^B	A&<	K֏3&PR\0?V^|0j"iXvCuϸucOg+WB`gϯcutGS[v87.\ƴdH6dBXmRd`]1yz4CW3̰*"P=aD/umUёxe,]-"Z*Yq^]ZBqu}8
|ҼΔe}0.ko|iBQ]Xd6,kՍAj	B<$<	[LYs*={Y[ldv$^-3X nuxU?햓4\?6z/%;%pիO8bIoGWf֖=ZFSqaC.B@V4<{ttq1,R5ʶ)s r]<ڲs'ŞiQeG `L#nu9f̫^SqtcOIڙr5Wu+{dx)BAR)`fF:ꮒ7c.1e>קnЇԦ	:U ?!aC+;qoqM衾yR;1/6w-5S4@VĒ洀x#t?]rzkg5@6icD\oWZGv8M9MT-s.KJ0DV2 4A1ۑ-? z+JӈxOr^{]_m+d\&P_:(/HG4Yv% :I핝|b|cx@ 1pNa)mm,ٚZ߰xdd)8<=<.h ݋و/LF~Nuܛj0YlZfl}G XKa.f/	Ұ[Wo0#NKWШIBOj9XuqX$8w1|#lԇ4Pky"؇>ivIR)0DY/^L}Z]l`A(ԨfLsãɐۀ\>8 tHAp!PQqdXwVgm<h@lCSF㳽'
sҝ ~R+V6ߛ%sz>|?dYx	i#p)
Y*X-f|v&CҮ-jqFf"$p5K0 80w+mhr:Tki>˨17xۦ.]:]ӥ}}ji*Ȃ^X#<`U<iüUy	<(:(ݷ{9G+pr(DJqim-MfF\@#{lُmSJe;o
/Fym]ZC1c'/zA	Hsrq懶:A`Ή7`HXzi)_$J[	+\&g|Ѽ-_z7@-`cpj,HIҩ wS5uR 06Wpp{ߟŝp{w_{NcݫI} !.[lng[!33#,k%bV]wBU?5?s1zcHa00w9U<Zɚ=ן'plh3M,JC^G$pn
"]O^rAI'wHBz՞ή\7.e{xøWTKTCψaiQRJDi+!q@ LBGAPX#h*
ƚU@N|w!dk!
zvhBqQ;a#8=w8?=\5Y"g?cZ@z`Jw*wL7^8xҶE賂u*T㥾/S"!2>4yC*>*"c/mfc_okbcW^oWxCvi&@Zgս{m9^Lϳm8Zy+7t-)I}oHg'pl(kw\
D pG=B`mLBe~}q3~LZPjo%'Cocqŭ	Řv.ţCL㊯0pb>NT
ƣTL*bں+1 yWP~RKU|T4г5]{DڍXk;3Qm=obZ%1Cd^3Pÿ́~;toʌ)k׆+	qϳ'sP?΍cn`4``c$8'LxQ"qeE3Bo"Rcn5C1G(.il̢)u>e^~yXQLe
Cܕ^8u9X/e-]GPŖPɍ<b'Ty۞)!w,s:02
 t;pJ6`?	݋ YXI'_3!2\1|aIߐ_̬˔:;W vDvP:{o4Zg+ɷQ|dP9(X.n4γ^db#.(NɡU&'{K<={B39`l^4#U1Z;wv(h5<Xző)=M=8ޛRȝ`qa^J*"ތɝඒe+*j5LaƩ!П05rr=`os9RI5bVQ̈VHٜdܒ;c$Pܵz}ĮDW[/?ߠ`89(}QK[_:?/8Z"qjmK{483
#JiJ'/ܣI8/cO}dP0I_MwTQי{MNziV3}QߛEسo)ar0KV+>שhV4$k=O,Z;dy^tF`G x&¹>%;q8	gwp-dF	ZY:7?dk%3$R2mzͤ9tU*27묵>iK[5ɜ+VGbOKTQ&-+/VmPmmSI}N܉B.
uS[mFwFcyk&H:T/"o<Uvʹ4l;>z:DFhm9.n7VaQ1:6mbko/2Jl2ad`"b_3NǗ&'5AJpR}t!q=y0ZhDcc0ʱʦm*'MO|Cgmk	3w9LEU{SDQ"a4lx4"9++t{y^8vNiMC@s.;nXS}n}&f60a?`7)tgt4ϥ8ichDZ\{Zy?r
ǼqhRr4߭M8>!b}VgC9}lqO竀X]jcGFL/e)MI3łQo_ЄJ}1H!QNQ֤j/D1|J#8圕/hs'-O.nX^>a|U`U4I9u\q0K>o;@6ڟiAߑЅ?$s%<cS^%w2d"r,)P<Pq>MtH!JzsO"׸jMR18/Y7>'"%]~^Kp+yᮜB:KY6	oE:?]?ד+qjT&׈x gmqT;b4|T7ޙ[)'ۚ!YoS|T+vxh yK_6oNTԐiOɐ2x$xbȈKDt;Ɵ5$]\hMSU<{kܣ{`ypJ&s'{\*ɘo$fS.xU2NEZb~NgA'WB|To"'E#DXڟjj
I:~	lP,V%;Y7{uL#a;+`F 05&.-Hy`"}Zvn#=|MC\~oK#8uLyIC8tF5{%s[ Qw.XE.="U#],Du/u:8GScԨE d+I3~dT-u.m%*̪0aͼzjTWyX>O7)y9>Av'[/t@݃;wDNÑAaڳ1/=_fKhmN9!TL?/⨜֔~>y;oGAͿ a0]t	"MlOH2AlG	j(9EVY8[rۨeB#uWh3)ӆJCH4gG@^{W9f&;PU˚'8}1ój8ae6do,0E7:.F/~eJ[=18x>Z1Tw_H~88fr5]#NM6rRcAsFdn/fBMM<h_u#](PdZT^aAgZn{Wю>otlD̅ ;yyQ ۉ_w^F {bZ; +^b!>:!9XG>h_у-Z ˱/+;د5~Ut3ƽ?T)?9P[VyK!Էz{bՌ,r12[AJ58e;P3^^2:%*0 f.?UlU!e?3ė5^q&
^Rc1Ϩ HWL[R\Rm ̐b^ernA'lߛȽ10<$P:$/EՄӻ;󤦆~GPEVPfĐX):_nߟx26;3QL3n+ީzCx'MyҎ$1u>>dawۖӴGP)a2>WC(~]T(9/?==0Z"a߾Ќ[>?~i梔=@8^MW-2f3*
wBSl҃r;,=x<˗űtp`Zy5F@_1%,_`5ZʑThJY齦71۵d8&9L{lC#{̲[KČaJ?E5/dm_wmx?ƗNؽY5kp{g5~u%y$/{w<A:L,bAH-E"{^7	#fZȥ3y
m5˘V.D!d?^8l8碦G3~]4l|ʲr=lY#Mgy1ԣgMK?uEk;J >\ 9%&oG-V,-(.rqɝ3`"YKBcRiK53wXͫң]Bsb0?Ujjyqw9cc`KHU:~5.64zV A	8;iy);`7Zx/U}tSwrZ
^xyGZaܠdn^gt*o /hVbe2i@iv
w)N*5*-dq*g>8sqiV'1S̯v񰔟tE|zS%%},ߟ䂵AJA#( 65e5#ty+,;)Sg6W8s+{MhG("A) M8jJPnOp![t6o
* %V"h"u+|?Rۉ@F2)
O6F|>VF|r4kYhtuYbLH>.I 7r/M|Ep)AI3dS5tkE X2)iqti7I#4@ 	,yfun2kBeojb_2詚k5FԘ$߳#,G%...y~n[	<Fw;&q1PqRQnp6<XӓRg5H%^1a쀢Wm> LM6oL[g Ɍzx
$1jP#bQ_ҕ=vNg<+X̈́yʈ%\0̌ͺBE[G.00i08#cƍgnP̪`P|b0Gơ{Ux	rG[ι鋪:\>TLb_SyOpo:%GǦ+kw#HM Aܾ2ސ٩lb3H5%G 7
ZT{`&
Tl2U#4R9 *ٵ3+oLK&!MÎv)ja%j~_FTk!DZsqLj n}6y-emEFm9Zoly܈Fod}F,*9F:n;Vf-DI|0	 tMMR>Y5l!5	\N=	@0h@JrN_߁Q?GPCfFec aߚUy-.@<O II3Nj;SsVIzq jSh{,$kXw!@o6tP"wʚ<<`]<xnWqN!e$C<$i
Ϫah?`t07fzLmS<-c~ e\1Kً.LiɍyP*#*㞧=ʨNvbnz3ii6m_)=n_flٕSTl/Z.BΑս#!GD*gVڵeoZ%f_FU>
4F,iNAà !=]_Ƕ>S<q*/!OE_s"\F~6	I$PS| {!7z:=zc/b`hMz ?xeCa]t~.oOEN-G{Y_TAe$$``r\b;ϝ/+<)1`SUwpOp+!$~nF*Zfa{p'cʾjrdL{J\mX*?EDurIo+4*PD*׉f3"> _&z*\P^0,v<IۂѲk3BUDk7wtׄ@Ypt<^ɹ}<?s8f"B׸x!ä2:ch!)HZ[Tbŕk[K`2 s-pA7irSQ(|o3;ۣ&sH4TvF/	[ݼ\5OPobR*=M6!_e6:sʷDhk=K47ûN"S7[;r<nVY	pz٨q,$l1۞3kAwK|n9wP94ڈ[ֆmRa/S֙
=7ģ}Ȝ6ݿq\0hKT`5Er6R7#ω0NV|2l.p Ճ+r,ڶ'4&?[#V<K9*.C=CXeH8@,1|Y&'a CJJ[:e@ |F,ݲOdRcq0>| Oco/Gkc.-+=ƽµB݅:K%y.Uϭ-j qM]v.*m3V2y"|
H~V+n,d9NhGI)FL	'SLe|Pcyk[=M}s	W	6*U[[Z,<5u\oX+-*mxA6Rvȍt͋m&b9P%QF//h9DS[@Kwл=fpf4G/ <$kt~_Az%Wa#e.&X:Ma/---3t2]7 Eg MD;BP<Eܙ|"<بQ9tq1PT*Ck&-Ex(JrhnY݁"](IvR)hqҢc%i݅԰ffKxⶡ~+N.4sZ6Җ|dT4n-ɜpR}Vmbmy㌬ABjږMٳd4
leibtIS¡4vIf5~LㆇĥeۉF;o"^hēP"ǆXA%r/+@l;\'{rcw2`!=R>f@*s"{Cb/?n.O	+Zmg%T@3\I^'bQk
6R@uE`jٜ.;ɱJ#Ca׵
+K5ӨpUQ-3fcS@sCݎPge zb m.	l8;Q6K y2&zeX-7֑#k֥sfm4EaӶ<yڷuUj;&~	2#]ekB?Bc= 2A4]\rsP@tTi½j)Dfj6Y~&믿_q+DɰDQMi	?Yg@W W c<321;Mj୏a
0s'2%XpI3?[=WOX౦:'`˲Ms `tc;ۂzdQ-7#^RP^qw`|˖-#dUh'{4񒩜f{V-{
ݾQ037<I0.6"fČef	kn%(0Au.^\0zq#^_ 0NYUm'Dp5"Y6KaleyI6,q!qb>v׌2:1Āj&#IF{b!<[Ixb xF95iK'⛕>똞Lr3u&seqL2k}8K&e_bҏh3Zٝ#e Gf"k	a2g=:K#8.y,3k<JPZl`̳+j~!)}O2)e/uhIfQQaK:Q+'|ܱ1%~x8b*ut"ޮCi΅,6lsǈrlPfscs#x:-v8u>gGH&'Ui#DYQh|0K16q_:qVCK!ːP^.;%t^i3AwJ40gܢ8_8
uȠڄޏ z9
3{9քmm࢕+d8a!QPqQVᆠȂr*afMrC?C6DnCwhYY2eǱwaRWDAS\+buAh	@
 ŧ%~A JInכKy.;lV:bj'Lgz@i^43?00&x<p/h1/\}˫_RQON#ҹdVHvаvIhrABxA5arpύt%9,,(-o;qɟYN>~Lp+51,]0{+&/@8)n9ҥ]HZ0=]؅4SuU<ÿ; <AwjHʴ+>CWeơ~!z`)h&0-ipB[zhM *˻sݷsgd2I&dHTD*"ڐjZX*njdQ2!@ɞ6̾}3w mXI/Lv,\{<PŢmuQo4ZK2[;M*y¯«XTqlH穒C81%u gR#PF^)=1Z3_#phbuGwU?āVYѨXϏ o]Z;Hn8yM4G2H#s;Pa(m}U	X:>z@;6,y3nV#F`š!$Np zq-YFԍj_a3LӎiJ *@]N*LiB,N@gB9}fj, nmjŉ?]^eh sPztK||Kno rHh`Ɩ/W\M	6.˅{Z}e1b3( T$\iVePV|UC:`
:C-Eq1*[|`|`úXOS6bٙ~,)%FSwÌ~I/Y? ^IaO|o4ׄZIHTD=J?5}@b24 ׮͛l'/S-f2X,z1h/bYȴSݛ){Qвۥ{[iU׉*c6A{ÑyU܇Tρ]\m?'誢? +W_q>Y.RmKq6W3E]~lr_v@Њj(ޢN$`M݂ g3 f7'?NG-M@tp3(<ĆhH!~0Ku4NJWIXe"/A)&3>(QEAtRer%(iwvA&y;Q0_x$ϗz{?h7ajb^fyi%qX&cԺV92Py"fӣeq31F;weߟρԯPoJ߸NbhZ299|mLL9wf6SڪSF7O	mK	ʅ3ZjR,2zh5d/+峕e<o{&OS1N&麪&QNfî|E\_϶SVQؖa-`I֋RyOSA]]~k;~XO%I4@6UĨa<A1WrpXqtv?K)r2&۸Q;*:Tɍm%R]/_ *7ҳWtauIZb51X\Ω:	p1'IYtuXK)RMvPZ(/6F+ER}z3
:Өhx:~ƝB:P`xl=M5x!Xt
O> &f^bRgw\6\4jc|!jU&P# ѝN*1;x)|0dsN2^+ÛfOd]B8zFi7ZW#=_Zڡvrz=Ztdkog*-+23,"Ի;ΰ>C "Mv]P7Z =D*^e@"Bk; W6b10"\BKJZ=ω8'Ֆ1YF9Gs}{h"Kn38lZ&/[q H-?'a݇<u$9R:H^V
@d}s!!A(/Y&\GW\Vw`(Tw7]t=t3	F6<ATo*{X9LpzŒ)R9A9ͨq\>(0lg!2c׶7WS0# Eԫ3ZZ(-\ސO9o	`Ȍl  d{+Epi=ЩFk76UOÕ1,3kUw93O=hm6z7KCD$Xt|+=^V;ؽ7zz@{HV9n<`g]%6K(_\h.8LK8>X5Wx͌:3㭼Jsv:z\ҴHKbS@dҦj<}:cӟ<鬢]^eӯ4c/!@f駾&[뙤z7WGTggH~jWtQmbme-*Lh,?BNE(,6%f:ГEC)!Ls7zzdc,v'YhX 8=pkGBwf;*&6RuS %<9nYPNvvT(.sOkͮNu<|cR-(+%BAw4e }^i_E5*X[;@5h7ǲ87Tx&D&;B	ǓBAuEږs/[,J*H|;j5+sB	d!C	w,toEn7v/ I}Tԋ_rZ<.tQ//b?D\R5h~  z# T9,
m[B*di4jm$rl&)_iأ%%5  @ IDATUr!:__ޞ=dX[Ƞc/3+=8m;+<ӏtI7[6 CgF;&+0)nK$*,\O<umNS9'PCl<yQZу}v67@<1)eK[^Y*ifwhT<ۊqb ymXBɳ CPkԫq7DA>SN+ϦS=^.HQx>쑁3W/lH;_C+O9||>	kmeD~J|Ma67ݛp))C}/f/K!2p|LgR·Jr0Y XC(4z6Jwsĸ;?^Lil~/XmñٛlO,"9ksEm)9y }ZKz?_h1۹Qf/+`x_gW:C췟-Eώ[E<)rx	Sf,?ػ-LQtRlJ8}&A$HL"!|>Vd?+:F࿄1jnnXH!m_0.k{5c&!YJ )rAðj}.ERU3|0wDH@^m&ғ"еwU.Ô+ǉL@H_ m,3l:]>r6r;Ӌ}ɖb-$K$ITl17-e;z(?]dMHpnch=\Ft~RTz05Æ߄E8Axl re[D2XFH2ź1uU3oGzLxJ#葲tsS&4u$hsRbca_cz=27znHQq=ER qT5|x5Y6ݚR/ffȇ2 >Ώ;"-ij	upz>כ\H9NQbMZ:]97;>2f*)Ԃ#=.yD{rrR^.4Ph1+.ڄܓI)?b#2K`?Q,[h٫˗}#W/tM7'lLQ"E*k5{Is5&חi`~*Vqlv5odR/F^=G
}4[w/r-0P1h禍s{ǳ<aċf:;D\m՟3MtP 4+ ,B23<}l̛҆M_E|"4&)jfc/d3/K{zEI[a29?&GQDJMJ+J>/fbQ&6n,<r! ߂fvh'.zY᭨6Kd=tt
jVV읳9vՈLs0n0(n/ki<hN.1-۟iZ;ZzJUg*77ޟdJ?%f!$f&i,	?s5 zA!u0<poOGq+n/fE{svxQ;U&.Y^S\5!f1}%{
Xno޲f"Q51+)3Y2%&@~SSB׊RvҎ~YUJEf"Ǔv)@37 e%D7I,{n51j\#V$zbM
QS3<j{2'~?޽ٓCTU}m!G(p&j#_	CcY4/
sɞ=_޼>Q9Ջ*0OckP9Y`{WK/(ڕ8La07"CL<dSBNc9B7Lv-U&jVUY
JцPޏf47cs8A	m6FtbJJdjQZl^3oh%Z`yĈh7䃻{_%RfU(imhIMkm(oIޓNYJ(% =RV5	>YvF&1#!ᢍ'JN\v.}90gC[ʁJ8+
'iU *wmg5bYAxWt3E]gZA<=pp^ułGh
rL-t' FuLZ*f5JDn0IRhGSX!h3dPfWPu~z'`fkvهӥdb7
7[nir٨pY}Tc ځ"Nei0O#@3Xȱ!4bJIY~ҎSs9k1<RQhi):tMFlz9ݣ(?9E?i\~jll^7ꬹβa3EX7nmLA(_rto5`::-8%Sq@Gs,̹sgO
ea֍ߣ$֧' oEQV~!ҁ,|sAycMw?0NH?>qzɕ0TLUvcb`b@e/V"ȑ3F?ѰafNn ?b!^Sdӥ"}DN%,]9Akz_DA0W iBT؉	 1Y6OZъgD6b{噇bi`-0x}a5(Vr@FVHp2ɓb GhTMbAK\uXjլ6Bi*Z4DqЛ6HR~y0~ xϥ;Ǹrp,L;O$PFv"gqS#3B۳}Yt%DT*z)1\¢|^Qob"bOn9BT)CQ܌~wL<k(s/?<cIYQFdp,}Y7X,̌q*eфH+<3nP8+޺\[j[ΩmLRAOiG\%ydE[~Ĕ/8Q/<)Lj]36sr`B#E1fVR5s'O}~)h0i0_9xK"gҕ8]T[.A.Ph5PcRfW9jխ=c#T]-|iD^N%r1jηm?;')3O3%T2m(yp}m۟W߳-_ <(+cRA¿PpIވvAufa;d ;Npv.KI}@-UH;(ԩ`|dF%0B@ҳAvz8Bϩ-f&LspԁZScY(>Y>rGC/2srM4?CY$9g,,@3`آ{Ky㋘w"ʁ9[
]i".nה'tP6GAIUsbI8ޮd6R`Ց*dQgxJQEEHǢ6ğ>]*Xj˟F"!WDdn\F!:B|9vE
1k TpߑrJxHҝWɄ x@DɠE7kp#9*Qd6b:\ns1]Eu]Dnh
D'dwq@S*R>XP՜#޽|wvV5A|ZyoF6~
mQގg(
=vQC/V+%II*>$/t][
09k/,RQ	:v9NouZٖ'pEUMH_[8BrU:6kuoQ/]p>t:RXz7+Ll6HuIXPxˤ6O|۵sE@IU:2iL}+ˀՒ3@L.(!IvMP<E']}<H)&]BݜXmYvY|v?=V~R=/ i3'=hY,ZKU5q#eRCxRD֩;YU[_EAWJY,cZrd	/gxbNO	&YCn S#k { 8YxnhsPd 1%KNg^^_M61u,+!skh؜Gr`?N/C_\N}My5`j6.A MKf
9a?VvIL"O(?wt) 7yLhuCCL,w;>&LwafD8A|dEaoZD3v&Zq걋aR5wl<Sr)yUr\RuI`SRf\h%'
;YzM8-^d]v+^>՜Lt%''+<&S'
ч%yTsLsهmDPVGeux#Mtg60[.YÛ&Ǚa Cd GuU͸\2Fis=</C? '2JolPϯx`6pZm=DB*tx/ar1)x	\;c&q3m{|1pWSf#fۖnbf2&(.:;$"ӷS~L["E=C^3j&[sZ!vAP2 q̶x&XR0<buVdkzť|Q)cM4SMhxhBˀ'^ȡD'c```B91]\}e2ɶ![Bƨ(D|SmnQ xΚ6hF4#MEd&mO4ߍu>Қ=&,2VJь#ܓl+,../d׻ l&#LB~n9;YaEKZ.`go'NeGJfC*y:pOU*|z߈?fS87k|%_~S\ШAQq_^B6/4X
Fh9p~IKC=Q!ËZ*]g-'Sb5C>J*[VOW@`<bklalZ}M"ˊb&?V~C p)$Q+i5w7g6/|b&yЪyLMW5Vf\'gDJeFP6=kd囚P+h v4$)dԔF[1|C~ToC|FG$\Vo,c_P CQKJ
'	ʶ5_Fpn7̡kY`׎l?G`Ch;e'_:.fL<LM̀P]F}$TF+ z[i&T
CD$.k!]R45g.kjaX.B rA*'PTuZQ>7{ps(^D	PX6nitJvRԩdQب bçX9tAh	4ĩ񆘪%\=PĠ_ț645(>"4QD|y:-`lyC_1t4U`8kM:_IMT!slU;Q}픞SlHgy_٭QnS6MPtV6"ds]H_!̣?_/7!hJL	Q r-`*.Aqo~F&/D¥yu_>qV[Qǽ-.Qg$;d@X`)b]XMeK8˂B\:z]r09}7_}mql*g	gFW,B6"]HI8ق`yQj0.}]{vPj|\WbJW̩}m2;QMUӑg$-;Q2(%j<(|`Q[3Ȃ,ܵs"x<EFȌ:k7>ůC?Te)H
c"6(<`M-|ӏ~_r_͐Isz;E0kPꚇJjI56B!CJxJ4a'*6[O	:G~^L*&R2Td2~O9MEQ3	*B)/g`) ' vqp!x.k^;]b#eɺQ* \&yJ@</jQ|lxA9ɯ{ZC_YAuԇXΚųOnҿ!F9!Y5
gXՎApŠ	%meJ	)+dMʷɈpOmGT֍Z|9Rhd\~)(.tT349=(z" a9&Qx+r`|Xz(`5&Jl
dc&@3*/lebMkUZWiۓpO4b72iqDQ .0y<
mR%z&W<DgI)DAk)-sEl;!ÎrF"FrFPKxYIv!xӎ!sZO
2¨	\M:[;:1kؒ`N7**8AFJ04B`a@xQ'vAAdݘQtdc~UjhCkp94xNLyO֚߬ZJTrog${2^؟!؍!C6Zٶ!1TYֿuU
{kęrkz"QeL 󱘍^W({`㌯zh(2v+fzLy:WE09" ɾeMn$;1#T 	Gy k2sg{!d}-b"燢FUlV6d21`N!9>% I{/I)6Q| Dqf.d^'%VZ,oUоb:&s
	%G)!6}b<#^+P!Fhä[y#^w}'CY$_M90l0cPͱDd~QwT>mmZ3qΊlz.4gAR܅~T*BEm<w[\ʕcU	k[0mfCs3?~E!&<*K,$h"i_+=4}ZԠ+Q9ZQh7(E[\;ZEdw(R|M/]֮doae M<8ia-Hb>ao\$29,:\HNea@1JQiq.8/f%
e[h5󐍿VlZ8/m.Yt!YCKr>Xfw Ed[r𚪪HR=ϿXQN)R-йª45S9I  g_|	n<7^@fw)I傣٬O񗢞HoPf*}cR
+&y%xz=g09eb-T!@-N3ЋFn&U5EJؑnⱴ^/.6(R<` 3Z+&ļ(X0Qxs'	~G 0)fΰʗ-E[o+{4Mq1v='8E.C421}K-=m&t;AIꧡJ=}|۵rԦ5+,}o1C(Lw /b<dQ!J0aD>C"I VxA! t).ێ&})(LR0g)\ql`˃Zr76dK$,u~󑌺F'sI3F ] M)0JZf#z6CuS̫OzOVJ0U_up=KoģBG32B£"YԆ\w9U+1  Z[}Vg
gȏ}6bg|=F-tGA+TPzK甃dYАcn,߿,,c79G+ܯp0*-!6E>\9RTgj!W"ODYpi<ͅrQ>ܫZ.½Xvy"4&F/FFl0]V˸V^qM]Ӻl@TJ\lࢹ
!I܌o׋m?NP&!_8hb2qX_D!ԈQY?&4;XVs`"hO㱱5RfprT`lYL$bq+6d%|(DܡoL{畂Ykm2OUٌZ}F411Pw0qed̸e{Q1i>VQM-?2NmvH1dƸ6Ma>Dm\n0CAiYNlf"iٚpvKx@HF],i$p) l]ps$ cȢJg`hOhڷ2Kfkj\#]ƱvԤBDf̘ھ(9IyR0Nma6K!(Yn.Qp//i(2(=a8S<?n<d??z+ccF1~qzfǬK]`C "gX3LmʲL~P&	QJC60 t\U1&/Ψhwmrr$"I7QDܞǾiė^Jٗ^y8M-M1M4QuޟBu҇IMJ֬}%2пkh
p#eyI}֊`؊BkHz!7GasEf=^c|ǩrQ(aQ\T%qETJP.2 !/Kz<Hdbow)Zpd>
0<4ʧ XDkbn8/{R˧b}MF0h2̍k`ذ>lm0:>	2f^SI_}XOfd&"}eU*}T }EK\͙oZhKW@@_=_(jαoyHGq*v_6gBhA9Ւ=gE@l
!yzNk"DL>*rl\'&ڦ&y`-tjȲ9 ))o8k83@6jt;R)/F}8Eٟ4ZX P:<I$4[;97"Bh1:I yUbve//:{L}Vkcd(rwo#ol-Yfi:dA,3 )l5)K{GJ@K+p\:aQ4L) Me'Y)z+%G܀vv;ZΪ+?|_)o"XDu'ODo7FbBAڷYCZVgwVGxK{`qF+g =?yhd]aÆ_ggz]JDk"wfqp֫C[	nn)goDm!WpQ! k5ioc1y>4Ţ3SLv/@`nϧw-kutY+7<m%oMd1Uh" hy<S(x0ze$~Q}qT;IyS	Xq2_u$+kzZ7/Nɥ12@EpDש$biGA0kN6<r%ɜȯj(P"	!wBFFhFܼ>ex~	|?яtt`)+|??Շ:qdN]bwTø4o$FE*NwczrpWYSnU5n9aB)vrJPo)6$̗] èxQgfaW:Z$m=l5#Ev+~5N'{>>~uka͚IýMOW,y5޹n(
y4͖
;[
i!/'MUK^L^5Ez5U]'OJye˥l*\qcι78/.59p#hɖ Ӂڪ֎z虻-'VPQ<2C`nF.ޤГ%4&U6ULNp #w|:{Ympa5U6C = ^F"sn#0s"򎠜ܚB4M6
ONli(mCgc]̪wP|XI/&K[j8Xc㘖s8Y	'Y?;2 0c
"q+7ȇ@ׄd̺S#=C˲NO޾Vpΐ_ѫ)9?^2Ͻq&ر-NKosۄ?uJCG=AE1Y
@P	jijvw}͘Ź||Ьzmw#'K߀285phiHq|AD̉9 Tn=黃<mBe~2xכ>}W\ο(˲єeMK:vBAo	k	OQ))vX3/pcܤz}(]8}6]u ׊4Yt	>^19#+g(qi(<u9YHZ&y2z0m&dAN!xqs87ij6w%~F!W!/0W'L׊zĔRf!9|Pl0rf4+%qmb|69t|]Ō:>b@h4v1V4"WS&fEYgEo:9i'a(FѬnZ;F,/YT{{DfhnPe{)rl)y.{Z焕38{Rȳ%k,!=/oWӃbyh;`B lJ `u|dOA4yP:V'Lw,,>%Ao1vkM;
a	\xJΜN];&:?-o[qI+4)?:y\8VL1T@ )jwjqL6squu}2?ʨ= xODҼD˲ȉ$F]w=ߝ: %;+b?ZZ(AN 8!\>pV7#K\>טWT𨡫SMIB%uHxeRi?PN(Nw2wȮ>`蝚.keZȰU z)j*fHLQ)IRF}}}|xy.+Ee]mϸ0}0wEN@-6wc 	L lFhA/E4ܬ[KQ#6܈;Gqb'-reۺW]W yE螪`jߝf),|+
l3s6p(o|T!EAo/DRٖX#uUsʖ255M89dٯly1,Q_ZdA}7D?cBP͊>Jt3Y)]}ZyS3SpDOM^z->qʐwSsK2FvgMM\&oH)N&HS?J:%Mzf@~MT #ȹ9,}g#.JOr3,/)⿂~/;
8j%Lc<?gݪU(F!̆W y@ѬcShd2
<lwp֧(A(bsnЇ>%Wmsr} s	Ť\	ʃj/i"F>J륁K/#F<;"9:y7MSsz>X;n(<̘6
*xYk!չ0WdK$<Wok>{hɎFb"~V3D]D+Ct];pSb6ec>/PxFPF<܋hUE&}
[]/cf"d>Ez$ו}eAD-1-w =gTEM܋.nVw[\ގvAǲ K[$bxmS}} چlFPt♟묀,j8!e=esqRQclpR)ֳ9vs/H`427Aϗ|lgU[یyeZd%co4i{9lcf-1,sHwN1w@ N>$uf=3DaaV:e4~䙍hn+Y:/P] he=\hWH`2lAR$<[Kn` HOCJh˟F}=&hsR04)|d9PH2D5RFJXF?&JCOIwݳZ3 1(,pY<KPqv9 V|0\X0"O^)ˤ2<9gV:V/+q@lTQP:@ʔ_WŰ%վ);"g{uQC 61b!J }QDʃ4S鴖F5tgwc3kk_yѓ 8a^x!M|ZH<}u.zsjol
ar2rcHTVyh~ƿ܊ Ds$mrgL+k,c0 d5u%n^eҝ__'HO*W?538H4Es4^ТLGe8SP^dL붫ږ#B#'z!i?``Q	@żF8?j9eڷ^t2k]c,Ҍe-Aq!`kq6(-A-zP%QM/ G`t^X*0'0sbyvwצiZTa,.B'Y|2gs*,L@×YVRc	sVf=mҖh6_01PAܫͫ׻5CmXe>3{N1.Ǳ*O,CC۷o?ikkK%Z':RL2mP=X P9`UJ. * ɋB c$aBHA$\0gS{$_+-ߺ/o9z⹤}7ƚ, >_	Ɣ;Q߃L"2R3D ˷5DS	W k飐-vU1߬ұ}V=wb<vaAy'# ߏ&f5I8j7#8DGYrS@Io Hq
0M	O>oLX֮LJ;j'9ECZ|eH_hƌ\"Q@UWWOPM͔nl /s9(6mpl:n8	:Xݲ@	Fj܊,"`;mBQ`yV*6A&6:嫣0XdMnuc<y/]I4<g f XagExK-OV1yJr5II&AVNgܻ=BzQONfOʟ)*ɀwd d2*^X!;
o7baxIx|·QìNmVf	rPD*7ԿS,U̧$ôv@Zg [y;r3ӽi[Z>_&j1n|s-Ys)#W<=}Dkbb?*Wuy!n[f7&k "єWAU^ض~t<8,(VI^;jb+;U{˖BxÆjv64@v#UE\	8((־7"yJz:ܜ<r8zP5_wh숻K!ݗC!mײ@YyMwL4BZ$-ybQW(Bح\:jA(\'a90ȦɉOGRA-ؓN5;{Kh}/!'C{'\lU,Qc:h?!fl2G.*ÄꊧY G-aP fSDP9!, ,YRch1?5]:P͢sx+E t;){W̂O Hme̙JxI@*	3^jI9Ylko=_r80</@cF3;޼ŬЎ'NM"X6`"DJr䘵FP]ꤧp%8c_&'KFAa0UZ
q !%3LoN=+ud+UT(̘D\Hrd*BkjY	UAdxX8Ŀ	s\0+RI:}[zoEs;V&^'4Jbjq9G@~Ȏ👦RƨTrmx7Oefgi>q.;w?c+K$\%9H
xpk 0IK7 R$yaΗ-2m( zbW đF/idrm>EmdA6	(6u(Hޕ9M4[ctn__%0%vl&H`(*,O[6Je&6$%ba+JqC
id7Pj|Mx@:7b6̖(\5rb(ʎsnr)F.3_?eڣ_vE\:DX`xܝZHgzBDmhjVƋ  @ IDAT?=D皐r30 	@;Dc4FNf,?䠧O!V3P;^7B>M϶".G9*X VZS8xKi^w۱kB]ҭ|!Kg!;<"@ց]/RRI{EGs1Qj|à9C&s;5X}Љ
to{C]Y@~rAi;*⯐,rчkIvM_y+U4Pj`6kEz;A1s~7RՖ^ev9GsqMGL,^|i0V׬4Y'|UV_lAT7!.立5Ivoq}pG|O)̈́O+|	~g%iֈp7YmtHn1\(Oe[-0	ZA\dۡSHʘ)#wz~kV'!(<ud2_8,ثv/vҏm< )2nhsm#0s YܯN]N=~6})zI1f(gb+k4ެYb@;!B7C)bOzHM
@Ρdk>8>n<~Jk%!Nb;*.xvgl>GY_J%~+TI4+=)9Y`@I腔~mv{6h6}s@0LU5J|ٜdN)cd % a"peA>'W9nx4,Qa y7(ՙ66"e
1 -!LimW^Os-pM -V"s4%^ IgŮ;ůXX(QhP[AɝG6z<:x鑌Ubt~P&ɒk3Ȃr`;AB}F̘7]-H_
Ն&GU"ktA>Gq3fw@B5aڈ^y;alʙQ?,yLtJW76Hη,yYi^oΩyp)!kqgezѨbْ{,c8HLB	%!&KMXۛR4@,d[nf4!\I3=8(S
E͵qԔ"C;Rd|X"0|DI^S*ry6itēNd!:捇L_pD8#q~ފ}u>ܢ]y;/Uj#ο BMN?_Q"wfX-vl5f;qS.1(\Bx@2'+`h%qLi'|vo/,)ukMxF}\ǟN<^
П®?oƷGFR*<܎bބAUt@Ә?$'PP)m3X-C4^c`A4C|뎡&xb>8J?GEQ~oXb-94L~p)aw=JJ=`F<b*gUhM|U"{mYA<ھp6N	|*~DKg}"	Cik,@|*ac$nHǂ#Щ| 'Z?Q;1mR(Lcism) Sk80 ld0/0T7n8^
%@jء|7mrZ)`*Ulv7WCmy@i&uH@5	elsGE8_-Erq)5K\h٘x?Bo$OK:T1pAIYG/5H>D'rl<>OCYbmHqfjZmc/Jy.~5냃}]Fs-_?7V`@s>"W|;OltQA}c vG$!6&m
P@2N<$U>T9N璺:ӐNnhOcAvI;ǟNHӗ4{;.vB
,O|}ޟbrޒU;=,((IşB._vľ
GM%^\6li5H;y{S;DK^=[	kGaS#]%:=6$3XAGY2s['::DYsSu=o3	@=\=N~ș*&~,c+xj$ky1ENOok.`iXqelcVRw߰ &!w/ţ	?EE7GsF-`c)~0i0E5luČJ_lj"̃]z<|QI;\.l6"=9D0(j*_kgHR5Sѝwb{f[_4J2\?ǟ dx$wM㷨j"dY:xor%
Zv0*Juozr#=FX^Q4އozݯ:.ONF+
}Ȅx0}8"ek&p++@ϩ!@=9fG]?MfG,u#m]wWSv=EKjCL9Fs^%n)<>AVs5/YS(NĻbsu4<͙ ~B;okzq|<98pi-I{)7fyWVTR$A3p%QtrLQD)\NH-X68RMY}iOwM.UL{zhN_eEE]-nohV4feuu`$ 3U{Rjwzy7qq8뭧qfVA'! ܤr+{nB}qHQF2Wbuڎb?\X I7|j٫)޺T*8<:H{Dw[&`AIiuz%1򮷢wvI.WľCX\!pm3[kd Ѐ	>l^E=dњL"F g b4ԭ8v'`_Tʠx߬^F֚qH4<
',e*T%t8_Nr[b\nnXG?cJ1Fpc':w%QKGDE((2zdY
Z;vc@PaR:W͔G0!ƋvC:ݜWBB`N^yܓt=٦2| 6_Ho>y98" _h`@/!n/XxoIܯxBG?E_( ^iu`pF6u,=;tDy*)Rڋ /,kjqxw]-)55eMf7~ח"kyκݵC>]җIn[TPB52x3tvy;M~cQڟlR([r B1rC;yKBy.9sB$4@[dx1RMd&J:w
-=9x`I?flOxɛͿK:宍#ѱao".֘N`DM-D\8'UӈkّÙLr	m`qdu5kŊ&-QMP<t=`SG%H:>Rg`}1pf|=WE4w_ݑ4]#0agOv`/mB9CbU4b=(t%~Eп[˖>êV+.[ZA,CG{-AK8vm8`O^?$N}B$wK (YL*$%O%TZ[[.zâ54+' І|dMqi	`ỪluFvJk,o yFzOmVk>wMd^D{3rs^RKj
0m]CQgfڼt+U6",!bWW[YoRt};[]${5=!`O$(ߝgTgF`M@.<L2sa/Je.q:,8/zv;ӿ'H
!^߰XA\-Q{aLr?Ƽx/%H{,Ȟ*ŌCa=o05E\xR}ά^!̯K'\zQUs3
FD}>k UUC@5vpyIUJBa]ug9] ѕoz[L ~ɨ͟8ߴ@ 2$}D?%$B`<g Mt%J\	 |pO8ҢY7h-ǌW_9Q@
Ȝ}~D`}㺤?F~@rIu9y" {"7C@9tiKpМ1Xkoi8zRt氮'63YppMdҊr{ִlX91J.xMll\\ fj;A5B?4^(Y z+w;@,;[&&>g7릁qn?v7x+CC6 ߅2NnM	HUQ/$Kk  H%/݇YH%?똮*7^~QtLSS(}
a|5f/*#+/d:Uȑx*=}~[
b33S"dJ2-ֺ\4Bo,*
<},D@bc)9|8eS*q.g&<i>1D7"$b?eW"mчd<mڷi;L"	lYATcXԶ/=Uhf"R;{l(חw6sQ@\{]Sd*%I)OlZ._OeY0!u|$7?bR^y9cF.$wOxJHeUV=B+|Ñ+](2=2^|a><M
0|)^;o4)[`$)*COcc="w>w!c}6n?m=^̙bu޶^P!hń<O|:UbW<{
~/ye(NP'<*&Sa-sP/$1#C Zzx.֧qIp
Xbډ%r,ભV7<3 [R#.F6UT@o[-3ģp44RTjKU~3{!c	k:+I:y[ug0nh֕@eHw;vc\{ 6Yerq]2M bccBe*Y![*Ln/]%^<f7ekymmk/+"	9E^ 	fC,¡d7czE_p&#u 9pQK<F~0+H '&{sL,HPSM+KnKhZ@h\J|]tWj\E9bD'/# <(کf~%.`Y(⭌]kIY~8%Fbr|5nV.U7R|
 y+)t`Y8}!]KBBAiѨM8XteF0MO
NwǸ)sEtz5*ŐIgS[.s˄~~	 0UVaag@
|oTRi/R.h@G`Z}rQ[eGLO
'-Cv랅b%Y3FQ}h<T唭X#qC-OBTts:9&1E+y!ҊAŰ\+<gk'sPǯN&  Rz6 $Eg@r3:a.GXՙ0$탡?}6X JFmRj3pm9܅	y@Y.<jk[M允j:HhTPJR1[Q6e՞םrnOOvq[i3nqrt
|~ß竿,?%vRVvZԆ)cFUPpyXjHIO,	c߹F&"O|+"\hDZJw'v/J*JXK$/ȫ(FU
>
Թܞ?ߝyƠj)oըf7Fwf*AKF ,(	hGȞWQɇ>mRtqjhFtD*:dsD\Ge1?vp]A#@@:ޞ7t6D\~fvOfLf[K#3Q*KAbֹ^Qny(%WvSVq(^ ]SG/FA>nD||Ksˑ+9'?r&{+˲tŬkk2v"pN .F$緹+To$9	苲7)N{(5dj9B+/,rU?hQa K-yMY#fʪ "QeY<$l!ù-TDl:c),J_CwޢB?D{_Aֶg1g@S` ͔Ays:"xFRn[M79qJO7R!k3#ޤO.2@htJ&btYg4{84݋Isӆ
&'sbxtvP<"`VND&SۇVbRjrfM	|'Sm} 'B\}#J1SDɷLT&wg[zs~);E#Rr\fbHdrٻwnfu085j$1!<RCEHW CFF'Hy*Q(Kٌ[M
hwVEeP3(Ȓ\.IN:+,(m"wxp(PBۋakX w	A洎Lo^9g|U
!`#L:,*&(h3ZxwT/&sQ/DE.p3!Aa2szfKt9㐥 &@K2v
$۽{w'ϼp,HL()(O<uIwQZzrk`BJaUyW	ˮB_s,[V6Mz2&Óc3#S A6AwJ[T%ލ.̂W/+KD#,ܘ466Zh|(iWh-Ql9喏	p71HUl
SqoC!eA1,</:Cg@jL*qe*%*^UxPjuqJ|̣s"k.)NBnZYEdxz?^L(]L#r
U%h5dU^o'²n=p;kwۈ8P.b
tn焨<4&zwb,hsV>Whxh
M(YEJp-94gMu!5Kn=<ǩY^` U.0d|p?.w:Tehԝ}{~iiы_\$I6\kPy$ҐZ"
zʛvcr ^)W{rlv>>::إ~_rd^վ|֏t؄|ow6R.M3V2	M<+
2&$LyUc/M]C9EF:qPF7D'	#e
50 BQ46]B#P*صtH8X[HHEƟF}oOlrą͉e-&0ocXhCɚ5$	fc}~9ur`-nޯ:ӷP&xNaG~LThr'TrMGVq ̷PWpWB"y|WBuZ%rBc
8X~3τ"m6* 1e0stZZXBSTc^^ˀq@EVhCt:j"L ޱzhճnzJ5ߞQU7?,
"gFAoӍhly?_b}ݨB*~̆R;#u֡]:W(CMc譢"ǀLHHsրݬ|Ǧ7D&Q@PaM3-Mpoҵl &Om,Y~~tS_Rߒ5#TIxRvj[PDg[U3NZ7
+zPT:bs2E↮	YE]|t]m50[\l F/6q#jVi% %~0Ȯnn:"G΁dJY7¡k/+[1߾bOLf$í~9s9o6튪ߡ7,Z7<IDlȇ۫he0mა@0T`F =;+PN]ͱ?\>{?6LpA |@	y<ݰadf"כ;t,&AC'gy{ftFM(۝B	:PFP]HFUq:sцѬfF1;B9Eȝ$W[Ifp)Y`A	nfbEFJc6;'Í_};
m٤H+
*b7Ɵ 8Y[Cic7݆l ٳ0W=Be@̵!5[4ra~%?ўTQդ4O/Rz7up64BQѢH^Hwt%бGNԪ^Ɗ>h:pr<#NQ3ڋ'5zs^#μ4h1͏k#zn0)r$m\ޅB_YuZrSy}~a-؍U凨|#

J-	n_y0ĳ౮	t0l%dS
SP"lI<e<nBfL~y]t&"7gR[OKtk[O #<v}uvfAbwgHALbH-2Zm|okS_L7he}4z1̀imTʏGpEyHx5@#}ܫ.,DdpETbnS0JO6#SE;UD2Fͦ}ﬢܧNVAUEK\f:Z]iq?o]v_qt mH6?jFSPU\*ajy	<~O<_evnWFQJ~jLiAI\>A7k4T  atG!Uw6#`78ñt`vhg,FS"4(AD$L&mw"Z`w	OlqB#1@(}3v*U*rR&YB_lcR˫^ʿOL9s<{oog8Ro,FM]\M&xO]mioY	eA^,涾"#j܁L&cF>;f	.YAMQ.kjm>|94O(P~cٛƵI_gAܮk"F?
e+w0c{ L.÷ y٥@I2J4}J/"pPdǑNW̓:utq څ,|kohZ&Q`<_y5eha>u!s]Ϟ=NZKݢK1fq|݀W3hnAgʌþS']l][2pɊ/#G_I3y5y~Ԃgۓu6nSʔie*\dǟ>P 5]6"ݤpNCvLù=zd~%R[B[ph6pt~Oνf=çcGT^'oGS$rLoLq o;7]jirKLC5tRw4.XF:^gxwW	Zp}rk18+"סJB+n<&1ts:>kl`1[RJx?%}WFՎxL!/(0:ݞb3Yƈst#	(B4|SPiYjHQv0=ڣ6E`GA.baQie&Nd<T敼^eo@8K*2OО_dJ#@mT#6M`FsH;Dɰ'	%9_⁶$@R1ى|,)wFY{pvg#$.(^F*8*%!O~^l,AMt˧5u/cG]x}l\ʣ;r%rK Ei]4}KYʸAU(X%
'U4.:DuS'ΉyTPE/|=i.i=|rC[PMů	x.Fbt͔y[H*U@Id.f~F/sx{+qJ'kW$||ڛѤԵY	2S?N,K)VIa{%.owzoA IAː.,س}];@er<8=%4#I{
%_}<6pjAy91c
.c0[G^_/R`1iW/SOEAǺ0]e˚LEɄļB	ac|m${(qN;t[h`6C79/|J&M+7K{]{]@OM7?<|HC(Z;!|֍֗Cm01b~l$J/H(ȉ^HJۚ1gc
6`bi@l)x3,[M=H!^&c;JKI欍Ng`\,Бdj-^\rd@.pkxs5NNbq[M5~+-l?̓c]*,X{ݖʏ~:	68x:c|u#%#exnw1wS}3קfT"cF:cii]Kj
ɯaA7ÃۛB_(t7D.By"%P~	l;גSjJ%lEd2-O溦σϣ$YQ Zh&g {v /pve	*/aB(ޮ[T9kj(NZ7BNBS88?qJ$Zk~mBxy/̨ `*sH~:ֻՌXRnKT2.+,_TPɄ%mˀNऽ.>	%JRZQ1_H[T&n3f }Ȉ36kiBcuCO+lJ"a7o9.p	/񮅧Of_Ioj)vixM8dIC錁t[c@1s}]\svZZWK]8t(I< #a3Ń˄Fi+]j6En7rXKJ>*[2WGܯҳqZ`~M/O5b0pΣSkglzo{'ZZV)B5 `3   }O/_ts!0İ 5v<@gjk N(oJ2IՅT&-M\SjBٚ7cAP363<丒Lx.+9muן<@QpZynH+7HηQ`٣u%Bj8hզfA Mum}KkKzG`yݏY<DҜDS9[a|HD0uA~3CL02psbe/tY`tHOi5<+LـhdL&WvKݣo<Du伊
J+@H+Mg{#q-&S@r$PpZ6Q7d,\PƹDWRn&]
FGp>WwZ	tj[NwsEV-WZx-cz=极Ǡ`㚂0E*Gl] E=iEn_7ƹ!x	s(៸c3xҳ[/ܨ!tڋM(S5VW+q1709|<o$TMS
>Bm5 ?1XaLTv)zw`3v{0BЕXϞ	9n[ܰH$rʦU:ȢwvZ)Gtѿlqt f3>8"P@GdFtU21+z2R[~*8wũ#k˗!˩2oqX9do'}pze9dgf6,N(=H)1mY:A ?O75Ht	q?ͩlZrя~h^ϗTK̓fF4DQ~PraxyE XoH%2v_vfGΕ;(ZQw0>N-bLRMe+W=pēz
 -լd鮟hEB#F}<cxoH2?PߓCn*Lorm~Y/=7*Y܌t-Ǒ,A.BH*,@*fk(8y5yGY2~ڇ|F3. FѲRŐMwy	e_C*)ƚ`stiEϬ٣rg"1gmo]A0sIш^XwJO:&T7 w
!~.ܙ<12b|Nibtq+?dWg@f X؉ nGб˧,{mHr=6\RPH$JX*f8,8я^##	Rx3;9`WvW TvZPdC|iy$/Rq${Q=_޳P}jo]E=5l.,Şs'`qRtnuĴՓfuFwVPȦ0S-oz*G|	YV-V9F(m%U:4Bf aF&JYQ\ӐzS`9K'xf#MWgZ~%Ԁ>>G"Jb*sF
&	2x /
9R0kP.#|ѡ>ՀgY7Noogt#Jp3鯍8h:)<1u?'ФeMA{ IWW%H(lU;?hs$;x4,mɥY
ykz3=]5ҙR&~T߿?zKkӷc_vr~OY=V5$QCHוw6v#x]ҏVһfcg_HO3kс"c/ -xowđ UFq,<how><|4@M3ݐ/QքN&ƣp<^RK\ogߵDnP 	4ԓnC-֩S]H?W:c`mH~o2M`1IFyhԳ܋}yMp$ۚ,&lz<'s^lu=mFT%]J]u	r52]at7[1KdP0,gȖiO%RV IH8%Hϥ X1'ᱢ(Ttlex! ̯2QѲe˶#W{`{wxY(Hi뙄UərY.fy#+VhOBer{%QBYeʫ/pQӵzDӲ
a '?e`8Cgg0HSͻOcЈqF&4;J\-(9""Am&#;Ŗ}w͙3|8ی6qraIץ8+>@QKFuh 
քN)4,aN-('O2|h9׿7)?x~/B.,SM
efݣJˣv-';	#?\ŝmtI^B(h[<բomZ\e:H.n\@5(mX(ɨ@R&\5L{5w2Sғmy
jlvm@3i>r  6Sp鱓fw5P+3r=Z.F#1kȦ!Dw/ՎTKJU#'RA~?2WV?UNf?0{g@x/5HS]}xOT<0lE"J*50
@5F[RlRw Zr/Ϛe\i0OfwDb&t3sK3ֆ@$Cݖ6ZٛڎBVˆ;i*x1	!C4܁n	(X,u
E2-g/V_v#ɸhgAGLW&x⻗;"jq5O3ayCC]0ԅx
"y#n0[70W㯬m~	+yސV0@>bzȳnv˹p o{J3,e.KX+k}	=!ph|am$dHQ)g 
yͷ+s~4ᅕovFyF1 FD3߆9C1"QӐ.>&Z\t(jh06e  @ IDATȆ!%2IC^~ݺTKXZ }{Utwr}ڸ mģqޗ:JXp@ug6o=Mk]crÂ1
2
-Pnv<XU!֝.r?*=}GA}ŷF2g{R6ӆ(qkk45~*1mӲy
A8~0PiUE4ϛp :_1zc!b<;5ى\k\!N0,2W[!CvN4A4'3yMK촳LM6.&-;t&f[$uH&N|"ޤLE!XhSqjLw;@I
;$1%Bh4PS#[ebonΰHl㹬ܗxOD[
vq8hTݘce+рQX(9{qV5FJ3.˫BN6L6!&І[owp4*)sSAgRӁı0 m%& £0n'Bj23^.{ik^xv~ySS]-h[mU!;2d\T쯵7%v sz'}67|4?dpDHɼfOˣrƍ^CQTK&[^IeYluf{}KdҺ"FPlMpt%O.W`	̌*.*_^mweF´Hy08EN,iyI፡!D,~8VZv^ЃƇy7k00_IͦSH$1UΥ(F4PYQjxzR4|Vc:< JxPzs]PYkL81ї ץcEBx- _X-|r@VSK{DFMn4PEf,g#+)ErmUM$n)>VyT\34E/>9wL~Ea';X䡹,iZB.ބd7{Љ9 Or6>䙸-jBY >zxS}pcmSq/→K$@X\W@937[ڽ{sHk gp_vlt"c;zMj*=f:7LHpjf|5wB/\ Ul#sHvA&睝YHpX1Fݤڊ?Ǒh"R+0:ǆ-Sv=zNtZ[F<_O걨P{ڣ'lAY`\N4\xzVLP%xkR6#adioH`]boć{8Xt\cܚqE|;8ܢl8$A=|ލ_o?D4ƂSپ!gRD)3vws*G3@ =8I^#i%9Enld@V`'߄w{LjGvInS!x[V[nїB,t0+m=b'e9Pǵ|I|5eeUa^BOS:;׍ 
5Uǚ%豻
ơ3E|QXOhd/ߴt$dj=Z,k'EE){yp>q.
& VTMX/5kV%0]]Q's/(2ƲB
lETveѬ;{U) inyeB"x[_uQ}}
U'@C"7|;D'_;"ӂ+ٓ>0)A1oɢyY۵PvǦu-1"1vtZfUa,JFe(G9@Q;0khrA~"4#b!>	7~
ԏ{wȒ	Tn;2hqKgkUvҬ+-'A>mScBQR$i-#JT:Yhq@$攅XwץY5 Z_Y_1`INQJ1;wC%y^zŗCL-)Ҙl^ɔ3Ҍ!ws΁X]Zu Z!ZQgA0q/(dןydЛ&|-pn߸z9/ ɍ	AF2)J	`h5Ɔ{-ߎԯ*r:O͙TOʌ0A5.boF!3(VXqBk8|:{# <e?g py*!'W3~{hF|G ſǛT0XI8==#kYո9f<)Y 5$okJ7|u{|YԈ8Ob*u,>6J/22k-cC3dRgƟ侐sJ½C}J^/_6e8N1eRjAh~"~Cz!/߅!@w3_(GS;J78#	1~(󭟕͖gDwIs:BP<Y0Qxa^iM3[#CVp[6nh^Y+Mzqr<|8OIacȌ s]ZqM(\i<G8yC&vD6=+=z9fw 
aGC,SWC׿=W8hOaεŭo	u~ϋ{ʕ#`V
PvČ*v9A2FC3mpPħ$QVyAW'Rz$V[tiUMfRt{mLj=⟇2WFt֮.ϳVaTi)TZ(:gq-Bhn*
UP1v3R Gb,5WO(S-C?&$L;[F%4/-bZK!٬jv]ύnK&?/{\ăS@{W	ȃY#c&kާ>t,PWFTR)"Sqazm`4خ*fҳ0.'L5㢝:S1xHbޫڅ'~f|KvR59]qdϻђepY1s4d9c WfWY'i(c)-{6?<gU!]$հX!w@/gEQC77pxʸV[P!i)VW&e1V1@c#CAL׳N=.d;-._eFNo*b;.Z/"z6ֵB8";n"5E^˚#GoPPaқl:,~yZ?F?ɬyEs纖G" P>FaSc:~b|S'zNgjvP0'XZ]kEL,vtV]'|КVAU6d䴈)ÜsRӦ&tX q	u|6Ncv&)x#oʺ삉=b5K'CeyeEdRf@ĘkfCvpȪÃ濃ipWo -]E0YQ,&yks)gbOuc_d7h+C/A&,6i;灠|wU !+~.v駚f8{Bw.x/c#/4Gj䄦&Riz0ӭ,rCrc=Q+Eųv-]{XCGlɦʜѶ,']6ف6|zUgu
)`-)EՉ0^/޹!g j'P 6H]+;R&,0ֆ"Aچ>Ɲ3R;lOZC`ya!j@>]o7l]_;<#q߄)E$S:)% ;N8`3eF!Ahh|8 dnHmxY0yꋑk	=`]aؚaA?/Ɨo2]3@Y%[|cXBɛSjlS<@P(q|&}r>7y'tZ'N8i"5\AE]n=iRz1UB[Ɉ1Ëci)Z9cv`ósfs}_yᡭĪ*mȑ$kkSc;f)[? LvF[<+55C&w&NAA8(y@y6vt/WC= ImY7kfpx*u8YIrS\E	/E0sw|S(P^BX-xKEŞ8U7-vmpՐ ,
K*Ȁ8KP>^rT{ ~v;ǟ_ߑply5°aMȎ
tb,C+Р%LQ)݆<?agM㨮ڗ[־Y-[7l&&BH&Y7$a/$qBBB	$a36eEؖm־{wU{[KbL=[ꮮUu+4c0&M%#Tt&КyrMTǖϤ^!:r%xp}84 i` "x	묜z~p6%u>@;Cp{[7Pg("~m]ot+c{PJ,l	T D?>SfH%}4~(!};{[֍yokK<9.m~[``/򳾖S1K2HoE?D%o YSXɶf͚+/oX?yo [iK(s7y Fo'?Q̗+Qjvŋ%ƍK/A`hYj@;FTM?Iũ.	m$~@oF}~'	EE#v z)I,{w3("R6eX?e*%sYձ{&# ȅUl{^,ƛoPHU^5CJyXMyl!F`6HqT)$tH%?*(]Nri`#2,}Eo6'댏/
Ռm8pˉEhWL%6_"gT x~}~$`bw	d0XEѵJJN:rU~!qh.X 02NڋTwV^s?AdŃ]tte3Xdn,
vWͮ-O@T'#]xz5d8snTS]n|/<eؙRS.{iDsV:[pF
@C\59WGj*F}cٟ]j(pwMPq<MZl"c¢6>@ELvFpUTpN׃P/-V?ҥsHxT1412.lO 9`V<P;Ƀ9B\/PO#7*<>'dxo~0FpL$w)	tM1E["]H|@4/&}1 $&C`pnhqm_x $M,n^ҭ~vV_(4PE;[??lCacqͨs:i[vH^	Fain?M*=s
1\~~]X$((]K8x4Xk/b{Gb.[sX J5iO73B
$*Cc?gd'?H3+z5&({ws~Ќ>_d{p!kKDh3ʫ$ elZ@YN#g
R.=a[mDi۴ ە%%9zO
cfyζ};0_ guf؛9:{k&(%tٲ9#D½o;9%SoFʁ6Itw99Pcp	9<~̛znS0gԹ(J]*Κ;~Y{F3&'~˰:@xCժ}c iFqB{edZl5X@ĉŠ^QU!W~a⣧0♹CTe6k?8>jnɷ+VW@!ʮq^Bx22	TwDgR2s\čk/M\'ax+I_0V=0v'#̣t	UIBrޥ!?gFcmvn
TIE~%BKs5?U(xT핸ŝPY@]Oܞ'!LD̵yFz:<rQF0Aߪ03XsyJ 9-H#`W2y5n7-'/baGorόb_:AbzrCp֌}K%Ҿ],E%"#`;/s8i|:aj*j
*Tm*m?H rrk) .M$o²?%Oo{-0>Ip_맞c'H]هZ^Y\=@r޽||Eu.DBuȕ̾V^F*h+6Bu;BkOm{pN/i$nzs#Zc@LO!塡ˢ*yeqn؝axFlX&{<L?	tPoW]e4"AnSG4*sH\
g,2
 qz-:|><No#ճ>k5Ɯ;{U2ȉ!Opꖇ"岜{\@
x!$Pcvc]k
&0Rhf3m&pe_Yk؅>icr^#Z.8rG5fB긋\1ܯs <NbkƄU'3hJ:ˀf-}`~?5^K~ȡdP l'h:2fĿQ}iu52Y3y3J5H2n9I YC$q֭dԌ
+VJv$ƢurӊƊrƻ	af윘,N;}L=phOblW_
mNr/وKh/;i|X3 OWfs?G&*%}Hp.UҊ<o}˨	ys`vn}/!R*h/ Wy\S%%33fKX`Q[,'||+4X/Tpc<rVl59`/G.8R;j>nz$;}Ado4JG$	?Q<!V;-]娫GXȁ!,q*LNj
0}Hj(
,7*xbH'+BgX
jDvc@^xGOg;PVLW&22w Ѱqsb/`tzHL>Ѷgٌ+ém,D`\/i%NE+0[3N<%rh;ѽ9_t~'GN&Tn*E`%St;% ) HJX	Feo__lH3zAfc|N[52n]ֳG5t)gȒE]G6ty r92^O#.ܴPtt 
l@ԜAh'	mHl@}ٰd_$}ok+{a ?jm`}\7Zo?5lr']$LgLسGĠ`Z'rP9݇|o	z<}6Ɇ;
$3'):ぜ8ydiyE|U{kGt)L=.)J,2 Kx=kڕhh/MI
uh궻o;ՖՍqw_CIr2h^tB1Þ3K2/D瘌Y+zꭟdyA}=H=x$êp17<F7KJ)Zd+$Ψy}<,!X.
>[E	H=HmSc{%$z>rSRt	yŀ|-^|NEZ'RO\6 @:arϐ_잿{~R7Q˗"7Ӵv(бBLz.k8H	R+/dh%(Zm82P-`0ԫ<r@$\ Zl*cEhb3V@WYcC6x)d:>aLcw9&wu޸2Y}u Fk\e=2s9@\w1 ),SfT39VuzFZ˪碚1`eU)j6匍J:U&G&AG6o>Dd
a>UpQtjY1ɢVkKd{́BqUW-K.pɝ/m&fYA&=1QٽxQxFstd:GzIIHL(ɟ2J6;KKa0;rjH*R$~pDcc7BmQtGBݱ8dZۉsf|e(
DvR䅬r
Soz՜/:h2~cX*.ÒQًM&@!e'y@!Q@ć#ð@v(x'"\hQX47'"U'F,Yg2քw=*7<9kg:º~avyF3=c'0hK?]b V郐crMڵyQa8*0jW5>џ0޽{gC1M]tP5Wur"}"Xwd5
DeBNذzCq{@ h<^;Y>~>+5_IDH'Gz-073҉@~NG)>K*=P
H%H"m{4;K/@aocz up{Aׂ=rf୻ɼu	E%*:~THF4;VpӦ(u/m|e,Ū*Bcc o*zƱ6B[l bϔW+=lΣ9+[<&vV^i֪Ry0X脠$x^~&r2@mP_C41|>H{oKALm|25+"cM-4NAn~hMWQ̄}q/eYꞪUW]!_/V'zt|+0=UZfthM9WKtAR]^O5lOۉ7cPOk./R|XGVص`́%È~Cs?,H܌VznHXΙVk.Y0ZAN(4'Ko}T><3I7ݘEߙԢGٽj/f8ŁEa|<s~IgXEeZ@CUZ(Y4	%_ux:8֕n#x"(GlR1У<6_6zPKgEI1ۋ6I-?M@JݺuS(r-\ǁ"}뽀nMCT&v<
.dl?nweXA/f8jB rK"j2JFڀr@)S]rlg9/9{e#΂H&=8M/ɍ>"oe!#>Kq:k3?l$?u}ގW46R()EbFN*L~VTR^!@OfL3JE"WAhu3sxWʎ"Gz$]H{boD8xG֬^^ʦW~*ׁ8
v,<}}ͮEb٘0tYU=Mg|)ЫIYEz'pb+]۟91&e}Z'bifyq9SY75۩վ}&bL7r.m[?|OnqZL:ϽcFgnվb?st,{2g
+5<(+Y5&7X<VeūPq-ChSǄg%:w	:k(
6^J?֊xa F21LwΦckȣ6Sޡrp·Fbf%/Yrra
g6>:f
s1uT.Ά52,0J5k!Ⱥ .gUjXk#qMҦfp4
HI|lKٔ`I.TcBC^.&RfQ7u9Dcpp:1$:F21gVj{-7WBpy8}UTE".X-c5#eAIצh9aC	Wcu'n+#<zHDLj?%L!d!L~D2}]gt#BO͢x^}m#B
*B*D滨Z!n*z8fȞ[mʼ/.\EH|("y,fS#U4Mb<A ٧>MEM0c9yf֋
&F3/9:w?nFذ<s,^, trKN_%5<Is#	҂`v7@gsg'v{<֕,5|.@WYT<lz~+D˽76:|Qv\rmS,1 %ZIl4="8F/Y{qiDLdt4sl,܊x7h	/᳸fK$+w[=g5b!s ]-&SÚ>"4NY7O\BP{JPX?Q\a9n=mO*D6"TB,C>3fo1eN
1ϮsQS$B[woSW(]♳gܓ᤯~<MC[mNPW*`ۡ="zniABC'`qd+M*ٝwvN<_G}!i	R3^7y~6RE(?9֑}3ؼlOxx3Ԝ+	cYqɸLF&{Zs?Xdiu{G^bnH9Q	Cx44^/jZSUR@rsn~2L?b/jY	0e
_WSm:||Hv(uJ۱a!օ޻
;ru4s彎q	Xs)+H&󛗥MHP["9XkXv>d R<{{H%bEuc=)EZ9wy}f6`"НJ
ǬޱjT1x'O3gފԳރ`|JF}DL}wcfv4ؿh<Z/;jZvXg_O4g2u+0smIY[+$$v	hl J.L~Acv8XhfCT<3)D]W]d"]3	%ɷ6_Q
!}/^BI>4} pR,!/X+U)êbLVٔef:`ѧމLiHgx&l\X	SzVEaf=emEAdH{~j\;6zvߠ;+ΞwsƗ'.*/Xg5W<p?5VT12v򴮧<u|rDm1+cSAۅH+.{4a":<SmR)dS/sWI4q(/G57?WLi)9V' oeGЯS,wmYsz!5m4mDXFNfWٱxEє*Ai%	MYMXEPy96gm-`/xI$WН7_䶼5se^	TK"f|8^w\wU'N4k)(~w:ྂHpp;h.V_%jJG8<O\|嶒ߣEg/Ij	"HPbC$(E9m>Xa֧e'lz_ /k(.//_u$$Yb,G<β	tj/UM1?uދp^;6dBF?_rZޢz!U]H%(10QI]i9`މ{Bc. B$6@.1:P=	
xa>ԘC߸P\qqOG"ǟ޻-0:ecXj|WKh#Y'Sǳcee4(h{;TQq%<8#ﲴ/
4eR-*R?ߛȎniFoz?L֎B3@\\TM}FmD OA3*Ŋ !wq`B`˼bM^,gw2M/.%WTa_AԾ>yaya'wDk_Ղ
mv'l*=<uSN_G嫗W{
(<xZQţ{T][ͼGMW}q9߼9)@`zgֱ,3pޏ 	y	oA}IPaB:(?nW-sosE1h^S v"ddY@C4o|[@l|/yc+ky4l;R9;)K<2NTpf_~F`Ps^7V7wD\JCA~$g^|%.@T:WSOAQJLv_O1]0&%#d>* YĆCr3⇿9kgDxH\V8<#dt\+_u\(!u	<$};e214[Vw%w\raHD`X
db/6r*DD%_T
}d8'!cʡbÜDxL6fmHl%Ƶؿsl$]$يQH0q 5@b`KJKOtΑiеɩ<gAqj;,s6_aT̈m-
NcTF
^H$ߢr̒R5T<0r	"[Tsz@'>FA]@CNLPg`
,KzUmk+HxbjfmTo'
>arn=*(0K\d_-GYMMoK˼&_/y;ՠM)MU|
PH#[
X[QmʢzĶW ۺ~`:ndgg+5(	xiY+1 ~א~-:tig #{ªMW ]];)JSǎi1 Ёd G2\2smi{J܂ȫ%DK`5To$~3t3c1|;Umd$7y͂öj9!7?O-)üy uw,@/ErSI'P)@9Rzr0r=Ubp	5ҧUm|Ր*A0T6Fh{XkF 1Xg_,Ӑ>;6Rlǘ: pEʎsĸ6FEC/,6J֕0)Zhps=LQ[;b'e_cЩ_Q/y	Qτżibڒu#72`qAv/׿Tj[Am"37SclS)eXJVTkRߤ.+
^gT v'1Qda0XL"Ӹ+$a棛2?eJ|z}#GQ]\_\rfAGH?q zPA$'.zͤf`k!AgpIP̑h'&&mb8i s:DaVkD9o0.|bk73uj{Զ|1gO&u&,A"_;J[c4+Yɮmwfk1iڅ0{zG-#\MX簨{c[Th\[DSjPU]PA>#8ΰlo$˅[Dqo<{0Kbw%qrfqQT3֑
Ɓ3Pl]_&O&_yƕGBi|# +z =p+APAEZf,WL(ƙ}/ȓOomrr}'$^V7Ny
uIQSsϐVvbo)1*7 JƬȂBFY(F+6ܚxz)rҠmi?0AEUs\ϥ'_xhM(3v$ڨQꘝLlqʋ8'S5``JR@C[̊~ÓgC@igaÜޞ1U4[a8/I?Z3geJ
:J:$B}BXR
K
2<	d7<}16CmJA#?L.m	Ĝʣ۾ΆBș[' pOI/BT\O-+/Oþ K(_do/N#+zFɕ3ˁ@}w'35X idWZB{>9蜌4J2::ULOaQTE:/&j#+Fid>;{i'Q 䂜`r]|^ĩ  @ IDAT:>:;W}AZQɶYu)M<͓V #KV$w2 E!LE	'18B[JPst|y~՜gԤm=l% ~7}ω;}͠SG91Q[xb[ [0ϧ?ZZMi>AP7&QqT+Mo/f ! xUȽHg}Qڳ7RuAN;}|7qͬb#]}?.km	3a8N-˦5k
-> ub(ëc9Щ쟓uWNv	TrOw(%l#zCخ4 YE Q@
4&0OIbIt+йRVḄcثbK!	 @.|R)Ɋfp{镸x"x;?oQ:goМ)#MtiF\}$?.]WÙSCbSOfj=f#ִ/XlGyfO8 C'A4Q2k)$6.m{&=9 pPѹM8U\o65t^'{;,1[{!4`9zƥ@Q5~1EQ6uKJ&e1Ha(neuP?@o\a},cax:Ax7id[Z%ݍKʔ1@}N7H7ks͘P|
XfnZǫCg Gb镀7}x<ub=Il%RvgO(zM ]?[B4 p\[>6j'j{S3HB &lݎny$5? nַ :h?]{ACeHPeJ_ǒhAL~ol	#Id;xN47 %JAf-btaxDAO I$T`*fN4!;pw1HkNBGSt݄I2wuVgg"%y<4/^	%[0o'Ц/RPFE+&E!
b ߅_AH(&sŃ|S<+T59֕xR҇._2m\d~s!2/B"Uh.&L\V,OֺQ|''ԓ:cY>}M^[㹫yh^"F݂yYDx)BNrE<BhgdbxTK.T.g9|P4\<z?ީΩ;hbx_ֆep]kC'0I|"MW`)K0MSH3;cQPG@-{CӺt6ރV\%D5$yjkN7^3Q~-n2TT-,=8%+RVTч].b'ӱ$O+$nGjIϩ$DeSIB!-]z7۟feq"3%x 1B@Ӣ{< 裳DSދ\xߐ1.$%'G"N{b/A5r>`TNnvL,+@>;JEvM+"b?X'Etî bL
:&!v»ݡK5?S x#/mGIp@}vܹRmGn<*!kd$CURO[nc\nL &|Pun=/=sn_<WݫjjLמ3wZXƂ|(vrrrɊ*0Kx1h#m𒣬,OfOv#T hu\-)/9p-ckE`D^UĤGC \#"G}s[xY[{>gÈ%K}5T>:;5gs)kJ8݇x-4KK`"׿dIװ`ቆ)ԋkރ2 0wQMf&~V4-K,@k؉暚h9֚&ࠝ|G<'xƉnd?8Z|wyWWϭխf0A/2}ES5P\o0hGa5%?Z o0mB5#&"o8V mi?ډ`3ڐd|#sӶ(+/Ys&_Bx!*.v{AKmۈ! ^D|J_+?raUQ/==VJ>)};IhMq\@@~83HD0^CFShgIwrYokEQ!!WZ6u54kL6B'TnzV:[DVZǄo9H\E`bĦ?GmߕG	av	iT
N/３'Yq>JHI&oC} 	9h?m*&#(Jo$UK?Y7~c^{vk0:%tzKO<7:; k0Y!m!|P?ڢodTIH]).vEt<ȟ.nh;dEA;>lۮhDxߠAˢwun}EKV霒g|TCޣ	3Y %0?dʦ+V9A295K#@Xr-9ŲpdQ<|EzAIDrm/BWwkG?͒&V#?6N<t$7/+v{;'HWWbA?|`-e;xMx+ԟw&@=Gl6?D\HN]N]XNvJ,Uߍ\ߺ2O=t{QcOMB:KEY`f՟zo{{J"cLd"xu8RlWkXH·m;At|~ڄrq0d((ⓟ;Qg޹
;jGX.MnWֱw?7;!1w˦>1=P|')셷O-K1R]"@.igӨjٟ{'g-L
<&T$|x]b.Fe21Uci@(rԛW2z1+ |Zt*uWؘ+tqu,%*%f{hfZǀg3sn&I/VnP\0֯Z~= o4 iUh9K<Ǩ9$TXͬǽdwe7t12dw(.Q700~#ܭ1ΰ˵%ǯL[׀wG<MTj:]>0jAތq"'drHۑIk~!4DP2po3!*_1#b6u=fMF߃'<~	(ؠEj\ƒB3]|1T7~r܈eY9Jj~ƶ7O	-͙G{wRi9P&c1~@vERziiV6y;8JS;@Gҵ¢4~~%HUX.D2+N܆;	ЁpɠLxC/<Cx]1E
n@<9K&Cӟ^ϕRT$|ys%uܚaR^12ԥ_ƒL@d7vT\r dzʰ>?5PhA$5Is֗T˥ETw5% ৺TpvRIO ~Șl	 ,>#x4Ts +	+UΟHhQYwx$ØƄ`#Ʃx7bq
ӝRkwVBj7=eao88>ȍ0׵Qv:TCT*Gmz*'mz+H ozxg	ѠbPYOaTׅ--}˚@p^pwk<^]&Խ=yẖC9T%J]]]z>λS6o6]п[Ho_TG%Ȭ
	[J*KAش%>+|lzC#L3rN]mx`(!jЬz@ IkN25/(jYVѼ_zK=d]%wKgPA-aDUbU{XD<eFesK@m?<:);gy?֤рe?~2 ӔGy?`5	$Mة`%x8 1 R|2,1N2,`X9~eBKLYq 	`<Ǿ*ڊsUw|:WK|ܤl/(uh?%>0:JR'zc_/YJƁVڧeg&0tX	<%E<փֵ8k8](Z"{gfضn]#J0v! $*a 
Z%4i#z%2b҄W[Qq1Tb'8]Zҥ-8G<w&.44ɾ`g@Y%}¾y{Ei2I·E⳿@[2h{0cǁn
6;TϚVgkDpz[deGݦ׭ЦRe9H2!<ەHdKњ9Xz6'E cs5Fi7P'Y%6 6M5g+*xf,W*DD@ovMS:<O}1_bqAs31|n	Ã5@%:3u9"}P-0~
#.&ٙtԂ"ES;dEy XYTSFvV	eY,	Id{c?g/Gߗh)
IPT_pHF=OYC:/nV?9_<@$~{m!E|z8pmcΦ Xw4K}\Ȣ]]"_qT^ydMũ6`I'dz\
5f>>Ms//:q
͜BзoINtɒЉp)%=OuS،Q	+(n&D
t$e(I]H
9Z6:Nae}(MҌS,\jȾc/{K#DqLM!dlPXCvܴ6C$}&5ل)֗,GZZ+lBYU_2F8@/;6:]犌8kG:Ձ|;q9+,1L$|13aȇ:e
 LjjBԙcf&R6tzTѶ@]A@?+whZ(v4NiPs	=p2Yl@|Nڴ߇',͡2zo9EX}O B"*Gk
(-0͘lohj2ZvB6k;Ũlg|r؁/٪Lܫ@	Qv%,$vn_5TVP .7\ڙthgXnG9d׭s9xH	9Gr;
DTMg'mPAVҋu6zψ[nҟKwRxHY	!],Ӿ
c>:,~1VBBTRHh m+hs(2YNIlg^eʼ2riS˛f| ^.Ͱ/q34)fI(X}!^]zcN xb!QG'XZb^\T|44V=`7$;t54%81J!Ivpzy/	kAPC/p;>b?pZ<'nUʂl>r-n./}kRQ6,#qٯZr[~ n
҂m+r{\@2G9LDY!BGRO'N .d.N[_	վǹaIt!KgžO;  fex<U&N#|~t p"3.ws%{wl2eLfFS7b;:csh\咏w9hk'Ϲ\aqfwU&Sv^ټ9<@/{n7/J<bN\piW<OWji='aræ@N7fRH)B;1'SB>ߪ4cakgxx@03`&ӟCIK(òsXw#yiSC8EFpUE#<)Gp34et
˱ݮ!e*cYha /[*0_-`\U=[Pp==~Bg0Bu|8Sfyo3@'Bhbo3<"L)t>CՔ!<uɽ89CZc26  xH`xIj)T)y	9lxpQ/yH[@u	wUyG ysΣ +3ǀF(fߥ4Ŵ]3t9\Ҥ9CV!`JMx+OJ7?փ|MC'S?	Hnb|9e2_~>N/9_LBs{GK*ɱ>1uN{e` 	9[yp)۶^6M,RI)ęDp%j!-Je|P$tH ׿wʀ]Ŋ 蜏|:='<RdxV3::$F _P9fY[bCYo,wjٙFSԔ'2#Yv#* >YHPZf 0/!/W~#Nٝ/-c9dg?t	Pz&.yGz8V[[l%t@cX|b=K#I}K)SFDmPVՁ&+@DBh_ m-l̇Ⱦ]8D(He`sYt+^B'^dKPKE!A&xǅV+r.[}H]3-4yYB=xq'`ɱ(Cvxɳ/]8ZSeHJæp/63uscY=!xW$.vzFcKh2oW *tFxܓ	P<ܙщeЕ>-WAQx2Tڙwk"c{Y+ZITW;G=>rD2Ş}󗾴.1]$h Z%ýmΝ݉Yn)Ѽ'=X ㇀XEǹ5k\F6_LJ@J pt"m*Ҭ$Q-`ڽwWMMM~2	WϺ+ՄX*ys늋QwPbDU_R;az<:+e	[/{ӟN@h9.<cX!.nK:=_jX]_g
ݑɕE}ل0#W l3Me82P]6V#Xa딱i//`:gFbc4' "e?.<qxdk:SG{\w30]I%{t\)H%<m[MMg(;H"kO\R*<݈_}@Ym|"tW$N~3BE^1Y0PF
PȀE6c>6 /Ĵ-e:pA AAV yYuV4~>8HwUB^ڨxJ_j^MUgpɯ,g5#V|Ag#Urڋ&n2I9M0by
bdc!	:YKcc([ao%4@b)3￿5WȕX0K`B`r||QL/+o+dl_ևG:s
|ul:~@?ލFBy{ QigVZ.ْ%wi&@$BBB
I%w!G:	%jLrjWwm9]$b;W2H;1h<b6f/;~2¾jHݬ:*拥[۬oWzzWLi ΤG뒇Ɓϥ"&~.	#eK܎JV
χm=|P{xme'(}S '@tI}h);\uwv%ׄt#x6j	cVؚ2zb~r UWfU~.VUGbsP2ٽE?""yRr+qG]^\L]Ȝ+q`]=W@K2: ۿ1{`yR!e_ݧXVT//D	
cieE	9A-RxEϥ}1_u;@ 5PܫٽtΌj' n(fDn]IIrr$F*ϲFRr6pǈ\c}ՔG5KsG#˰ɹQD咺*aYAGZ缳;O[=ÓĒoae+ \3(#[K}>UsZ_&[g0.lnl4B>l^6j)gUR^ φC#Ea%(}cǂ4}oh'=QJJP1g>*ٯT
f(ry_$RᲳã>c<-ZZ.QֶnQo)-L_1~BazLgă!'QRQTŕ^[tC-SLc2J<<ls?ߞ4qH ( qcQjέ݅	dl6%@wV.Y-\w򥕙U^ykOW}j# 	oHV0CDT/a1^HvВ.guwl<}ͤ+ǇRt#'*=q2r%9|Rn_y{BtԨe2$qe&Zw݃ҾVTU"
yl'T&#i54- /L$Avͧ7"ItI>ģ5K(AׇPPgIѽvI( ðjzn󪪀4lZ!Zg,0
̨pw,:'8&_Gr\s g*l>EUѷ'bkݥȓ]TjXkUqJ?;bsr#Nk^Ѕ@`<O"{fz7tpCaS$Q	M;b\,5oͣ'& m~>Oʋ+b]\$a<*X"k)Yps"| aPamlt>$nA)ɖ qNjTPLpK.JL8Fє+@ߑHrr(~|5l1]ˌ!GG\
PN{Ԕ<FٕHs54ǫldBm,a`BP⭟tW&6c[D
$]#vQՌX%!\7t"#ȏFY^ȁA)dAM@cM950LZ=1Br3uE߁f*??2V/Z% *	$c}a72z[i1dp&o"oD#6ʝu`=y㍎c.&2 $*lTϝ*=ݸȏmA%5D0LZV_,դ6+IGZ$VCќ)0u88I@YJLP\h^ GX:Qy
5!pⷁd'E !ʉOD}E]"wrvGL*%	ba@;͕r0C*_*Àqʪ0!dBAdgsH$R2gТjiхCp'tU&`l<C-8{ǂҲy[,C	2fvY}}[_)N/jrѵI4=ҖQ90S|e B_졩0H(/@%aҫ{NB
ۊ |t^l6T_+ؓUpP1hp3QN³JB8pLGkҪ iMœ):v@_G+(9ka|Ad73|k?vXQ˖(:Rwb)u8v{25)`w|><w-m/f(\*0	|qȰbpבrNW$>D'<뻂/0+Lz&\Kc<"5c;o΃! أ7\JuE;hRE_BbNq_Y޼dO4;v ZV<u?	%
@hB嗸6ȋ]M3T~G6Ax<w!FX1l`P,xe@Z_tR{akmH3L!f>_Ntݎ=18bVq6FĀx)v9e-x5Kݧ,>M ɑi~h,Uޓ,xg#/FF58V mv'~ M ()8mܡḲ:T>`3/f"< مS{+WI$^׌LZS~ksTi)=5"!z'8倞	6Ȏ2m*4*a?KZ&Z ISy8]N7I&G1@b	gK1#An
t#$!PQ¼	%Wߡ?I|إ'm*;%S(Ks>18'⁨!Jj`,Lx+eC(!R0j,=3|6@'ɼ"{wkUV(^~~׾AR99}3['[{6Q{.wu#g5 \ގq%"ϯ<LFQՌ]b Dv+b:IJoǆf!" QA+W`Mi>C9Ҫ~Gd`j*>~&74OULIɆOX:bL>$l ZZvKzVUUo0_lV>0PpϞы/8E1ҙE烈<L-]TXVZ*⡐	 uuᚘIgOSps%3܇*3znZZ!M1*>ɤ+yoZr}-`'?7Aނ*rmrI.k#Ӻ(5E=c@a!Q1f	16d/kG^3%T!\Ydxg^T5s 5JM(_dTOvOBY0έHD0nɤX't;#|qGI SHYCX70
ڀWJJXF'#rXѼѪ+8/J\Xz8Рl0H>G }vQ.%%pMbsjaAaNc";D'ف%~88bQ}2ͽc\*=}a/LNEcQ^pBjhg	 x__;-yX<?t(u7b<רyLխQ[»^};ef{[Nf%Û}s}諮ɳ߈R+9Yʬ5K_򏄩j ySBxKAB^&uspXx^I}9wv>mm`IrBx}A$Q/ڷ-GXn֢}C:UD(hvmTsTEGS9=n.c umn=>2b la`7I34ªZx,TaF;O	K?uK,27r%(n9`9Hl<2wn: d\`]^x GYpg&'Lx넕Ũ]☠~?y+x
k>xl}},O邴Q	15!D`n&p;4b2lpE}lg54`HnFbJhŐ==ɰ^FiO7\/&b.#os >aBXT݉~A|w=ӾR\,@7ikM)IaÑ>0r!?dd;,D1F%`ô1P?S	V2G_*VNO|6&]Ȝã{F3 S>2)L`5FZ<sz򊖘BPIu텆n=lCF *gg
QU7>77
M-]BW"[JM+F"To:xv Q7>MnXqp944χ~c_c(,Ro7?{X	HhϻxYBr/VeR}]`	vqZ*|`LfK0 |#F&+F(߹J9x+;(ʇ %dߍ_pi[t<.bgy[NXKgp0H*TaŰ~
:(с?޲n]#$ nt Ǚ;Nx7V3nԁbB%.hL[{|I-iǅ>gIbsx`>vy6@"GBUN_SX2r'?N«i0P 4Gz7X FW{}LuƠjn{)Y;>\4gN
A:$'$%mm?F
B$%|Ŧ<xZڼ4_ w$7K^i6>zpD cqZg#<S
{l(ؑ˧!}Y|m 7:}Cb{2kcÓMiUe_)(h5VGQ-w^Z#G|>h=2{69|iv>ԘMdsTMٝ|BsГc
d?U+¢CuxCs$[j19H"k)~\#z@u3V2d$kN+zHh֍/GWBA=}vwcuӊމ(03x\E0o$BW6orQQܨ,J]M1pË%X|uopM5?e*pf'L}x9a(B,Գ/Ru?hEkf<'ˌB7
p P.TY6]?Xv\ITGZ͖;./u(@k"O>bָcv*>w^dTU|A7y67xo(r*nTѶc'7?RMϭ}.čBL*mL۞|S{_dh&XȽtY
ZlO2#wxq1L
5M38ag0gyƧwFQYu`f
9$v>V	Y*RVxERJNPv#ҁV1ݾa8TR8w5n&]Eu&PDԛSZ4[ܔ3۴A	EuCYRڼ|ߺ\w*5N&n#lW_uƔG_׾N=WoLRH3or&U;;b.xj`8?|m+g:̬D5TT V3gQvVjKÄ#'ϛY"  CB Y4HQy2v<*JF9i@y(c3ǿ\EV8&+a pYg 9.~鲲H_ϸIL/O.'c[aTuy~T͑g2}L|q[wk,"δL.g?v,O%9j@R^HSeAU\w~&67N%^~𨙯򱉡L{ڝXB(]b0An/<QWwoee6<Bں7:О5H>6:|`ák#IDgtF+YԐF%={g%cqم^IVPG-*49Qj^&Z8!?)$zCWE%S"7}ӗ1iz-=b|ceN}`lH׏_]=0&}>if.g
LKm#$qvd3a;$-w	C=+Ҫh,q$'}@?z0h3Qhd͏ap^),B{
'xyx| 59.<%IBa@, E<K{ѵiа$#Y3ٜʥK]LQ#뛛If7{<N%{iހd:)vQؐRaܵ_$N"".Z.lp_D:Y$/ Xvy5sX7~ØtʂkG^r?wJa\ű
lMaqϿ-d B˗cCnXvh`[Ntf5PGK6lȥGLJp39]bn5c!}#>on56ߍϜZŵ!YgS)2+Z/χ7()o;Xwgq4""}22sqpKuM]]^Bgy>r%fX_^QېCG$ѫ+w%<`<m=7.4ecN;|>:J |e92evLқ߸=99`+:uNQ8P+d\ @hX)
ST6Gg +jE(Ul`i`<3`]`c'iBӃ6add2AII?圥'|D&`p;Uv,  @ IDAT0$n[V38e\aS敨SPD~Ry}hhϙuՌe*3Ծ7cO&A!P"4%WIXSKJ]@/I01! 3
LJdzTu%TCFOXv/g_h~dSR%!cP&9pJJnۥGSU	j)Ԅ[/`X*.ڜK؝v`FAi@⸓WP[v@EX=UXVE>AyE@$9F!':wwAYPn.hZ무r?׾ Յ2Ӈ,Fbc>$1ud(dt{$5%9{6orUӉ].GTa:H6n QE]DA	@U9aUµ4N8\NMӂbTzSM'Sj>/<@I}Zh=.aIB4gp\::^LZdzAQպQ X{Z	_荛9}6`:ȆSbg0	/7`6XN ܔ:8F@O$ѧD^BHvz=\dciCLCtܙyrOk9D;ܩ`l6 -UUD1LyM|儗`Mo
|Iw"sS1Fn&3q/K؁8:;&ߌ jI?@PX0հZyo,9(z'+++@CbPϾ	0J`YUs񖦱"i3SoV|7^4qŬ
?QĜ$2q@ʎgrTΒti}qJ_]Y,fbg/P֔u*,nDX-=luX"w6^ ~/*Q.FYrp Ԫ	aKeGd$Ԍ,}RYc[Yf@H:klD58~sv3<7/&d ]\QߓJJtpy|مX(ZkMbζ~Ѕ]v	uv=SUIf3 (`p;C[c
hjZμ_^&6Ն [!iYi?^4ϲ0eg8UEJӑg|->ؑϨEp0C	BuT%5Ȍ{AnOebC=لW_YV
Y_z==zVhdGJt%xBrJQ;d_y.9kE%W^*K30dRdZMsTeK379ARpf䴢-*	O>~B_PTZq@QN~|"{jժro>Zӟ{dޭJEYE!mK:YnpT' y/Lo	d!SI3	W*Az`}	Xj${6*qP5	ZpݞƅC8@83ubF0eXc1e ;so--џ<I+llW]iŠ:U0Ev?'egUVsGGLc@39 BNCHۢ}+/)gߓѩD>;(r4UWSЭ&^ K`%_k:_H4o50?z\o_Rj<~ͷ*yq- h@)P'{%(P [.*_UH㋟ZQԢ7}=bY #|
/H^c-kX4,aIF2z4=2Z|.=q	p_Ԍ,a2r@1),1/8.P#/hXd2幒Ch#(5kt_|T^yQ7YͶ7PQ߯#0Z¡aé?{\=Zy W:ߖprNIZeb3Q2ϜK^並ioWe4jƓųա%A;C?u3-SF$DF!B$,Y>t<xD-E,"8v{Y04֝X"Pp0Yk0Ej<h򻜔"H]j usGF1St>?|F~wͬVI5}KkGT3Y 9s4^#;.]Zf{jO0vDb?QTZgbO@i1rz#
Vi#sC+vS^[z+f,-:$A9()x6N7nB?N]'kZ}O'$
R	ϡNl b!C)ҫ<E3W$w\/ν*l_/荣rX(?56!Ӷ_8r9U*0}5kf|,"<3Z
2PQw)$)M_LS5.1͞x;Pe»VĚ(*"h}jkƪMl,߸{ dY溬5l9>2㮓|@K( Od&IOFFWƘAl?9?Fw7ᩌY:@Mx.x=i5> MTLR&Gv4$k?|\U-T7? VC I6 ?	=D	zZD8>t{N>׃X#A:aq@ڬԧ좾O*NPº:۠4j˒SS@	ujÀ<]X e%qq'aSۋ# +0eoy| !{XJH,F\Ǻ',|(;n2g6ܺѲHi4!,	XE*ey榄I,-,H~O LFNӠ ~2mIvw\i}EdA6),^Xb+qf#%Bh"zBə3"?ԗ/c"
F*1yk&p`g^:fn\h@G nR5
oC
ɐo}==QCx0p x!^w<\ZɔQm~8,d͸leT)s;zj1/t5\c䠴I}qo:zł7֐5 ^oķNhưsl֭|/fRڛ 
x+pf`o;ޜ~
!QހυJb z=Pn(I&"ydj@>qWpG_a~|ޟ	?C.8>]b[z5I`v$[O[t6A`p9*}Ql_oxCYm<FJ'>3-ᆞю[T|
,~}	H?g'CPO}v7¬׳K[_U藬a}9
 sl뛳9zt('QYl@`EۍDji^K|ij7 c>ePUׁERBhݔ̧:2QtN?ȡ
Z'S'( a;d~*ym]{Z[V CN@ lk?@Qw:s%֮c`<,RF!Gq1`dupzݟ?l瑽J /3',f{!vRr"-&WRgPnTQEX}Kˋ5uzAV	R.V}ouRv!-g
[QuNCA*79,d;1Ti0{:c\YZ2?Ño%}Xpu61=rem`5,?qKKzQ.N_,RXlX0f77\Om<Ql1@*߳cߜ+dzLhJn2ZDcŭA
Unj6a^<B8TΟ0 G()ϖt6~batA/lթټi枰-V.?ACTvK:J Q𻕋 e-NwF$ܦ[<l"hI?mTvV	rZxhoUeYuF?0ds $.Tn1%>;{g@(i^^,mYQΛ]GUsMݯzI<Z¦+sn۩R;O;8ccV'(}kim:+snm#K\OKkz ^I	F?7M~ay>T	EX,j75G4qaI"v'3 u[ȳcXM9EW0sXunY~Gn/ZK%K~(oឞ55=)rySqx&r1/.;JEaV߳[:n)/w[,iu̶4Yñ,(Jn~`?.a-W1cI"DMFTM=nl<߉LZQT
nk}(:MaR$MA_1RUo
On#&):Mo};h6iܧ@ႉ3b*|lϠ>K+I@.HĦSr)sZ)MrM23o\|RLStlkխ/?9l9(#72mbREKυnmӞŷY'_31a-A}r9P8P2XU77Nz(p{ۗ-kPtuV"Ǆ z;]{y~޸dx(ߕh~פ")g o_rF^{[LE[`P4)T]Y0wrza3rJTp__ϱY:/&doѓLQ{*Y$ھp=3@р!k'Tm+sof	 ڣ}E3TZ?:03םI q_#A`Oʨً|R\͋-iQp~ Q ޓH)Y8`sCjzw6}%F]dz9A|)mf"OX40,ρ@zbiEQv6K,}4yVcJ[ fpI[6u!xԫ(2s!s\xf`T GI`;9TA>Ǥc&KfTHq٠wa>O;z=KrNqK%Xn<)Dpܱ/6R{>ǷQ6H;K1JR-H1$''K^h
iO tA_n01(cI#mp!u	o
1̌}}}b`eݟ8O)5[÷X^liJ9E9ekd hGF*yќwaucCIgc"Locub"Mٌx㽈o̽rɚ7!f}8Ɂ@1|/@5}9was
~4N!Qp._N^89nFGfzDFA.BLp%/|>osW>X伻6m͠ʟ}(=4@iQU\MeÇ;/m R&
lPQMgZyO(-Z*c]Y%=ٴXi/t90#'ng OY~Y
бd,ݺSeAe]LUToـKߠ𓚬|W%;FB2gXgCadFr.r?7vuŧ{3 \uxBZøCκJeRg,#`AI;m$(d@~e`t>Id^ ^cS.EӠ;	w$x~#Hf?ϬO"#3թ 'p pO(Xڔi$1>A`9\IʨFdNziеNx}_r-yT3&Ou:r7@1vRI)VjygSvv"\j!J"ocF5a&A3׿8(SʽDGRK`'.EvbAz

ip
l[6KzWg P`:nb26#MU#=7VϽ!;CԽT╘)X6'QiuHFsC(Dh"nNmQr!$23('m5r鎏C;0E\y}aaJ'ϑM2.C)Cb<w̙SwՂD\Dg^Lq,A-8mE%_DW_v]juAUifr9DlCǐ:wFgRof/\-υ		Sz
;|Ы=>|dwv  Vypb0[BO)SDGi^nSZn1ab??=uw]WyrYׅSK>]8Ө4}n>ot'ҿϛY^5>/ c,\xt徉";p+UXt	07'Lz,V,)q=Y(YeAYUU)`~CeFH3AbD%.8xafH2`'[#^{s߅IRP^:k늻NLDI s)hޞ]<5l] =bJg#zTz(8bHPPJ	Bd/6~SτwzˈEO>wAvdomxw#1u3,+	L L,342p.uݍjWcQ#K"Siʼ`z5=Xo|ǹUZ_3{~+(\
5Z5sk*y @@٭TwZh4	C!Xʯ{⬏Y*wQ-y'\tD㜊%
e6h2c] "/}Ay
ʍ)M+ Io/;ﲳF~lEn}"VWNF7brD9*3=홷C̕i[7Iה.ʇHnJJ!IRBt@lvI՘cؼ둇zTP%tE> 8 ݖ;oX|QaQ<:.]5C?SNή)dR*sԒlbѝ [M I%Ι~}_cӍI,(3cC}lD5jg[[.J"Zc =;8`į&ܶ=Tl.b,4oKfS\vW:@>sp7*Ϣ><"M@ECe/u'FgBCf6Mz{nă5-9dw䬒*h}}ݙh':SM'R}viU#L&7Y͚l(0ӽ,cef&A[^s
[w⾲lc/FE;/7\ZE^O+ym}{#@9~9ae@hiv4}< lf,(XEAB{1xn[?R<jCIZ55Kd%ا4wyZS}'6Cp/ȲhVSX]czIMş&d_s؊!}*UT0YSM	ͪo'BBӨ(̷%rj}G ch0)%%_@HXDs<`|I9l~|U#dIo̴u|G-ETILFuW@P%v'z/5пAt-sX6*[8:M~o~aгwx_|6,Au:|Vm	cָl٢c| `$03R\D%vХO9lLqT/e
]I(EaFw*^ rS;@{(m,\:H|aă')mJ}vaV?r-(m妲Z+YĴ
o!^PL(LaF|22R-`[hjVH=2'=VqV#un="kwH}%,4@hdnZVx|ČlbCJ߉Fs%euK`.isHc܆q9Yr@ء-/TF' n-&o*2 Rj\%?	8kZ	@Iw*K4*_"	?rMZ
烕l:Gtc$eI}zȃjHyMy<3JVwbn^@A# beMw :L~FJ>;"HOp:#X /:ïfF(won2}gn@Ά,#d9M`?shl̠k$#M610=6d%{"ݳXK"J.M*0^#bNk-z	RDKG;X N/|[[P%:N|υ*69g7*o齆b۹avx[Yހ'v`׆{YZaq~Y.?bM}R Pjop͕ىOX[cv_	)}=rbIZ/z/448M,H:kӎH乲n GEnЌ6CIKԉaOCalEWiSkZ,=X)Ͷ_[o2JDqGٌVS_Z߻}BM6l嵍(y(	 0ȡ@@wՌD0FX3ڼV}8e8 xo?V.TILTRX5#Il.᪪(:_MQM}}}9g!|IvF:fsr;;L5 sCѼ|]뮟1|+vY$mYfl!i׹<BFerXSiנsRlcyqEղYHd:>>k& /GQ8;77s,:ЁA?ZXWЅx} 5.(BzXnVرLd9;S&Ut{T=yHhumav$IoN[}]#{ף"=[]8{ߜx8x~oËCAA8نKU-X06tu]@$n0+uմ9\:V&CA!-ҡg alRot@+ųW?AgנBӴݮg̥;
4-۳/ysKQUYxwveΚÈu-c#J_F3ɵVq^1ߢTw6AJMI0gPp% |	amQ-!}Sʗ.Z#f55uUjj14XaV>=]%ݜT*|`/kJ2#ѵEbyA913scS|_xâx12xMrTPCKqj8e' 3'I/ۏB_,uS$̣\<ݯ8BS	Pl̒$~R:~ID Pef>wAAaʸFu瓬?$˼<+&e yh;	?:~MԏZ<_f$v6Ag黰Wzz4GCYNhoӬYQxZ!SypGdcvLDw@`OHlL!|!6
T-nf6|*P}`_jCFd<@;<g%zwIS[$=E-|^s#v	rO^kΉdb2ӟ%dL`,@vsxBnV[K,&~1)pni&ؼ@2J6AB&84;k\%bיnmvsQu|r?rv+D=v4x59E,P9[0l
*|P4JWThCĢ#
V窆ՙ3aN[egvN|XS%\GlFZƌub"yTy1 x9V}$Tpb0T1ao'9:lG~왾Ŗף?R8ycGnFFuo<	jyrz\KοZzD6}I<庱)o"$v{T}+j}c;<w3wfxx~Rźsb?}n`bd?(20 h81:9vؒzȝZIE@"L[]V/>rl+	8sLHt@COE{tdӚ9M^E^"C}~$}	>_p.Ԛ t`49<zNE;s63KQ=9pYN+VHѠ1E.JBR #}%#OSucjާ__OV@ROO[|sgsqKpN9)ov, B<O?0{ku4`$c75Ֆ`!cvfjAX3D-BpvE7wz{Wb}lx\	y3ҳǊvĭ!UY^p<ڑy8ɕ'3D"6C-hM3e[jD0d]>O!GH%KvJ##2[:s}yJ盂>4ΌZΚu|:p
DaQ,UZJ{&6]X[H'ּ2Qd D胢ϰl 8PzμOjf5ge(cdMx/wM'8>O:YrN͢*ix?D
iyl/ëƧC4qPamF87TFڷ~`s#j]!a[vog!I',sx]'r~M	M૪=3s@ EYb[֡ýzW`oZmlj(
a&@B|3O{uINk]σG?
pm1Md[~ ~XWRMኆP6V*X5+ $n*$h*Y	#roXT\:-c+-J_oN}h:)'>`U͍:TִָE͚к(U>t8лbM;s*}NClLL P6<}b>bu{@,2RU$'j82</1ˍᙢ8)pQ 4R$axkocJ4EՍOIX*Ee9C1NB]cPn`)Xx!YfB,\,EXywHoY4)NGwbQ`f=0t-U şI͗8<ؠ0emPmVHb`ѥ8%g@`.\3Ԕf 5k˗̦bY0^iս]
қ`y;gE#҃<ɓ,_e.6o
iImmXMQS7 բp0Z5vڜ	#ꕢ_R1ϙXS_R՗TdᏰMJP3;I``-?"pѷC"y8	δ& 0!(Nm{pͻ2uR!ZsFHʍ]^ڗcb*nEQgt,¤ue#92̋AZM5rO/.|p&Jq-Gz$|H,`#E[JTR]IJnCCYc-]+k7̜kIBDYh+]P⋭:&*qek~dÞƐtla	F3ze~+Yk^ەok1ϖ^!|_Upȣ'6۩Y2Vc.ʋev~nxHhi&k	K
Jb.;ifw& "[tEu pEA?ǧzA@рiu'c">`ǡf uްCBP Ж#$3}Lۺ O铏)ZaC:AEp&!^F9%k{׽|{~% SQ>vddm/>`yP7o/˜OR(bN9)O򔞷/ꉸ/^bϙSko_s|_cĶ jDXDuRioqC`<K`~d-/W쒢T5焘EJR;(];1ODEeV5\"I5( PbI?1ԴbHrmC̕"[3dUI(<=Q<enJ|)7ccY(XW]i/1!ZIq~`oOxV"NĖTOU)W9LLRY%+zhcU=>zIW
Oa+zd?^@rizPێzpj^iRXlʲkn
8v>}<%NTFVڦ[({a?:<~?4jwr%z͓F-
% }Ƈ3cʅ#CCVfY	sO2tY:Gm)f4VN>=y,7aQ.ee*[P^xY%wCZ4]'	Nl=J+mBD=z6ubm3"H2qVqp?xR"%'X,1us%g+v({&[ҐL\tC5 !cwɲ̱`,QF՘GRV'uG6wJP|IlNT4GךK[6R	Iɶ l,< s$i4FmQBz㖒U@}tfqK&S,
k ,;\c@\GUr}FE; ;sW%Vzۇ%9~gJc4Գ7PӐ9r<]&^
Uz7݄sKƪN xJ'f[V݌">SjJo($7HZpH!T7*> K NqҽI~	Esizfa,,jGamcQQAgێmbU<ہ6a.-|pb/%R2ryͥ=BP75UZ)16 JkBmLB=q$4.*pu. 2 l0u<L26"-5	hK8eySNt:Si$@aI"\S<xB,ܶᇡ~~Sv&Gl1Ɵ[h  "Jb8TÞE}sPMs2($>=Kl4;5k=b5^a3DNloG|~wojca2ha,AHLxmlC{L:Zabf,sbY!zUbGyjiP:N#hwֿsbňb&Lxq 8vj_VC;)d
Yk<nYKoȮe*>O㈷;9&zꜸO[9?!ͩ&>Fl箷WMD5;cЊOn"9
2z.TWTIPdеUs/YP_C/3*>shiӇ]m=43m`VӁχ=]磰,}}V}x* H';c
*"sp@|b7\K7,.t׷x/1r0of#obbnLs~/X$Tv1[EyyÙJ#,v£UQGӻ$4sV-|16޼D`3yF[fL\fR?3`^Wl<ns;TE	RgAď[j- Mӵ"G.1"aJrbp!53dk8HeBρvp7 tYTՁ`7V#7-u) \SK12=EOATA |(\jX7 6SKI-B-0I'΁KJ3{dѣ:儷e`Mq~hocϢ<gʕ4ZY6w.GnF}Ĵ2$Mh;/NѺ*2/ uۖv+םd6mƍliy!XCkIPtq썧&;jL˗*$AB(B^(ؤ:?We˵DxKnN/Wp"+O)ԯ|I~
XW*KBo~_̤N)Xv>xʗhH_2c0# @t#GHQ,ab9ė4z7m}!nJ䌢ca_9wYnNh*=-hcYS$g&Obx٪!o ~fwNn
Pݾ̺PյRq-  @ IDAT?ܙ$>.sێeoy<A/cHFld6dfrLԛPd6<]ɞ/97b@6N3+V7 #L"c㝺*NlO3%z?fa8Ψ<(L3$)F>D^ocp,d+??>R}do#w辴c=]YroZUE,s+AJݰkz*bʙʨTJ^4Nc	~WϜ)'g7:}0ۄ(0{tǩ݁d}ԫ.-HT%<9-;4	?F/E:7}kVq:ə~g=),^0ғ*3QfTU0dm4+LX|σ7"n}ڰ✕d]3A8,Af
ť֢߿:KM(c=rkŇoOn8IJ^s\lʣb}{XT] 	84.+
>lt{Oް<k75;#(0.a5W"%u{ZpW's9 z)u#7bxeE=m).&oh充G.yD,5T$>UVu	A6R@PlL%b< ^%7#DQeb^BDeͱ#M]w?!#{7ku%+& f];uݺ|ȳ qwswIrs,j3$ 3&'cd\b^6Dv/L]!rþc\G#JFYtБ2eqj
J'rob:j3OE8| =4$":@9=%ؗu1I%REAVTaUsRLgh}	EoJ3$x'~<LAE
hh߶D4"`%hfQqsR_OB/ښ5h5tjӖ?~'O02C.y@zz"׉˷ɒbZrHsW}^jX
k/pSv6rmo󐇀*
;<h|H
þj)#5G<jHbᆏ"2rhc#slx,fSSKWBJTrVvRtݱV5^1Q*x.&Gfkw_GcY-I0ltKR1`+c!gvΙCL{I7=`
$Yl<XLiƻ"4Um~#vnԠ_pp{ hvbp>{v{^ʜ@nGB+y3N).#n:'H
\~"MZ~Km<Buy,80uiOϵϽ]WkUG^'1>'0ݑ-hOQ9b'ø]h:1*5!a0S<{/xS]Ț5kzq,4V%Oʱڔ.$Q.'3BHMPE~.<{`GwΙ鐓R=zńsOr[}QEGi*+TIʺc,3'}vxXPfka'@{{#(dՁcZV6h<WӸ).C|]C20HX.WJ0vIasfQi vQvX*v޻#/T*[zf]W
%AT,yWQZ~No2)!즛 @wzR55dydNi`UUeIJ"0VͬIؾ_SyXOq
t6P*uɬJ{񒐲dcDŮgǀ^	,ۼy(\* 0sBjf@jhW[.[T^*F`f>YS (ozЎh*piý7xM߁݉ܠ:2i`bĬDQ١~yCS{t55Q8g\%Ww/Vob-{Ӯ'3m%|24o4@m,Uk'Sj[f֑?c썛Jl662K4d`c0 m)㌪2 H׀=L.o<mdNm`WJ~#Fic̝3Q&)fcU$HY=d47QzF?\db&8gE_4KR@}ߙZCAu-\M;M*/N[^Y+JOD-)TyL*UPSDsw76̨Ro(sX.~\FaN-dbE(%j}82HRNlۆz'zþ6؛d;^<ʂcǠVL$`8ࣸWQ{)ş+IpmVVρ_u2uyX5G.,ȖI(#<rTcƷf,BFOEh<ow75!΅x)u&aR@51x?8B<ŒO7h{CgL;I@ sn.;d-n)-a)t.l%HDF١dv\\?:Z_n]Yy|\ML=*Smi	
!@w!Ay!kDC<a{`LwrkjτxűFO[fDںG0v{ -|fYK[cJb7*E0!wL{=vUԝNYꐕ2?a׻įOm6+Qz Jv}CXTC`2naY"< &;(iĆ#}w̦i	䗁gXrɩP˸%EN%:iZ+p.Fi 0\+	;ATWUk.D(*EBră26|Ri^O[Ăq*[b[?@VF
6uK/*2z9f_##!jjNy÷T.eG;"}zFOrEF_'ӦV{зiZj5>S(UiD0 C%^֘va%,ginE1翫K҇V#Ȋ$ubLYm<n(P'FD5r#~CWph0v<꫑+hOoC~&$WGST	ZkNa؅,A}
]p9KqKĀsG$" qNj& "gk@̀ wEGq>(0i~*jw4x=2_f~L6aʊƲҎޖ4*0t ^7d Yoʘ
ʜuFT<(ѥCGu<%کiD%ߎxK QcpxfyMCz#$н#ٴl+=)2@jT\|Z+so'I	Vr(Ca2]Rҩ~܄(IԫEEZFy>BIjшǔN?AoSr7&G,%:wR؞kb8z׆N魋˳Q|sj%?3"sVh/ΉXt؇:ckrcEQO:3?*[K&&UWEXa5f#I)UX_j&8]hSdз['>0?EnAaF$j)d,i1~:T]g5nG[-􌢂9vT["s':C8&w7<XjOds%V'"sj	X>rbAArW)O#T7Eǹ:PZKscێ!,o"K}	.CSa܎H9uPLE6Q:\hxk0F^,>Fldr*l}s\~=*'W=oڻcE:|燦58$ڦа4ڑDZߵ{IDXi&2x;)ď6")GQI^iUSN'OӀ2hc8)8)Xu8vO=fz+5.##10]]"|{PoYvh>zZ7&'ދWS$TJ1r41Ϭb10=
cWвUP?n׹<0Ə#z_$V4!iDdIYU=`x-GІTER')ifL<SssûmT>o{v_uJTO,KpSKI#8Wi
=Nang$BzpP,(*[zBـM|ybgrc]e9.
 3K	k槓^^_i!o$hTގXUɂGڃzooJ+-;<:V`J,b<Fա.Hjow?㥨ׁ͇:ebްNdɮSjZ 0^|<H>o{I̭	иFgc!ˣ1JgcAaJ&XcD'yg·;K0I#
'8ju/ pS祆Ι33`d]ta?9EM(puOZk0)Y
U[ Hvo$'lK<=dq,UZhQ$_`0I2=hOo7eb:$_),'C%G<cTWm}Rpp7':=ݗC&dLVh\\~LΔ#?&JqYàK%,7Ioogcǯ5K㡮B'/壏RtW4y+ƶ<ӢsE15U*cOnD;q%|4M5"aP5(V+k>݈CqQD`F8;n`hW&ω狸 hBKZq3F㋛ p/>UW/'"-,/Suq-)-G7N.-O}^|(MxdAN6ⷥqjfy~|#p|YKNI)]l'+0AXq<UYwڠ5j2Q`,<Jr>'ǵdCwV6e?V.&HlkxT6FziSowΩ`E1%SA{WQU?4ș
G!o:1=m>e(D( )m:߶:O<W{ϊ*@)kN]ٔ6J?llP9JOFnDHAlǴu+Q붊5nuD8ngֱCˆ(s_65YĂyΌCkGZ=8KW/[V+Rlm;G7ob<#L'Uw̠=*QZPRCT)4Jzj]#4B87?~aa=}iO<2Of4<4fpl3>&إHo
Y6ĐE0ed?ysj%qHo'B$$QT9K9F#o;;j'VF0\X]<L<	=xGE̜kil-gHIHy^LF^X*&$9vEdZe{[e5E'0,$cNt&3v0Nzq@$Hwq"-@(p:RT :|HrkQ1GG 	` ˒9Z06YO2;Ud+9&q1ę@9̼S&|߆Lܽ-Zz'E~DZ唣Qn<.NDxbvpב+w<QTW1*w=Jg>mn1os00<'m/Y"~BT5C	H
7-344Yݚ|#x<L=:$VB.m8۪;d`!T+cduE$sf[OSsdvfW9
oQ	Mșo^pkUC`ǥ(\[YȮ>9ꜾTY11E
ʹ 0.0&$#h4g[PmFoxꏼ5y [رɞUydF^zK(N;_nRSR@<J7!5`+,v@ti`rURgnN#l#@ PRlAgIK݈O_<nN冫|"I^!;''	LEYX.xS/(.}e8x`ۧJbʃYfj(İ;=0HtpmE-.*\ !Y%!~SW	NBUlƺ7z]fWo~HqZ#x`-]M}F؏LbٗZ[>s"Ln =)4iҊA/[##=$?FO-#KZ+u:P)+p-o1babf F7	ONxٗl$wˌ5JDACD$Tu.!c4%!=t7^wJ}I3%`pMTSXG9*ݔxDuRyi:dkPER]
Ri/џDv|F-P>_T	*iΚZo9PRE{71l̊
p|zo͑;߇	Z_zCt<Q#qA9n[~2!)%6W!D#/_v4G 
Ƨepii$aU7"6N"PI/8<c2}EdKRI5,JqJ/~I̗0	5HW-PpFBjl<\&%X_{yJi%ND6:tJﾆC,$}\=?J=2Y}1lt~\nrd[7M.
ءkP0*ӸYu5n{2֭zIG唾)"N\rla?	oEdU*fa|H"Yap9ع2g9x׷+ack\&MV#,Î Lb[{c(S,
DQ3V>E2$(z(퓨y][xZ<TP!,LɄ?͎<_KJ-ԓmhL'#lˉG9%^xo!}yIJ8
DO<ˑ_6[bBVU=6S{p_fڒF|&Tiz*		PvH՛sLܩ1Op&fڷ"Xaw}$Մ~rMbG0":@Ar:k-9O s>i/9:INy#/	ky{X;VCnFkmV3܏Q	!&c(e]b0Vyxo@aC^0,|{N/iH\N;%e㟍M;NȐjx;LcB!gLU!ɰtug9%bϱP1t	W9ˠW:^PBTĈGG8°U197]{vS=;JǭY2+((7&{/vӃ$+f=*3D6E뀯8Ds29F\;e
U8wfʹT1UNRǿ.9!6>j#!jtQOO*S 13э]e-kˣ,x $>>gu'awv4dJ4VٗucRWPR;c)>h)tP!^̹Hh&b3/5lpb)2*۞@6 Fϳ57n}XiIM?1Mw$$[KBD؀OkGfyHRGoXƸ6u}4-<.ϙ3'(jD-LMlUWG{Hv1ߴuIbL.㓆<%H6M˯^:E9Q1}
fR3Q-?  n(kU}3U1Yf)CI@~>dAfu7Ț->:0VXoMHhs	AM(M>C5 [d7k|9
9f 'c6n$NI}~4&=8E~ǳ-/2|[xSUCv%gKT*|q/X&l&f=6LC5r#a"C-F. *vORt@VSd B5?q+R=Œxk:fM*1SUK1t1xDėD}b]P>I? ȐH/m_@%%W.< Bh%XdE=WQ?ukq2&`&.pB@;L?KgQMv'_w>ZXt^iu#.\}S3fRN$4{ڵEK]3LYchsD_g,i"r .Gs|yp.L:͕ES w2"y ?WgR
X_/<ӮA&nxr ZF1MS8B{GBIw{SO"߂2'y}ƿI&Oc{oѰLد'
4K)=M4*/
+"$&~	oZz7'c_=t..$IdcR\d1<+IL;At@'0J`ʢQ ]A@0> J<@H✟Y߭ÑCD΀T|%:&pIR~}|G.d+K-=V̹eUG:ʭXI`ҩ_|1u=%<Jꄍ^\ަ
joI:Y2Be,5)q\LyN\ap09/棸U骳su1wJ>4ťL1! ᥡ w1T4rߠ~֯bqm՘84"C8k¤n=oN}v}kd/xbtS.h`̱Rs#=R~6AOpb#/w p]</[ZʋAh\(jIqn=h6<\7&u)iqי*g>H9v?W؏oiOmp2zS,P	ȱN'3Pn~7ȭPٝ@@(%JKO1v=E'm96Q镒r,U9uN5K(]-ꤌHY~(eƼ#X2n}hd%V2&MZOQ֑|?3"Z#OKPY 
[ׅB&<=)j9~
c|&R ^Yzo !]P$iFYoJy͙lYׯ!NJ+Vԩ 1`\q@ڶi>
Ka3u=kjy%cc?o]xDUeEs󃌮^.t4֝B7p[*ĥ-KV#E.Gr}at6ϝ+&x?9w=s>UīCCP8镒XQ`r#|:@Ķ̵yڶ݉0m,{[Y9V@<nFu'tᓓ9ނj%	P
Day^ye!$ߏ>nqN 7@\쪗k"zB4^clm5Yn#X?ޖ,dPD}/j.ƀ1o-l|Ly(bw<ovA~^s7:^VQеK*vGuX9̮q=\[gj  X]Yǉ@((zbxHj;-Pv]lzA0,!{/ʖ3"?'hm`i4b|+(gZ퀍M^T>CјpC46r#-&8!'Qx['ˇGv@^vP͚ms^` qHDU{viu)g8GIx-
+	Da"wcNJ& l1^虧NQ2rƙM쿂2))o癡NM];*m6z<ux;:0M"9%(>XCME;|-on6tL\L<pojbt3|n
y|@Ԃ	X'\W+?pUBCmoYp+&MOv$jwD̪ߥ'[JPYڋ݈7w0_BWGć%$jYv#4)pR_"jp,l"A?.y0C7!ޭ<gxٝbfPJnیi9m!wW@sp 'rjY`sCpsR&s2d:7ݔuMstK뇱o8JLf9
GBGy=C`=BBCXdL@ZU"uu>ؔ!ӯy"GvT*JS]0.]ƯE93,rhIn4k8ח=K[fwE)f:\=|/? r!<vHx=JjX~K0cf`FOlXa7[+dJcy| #O5ԍT.D_?ORvo]A)! \_s7ލ˿r&rfSCB=@
Тhq'놡a$N7<}(&Pw,h2tW_ư"bC~`B9w[Rd6GNn<a\(Y"d݈CC)yh#Bfͱ_[Nȼ'
#*6[;snyh0\EC"oJzP?	DH=:[hi'e7⼘QV_a*qc.\t1Y
2H*#hL5q#)$ExbA"<7 k(ۣY}oP8bת'=qpL98휂	(xҬgp#O.(t3K*KBg_O1zˤId(P;S4uo,5+RܩQ~춎kggq!yn݉	B6qFr]ZY+Pu8Hasz$3 OCȹ^,VaYFSj3@O)j]܅LD|.P)ެXqCdiLη;0g%Rz"54@Z,
9.1ʣ|T<Ն@
ׯk&t<C~d2#F-s 3%G.xB;m+%˩N)
2Aǭ+T\yF:Qp?
Oem砏G&>yaGNa=n30'xM0u;@,yBC4=R@8xߵQry(y<(*/ޟYpW`e,A0*UDzdszvU5`^Y߅Re@nZI`8#*u5#bQِo]x[x1`K~ҡE|s_$%XŋF0yۺsa)BkA)I#F>3]`M@{A]z#4ޘꡀLzC !?+8;͡x61n'L#;?3K)ɧ,M]X()Vy_}wtb&הjΥBPzјbI`>VRo'| 2W,EԦK1͵eʾP,B$Be mG\ | N^_	6ktZ'<'7jnyH+Z3=:߉R[6.p_H5#EwF KP5STf};0gM@ooA;8	QO>
A˟Z wngS|>?8 ;TrN46_=2?>r텨凣l
 BM"kxU4?rJMB,TBc$Gv@fWKYP:!0pQ[̒tw/i#鯑cX47s
+j{l-}/70]6_&8YG (3G-ֹaIAseH\BN>*?2c*bmr}*vo} z33q^MI~=xg"2&uZyrXR8DiܫԮ̪'WI[q	4):طk~ҞUyR2Qt:-տ?f&hz*6āaze*ovcY4h%<XsJ.$SUB7wp!2?̴PT2/CѪ,=CsqL<c<-\/l}^w+]o(WCJ"Qa6MrBj\L'I=9f?l/괼}>z/(H&觑yEPgvPG{6'5;3]ִ[O hO`^r<VIs7&\+7iVS-ݘV?y(J*uR!2F,&S @ =ѥ3}9B?}q<GeB1X+|ÙLhG:8pqWRL0qu?ovcii7aX~٢&{H@9r[I<Bo7]WU.[ư	Vu\vOG,Z	O\` bYE^{!^ő@P6r&7h[u.+	$=_&㉷7l>pJBM+2y!_^?x~=>	W}]\gt(c E}Gq꿙 *fWU8}8c'"(1xʷ~vdB9z<b?8]-KıJO<6k@y""V:(2)ix\Eh,d}!KQ'B27;NrԼ\j4No +V3_ 7%ޕC|#	
E
ttbţQ:,[e+φG0l7W?bi(f~gh=l0ń3n'h_e=+/d)k3A8mDo;+,HUW6t w%MHRԜgI㟶,f6?E^

@̴/'Z}uԣ~kBST12JJ`lh,DZwo@^{]{б턿zK%ǵ0$3ᅠUn%ـRTN$!(Z`(c>&+u;DQj":v5?IƑF6֢z
_#CF!!+3y'	I(\g֘$hҶ1L'cfm6}lb{X+[_<AgpbA3e۟N_D"'QqH/(NG6eJ}` .W%o.3LÝ;<z@M9&!EQ!mT5%O<qX}I15b2x'	ǢJ/5^P]㲂a4>ͣ	@HHq`.>EWFII#VCiD2[cn}z];EخP"@1v7UI*iPXR@	Mb	NkQUn)]1fF2o `PK8<0O,o<xgC>p
_8ߟ+VCXF hMжnũۘ$'2fo0YZa*2#~6VP%1;ci.~υ?mT^Ul8GkW8ܻ{<HoC)%OC'6`$.oȸ,mPw"=yvBESe~i'7
ʑUC>@$BXG*fs_N뷯_d*3\c-,
쑚,Isn8zCO.jb*e|vPQ]_yʋTnEE}3JF#v4
%$%FU4.pz<8IJ,qZ	QSsUyHdA\ejFIu<0<z"DIWàc?Za;Q=}ۺ?|㍴7G2Rlv-ރll|!Z8^(ۄ)/Vy}0%O!"SVFl)!heF(؞,s@P,2;~ 39LۇOLzO ^Cl }a-kw]]PJ^'3301 /23<]EtN8?z 13ˈIPkLJ(X  @ IDATiru)Cܸ;-=f;Aj0u	8X:ݞqi˼?]q)\4b'F#7׹Eᘑ&Wp5P>T)56/~$}-+=YP01@r<̧7C
|Eu6ңGDu3Rto܍T60HAI\NSFQ*MS'}fúʋONR4h,ܮXfaÉyS\7ǑZdΝz7իUSqi1@u4c7eʅ֊b즟ys&<~b?:B8CmĎoڷNIʏkԳp6ε
ix znw5K{w2BW24Uqk5pbYhV{k*{ǗCĸI@
zqhNC:јt/m3 u#do:ϦU-yHQ5F#<b`@ljWqTDT}6ճ#|-80ah3-K&?A2C1OU]tJ2R\Dl!䘈!7RU_2Z\,_*BұjPIȫ^%אP$ [A	yzB9jjwdp]>Y~vIX\6W?Gx-c\t?¯ǿ+7Awx,ܮ&evil~fۅiQ0p+6CAF3l,ʫv*v˥|Z"HxBҢJ.IX=(7q6wP>{)|&p	b<j0WhX$"V),ekqFc8c9:roV#ThyuMZvuFg-]\aŧ,0])k	h9&Z}RR&G#(X\.g =Þbt_ͷS7Oa2pV'36^e.c۞<F:h0~EM(VnT}Grz\$?#:rDd5m-bMP\xl|=B/u4x/4Mܷ00&Ƣ h(_aY2x<<ͪ[U(gB;/%}R[%E9=,ը?u{ 
%兎*䒟iWmxL_«{dˇe<hj<cASn_W}QNOR;xB>s4 2 +-"8V"!eX=ųOvizU@/@@lm5CN|Q,nDvtc"^oͪQUxY~ͱhl֟-%"!T"-C-]hx`ewh+뗹Az:_~0!i7UgG[k׮D1&\
EUËa@/P~Ykl%cWt;tg
 ~iC}rzoރԔMk	SzYAjf#"c7q_¡Lz[3>g}m\>%Ra(!}*)T@nY^-â$%>g~n޸#/W%LKgRTCJ12{~E&5bv"bXu{Pe'U?-՜q{i<Iu$|</br;@y"iXǨʘMgn?0XQʚxT@t=<K|<hU{Hi.fʊHo0Tq"jQ.Dؿ<W]h\zLEi0	7Tto|EEVW9XTWWRl7i(5SHUjKիPpL'P`)mE}LZJJA=
p}9W xf\DÌ^]ÜamǿEy..ri{cKDƚ09F@h^ԎZyCފ)af醅o>iMq~SToQ{[
s77UퟛTַ.W?^\{:8,ǴFT~};cN(?$<_ClbQտ<wgctAoiEYl=tO@9PpΡfHA	b/fSPO-h=i,%T=z0F'd]<p=+ozmS+QUsX},E@1(%<$g)4є/:ԯ/e1kpMeׯl )xnvxsBJ<g5%TA+lB(+&s)GJ2%cT)e1pt]PsYP㘲R8)*rPm\tb o.$9p3MLhw#ܮ|$3KַnT;O,SPA{6V5%
3P1˚}'bFi&6P^h)6Ri3gvbrJ&janC(KhXHI$ϖ⍑MX?qkv5ĻmgIs`2PBB\#ׅ(8ܩYc=M]8r\

  3o$>Q-hkyx7{EwqaM@T3doW<#='?Y_#]kQ}PAZ7 # 
ZfpmDqvAG^|Ԭ[5#~ `g3cCxZ^4f4L0YIR#"k[5jϙ
;36rύNr8t%~{D}Z֕"1B% ;ҋR#!A
ghw*+zoS9-6jm7g߉!ȏA"K`,奶c3!+A˶9	]QF2tAV٧vwA	iNV[HlRwc<4CnfZ
L?J/QKsF7Px^D0H$B"*XȎW^C{9/1+Z<cDU}Auj:GD.usL3m$o6cbUGkz | R4(G'y Ґ0!rkM ]*Ah(}-{=E"D_A2	y?HzIWw`,dil9 s,>Ć4XLώ RƱ(2+j],.%(.k'& T<Ck|^?xoi#Y@x>3R0UDs*KgӂH@Hk4s7)kCe֬9y&sCmh&jv'/huC o_d%?`K`9H^ن j}fO|'?p__b$"6F95h{WyB5k
?nxfa7}"A2$[}A;9-a1/E&x!ۛ!}ӎ+w~{=fUUȭfYmtrKrs`v@~u\25ozs7ւVAYnYM: !*tPMTq-iwm o3{6=#SOک׼ʮ8dB( soj٬ѹ["gՕt]QQI> ހѵ.@20Y񛮄c9	j3~E4rEȟ,A.'W[Ul}+ՏąU񢽾еZ<.Ex<
%&˞3<Wܸж<.ۂb`\9Si܂AC}h ف8;orlIvL^P_ Y?1psqF4$G<aEC>뻇~}5q?vްQS#z?Lnn.&jyP4%6	$"+]{1iunD!`Pc×J~P+ŵ}M"kO1K%zڔOʹt=(37A*?үRr(J)ObL/f]yPe>>ֻ4:*2+%i0qpjH^:Np7JC'bX~o(
g|`4y3qT%w]{`_GhƊoTOuv9d9_̏(쫘Ƙ&UcթmՒ&p:ƞugg[sN(/Ϟ;#./!Z'~a[Dh)X
whi&v[gޓԒyv
^uQei;R5XJơ||EGW P:HͶ{.kyFg0XWlNF	p9<һ@>Q&6~=s,xNo3M(5e[`d޿QmfbR,i ^}8scZdƘ*+'2hC&iHO:Fy< gq=¿;Yv3:{%B*o ʯ>M(	ϜU|Ytt_l/נI.4VSX/.,Č0bWn8KRyD~<H5-;W-[zSKݾlU<[ kHpx^b	6E
-,'ܵ'1u?{
ѯC@8ҨE!HBעjY]پ
z@;</{\v{#P5b,tV @uu!I7DC0} vַN_[?/LE꟞Y&mtJ\ zx7iL\ <
϶dT~([ڃ]Tί!m}QS3G:c5M%\n<ۊ&	kW|CK1AJSiFƍ6٤(ҩ{QM`>ۗ=_d6}hnbI	IlLX=]
/JV- Qԓ_3ָ7ixk<1q}
N),4"nw2	JOŎJ>w(ihRX);2=5K/GQutQz2IN玘H&qʺU&4L}uGYnoVbs_& ͦ}yT\!<O'fp꺭OTR)p1GH#UZxYE5cODU#GZc#ҢgTD<^F+	&::uM~oX8@ k
z5{"WQǖ]c:E
K3. g&K8ZCrp\2J=`x)̏K]#*DX	0ō1RH}8@vbꞲ%0meQ#MK
M5k;c=⬿㲲\X+pYH*5~k 9ٓK$8zIMV|qԐjjOx0rפ0*LXlHjf7!h=025!>^gR<Rgi :zO@Ͼ.r; t[*OTp,!.]*%h`?0<_Etoh?DL:\cEoS|x6x˗ ЧG/)Z9<LB>I&%{n]~G7BU&@^	˘7*nQzǓ鍾}	$p9oV-Jcvy("I[]1M%}w_B1yU4 FU.3еcb Ib+IKTA qqȳՌ|A@\&1)H}@lNZUCj`9'
#ξoV:iqQ"~]yK623G{t@n)cցʾ8y({Na:4R.Zg@6dc4{fͷa:+0kp X[UbJv>&"@xy(C#!+
{ 	1;qZd2Gt[;U {;d)1>DQEؽ
Odr
5`Z7 [&rD{_zQ6uWIyT@Q꤈|b)9r=mug$)?!%]ӌU inVA2 &O@m#nS
j5EaHn͆7k(p:WyR&U#Ze6AQt#$_ﵽvɫQO#wu RhM?D7s'-p n<ڽPG){-ZH=6Fڦ0<&j9<5AO=[_FX5Z'.|iuؒj`gϢ- dFй)//;P6 IFn	`RWzn@{99Q~@^tr 4XzWׇw=_r $w	hɊRFVϟ8r19sA׀8TޱvF0$ĳ48 W,;
"=FղjMY242`УyԎ򥇦G3Px_H/A끨.#A*Dxy<}tw<Y9#ثĎ0<C㮍+M,_[)Q<P|?><Rf8<!9/հF1 E&~J#mJcrS6Ë_0N^iwK2qz({@e$9z)ol?%.eOX^Z`?k@`8~ Vn`+=yGW"xn1YtU5n^Uqg[ȿhݼs&$Ia$|%H]x`]bd};m99֥qPVSL!+ro>WL$40`jA[z\^Sc$
Tq05eJ^6	q}KXUbJkh|z'ګ߃a)7$2F21yO19h~2y!#w~&!Ɨbnjص.CWZ.4AꦒZyĠHvpԖ~iT`%z.fS?gA9abB6ŵ BޫPv6ܷb!!Eq#`]hф
1Ƅ>VczHR/GxibWftYc
y9&|kWdx7uG"Q1;ZYܨJmx`]
c8E;"nXy;*"<L?6.\hVGok29J]&PaQz%Oǈtͦf߄eC9=cĈ(
ʹ;|3o9t&0zfAL1P%,DR%$AnȄQt 99#<h?J:4;[ag<P	uR\H6y%RL M>V#R ®^6Io&csSs]PQqzG,;fU)rb>Pdė0Paow"Z1ѠRzymp;AJeYj@
ҷuSf"vuǍXXF(8#zZkҧ/Pv9>#P ,`6KEp,fGFtc%QZKY/H%B45Sr2|Au*O@|?m.ˮKM3:l\fx9x/ь]4ΏYzWgdY6>]ĻS<J-n@ tUG[ 20;ljg̡bSEى2@ŹmB[r]i<+uݭV*lpԀ򼎃[B<Ҟ`0uQ)F"ir+cP,z\O!C$wLxr Ǥ9#0=;RAω4+*G[(!0*+LpEnhQ)}9/G~9Ziv%51ÁB&*Z"Xo6ʩ-.n7XqXpiHÔ[yp b=ޓaxzѨF$oEKٶyME!GۢtM` 4@kTG\$S<x{n0s3Gw|*Օj)T GvV]Ez{5daӄ!CUT<zfT]XnYN%Tɴf6rBy0(i.R]ؾlL?cqP( "5ذ8G.bV.\,Ra9Ӿ3xRb`D]Sk^Y;0.|/UqKS",N |$ڨK榝[<%%%Z
aWNT-חMz-Z.iMV6QrVlJ;*heYmтU'mfSL{Bŉxk";!7Uf"o%i,:\ [^2WI {	#|Z!s>)鏯uhSٷ[Ί#)F	0u&y(3mBXl+8<I6E8Px;n<gIkؼG]v51aHɗX޷3CgD7Q(7ȵmƭ&떣"l٭N>xf#-|<ԁby]HAzE'ÙظhQO> 8SǼ4tĲbIWwDA]ӞꤣqA!Đ1\g6E%Bk=ɶʝN|Ch$(.d?-mή:+<*Hݘpb>߳K}B?j}<g6	F g5Oǀ)7Fp4|~~|5x9ڇSgF\Q7M{$4N{<j I*ׁNb8J^W5s@cmsX+SC7Zr?=$b(9BqQ AZ88cZFv5.K]y=E+ÌUU1732zd"9AΗT:C0tDAzG]8Bq(.4ͥ81~= .$]ZDΧ<Ǥe{nsH̥áTy&Q^]`*";jH%`-^IJTk qFON|bHu,~aЩ{(bmfJ0g^w[8ܴ1+d_:o*J	;hhޚ(<qLGמP|A;.+hvY?}'߿@;ͣd{NWe#
4w9:+W#B_sL)K=ghQuTj0\*@lΝ0iV620U6ʹV|Qwnh.Fs2ot
ka.zލ+uE.S~/sZ41aE?9f<ixg694{-Y#X#	VD^nl ?R`:@tbxI>`7s0ߜMP]1hV:T'u?"tq-g5,w/ixIibQenR8S1aLaԠ,ƇҥqXZ2moloEx`omPvaiWhW>0NP${~PcE.1<$_:TlD[K"	^}9xQ`L&2UԙوryhofMWLh+<}.\
w`VvsݼobR颼DUM-/1>BFneY#:5*݄(9Uv@+X|Eh޹yQET:&:DvX)&Х)jz_!a;AQ?'8DLN44ؓ$\ ڄZvWoZQ*ODh~Gd8.5 'mɿqI;FFCžn:IЁY.%#{+o~Č#]=,iWqx/BvbxǴ6v:4@<q>
v&	w79 gf4Bk3֢.Yϡրpǋ?n*@fY :dm$g K1} 1{Bۯfi(>
 xm]?׀)UiP>`!,FBK.YF-74[7WO5{Q9#NSŪsZRZj5>UfP1zqDi)|@Ќws1E!(>xHvE(H 3~9cX<j <-:8k4H>9ުä3n5RQHwekFHzL7˰Kv!F9h](dAHSAX~o㨢<̞KK 6ׄ
ۈ3UӔ}]ҬG!-r:BP@j*ka`PiOȾNԥ>cB1,5 ( "9Xu&9e "[,}㸂JQ1KFi'Pj.o<N8eʆ=a,/h\*k٢TO+WZ-1>d-k70퇼U}=Z)-w7^)??AR2Dd,{SQz6_=!y$w*	fDbA*C
1YpMr,=pIӽ/v4d'+mz2ȱS7\Y //[lj8AxuKF"]0c{Df,ɲ
ţ!;s%,={6YugkZ?ox#EE AmvnoC]&e3$M=!U{ҞXm2gXgV˃.Ӗ," rwo)OPŠ gF46l1~@4C}	.QK<K#!ЩGwfW_F3ށՀDE_Q{}\s9Fr{p
)} 1BNɧ(֖˫=Id]<kD-
Q<4q1͗-\Ȥm#9hЀoE_ÐWy1qF51FstGFHBOU'_K&k}%ؘ]#nwum~Nu-nv:%kc@m 4ULNPIP,{Ng`nM@(KxkryZW[V
-׷o'}KzXÒ8QJ&@1*Q%B<#^)= 'G^<󷁟!@ w*QPnb?L+G}8fA<c=xw.O'G㢺O\ZV\I7%"
mET>#Ek`it}ߠ,)~!3z[@@Pv[?)O]21UwttW& yP}aDr*J_BHb 0n@͠g@2N:cbm9%I10g	K7뜿8'J9G!*tS:"֧Y֔f>c"WC\ҝ O<`lkцmA k4|I31c<;6@:Co%R6uL-bz+x	OOMugX?b!nJ伐kL0<-Ck|ee.;k<4!+a
{ᵨ ]%Hڻ'C'p2/[4X3|RXG</LHwibW[0_iO\ỏQ7aS5lg})i]8z\
n.0Nbi:Nnpgɬ:XԘ\vhe#=u; )1Z4FZ	dC{DŒ`Ȃ^QPh`wN"L ?TpM1
.YqE'XYUV"QҞx4Tosf[歏W.*2	g{wGw4Ey7n)`8,̷1&׌m0%]l3C x5ix~fFy0Ѽ[`\:ti(Ό*r8&X} t-+yQ'x_8;^=r"BEE0"t,>\ݴ[o5QrOCMONr-azW9ϛvI[ݡPnˠ|]>t<ʽ'mStK*Fghp>;oz#i-/I|?tPE+bc΂y~^e"]sFɺ#A&y/~H|_A~f!%,EUn?T$Q6
Nb#1QR'Cn8%Um|CD}1hH6{¯,lƣ3Y(% >-iYI[:(m}=HEj!Iek*$
lƆ}ʢtr?x@~TbFxZvW
)z%t5_4qC'g&g`:y#wڊ@&Gaҡ7da7&0rY$z1ZQ'Bs-o_Ӭknn #YvjFmD/TǷ]Vxv}"Rٍd$^Ac_UP#<0n=i5iw_RN	ww7D-]vǸ~'2 v*jdEal	U<BEG:H_#E95A|]<$y%),nc%G|{H~qʋEjYeM.Y(i y9CPuFs>]}O ǛVﯣ6BO&g]+2&wFc&>|AH*gw~׈(/Ҩt~H
<u΂ͦ}oTiZ3tId%duu
EG"iy:4bzўֆr]ȪTŔ9HGRKRk?@Hb`\#9ޯVz5\&H%hlD{)8o*LZ3DϾ>`L0p\&C4B 9N5x)^#WrU`+*7ˏԅL1j>Ic2]0j+ͱz>BHȖf[hZPy7#6"֎3ִˑ-`MyG`;Qr5wQ(+gf</?bz 9 ќ̫M1Y~p\<Vq:@z6@b>jڼn<ñ?LgkIN-	"i(@4Tե;`4Rk*wkrm#MP遣oprF G{T`30$}+F籌L>G:!{}!qE7eDl1p&^)vBƌ{s֢hYIc}%Zwb;L**D=Zyt𢡄sѨOOnvJ+ȡi9.I?)z0{C$,s%E<J=G"8qM@G(ׄu
)ӞZc")'ާM͵}~1hWS},\`A[4L&gX9or@;%2/g!̄w<^ݫދ\O}řE3WI~Ohn%T='%RP+$2'ՍU_;c?{/ 6=Bg@]̂/yz3
4stQ匍
o ɏ[,"
}:&|&I8)!.,)z)u3w!:4sذC)&= ޗf1%oO"4!ካ!߇|'N$=`z\3?<Uf

	Q(|ô<퐅xdB!TrX)p[ƃu*o䙀J/zcwԅوz0.$}0'62n(p:{7GfW<Ԅ0CI@
$LHIK-5Ǉָۛ,<d<P.?TQa 0iaZ!zcB5aɤ=]nBj`zr16њ	Aٷ*Gu@kUB"矰̑yo	XL[#sF-!cC^;QI&0혈3hJQ{88v$nR`H)Yx*}k2+p=vwc?8	+Br ː@zZ>.vqYݝu᫽|W6U6a=v:$ʰclytxB8Obh913;BHg4 n	 }GTU0r6ȃWD0x؁/V%/G<qE  @ IDAT>3(Zrn@F<~:hVIfھ9ͬ5b Fi:Tmgʤ+);>|c'c8khKv[~湬"ߋ\?]-`;\O\	=.E>Y}Hl)%(''L2a^Mx3&RG.l{h(Cu`~3I9bnw𜣱~?ܶDIYZtN6{7 >a0*P
A')7{;q	#L{-f_nmF|a}>4y!*Fؽ{؄޷j1^"h)Qx-Sc;]'KW$6.'ƀ{"8y0ݒM~Cr#:rpv9NY*p*(*Hn^j5\0_~1/m]/bv7kFK7vhjN7 zPhSYe9q3E|haQ1?8iP>;j3:E''jNiZc>oB1ghzgByv:r/Nq"q|*~=Js<' 'D7t ڠ+ GzS<ϰmxy8nX5jfKR[/"mDmvҏv%/4!A}\ $Y?l!آjY9nnWCް1HDK"R4$`QRh:lO]䭧_eJJݸq؝I?C
"[T6QCG{P9xNq%#E1餸NQӯq_!EFW@qك#Z u~SPǂ4n$C1#nEc b4cEuX_Z)QdcҴ}QY6}MNC[?9&c<dI[##́{D%z[/%|KLTN`mg1qD,N܁	PQI6Epߚ3<KI
Ir'Gq<LI}6#5)%^p
"4 ?D)ԋpfm@zo#tde&H-V|6dnfz@ES~]$"Vstb4$aZWߦVWi40mA};aTJ"kxbE;Gf~ f&4~E@B:
G4{lR}bX+1(HY&DTa;득u}`|+q-=(0u{w{s3X=}ED	$ym<<и{rsn^P``<눚9O1C`iLw@,\yn۲{"P#E p| cJ>"RH<<5c+iox`ƍA_,b%P+2dX',+?.MWd]&fwo~&'ƿ0T6R?fX,L1{3­PȊ}$$1 ^쬬&eߟ(pt%fL22RseڙR䦦<Z`R\WE1I)EԀgF(" 5?';F9~Tdv<%v#9xZGt;(}=(;F&~ SO)ȼq10:XALWoFӸ~iBڱ1V@h+Aђ<8SvO]@<\G{Mĉq3(&BNr8ZBqJr\%iMq{g[%Ԇ/8P9:bSZRf	XZ)4=/P|{%EP-&xȴ+UvYZg+M[3vzĪgOH8v1|&yZUWoM/ቔOsϺ;v`@/Pٟ!=е[êݮ5ٶ$ z[Z/+(|-o/c{{%F~"nt:weJL,h !꽀e@)-n4pt7le4u."5
a-t=CrOng!_A)0tAPT2_=rKGyF+hl~Նerz%mg> c%7'g5w67H&kk4򅮫_yM{'kFqzW196KR)ZCCL-خ aLI Gi_8b ŁH]!N]ҿ!8AI)BjPHLO"JCouځȭgEx_};z5HrpNs8h;r '7ZoUPH}_O>[ 4c	*ۻif#|VhGw%@	_֙(n0
vO v7;űp:X̙I1håCK S.L7v!Z_%#9C]n>CsFUwkqz%Y=cb7;XWHD'˂*u@yE=wz",y!o=&O]BIFBXH7:̯PhTRO̼ш<~gӉ	X=3%s%k6 u<"s{)f4:\qiL6ڻ*4ob&IckJOO7	(EїER3usƓrM&D?D=mrm$Ҹ )O)c6pfZcZ'B:;O?DH5blY??abM>^9a.kRlXVX
MrtD~w-SyH^bg,k63sTRn=I&?`j-Z5!A{BZ8׶޵_( ?h68^	^xZJ􍤺SN=2A3d,tE@:gbwmqkְL-YP<0⎇e;՘4sywFe7~?g2jSQ75p--QڊԦBm)'1:@|]l3z+ߓ![B)"!Co_.BBUP<(VSjjjRv[)XDvFk1V;Qp4!:!knѐ?%m|>$<	WE3HT]lO1 9|!WcD<@Sm4vZoO4<`ӿT6B~ѪryŪ&[gx~op,JFe|Ҫ]R{dy
e<bg~dHU>4nJ#sf]k?H;hEtC}"#KmBx<مi+ںv=EN9q>GZĽFIff`z\/هBʥƵ'&!9%wm!t;7e <Ӏ2#DjٛZ[С5jɡ<c&GyZV園_o%R<T4] Vyz6F fQC=
c]9=cڟȻf}7=g]rހF_<fq"I=प}R^
 EƮ'XcݨEeA-m{-gD/ޏrggn9s}чq3(ڧmq(^U4]Zc/ƀj~6w_'E 	&>6!a{}NTS'>f0#n(?1rEL*L03Wc{<|?dFK*NFoVu~Rm;efFbQ2_p3nڋ1 I.na ā:Qg(MHuL(%+_`&,En<k"~x'd~ Z<jQEmJ=c]gt5s{X39G_8V
(OBLD?tz}ucձs#Vx5Q"|.	X:̭G\Ă6hL쑺[K2GS? C7N8N^_r=xm@(GyGM:Rm7 0s>^.DߦZr}Fhs(B8 r<}Ֆ<cV89/݌ںN2>
X؄TߺںAu^9J͵ڳQ3ƪ_~ќ'-b~ pJ|^`5$~oy*F/:j.7˯FẂc{93nș;(.(/IR̳Yq=rƌ~j0C
4?0),~`.Hʹ(Wx4^hn^7!Yn#dw#:Y{^?`g'G m/M'#ܿmGw -67J{**=CT|]>19zȆaXVcu6ɣȵkiy!pKOO)mRk^ÓCbYZϝ  |d8T,ff ?K!S:6A۬__wHdO42}I}KQ8ӰxeW{s{mۦzZ;1?UT>_yL{TH?~ޯ^"(&vFA&/
k趓륅, *7yh߇%#C>}\(%I#}DS^Ήh5{;bo)
l*f1ԱN7^؉@yɰܬf4B$]Ct]YŅ)RhQxִ1G8#R+YyW:L)B	bǅ$Tt]_d=߭EoaZ@@hna/G 
-N3ϰ
:UكL,JoyU=;ý9=A1m1.v8]uoEޭpQ/"XdLTwk# %ۢ吜MdKG֠FtC]QB>FZgi,l/̴쌏;B)l ڰ羐Fܹ~PnnZ%db
j,A q},aXi<#6]h/q=VJ2U3DZh$ [FMr̀7 W/Q/x0ݾcڊ+Ϟޥcn?zLnFԙFRڵ^90G)hn&V\:g,W,ھ΢ڲncL~?zTUW'ٽSFk{#Y~֔wz=cdA Ukj-h3&o:Qƅ;-X+H0vU%W&汞iM 6&C㌠bF&ȫwN"4/gyxߑ=oZ>?Ϲtf! FƓUdmoMSDGa>"~!p'!Y!*L<rt;ddl'}fv
jϜ9Dt&\d:0kX`fٿjӷ \64tVRe9`Uc<800W	nۍTQۤEıh6qȓ6Jlj	/0+}TItv1$n✣4dTm%M!UDm>Ư7sLQj;~|S,xN8v7|pKc	juȪs
o^yTȶVSea7g9ĖF YwAuk?;[FzdKn8@`ӟ"4V@(tׂ>Va0j|Xh*5^&4׽(Du14(VIҙvJCTUpTD[EQ,cfrb1oJD'¾^zIvի-ل٠t7==R;,!iݶA5]J,*G;d]I~BS Zt,ul}^(9N$ \j*Ǻ 401iQ0"DlGgIoa fT"(|3͏~,ACϢ߆ fY9HڣHd#:`!}h_WOgX텂qSO!Q&Ih4oA)#zxO"3bz\9,+@2'+(f>dmMMϞޚ-ܣƦ@{2,mӚpYGkX5h^XӚYCmoME|%0muKU#'D]!d珱*+/3a!đH"AoԁՇJ~+JN(utI+ .^z&b́kqN$҆SAOpq$A0vЩ+Ѵ}ӑJ|;݊[Q
W2a؉'HmO(	CHO^yŋ6[+outCGzH]Gvcf|״hbb okn&:LEfD?<?z2JDqL&ٵ!LS!VkJɑp;qDF	mmPκuYۺ'GjEd@|4`kSܼ	x_}1.׹8JpZemM"heiF0MK*x	RTmfKǷJ@5
ߩTre怶I*Ww	_
1Ђy3Þ*Ia!А55):=d)^ԣ*XRUnНHu  7v}&N>^UEr>~"V1TH%iOY{5ʛ_ll v!-9B[\MB_39Q9&{]tz=1Ükn4ivk$fdICh4M*>J݁˲^`7@1a
0JQoZ;P0BNW#g""92gb~;tzO1m@TۈRߺ#,"1[ąȂhe\d˲vV63ǾR~C>gX2>~y$޵?Q̯}FJN}R",gNXn3`˹:_ь<Y0~0yS'g\L>!Dƈ
O4ۗRXA^*Ji0B VHL_zuX W 	Ri`1bO/!NEi4lhfzD.-({Ԯw@@T[	oDo/@ɂFҷt66GV]MWGC9kSshD$+~-=]?[~:p]a֤,[#o	oG2C :mߓ{aVGQ2!Y5.2Y$Tԭ^piz%G)IIZZBf$EUy);hf.
6=!ɘ @yo"	J)ē+"˂'M!̎SckIꤥ,`F
,m?62^=a#=1Z;Y~*8!-K+u0QƱeD*) _[99H n>%\h+>x;V@>L:Gӟ9fJ[Jh822;\b=?;EG@Hhړ.A?},gMTk;w'7l)pJAS@,`䕸Qzmoeg%Sg L-P} ͧ'|h2T.Д|P.?>__Ua%0T59Lyt+<(ؚw"Ԕ9EY6i{Af@IJ.w=o"HW6u{ c,2ԶH!3pޕ7a¼;'Cy9^/N /s45SKr_/H;U;Iɷ&j$PɆKxd4;(CS?ѡӵ}2!I2☻Qml"ԅ3"Ћ0P`9\l)tɢr`(KkEs<{dm2]~n@]a6B]fGMU]|IWV(ZNexo߼oMc{d=0nuP{u10/(ƑID&Nd{9SÓ @2ZjLl=ͫ`Tj%(1eA:]sdh#5^o#m^Tl6Y'16/ Z׭l!s1Ǐ	l^~Nk^R#^FޑN]GU};eZ/1+g؏5Cf)'lm
)=39e *fGդOTN,XDq(>vcTo8QgAƔ(?\uAep~4.ʮǱ
`>lrTlK"~#Hq(5		Iw4S xqٿ_,|_nfCaINg]Ӳu(gk[BgY6@ɐ&oF)r0`n{j4A@ Ԇ+5
x^	rdhźUX)RMNlH{(J};-HoKGMT@/MsI8m:sQNȍ:l),>6x݆야eeh~T[Z}ZA؃eY6-eyie^
Ҫ1: m3,,hvʤ:4O(=m<;TPZu`q-<QEm@bx.Ccu0|Duu{}m@8!iVE.;8'.	APtC@$F_pQ}	}bݣbQv2zl{;IHzE1lƶm*B=epRB/Ñ=zjEfH
(R%8`
EFG?o;(ΰ;;tO:"Mg{ZO ۝Y,:U:!ܶm0HѼϬ]Yaw}&ߣ00iXSZ&Hynyw &$~<zj>ङB@edd3	GO^>ܪJ¡*ECPx[Cc&/ ˄\+aFDçp*UD$gO^V1"3&R0z28Cp#0k>&QfѼ|'<kIkВfWbPƊ2>1jlB㾭O;͠tE )~-|k )}Q.[FfdB!eF2qKq߻oW||z8A𒤋0:\&ő,X)()`1-m5({n\/:40}`9䂤=an
|%xɵ3}7+
']Kb#$6³;x3x212_,)G~R\XL/rT0ӳeZMQ7|l'Qq= a۽J|޿?1	B[۸ϋFhϕN?uA&ڳu6Os;Zk(e9n
Ђ%?̓$Ly(-[)y23[rИ~O2 m+5x/y'1c8-:5Fh @M' px9蝲{38TL8x{FV\lurL]ַO0ftפ6A+|^ލXݺ6L>[\+zX}dhO
<3	MSތŒQ3PM~ߦ`)䜃E>1c'I (lWN_Oqy]<\C	߻hN2Kegr<Y< 0B<ѵ k;_tBϰӢC2boP7sQ,6ZXX?M(VL(N7lѸNAs5 !6Rf.>Ж`/Vڋᯄu`]U>Ɋj5qQv0k1nk,; eƀowa mebp$"JٌrOtR}#^&v//_QcHolVD6xdFI̗DO֎t\`Jp8TTSrXMVhp3u"$Ҟhe*\3VJ!9ݱzJ(AY??'jgPzH2ISXeT鶌OqSG$Oΐ,}|@3()	NZc/<:ysjJV%
ZkT0S641km_Rrf!pnn%⴪Sw kY}J.ki|##3^ۭQF[Xb|LOfedw~sR~q2]&¥
nM{P( Q),kz(r=[MTNsP%9Wj]v1HB휬>mXl,)ZVbz
Ǳ=iNMCa
,WRӊCbb6ƃSw[o9!an ,3P-yF:dʁ>=՛,Ub<ٮNhT'UqēJ<ǞJng[ss{57E8K\3~IV9Rv<C7m6+yN{X)WZG} %:oh;I Hlmo7Gi)#@X{Tu[a"Z8,f]q^{9)1]{2a/[ |Ǘ=)'e1VjjlB=~2|Fe\;mݡSNC cYW8}1.A?zꃹ.VmmSDEEM3?9I!:igjq*xQ=#&ƭ_:
]/hZ@xIinwv]yk@B<dU:*7KRRFRvh,6+;T?<X9OОU'd3hGpG IX/13T@:J`%&s>f.Ouk`p1B70\ч6Ҟ-u"}^~1Ec!ՐQ;8Pr1R\)v$@rh )Lyh8EZ
^DH)$YtLYmqd^),Tɦё:]~fWؒ/y!5f"DH3Lnhg}
=n'v8;|x%5ˢ fO74nH-܌*ΟU vN@?ʀ^SpaB|@OaH; -EޑhC	=mhɋ"XCXEXR):ASxDhda:N?	s@<ޱ`	'`H],(1&Q%fCF,-`Pz	xtn[s<>?p!&Li0J]půwZ`jOnnUqAϬ݄@&+o*9.7|9g{`8j<j&"<ӂ{ S@8GH]7cmn.Ց%ٛ,=0euK+~o i[Ee >V ɉ%IAL-HJ[AW8dDhm|	#gGfy[;uwb6tS2tc4ؿ0~'c9"}.|5ӢOA@3aP<
U0[W=Oc6&ą8*A^^.[x+@ޮj-փ:Ov{sBB"(ka{M.4&Yuqy4Y܋R	Ȍz'] gMdNgؤ
~MC2*۹GIXzB˔au_lq[I[hǼe9$Ǣ''foTl98><궋0^Ҋ1x7\..8	ZA4T`X#e[H.xw*(#G,2CB)7AO稊Z+)AJ~{kDD\4nDP0qb:,	'PJhE&>/cYI=.-OAQ'5+a	?b3LnLY
d4jCTKaFY˸k[{;.-OG'D࡚uEqWΫgJ8SEv3iḰ<KVNW?\6щpL?!7	+#L {SW.)UD8{#:	#Vƥ+p.3И@maKPBg^dm Y](oCeZ_;2+@)f9&-}IL BCP]Tm d lPxF0:-"l7f*wh|B`;;`$HEƍszkjjed4xssIJ 6]ajzmjc
ˇ +ูy{'i.З#ڟ{_nK׺e%/>alkdehऍ,f B\Dkz|UU(1B>9{v][4;"S˨>|a8v"Gm@RuOGNiTv.i'AR9Q[nA.T
NoT5ȲIC\]9Ճ#cy=uMPKBZhYP-k+$ @[lЄp_ulOA<el>,Dэ?+Ҡ́0g9j$
2kzRTtGl`a0Զ׷$	\["F昬jC)EȖNq#^"tƋgBv FP *Sw!#ꔒ!&(kЏ(&Ă.x_a&*{	7x*<W>#?fw'W2F!E
i:ۦHLюN)qk^gDW	E'`_u1->ʀA?
~s3+'1/ߋbR8aÏbqI?YY}_F_D7B8~X:A$0gq{9~`+ O@=
Hwq 5ځ3<W<!%,G OSGMug`@JMvлctYZjŪIsu~Z3ɴ;ƮâWdhkͮ#|QݵnֵXЎ@	m3kHn$1fXq4ҿt0Ul ZE]5A^'9ߕFڴnASO%0~VڴO ٲDc&6!?.C?"ꞙ[Jmjg2UBDq%{MKCٌ@ib&CtEwqb`bZS#>	f/35m!r!P|R?x^ٙx1O?,$Tfmu`s4EM{{L\j/×hףXCqhhjڝ5zƵuw*/Dljy;ARyC"oNϳeo;Vgi1f
cM6ǓEW6e}[eJtv$4Oج dSOfMk@V%0
O?Z]w8 ?a5v#=A",ԫ
-m4o0L&K&4E'勂^yM=Ugsf	tfA+5i';)k> ~wӽ2tᄁaMS 8S{NŠCLߌ.5fL{շMB+0NMfV0Z*c ]@Qa5ݶפVbvg˖QQ!#&~#KtdN֑JNiOʔR+PI`A>`D.j9Ś/I.+()&yw2|t1TCbDdj{E.++&!Pfz	ڿPaa65A#
S\'!	wuek6!XR 4QhLh\IN8`{gƳh:|G`SϘ-v{B[[JB`cY
UQ\6>6  
yB\
Q\fMqx$Rde*J}
Z/?/SS-"}LV'[:j#|'rz}܉É`7$'P6$Fc }?QhrX&c-~Yl1CP닆_ :_o	qy8yo,\"gUxz))`LXHAd|'Q-vպm=Ѷο"l8A#$h9gWDLDE97Ce3śv#tw7aSC äe-Yeu'wՁ!T_QdaX-(<$j0(Fe= 0 Zh!UHZ,2MzXx̬n'`l쵲f'W"&u_˶{BUg c6P񒮤WAo^`´Ƞ#̾IMt	802[APyUʬxy"j?˕b؅A_SƷ0L  @ IDATv|nCS	UTd5u	0rC{ϖP~K֘	 j]FR<=)#6	FhV4u-տAf@:8<L0膽8-
EOv92;kV`E?oo_jx;a7DzYu[rE:(+RT|W-vSqNĎTN8[^k}37F[^ػz:$Τr1	Z?&n;.C0AW@䓢	\1G&n8'j,[0uΆd(%P$f<Qjy-V}KAS*!>0d Oդ/JKa)g~c&xp#F珲W=&Ȃ^uS$T⨣mEewu!x! LaY~/,t 5kА6A)0TN}N;I7ä΅rzhIkc-D	  ``( W
+M	[a>=(͵8g!˺Ϻee&ˏK%u{iyqav:5q_,O1hƘCI&m)Uv]YSqܵ0S	WmYQ.0K(Ԃ9tWgE0ކ"/[ۓ$zɵ7JdFSVF0:QQըfCJcgz÷
-%ZfڿK%IiNoUʡEɁIrL೽(SY*{E_VMŮsqHW#T>8Vݮm"%\lAG6ynV8t}K`
|EVb!*٤sq? Ցqi}bYpReִxO Ì	K[BϘ̙P~`4f:PtIȢ}H74ֆuɹfݻyb<Ngor! uB^6rpe".?LD?Q7K9[~aY7_m$}u>Ɣ)pʥcWK1DD>Ea@2yT ܎Uszڗc{B}FW@{g;$M`, _&nXuDu;{Qj4O=셺QOoϵ!prN?%&틪=U7160?8XN0^GmrHyRpXl8!2U$w\kEC9A*eH[Bp$+/1gkLdeyvv"V0%=А+MBT	dq(]>sBap}/uuYrƜ7G6̅%qC{Z&SUۼM}yZVV*SCxY:`D,큅eT|Ҝmssmu6I#{bYW	}!i{ՙl{IPa) }%;;PBI7.d5;7aźB%qmqGLm	ҭtc<
\;'*='qyU:[QT1٠ߛB%Ɨkٱ gՙX`Ϸ`k73p@| ȨhH"hͽKr|7,VX/4u7Op݋\H,Рn#_^uad$VDx <mߛ
G4AJe-y,K=E:.s[mB|OkXݒ/qTa YdDHϟ3z 3c;YP9OAY `ɢUD4ҮO|*z#/r'#d=t,j}FN/##i;aZ򙴓{?tSl05,,oVXsM,W2%B.I<Ʊ6˔/Ր}BЫ?@-~[@ HQ A=@	ALWO.ܙ/xK
m&37YCGɜ#'qlB"9Pw0{ep g?2qwN&kM7B+~2PƉ'1OV a0xs32Bk|#ӦUEE
u{Is%FKGp?$=Q2OZ'< 82*v |@>S3zۻTF}`[*8#TcA1;r\48LBţ#vEPX$IH#8=v xz4x8Ĕ;PUYP4ziOi	͕$"6ţ0QG]`ܸ7:-{9)9c/>r
YRN-^3I>#5gSE6
MZ'x*K[`B=5pi84z۵X`y"4_G~9#@ea>d;sM*(8jkJhFa]gt߶zi~Yo'|WEd&t"h3ïF4~d>b
{ P89^YSA?FEBн!v3v*SEYc~o7=EA,gt16j,cUnEA^UyGVD]2-hE|p13bTiɱoamv}6g@J)	*Q&N:}(ބ94!PTKp;ڰ1#[ko)UVfߪls^?2Y>EuvJSOh%cO]ss.hzYM@vbJ xF2`H?fMut]L8!9ZDa\^Z\t^oSmdLPs&viݏM|>0s,倿5nkk&c}/z8Q]8hndlq;q^b_?3j"6~EWdSv^Vuh]'*r%N'#L`tl(;8Pu{khAH.~,.H
!->B%T({qj6<S6$n
Dzs o4zaM%#}p䋑,q^| TaAySD\z\C&EBeybјnwCjC]%7mh:C q Žj3iiCW&:)ZogaRZk7ꐆ>c؈dp)as>,Z
mVd$ypI,+6SXaA0heg/ᶁƑ~:#m`dD*JTf0s@۶m-SQ}Dc7,[aZqѡF՝nMVıdJ|&wy&#`}92źu*RY
kPu[jCʏ o!'ϥ+){{E|yCV#:W= L5%% Ǔ^!2ׂGcv3߄?:7ŉOvYg8"1o; ~4ΫzŌn-?-|JXauT2[v񗫼w37[J&D
@E #I+֪pw	wҷtCw^s(?近>A.S<;O&H{}I6(aN32&'iO hg |3_ >7)SI$ͼoP3+m87 ̹ žtYwCGvh#{&Qg	.wcLD჆mE67fGmG1 Ex-X?0l=oaH?CA?EAtSPF޷nT	??tLGMAg,33{6ך_d!Ruu	UT3S& e+ˋVPz󶴇']rhR;>)I҄JN-+A|1,S7Z(2o=@$ڗ6nPjC[#]`ۥX0[E*:x\%'N@`rHvST5ֈlצKRcI\b%qoXMFBaKKmkn 4UE+P~(a'w1K:<DvT"Ssc,,zp۶989PZwaP<{_űՓ]y0نZ.a	[Aa2c$Aý	;4TuY2rY%`
3OIJT`uٳVh|~A`p6,z{|	ۃ=~l'˗gK9&ordy'q/ySȔu>)	NZ/,&?P+i5J
0CϸR[hZqE@wS6,Ή:8?nRɅhZ-e1S@gtdy*KEIs]/ϽGة`,AA	_D+Cx)]= ,eNAbJB"K]("H,u%f@Yk3x.Ol"?p3PQ5C0[ T(.0?& ՔY,G wH" K{`44'NjzG7\2Kk'5Ґn_ X V","]G:ep*X}Ɲ4MlbP) 7Ji \oy)7\{ۙN:w-iXXݖ[F\0.EVprivW;DC
kImo+?ۮZMǼaRlI*}AP˺ؿM룀?էX-+#Xk@T٦:2=lEX'yz:A+*ΑSVYaPgpvk~Jwfyݱ7+m`/4E*CgiQ*1[!<<DY6o5x&Ui*y&t:$ҟԶ9ݬN=="C@(v}tPw5 BSP~}u邳&xnKvas~p\n?vsb:S\d:Z&P/#%N<#32iIW9#eb@!~U9x~TSpۓ0qjB9wko`f"?S
Qd"뽈T !e|ScA0@S!%rGsx,<#5!cxڟm{!g(B]#`$ ~'-V2\bHۺo-܁n2V	Dsj-)huݟD` V,Q>0?}NrU˞|U.)	o>8ԉ" TNm[\6ۚ+=OPⶕ;H Ӓw}ZWMS]QM9F'?i>-#]3L,e=e_?^؉'{cG"$EjyVv>AיhYęSf̯o&" @2Teʳ5j3,Rǈ\hʉ`0US3?2 ]"8nnyt2"x)<HP%MSj/|TLuX~ yOƪKCOo!A_1e46պI'ׯŤ-D}c(wQ^24樿 -p.:x%[#D%u4&Oٌ̭5G绦QK]SADQfNNW8/D,\oVfb-xĐ$#UwO$nWG^r2kH"oB|7[tmY(Ho 6!FgjFݸH[좾U}`0
P?E4⒒-dmhac[7w[lNRFG
,+|8~XߺSVq%?Cd)=W``Ɲ82C&%Pn\l{nw,|IBPh+ȱ	{׻M2ؾt})8<>XD˹o`#1Ixh^fu/&Y\VnrdiUK"!-h>N<o뻺14aɒ%&>s!-yf2/qIT3J~xdN3CgV̛CQ"`u~8-pvBDgKku鲞Vǂ9OW&&v-QF74qYa"G%)6&pƿ@4YDTȸi|핝Jxr#H8Quo,qL6Z
^(yyA*qeH6RÙHlgiiJ΄TM͏Oy'-AQѣKHq?0!27'hs{]X9%vA|YwE`%Lw2ڊ6mj\0}NnsA~#B8SlG&o=\솆X(uj@ʻsϼibGgfl=Zh6wn"j0P(A&3s'vIIDϞ=dj_Eg1E8%NFo^jgӏ52N&Ra"̀Pܕ6~'$]X~LmXKI,wt+JJO!1%q=Hs%DZdRU3Or$D9Q:ˉᑊŞr44a~ZdkTU?>6 >w_J4̗L7Vqi*ṋ@~l3@=%:mN
{I0hCKYLVhجxp*⨌`lCPBqĵ'2׹}o	#Oϒj4aHO!@9th-AFncZO;YΜwu5[1ީfP|yLSnJ]4/p*EODcKA@A8/IXi;,ϽSk݁{׸M'-ߵ"4g׷G} h]ǀ7&R#榯9W|k>Ψ.(4`;[Su5{94m
Wr2o0ofc;|IKmOoA⢫?V!fUR}
~T2ɑw߿Hr솵*0I~c]a/;߇5UwtJȠ(m.[U|;1_U5KAyGiĢQ2~vYW8*i'*1*BE=Y]ᘮc``Q/!/!v$)p+siB0{	> .K5Q "bc9};qChckNC vhi.ǕhQ9jeC{q(}V'{lͰX~$͚q]7D0m\R9`5>&z6l&~ߤ̤7펲Z_h0^ 
[s#3=d1gike~hIN	ŉ/}!/(h
mɂ{g&B о6 Iϴ~4FPV[0ܵeL3k Rr{u(YHj-^R4
Qhtb#"/z\1f̘KXnn"uXwߓBJkkl lczkyu6=ȋɀB$[qzȽ4x[Y^dhdG͘SKlqPvRCSt7^4r$8rc{$k[K,~N!<'0c |ܽ-Zgvȳ{qp,4]&)۵Җ 0ҥ鐴ZdDQHJ{fw\,p+ʢZk>Skv{'%oz];:F]R 勎&N(̪xqUC; >23>Pu揌m
 kdϺɨq%60bh;@^WVV\P}F	(,ͱ>1821a{!b/4S.?MϤ'$BҤ!(`bA׾{A#v]EDRׄH/L2}n`bvq&3o޻{=;|G7N) >G5h+AP>`ϠJ :,0_w8KD
.S4f8$&diPZӂ&46i=xZ{\	hk#Cfg[%Mq#\ЏAGᠼt/ nwes,"ÞĊ%~<l>a``=g<T6M2:a5+??yk6K*'9ʺ0_ Y8-/CP_`3vՌ{h˖{N܂*P(DCB[|L	E?BҀ7ۼ.	edBU)%pF7NnѨa>jQhwLaƌ MkA%6
 !	#yOKStY,G@wmIf~YNhS:-2A՝5WDRPxJ#'sB-&wTQ᭞SZgWS&毧p]`
N1ܣ=K$;ĉNV9+, >8ě6NRQd.PEu+(KBN0O7Ŋ! Ϙ1>5s0@8h2އyi%/#^tB:!AkRa0&ࣝ*(޵>*(poN٩5b3I2C{81QcM  `Hp.jӐX /<<xau54'+Cmn DlqnH|=YI\PĠ,;e؇,&y0F"Q)8.Qh&`(BA(΅꫗PMcCxBzhGG3u"rxS]6UjOs6{Xm9p>kLsHIR{>>75j `kaɅQt-I`CwǏo;tiM.c%nĸƑ0"!vQi
>AY՟i
+ c]7F; 3rTޙ I\dPXGXvpgwG0QCԣW>/	y_2fD7.xZeUCTկQ\f], e-2$mHEÚ2	~9,#-KW|L3w8aRMmv`C'1"fnaQ3Zw!Io'nWS܅@2-RU;7N;DLİނ`sXhhe-gaO^.dJ\~T0k2/+=ܦ`߂dM@'m%t{5 q~DxChx{p0JKb?Qm{+ǀF{ (ٌ"ezc[
5U}NI8̉.9zIcc:$w6ՅѬ+k6+ TO&E+JaӮ#;}yBg&upG(i32p=sG_$kSP4	sSul[mm3HAsaNHRV_RrL <!I9gNKka|qu\fjƤOd,PZGcOm-|O! fr2d@U^zGqQZIEwOO#ˏ tV$e0VGĢV߈E
e3EhS7[~B*Kkx
!.0$RpPSYUDkD%G;brm܌V4^82z[_VtyuBǆ`FMidl@2vi _)#J6.ySVv{}xE[Cg opXՑf$&=Yd@,He^]aWe5fv>7-K89өxΘQCY_݇Q;݄/ץ(&"$ݱ"3=);T'=LMirȒ&%Uf<a%E{`}	2yD?Ƃh\}Ph`r!>:@Dw*t(&rzǛc7F8Wu;r!c7}gY]5͋fl+,q {esM#SPr6vWl'c};c1&|ӡ``i*Xm.qGDL~b_ۍtpARe zW]IDݗaAy2Q"n<WiTp#e.;?iđ#-מ,=i?0Lhtk;2&E#?;g&Aӳ!"Xm}ժ{ p	>JEHGB>}aD򛵨qƱ:͌Fsym3_znq2r
ȖB<{7<u
U!UovR:ԻAT2
euXK˷y#sK_2Uc@G"Ezo;	X4hwhjq ]Q%O4AD0n]63&.5;trYؿVz&Cz$.!!5b~SHgrpoppT2V.Jym&偳ڰw`Iv])$JU9;Z=cLw}~<5ʨ542gc?һ7=HF'<e]mkZa2f?;X4B~<hby7q;}.YYC>"t'(O`S.zD傻aAuiIa܅R]X،Uڥ"?蠾}z].YN8]p=gCAΞE0Gxb!UMO%8^e~=]. (oz;I8Cꪲ%6>XYpmXvC?p#`c]n4hkR3=}<G-G06.Ui@VV|?ғYq,#̋NJ9#\OR7YY\`qR9|c6w-igБ:"rO+@0-K||a
/ Q$)8.WR=GKyx+WpC،iD'88^F|e3Kv랧fM̀.r,w9*<=Zֺs4+q.;tN_:Hr]`lO,K_C>6vo8JydnR !YY)P䳋aա4yn8,"fPl:47X\".-VK:<8n</26|.v[0my)}!Bi޼ w&ԵSYԚ:_11|c4;55S}@>?B+e	XIU[xh´t;
0pQkeE&8ܷD@ᕙkPYQY^~
4(D"W`*D+A,.ItL
4#`<YG"0	fLg1@Yxo#`]\dEEѿ;hw@Z̜XCdZqZ^4Ne$,c=ѱS>y/E*4l^zQX`7vcQ)#	!䕄軸d'ttFKi|-8̻tU{7KN`o-7rFuŘZ:ߑΜ:|5G~zQL'.U7As<(L̔_FYpBM)0{ŗB[?_Yq|rΓXA
]Ȑބ8zZ0a*ްtųB3-t8??P{LG/,grF34Ϯ=,>1V8*y.kҗCcEy9VlFƂ6FH<tS9>"s3˾aP!f]<_=eʔ2{5ws%ͳ#u%Ͷ-Nvȳ'Y®h|gê&0ٲqҦ/Ej4CMzϋXGЉ{|fS'hh!C_9 }a~kʳD..k")ksDOH=6ٝS#ݱC`Dc%Syi۱W$1,<FD}o6S3Pi]ݧNN3&d=(TՠUՆHu#U\L3k!P>^l)Fݕ)R/Xw6mC#;=fjkL;az0i'ߏמ'ِHf-PS?sݰЏh	.fY?#6be<ԺfDtwR,߱H#=S3FM2E/BzuX wtU\7Lnm~Jsٓ4#x7eZx'E3l1U a*W-p_bT%i9'K{`ckC$"tCn(A6S+aƲP.fWº/0!C[0%ll=/@j>jDo6.u旙,<QEO2RrNkֺ>;풾G<KvghL$lwCڶb/Spm^<T֚y:',|Zg%[SܶƣDgPq'}7GLt1bzǑayC,"sb	
Uh3$l
ׂ=cnzr(XIJ3P[tsB!^-$ycf</g!
Q(ljH:2GP͗h̴ǖQV(#-:#FKx9'YdmS?X,I!1P]9,\ʊP>ZL௼Yj #[NE_cgPݷX7uCfg^p|wʒ9S!`͊J?BPt֠4ͳ;yj/2g~8!i=qOti;r_66nlqC>NCѹŨ{H2arrfaZ_尥VD:W"$?pM偼[È/!o2FD=YH:鏶4"#y[iHHu)x(`s&ߘˣ/P(o^%΂QN-yQcew1iV//yf[pL}sE0{p,;F9]?lLcY /)4L)N ı
UR0oiƾ^D6 tQN|0(k>UPcH^w65c(Q>gX&6kF$8qB?wJ}}`L/-D{mOUՠ^D${^OKxAev<RK[wFȵi07à|%z{mcuOX{2"\Cvb>KeiRBb05h#sN{3w~
lD`ўL17FrH&4s=MXb{&--"35kǬǹ#zydϘaZ9vL蝆>j/IP̡OB@Z}$P{ސhɟ6"^lqrzSE}؋ce/|'4f3p/v '@@:inG_s!w6u.ǚ>
*lk;p]aot_/AhM[Ln[LZT0V1XY3vGka$::kH~뇗.(j 8V0ټ>Qe?V@grIH-oRDNlFݒJL.9*\M0%M=>&1g;Fs<\᫇	hڅJ|$E;^|0 6W5֬i[l*H_+Os|Q!o0h)l-(6Q'1GV@w8flhr.6P2ONxR_Hym#求}gxL~J9Z#;A[c*Rc;Lpp2)KRR r2򩼠OZ8$*MD菪&+XeI<`;>oY2'+q={R<(i\4]5Ydqˤ΁Lw
=SoOF }Ku{	vN".B6nW5Qj"R$UT\#JܷWҮM&CdhH`\lT$56ƱIp/R̋e5djr~J*X#v/bgQw3H6Ӑ*"Nk\rٲJ+Ou4i6uߗ?! H";j!)
ʥKaݺY$:/hl"Ƚvƞ+)&ӯ6o2YgneaVoӮ`УQY=+%i吵RƓ
HdQ7l!&4sRцխ]b~w	,'(\,ES[,Oc'z  @ IDATVW$ZVlT0M;L{!<f@C8	VTWCݳ<7%x%^K`eakt0{p&0T v=P0<&Jr hA(Pm%l|&R=YiK1e*	M!Ssy)o+߷hDCM2l)Y`u,<I;@{`^Np̽pf>FW>F*2Ġ&@np>@.@#%E*KJׯq1I*@a*Ջۺs-vI0lqdYغh4|Y(WǇt$}jĀ!j &3۹W	1vR8Yu{[
Y#2bT1C4cdrE { hH}o?gT"HJ;W^~kV]\p7#7US/}A_T
]d}#jsG߼|R@WqaI;A9`f0.@i	>I5[O8^ϴrK,SeUxzo:7caa7ьEJ S΁ ҴkBYX
<9/P0\ nTwŸp{\p/( %[!`wt~ǂT%U}w2s;h_BӢڻM$2`SYC&?x.J<p$ڀX]_ "iPsѸwu9}6^~IIhW${wL FۖvW)/Bs-^6kԃQA<v[;^FVCjC$>`EE}Yz͇lfjNy-WIQKMmۏ=MaP<U[ŢJM
m}R% ,T$}TK)5L_
3V`Dݦ&od;[ݝy8f6Qqp{2ο'HaՙEqAGe}4\Oq-(|Wj|!_Pw.kjb6#ͧ5|jZ3rpRQM3%(fZqHڅjvݟȆQ?;>޹FIOLDephnoKE9܇]NNVazV s4Aћ#rpW!zO<mZYx@Lra5=<PK);kJL.(z`=AAՃ=ۼN-a%D2L"XS}HIFuLƧ|tvݨQ#n4Z4^80ݷ".9r.=?K	p+d"eʃ	@Cے8cξZKʩꨱIG	pF pyyMS,qڌ1" )j9g)u$[VNۏ=邞okk zqapHBk	2qB_g{6dƦdk)Q$}"Z^!球X7QxW6ORM*;hhvɫN48(V5Mՙ:|udXO=E1~~wJ*% .(eM"a⑳Lh1%lܬjs!?K<:?s?SkQm |-7j60kTWYӒs}VR/yMiXkϼ;KdŜ&e^_ݷ	ʕ++\B{`*!J#*`$>Awk\r愔_UHbD<NH(xMpLaҊ%LϺN!k Ĺt8&Ҍ	{e#::|_F6TېUHw;)Z qP2YD@XLc궯A+MyG&g+\x"zU`8d?Vul>B;6XvW%yK(#zeX);oDh\JSo'Y<cBE>n2gf'JrpW^4adlҦo$)1#!ߢtK22)
e<<"/e?oMm-[
Ά5z)pړ^;#g;l+%wJNsMo<lˆCEڝ~>n;}=R(qUYRp(L_,feύ̌95ۯWe'j߻LcY1 *54'UY(0+YCUX|x37WtrSABgPIBb}^&"W>@
,T@PnTS1ʢfG=8s|@1w
o%k~9lN(wp8RjvNٺ6Fb:mz%*ސ{k}	1h뛀zB^q7+WyyyF^(8ffWdBYZRcr7 `vWjAb¯WǞ"ݰk
nh!bUڡ;2>*LkZ՘824 g*Yn,+<K%mr%;(' aƪ,ZtNqMRU[i}mbuqẅ䗘xZ	LXĎV:yiޯh.P ZHTlto[kpȒ3LhrNT)==i0cgC:3(zij3cM\LNOm~=P1PqǙȊOvF0+tMƳtmA,0F_"f!ORܢp., hQ*ex{ּ3K;wT\bRD`imR0B!0=X3:9ꏽy_XuXE)9M#Qe829PԴ"[p遆'IG4hE^aPflRQ޳GHɘ%'к4bPy mV19oeʸbvB6DH'Jo>S)d,@s Un-#AL}<t锶h@Zg1kISG̠?`/'Aėxk8>By6~)wʴ	lfW&`ýuK#zS]/>,.h '2$O#H3鷯zx09ykCV?IjY/*qذ)g/q hb``IL"QAfæ7<<v߿>mʯ
^r]bqH2 C{nNd g\	[c(<Ս[pl࿳YH"|X@] sd0Ml,T;=YXMQ\48n	t0 |-0(49VWݠ'KĝM7-;iE2X
VĂ1]@:j"tUԫз9|Ҩ78\YF<TeQzEo 6YZ/LE`>,0-껲NOBjL7ԝmQ1Č0VI>lղ]"e
cznpAZ"ƒ[[46h@2:W~}BW\}ڜ"$"!׸	:8dտi0p$66^#+6Gl&YM%b@ˆ/k^D{?
"ql<J܏1rl
au][CÏeu1M"6B1C8qtvzْ}"X#+z15F̰ǵ.a4);W.v%ڑ!PHH["p>[WV#mz RO6?ݚ/iYO9҄K-;͡k=9CRݐ0c?	|_Og^V(xYuL^("_
M{dc\`F'[H٣W^I]wgW?~oS+%m"@cÔ~W$PBàaHF|ɲ3];}\SuCى3h>u[`K\yWaL@PLHut%__]9pnFĄ-'@Fu°\iΚ0돲WLuI(XhZmI+/}ʖi"fDc=MH
Ќ"0,`#+}UU}2eEh|ZO|Gӏ}mEJ2qCeHpUUa(uR]JiG"9sc;H;~'3$H#\y!/7yƶ,qbExfbezq,ljTb^ga~j̻`Scl*xN/Ѽ"kgPļ#Bðbℋ J`	|yY­Y_	MsN1N?`*2Y"'CHGφ?,*_as9VaTpF mnF
G1BoqPbg1G}I`BQ_ Ue׏kS-EGhK@s]`lB	"4i>FgQ5uqL#*=@x$W՛aEǀ@#eYgrbC0
tITѪxkM'!jVve$s6jEN!Ɂݻә	6ĵ+g	<{Ǔv6x22Er_͞yqSQvԘt@ǀ1vCPZ3'
yg8oF5/$r>v)fZ%"n/{$f@OovLu~hBٗ6$Ք70xTz셽3lx|}<0M_ ;Ɏp,߄r7*&`bQ`hi,;4Ayp¶1wz#'Ѣw xgc<eCE,z>qÜu&Crr܏52@5ĳ%|ӑ;OVS9?"iH&<VBܽ_.$hp[=B0oC^	~u>,JXQz5cGd=<X DܘKDf1꯻I}IyJãm7ʙMuWJu>'T&:F lyjih(V@k+vUONd羡CƷC	g93Xne<w1g%ݭW@0faE0=$dZ05<1*vv% qcWb$f}K'lo7ja},Y^@/N =Xt5H[1l!2~"q[I ŵHLb%X	6qL""8%3C_!><=;АL5xrv3gBF߸*'U2[ϊEzZ8$Y]	>=u+&$cnuU`JԹ%U9r<y&k6' i4J֯6:<9%6c}|M\]S6Zm#^u aGΜ\{hoB{5&$G#"erUQiե%H`au6v/cB{#
=@QY{%0Ej!iqVZD1Y>iQGSÞ2iI9}{pϬ>f((Hw3P,6^ծ/@)x7rME5s%%'dMv)1$%n34bfl_d,I,E"yxT6oKw>-fK,fb9bG$/5XA_J1i-@=yR~wQDȇ#>$7`7|IΈ@n^xq<M&?GqiChw@U"dZ
kB&Qh<2X8 +u%.q`#}<؆G碪UĹ`c7&Ն*i=󢼖ޛN$LIEqH;6ˊS͐aLdg*>{da_Mcy?TO X'!U?#p=i]^\aI
eAp~:xdItSقk$܃<gFh;~	_v3#F+y1ÞM;ДDXAOO8<_ֿ.o<n*Jw5\3v'Ԕ2",[?hxܬ]PO(ہ̹(6`|KW!_.)3)]D9;{O{O9S>%[\vȺ$Y٣GJ<PBqWun%ϨCv-]=qn붶~OFzϞ"RvyDy+oZS
<AdĖ^3gCtQBI*
$Lm;Ymq"ߟpK] AusM]][mXE;Q1iU`+h7| 9X0<2磄OJתf,Dn9h5ѤTvb0F5kbڃZL8̖VY]_H|UG9L-19|C <D1$Gw%#mG_AZ<^dtNY~ţla+j
ѡ4S9)c]63H{3hI>cGyތ!q8Dі[JqQ	hAHmy={z44iiiϠPq=SE];eRɽBysE_&)pQPR{'Q0L>[[+/i
D&|{A8/[kZdsu.z@sH.D Yѯ9%띍K,<ƂäΟX_?ຩb{J!s443hRioW4Iv3P]fḁMºeD5RYL{J!N
qpȆYk>%Lԓ#cHf='B&<,#z?9x㏄vK5 ȇ\<}&dNRwEFA.)X{Jk}{C&؃۲)?

\,<2IL5}f!d(GԽDnI?뀿6y 	K<CFm$p2	A9hpkrǲRt
0:87c&KU_;h61@1
G<MFRRTQUY=ᨍABl*2d	8YB((T5;Xt8nBQ 36*SBW4Miӓ_]}kVU&/-σ℠=l.LtxkOúeb6-"ۻ+~nڅ໵ʚݻ
",ڴBR+1Xf,Ǯ
϶PUYZŔkW^Q f<FY3gւ݄m.p@'`nACEӏd~·^m*wV כiAd{"\xyj9\l)z{#EaΝ`ꨣfߐbK|r)m\: N5'Ӣ-5;:ӭpEbϓOomAeRRB_Zذj\>;p6K"
Ev!j-fdfCN-PguQיWGD۸	kuFMjk!sE˂J$xo 	J5-_KJ{XqX(GT`(|}lnTŌRnY`|n|v%u@	Qx-Âv,|gmzVVCI}S3 e&8	"n"`pBMn{NCM
*pVk33~I9tTO!0ܴcw4+wq'ZtTM>cG]	Mzl<1LH?";2'CNTYUFrFŮ){?(3y(ÂGb %/G}.=\|G4p9ne3􃑸eBC&;| 1.k{8|KkaF7Eu[8_L'ɌV(Ďv].'{Tνk\w	*Ѯ&KYD~/5͌?+]z"sbF^X,OJE ;ɡ
P.C{#&ԃh*#+fV)ȲS+gd4+oF5iC٬9Z`7MbKtq
x`
?^֟w8A+:5D!x.oXNB
8T8<vT>[7
.vڳivkmDꈟV|*z;TዅB,6*-Mw,>tcG}B/8SZy)BOЗmr:rw!U'bC~-cl:վ+h_$5~~w#{HC,i(<ZXU?~qrM/E9!3J؃hC%eUі)a:R|Ѯ
I 	C1
`k8%슆ɵ4k֍G^`O]X35S]bP旾2z"Ls2l4L.7jx'L\ԽH@.Yqp{tٌӔu]%D%?ӉQasS,wY<qtBCyTS}7x)/p/@Tt>1@ر=C4~X}Dn)}4hr)('m(Ba?;Uۏ7N'XS88b2	DM=EC#~JX_\O²62O/i( 1 Ëdnn-|[8TeĤ#_NY6:NoH<nNځxx WcC`tT˙y%{&,7-XI,iOύkRaYԃ5ՅlŌh1s=65X8SNMDHv{p-kQd /1Vu*+XnWy&/9vmLR{B'ڄa8p=FczN -f+Dip,rZ34qY?KvmꈈB9$B;3S\4J'o~j$I&K&R6!	$%O$3!|k`5Gh2ZOMgb`_E$©2Qߍa,Ť4wWj(xգqHL5_]s#H⛄MsW\'>u6Cоdd A݀mTTik#HͬՁ~dnm춻	")!F36~ J7 Ce:XLd qxYxxO]LK*7.ٵur~'Yn3euX$FC>s<ir1_!dXً@A92ߧ~HHu<(=%Jyb eai]B>W[w3COҒ^0 #;ϵ*p2pw1,7YzȠ"WŗaڬY _u9p/=ԇ9bprY
Ե+S1W獪h.uVg!f#Zz6WЀ%O<wSUDz`ˍA?rf52HL? ~TM؛nW\萊	 o?NoLdxl]M
Oֆ%"`FXr\ņa6l;*j
"z (*S3K}BWxP9r&?0Vhx'QMYV'CԳUPlٝiLJx5K5S'̜l_oX-m.7p5 1Y};DBRuI(XnXVy󖓉g{cڈ̴no6FkM8+;(aKPw-C&#LspH^NYfFbҀ%9+VBˍVZdPASs=v{jvK}h+^Ki%v0Ü Ђ"R%&A,:Ƹܺc!	?q:^yB]`Pbu:!PfkPx.y1l̿3!8G`?A019h#QZkl
E{NSGz
Bvn^8&|ҹICvE,ΉNUU
1jƤy~1y_Ybo+(䀓vV8j躜
͆PlsXvC$qWki^fĔ8CG(;{KHXd ߲_,7 />NvnX 8<vyy+F,$ٿecˏ M$Ϛ_Z. &OP%L|wkm!A07#؞av[X85")~I$BdD䬆#- $!'QImV2hELƵw"Z#YX"do`_鵻!rv_'?Kp˸⹖n݁%N-Xp:*sxnx.Tfg܉D;^ E8Xs6
i'H~<<"-$Rk?U999ir]wO	ջ%sG`U4ރ J _SPwͯF^
&y<mz%wOsY(Q
!cGhGCx댺z˯j2:	 $UgGr?omYusTzT;MߦkwO06[3W`љG?	l?2C9mY@eg<D_tg34WZU&OW Ʉ?WiA_TOy;V̑L**5{8v$H}[BEJ!;h<s&9<)1a&͘>g4?82!|;翄"VE6﵊iiQ%ܜ9
hTy鷑>,݁EQONb.X~hV3'1Y01ɪ O`j ;![_Bpl"$[}vՇ &}}GPptǞ	Z^Ng(Y;ŒƲG~#T?mH5/n'$H6\V,X1;@4N3 9EG]'oB+cL08A
MYOIur`9ွXh2WR.-Zo<'Kߛ8pȿ^yF5SYUd#A*7mUSc&@L{S]:]5@0\UZxOeE3ݿ.t!m+f1@wGXU3Q<;Qk8(G_DȠD|fCb<|Rw9S8Ȇ	2 
N̂aEuͿ>ykHH3/'LVja _:jEBzޏDɅ-@hU+i!eg{tJ98#?=0)B mE'h~}~oLk90&p`g	"n;'gAb9B3a'yBL&3AA }WtPWB_bIhL"\e[AD~<FsL{&9p<8M34Z/)mrvNف\L|+hA
xlb5Ɔ9[v6SPGgBǺ[|,HOףQȂ!d=<dZYlZknaj:`^x1{s`6L!#aM[¡ib|_D`a+FQuv(᤼Q5h^*,&]ИC) Jkяʼ9"e#ُ1;J]w9;u0:u bj2FσSQ#cضߓ"'oʰ
DQmHc:ǕuZĂu=z4];<5|<aFJX!)XMoD(U{)M#
ΆYV~d,Wš 	ӍUrV+e1z~Tֲ7$T0
QI?o0{vN< ~o'5Do!(i+Up눂UI<rNN^$ѿ>ej/ylE{<J!pn=	z9FH;XbbeM(zۘ*0  G]pU?s4@y
jdɬӮn.ڝu;ltmeUjuSug
Bl$D!R!\Inr}Or`'6gnrs9~;?)Bw
g ;+{Ӗ3^z;A<CB7t(t	wu?`:,qT~Px}h|mZWmO'<RV	(0O)
xMjj.	@K-Nx	+\40FHV03
ڣVz[`ܛ4Ouj}tB2'4PF¶?-EO.	%tͯ>]Lیzjۊ++r܄`	GQ6^ŋ^ xTpȮlA#@xne0vK8E$ZCIgU)k2޴CYӒ"Z󇼒$S#:]ߟFKvaDs~XW.eرg>zB^˗*od1>h:ӻyt0̀<ƍ
/`Kܚy
rDzCw"C^E' 7;)l}E?6P3*.Yf:"AnҦ啞n@ntn#h|u-ΑaP̋҅?2R# hAʛT,ESN6?~.d~lIY-N+E9X*tHR</ƶw%)ͩ¢a=ﮞMj0YUӹ}_>s9)q$	=Qʥ4PvΉ	RW;bu\Aފ]jn_if__*)Opd엨=KAǜ 2˴c&oll=`Xa;znX!ha
=dJcԟ+uމkߏ%WN7AEWnsb GT^vʌ7ܟZm~fo ;)jN'NCR_֓+݆k=4͏7ڣ!n o	.m eFd sc}R|O+0gAhB2%]HC@Z(4]=b[0ǹM",<DV]^kb/9Z	yp!ETQ0G{vXO/H%
ѧGC,kA瞈WzXܛ%܎9"zP"cVݶnw[Rc))\U::lTȕR1eJXI5Fί}MiI(py'b(Y&dUL ؝H#m8t3VLGWG*\ȵt1o"4m* 'na>xs}тĿ̀<;
lVp#a)j@g>T<VTXu:k,+vʩ,
F7$tӸ
mCCNYb?: `-:P:kE.7aےǼW^1	cY+x0(Boy7&7nnjڀ^ 1K=
+ԵHߑT+\9)K`fU3"dE[HC܏Żu6ԀWt<jH=?vmF<2|@=Nt/Hѩ ?`Xu)Jr@OnG.Fc+Z#*J5>{NZS[)h̽TG1CLO>oφw$,ȳ:,Z!"2Ώ+܎7C9o,"@knq-^'җFYM!9}D4 J/}<dV=kGISr q6;YBwŸ4]H׿[6wyATu>_p&J|bDϿ6%*e!ǻ`j__W<Gh_<($q'n 0'`ؗ]?-8K;2I]&k;ڱ^<`>/t[	D&G?gY;gMArʕ@g\vh0%SQ::8<sx%3OJp²dy%T*Eх!'crlw &B=azPdZQ 2asO]Iosa oZGEzm"\wKc}F:OFyeGn$j,_i%ݜU:piT]bƉ,3}ݱ/WkfCЈ~`ou:8ڗlZǱB]> HscHODwgdb6f^8XJI `ZF;ERFY3KOOq,`t	K[M)	*KQrs#wk1WR{S_ [2AU 
\B
J=[ ~E%n^AhrYXfuPhL<үu\iq#cA[sN1ib0ϼ>xflhF	?Ǿȥ߇kcbBTy><؞Htk	h+)Lp)eK2`v/  |IDAT:Eہ]s&gXrZn3&4i rTjAԛ샢Ø©w (yHKEjÃoEk$[cntDJ'Xr5y^Vۧ[~ΏGǖ\pP SF9/SvȹB^T<weG$Ea/̢%/C?"}W4%Ri2	N8؎BFpHQ@پge	>JMkZh-
]Ӯ әVRcζǎeɈt%3ɾ]ɂ)E\/"H5'>{9ykb|w t0\(hf#+ҙ|Vr&g̅>4B9FJ-{NZ17$ϫRev-,	DxOn_J},?0v>d>S//'ڵ!S0γۥW04~8;7CYrO_)ɮ>:2PVeAkW*94OMޟ?
rėdg#MHVBwLp浊EE!7MՊ)Uvp/Ptls2Y0dԀCxՊŊ\ZW4D5VRrR@*ք̘x)b k!UGG[XpzZ[CyeZݎKfwPuȷ\!'? oC.1+XG[Q@@y^,R}o<&+k2CR|l_X-]Zz~n61Aӝ7 qCKuIߏrs+oۨ@B<wKr<]{h#%?r2(욐̯RlF'6֎ʼ
3	m1BF*X6r<U4M.+&^_܅мsU3dvkQR?SX>Dh(0r̈́hY"GhsB%5bjGxTK gr}(j;2*K*SfFŊoCehF{u"i}>l)4ʤZEd?M#7tbFRtłm６ٸqǨ!Z|kV:H
$afvZS	IOc"81ޡΓ#*]Pos=ߧI{=ߝkN^^.y%$:a?9`tƳ%ŕ5﷋j#=فH,TnżNDĈ5+i6p1UHL{&ӃPtڦvw;I5vJI?-:sQ*=f(tF>͊45^x9ܛXY3v\My$-h=wK;u|=dPe
`Wljt}VZż>;Q\iɽGϱ??Z
rӗM5TT=/sH<ݱi'G`r&dFr?1=    IENDB`<?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 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 ResponseInterface extends MessageInterface
{








public function getStatusCode();





















public function withStatus($code, $reasonPhrase = '');














public function getReasonPhrase();
}
<?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 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 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\Log;








abstract class AbstractLogger implements LoggerInterface
{







public function emergency($message, array $context = array())
{
$this->log(LogLevel::EMERGENCY, $message, $context);
}











public function alert($message, array $context = array())
{
$this->log(LogLevel::ALERT, $message, $context);
}










public function critical($message, array $context = array())
{
$this->log(LogLevel::CRITICAL, $message, $context);
}









public function error($message, array $context = array())
{
$this->log(LogLevel::ERROR, $message, $context);
}











public function warning($message, array $context = array())
{
$this->log(LogLevel::WARNING, $message, $context);
}








public function notice($message, array $context = array())
{
$this->log(LogLevel::NOTICE, $message, $context);
}










public function info($message, array $context = array())
{
$this->log(LogLevel::INFO, $message, $context);
}








public function debug($message, array $context = array())
{
$this->log(LogLevel::DEBUG, $message, $context);
}
}
<?php

namespace Psr\Log;




class LogLevel
{
const EMERGENCY = 'emergency';
const ALERT = 'alert';
const CRITICAL = 'critical';
const ERROR = 'error';
const WARNING = 'warning';
const NOTICE = 'notice';
const INFO = 'info';
const DEBUG = 'debug';
}
<?php

namespace Psr\Log;









trait LoggerTrait
{







public function emergency($message, array $context = array())
{
$this->log(LogLevel::EMERGENCY, $message, $context);
}











public function alert($message, array $context = array())
{
$this->log(LogLevel::ALERT, $message, $context);
}










public function critical($message, array $context = array())
{
$this->log(LogLevel::CRITICAL, $message, $context);
}









public function error($message, array $context = array())
{
$this->log(LogLevel::ERROR, $message, $context);
}











public function warning($message, array $context = array())
{
$this->log(LogLevel::WARNING, $message, $context);
}








public function notice($message, array $context = array())
{
$this->log(LogLevel::NOTICE, $message, $context);
}










public function info($message, array $context = array())
{
$this->log(LogLevel::INFO, $message, $context);
}








public function debug($message, array $context = array())
{
$this->log(LogLevel::DEBUG, $message, $context);
}









abstract public function log($level, $message, array $context = array());
}
<?php

namespace Psr\Log;
















interface LoggerInterface
{







public function emergency($message, array $context = array());











public function alert($message, array $context = array());










public function critical($message, array $context = array());









public function error($message, array $context = array());











public function warning($message, array $context = array());








public function notice($message, array $context = array());










public function info($message, array $context = array());








public function debug($message, array $context = array());









public function log($level, $message, array $context = array());
}
<?php

namespace Psr\Log\Test;

use Psr\Log\LogLevel;






abstract class LoggerInterfaceTest extends \PHPUnit_Framework_TestCase
{



abstract function getLogger();








abstract function getLogs();

public function testImplements()
{
$this->assertInstanceOf('Psr\Log\LoggerInterface', $this->getLogger());
}




public function testLogsAtAllLevels($level, $message)
{
$logger = $this->getLogger();
$logger->{$level}($message, array('user' => 'Bob'));
$logger->log($level, $message, array('user' => 'Bob'));

$expected = array(
$level.' message of level '.$level.' with context: Bob',
$level.' message of level '.$level.' with context: Bob',
);
$this->assertEquals($expected, $this->getLogs());
}

public function provideLevelsAndMessages()
{
return array(
LogLevel::EMERGENCY => array(LogLevel::EMERGENCY, 'message of level emergency with context: {user}'),
LogLevel::ALERT => array(LogLevel::ALERT, 'message of level alert with context: {user}'),
LogLevel::CRITICAL => array(LogLevel::CRITICAL, 'message of level critical with context: {user}'),
LogLevel::ERROR => array(LogLevel::ERROR, 'message of level error with context: {user}'),
LogLevel::WARNING => array(LogLevel::WARNING, 'message of level warning with context: {user}'),
LogLevel::NOTICE => array(LogLevel::NOTICE, 'message of level notice with context: {user}'),
LogLevel::INFO => array(LogLevel::INFO, 'message of level info with context: {user}'),
LogLevel::DEBUG => array(LogLevel::DEBUG, 'message of level debug with context: {user}'),
);
}




public function testThrowsOnInvalidLevel()
{
$logger = $this->getLogger();
$logger->log('invalid level', 'Foo');
}

public function testContextReplacement()
{
$logger = $this->getLogger();
$logger->info('{Message {nothing} {user} {foo.bar} a}', array('user' => 'Bob', 'foo.bar' => 'Bar'));

$expected = array('info {Message {nothing} Bob Bar a}');
$this->assertEquals($expected, $this->getLogs());
}

public function testObjectCastToString()
{
$dummy = $this->getMock('Psr\Log\Test\DummyTest', array('__toString'));
$dummy->expects($this->once())
->method('__toString')
->will($this->returnValue('DUMMY'));

$this->getLogger()->warning($dummy);
}

public function testContextCanContainAnything()
{
$context = array(
'bool' => true,
'null' => null,
'string' => 'Foo',
'int' => 0,
'float' => 0.5,
'nested' => array('with object' => new DummyTest),
'object' => new \DateTime,
'resource' => fopen('php://memory', 'r'),
);

$this->getLogger()->warning('Crazy context data', $context);
}

public function testContextExceptionKeyCanBeExceptionOrOtherValues()
{
$this->getLogger()->warning('Random message', array('exception' => 'oops'));
$this->getLogger()->critical('Uncaught Exception!', array('exception' => new \LogicException('Fail')));
}
}

class DummyTest
{
}<?php

namespace Psr\Log;









class NullLogger extends AbstractLogger
{








public function log($level, $message, array $context = array())
{

 }
}
<?php

namespace Psr\Log;




trait LoggerAwareTrait
{

protected $logger;






public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
}
}
<?php

namespace Psr\Log;

class InvalidArgumentException extends \InvalidArgumentException
{
}
<?php

namespace Psr\Log;




interface LoggerAwareInterface
{






public function setLogger(LoggerInterface $logger);
}
<?php

namespace React\Promise;

class RejectedPromise implements ExtendedPromiseInterface, CancellablePromiseInterface
{
private $reason;

public function __construct($reason = null)
{
if ($reason instanceof PromiseInterface) {
throw new \InvalidArgumentException('You cannot create React\Promise\RejectedPromise with a promise. Use React\Promise\reject($promiseOrValue) instead.');
}

$this->reason = $reason;
}

public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
{
if (null === $onRejected) {
return $this;
}

try {
return resolve($onRejected($this->reason));
} catch (\Throwable $exception) {
return new RejectedPromise($exception);
} catch (\Exception $exception) {
return new RejectedPromise($exception);
}
}

public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
{
if (null === $onRejected) {
throw UnhandledRejectionException::resolve($this->reason);
}

$result = $onRejected($this->reason);

if ($result instanceof self) {
throw UnhandledRejectionException::resolve($result->reason);
}

if ($result instanceof ExtendedPromiseInterface) {
$result->done();
}
}

public function otherwise(callable $onRejected)
{
if (!_checkTypehint($onRejected, $this->reason)) {
return $this;
}

return $this->then(null, $onRejected);
}

public function always(callable $onFulfilledOrRejected)
{
return $this->then(null, function ($reason) use ($onFulfilledOrRejected) {
return resolve($onFulfilledOrRejected())->then(function () use ($reason) {
return new RejectedPromise($reason);
});
});
}

public function progress(callable $onProgress)
{
return $this;
}

public function cancel()
{
}
}
<?php

namespace React\Promise;

class LazyPromise implements ExtendedPromiseInterface, CancellablePromiseInterface
{
private $factory;
private $promise;

public function __construct(callable $factory)
{
$this->factory = $factory;
}

public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
{
return $this->promise()->then($onFulfilled, $onRejected, $onProgress);
}

public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
{
return $this->promise()->done($onFulfilled, $onRejected, $onProgress);
}

public function otherwise(callable $onRejected)
{
return $this->promise()->otherwise($onRejected);
}

public function always(callable $onFulfilledOrRejected)
{
return $this->promise()->always($onFulfilledOrRejected);
}

public function progress(callable $onProgress)
{
return $this->promise()->progress($onProgress);
}

public function cancel()
{
return $this->promise()->cancel();
}

private function promise()
{
if (null === $this->promise) {
try {
$this->promise = resolve(call_user_func($this->factory));
} catch (\Throwable $exception) {
$this->promise = new RejectedPromise($exception);
} catch (\Exception $exception) {
$this->promise = new RejectedPromise($exception);
}
}

return $this->promise;
}
}
<?php

namespace React\Promise;

class UnhandledRejectionException extends \RuntimeException
{
private $reason;

public static function resolve($reason)
{
if ($reason instanceof \Exception || $reason instanceof \Throwable) {
return $reason;
}

return new static($reason);
}

public function __construct($reason)
{
$this->reason = $reason;

$message = sprintf('Unhandled Rejection: %s', json_encode($reason));

parent::__construct($message, 0);
}

public function getReason()
{
return $this->reason;
}
}
<?php

if (!function_exists('React\Promise\resolve')) {
require __DIR__.'/functions.php';
}
<?php

namespace React\Promise;

class Deferred implements PromisorInterface
{
private $promise;
private $resolveCallback;
private $rejectCallback;
private $notifyCallback;
private $canceller;

public function __construct(callable $canceller = null)
{
$this->canceller = $canceller;
}

public function promise()
{
if (null === $this->promise) {
$this->promise = new Promise(function ($resolve, $reject, $notify) {
$this->resolveCallback = $resolve;
$this->rejectCallback = $reject;
$this->notifyCallback = $notify;
}, $this->canceller);
}

return $this->promise;
}

public function resolve($value = null)
{
$this->promise();

call_user_func($this->resolveCallback, $value);
}

public function reject($reason = null)
{
$this->promise();

call_user_func($this->rejectCallback, $reason);
}

public function notify($update = null)
{
$this->promise();

call_user_func($this->notifyCallback, $update);
}





public function progress($update = null)
{
$this->notify($update);
}
}
<?php

namespace React\Promise;

interface ExtendedPromiseInterface extends PromiseInterface
{



public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null);




public function otherwise(callable $onRejected);




public function always(callable $onFulfilledOrRejected);




public function progress(callable $onProgress);
}
<?php

namespace React\Promise;

class Promise implements ExtendedPromiseInterface, CancellablePromiseInterface
{
private $canceller;
private $result;

private $handlers = [];
private $progressHandlers = [];

private $requiredCancelRequests = 0;
private $cancelRequests = 0;

public function __construct(callable $resolver, callable $canceller = null)
{
$this->canceller = $canceller;
$this->call($resolver);
}

public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
{
if (null !== $this->result) {
return $this->result()->then($onFulfilled, $onRejected, $onProgress);
}

if (null === $this->canceller) {
return new static($this->resolver($onFulfilled, $onRejected, $onProgress));
}

$this->requiredCancelRequests++;

return new static($this->resolver($onFulfilled, $onRejected, $onProgress), function () {
if (++$this->cancelRequests < $this->requiredCancelRequests) {
return;
}

$this->cancel();
});
}

public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
{
if (null !== $this->result) {
return $this->result()->done($onFulfilled, $onRejected, $onProgress);
}

$this->handlers[] = function (ExtendedPromiseInterface $promise) use ($onFulfilled, $onRejected) {
$promise
->done($onFulfilled, $onRejected);
};

if ($onProgress) {
$this->progressHandlers[] = $onProgress;
}
}

public function otherwise(callable $onRejected)
{
return $this->then(null, function ($reason) use ($onRejected) {
if (!_checkTypehint($onRejected, $reason)) {
return new RejectedPromise($reason);
}

return $onRejected($reason);
});
}

public function always(callable $onFulfilledOrRejected)
{
return $this->then(function ($value) use ($onFulfilledOrRejected) {
return resolve($onFulfilledOrRejected())->then(function () use ($value) {
return $value;
});
}, function ($reason) use ($onFulfilledOrRejected) {
return resolve($onFulfilledOrRejected())->then(function () use ($reason) {
return new RejectedPromise($reason);
});
});
}

public function progress(callable $onProgress)
{
return $this->then(null, null, $onProgress);
}

public function cancel()
{
if (null === $this->canceller || null !== $this->result) {
return;
}

$canceller = $this->canceller;
$this->canceller = null;

$this->call($canceller);
}

private function resolver(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
{
return function ($resolve, $reject, $notify) use ($onFulfilled, $onRejected, $onProgress) {
if ($onProgress) {
$progressHandler = function ($update) use ($notify, $onProgress) {
try {
$notify($onProgress($update));
} catch (\Throwable $e) {
$notify($e);
} catch (\Exception $e) {
$notify($e);
}
};
} else {
$progressHandler = $notify;
}

$this->handlers[] = function (ExtendedPromiseInterface $promise) use ($onFulfilled, $onRejected, $resolve, $reject, $progressHandler) {
$promise
->then($onFulfilled, $onRejected)
->done($resolve, $reject, $progressHandler);
};

$this->progressHandlers[] = $progressHandler;
};
}

private function resolve($value = null)
{
if (null !== $this->result) {
return;
}

$this->settle(resolve($value));
}

private function reject($reason = null)
{
if (null !== $this->result) {
return;
}

$this->settle(reject($reason));
}

private function notify($update = null)
{
if (null !== $this->result) {
return;
}

foreach ($this->progressHandlers as $handler) {
$handler($update);
}
}

private function settle(ExtendedPromiseInterface $promise)
{
$handlers = $this->handlers;

$this->progressHandlers = $this->handlers = [];
$this->result = $promise;

foreach ($handlers as $handler) {
$handler($promise);
}
}

private function result()
{
while ($this->result instanceof self && null !== $this->result->result) {
$this->result = $this->result->result;
}

return $this->result;
}

private function call(callable $callback)
{
try {
$callback(
function ($value = null) {
$this->resolve($value);
},
function ($reason = null) {
$this->reject($reason);
},
function ($update = null) {
$this->notify($update);
}
);
} catch (\Throwable $e) {
$this->reject($e);
} catch (\Exception $e) {
$this->reject($e);
}
}
}
<?php

namespace React\Promise;

interface PromiseInterface
{



public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null);
}
<?php

namespace React\Promise;

class CancellationQueue
{
private $started = false;
private $queue = [];

public function __invoke()
{
if ($this->started) {
return;
}

$this->started = true;
$this->drain();
}

public function enqueue($cancellable)
{
if (!method_exists($cancellable, 'then') || !method_exists($cancellable, 'cancel')) {
return;
}

$length = array_push($this->queue, $cancellable);

if ($this->started && 1 === $length) {
$this->drain();
}
}

private function drain()
{
for ($i = key($this->queue); isset($this->queue[$i]); $i++) {
$cancellable = $this->queue[$i];

$exception = null;

try {
$cancellable->cancel();
} catch (\Throwable $exception) {
} catch (\Exception $exception) {
}

unset($this->queue[$i]);

if ($exception) {
throw $exception;
}
}

$this->queue = [];
}
}
<?php

namespace React\Promise;

interface PromisorInterface
{



public function promise();
}
<?php

namespace React\Promise\Exception;

class LengthException extends \LengthException
{
}
<?php

namespace React\Promise;

function resolve($promiseOrValue = null)
{
if ($promiseOrValue instanceof ExtendedPromiseInterface) {
return $promiseOrValue;
}

if (method_exists($promiseOrValue, 'then')) {
$canceller = null;

if (method_exists($promiseOrValue, 'cancel')) {
$canceller = [$promiseOrValue, 'cancel'];
}

return new Promise(function ($resolve, $reject, $notify) use ($promiseOrValue) {
$promiseOrValue->then($resolve, $reject, $notify);
}, $canceller);
}

return new FulfilledPromise($promiseOrValue);
}

function reject($promiseOrValue = null)
{
if ($promiseOrValue instanceof PromiseInterface) {
return resolve($promiseOrValue)->then(function ($value) {
return new RejectedPromise($value);
});
}

return new RejectedPromise($promiseOrValue);
}

function all($promisesOrValues)
{
return map($promisesOrValues, function ($val) {
return $val;
});
}

function race($promisesOrValues)
{
$cancellationQueue = new CancellationQueue();
$cancellationQueue->enqueue($promisesOrValues);

return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $cancellationQueue) {
resolve($promisesOrValues)
->done(function ($array) use ($cancellationQueue, $resolve, $reject, $notify) {
if (!is_array($array) || !$array) {
$resolve();
return;
}

$fulfiller = function ($value) use ($cancellationQueue, $resolve) {
$cancellationQueue();
$resolve($value);
};

$rejecter = function ($reason) use ($cancellationQueue, $reject) {
$cancellationQueue();
$reject($reason);
};

foreach ($array as $promiseOrValue) {
$cancellationQueue->enqueue($promiseOrValue);

resolve($promiseOrValue)
->done($fulfiller, $rejecter, $notify);
}
}, $reject, $notify);
}, $cancellationQueue);
}

function any($promisesOrValues)
{
return some($promisesOrValues, 1)
->then(function ($val) {
return array_shift($val);
});
}

function some($promisesOrValues, $howMany)
{
$cancellationQueue = new CancellationQueue();
$cancellationQueue->enqueue($promisesOrValues);

return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $howMany, $cancellationQueue) {
resolve($promisesOrValues)
->done(function ($array) use ($howMany, $cancellationQueue, $resolve, $reject, $notify) {
if (!is_array($array) || $howMany < 1) {
$resolve([]);
return;
}

$len = count($array);

if ($len < $howMany) {
throw new Exception\LengthException(
sprintf(
'Input array must contain at least %d item%s but contains only %s item%s.',
$howMany,
1 === $howMany ? '' : 's',
$len,
1 === $len ? '' : 's'
)
);
}

$toResolve = $howMany;
$toReject = ($len - $toResolve) + 1;
$values = [];
$reasons = [];

foreach ($array as $i => $promiseOrValue) {
$fulfiller = function ($val) use ($i, &$values, &$toResolve, $toReject, $resolve, $cancellationQueue) {
if ($toResolve < 1 || $toReject < 1) {
return;
}

$values[$i] = $val;

if (0 === --$toResolve) {
$cancellationQueue();
$resolve($values);
}
};

$rejecter = function ($reason) use ($i, &$reasons, &$toReject, $toResolve, $reject) {
if ($toResolve < 1 || $toReject < 1) {
return;
}

$reasons[$i] = $reason;

if (0 === --$toReject) {
$reject($reasons);
}
};

$cancellationQueue->enqueue($promiseOrValue);

resolve($promiseOrValue)
->done($fulfiller, $rejecter, $notify);
}
}, $reject, $notify);
}, $cancellationQueue);
}

function map($promisesOrValues, callable $mapFunc)
{
$cancellationQueue = new CancellationQueue();
$cancellationQueue->enqueue($promisesOrValues);

return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $mapFunc, $cancellationQueue) {
resolve($promisesOrValues)
->done(function ($array) use ($mapFunc, $cancellationQueue, $resolve, $reject, $notify) {
if (!is_array($array) || !$array) {
$resolve([]);
return;
}

$toResolve = count($array);
$values = [];

foreach ($array as $i => $promiseOrValue) {
$cancellationQueue->enqueue($promiseOrValue);

resolve($promiseOrValue)
->then($mapFunc)
->done(
function ($mapped) use ($i, &$values, &$toResolve, $resolve) {
$values[$i] = $mapped;

if (0 === --$toResolve) {
$resolve($values);
}
},
$reject,
$notify
);
}
}, $reject, $notify);
}, $cancellationQueue);
}

function reduce($promisesOrValues, callable $reduceFunc, $initialValue = null)
{
$cancellationQueue = new CancellationQueue();
$cancellationQueue->enqueue($promisesOrValues);

return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $reduceFunc, $initialValue, $cancellationQueue) {
resolve($promisesOrValues)
->done(function ($array) use ($reduceFunc, $initialValue, $cancellationQueue, $resolve, $reject, $notify) {
if (!is_array($array)) {
$array = [];
}

$total = count($array);
$i = 0;


 
 $wrappedReduceFunc = function ($current, $val) use ($reduceFunc, $cancellationQueue, $total, &$i) {
$cancellationQueue->enqueue($val);

return $current
->then(function ($c) use ($reduceFunc, $total, &$i, $val) {
return resolve($val)
->then(function ($value) use ($reduceFunc, $total, &$i, $c) {
return $reduceFunc($c, $value, $i++, $total);
});
});
};

$cancellationQueue->enqueue($initialValue);

array_reduce($array, $wrappedReduceFunc, resolve($initialValue))
->done($resolve, $reject, $notify);
}, $reject, $notify);
}, $cancellationQueue);
}


function _checkTypehint(callable $callback, $object)
{
if (!is_object($object)) {
return true;
}

if (is_array($callback)) {
$callbackReflection = new \ReflectionMethod($callback[0], $callback[1]);
} elseif (is_object($callback) && !$callback instanceof \Closure) {
$callbackReflection = new \ReflectionMethod($callback, '__invoke');
} else {
$callbackReflection = new \ReflectionFunction($callback);
}

$parameters = $callbackReflection->getParameters();

if (!isset($parameters[0])) {
return true;
}

$expectedException = $parameters[0];

if (!$expectedException->getClass()) {
return true;
}

return $expectedException->getClass()->isInstance($object);
}
<?php

namespace React\Promise;

interface CancellablePromiseInterface extends PromiseInterface
{



public function cancel();
}
<?php

namespace React\Promise;

class FulfilledPromise implements ExtendedPromiseInterface, CancellablePromiseInterface
{
private $value;

public function __construct($value = null)
{
if ($value instanceof PromiseInterface) {
throw new \InvalidArgumentException('You cannot create React\Promise\FulfilledPromise with a promise. Use React\Promise\resolve($promiseOrValue) instead.');
}

$this->value = $value;
}

public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
{
if (null === $onFulfilled) {
return $this;
}

try {
return resolve($onFulfilled($this->value));
} catch (\Throwable $exception) {
return new RejectedPromise($exception);
} catch (\Exception $exception) {
return new RejectedPromise($exception);
}
}

public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
{
if (null === $onFulfilled) {
return;
}

$result = $onFulfilled($this->value);

if ($result instanceof ExtendedPromiseInterface) {
$result->done();
}
}

public function otherwise(callable $onRejected)
{
return $this;
}

public function always(callable $onFulfilledOrRejected)
{
return $this->then(function ($value) use ($onFulfilledOrRejected) {
return resolve($onFulfilledOrRejected())->then(function () use ($value) {
return $value;
});
});
}

public function progress(callable $onProgress)
{
return $this;
}

public function cancel()
{
}
}
<?php










namespace Symfony\Component\CssSelector\XPath;











class XPathExpr
{



private $path;




private $element;




private $condition;







public function __construct($path = '', $element = '*', $condition = '', $starPrefix = false)
{
$this->path = $path;
$this->element = $element;
$this->condition = $condition;

if ($starPrefix) {
$this->addStarPrefix();
}
}




public function getElement()
{
return $this->element;
}






public function addCondition($condition)
{
$this->condition = $this->condition ? sprintf('%s and (%s)', $this->condition, $condition) : $condition;

return $this;
}




public function getCondition()
{
return $this->condition;
}




public function addNameTest()
{
if ('*' !== $this->element) {
$this->addCondition('name() = '.Translator::getXpathLiteral($this->element));
$this->element = '*';
}

return $this;
}




public function addStarPrefix()
{
$this->path .= '*/';

return $this;
}









public function join($combiner, XPathExpr $expr)
{
$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()
{
$path = $this->path.$this->element;
$condition = null === $this->condition || '' === $this->condition ? '' : '['.$this->condition.']';

return $path.$condition;
}
}
<?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 = array();




private $extensions = array();




private $nodeTranslators = array();




private $combinationTranslators = array();




private $functionTranslators = array();




private $pseudoClassTranslators = array();




private $attributeMatchingTranslators = array();




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($element)
{
if (false === strpos($element, "'")) {
return "'".$element."'";
}

if (false === strpos($element, '"')) {
return '"'.$element.'"';
}

$string = $element;
$parts = array();
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($cssExpr, $prefix = 'descendant-or-self::')
{
$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, $prefix = 'descendant-or-self::')
{
return ($prefix ?: '').$this->nodeToXPath($selector);
}








public function registerExtension(Extension\ExtensionInterface $extension)
{
$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($name)
{
if (!isset($this->extensions[$name])) {
throw new ExpressionErrorException(sprintf('Extension "%s" not registered.', $name));
}

return $this->extensions[$name];
}








public function registerParserShortcut(ParserInterface $shortcut)
{
$this->shortcutParsers[] = $shortcut;

return $this;
}








public function nodeToXPath(NodeInterface $node)
{
if (!isset($this->nodeTranslators[$node->getNodeName()])) {
throw new ExpressionErrorException(sprintf('Node "%s" not supported.', $node->getNodeName()));
}

return call_user_func($this->nodeTranslators[$node->getNodeName()], $node, $this);
}










public function addCombination($combiner, NodeInterface $xpath, NodeInterface $combinedXpath)
{
if (!isset($this->combinationTranslators[$combiner])) {
throw new ExpressionErrorException(sprintf('Combiner "%s" not supported.', $combiner));
}

return call_user_func($this->combinationTranslators[$combiner], $this->nodeToXPath($xpath), $this->nodeToXPath($combinedXpath));
}









public function addFunction(XPathExpr $xpath, FunctionNode $function)
{
if (!isset($this->functionTranslators[$function->getName()])) {
throw new ExpressionErrorException(sprintf('Function "%s" not supported.', $function->getName()));
}

return call_user_func($this->functionTranslators[$function->getName()], $xpath, $function);
}









public function addPseudoClass(XPathExpr $xpath, $pseudoClass)
{
if (!isset($this->pseudoClassTranslators[$pseudoClass])) {
throw new ExpressionErrorException(sprintf('Pseudo-class "%s" not supported.', $pseudoClass));
}

return call_user_func($this->pseudoClassTranslators[$pseudoClass], $xpath);
}











public function addAttributeMatching(XPathExpr $xpath, $operator, $attribute, $value)
{
if (!isset($this->attributeMatchingTranslators[$operator])) {
throw new ExpressionErrorException(sprintf('Attribute matcher operator "%s" not supported.', $operator));
}

return call_user_func($this->attributeMatchingTranslators[$operator], $xpath, $attribute, $value);
}






private function parseSelectors($css)
{
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($cssExpr, $prefix = 'descendant-or-self::');









public function selectorToXPath(SelectorNode $selector, $prefix = 'descendant-or-self::');
}
<?php










namespace Symfony\Component\CssSelector\XPath\Extension;











abstract class AbstractExtension implements ExtensionInterface
{



public function getNodeTranslators()
{
return array();
}




public function getCombinationTranslators()
{
return array();
}




public function getFunctionTranslators()
{
return array();
}




public function getPseudoClassTranslators()
{
return array();
}




public function getAttributeMatchingTranslators()
{
return array();
}
}
<?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()
{
return array(
'root' => array($this, 'translateRoot'),
'first-child' => array($this, 'translateFirstChild'),
'last-child' => array($this, 'translateLastChild'),
'first-of-type' => array($this, 'translateFirstOfType'),
'last-of-type' => array($this, 'translateLastOfType'),
'only-child' => array($this, 'translateOnlyChild'),
'only-of-type' => array($this, 'translateOnlyOfType'),
'empty' => array($this, 'translateEmpty'),
);
}






public function translateRoot(XPathExpr $xpath)
{
return $xpath->addCondition('not(parent::*)');
}






public function translateFirstChild(XPathExpr $xpath)
{
return $xpath
->addStarPrefix()
->addNameTest()
->addCondition('position() = 1');
}






public function translateLastChild(XPathExpr $xpath)
{
return $xpath
->addStarPrefix()
->addNameTest()
->addCondition('position() = last()');
}








public function translateFirstOfType(XPathExpr $xpath)
{
if ('*' === $xpath->getElement()) {
throw new ExpressionErrorException('"*:first-of-type" is not implemented.');
}

return $xpath
->addStarPrefix()
->addCondition('position() = 1');
}








public function translateLastOfType(XPathExpr $xpath)
{
if ('*' === $xpath->getElement()) {
throw new ExpressionErrorException('"*:last-of-type" is not implemented.');
}

return $xpath
->addStarPrefix()
->addCondition('position() = last()');
}






public function translateOnlyChild(XPathExpr $xpath)
{
return $xpath
->addStarPrefix()
->addNameTest()
->addCondition('last() = 1');
}








public function translateOnlyOfType(XPathExpr $xpath)
{
if ('*' === $xpath->getElement()) {
throw new ExpressionErrorException('"*:only-of-type" is not implemented.');
}

return $xpath->addCondition('last() = 1');
}






public function translateEmpty(XPathExpr $xpath)
{
return $xpath->addCondition('not(*) and not(string-length())');
}




public function getName()
{
return 'pseudo-class';
}
}
<?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
{
const ELEMENT_NAME_IN_LOWER_CASE = 1;
const ATTRIBUTE_NAME_IN_LOWER_CASE = 2;
const ATTRIBUTE_VALUE_IN_LOWER_CASE = 4;




private $flags;






public function __construct($flags = 0)
{
$this->flags = $flags;
}







public function setFlag($flag, $on)
{
if ($on && !$this->hasFlag($flag)) {
$this->flags += $flag;
}

if (!$on && $this->hasFlag($flag)) {
$this->flags -= $flag;
}

return $this;
}






public function hasFlag($flag)
{
return $this->flags & $flag;
}




public function getNodeTranslators()
{
return array(
'Selector' => array($this, 'translateSelector'),
'CombinedSelector' => array($this, 'translateCombinedSelector'),
'Negation' => array($this, 'translateNegation'),
'Function' => array($this, 'translateFunction'),
'Pseudo' => array($this, 'translatePseudo'),
'Attribute' => array($this, 'translateAttribute'),
'Class' => array($this, 'translateClass'),
'Hash' => array($this, 'translateHash'),
'Element' => array($this, 'translateElement'),
);
}







public function translateSelector(Node\SelectorNode $node, Translator $translator)
{
return $translator->nodeToXPath($node->getTree());
}







public function translateCombinedSelector(Node\CombinedSelectorNode $node, Translator $translator)
{
return $translator->addCombination($node->getCombinator(), $node->getSelector(), $node->getSubSelector());
}







public function translateNegation(Node\NegationNode $node, Translator $translator)
{
$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)
{
$xpath = $translator->nodeToXPath($node->getSelector());

return $translator->addFunction($xpath, $node);
}







public function translatePseudo(Node\PseudoNode $node, Translator $translator)
{
$xpath = $translator->nodeToXPath($node->getSelector());

return $translator->addPseudoClass($xpath, $node->getIdentifier());
}







public function translateAttribute(Node\AttributeNode $node, Translator $translator)
{
$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)
{
$xpath = $translator->nodeToXPath($node->getSelector());

return $translator->addAttributeMatching($xpath, '~=', '@class', $node->getName());
}







public function translateHash(Node\HashNode $node, Translator $translator)
{
$xpath = $translator->nodeToXPath($node->getSelector());

return $translator->addAttributeMatching($xpath, '=', '@id', $node->getId());
}






public function translateElement(Node\ElementNode $node)
{
$element = $node->getElement();

if ($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()
{
return 'node';
}








private function isSafeName($name)
{
return 0 < preg_match('~^[a-zA-Z_][a-zA-Z0-9_.-]*$~', $name);
}
}
<?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()
{
return array(
'exists' => array($this, 'translateExists'),
'=' => array($this, 'translateEquals'),
'~=' => array($this, 'translateIncludes'),
'|=' => array($this, 'translateDashMatch'),
'^=' => array($this, 'translatePrefixMatch'),
'$=' => array($this, 'translateSuffixMatch'),
'*=' => array($this, 'translateSubstringMatch'),
'!=' => array($this, 'translateDifferent'),
);
}








public function translateExists(XPathExpr $xpath, $attribute, $value)
{
return $xpath->addCondition($attribute);
}








public function translateEquals(XPathExpr $xpath, $attribute, $value)
{
return $xpath->addCondition(sprintf('%s = %s', $attribute, Translator::getXpathLiteral($value)));
}








public function translateIncludes(XPathExpr $xpath, $attribute, $value)
{
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, $attribute, $value)
{
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, $attribute, $value)
{
return $xpath->addCondition($value ? sprintf(
'%1$s and starts-with(%1$s, %2$s)',
$attribute,
Translator::getXpathLiteral($value)
) : '0');
}








public function translateSuffixMatch(XPathExpr $xpath, $attribute, $value)
{
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, $attribute, $value)
{
return $xpath->addCondition($value ? sprintf(
'%1$s and contains(%1$s, %2$s)',
$attribute,
Translator::getXpathLiteral($value)
) : '0');
}








public function translateDifferent(XPathExpr $xpath, $attribute, $value)
{
return $xpath->addCondition(sprintf(
$value ? 'not(%1$s) or %1$s != %2$s' : '%s != %s',
$attribute,
Translator::getXpathLiteral($value)
));
}




public function getName()
{
return 'attribute-matching';
}
}
<?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()
{
return array(
'nth-child' => array($this, 'translateNthChild'),
'nth-last-child' => array($this, 'translateNthLastChild'),
'nth-of-type' => array($this, 'translateNthOfType'),
'nth-last-of-type' => array($this, 'translateNthLastOfType'),
'contains' => array($this, 'translateContains'),
'lang' => array($this, 'translateLang'),
);
}











public function translateNthChild(XPathExpr $xpath, FunctionNode $function, $last = false, $addNameTest = true)
{
try {
list($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 = array(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)
{
return $this->translateNthChild($xpath, $function, true);
}







public function translateNthOfType(XPathExpr $xpath, FunctionNode $function)
{
return $this->translateNthChild($xpath, $function, false, false);
}









public function translateNthLastOfType(XPathExpr $xpath, FunctionNode $function)
{
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)
{
$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)
{
$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()
{
return 'function';
}
}
<?php










namespace Symfony\Component\CssSelector\XPath\Extension;

use Symfony\Component\CssSelector\XPath\XPathExpr;











class CombinationExtension extends AbstractExtension
{



public function getCombinationTranslators()
{
return array(
' ' => array($this, 'translateDescendant'),
'>' => array($this, 'translateChild'),
'+' => array($this, 'translateDirectAdjacent'),
'~' => array($this, 'translateIndirectAdjacent'),
);
}







public function translateDescendant(XPathExpr $xpath, XPathExpr $combinedXpath)
{
return $xpath->join('/descendant-or-self::*/', $combinedXpath);
}







public function translateChild(XPathExpr $xpath, XPathExpr $combinedXpath)
{
return $xpath->join('/', $combinedXpath);
}







public function translateDirectAdjacent(XPathExpr $xpath, XPathExpr $combinedXpath)
{
return $xpath
->join('/following-sibling::', $combinedXpath)
->addNameTest()
->addCondition('position() = 1');
}







public function translateIndirectAdjacent(XPathExpr $xpath, XPathExpr $combinedXpath)
{
return $xpath->join('/following-sibling::', $combinedXpath);
}




public function getName()
{
return 'combination';
}
}
<?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()
{
return array(
'checked' => array($this, 'translateChecked'),
'link' => array($this, 'translateLink'),
'disabled' => array($this, 'translateDisabled'),
'enabled' => array($this, 'translateEnabled'),
'selected' => array($this, 'translateSelected'),
'invalid' => array($this, 'translateInvalid'),
'hover' => array($this, 'translateHover'),
'visited' => array($this, 'translateVisited'),
);
}




public function getFunctionTranslators()
{
return array(
'lang' => array($this, 'translateLang'),
);
}






public function translateChecked(XPathExpr $xpath)
{
return $xpath->addCondition(
'(@checked '
."and (name(.) = 'input' or name(.) = 'command')"
."and (@type = 'checkbox' or @type = 'radio'))"
);
}






public function translateLink(XPathExpr $xpath)
{
return $xpath->addCondition("@href and (name(.) = 'a' or name(.) = 'link' or name(.) = 'area')");
}






public function translateDisabled(XPathExpr $xpath)
{
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)
{
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)
{
$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)
{
return $xpath->addCondition("(@selected and name(.) = 'option')");
}






public function translateInvalid(XPathExpr $xpath)
{
return $xpath->addCondition('0');
}






public function translateHover(XPathExpr $xpath)
{
return $xpath->addCondition('0');
}






public function translateVisited(XPathExpr $xpath)
{
return $xpath->addCondition('0');
}




public function getName()
{
return 'html';
}
}
<?php










namespace Symfony\Component\CssSelector\XPath\Extension;











interface ExtensionInterface
{







public function getNodeTranslators();






public function getCombinationTranslators();






public function getFunctionTranslators();






public function getPseudoClassTranslators();






public function getAttributeMatchingTranslators();






public function getName();
}
<?php










namespace Symfony\Component\CssSelector;

@trigger_error('The '.__NAMESPACE__.'\CssSelector class is deprecated since version 2.8 and will be removed in 3.0. Use directly the \Symfony\Component\CssSelector\CssSelectorConverter class instead.', E_USER_DEPRECATED);















































class CssSelector
{
private static $html = true;











public static function toXPath($cssExpr, $prefix = 'descendant-or-self::')
{
$converter = new CssSelectorConverter(self::$html);

return $converter->toXPath($cssExpr, $prefix);
}




public static function enableHtmlExtension()
{
self::$html = true;
}




public static function disableHtmlExtension()
{
self::$html = false;
}
}
<?php










namespace Symfony\Component\CssSelector\Node;











class ClassNode extends AbstractNode
{



private $selector;




private $name;





public function __construct(NodeInterface $selector, $name)
{
$this->selector = $selector;
$this->name = $name;
}




public function getSelector()
{
return $this->selector;
}




public function getName()
{
return $this->name;
}




public function getSpecificity()
{
return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
}




public function __toString()
{
return sprintf('%s[%s.%s]', $this->getNodeName(), $this->selector, $this->name);
}
}
<?php










namespace Symfony\Component\CssSelector\Node;











class SelectorNode extends AbstractNode
{



private $tree;




private $pseudoElement;





public function __construct(NodeInterface $tree, $pseudoElement = null)
{
$this->tree = $tree;
$this->pseudoElement = $pseudoElement ? strtolower($pseudoElement) : null;
}




public function getTree()
{
return $this->tree;
}




public function getPseudoElement()
{
return $this->pseudoElement;
}




public function getSpecificity()
{
return $this->tree->getSpecificity()->plus(new Specificity(0, 0, $this->pseudoElement ? 1 : 0));
}




public function __toString()
{
return sprintf('%s[%s%s]', $this->getNodeName(), $this->tree, $this->pseudoElement ? '::'.$this->pseudoElement : '');
}
}
<?php










namespace Symfony\Component\CssSelector\Node;













class Specificity
{
const A_FACTOR = 100;
const B_FACTOR = 10;
const C_FACTOR = 1;




private $a;




private $b;




private $c;








public function __construct($a, $b, $c)
{
$this->a = $a;
$this->b = $b;
$this->c = $c;
}






public function plus(Specificity $specificity)
{
return new self($this->a + $specificity->a, $this->b + $specificity->b, $this->c + $specificity->c);
}






public function getValue()
{
return $this->a * self::A_FACTOR + $this->b * self::B_FACTOR + $this->c * self::C_FACTOR;
}









public function compareTo(Specificity $specificity)
{
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;

use Symfony\Component\CssSelector\Parser\Token;











class FunctionNode extends AbstractNode
{



private $selector;




private $name;




private $arguments;






public function __construct(NodeInterface $selector, $name, array $arguments = array())
{
$this->selector = $selector;
$this->name = strtolower($name);
$this->arguments = $arguments;
}




public function getSelector()
{
return $this->selector;
}




public function getName()
{
return $this->name;
}




public function getArguments()
{
return $this->arguments;
}




public function getSpecificity()
{
return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
}




public function __toString()
{
$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 PseudoNode extends AbstractNode
{



private $selector;




private $identifier;





public function __construct(NodeInterface $selector, $identifier)
{
$this->selector = $selector;
$this->identifier = strtolower($identifier);
}




public function getSelector()
{
return $this->selector;
}




public function getIdentifier()
{
return $this->identifier;
}




public function getSpecificity()
{
return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
}




public function __toString()
{
return sprintf('%s[%s:%s]', $this->getNodeName(), $this->selector, $this->identifier);
}
}
<?php










namespace Symfony\Component\CssSelector\Node;











class ElementNode extends AbstractNode
{



private $namespace;




private $element;





public function __construct($namespace = null, $element = null)
{
$this->namespace = $namespace;
$this->element = $element;
}




public function getNamespace()
{
return $this->namespace;
}




public function getElement()
{
return $this->element;
}




public function getSpecificity()
{
return new Specificity(0, 0, $this->element ? 1 : 0);
}




public function __toString()
{
$element = $this->element ?: '*';

return sprintf('%s[%s]', $this->getNodeName(), $this->namespace ? $this->namespace.'|'.$element : $element);
}
}
<?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()
{
return $this->selector;
}




public function getSubSelector()
{
return $this->subSelector;
}




public function getSpecificity()
{
return $this->selector->getSpecificity()->plus($this->subSelector->getSpecificity());
}




public function __toString()
{
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()
{
if (null === $this->nodeName) {
$this->nodeName = preg_replace('~.*\\\\([^\\\\]+)Node$~', '$1', get_called_class());
}

return $this->nodeName;
}
}
<?php










namespace Symfony\Component\CssSelector\Node;











class HashNode extends AbstractNode
{



private $selector;




private $id;





public function __construct(NodeInterface $selector, $id)
{
$this->selector = $selector;
$this->id = $id;
}




public function getSelector()
{
return $this->selector;
}




public function getId()
{
return $this->id;
}




public function getSpecificity()
{
return $this->selector->getSpecificity()->plus(new Specificity(1, 0, 0));
}




public function __toString()
{
return sprintf('%s[%s#%s]', $this->getNodeName(), $this->selector, $this->id);
}
}
<?php










namespace Symfony\Component\CssSelector\Node;











class CombinedSelectorNode extends AbstractNode
{



private $selector;




private $combinator;




private $subSelector;






public function __construct(NodeInterface $selector, $combinator, NodeInterface $subSelector)
{
$this->selector = $selector;
$this->combinator = $combinator;
$this->subSelector = $subSelector;
}




public function getSelector()
{
return $this->selector;
}




public function getCombinator()
{
return $this->combinator;
}




public function getSubSelector()
{
return $this->subSelector;
}




public function getSpecificity()
{
return $this->selector->getSpecificity()->plus($this->subSelector->getSpecificity());
}




public function __toString()
{
$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;











interface NodeInterface
{





public function getNodeName();






public function getSpecificity();






public function __toString();
}
<?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, $namespace, $attribute, $operator, $value)
{
$this->selector = $selector;
$this->namespace = $namespace;
$this->attribute = $attribute;
$this->operator = $operator;
$this->value = $value;
}




public function getSelector()
{
return $this->selector;
}




public function getNamespace()
{
return $this->namespace;
}




public function getAttribute()
{
return $this->attribute;
}




public function getOperator()
{
return $this->operator;
}




public function getValue()
{
return $this->value;
}




public function getSpecificity()
{
return $this->selector->getSpecificity()->plus(new Specificity(0, 1, 0));
}




public function __toString()
{
$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\Parser\Handler;

use Symfony\Component\CssSelector\Parser\Reader;
use Symfony\Component\CssSelector\Parser\Token;
use Symfony\Component\CssSelector\Parser\TokenStream;
use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;











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)
{
$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\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)
{
$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;











interface HandlerInterface
{






public function handle(Reader $reader, TokenStream $stream);
}
<?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;
use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;











class NumberHandler implements HandlerInterface
{



private $patterns;




public function __construct(TokenizerPatterns $patterns)
{
$this->patterns = $patterns;
}




public function handle(Reader $reader, TokenStream $stream)
{
$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\Token;
use Symfony\Component\CssSelector\Parser\TokenStream;
use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;











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)
{
$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\TokenStream;











class CommentHandler implements HandlerInterface
{



public function handle(Reader $reader, TokenStream $stream)
{
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\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\TokenStream;
use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerEscaping;
use Symfony\Component\CssSelector\Parser\Tokenizer\TokenizerPatterns;











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)
{
$quote = $reader->getSubstring(1);

if (!in_array($quote, array("'", '"'))) {
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 %s.', $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;

use Symfony\Component\CssSelector\Node\SelectorNode;











interface ParserInterface
{







public function parse($source);
}
<?php










namespace Symfony\Component\CssSelector\Parser;











class Token
{
const TYPE_FILE_END = 'eof';
const TYPE_DELIMITER = 'delimiter';
const TYPE_WHITESPACE = 'whitespace';
const TYPE_IDENTIFIER = 'identifier';
const TYPE_HASH = 'hash';
const TYPE_NUMBER = 'number';
const TYPE_STRING = 'string';




private $type;




private $value;




private $position;






public function __construct($type, $value, $position)
{
$this->type = $type;
$this->value = $value;
$this->position = $position;
}




public function getType()
{
return $this->type;
}




public function getValue()
{
return $this->value;
}




public function getPosition()
{
return $this->position;
}




public function isFileEnd()
{
return self::TYPE_FILE_END === $this->type;
}






public function isDelimiter(array $values = array())
{
if (self::TYPE_DELIMITER !== $this->type) {
return false;
}

if (empty($values)) {
return true;
}

return in_array($this->value, $values);
}




public function isWhitespace()
{
return self::TYPE_WHITESPACE === $this->type;
}




public function isIdentifier()
{
return self::TYPE_IDENTIFIER === $this->type;
}




public function isHash()
{
return self::TYPE_HASH === $this->type;
}




public function isNumber()
{
return self::TYPE_NUMBER === $this->type;
}




public function isString()
{
return self::TYPE_STRING === $this->type;
}




public function __toString()
{
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\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($source)
{

 
 
 
 
 
 if (preg_match('/^(?:([a-z]++)\|)?([\w-]++|\*)$/i', trim($source), $matches)) {
return array(new SelectorNode(new ElementNode($matches[1] ?: null, $matches[2])));
}

return array();
}
}
<?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($source)
{

 
 
 
 
 
 
 if (preg_match('/^(?:([a-z]++)\|)?+([\w-]++|\*)?+\.([\w-]++)$/i', trim($source), $matches)) {
return array(
new SelectorNode(new ClassNode(new ElementNode($matches[1] ?: null, $matches[2] ?: null), $matches[3])),
);
}

return 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($source)
{

 
 
 
 
 
 
 if (preg_match('/^(?:([a-z]++)\|)?+([\w-]++|\*)?+#([\w-]++)$/i', trim($source), $matches)) {
return array(
new SelectorNode(new HashNode(new ElementNode($matches[1] ?: null, $matches[2] ?: null), $matches[3])),
);
}

return array();
}
}
<?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($source)
{

 if ($source == '') {
return array(new SelectorNode(new ElementNode(null, '*')));
}

return array();
}
}
<?php










namespace Symfony\Component\CssSelector\Parser;

use Symfony\Component\CssSelector\Exception\InternalErrorException;
use Symfony\Component\CssSelector\Exception\SyntaxErrorException;











class TokenStream
{



private $tokens = array();




private $frozen = false;




private $used = array();




private $cursor = 0;




private $peeked = null;




private $peeking = false;








public function push(Token $token)
{
$this->tokens[] = $token;

return $this;
}






public function freeze()
{
$this->frozen = true;

return $this;
}








public function getNext()
{
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()
{
if (!$this->peeking) {
$this->peeked = $this->getNext();
$this->peeking = true;
}

return $this->peeked;
}






public function getUsed()
{
return $this->used;
}








public function getNextIdentifier()
{
$next = $this->getNext();

if (!$next->isIdentifier()) {
throw SyntaxErrorException::unexpectedToken('identifier', $next);
}

return $next->getValue();
}








public function getNextIdentifierOrStar()
{
$next = $this->getNext();

if ($next->isIdentifier()) {
return $next->getValue();
}

if ($next->isDelimiter(array('*'))) {
return;
}

throw SyntaxErrorException::unexpectedToken('identifier or "*"', $next);
}




public function skipWhitespace()
{
$peek = $this->getPeek();

if ($peek->isWhitespace()) {
$this->getNext();
}
}
}
<?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($source)
{
$reader = new Reader($source);
$stream = $this->tokenizer->tokenize($reader);

return $this->parseSelectorList($stream);
}










public static function parseSeries(array $tokens)
{
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 array(2, 1);
case 'even' === $joined:
return array(2, 0);
case 'n' === $joined:
return array(1, 0);
case false === strpos($joined, 'n'):
return array(0, $int($joined));
}

$split = explode('n', $joined);
$first = isset($split[0]) ? $split[0] : null;

return array(
$first ? ('-' === $first || '+' === $first ? $int($first.'1') : $int($first)) : 1,
isset($split[1]) && $split[1] ? $int($split[1]) : 0,
);
}








private function parseSelectorList(TokenStream $stream)
{
$stream->skipWhitespace();
$selectors = array();

while (true) {
$selectors[] = $this->parserSelectorNode($stream);

if ($stream->getPeek()->isDelimiter(array(','))) {
$stream->getNext();
$stream->skipWhitespace();
} else {
break;
}
}

return $selectors;
}










private function parserSelectorNode(TokenStream $stream)
{
list($result, $pseudoElement) = $this->parseSimpleSelector($stream);

while (true) {
$stream->skipWhitespace();
$peek = $stream->getPeek();

if ($peek->isFileEnd() || $peek->isDelimiter(array(','))) {
break;
}

if (null !== $pseudoElement) {
throw SyntaxErrorException::pseudoElementFound($pseudoElement, 'not at the end of a selector');
}

if ($peek->isDelimiter(array('+', '>', '~'))) {
$combinator = $stream->getNext()->getValue();
$stream->skipWhitespace();
} else {
$combinator = ' ';
}

list($nextSelector, $pseudoElement) = $this->parseSimpleSelector($stream);
$result = new Node\CombinedSelectorNode($result, $combinator, $nextSelector);
}

return new Node\SelectorNode($result, $pseudoElement);
}











private function parseSimpleSelector(TokenStream $stream, $insideNegation = false)
{
$stream->skipWhitespace();

$selectorStart = count($stream->getUsed());
$result = $this->parseElementNode($stream);
$pseudoElement = null;

while (true) {
$peek = $stream->getPeek();
if ($peek->isWhitespace()
|| $peek->isFileEnd()
|| $peek->isDelimiter(array(',', '+', '>', '~'))
|| ($insideNegation && $peek->isDelimiter(array(')')))
) {
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(array('.'))) {
$stream->getNext();
$result = new Node\ClassNode($result, $stream->getNextIdentifier());
} elseif ($peek->isDelimiter(array('['))) {
$stream->getNext();
$result = $this->parseAttributeNode($result, $stream);
} elseif ($peek->isDelimiter(array(':'))) {
$stream->getNext();

if ($stream->getPeek()->isDelimiter(array(':'))) {
$stream->getNext();
$pseudoElement = $stream->getNextIdentifier();

continue;
}

$identifier = $stream->getNextIdentifier();
if (in_array(strtolower($identifier), array('first-line', 'first-letter', 'before', 'after'))) {

 
 $pseudoElement = $identifier;

continue;
}

if (!$stream->getPeek()->isDelimiter(array('('))) {
$result = new Node\PseudoNode($result, $identifier);

continue;
}

$stream->getNext();
$stream->skipWhitespace();

if ('not' === strtolower($identifier)) {
if ($insideNegation) {
throw SyntaxErrorException::nestedNot();
}

list($argument, $argumentPseudoElement) = $this->parseSimpleSelector($stream, true);
$next = $stream->getNext();

if (null !== $argumentPseudoElement) {
throw SyntaxErrorException::pseudoElementFound($argumentPseudoElement, 'inside ::not()');
}

if (!$next->isDelimiter(array(')'))) {
throw SyntaxErrorException::unexpectedToken('")"', $next);
}

$result = new Node\NegationNode($result, $argument);
} else {
$arguments = array();
$next = null;

while (true) {
$stream->skipWhitespace();
$next = $stream->getNext();

if ($next->isIdentifier()
|| $next->isString()
|| $next->isNumber()
|| $next->isDelimiter(array('+', '-'))
) {
$arguments[] = $next;
} elseif ($next->isDelimiter(array(')'))) {
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 array($result, $pseudoElement);
}








private function parseElementNode(TokenStream $stream)
{
$peek = $stream->getPeek();

if ($peek->isIdentifier() || $peek->isDelimiter(array('*'))) {
if ($peek->isIdentifier()) {
$namespace = $stream->getNext()->getValue();
} else {
$stream->getNext();
$namespace = null;
}

if ($stream->getPeek()->isDelimiter(array('|'))) {
$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)
{
$stream->skipWhitespace();
$attribute = $stream->getNextIdentifierOrStar();

if (null === $attribute && !$stream->getPeek()->isDelimiter(array('|'))) {
throw SyntaxErrorException::unexpectedToken('"|"', $stream->getPeek());
}

if ($stream->getPeek()->isDelimiter(array('|'))) {
$stream->getNext();

if ($stream->getPeek()->isDelimiter(array('='))) {
$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(array(']'))) {
return new Node\AttributeNode($selector, $namespace, $attribute, 'exists', null);
} elseif ($next->isDelimiter(array('='))) {
$operator = '=';
} elseif ($next->isDelimiter(array('^', '$', '*', '~', '|', '!'))
&& $stream->getPeek()->isDelimiter(array('='))
) {
$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(array(']'))) {
throw SyntaxErrorException::unexpectedToken('"]"', $next);
}

return new Node\AttributeNode($selector, $namespace, $attribute, $operator, $value->getValue());
}
}
<?php










namespace Symfony\Component\CssSelector\Parser;











class Reader
{



private $source;




private $length;




private $position = 0;




public function __construct($source)
{
$this->source = $source;
$this->length = strlen($source);
}




public function isEOF()
{
return $this->position >= $this->length;
}




public function getPosition()
{
return $this->position;
}




public function getRemainingLength()
{
return $this->length - $this->position;
}







public function getSubstring($length, $offset = 0)
{
return substr($this->source, $this->position + $offset, $length);
}






public function getOffset($string)
{
$position = strpos($this->source, $string, $this->position);

return false === $position ? false : $position - $this->position;
}






public function findPattern($pattern)
{
$source = substr($this->source, $this->position);

if (preg_match($pattern, $source, $matches)) {
return $matches;
}

return false;
}




public function moveForward($length)
{
$this->position += $length;
}



public function moveToEnd()
{
$this->position = $this->length;
}
}
<?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()
{
return '~^'.$this->newLineEscapePattern.'~';
}




public function getSimpleEscapePattern()
{
return '~^'.$this->simpleEscapePattern.'~';
}




public function getUnicodeEscapePattern()
{
return '~^'.$this->unicodeEscapePattern.'~i';
}




public function getIdentifierPattern()
{
return '~^'.$this->identifierPattern.'~i';
}




public function getHashPattern()
{
return '~^'.$this->hashPattern.'~i';
}




public function getNumberPattern()
{
return '~^'.$this->numberPattern.'~';
}






public function getQuotedStringPattern($quote)
{
return '~^'.sprintf($this->quotedStringPattern, $quote).'~i';
}
}
<?php










namespace Symfony\Component\CssSelector\Parser\Tokenizer;











class TokenizerEscaping
{



private $patterns;




public function __construct(TokenizerPatterns $patterns)
{
$this->patterns = $patterns;
}






public function escapeUnicode($value)
{
$value = $this->replaceUnicodeSequences($value);

return preg_replace($this->patterns->getSimpleEscapePattern(), '$1', $value);
}






public function escapeUnicodeAndNewLine($value)
{
$value = preg_replace($this->patterns->getNewLineEscapePattern(), '', $value);

return $this->escapeUnicode($value);
}






private function replaceUnicodeSequences($value)
{
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);
}
}, $value);
}
}
<?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 = array(
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)
{
$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\Exception;









interface ExceptionInterface
{
}
<?php










namespace Symfony\Component\CssSelector\Exception;









class ExpressionErrorException extends ParseException
{
}
<?php










namespace Symfony\Component\CssSelector\Exception;









class ParseException extends \Exception implements ExceptionInterface
{
}
<?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 InternalErrorException extends ParseException
{
}
<?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($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










use Symfony\Polyfill\Mbstring as p;

if (!function_exists('mb_strlen')) {
define('MB_CASE_UPPER', 0);
define('MB_CASE_LOWER', 1);
define('MB_CASE_TITLE', 2);

function mb_convert_encoding($s, $to, $from = null) { return p\Mbstring::mb_convert_encoding($s, $to, $from); }
function mb_decode_mimeheader($s) { return p\Mbstring::mb_decode_mimeheader($s); }
function mb_encode_mimeheader($s, $charset = null, $transferEnc = null, $lf = null, $indent = null) { return p\Mbstring::mb_encode_mimeheader($s, $charset, $transferEnc, $lf, $indent); }
function mb_convert_case($s, $mode, $enc = null) { return p\Mbstring::mb_convert_case($s, $mode, $enc); }
function mb_internal_encoding($enc = null) { return p\Mbstring::mb_internal_encoding($enc); }
function mb_language($lang = null) { return p\Mbstring::mb_language($lang); }
function mb_list_encodings() { return p\Mbstring::mb_list_encodings(); }
function mb_encoding_aliases($encoding) { return p\Mbstring::mb_encoding_aliases($encoding); }
function mb_check_encoding($var = null, $encoding = null) { return p\Mbstring::mb_check_encoding($var, $encoding); }
function mb_detect_encoding($str, $encodingList = null, $strict = false) { return p\Mbstring::mb_detect_encoding($str, $encodingList, $strict); }
function mb_detect_order($encodingList = null) { return p\Mbstring::mb_detect_order($encodingList); }
function mb_parse_str($s, &$result = array()) { parse_str($s, $result); }
function mb_strlen($s, $enc = null) { return p\Mbstring::mb_strlen($s, $enc); }
function mb_strpos($s, $needle, $offset = 0, $enc = null) { return p\Mbstring::mb_strpos($s, $needle, $offset, $enc); }
function mb_strtolower($s, $enc = null) { return p\Mbstring::mb_strtolower($s, $enc); }
function mb_strtoupper($s, $enc = null) { return p\Mbstring::mb_strtoupper($s, $enc); }
function mb_substitute_character($char = null) { return p\Mbstring::mb_substitute_character($char); }
function mb_substr($s, $start, $length = 2147483647, $enc = null) { return p\Mbstring::mb_substr($s, $start, $length, $enc); }
function mb_stripos($s, $needle, $offset = 0, $enc = null) { return p\Mbstring::mb_stripos($s, $needle, $offset, $enc); }
function mb_stristr($s, $needle, $part = false, $enc = null) { return p\Mbstring::mb_stristr($s, $needle, $part, $enc); }
function mb_strrchr($s, $needle, $part = false, $enc = null) { return p\Mbstring::mb_strrchr($s, $needle, $part, $enc); }
function mb_strrichr($s, $needle, $part = false, $enc = null) { return p\Mbstring::mb_strrichr($s, $needle, $part, $enc); }
function mb_strripos($s, $needle, $offset = 0, $enc = null) { return p\Mbstring::mb_strripos($s, $needle, $offset, $enc); }
function mb_strrpos($s, $needle, $offset = 0, $enc = null) { return p\Mbstring::mb_strrpos($s, $needle, $offset, $enc); }
function mb_strstr($s, $needle, $part = false, $enc = null) { return p\Mbstring::mb_strstr($s, $needle, $part, $enc); }
function mb_get_info($type = 'all') { return p\Mbstring::mb_get_info($type); }
function mb_http_output($enc = null) { return p\Mbstring::mb_http_output($enc); }
function mb_strwidth($s, $enc = null) { return p\Mbstring::mb_strwidth($s, $enc); }
function mb_substr_count($haystack, $needle, $enc = null) { return p\Mbstring::mb_substr_count($haystack, $needle, $enc); }
function mb_output_handler($contents, $status) { return p\Mbstring::mb_output_handler($contents, $status); }
function mb_http_input($type = '') { return p\Mbstring::mb_http_input($type); }
function mb_convert_variables($toEncoding, $fromEncoding, &$a = null, &$b = null, &$c = null, &$d = null, &$e = null, &$f = null) { return p\Mbstring::mb_convert_variables($toEncoding, $fromEncoding, $v0, $a, $b, $c, $d, $e, $f); }
}
<?php










namespace Symfony\Polyfill\Mbstring;


















































final class Mbstring
{
const MB_CASE_FOLD = PHP_INT_MAX;

private static $encodingList = array('ASCII', 'UTF-8');
private static $language = 'neutral';
private static $internalEncoding = 'UTF-8';
private static $caseFold = array(
array('µ','ſ',"\xCD\x85",'ς',"\xCF\x90","\xCF\x91","\xCF\x95","\xCF\x96","\xCF\xB0","\xCF\xB1","\xCF\xB5","\xE1\xBA\x9B","\xE1\xBE\xBE"),
array('μ','s','ι', 'σ','β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1",'ι'),
);

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', $s);
}

return preg_replace_callback('/[\x80-\xFF]+/', array(__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, $s);
}

public static function mb_convert_variables($toEncoding, $fromEncoding, &$a = null, &$b = null, &$c = null, &$d = null, &$e = null, &$f = null)
{
$vars = array(&$a, &$b, &$c, &$d, &$e, &$f);

$ok = true;
array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) {
if (false === $v = Mbstring::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_convert_case($s, $mode, $encoding = null)
{
if ('' === $s .= '') {
return '';
}

$encoding = self::getEncoding($encoding);

if ('UTF-8' === $encoding) {
$encoding = null;
} else {
$s = iconv($encoding, 'UTF-8', $s);
}

if (MB_CASE_TITLE == $mode) {
$s = preg_replace_callback('/\b\p{Ll}/u', array(__CLASS__, 'title_case_upper'), $s);
$s = preg_replace_callback('/\B[\p{Lu}\p{Lt}]+/u', array(__CLASS__, 'title_case_lower'), $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::$caseFold[0], self::$caseFold[1], $s);
}

static $lower = null;
if (null === $lower) {
$lower = self::getData('lowerCase');
}
$map = $lower;
}

static $ulenMask = array("\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, $s);
}

public static function mb_internal_encoding($encoding = null)
{
if (null === $encoding) {
return self::$internalEncoding;
}

$encoding = self::getEncoding($encoding);

if ('UTF-8' === $encoding || false !== @iconv($encoding, $encoding, ' ')) {
self::$internalEncoding = $encoding;

return true;
}

return false;
}

public static function mb_language($lang = null)
{
if (null === $lang) {
return self::$language;
}

switch ($lang = strtolower($lang)) {
case 'uni':
case 'neutral':
self::$language = $lang;

return true;
}

return false;
}

public static function mb_list_encodings()
{
return array('UTF-8');
}

public static function mb_encoding_aliases($encoding)
{
switch (strtoupper($encoding)) {
case 'UTF8':
case 'UTF-8':
return array('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, array($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);

return iconv_strlen($s, $encoding);
}

public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null)
{
$encoding = self::getEncoding($encoding);

if ('' === $needle .= '') {
trigger_error(__METHOD__.': Empty delimiter', E_USER_WARNING);

return false;
}

return iconv_strpos($haystack, $needle, $offset, $encoding);
}

public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null)
{
$encoding = self::getEncoding($encoding);

if ($offset != (int) $offset) {
$offset = 0;
} elseif ($offset = (int) $offset) {
if ($offset < 0) {
$haystack = self::mb_substr($haystack, 0, $offset, $encoding);
$offset = 0;
} else {
$haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding);
}
}

$pos = iconv_strrpos($haystack, $needle, $encoding);

return false !== $pos ? $offset + $pos : false;
}

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 (0 === strcasecmp($c, 'none')) {
return true;
}

return null !== $c ? false : 'none';
}

public static function mb_substr($s, $start, $length = null, $encoding = null)
{
$encoding = self::getEncoding($encoding);

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 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);
$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 = array(
'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', $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;
}

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($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_lower($s)
{
return self::mb_convert_case($s[0], MB_CASE_LOWER, 'UTF-8');
}

private static function title_case_upper($s)
{
return self::mb_convert_case($s[0], MB_CASE_UPPER, 'UTF-8');
}

private static function getData($file)
{
if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.ser')) {
return unserialize(file_get_contents($file));
}

return false;
}

private static function getEncoding($encoding)
{
if (null === $encoding) {
return self::$internalEncoding;
}

$encoding = strtoupper($encoding);

if ('8BIT' === $encoding || 'BINARY' === $encoding) {
return 'CP850';
}
if ('UTF8' === $encoding) {
return 'UTF-8';
}

return $encoding;
}
}
<?php










namespace Symfony\Component\Console\Style;

use Symfony\Component\Console\Application;
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\Input\InputInterface;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Question\Question;






class SymfonyStyle extends OutputStyle
{
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 BufferedOutput($output->getVerbosity(), false, clone $output->getFormatter());

 $this->lineLength = min($this->getTerminalWidth() - (int) (DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH);

parent::__construct($output);
}










public function block($messages, $type = null, $style = null, $prefix = ' ', $padding = false)
{
$this->autoPrependBlock();
$messages = is_array($messages) ? array_values($messages) : array($messages);
$lines = array();


 if (null !== $type) {
$messages[0] = sprintf('[%s] %s', $type, $messages[0]);
}


 foreach ($messages as $key => $message) {
$message = OutputFormatter::escape($message);
$lines = array_merge($lines, explode(PHP_EOL, wordwrap($message, $this->lineLength - Helper::strlen($prefix), PHP_EOL, true)));

if (count($messages) > 1 && $key < count($messages) - 1) {
$lines[] = '';
}
}

if ($padding && $this->isDecorated()) {
array_unshift($lines, '');
$lines[] = '';
}

foreach ($lines as &$line) {
$line = sprintf('%s%s', $prefix, $line);
$line .= str_repeat(' ', $this->lineLength - Helper::strlenWithoutDecoration($this->getFormatter(), $line));

if ($style) {
$line = sprintf('<%s>%s</>', $style, $line);
}
}

$this->writeln($lines);
$this->newLine();
}




public function title($message)
{
$this->autoPrependBlock();
$this->writeln(array(
sprintf('<comment>%s</>', $message),
sprintf('<comment>%s</>', str_repeat('=', Helper::strlenWithoutDecoration($this->getFormatter(), $message))),
));
$this->newLine();
}




public function section($message)
{
$this->autoPrependBlock();
$this->writeln(array(
sprintf('<comment>%s</>', $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) : array($message);
foreach ($messages as $message) {
$this->writeln(sprintf(' %s', $message));
}
}




public function comment($message)
{
$this->autoPrependText();

$messages = is_array($message) ? array_values($message) : array($message);
foreach ($messages as $message) {
$this->writeln(sprintf(' // %s', $message));
}
}




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=white;bg=red', ' ', 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)
{
$headers = array_map(function ($value) { return sprintf('<info>%s</>', $value); }, $headers);

$table = new Table($this);
$table->setHeaders($headers);
$table->setRows($rows);
$table->setStyle('symfony-style-guide');

$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];
}

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) {
$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)
{
parent::writeln($messages, $type);
$this->bufferedOutput->writeln($this->reduceBuffer($messages), $type);
}




public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)
{
parent::write($messages, $newline, $type);
$this->bufferedOutput->write($this->reduceBuffer($messages), $newline, $type);
}




public function newLine($count = 1)
{
parent::newLine($count);
$this->bufferedOutput->write(str_repeat("\n", $count));
}




private function getProgressBar()
{
if (!$this->progressBar) {
throw new RuntimeException('The ProgressBar is not started.');
}

return $this->progressBar;
}

private function getTerminalWidth()
{
$application = new Application();
$dimensions = $application->getTerminalDimensions();

return $dimensions[0] ?: self::MAX_LINE_LENGTH;
}

private function autoPrependBlock()
{
$chars = substr(str_replace(PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2);

if (!isset($chars[0])) {
return $this->newLine(); 
 }

 $this->newLine(2 - substr_count($chars, "\n"));
}

private function autoPrependText()
{
$fetched = $this->bufferedOutput->fetch();

 if ("\n" !== substr($fetched, -1)) {
$this->newLine();
}
}

private function reduceBuffer($messages)
{

 
 return array_map(function ($value) {
return substr($value, -4);
}, array_merge(array($this->bufferedOutput->fetch()), (array) $messages));
}
}
<?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\Style;

use Symfony\Component\Console\Formatter\OutputFormatterInterface;
use Symfony\Component\Console\Helper\ProgressBar;
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();
}
}
<?php










namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputAwareInterface;






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;




class TableCell
{



private $value;




private $options = array(
'rowspan' => 1,
'colspan' => 1,
);





public function __construct($value = '', array $options = array())
{
$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\RuntimeException;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;









class DialogHelper extends InputAwareHelper
{
private $inputStream;
private static $shell;
private static $stty;

public function __construct($triggerDeprecationError = true)
{
if ($triggerDeprecationError) {
@trigger_error('"Symfony\Component\Console\Helper\DialogHelper" is deprecated since version 2.5 and will be removed in 3.0. Use "Symfony\Component\Console\Helper\QuestionHelper" instead.', E_USER_DEPRECATED);
}
}
















public function select(OutputInterface $output, $question, $choices, $default = null, $attempts = false, $errorMessage = 'Value "%s" is invalid', $multiselect = false)
{
if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
}

$width = max(array_map('strlen', array_keys($choices)));

$messages = (array) $question;
foreach ($choices as $key => $value) {
$messages[] = sprintf("  [<info>%-{$width}s</info>] %s", $key, $value);
}

$output->writeln($messages);

$result = $this->askAndValidate($output, '> ', function ($picked) use ($choices, $errorMessage, $multiselect) {

 $selectedChoices = str_replace(' ', '', $picked);

if ($multiselect) {

 if (!preg_match('/^[a-zA-Z0-9_-]+(?:,[a-zA-Z0-9_-]+)*$/', $selectedChoices, $matches)) {
throw new InvalidArgumentException(sprintf($errorMessage, $picked));
}
$selectedChoices = explode(',', $selectedChoices);
} else {
$selectedChoices = array($picked);
}

$multiselectChoices = array();

foreach ($selectedChoices as $value) {
if (empty($choices[$value])) {
throw new InvalidArgumentException(sprintf($errorMessage, $value));
}
$multiselectChoices[] = $value;
}

if ($multiselect) {
return $multiselectChoices;
}

return $picked;
}, $attempts, $default);

return $result;
}













public function ask(OutputInterface $output, $question, $default = null, array $autocomplete = null)
{
if ($this->input && !$this->input->isInteractive()) {
return $default;
}

if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
}

$output->write($question);

$inputStream = $this->inputStream ?: STDIN;

if (null === $autocomplete || !$this->hasSttyAvailable()) {
$ret = fgets($inputStream, 4096);
if (false === $ret) {
throw new RuntimeException('Aborted');
}
$ret = trim($ret);
} else {
$ret = '';

$i = 0;
$ofs = -1;
$matches = $autocomplete;
$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 ("\177" === $c) {
if (0 === $numMatches && 0 !== $i) {
--$i;

 $output->write("\033[1D");
}

if ($i === 0) {
$ofs = -1;
$matches = $autocomplete;
$numMatches = count($matches);
} else {
$numMatches = 0;
}


 $ret = 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 = $matches[$ofs];

 $output->write(substr($ret, $i));
$i = strlen($ret);
}

if ("\n" === $c) {
$output->write($c);
break;
}

$numMatches = 0;
}

continue;
} else {
$output->write($c);
$ret .= $c;
++$i;

$numMatches = 0;
$ofs = 0;

foreach ($autocomplete as $value) {

 if (0 === strpos($value, $ret) && $i !== strlen($value)) {
$matches[$numMatches++] = $value;
}
}
}


 $output->write("\033[K");

if ($numMatches > 0 && -1 !== $ofs) {

 $output->write("\0337");

 $output->write('<hl>'.substr($matches[$ofs], $i).'</hl>');

 $output->write("\0338");
}
}


 shell_exec(sprintf('stty %s', $sttyMode));
}

return strlen($ret) > 0 ? $ret : $default;
}












public function askConfirmation(OutputInterface $output, $question, $default = true)
{
$answer = 'z';
while ($answer && !in_array(strtolower($answer[0]), array('y', 'n'))) {
$answer = $this->ask($output, $question);
}

if (false === $default) {
return $answer && 'y' == strtolower($answer[0]);
}

return !$answer || 'y' == strtolower($answer[0]);
}












public function askHiddenResponse(OutputInterface $output, $question, $fallback = true)
{
if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
}

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;
}

$output->write($question);
$value = rtrim(shell_exec($exe));
$output->writeln('');

if (isset($tmpExe)) {
unlink($tmpExe);
}

return $value;
}

if ($this->hasSttyAvailable()) {
$output->write($question);

$sttyMode = shell_exec('stty -g');

shell_exec('stty -echo');
$value = fgets($this->inputStream ?: STDIN, 4096);
shell_exec(sprintf('stty %s', $sttyMode));

if (false === $value) {
throw new RuntimeException('Aborted');
}

$value = trim($value);
$output->writeln('');

return $value;
}

if (false !== $shell = $this->getShell()) {
$output->write($question);
$readCmd = $shell === 'csh' ? 'set mypassword = $<' : 'read -r mypassword';
$command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd);
$value = rtrim(shell_exec($command));
$output->writeln('');

return $value;
}

if ($fallback) {
return $this->ask($output, $question);
}

throw new RuntimeException('Unable to hide the response');
}



















public function askAndValidate(OutputInterface $output, $question, $validator, $attempts = false, $default = null, array $autocomplete = null)
{
$that = $this;

$interviewer = function () use ($output, $question, $default, $autocomplete, $that) {
return $that->ask($output, $question, $default, $autocomplete);
};

return $this->validateAttempts($interviewer, $output, $validator, $attempts);
}



















public function askHiddenResponseAndValidate(OutputInterface $output, $question, $validator, $attempts = false, $fallback = true)
{
$that = $this;

$interviewer = function () use ($output, $question, $fallback, $that) {
return $that->askHiddenResponse($output, $question, $fallback);
};

return $this->validateAttempts($interviewer, $output, $validator, $attempts);
}








public function setInputStream($stream)
{
$this->inputStream = $stream;
}






public function getInputStream()
{
return $this->inputStream;
}




public function getName()
{
return 'dialog';
}






private function getShell()
{
if (null !== self::$shell) {
return self::$shell;
}

self::$shell = false;

if (file_exists('/usr/bin/env')) {

 $test = "/usr/bin/env %s -c 'echo OK' 2> /dev/null";
foreach (array('bash', 'zsh', 'ksh', 'csh') as $sh) {
if ('OK' === rtrim(shell_exec(sprintf($test, $sh)))) {
self::$shell = $sh;
break;
}
}
}

return self::$shell;
}

private function hasSttyAvailable()
{
if (null !== self::$stty) {
return self::$stty;
}

exec('stty 2>&1', $output, $exitcode);

return self::$stty = $exitcode === 0;
}













private function validateAttempts($interviewer, OutputInterface $output, $validator, $attempts)
{
if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
}

$e = null;
while (false === $attempts || $attempts--) {
if (null !== $e) {
$output->writeln($this->getHelperSet()->get('formatter')->formatBlock($e->getMessage(), 'error'));
}

try {
return call_user_func($validator, $interviewer());
} catch (\Exception $e) {
}
}

throw $e;
}
}
<?php










namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Console\Exception\InvalidArgumentException;










class TableHelper extends Helper
{
const LAYOUT_DEFAULT = 0;
const LAYOUT_BORDERLESS = 1;
const LAYOUT_COMPACT = 2;




private $table;

public function __construct($triggerDeprecationError = true)
{
if ($triggerDeprecationError) {
@trigger_error('The '.__CLASS__.' class is deprecated since version 2.5 and will be removed in 3.0. Use the Symfony\Component\Console\Helper\Table class instead.', E_USER_DEPRECATED);
}

$this->table = new Table(new NullOutput());
}










public function setLayout($layout)
{
switch ($layout) {
case self::LAYOUT_BORDERLESS:
$this->table->setStyle('borderless');
break;

case self::LAYOUT_COMPACT:
$this->table->setStyle('compact');
break;

case self::LAYOUT_DEFAULT:
$this->table->setStyle('default');
break;

default:
throw new InvalidArgumentException(sprintf('Invalid table layout "%s".', $layout));
}

return $this;
}

public function setHeaders(array $headers)
{
$this->table->setHeaders($headers);

return $this;
}

public function setRows(array $rows)
{
$this->table->setRows($rows);

return $this;
}

public function addRows(array $rows)
{
$this->table->addRows($rows);

return $this;
}

public function addRow(array $row)
{
$this->table->addRow($row);

return $this;
}

public function setRow($column, array $row)
{
$this->table->setRow($column, $row);

return $this;
}








public function setPaddingChar($paddingChar)
{
$this->table->getStyle()->setPaddingChar($paddingChar);

return $this;
}








public function setHorizontalBorderChar($horizontalBorderChar)
{
$this->table->getStyle()->setHorizontalBorderChar($horizontalBorderChar);

return $this;
}








public function setVerticalBorderChar($verticalBorderChar)
{
$this->table->getStyle()->setVerticalBorderChar($verticalBorderChar);

return $this;
}








public function setCrossingChar($crossingChar)
{
$this->table->getStyle()->setCrossingChar($crossingChar);

return $this;
}








public function setCellHeaderFormat($cellHeaderFormat)
{
$this->table->getStyle()->setCellHeaderFormat($cellHeaderFormat);

return $this;
}








public function setCellRowFormat($cellRowFormat)
{
$this->table->getStyle()->setCellHeaderFormat($cellRowFormat);

return $this;
}








public function setCellRowContentFormat($cellRowContentFormat)
{
$this->table->getStyle()->setCellRowContentFormat($cellRowContentFormat);

return $this;
}








public function setBorderFormat($borderFormat)
{
$this->table->getStyle()->setBorderFormat($borderFormat);

return $this;
}








public function setPadType($padType)
{
$this->table->getStyle()->setPadType($padType);

return $this;
}















public function render(OutputInterface $output)
{
$p = new \ReflectionProperty($this->table, 'output');
$p->setAccessible(true);
$p->setValue($this->table, $output);

$this->table->render();
}




public function getName()
{
return 'table';
}
}
<?php










namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\InvalidArgumentException;






class HelperSet implements \IteratorAggregate
{
private $helpers = array();
private $command;






public function __construct(array $helpers = array())
{
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));
}

if ('dialog' === $name && $this->helpers[$name] instanceof DialogHelper) {
@trigger_error('"Symfony\Component\Console\Helper\DialogHelper" is deprecated since version 2.5 and will be removed in 3.0. Use "Symfony\Component\Console\Helper\QuestionHelper" instead.', E_USER_DEPRECATED);
} elseif ('progress' === $name && $this->helpers[$name] instanceof ProgressHelper) {
@trigger_error('"Symfony\Component\Console\Helper\ProgressHelper" is deprecated since version 2.5 and will be removed in 3.0. Use "Symfony\Component\Console\Helper\ProgressBar" instead.', E_USER_DEPRECATED);
} elseif ('table' === $name && $this->helpers[$name] instanceof TableHelper) {
@trigger_error('"Symfony\Component\Console\Helper\TableHelper" is deprecated since version 2.5 and will be removed in 3.0. Use "Symfony\Component\Console\Helper\Table" instead.', E_USER_DEPRECATED);
}

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\Output\OutputInterface;
use Symfony\Component\Console\Exception\InvalidArgumentException;









class Table
{





private $headers = array();






private $rows = array();






private $columnWidths = array();






private $numberOfColumns;




private $output;




private $style;




private $columnStyles = array();

private static $styles;

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 (!self::$styles[$name]) {
throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name));
}

return self::$styles[$name];
}








public function setStyle($name)
{
if ($name instanceof TableStyle) {
$this->style = $name;
} elseif (isset(self::$styles[$name])) {
$this->style = self::$styles[$name];
} else {
throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name));
}

return $this;
}






public function getStyle()
{
return $this->style;
}









public function setColumnStyle($columnIndex, $name)
{
$columnIndex = intval($columnIndex);

if ($name instanceof TableStyle) {
$this->columnStyles[$columnIndex] = $name;
} elseif (isset(self::$styles[$name])) {
$this->columnStyles[$columnIndex] = self::$styles[$name];
} else {
throw new \InvalidArgumentException(sprintf('Style "%s" is not defined.', $name));
}

return $this;
}










public function getColumnStyle($columnIndex)
{
if (isset($this->columnStyles[$columnIndex])) {
return $this->columnStyles[$columnIndex];
}

return $this->getStyle();
}

public function setHeaders(array $headers)
{
$headers = array_values($headers);
if (!empty($headers) && !is_array($headers[0])) {
$headers = array($headers);
}

$this->headers = $headers;

return $this;
}

public function setRows(array $rows)
{
$this->rows = array();

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 setRow($column, array $row)
{
$this->rows[$column] = $row;

return $this;
}













public function render()
{
$this->calculateNumberOfColumns();
$rows = $this->buildTableRows($this->rows);
$headers = $this->buildTableRows($this->headers);

$this->calculateColumnsWidth(array_merge($headers, $rows));

$this->renderRowSeparator();
if (!empty($headers)) {
foreach ($headers as $header) {
$this->renderRow($header, $this->style->getCellHeaderFormat());
$this->renderRowSeparator();
}
}
foreach ($rows as $row) {
if ($row instanceof TableSeparator) {
$this->renderRowSeparator();
} else {
$this->renderRow($row, $this->style->getCellRowFormat());
}
}
if (!empty($rows)) {
$this->renderRowSeparator();
}

$this->cleanup();
}






private function renderRowSeparator()
{
if (0 === $count = $this->numberOfColumns) {
return;
}

if (!$this->style->getHorizontalBorderChar() && !$this->style->getCrossingChar()) {
return;
}

$markup = $this->style->getCrossingChar();
for ($column = 0; $column < $count; ++$column) {
$markup .= str_repeat($this->style->getHorizontalBorderChar(), $this->columnWidths[$column]).$this->style->getCrossingChar();
}

$this->output->writeln(sprintf($this->style->getBorderFormat(), $markup));
}




private function renderColumnSeparator()
{
$this->output->write(sprintf($this->style->getBorderFormat(), $this->style->getVerticalBorderChar()));
}









private function renderRow(array $row, $cellFormat)
{
if (empty($row)) {
return;
}

$this->renderColumnSeparator();
foreach ($this->getRowColumns($row) as $column) {
$this->renderCell($row, $column, $cellFormat);
$this->renderColumnSeparator();
}
$this->output->writeln('');
}








private function renderCell(array $row, $column, $cellFormat)
{
$cell = isset($row[$column]) ? $row[$column] : '';
$width = $this->columnWidths[$column];
if ($cell instanceof TableCell && $cell->getColspan() > 1) {

 foreach (range($column + 1, $column + $cell->getColspan() - 1) as $nextColumn) {
$width += $this->getColumnSeparatorWidth() + $this->columnWidths[$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) {
$this->output->write(sprintf($style->getBorderFormat(), str_repeat($style->getHorizontalBorderChar(), $width)));
} else {
$width += Helper::strlen($cell) - Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
$content = sprintf($style->getCellRowContentFormat(), $cell);
$this->output->write(sprintf($cellFormat, str_pad($content, $width, $style->getPaddingChar(), $style->getPadType())));
}
}




private function calculateNumberOfColumns()
{
if (null !== $this->numberOfColumns) {
return;
}

$columns = array(0);
foreach (array_merge($this->headers, $this->rows) as $row) {
if ($row instanceof TableSeparator) {
continue;
}

$columns[] = $this->getNumberOfColumns($row);
}

$this->numberOfColumns = max($columns);
}

private function buildTableRows($rows)
{
$unmergedRows = array();
for ($rowKey = 0; $rowKey < count($rows); ++$rowKey) {
$rows = $this->fillNextRows($rows, $rowKey);


 foreach ($rows[$rowKey] as $column => $cell) {
if (!strstr($cell, "\n")) {
continue;
}
$lines = explode("\n", $cell);
foreach ($lines as $lineKey => $line) {
if ($cell instanceof TableCell) {
$line = new TableCell($line, array('colspan' => $cell->getColspan()));
}
if (0 === $lineKey) {
$rows[$rowKey][$column] = $line;
} else {
$unmergedRows[$rowKey][$lineKey][$column] = $line;
}
}
}
}

$tableRows = array();
foreach ($rows as $rowKey => $row) {
$tableRows[] = $this->fillCells($row);
if (isset($unmergedRows[$rowKey])) {
$tableRows = array_merge($tableRows, $unmergedRows[$rowKey]);
}
}

return $tableRows;
}









private function fillNextRows($rows, $line)
{
$unmergedRows = array();
foreach ($rows[$line] as $column => $cell) {
if ($cell instanceof TableCell && $cell->getRowspan() > 1) {
$nbLines = $cell->getRowspan() - 1;
$lines = array($cell);
if (strstr($cell, "\n")) {
$lines = explode("\n", $cell);
$nbLines = count($lines) > $nbLines ? substr_count($cell, "\n") : $nbLines;

$rows[$line][$column] = new TableCell($lines[0], array('colspan' => $cell->getColspan()));
unset($lines[0]);
}


 $unmergedRows = array_replace_recursive(array_fill($line + 1, $nbLines, ''), $unmergedRows);
foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) {
$value = isset($lines[$unmergedRowKey - $line]) ? $lines[$unmergedRowKey - $line] : '';
$unmergedRows[$unmergedRowKey][$column] = new TableCell($value, array('colspan' => $cell->getColspan()));
}
}
}

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, array($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, array($row));
}
}

return $rows;
}








private function fillCells($row)
{
$newRow = array();
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($rows, $line)
{
$row = $rows[$line];
foreach ($row as $cellKey => $cellValue) {
$row[$cellKey] = '';
if ($cellValue instanceof TableCell) {
$row[$cellKey] = new TableCell('', array('colspan' => $cellValue->getColspan()));
}
}

return $row;
}








private function getNumberOfColumns(array $row)
{
$columns = count($row);
foreach ($row as $column) {
$columns += $column instanceof TableCell ? ($column->getColspan() - 1) : 0;
}

return $columns;
}








private function getRowColumns($row)
{
$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($rows)
{
for ($column = 0; $column < $this->numberOfColumns; ++$column) {
$lengths = array();
foreach ($rows as $row) {
if ($row instanceof TableSeparator) {
continue;
}

$lengths[] = $this->getCellWidth($row, $column);
}

$this->columnWidths[$column] = max($lengths) + strlen($this->style->getCellRowContentFormat()) - 2;
}
}






private function getColumnSeparatorWidth()
{
return strlen(sprintf($this->style->getBorderFormat(), $this->style->getVerticalBorderChar()));
}









private function getCellWidth(array $row, $column)
{
if (isset($row[$column])) {
$cell = $row[$column];
$cellWidth = Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
if ($cell instanceof TableCell && $cell->getColspan() > 1) {

 $cellWidth = $cellWidth / $cell->getColspan();
}

return $cellWidth;
}

return 0;
}




private function cleanup()
{
$this->columnWidths = array();
$this->numberOfColumns = null;
}

private static function initStyles()
{
$borderless = new TableStyle();
$borderless
->setHorizontalBorderChar('=')
->setVerticalBorderChar(' ')
->setCrossingChar(' ')
;

$compact = new TableStyle();
$compact
->setHorizontalBorderChar('')
->setVerticalBorderChar(' ')
->setCrossingChar('')
->setCellRowContentFormat('%s')
;

$styleGuide = new TableStyle();
$styleGuide
->setHorizontalBorderChar('-')
->setVerticalBorderChar(' ')
->setCrossingChar(' ')
->setCellHeaderFormat('%s')
;

return array(
'default' => new TableStyle(),
'borderless' => $borderless,
'compact' => $compact,
'symfony-style-guide' => $styleGuide,
);
}
}
<?php










namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Exception\LogicException;







class ProgressBar
{

 private $barWidth = 28;
private $barChar;
private $emptyBarChar = '-';
private $progressChar = '>';
private $format;
private $internalFormat;
private $redrawFreq = 1;




private $output;
private $step = 0;
private $max;
private $startTime;
private $stepWidth;
private $percent = 0.0;
private $lastMessagesLength = 0;
private $formatLineCount;
private $messages;
private $overwrite = true;

private static $formatters;
private static $formats;







public function __construct(OutputInterface $output, $max = 0)
{
if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
}

$this->output = $output;
$this->setMaxSteps($max);

if (!$this->output->isDecorated()) {

 $this->overwrite = false;


 $this->setRedrawFrequency($max / 10);
}

$this->startTime = time();
}









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 isset(self::$formatters[$name]) ? self::$formatters[$name] : null;
}









public static function setFormatDefinition($name, $format)
{
if (!self::$formats) {
self::$formats = self::initFormats();
}

self::$formats[$name] = $format;
}








public static function getFormatDefinition($name)
{
if (!self::$formats) {
self::$formats = self::initFormats();
}

return isset(self::$formats[$name]) ? self::$formats[$name] : null;
}

public function setMessage($message, $name = 'message')
{
$this->messages[$name] = $message;
}

public function getMessage($name = 'message')
{
return $this->messages[$name];
}






public function getStartTime()
{
return $this->startTime;
}






public function getMaxSteps()
{
return $this->max;
}








public function getStep()
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.6 and will be removed in 3.0. Use the getProgress() method instead.', E_USER_DEPRECATED);

return $this->getProgress();
}






public function getProgress()
{
return $this->step;
}








public function getStepWidth()
{
return $this->stepWidth;
}






public function getProgressPercent()
{
return $this->percent;
}






public function setBarWidth($size)
{
$this->barWidth = (int) $size;
}






public function getBarWidth()
{
return $this->barWidth;
}






public function setBarCharacter($char)
{
$this->barChar = $char;
}






public function getBarCharacter()
{
if (null === $this->barChar) {
return $this->max ? '=' : $this->emptyBarChar;
}

return $this->barChar;
}






public function setEmptyBarCharacter($char)
{
$this->emptyBarChar = $char;
}






public function getEmptyBarCharacter()
{
return $this->emptyBarChar;
}






public function setProgressCharacter($char)
{
$this->progressChar = $char;
}






public function getProgressCharacter()
{
return $this->progressChar;
}






public function setFormat($format)
{
$this->format = null;
$this->internalFormat = $format;
}






public function setRedrawFrequency($freq)
{
$this->redrawFreq = max((int) $freq, 1);
}






public function start($max = null)
{
$this->startTime = time();
$this->step = 0;
$this->percent = 0.0;

if (null !== $max) {
$this->setMaxSteps($max);
}

$this->display();
}








public function advance($step = 1)
{
$this->setProgress($this->step + $step);
}










public function setCurrent($step)
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.6 and will be removed in 3.0. Use the setProgress() method instead.', E_USER_DEPRECATED);

$this->setProgress($step);
}






public function setOverwrite($overwrite)
{
$this->overwrite = (bool) $overwrite;
}








public function setProgress($step)
{
$step = (int) $step;
if ($step < $this->step) {
throw new LogicException('You can\'t regress the progress bar.');
}

if ($this->max && $step > $this->max) {
$this->max = $step;
}

$prevPeriod = (int) ($this->step / $this->redrawFreq);
$currPeriod = (int) ($step / $this->redrawFreq);
$this->step = $step;
$this->percent = $this->max ? (float) $this->step / $this->max : 0;
if ($prevPeriod !== $currPeriod || $this->max === $step) {
$this->display();
}
}




public function finish()
{
if (!$this->max) {
$this->max = $this->step;
}

if ($this->step === $this->max && !$this->overwrite) {

 return;
}

$this->setProgress($this->max);
}




public function display()
{
if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
return;
}

if (null === $this->format) {
$this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());
}


 $self = $this;
$output = $this->output;
$messages = $this->messages;
$this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) use ($self, $output, $messages) {
if ($formatter = $self::getPlaceholderFormatterDefinition($matches[1])) {
$text = call_user_func($formatter, $self, $output);
} elseif (isset($messages[$matches[1]])) {
$text = $messages[$matches[1]];
} else {
return $matches[0];
}

if (isset($matches[2])) {
$text = sprintf('%'.$matches[2], $text);
}

return $text;
}, $this->format));
}








public function clear()
{
if (!$this->overwrite) {
return;
}

if (null === $this->format) {
$this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());
}

$this->overwrite(str_repeat("\n", $this->formatLineCount));
}






private function setRealFormat($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 setMaxSteps($max)
{
$this->max = max(0, (int) $max);
$this->stepWidth = $this->max ? Helper::strlen($this->max) : 4;
}






private function overwrite($message)
{
$lines = explode("\n", $message);


 if (null !== $this->lastMessagesLength) {
foreach ($lines as $i => $line) {
if ($this->lastMessagesLength > Helper::strlenWithoutDecoration($this->output->getFormatter(), $line)) {
$lines[$i] = str_pad($line, $this->lastMessagesLength, "\x20", STR_PAD_RIGHT);
}
}
}

if ($this->overwrite) {

 $this->output->write("\x0D");
} elseif ($this->step > 0) {

 $this->output->writeln('');
}

if ($this->formatLineCount) {
$this->output->write(sprintf("\033[%dA", $this->formatLineCount));
}
$this->output->write(implode("\n", $lines));

$this->lastMessagesLength = 0;
foreach ($lines as $line) {
$len = Helper::strlenWithoutDecoration($this->output->getFormatter(), $line);
if ($len > $this->lastMessagesLength) {
$this->lastMessagesLength = $len;
}
}
}

private function determineBestFormat()
{
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()
{
return array(
'bar' => function (ProgressBar $bar, OutputInterface $output) {
$completeBars = floor($bar->getMaxSteps() > 0 ? $bar->getProgressPercent() * $bar->getBarWidth() : $bar->getProgress() % $bar->getBarWidth());
$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 (ProgressBar $bar) {
return Helper::formatTime(time() - $bar->getStartTime());
},
'remaining' => function (ProgressBar $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 (ProgressBar $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 (ProgressBar $bar) {
return Helper::formatMemory(memory_get_usage(true));
},
'current' => function (ProgressBar $bar) {
return str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', STR_PAD_LEFT);
},
'max' => function (ProgressBar $bar) {
return $bar->getMaxSteps();
},
'percent' => function (ProgressBar $bar) {
return floor($bar->getProgressPercent() * 100);
},
);
}

private static function initFormats()
{
return array(
'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%',
);
}
}
<?php










namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;







class TableStyle
{
private $paddingChar = ' ';
private $horizontalBorderChar = '-';
private $verticalBorderChar = '|';
private $crossingChar = '+';
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 setHorizontalBorderChar($horizontalBorderChar)
{
$this->horizontalBorderChar = $horizontalBorderChar;

return $this;
}






public function getHorizontalBorderChar()
{
return $this->horizontalBorderChar;
}








public function setVerticalBorderChar($verticalBorderChar)
{
$this->verticalBorderChar = $verticalBorderChar;

return $this;
}






public function getVerticalBorderChar()
{
return $this->verticalBorderChar;
}








public function setCrossingChar($crossingChar)
{
$this->crossingChar = $crossingChar;

return $this;
}






public function getCrossingChar()
{
return $this->crossingChar;
}








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, array(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;
}
}
<?php










namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Exception\LogicException;










class ProgressHelper extends Helper
{
const FORMAT_QUIET = ' %percent%%';
const FORMAT_NORMAL = ' %current%/%max% [%bar%] %percent%%';
const FORMAT_VERBOSE = ' %current%/%max% [%bar%] %percent%% Elapsed: %elapsed%';
const FORMAT_QUIET_NOMAX = ' %current%';
const FORMAT_NORMAL_NOMAX = ' %current% [%bar%]';
const FORMAT_VERBOSE_NOMAX = ' %current% [%bar%] Elapsed: %elapsed%';


 private $barWidth = 28;
private $barChar = '=';
private $emptyBarChar = '-';
private $progressChar = '>';
private $format = null;
private $redrawFreq = 1;

private $lastMessagesLength;
private $barCharOriginal;




private $output;






private $current;






private $max;






private $startTime;






private $defaultFormatVars = array(
'current',
'max',
'bar',
'percent',
'elapsed',
);






private $formatVars;






private $widths = array(
'current' => 4,
'max' => 4,
'percent' => 3,
'elapsed' => 6,
);






private $timeFormats = array(
array(0, '???'),
array(2, '1 sec'),
array(59, 'secs', 1),
array(60, '1 min'),
array(3600, 'mins', 60),
array(5400, '1 hr'),
array(86400, 'hrs', 3600),
array(129600, '1 day'),
array(604800, 'days', 86400),
);

public function __construct($triggerDeprecationError = true)
{
if ($triggerDeprecationError) {
@trigger_error('The '.__CLASS__.' class is deprecated since version 2.5 and will be removed in 3.0. Use the Symfony\Component\Console\Helper\ProgressBar class instead.', E_USER_DEPRECATED);
}
}






public function setBarWidth($size)
{
$this->barWidth = (int) $size;
}






public function setBarCharacter($char)
{
$this->barChar = $char;
}






public function setEmptyBarCharacter($char)
{
$this->emptyBarChar = $char;
}






public function setProgressCharacter($char)
{
$this->progressChar = $char;
}






public function setFormat($format)
{
$this->format = $format;
}






public function setRedrawFrequency($freq)
{
$this->redrawFreq = (int) $freq;
}







public function start(OutputInterface $output, $max = null)
{
if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
}

$this->startTime = time();
$this->current = 0;
$this->max = (int) $max;


 $this->output = $output->isDecorated() ? $output : new NullOutput();
$this->lastMessagesLength = 0;
$this->barCharOriginal = '';

if (null === $this->format) {
switch ($output->getVerbosity()) {
case OutputInterface::VERBOSITY_QUIET:
$this->format = self::FORMAT_QUIET_NOMAX;
if ($this->max > 0) {
$this->format = self::FORMAT_QUIET;
}
break;
case OutputInterface::VERBOSITY_VERBOSE:
case OutputInterface::VERBOSITY_VERY_VERBOSE:
case OutputInterface::VERBOSITY_DEBUG:
$this->format = self::FORMAT_VERBOSE_NOMAX;
if ($this->max > 0) {
$this->format = self::FORMAT_VERBOSE;
}
break;
default:
$this->format = self::FORMAT_NORMAL_NOMAX;
if ($this->max > 0) {
$this->format = self::FORMAT_NORMAL;
}
break;
}
}

$this->initialize();
}









public function advance($step = 1, $redraw = false)
{
$this->setCurrent($this->current + $step, $redraw);
}









public function setCurrent($current, $redraw = false)
{
if (null === $this->startTime) {
throw new LogicException('You must start the progress bar before calling setCurrent().');
}

$current = (int) $current;

if ($current < $this->current) {
throw new LogicException('You can\'t regress the progress bar');
}

if (0 === $this->current) {
$redraw = true;
}

$prevPeriod = (int) ($this->current / $this->redrawFreq);

$this->current = $current;

$currPeriod = (int) ($this->current / $this->redrawFreq);
if ($redraw || $prevPeriod !== $currPeriod || $this->max === $this->current) {
$this->display();
}
}








public function display($finish = false)
{
if (null === $this->startTime) {
throw new LogicException('You must start the progress bar before calling display().');
}

$message = $this->format;
foreach ($this->generate($finish) as $name => $value) {
$message = str_replace("%{$name}%", $value, $message);
}
$this->overwrite($this->output, $message);
}








public function clear()
{
$this->overwrite($this->output, '');
}




public function finish()
{
if (null === $this->startTime) {
throw new LogicException('You must start the progress bar before calling finish().');
}

if (null !== $this->startTime) {
if (!$this->max) {
$this->barChar = $this->barCharOriginal;
$this->display(true);
}
$this->startTime = null;
$this->output->writeln('');
$this->output = null;
}
}




private function initialize()
{
$this->formatVars = array();
foreach ($this->defaultFormatVars as $var) {
if (false !== strpos($this->format, "%{$var}%")) {
$this->formatVars[$var] = true;
}
}

if ($this->max > 0) {
$this->widths['max'] = $this->strlen($this->max);
$this->widths['current'] = $this->widths['max'];
} else {
$this->barCharOriginal = $this->barChar;
$this->barChar = $this->emptyBarChar;
}
}








private function generate($finish = false)
{
$vars = array();
$percent = 0;
if ($this->max > 0) {
$percent = (float) $this->current / $this->max;
}

if (isset($this->formatVars['bar'])) {
$completeBars = 0;

if ($this->max > 0) {
$completeBars = floor($percent * $this->barWidth);
} else {
if (!$finish) {
$completeBars = floor($this->current % $this->barWidth);
} else {
$completeBars = $this->barWidth;
}
}

$emptyBars = $this->barWidth - $completeBars - $this->strlen($this->progressChar);
$bar = str_repeat($this->barChar, $completeBars);
if ($completeBars < $this->barWidth) {
$bar .= $this->progressChar;
$bar .= str_repeat($this->emptyBarChar, $emptyBars);
}

$vars['bar'] = $bar;
}

if (isset($this->formatVars['elapsed'])) {
$elapsed = time() - $this->startTime;
$vars['elapsed'] = str_pad($this->humaneTime($elapsed), $this->widths['elapsed'], ' ', STR_PAD_LEFT);
}

if (isset($this->formatVars['current'])) {
$vars['current'] = str_pad($this->current, $this->widths['current'], ' ', STR_PAD_LEFT);
}

if (isset($this->formatVars['max'])) {
$vars['max'] = $this->max;
}

if (isset($this->formatVars['percent'])) {
$vars['percent'] = str_pad(floor($percent * 100), $this->widths['percent'], ' ', STR_PAD_LEFT);
}

return $vars;
}








private function humaneTime($secs)
{
$text = '';
foreach ($this->timeFormats as $format) {
if ($secs < $format[0]) {
if (count($format) == 2) {
$text = $format[1];
break;
} else {
$text = ceil($secs / $format[2]).' '.$format[1];
break;
}
}
}

return $text;
}







private function overwrite(OutputInterface $output, $message)
{
$length = $this->strlen($message);


 if (null !== $this->lastMessagesLength && $this->lastMessagesLength > $length) {
$message = str_pad($message, $this->lastMessagesLength, "\x20", STR_PAD_RIGHT);
}


 $output->write("\x0D");
$output->write($message);

$this->lastMessagesLength = $this->strlen($message);
}




public function getName()
{
return 'progress';
}
}
<?php










namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Exception\LogicException;
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;
use Symfony\Component\Console\Style\SymfonyStyle;






class SymfonyQuestionHelper extends QuestionHelper
{



public function ask(InputInterface $input, OutputInterface $output, Question $question)
{
$validator = $question->getValidator();
$question->setValidator(function ($value) use ($validator) {
if (null !== $validator) {
$value = $validator($value);
}


 if (!is_array($value) && !is_bool($value) && 0 === strlen($value)) {
throw new LogicException('A value is required.');
}

return $value;
});

return parent::ask($input, $output, $question);
}




protected function writePrompt(OutputInterface $output, Question $question)
{
$text = $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:
$choices = $question->getChoices();
$text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, $choices[$default]);

break;

default:
$text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, $default);
}

$output->writeln($text);

if ($question instanceof ChoiceQuestion) {
$width = max(array_map('strlen', array_keys($question->getChoices())));

foreach ($question->getChoices() as $key => $value) {
$output->writeln(sprintf("  [<comment>%-${width}s</comment>] %s", $key, $value));
}
}

$output->write(' > ');
}




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\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\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Question\ChoiceQuestion;






class QuestionHelper extends Helper
{
private $inputStream;
private static $shell;
private static $stty;












public function ask(InputInterface $input, OutputInterface $output, Question $question)
{
if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
}

if (!$input->isInteractive()) {
return $question->getDefault();
}

if (!$question->getValidator()) {
return $this->doAsk($output, $question);
}

$that = $this;

$interviewer = function () use ($output, $question, $that) {
return $that->doAsk($output, $question);
};

return $this->validateAttempts($interviewer, $output, $question);
}










public function setInputStream($stream)
{
if (!is_resource($stream)) {
throw new InvalidArgumentException('Input stream must be a valid resource.');
}

$this->inputStream = $stream;
}






public function getInputStream()
{
return $this->inputStream;
}




public function getName()
{
return 'question';
}














public function doAsk(OutputInterface $output, Question $question)
{
$this->writePrompt($output, $question);

$inputStream = $this->inputStream ?: STDIN;
$autocomplete = $question->getAutocompleterValues();

if (null === $autocomplete || !$this->hasSttyAvailable()) {
$ret = false;
if ($question->isHidden()) {
try {
$ret = trim($this->getHiddenResponse($output, $inputStream));
} catch (\RuntimeException $e) {
if (!$question->isHiddenFallback()) {
throw $e;
}
}
}

if (false === $ret) {
$ret = fgets($inputStream, 4096);
if (false === $ret) {
throw new \RuntimeException('Aborted');
}
$ret = trim($ret);
}
} else {
$ret = trim($this->autocomplete($output, $question, $inputStream));
}

$ret = strlen($ret) > 0 ? $ret : $question->getDefault();

if ($normalizer = $question->getNormalizer()) {
return $normalizer($ret);
}

return $ret;
}







protected function writePrompt(OutputInterface $output, Question $question)
{
$message = $question->getQuestion();

if ($question instanceof ChoiceQuestion) {
$maxWidth = max(array_map(array($this, 'strlen'), array_keys($question->getChoices())));

$messages = (array) $question->getQuestion();
foreach ($question->getChoices() as $key => $value) {
$width = $maxWidth - $this->strlen($key);
$messages[] = '  [<info>'.$key.str_repeat(' ', $width).'</info>] '.$value;
}

$output->writeln($messages);

$message = $question->getPrompt();
}

$output->write($message);
}







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)
{
$autocomplete = $question->getAutocompleterValues();
$ret = '';

$i = 0;
$ofs = -1;
$matches = $autocomplete;
$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 ("\177" === $c) {
if (0 === $numMatches && 0 !== $i) {
--$i;

 $output->write("\033[1D");
}

if ($i === 0) {
$ofs = -1;
$matches = $autocomplete;
$numMatches = count($matches);
} else {
$numMatches = 0;
}


 $ret = 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 = $matches[$ofs];

 $output->write(substr($ret, $i));
$i = strlen($ret);
}

if ("\n" === $c) {
$output->write($c);
break;
}

$numMatches = 0;
}

continue;
} else {
$output->write($c);
$ret .= $c;
++$i;

$numMatches = 0;
$ofs = 0;

foreach ($autocomplete as $value) {

 if (0 === strpos($value, $ret) && $i !== strlen($value)) {
$matches[$numMatches++] = $value;
}
}
}


 $output->write("\033[K");

if ($numMatches > 0 && -1 !== $ofs) {

 $output->write("\0337");

 $output->write('<hl>'.substr($matches[$ofs], $i).'</hl>');

 $output->write("\0338");
}
}


 shell_exec(sprintf('stty %s', $sttyMode));

return $ret;
}










private function getHiddenResponse(OutputInterface $output, $inputStream)
{
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;
}

$value = rtrim(shell_exec($exe));
$output->writeln('');

if (isset($tmpExe)) {
unlink($tmpExe);
}

return $value;
}

if ($this->hasSttyAvailable()) {
$sttyMode = shell_exec('stty -g');

shell_exec('stty -echo');
$value = fgets($inputStream, 4096);
shell_exec(sprintf('stty %s', $sttyMode));

if (false === $value) {
throw new RuntimeException('Aborted');
}

$value = trim($value);
$output->writeln('');

return $value;
}

if (false !== $shell = $this->getShell()) {
$readCmd = $shell === 'csh' ? 'set mypassword = $<' : 'read -r mypassword';
$command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd);
$value = rtrim(shell_exec($command));
$output->writeln('');

return $value;
}

throw new RuntimeException('Unable to hide the response.');
}












private function validateAttempts($interviewer, OutputInterface $output, Question $question)
{
$error = null;
$attempts = $question->getMaxAttempts();
while (null === $attempts || $attempts--) {
if (null !== $error) {
$this->writeError($output, $error);
}

try {
return call_user_func($question->getValidator(), $interviewer());
} catch (\Exception $error) {
}
}

throw $error;
}






private function getShell()
{
if (null !== self::$shell) {
return self::$shell;
}

self::$shell = false;

if (file_exists('/usr/bin/env')) {

 $test = "/usr/bin/env %s -c 'echo OK' 2> /dev/null";
foreach (array('bash', 'zsh', 'ksh', 'csh') as $sh) {
if ('OK' === rtrim(shell_exec(sprintf($test, $sh)))) {
self::$shell = $sh;
break;
}
}
}

return self::$shell;
}






private function hasSttyAvailable()
{
if (null !== self::$stty) {
return self::$stty;
}

exec('stty 2>&1', $output, $exitcode);

return self::$stty = $exitcode === 0;
}
}
<?php










namespace Symfony\Component\Console\Helper;








class DebugFormatterHelper extends Helper
{
private $colors = array('black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'default');
private $started = array();
private $count = -1;










public function start($id, $message, $prefix = 'RUN')
{
$this->started[$id] = array('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($id)
{
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\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\Output\OutputInterface;
use Symfony\Component\Console\Exception\InvalidArgumentException;






class DescriptorHelper extends Helper
{



private $descriptors = array();




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 = array())
{
$options = array_merge(array(
'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\Output\OutputInterface;




class ProgressIndicator
{
private $output;
private $startTime;
private $format;
private $message;
private $indicatorValues;
private $indicatorCurrent;
private $indicatorChangeInterval;
private $indicatorUpdateTime;
private $lastMessagesLength;
private $started = false;

private static $formatters;
private static $formats;







public function __construct(OutputInterface $output, $format = null, $indicatorChangeInterval = 100, $indicatorValues = null)
{
$this->output = $output;

if (null === $format) {
$format = $this->determineBestFormat();
}

if (null === $indicatorValues) {
$indicatorValues = array('-', '\\', '|', '/');
}

$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 getMessage()
{
return $this->message;
}








public function getStartTime()
{
return $this->startTime;
}








public function getCurrentValue()
{
return $this->indicatorValues[$this->indicatorCurrent % count($this->indicatorValues)];
}






public function start($message)
{
if ($this->started) {
throw new \LogicException('Progress indicator already started.');
}

$this->message = $message;
$this->started = true;
$this->lastMessagesLength = 0;
$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 isset(self::$formats[$name]) ? 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 isset(self::$formatters[$name]) ? self::$formatters[$name] : null;
}

private function display()
{
if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
return;
}

$self = $this;

$this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) use ($self) {
if ($formatter = $self::getPlaceholderFormatterDefinition($matches[1])) {
return call_user_func($formatter, $self);
}

return $matches[0];
}, $this->format));
}

private function determineBestFormat()
{
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($message)
{

 if (null !== $this->lastMessagesLength) {
if ($this->lastMessagesLength > Helper::strlenWithoutDecoration($this->output->getFormatter(), $message)) {
$message = str_pad($message, $this->lastMessagesLength, "\x20", STR_PAD_RIGHT);
}
}

if ($this->output->isDecorated()) {
$this->output->write("\x0D");
$this->output->write($message);
} else {
$this->output->writeln($message);
}

$this->lastMessagesLength = 0;

$len = Helper::strlenWithoutDecoration($this->output->getFormatter(), $message);

if ($len > $this->lastMessagesLength) {
$this->lastMessagesLength = $len;
}
}

private function getCurrentTimeInMilliseconds()
{
return round(microtime(true) * 1000);
}

private static function initPlaceholderFormatters()
{
return array(
'indicator' => function (ProgressIndicator $indicator) {
return $indicator->getCurrentValue();
},
'message' => function (ProgressIndicator $indicator) {
return $indicator->getMessage();
},
'elapsed' => function (ProgressIndicator $indicator) {
return Helper::formatTime(time() - $indicator->getStartTime());
},
'memory' => function () {
return Helper::formatMemory(memory_get_usage(true));
},
);
}

private static function initFormats()
{
return array(
'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\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)
{
if (false === $encoding = mb_detect_encoding($string, null, true)) {
return strlen($string);
}

return mb_strwidth($string, $encoding);
}

public static function formatTime($secs)
{
static $timeFormats = array(
array(0, '< 1 sec'),
array(2, '1 sec'),
array(59, 'secs', 1),
array(60, '1 min'),
array(3600, 'mins', 60),
array(5400, '1 hr'),
array(86400, 'hrs', 3600),
array(129600, '1 day'),
array(604800, 'days', 86400),
);

foreach ($timeFormats as $format) {
if ($secs >= $format[0]) {
continue;
}

if (2 == count($format)) {
return $format[1];
}

return ceil($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)
{
$isDecorated = $formatter->isDecorated();
$formatter->setDecorated(false);

 $string = $formatter->format($string);

 $string = preg_replace("/\033\[[^m]*m/", '', $string);
$formatter->setDecorated($isDecorated);

return self::strlen($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 = array($messages);
}

$len = 0;
$lines = array();
foreach ($messages as $message) {
$message = OutputFormatter::escape($message);
$lines[] = sprintf($large ? '  %s  ' : ' %s ', $message);
$len = max($this->strlen($message) + ($large ? 4 : 2), $len);
}

$messages = $large ? array(str_repeat(' ', $len)) : array();
for ($i = 0; isset($lines[$i]); ++$i) {
$messages[] = $lines[$i].str_repeat(' ', $len - $this->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 getName()
{
return 'formatter';
}
}
<?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;
use Symfony\Component\Process\ProcessBuilder;






class ProcessHelper extends Helper
{












public function run(OutputInterface $output, $cmd, $error = null, $callback = null, $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE)
{
if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
}

$formatter = $this->getHelperSet()->get('debug_formatter');

if (is_array($cmd)) {
$process = ProcessBuilder::create($cmd)->getProcess();
} elseif ($cmd instanceof Process) {
$process = $cmd;
} else {
$process = new Process($cmd);
}

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);

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, $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, $callback = null)
{
if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
}

$formatter = $this->getHelperSet()->get('debug_formatter');

$that = $this;

return function ($type, $buffer) use ($output, $process, $callback, $formatter, $that) {
$output->write($formatter->progress(spl_object_hash($process), $that->escapeString($buffer), Process::ERR === $type));

if (null !== $callback) {
call_user_func($callback, $type, $buffer);
}
};
}






public function escapeString($str)
{
return str_replace('<', '\\<', $str);
}




public function getName()
{
return 'process';
}
}
<?php










namespace Symfony\Component\Console\Helper;






class TableSeparator extends TableCell
{




public function __construct(array $options = array())
{
parent::__construct('', $options);
}
}
<?php










namespace Symfony\Component\Console\Descriptor;

use Symfony\Component\Console\Output\OutputInterface;






interface DescriptorInterface
{







public function describe(OutputInterface $output, $object, array $options = array());
}
<?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)
{
$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)
{
$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->appendChild($usagesXML = $dom->createElement('usages'));

foreach (array_merge(array($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, $namespace = null)
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($rootXml = $dom->createElement('symfony'));

if ($application->getName() !== 'UNKNOWN') {
$rootXml->setAttribute('name', $application->getName());
if ($application->getVersion() !== 'UNKNOWN') {
$rootXml->setAttribute('version', $application->getVersion());
}
}

$rootXml->appendChild($commandsXML = $dom->createElement('commands'));

$description = new ApplicationDescription($application, $namespace);

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 = array())
{
$this->writeDocument($this->getInputArgumentDocument($argument));
}




protected function describeInputOption(InputOption $option, array $options = array())
{
$this->writeDocument($this->getInputOptionDocument($option));
}




protected function describeInputDefinition(InputDefinition $definition, array $options = array())
{
$this->writeDocument($this->getInputDefinitionDocument($definition));
}




protected function describeCommand(Command $command, array $options = array())
{
$this->writeDocument($this->getCommandDocument($command));
}




protected function describeApplication(Application $application, array $options = array())
{
$this->writeDocument($this->getApplicationDocument($application, isset($options['namespace']) ? $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)
{
$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()) ? array(var_export($argument->getDefault(), true)) : ($argument->getDefault() ? array($argument->getDefault()) : array()));
foreach ($defaults as $default) {
$defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
$defaultXML->appendChild($dom->createTextNode($default));
}

return $dom;
}






private function getInputOptionDocument(InputOption $option)
{
$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', '-'.implode('|-', explode('|', $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()) ? array(var_export($option->getDefault(), true)) : ($option->getDefault() ? array($option->getDefault()) : array()));
$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\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 = array())
{
if (null !== $argument->getDefault() && (!is_array($argument->getDefault()) || count($argument->getDefault()))) {
$default = sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($argument->getDefault()));
} else {
$default = '';
}

$totalWidth = isset($options['total_width']) ? $options['total_width'] : strlen($argument->getName());
$spacingWidth = $totalWidth - strlen($argument->getName()) + 2;

$this->writeText(sprintf('  <info>%s</info>%s%s%s',
$argument->getName(),
str_repeat(' ', $spacingWidth),

 preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 17), $argument->getDescription()),
$default
), $options);
}




protected function describeInputOption(InputOption $option, array $options = array())
{
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 = isset($options['total_width']) ? $options['total_width'] : $this->calculateTotalWidthForOptions(array($option));
$synopsis = sprintf('%s%s',
$option->getShortcut() ? sprintf('-%s, ', $option->getShortcut()) : '    ',
sprintf('--%s%s', $option->getName(), $value)
);

$spacingWidth = $totalWidth - strlen($synopsis) + 2;

$this->writeText(sprintf('  <info>%s</info>%s%s%s%s',
$synopsis,
str_repeat(' ', $spacingWidth),

 preg_replace('/\s*[\r\n]\s*/', "\n".str_repeat(' ', $totalWidth + 17), $option->getDescription()),
$default,
$option->isArray() ? '<comment> (multiple values allowed)</comment>' : ''
), $options);
}




protected function describeInputDefinition(InputDefinition $definition, array $options = array())
{
$totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions());
foreach ($definition->getArguments() as $argument) {
$totalWidth = max($totalWidth, 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, array('total_width' => $totalWidth)));
$this->writeText("\n");
}
}

if ($definition->getArguments() && $definition->getOptions()) {
$this->writeText("\n");
}

if ($definition->getOptions()) {
$laterOptions = array();

$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, array('total_width' => $totalWidth)));
}
foreach ($laterOptions as $option) {
$this->writeText("\n");
$this->describeInputOption($option, array_merge($options, array('total_width' => $totalWidth)));
}
}
}




protected function describeCommand(Command $command, array $options = array())
{
$command->getSynopsis(true);
$command->getSynopsis(false);
$command->mergeApplicationDefinition(false);

$this->writeText('<comment>Usage:</comment>', $options);
foreach (array_merge(array($command->getSynopsis(true)), $command->getAliases(), $command->getUsages()) as $usage) {
$this->writeText("\n");
$this->writeText('  '.$usage, $options);
}
$this->writeText("\n");

$definition = $command->getNativeDefinition();
if ($definition->getOptions() || $definition->getArguments()) {
$this->writeText("\n");
$this->describeInputDefinition($definition, $options);
$this->writeText("\n");
}

if ($help = $command->getProcessedHelp()) {
$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 = array())
{
$describedNamespace = isset($options['namespace']) ? $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");

$width = $this->getColumnWidth($description->getCommands());

if ($describedNamespace) {
$this->writeText(sprintf('<comment>Available commands for the "%s" namespace:</comment>', $describedNamespace), $options);
} else {
$this->writeText('<comment>Available commands:</comment>', $options);
}


 foreach ($description->getNamespaces() as $namespace) {
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 - strlen($name);
$this->writeText(sprintf('  <info>%s</info>%s%s', $name, str_repeat(' ', $spacingWidth), $description->getCommand($name)->getDescription()), $options);
}
}

$this->writeText("\n");
}
}




private function writeText($content, array $options = array())
{
$this->write(
isset($options['raw_text']) && $options['raw_text'] ? strip_tags($content) : $content,
isset($options['raw_output']) ? !$options['raw_output'] : true
);
}








private function formatDefaultValue($default)
{
if (PHP_VERSION_ID < 50400) {
return str_replace(array('\/', '\\\\'), array('/', '\\'), json_encode($default));
}

return str_replace('\\\\', '\\', json_encode($default, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
}






private function getColumnWidth(array $commands)
{
$widths = array();

foreach ($commands as $command) {
$widths[] = strlen($command->getName());
foreach ($command->getAliases() as $alias) {
$widths[] = strlen($alias);
}
}

return max($widths) + 2;
}






private function calculateTotalWidthForOptions($options)
{
$totalWidth = 0;
foreach ($options as $option) {

 $nameLength = 1 + max(strlen($option->getShortcut()), 1) + 4 + strlen($option->getName());

if ($option->acceptValue()) {
$valueLength = 1 + 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;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Exception\InvalidArgumentException;






abstract class Descriptor implements DescriptorInterface
{



private $output;




public function describe(OutputInterface $output, $object, array $options = array())
{
$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 = array());









abstract protected function describeInputOption(InputOption $option, array $options = array());









abstract protected function describeInputDefinition(InputDefinition $definition, array $options = array());









abstract protected function describeCommand(Command $command, array $options = array());









abstract protected function describeApplication(Application $application, array $options = array());
}
<?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 MarkdownDescriptor extends Descriptor
{



protected function describeInputArgument(InputArgument $argument, array $options = array())
{
$this->write(
'**'.$argument->getName().':**'."\n\n"
.'* Name: '.($argument->getName() ?: '<none>')."\n"
.'* Is required: '.($argument->isRequired() ? 'yes' : 'no')."\n"
.'* Is array: '.($argument->isArray() ? 'yes' : 'no')."\n"
.'* Description: '.preg_replace('/\s*[\r\n]\s*/', "\n  ", $argument->getDescription() ?: '<none>')."\n"
.'* Default: `'.str_replace("\n", '', var_export($argument->getDefault(), true)).'`'
);
}




protected function describeInputOption(InputOption $option, array $options = array())
{
$this->write(
'**'.$option->getName().':**'."\n\n"
.'* Name: `--'.$option->getName().'`'."\n"
.'* Shortcut: '.($option->getShortcut() ? '`-'.implode('|-', explode('|', $option->getShortcut())).'`' : '<none>')."\n"
.'* Accept value: '.($option->acceptValue() ? 'yes' : 'no')."\n"
.'* Is value required: '.($option->isValueRequired() ? 'yes' : 'no')."\n"
.'* Is multiple: '.($option->isArray() ? 'yes' : 'no')."\n"
.'* Description: '.preg_replace('/\s*[\r\n]\s*/', "\n  ", $option->getDescription() ?: '<none>')."\n"
.'* Default: `'.str_replace("\n", '', var_export($option->getDefault(), true)).'`'
);
}




protected function describeInputDefinition(InputDefinition $definition, array $options = array())
{
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 = array())
{
$command->getSynopsis();
$command->mergeApplicationDefinition(false);

$this->write(
$command->getName()."\n"
.str_repeat('-', strlen($command->getName()))."\n\n"
.'* Description: '.($command->getDescription() ?: '<none>')."\n"
.'* Usage:'."\n\n"
.array_reduce(array_merge(array($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 = array())
{
$describedNamespace = isset($options['namespace']) ? $options['namespace'] : null;
$description = new ApplicationDescription($application, $describedNamespace);

$this->write($application->getName()."\n".str_repeat('=', strlen($application->getName())));

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) {
return '* '.$commandName;
}, $namespace['commands'])));
}

foreach ($description->getCommands() as $command) {
$this->write("\n\n");
$this->write($this->describeCommand($command));
}
}
}
<?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
{
const GLOBAL_NAMESPACE = '_global';




private $application;




private $namespace;




private $namespaces;




private $commands;




private $aliases;







public function __construct(Application $application, $namespace = null)
{
$this->application = $application;
$this->namespace = $namespace;
}




public function getNamespaces()
{
if (null === $this->namespaces) {
$this->inspectApplication();
}

return $this->namespaces;
}




public function getCommands()
{
if (null === $this->commands) {
$this->inspectApplication();
}

return $this->commands;
}








public function getCommand($name)
{
if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) {
throw new CommandNotFoundException(sprintf('Command %s does not exist.', $name));
}

return isset($this->commands[$name]) ? $this->commands[$name] : $this->aliases[$name];
}

private function inspectApplication()
{
$this->commands = array();
$this->namespaces = array();

$all = $this->application->all($this->namespace ? $this->application->findNamespace($this->namespace) : null);
foreach ($this->sortCommands($all) as $namespace => $commands) {
$names = array();


foreach ($commands as $name => $command) {
if (!$command->getName()) {
continue;
}

if ($command->getName() === $name) {
$this->commands[$name] = $command;
} else {
$this->aliases[$name] = $command;
}

$names[] = $name;
}

$this->namespaces[$namespace] = array('id' => $namespace, 'commands' => $names);
}
}






private function sortCommands(array $commands)
{
$namespacedCommands = array();
$globalCommands = array();
foreach ($commands as $name => $command) {
$key = $this->application->extractNamespace($name, 1);
if (!$key) {
$globalCommands['_global'][$name] = $command;
} else {
$namespacedCommands[$key][$name] = $command;
}
}
ksort($namespacedCommands);
$namespacedCommands = array_merge($globalCommands, $namespacedCommands);

foreach ($namespacedCommands as &$commandsSet) {
ksort($commandsSet);
}

 unset($commandsSet);

return $namespacedCommands;
}
}
<?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 = array())
{
$this->writeData($this->getInputArgumentData($argument), $options);
}




protected function describeInputOption(InputOption $option, array $options = array())
{
$this->writeData($this->getInputOptionData($option), $options);
}




protected function describeInputDefinition(InputDefinition $definition, array $options = array())
{
$this->writeData($this->getInputDefinitionData($definition), $options);
}




protected function describeCommand(Command $command, array $options = array())
{
$this->writeData($this->getCommandData($command), $options);
}




protected function describeApplication(Application $application, array $options = array())
{
$describedNamespace = isset($options['namespace']) ? $options['namespace'] : null;
$description = new ApplicationDescription($application, $describedNamespace);
$commands = array();

foreach ($description->getCommands() as $command) {
$commands[] = $this->getCommandData($command);
}

$data = $describedNamespace
? array('commands' => $commands, 'namespace' => $describedNamespace)
: array('commands' => $commands, 'namespaces' => array_values($description->getNamespaces()));

$this->writeData($data, $options);
}









private function writeData(array $data, array $options)
{
$this->write(json_encode($data, isset($options['json_encoding']) ? $options['json_encoding'] : 0));
}






private function getInputArgumentData(InputArgument $argument)
{
return array(
'name' => $argument->getName(),
'is_required' => $argument->isRequired(),
'is_array' => $argument->isArray(),
'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $argument->getDescription()),
'default' => $argument->getDefault(),
);
}






private function getInputOptionData(InputOption $option)
{
return array(
'name' => '--'.$option->getName(),
'shortcut' => $option->getShortcut() ? '-'.implode('|-', explode('|', $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' => $option->getDefault(),
);
}






private function getInputDefinitionData(InputDefinition $definition)
{
$inputArguments = array();
foreach ($definition->getArguments() as $name => $argument) {
$inputArguments[$name] = $this->getInputArgumentData($argument);
}

$inputOptions = array();
foreach ($definition->getOptions() as $name => $option) {
$inputOptions[$name] = $this->getInputOptionData($option);
}

return array('arguments' => $inputArguments, 'options' => $inputOptions);
}






private function getCommandData(Command $command)
{
$command->getSynopsis();
$command->mergeApplicationDefinition(false);

return array(
'name' => $command->getName(),
'usage' => array_merge(array($command->getSynopsis()), $command->getUsages(), $command->getAliases()),
'description' => $command->getDescription(),
'help' => $command->getProcessedHelp(),
'definition' => $this->getInputDefinitionData($command->getNativeDefinition()),
);
}
}
<?php










namespace Symfony\Component\Console;

use Symfony\Component\Console\Descriptor\TextDescriptor;
use Symfony\Component\Console\Descriptor\XmlDescriptor;
use Symfony\Component\Console\Exception\ExceptionInterface;
use Symfony\Component\Console\Helper\DebugFormatterHelper;
use Symfony\Component\Console\Helper\ProcessHelper;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputAwareInterface;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Command\HelpCommand;
use Symfony\Component\Console\Command\ListCommand;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Helper\FormatterHelper;
use Symfony\Component\Console\Helper\DialogHelper;
use Symfony\Component\Console\Helper\ProgressHelper;
use Symfony\Component\Console\Helper\TableHelper;
use Symfony\Component\Console\Event\ConsoleCommandEvent;
use Symfony\Component\Console\Event\ConsoleExceptionEvent;
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
use Symfony\Component\Console\Exception\CommandNotFoundException;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
















class Application
{
private $commands = array();
private $wantHelps = false;
private $runningCommand;
private $name;
private $version;
private $catchExceptions = true;
private $autoExit = true;
private $definition;
private $helperSet;
private $dispatcher;
private $terminalDimensions;
private $defaultCommand;







public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
{
$this->name = $name;
$this->version = $version;
$this->defaultCommand = 'list';
$this->helperSet = $this->getDefaultHelperSet();
$this->definition = $this->getDefaultInputDefinition();

foreach ($this->getDefaultCommands() as $command) {
$this->add($command);
}
}

public function setDispatcher(EventDispatcherInterface $dispatcher)
{
$this->dispatcher = $dispatcher;
}











public function run(InputInterface $input = null, OutputInterface $output = null)
{
if (null === $input) {
$input = new ArgvInput();
}

if (null === $output) {
$output = new ConsoleOutput();
}

$this->configureIO($input, $output);

try {
$exitCode = $this->doRun($input, $output);
} catch (\Exception $e) {
if (!$this->catchExceptions) {
throw $e;
}

if ($output instanceof ConsoleOutputInterface) {
$this->renderException($e, $output->getErrorOutput());
} else {
$this->renderException($e, $output);
}

$exitCode = $e->getCode();
if (is_numeric($exitCode)) {
$exitCode = (int) $exitCode;
if (0 === $exitCode) {
$exitCode = 1;
}
} else {
$exitCode = 1;
}
}

if ($this->autoExit) {
if ($exitCode > 255) {
$exitCode = 255;
}

exit($exitCode);
}

return $exitCode;
}









public function doRun(InputInterface $input, OutputInterface $output)
{
if (true === $input->hasParameterOption(array('--version', '-V'))) {
$output->writeln($this->getLongVersion());

return 0;
}

$name = $this->getCommandName($input);
if (true === $input->hasParameterOption(array('--help', '-h'))) {
if (!$name) {
$name = 'help';
$input = new ArrayInput(array('command' => 'help'));
} else {
$this->wantHelps = true;
}
}

if (!$name) {
$name = $this->defaultCommand;
$input = new ArrayInput(array('command' => $this->defaultCommand));
}


 $command = $this->find($name);

$this->runningCommand = $command;
$exitCode = $this->doRunCommand($command, $input, $output);
$this->runningCommand = null;

return $exitCode;
}






public function setHelperSet(HelperSet $helperSet)
{
$this->helperSet = $helperSet;
}






public function getHelperSet()
{
return $this->helperSet;
}






public function setDefinition(InputDefinition $definition)
{
$this->definition = $definition;
}






public function getDefinition()
{
return $this->definition;
}






public function getHelp()
{
return $this->getLongVersion();
}






public function setCatchExceptions($boolean)
{
$this->catchExceptions = (bool) $boolean;
}






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('<info>%s</info> version <comment>%s</comment>', $this->getName(), $this->getVersion());
}

return sprintf('<info>%s</info>', $this->getName());
}

return '<info>Console Tool</info>';
}








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)
{
$command->setApplication($this);

if (!$command->isEnabled()) {
$command->setApplication(null);

return;
}

if (null === $command->getDefinition()) {
throw new LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', get_class($command)));
}

$this->commands[$command->getName()] = $command;

foreach ($command->getAliases() as $alias) {
$this->commands[$alias] = $command;
}

return $command;
}










public function get($name)
{
if (!isset($this->commands[$name])) {
throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $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)
{
return isset($this->commands[$name]);
}








public function getNamespaces()
{
$namespaces = array();
foreach ($this->all() as $command) {
$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 CommandNotFoundException($message, $alternatives);
}

$exact = in_array($namespace, $namespaces, true);
if (count($namespaces) > 1 && !$exact) {
throw new CommandNotFoundException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces));
}

return $exact ? $namespace : reset($namespaces);
}













public function find($name)
{
$allCommands = array_keys($this->commands);
$expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]).'[^:]*'; }, $name);
$commands = preg_grep('{^'.$expr.'}', $allCommands);

if (empty($commands) || count(preg_grep('{^'.$expr.'$}', $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)) {
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, $alternatives);
}


 if (count($commands) > 1) {
$commandList = $this->commands;
$commands = array_filter($commands, function ($nameOrAlias) use ($commandList, $commands) {
$commandName = $commandList[$nameOrAlias]->getName();

return $commandName === $nameOrAlias || !in_array($commandName, $commands);
});
}

$exact = in_array($name, $commands, true);
if (count($commands) > 1 && !$exact) {
$suggestions = $this->getAbbreviationSuggestions(array_values($commands));

throw new CommandNotFoundException(sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions), array_values($commands));
}

return $this->get($exact ? $name : reset($commands));
}










public function all($namespace = null)
{
if (null === $namespace) {
return $this->commands;
}

$commands = array();
foreach ($this->commands as $name => $command) {
if ($namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1)) {
$commands[$name] = $command;
}
}

return $commands;
}








public static function getAbbreviations($names)
{
$abbrevs = array();
foreach ($names as $name) {
for ($len = strlen($name); $len > 0; --$len) {
$abbrev = substr($name, 0, $len);
$abbrevs[$abbrev][] = $name;
}
}

return $abbrevs;
}











public function asText($namespace = null, $raw = false)
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.3 and will be removed in 3.0.', E_USER_DEPRECATED);

$descriptor = new TextDescriptor();
$output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, !$raw);
$descriptor->describe($output, $this, array('namespace' => $namespace, 'raw_output' => true));

return $output->fetch();
}











public function asXml($namespace = null, $asDom = false)
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.3 and will be removed in 3.0.', E_USER_DEPRECATED);

$descriptor = new XmlDescriptor();

if ($asDom) {
return $descriptor->getApplicationDocument($this, $namespace);
}

$output = new BufferedOutput();
$descriptor->describe($output, $this, array('namespace' => $namespace));

return $output->fetch();
}







public function renderException($e, $output)
{
$output->writeln('', OutputInterface::VERBOSITY_QUIET);

do {
$title = sprintf('  [%s]  ', get_class($e));

$len = $this->stringWidth($title);

$width = $this->getTerminalWidth() ? $this->getTerminalWidth() - 1 : PHP_INT_MAX;

 if (defined('HHVM_VERSION') && $width > 1 << 31) {
$width = 1 << 31;
}
$formatter = $output->getFormatter();
$lines = array();
foreach (preg_split('/\r?\n/', $e->getMessage()) as $line) {
foreach ($this->splitStringByWidth($line, $width - 4) as $line) {

 $lineLength = $this->stringWidth(preg_replace('/\[[^m]*m/', '', $formatter->format($line))) + 4;
$lines[] = array($line, $lineLength);

$len = max($lineLength, $len);
}
}

$messages = array();
$messages[] = $emptyLine = $formatter->format(sprintf('<error>%s</error>', str_repeat(' ', $len)));
$messages[] = $formatter->format(sprintf('<error>%s%s</error>', $title, str_repeat(' ', max(0, $len - $this->stringWidth($title)))));
foreach ($lines as $line) {
$messages[] = $formatter->format(sprintf('<error>  %s  %s</error>', $line[0], str_repeat(' ', $len - $line[1])));
}
$messages[] = $emptyLine;
$messages[] = '';

$output->writeln($messages, OutputInterface::OUTPUT_RAW | OutputInterface::VERBOSITY_QUIET);

if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
$output->writeln('<comment>Exception trace:</comment>', OutputInterface::VERBOSITY_QUIET);


 $trace = $e->getTrace();
array_unshift($trace, array(
'function' => '',
'file' => $e->getFile() !== null ? $e->getFile() : 'n/a',
'line' => $e->getLine() !== null ? $e->getLine() : 'n/a',
'args' => array(),
));

for ($i = 0, $count = count($trace); $i < $count; ++$i) {
$class = isset($trace[$i]['class']) ? $trace[$i]['class'] : '';
$type = isset($trace[$i]['type']) ? $trace[$i]['type'] : '';
$function = $trace[$i]['function'];
$file = isset($trace[$i]['file']) ? $trace[$i]['file'] : 'n/a';
$line = isset($trace[$i]['line']) ? $trace[$i]['line'] : 'n/a';

$output->writeln(sprintf(' %s%s%s() at <info>%s:%s</info>', $class, $type, $function, $file, $line), OutputInterface::VERBOSITY_QUIET);
}

$output->writeln('', OutputInterface::VERBOSITY_QUIET);
}
} while ($e = $e->getPrevious());

if (null !== $this->runningCommand) {
$output->writeln(sprintf('<info>%s</info>', sprintf($this->runningCommand->getSynopsis(), $this->getName())), OutputInterface::VERBOSITY_QUIET);
$output->writeln('', OutputInterface::VERBOSITY_QUIET);
}
}






protected function getTerminalWidth()
{
$dimensions = $this->getTerminalDimensions();

return $dimensions[0];
}






protected function getTerminalHeight()
{
$dimensions = $this->getTerminalDimensions();

return $dimensions[1];
}






public function getTerminalDimensions()
{
if ($this->terminalDimensions) {
return $this->terminalDimensions;
}

if ('\\' === DIRECTORY_SEPARATOR) {

 if (preg_match('/^(\d+)x\d+ \(\d+x(\d+)\)$/', trim(getenv('ANSICON')), $matches)) {
return array((int) $matches[1], (int) $matches[2]);
}

 if (preg_match('/^(\d+)x(\d+)$/', $this->getConsoleMode(), $matches)) {
return array((int) $matches[1], (int) $matches[2]);
}
}

if ($sttyString = $this->getSttyColumns()) {

 if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) {
return array((int) $matches[2], (int) $matches[1]);
}

 if (preg_match('/;.(\d+).rows;.(\d+).columns/i', $sttyString, $matches)) {
return array((int) $matches[2], (int) $matches[1]);
}
}

return array(null, null);
}











public function setTerminalDimensions($width, $height)
{
$this->terminalDimensions = array($width, $height);

return $this;
}







protected function configureIO(InputInterface $input, OutputInterface $output)
{
if (true === $input->hasParameterOption(array('--ansi'))) {
$output->setDecorated(true);
} elseif (true === $input->hasParameterOption(array('--no-ansi'))) {
$output->setDecorated(false);
}

if (true === $input->hasParameterOption(array('--no-interaction', '-n'))) {
$input->setInteractive(false);
} elseif (function_exists('posix_isatty') && $this->getHelperSet()->has('question')) {
$inputStream = $this->getHelperSet()->get('question')->getInputStream();
if (!@posix_isatty($inputStream) && false === getenv('SHELL_INTERACTIVE')) {
$input->setInteractive(false);
}
}

if (true === $input->hasParameterOption(array('--quiet', '-q'))) {
$output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
} else {
if ($input->hasParameterOption('-vvv') || $input->hasParameterOption('--verbose=3') || $input->getParameterOption('--verbose') === 3) {
$output->setVerbosity(OutputInterface::VERBOSITY_DEBUG);
} elseif ($input->hasParameterOption('-vv') || $input->hasParameterOption('--verbose=2') || $input->getParameterOption('--verbose') === 2) {
$output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE);
} elseif ($input->hasParameterOption('-v') || $input->hasParameterOption('--verbose=1') || $input->hasParameterOption('--verbose') || $input->getParameterOption('--verbose')) {
$output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
}
}
}















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);
$this->dispatcher->dispatch(ConsoleEvents::COMMAND, $event);

if ($event->commandShouldRun()) {
try {
$exitCode = $command->run($input, $output);
} catch (\Exception $e) {
$event = new ConsoleExceptionEvent($command, $input, $output, $e, $e->getCode());
$this->dispatcher->dispatch(ConsoleEvents::EXCEPTION, $event);

$e = $event->getException();

$event = new ConsoleTerminateEvent($command, $input, $output, $e->getCode());
$this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event);

throw $e;
}
} else {
$exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED;
}

$event = new ConsoleTerminateEvent($command, $input, $output, $exitCode);
$this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event);

return $event->getExitCode();
}








protected function getCommandName(InputInterface $input)
{
return $input->getFirstArgument();
}






protected function getDefaultInputDefinition()
{
return new InputDefinition(array(
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 array(new HelpCommand(), new ListCommand());
}






protected function getDefaultHelperSet()
{
return new HelperSet(array(
new FormatterHelper(),
new DialogHelper(false),
new ProgressHelper(false),
new TableHelper(false),
new DebugFormatterHelper(),
new ProcessHelper(),
new QuestionHelper(),
));
}






private function getSttyColumns()
{
if (!function_exists('proc_open')) {
return;
}

$descriptorspec = array(1 => array('pipe', 'w'), 2 => array('pipe', 'w'));
$process = proc_open('stty -a | grep columns', $descriptorspec, $pipes, null, null, array('suppress_errors' => true));
if (is_resource($process)) {
$info = stream_get_contents($pipes[1]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);

return $info;
}
}






private function getConsoleMode()
{
if (!function_exists('proc_open')) {
return;
}

$descriptorspec = array(1 => array('pipe', 'w'), 2 => array('pipe', 'w'));
$process = proc_open('mode CON', $descriptorspec, $pipes, null, null, array('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)) {
return $matches[2].'x'.$matches[1];
}
}
}








private function getAbbreviationSuggestions($abbrevs)
{
return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : '');
}











public function extractNamespace($name, $limit = null)
{
$parts = explode(':', $name);
array_pop($parts);

return implode(':', null === $limit ? $parts : array_slice($parts, 0, $limit));
}










private function findAlternatives($name, $collection)
{
$threshold = 1e3;
$alternatives = array();

$collectionParts = array();
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 && false !== strpos($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 || false !== strpos($item, $name)) {
$alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev;
}
}

$alternatives = array_filter($alternatives, function ($lev) use ($threshold) { return $lev < 2 * $threshold; });
asort($alternatives);

return array_keys($alternatives);
}






public function setDefaultCommand($commandName)
{
$this->defaultCommand = $commandName;
}

private function stringWidth($string)
{
if (false === $encoding = mb_detect_encoding($string, null, true)) {
return strlen($string);
}

return mb_strwidth($string, $encoding);
}

private function splitStringByWidth($string, $width)
{

 
 
 if (false === $encoding = mb_detect_encoding($string, null, true)) {
return str_split($string, $width);
}

$utf8String = mb_convert_encoding($string, 'utf8', $encoding);
$lines = array();
$line = '';
foreach (preg_split('//u', $utf8String) as $char) {

 if (mb_strwidth($line.$char, 'utf8') <= $width) {
$line .= $char;
continue;
}

 $lines[] = str_pad($line, $width);
$line = $char;
}
if ('' !== $line) {
$lines[] = count($lines) ? str_pad($line, $width) : $line;
}

mb_convert_variables($encoding, 'utf8', $lines);

return $lines;
}








private function extractAllNamespaces($name)
{

 $parts = explode(':', $name, -1);
$namespaces = array();

foreach ($parts as $part) {
if (count($namespaces)) {
$namespaces[] = end($namespaces).':'.$part;
} else {
$namespaces[] = $part;
}
}

return $namespaces;
}
}
<?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($question, array $choices, $default = null)
{
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 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()
{
$choices = $this->choices;
$errorMessage = $this->errorMessage;
$multiselect = $this->multiselect;
$isAssoc = $this->isAssoc($choices);

return function ($selected) use ($choices, $errorMessage, $multiselect, $isAssoc) {

 $selectedChoices = str_replace(' ', '', $selected);

if ($multiselect) {

 if (!preg_match('/^[a-zA-Z0-9_-]+(?:,[a-zA-Z0-9_-]+)*$/', $selectedChoices, $matches)) {
throw new InvalidArgumentException(sprintf($errorMessage, $selected));
}
$selectedChoices = explode(',', $selectedChoices);
} else {
$selectedChoices = array($selected);
}

$multiselectChoices = array();
foreach ($selectedChoices as $value) {
$results = array();
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;

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 $autocompleterValues;
private $validator;
private $default;
private $normalizer;







public function __construct($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->autocompleterValues) {
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()
{
return $this->autocompleterValues;
}











public function setAutocompleterValues($values)
{
if (is_array($values)) {
$values = $this->isAssoc($values) ? array_merge(array_keys($values), array_values($values)) : array_values($values);
}

if (null !== $values && !is_array($values)) {
if (!$values instanceof \Traversable || !$values instanceof \Countable) {
throw new InvalidArgumentException('Autocompleter values can be either an array, `null` or an object implementing both `Countable` and `Traversable` interfaces.');
}
}

if ($this->hidden) {
throw new LogicException('A hidden question cannot use the autocompleter.');
}

$this->autocompleterValues = $values;

return $this;
}








public function setValidator($validator)
{
$this->validator = $validator;

return $this;
}






public function getValidator()
{
return $this->validator;
}












public function setMaxAttempts($attempts)
{
if (null !== $attempts && $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($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'));
}
}
<?php










namespace Symfony\Component\Console\Question;






class ConfirmationQuestion extends Question
{
private $trueAnswerRegex;








public function __construct($question, $default = true, $trueAnswerRegex = '/^y/i')
{
parent::__construct($question, (bool) $default);

$this->trueAnswerRegex = $trueAnswerRegex;
$this->setNormalizer($this->getDefaultNormalizer());
}






private function getDefaultNormalizer()
{
$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;






final class ConsoleEvents
{












const COMMAND = 'console.command';












const TERMINATE = 'console.terminate';













const EXCEPTION = 'console.exception';
}
<?php










namespace Symfony\Component\Console;

use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Input\StringInput;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Process\ProcessBuilder;
use Symfony\Component\Process\PhpExecutableFinder;












class Shell
{
private $application;
private $history;
private $output;
private $hasReadline;
private $processIsolation = false;









public function __construct(Application $application)
{
@trigger_error('The '.__CLASS__.' class is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);

$this->hasReadline = function_exists('readline');
$this->application = $application;
$this->history = getenv('HOME').'/.history_'.$application->getName();
$this->output = new ConsoleOutput();
}




public function run()
{
$this->application->setAutoExit(false);
$this->application->setCatchExceptions(true);

if ($this->hasReadline) {
readline_read_history($this->history);
readline_completion_function(array($this, 'autocompleter'));
}

$this->output->writeln($this->getHeader());
$php = null;
if ($this->processIsolation) {
$finder = new PhpExecutableFinder();
$php = $finder->find();
$this->output->writeln(<<<'EOF'
<info>Running with process isolation, you should consider this:</info>
  * each command is executed as separate process,
  * commands don't support interactivity, all params must be passed explicitly,
  * commands output is not colorized.

EOF
);
}

while (true) {
$command = $this->readline();

if (false === $command) {
$this->output->writeln("\n");

break;
}

if ($this->hasReadline) {
readline_add_history($command);
readline_write_history($this->history);
}

if ($this->processIsolation) {
$pb = new ProcessBuilder();

$process = $pb
->add($php)
->add($_SERVER['argv'][0])
->add($command)
->inheritEnvironmentVariables(true)
->getProcess()
;

$output = $this->output;
$process->run(function ($type, $data) use ($output) {
$output->writeln($data);
});

$ret = $process->getExitCode();
} else {
$ret = $this->application->run(new StringInput($command), $this->output);
}

if (0 !== $ret) {
$this->output->writeln(sprintf('<error>The command terminated with an error status (%s)</error>', $ret));
}
}
}






protected function getHeader()
{
return <<<EOF

Welcome to the <info>{$this->application->getName()}</info> shell (<comment>{$this->application->getVersion()}</comment>).

At the prompt, type <comment>help</comment> for some help,
or <comment>list</comment> to get a list of available commands.

To exit the shell, type <comment>^D</comment>.

EOF;
}






protected function getPrompt()
{

 return $this->output->getFormatter()->format($this->application->getName().' > ');
}

protected function getOutput()
{
return $this->output;
}

protected function getApplication()
{
return $this->application;
}








private function autocompleter($text)
{
$info = readline_info();
$text = substr($info['line_buffer'], 0, $info['end']);

if ($info['point'] !== $info['end']) {
return true;
}


 if (false === strpos($text, ' ') || !$text) {
return array_keys($this->application->all());
}


 try {
$command = $this->application->find(substr($text, 0, strpos($text, ' ')));
} catch (\Exception $e) {
return true;
}

$list = array('--help');
foreach ($command->getDefinition()->getOptions() as $option) {
$list[] = '--'.$option->getName();
}

return $list;
}






private function readline()
{
if ($this->hasReadline) {
$line = readline($this->getPrompt());
} else {
$this->output->write($this->getPrompt());
$line = fgets(STDIN, 1024);
$line = (false === $line || '' === $line) ? false : rtrim($line);
}

return $line;
}

public function getProcessIsolation()
{
return $this->processIsolation;
}

public function setProcessIsolation($processIsolation)
{
$this->processIsolation = (bool) $processIsolation;

if ($this->processIsolation && !class_exists('Symfony\\Component\\Process\\Process')) {
throw new RuntimeException('Unable to isolate processes as the Symfony Process Component is not installed.');
}
}
}
<?php










namespace Symfony\Component\Console\Tester;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\StreamOutput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;






class CommandTester
{
private $command;
private $input;
private $output;
private $statusCode;






public function __construct(Command $command)
{
$this->command = $command;
}















public function execute(array $input, array $options = array())
{

 
 if (!isset($input['command'])
&& (null !== $application = $this->command->getApplication())
&& $application->getDefinition()->hasArgument('command')
) {
$input = array_merge(array('command' => $this->command->getName()), $input);
}

$this->input = new ArrayInput($input);
if (isset($options['interactive'])) {
$this->input->setInteractive($options['interactive']);
}

$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']);
}

return $this->statusCode = $this->command->run($this->input, $this->output);
}








public function getDisplay($normalize = false)
{
rewind($this->output->getStream());

$display = stream_get_contents($this->output->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;
}
}
<?php










namespace Symfony\Component\Console\Tester;

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\StreamOutput;











class ApplicationTester
{
private $application;
private $input;
private $output;
private $statusCode;






public function __construct(Application $application)
{
$this->application = $application;
}















public function run(array $input, $options = array())
{
$this->input = new ArrayInput($input);
if (isset($options['interactive'])) {
$this->input->setInteractive($options['interactive']);
}

$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']);
}

return $this->statusCode = $this->application->run($this->input, $this->output);
}








public function getDisplay($normalize = false)
{
rewind($this->output->getStream());

$display = stream_get_contents($this->output->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;
}
}
<?php










namespace Symfony\Component\Console\Formatter;

use Symfony\Component\Console\Exception\InvalidArgumentException;






class OutputFormatterStyle implements OutputFormatterStyleInterface
{
private static $availableForegroundColors = array(
'black' => array('set' => 30, 'unset' => 39),
'red' => array('set' => 31, 'unset' => 39),
'green' => array('set' => 32, 'unset' => 39),
'yellow' => array('set' => 33, 'unset' => 39),
'blue' => array('set' => 34, 'unset' => 39),
'magenta' => array('set' => 35, 'unset' => 39),
'cyan' => array('set' => 36, 'unset' => 39),
'white' => array('set' => 37, 'unset' => 39),
'default' => array('set' => 39, 'unset' => 39),
);
private static $availableBackgroundColors = array(
'black' => array('set' => 40, 'unset' => 49),
'red' => array('set' => 41, 'unset' => 49),
'green' => array('set' => 42, 'unset' => 49),
'yellow' => array('set' => 43, 'unset' => 49),
'blue' => array('set' => 44, 'unset' => 49),
'magenta' => array('set' => 45, 'unset' => 49),
'cyan' => array('set' => 46, 'unset' => 49),
'white' => array('set' => 47, 'unset' => 49),
'default' => array('set' => 49, 'unset' => 49),
);
private static $availableOptions = array(
'bold' => array('set' => 1, 'unset' => 22),
'underscore' => array('set' => 4, 'unset' => 24),
'blink' => array('set' => 5, 'unset' => 25),
'reverse' => array('set' => 7, 'unset' => 27),
'conceal' => array('set' => 8, 'unset' => 28),
);

private $foreground;
private $background;
private $options = array();








public function __construct($foreground = null, $background = null, array $options = array())
{
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 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 = array();

foreach ($options as $option) {
$this->setOption($option);
}
}








public function apply($text)
{
$setCodes = array();
$unsetCodes = array();

if (null !== $this->foreground) {
$setCodes[] = $this->foreground['set'];
$unsetCodes[] = $this->foreground['unset'];
}
if (null !== $this->background) {
$setCodes[] = $this->background['set'];
$unsetCodes[] = $this->background['unset'];
}
if (count($this->options)) {
foreach ($this->options as $option) {
$setCodes[] = $option['set'];
$unsetCodes[] = $option['unset'];
}
}

if (0 === count($setCodes)) {
return $text;
}

return sprintf("\033[%sm%s\033[%sm", implode(';', $setCodes), $text, implode(';', $unsetCodes));
}
}
<?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 OutputFormatterStyleStack
{



private $styles;




private $emptyStyle;






public function __construct(OutputFormatterStyleInterface $emptyStyle = null)
{
$this->emptyStyle = $emptyStyle ?: new OutputFormatterStyle();
$this->reset();
}




public function reset()
{
$this->styles = array();
}






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\Formatter;

use Symfony\Component\Console\Exception\InvalidArgumentException;






class OutputFormatter implements OutputFormatterInterface
{
private $decorated;
private $styles = array();
private $styleStack;








public static function escape($text)
{
$text = preg_replace('/([^\\\\]?)</', '$1\\<', $text);

if ('\\' === substr($text, -1)) {
$len = strlen($text);
$text = rtrim($text, '\\');
$text .= str_repeat('<<', $len - strlen($text));
}

return $text;
}







public function __construct($decorated = false, array $styles = array())
{
$this->decorated = (bool) $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)
{
$message = (string) $message;
$offset = 0;
$output = '';
$tagRegex = '[a-z][a-z0-9_=;-]*+';
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));
$offset = $pos + strlen($text);


 if ($open = '/' != $text[1]) {
$tag = $matches[1][$i][0];
} else {
$tag = isset($matches[3][$i][0]) ? $matches[3][$i][0] : '';
}

if (!$open && !$tag) {

 $this->styleStack->pop();
} elseif (false === $style = $this->createStyleFromString(strtolower($tag))) {
$output .= $this->applyCurrentStyle($text);
} elseif ($open) {
$this->styleStack->push($style);
} else {
$this->styleStack->pop($style);
}
}

$output .= $this->applyCurrentStyle(substr($message, $offset));

if (false !== strpos($output, '<<')) {
return strtr($output, array('\\<' => '<', '<<' => '\\'));
}

return str_replace('\\<', '<', $output);
}




public function getStyleStack()
{
return $this->styleStack;
}








private function createStyleFromString($string)
{
if (isset($this->styles[$string])) {
return $this->styles[$string];
}

if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', strtolower($string), $matches, PREG_SET_ORDER)) {
return false;
}

$style = new OutputFormatterStyle();
foreach ($matches as $match) {
array_shift($match);

if ('fg' == $match[0]) {
$style->setForeground($match[1]);
} elseif ('bg' == $match[0]) {
$style->setBackground($match[1]);
} else {
try {
$style->setOption($match[1]);
} catch (\InvalidArgumentException $e) {
return false;
}
}
}

return $style;
}








private function applyCurrentStyle($text)
{
return $this->isDecorated() && strlen($text) > 0 ? $this->styleStack->getCurrent()->apply($text) : $text;
}
}
<?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\Output;

use Symfony\Component\Console\Formatter\OutputFormatterInterface;
use Symfony\Component\Console\Formatter\OutputFormatter;














abstract class Output implements OutputInterface
{
private $verbosity;
private $formatter;








public function __construct($verbosity = self::VERBOSITY_NORMAL, $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)
{
$messages = (array) $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\Formatter\OutputFormatterInterface;














class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
{



private $stderr;








public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null)
{
parent::__construct($this->openOutputStream(), $verbosity, $decorated, $formatter);

$actualDecorated = $this->isDecorated();
$this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated, $this->getFormatter());

if (null === $decorated) {
$this->setDecorated($actualDecorated && $this->stderr->isDecorated());
}
}




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()
{
$checks = array(
function_exists('php_uname') ? php_uname('s') : '',
getenv('OSTYPE'),
PHP_OS,
);

return false !== stripos(implode(';', $checks), 'OS400');
}




private function openOutputStream()
{
$outputStream = $this->hasStdoutSupport() ? 'php://stdout' : 'php://output';

return @fopen($outputStream, 'w') ?: fopen('php://output', 'w');
}




private function openErrorStream()
{
$errorStream = $this->hasStderrSupport() ? 'php://stderr' : 'php://output';

return fopen($errorStream, 'w');
}
}
<?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;







interface ConsoleOutputInterface extends OutputInterface
{





public function getErrorOutput();






public function setErrorOutput(OutputInterface $error);
}
<?php










namespace Symfony\Component\Console\Output;

use Symfony\Component\Console\Formatter\OutputFormatterInterface;






interface OutputInterface
{
const VERBOSITY_QUIET = 16;
const VERBOSITY_NORMAL = 32;
const VERBOSITY_VERBOSE = 64;
const VERBOSITY_VERY_VERBOSE = 128;
const VERBOSITY_DEBUG = 256;

const OUTPUT_NORMAL = 1;
const OUTPUT_RAW = 2;
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 setDecorated($decorated);






public function isDecorated();






public function setFormatter(OutputFormatterInterface $formatter);






public function getFormatter();
}
<?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 .= "\n";
}
}
}
<?php










namespace Symfony\Component\Console\Output;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Formatter\OutputFormatterInterface;














class StreamOutput extends Output
{
private $stream;











public function __construct($stream, $verbosity = self::VERBOSITY_NORMAL, $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 (false === @fwrite($this->stream, $message.($newline ? PHP_EOL : ''))) {

 throw new RuntimeException('Unable to write output.');
}

fflush($this->stream);
}











protected function hasColorSupport()
{
if (DIRECTORY_SEPARATOR === '\\') {
return false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI') || 'xterm' === getenv('TERM');
}

return function_exists('posix_isatty') && @posix_isatty($this->stream);
}
}
<?php










namespace Symfony\Component\Console\Exception;




class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
<?php










namespace Symfony\Component\Console\Exception;






interface ExceptionInterface
{
}
<?php










namespace Symfony\Component\Console\Exception;




class LogicException extends \LogicException implements ExceptionInterface
{
}
<?php










namespace Symfony\Component\Console\Exception;






class CommandNotFoundException extends \InvalidArgumentException implements ExceptionInterface
{
private $alternatives;







public function __construct($message, array $alternatives = array(), $code = 0, \Exception $previous = null)
{
parent::__construct($message, $code, $previous);

$this->alternatives = $alternatives;
}




public function getAlternatives()
{
return $this->alternatives;
}
}
<?php










namespace Symfony\Component\Console\Exception;






class InvalidOptionException extends \InvalidArgumentException implements ExceptionInterface
{
}
<?php










namespace Symfony\Component\Console\Exception;




class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}
<?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\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, $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;






class ConsoleCommandEvent extends ConsoleEvent
{



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 ConsoleExceptionEvent extends ConsoleEvent
{
private $exception;
private $exitCode;

public function __construct(Command $command, InputInterface $input, OutputInterface $output, \Exception $exception, $exitCode)
{
parent::__construct($command, $input, $output);

$this->setException($exception);
$this->exitCode = (int) $exitCode;
}






public function getException()
{
return $this->exception;
}








public function setException(\Exception $exception)
{
$this->exception = $exception;
}






public function getExitCode()
{
return $this->exitCode;
}
}
<?php










namespace Symfony\Component\Console\Command;

use Symfony\Component\Console\Helper\DescriptorHelper;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputDefinition;






class ListCommand extends Command
{



protected function configure()
{
$this
->setName('list')
->setDefinition($this->createDefinition())
->setDescription('Lists 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)
{
if ($input->getOption('xml')) {
@trigger_error('The --xml option was deprecated in version 2.7 and will be removed in version 3.0. Use the --format option instead.', E_USER_DEPRECATED);

$input->setOption('format', 'xml');
}

$helper = new DescriptorHelper();
$helper->describe($output, $this->getApplication(), array(
'format' => $input->getOption('format'),
'raw_text' => $input->getOption('raw'),
'namespace' => $input->getArgument('namespace'),
));
}




private function createDefinition()
{
return new InputDefinition(array(
new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'),
new InputOption('xml', null, InputOption::VALUE_NONE, 'To output list as XML'),
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\Helper\DescriptorHelper;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;






class HelpCommand extends Command
{
private $command;




protected function configure()
{
$this->ignoreValidationErrors();

$this
->setName('help')
->setDefinition(array(
new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'),
new InputOption('xml', null, InputOption::VALUE_NONE, 'To output help as XML'),
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('Displays 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'));
}

if ($input->getOption('xml')) {
@trigger_error('The --xml option was deprecated in version 2.7 and will be removed in version 3.0. Use the --format option instead.', E_USER_DEPRECATED);

$input->setOption('format', 'xml');
}

$helper = new DescriptorHelper();
$helper->describe($output, $this->command, array(
'format' => $input->getOption('format'),
'raw_text' => $input->getOption('raw'),
));

$this->command = null;
}
}
<?php










namespace Symfony\Component\Console\Command;

use Symfony\Component\Console\Descriptor\TextDescriptor;
use Symfony\Component\Console\Descriptor\XmlDescriptor;
use Symfony\Component\Console\Exception\ExceptionInterface;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;






class Command
{
private $application;
private $name;
private $processTitle;
private $aliases = array();
private $definition;
private $help;
private $description;
private $ignoreValidationErrors = false;
private $applicationDefinitionMerged = false;
private $applicationDefinitionMergedWithArgs = false;
private $code;
private $synopsis = array();
private $usages = array();
private $helperSet;








public function __construct($name = null)
{
$this->definition = new InputDefinition();

if (null !== $name) {
$this->setName($name);
}

$this->configure();

if (!$this->name) {
throw new LogicException(sprintf('The command defined in "%s" cannot have an empty name.', get_class($this)));
}
}






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')) {
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 = call_user_func($this->code, $input, $output);
} else {
$statusCode = $this->execute($input, $output);
}

return is_numeric($statusCode) ? (int) $statusCode : 0;
}















public function setCode($code)
{
if (!is_callable($code)) {
throw new InvalidArgumentException('Invalid callable provided to Command::setCode.');
}

if (PHP_VERSION_ID >= 50400 && $code instanceof \Closure) {
$r = new \ReflectionFunction($code);
if (null === $r->getClosureThis()) {
$code = \Closure::bind($code, $this);
}
}

$this->code = $code;

return $this;
}








public function mergeApplicationDefinition($mergeArgs = true)
{
if (null === $this->application || (true === $this->applicationDefinitionMerged && ($this->applicationDefinitionMergedWithArgs || !$mergeArgs))) {
return;
}

if ($mergeArgs) {
$currentArguments = $this->definition->getArguments();
$this->definition->setArguments($this->application->getDefinition()->getArguments());
$this->definition->addArguments($currentArguments);
}

$this->definition->addOptions($this->application->getDefinition()->getOptions());

$this->applicationDefinitionMerged = true;
if ($mergeArgs) {
$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()
{
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 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;

$placeholders = array(
'%command.name%',
'%command.full_name%',
);
$replacements = array(
$name,
$_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 (0 !== strpos($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)
{
return $this->helperSet->get($name);
}








public function asText()
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.3 and will be removed in 3.0.', E_USER_DEPRECATED);

$descriptor = new TextDescriptor();
$output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, true);
$descriptor->describe($output, $this, array('raw_output' => true));

return $output->fetch();
}










public function asXml($asDom = false)
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.3 and will be removed in 3.0.', E_USER_DEPRECATED);

$descriptor = new XmlDescriptor();

if ($asDom) {
return $descriptor->getCommandDocument($this);
}

$output = new BufferedOutput();
$descriptor->describe($output, $this);

return $output->fetch();
}










private function validateName($name)
{
if (!preg_match('/^[^\:]++(\:[^\:]++)*$/', $name)) {
throw new InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name));
}
}
}
<?php










namespace Symfony\Component\Console\Logger;

use Psr\Log\AbstractLogger;
use Psr\Log\InvalidArgumentException;
use Psr\Log\LogLevel;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\ConsoleOutputInterface;








class ConsoleLogger extends AbstractLogger
{
const INFO = 'info';
const ERROR = 'error';




private $output;



private $verbosityLevelMap = array(
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 = array(
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,
);






public function __construct(OutputInterface $output, array $verbosityLevelMap = array(), array $formatLevelMap = array())
{
$this->output = $output;
$this->verbosityLevelMap = $verbosityLevelMap + $this->verbosityLevelMap;
$this->formatLevelMap = $formatLevelMap + $this->formatLevelMap;
}




public function log($level, $message, array $context = array())
{
if (!isset($this->verbosityLevelMap[$level])) {
throw new InvalidArgumentException(sprintf('The log level "%s" does not exist.', $level));
}


 if ($this->formatLevelMap[$level] === self::ERROR && $this->output instanceof ConsoleOutputInterface) {
$output = $this->output->getErrorOutput();
} else {
$output = $this->output;
}

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)));
}
}











private function interpolate($message, array $context)
{

 $replace = array();
foreach ($context as $key => $val) {
if (!is_array($val) && (!is_object($val) || method_exists($val, '__toString'))) {
$replace[sprintf('{%s}', $key)] = $val;
}
}


 return strtr($message, $replace);
}
}
<?php










namespace Symfony\Component\Console\Input;






interface InputInterface
{





public function getFirstArgument();











public function hasParameterOption($values);












public function getParameterOption($values, $default = 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;







interface InputAwareInterface
{





public function setInput(InputInterface $input);
}
<?php










namespace Symfony\Component\Console\Input;

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;






class InputArgument
{
const REQUIRED = 1;
const OPTIONAL = 2;
const IS_ARRAY = 4;

private $name;
private $mode;
private $default;
private $description;











public function __construct($name, $mode = null, $description = '', $default = null)
{
if (null === $mode) {
$mode = self::OPTIONAL;
} elseif (!is_int($mode) || $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 = array();
} 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;










class StringInput extends ArgvInput
{
const REGEX_STRING = '([^\s]+?)(?:\s|(?<!\\\\)"|(?<!\\\\)\'|$)';
const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')';









public function __construct($input, InputDefinition $definition = null)
{
if ($definition) {
@trigger_error('The $definition argument of the '.__METHOD__.' method is deprecated and will be removed in 3.0. Set this parameter with the bind() method instead.', E_USER_DEPRECATED);
}

parent::__construct(array(), null);

$this->setTokens($this->tokenize($input));

if (null !== $definition) {
$this->bind($definition);
}
}










private function tokenize($input)
{
$tokens = array();
$length = strlen($input);
$cursor = 0;
while ($cursor < $length) {
if (preg_match('/\s+/A', $input, $match, null, $cursor)) {
} elseif (preg_match('/([^="\'\s]+?)(=?)('.self::REGEX_QUOTED_STRING.'+)/A', $input, $match, null, $cursor)) {
$tokens[] = $match[1].$match[2].stripcslashes(str_replace(array('"\'', '\'"', '\'\'', '""'), '', substr($match[3], 1, strlen($match[3]) - 2)));
} elseif (preg_match('/'.self::REGEX_QUOTED_STRING.'/A', $input, $match, null, $cursor)) {
$tokens[] = stripcslashes(substr($match[0], 1, strlen($match[0]) - 2));
} elseif (preg_match('/'.self::REGEX_STRING.'/A', $input, $match, null, $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\RuntimeException;












abstract class Input implements InputInterface
{



protected $definition;
protected $options = array();
protected $arguments = array();
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 = array();
$this->options = array();
$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($name)) {
throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
}

return isset($this->arguments[$name]) ? $this->arguments[$name] : $this->definition->getArgument($name)->getDefault();
}









public function setArgument($name, $value)
{
if (!$this->definition->hasArgument($name)) {
throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
}

$this->arguments[$name] = $value;
}








public function hasArgument($name)
{
return $this->definition->hasArgument($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 isset($this->options[$name]) ? $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);
}
}
<?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 $key => $value) {
if ($key && '-' === $key[0]) {
continue;
}

return $value;
}
}











public function hasParameterOption($values)
{
$values = (array) $values;

foreach ($this->parameters as $k => $v) {
if (!is_int($k)) {
$v = $k;
}

if (in_array($v, $values)) {
return true;
}
}

return false;
}












public function getParameterOption($values, $default = false)
{
$values = (array) $values;

foreach ($this->parameters as $k => $v) {
if (is_int($k)) {
if (in_array($v, $values)) {
return true;
}
} elseif (in_array($k, $values)) {
return $v;
}
}

return $default;
}






public function __toString()
{
$params = array();
foreach ($this->parameters as $param => $val) {
if ($param && '-' === $param[0]) {
$params[] = $param.('' != $val ? '='.$this->escapeToken($val) : '');
} else {
$params[] = $this->escapeToken($val);
}
}

return implode(' ', $params);
}




protected function parse()
{
foreach ($this->parameters as $key => $value) {
if (0 === strpos($key, '--')) {
$this->addLongOption(substr($key, 2), $value);
} elseif ('-' === $key[0]) {
$this->addShortOption(substr($key, 1), $value);
} else {
$this->addArgument($key, $value);
}
}
}









private function addShortOption($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($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));
}

$value = $option->isValueOptional() ? $option->getDefault() : 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;

use Symfony\Component\Console\Descriptor\TextDescriptor;
use Symfony\Component\Console\Descriptor\XmlDescriptor;
use Symfony\Component\Console\Output\BufferedOutput;
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 = array())
{
$this->setDefinition($definition);
}






public function setDefinition(array $definition)
{
$arguments = array();
$options = array();
foreach ($definition as $item) {
if ($item instanceof InputOption) {
$options[] = $item;
} else {
$arguments[] = $item;
}
}

$this->setArguments($arguments);
$this->setOptions($options);
}






public function setArguments($arguments = array())
{
$this->arguments = array();
$this->requiredCount = 0;
$this->hasOptional = false;
$this->hasAnArrayArgument = false;
$this->addArguments($arguments);
}






public function addArguments($arguments = array())
{
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 = array();
foreach ($this->arguments as $argument) {
$values[$argument->getName()] = $argument->getDefault();
}

return $values;
}






public function setOptions($options = array())
{
$this->options = array();
$this->shortcuts = array();
$this->addOptions($options);
}






public function addOptions($options = array())
{
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 = array();
foreach ($this->options as $option) {
$values[$option->getName()] = $option->getDefault();
}

return $values;
}










private function shortcutToName($shortcut)
{
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 = array();

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[] = '[--]';
}

foreach ($this->getArguments() as $argument) {
$element = '<'.$argument->getName().'>';
if (!$argument->isRequired()) {
$element = '['.$element.']';
} elseif ($argument->isArray()) {
$element = $element.' ('.$element.')';
}

if ($argument->isArray()) {
$element .= '...';
}

$elements[] = $element;
}

return implode(' ', $elements);
}








public function asText()
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.3 and will be removed in 3.0.', E_USER_DEPRECATED);

$descriptor = new TextDescriptor();
$output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, true);
$descriptor->describe($output, $this, array('raw_output' => true));

return $output->fetch();
}










public function asXml($asDom = false)
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.3 and will be removed in 3.0.', E_USER_DEPRECATED);

$descriptor = new XmlDescriptor();

if ($asDom) {
return $descriptor->getInputDefinitionDocument($this);
}

$output = new BufferedOutput();
$descriptor->describe($output, $this);

return $output->fetch();
}
}
<?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)
{
if (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 && 0 === strpos($token, '--')) {
$this->parseLongOption($token);
} elseif ($parseOptions && '-' === $token[0] && '-' !== $token) {
$this->parseShortOption($token);
} else {
$this->parseArgument($token);
}
}
}






private function parseShortOption($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($name)
{
$len = strlen($name);
for ($i = 0; $i < $len; ++$i) {
if (!$this->definition->hasShortcut($name[$i])) {
throw new RuntimeException(sprintf('The "-%s" option does not exist.', $name[$i]));
}

$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($token)
{
$name = substr($token, 2);

if (false !== $pos = strpos($name, '=')) {
$this->addLongOption(substr($name, 0, $pos), substr($name, $pos + 1));
} else {
$this->addLongOption($name, null);
}
}








private function parseArgument($token)
{
$c = count($this->arguments);


 if ($this->definition->hasArgument($c)) {
$arg = $this->definition->getArgument($c);
$this->arguments[$arg->getName()] = $arg->isArray() ? array($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 {
throw new RuntimeException('Too many arguments.');
}
}









private function addShortOption($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($name, $value)
{
if (!$this->definition->hasOption($name)) {
throw new RuntimeException(sprintf('The "--%s" option does not exist.', $name));
}

$option = $this->definition->getOption($name);


 if (!isset($value[0])) {
$value = null;
}

if (null !== $value && !$option->acceptValue()) {
throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name));
}

if (null === $value && $option->acceptValue() && count($this->parsed)) {

 
 $next = array_shift($this->parsed);
if (isset($next[0]) && '-' !== $next[0]) {
$value = $next;
} elseif (empty($next)) {
$value = '';
} 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()) {
$value = $option->isValueOptional() ? $option->getDefault() : true;
}
}

if ($option->isArray()) {
$this->options[$name][] = $value;
} else {
$this->options[$name] = $value;
}
}






public function getFirstArgument()
{
foreach ($this->tokens as $token) {
if ($token && '-' === $token[0]) {
continue;
}

return $token;
}
}











public function hasParameterOption($values)
{
$values = (array) $values;

foreach ($this->tokens as $token) {
foreach ($values as $value) {
if ($token === $value || 0 === strpos($token, $value.'=')) {
return true;
}
}
}

return false;
}












public function getParameterOption($values, $default = false)
{
$values = (array) $values;
$tokens = $this->tokens;

while (0 < count($tokens)) {
$token = array_shift($tokens);

foreach ($values as $value) {
if ($token === $value || 0 === strpos($token, $value.'=')) {
if (false !== $pos = strpos($token, '=')) {
return substr($token, $pos + 1);
}

return array_shift($tokens);
}
}
}

return $default;
}






public function __toString()
{
$self = $this;
$tokens = array_map(function ($token) use ($self) {
if (preg_match('{^(-[^=]+=)(.+)}', $token, $match)) {
return $match[1].$self->escapeToken($match[2]);
}

if ($token && $token[0] !== '-') {
return $self->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\LogicException;






class InputOption
{
const VALUE_NONE = 1;
const VALUE_REQUIRED = 2;
const VALUE_OPTIONAL = 4;
const VALUE_IS_ARRAY = 8;

private $name;
private $shortcut;
private $mode;
private $default;
private $description;












public function __construct($name, $shortcut = null, $mode = null, $description = '', $default = null)
{
if (0 === strpos($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 (!is_int($mode) || $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 = array();
} 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(InputOption $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\Finder\Expression;

@trigger_error('The '.__NAMESPACE__.'\Expression class is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);




class Expression implements ValueInterface
{
const TYPE_REGEX = 1;
const TYPE_GLOB = 2;




private $value;






public static function create($expr)
{
return new self($expr);
}




public function __construct($expr)
{
try {
$this->value = Regex::create($expr);
} catch (\InvalidArgumentException $e) {
$this->value = new Glob($expr);
}
}




public function __toString()
{
return $this->render();
}




public function render()
{
return $this->value->render();
}




public function renderPattern()
{
return $this->value->renderPattern();
}




public function isCaseSensitive()
{
return $this->value->isCaseSensitive();
}




public function getType()
{
return $this->value->getType();
}




public function prepend($expr)
{
$this->value->prepend($expr);

return $this;
}




public function append($expr)
{
$this->value->append($expr);

return $this;
}




public function isRegex()
{
return self::TYPE_REGEX === $this->value->getType();
}




public function isGlob()
{
return self::TYPE_GLOB === $this->value->getType();
}






public function getGlob()
{
if (self::TYPE_GLOB !== $this->value->getType()) {
throw new \LogicException('Regex can\'t be transformed to glob.');
}

return $this->value;
}




public function getRegex()
{
return self::TYPE_REGEX === $this->value->getType() ? $this->value : $this->value->toRegex();
}
}
<?php










namespace Symfony\Component\Finder\Expression;

@trigger_error('The '.__NAMESPACE__.'\Glob class is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);

use Symfony\Component\Finder\Glob as FinderGlob;




class Glob implements ValueInterface
{



private $pattern;




public function __construct($pattern)
{
$this->pattern = $pattern;
}




public function render()
{
return $this->pattern;
}




public function renderPattern()
{
return $this->pattern;
}




public function getType()
{
return Expression::TYPE_GLOB;
}




public function isCaseSensitive()
{
return true;
}




public function prepend($expr)
{
$this->pattern = $expr.$this->pattern;

return $this;
}




public function append($expr)
{
$this->pattern .= $expr;

return $this;
}






public function isExpandable()
{
return false !== strpos($this->pattern, '{')
&& false !== strpos($this->pattern, '}');
}







public function toRegex($strictLeadingDot = true, $strictWildcardSlash = true)
{
$regex = FinderGlob::toRegex($this->pattern, $strictLeadingDot, $strictWildcardSlash, '');

return new Regex($regex);
}
}
<?php










namespace Symfony\Component\Finder\Expression;

@trigger_error('The '.__NAMESPACE__.'\ValueInterface interface is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);




interface ValueInterface
{





public function render();






public function renderPattern();






public function isCaseSensitive();






public function getType();






public function prepend($expr);






public function append($expr);
}
<?php










namespace Symfony\Component\Finder\Expression;

@trigger_error('The '.__NAMESPACE__.'\Regex class is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);




class Regex implements ValueInterface
{
const START_FLAG = '^';
const END_FLAG = '$';
const BOUNDARY = '~';
const JOKER = '.*';
const ESCAPING = '\\';




private $pattern;




private $options;




private $startFlag;




private $endFlag;




private $startJoker;




private $endJoker;








public static function create($expr)
{
if (preg_match('/^(.{3,}?)([imsxuADU]*)$/', $expr, $m)) {
$start = substr($m[1], 0, 1);
$end = substr($m[1], -1);

if (
($start === $end && !preg_match('/[*?[:alnum:] \\\\]/', $start))
|| ($start === '{' && $end === '}')
|| ($start === '(' && $end === ')')
) {
return new self(substr($m[1], 1, -1), $m[2], $end);
}
}

throw new \InvalidArgumentException('Given expression is not a regex.');
}






public function __construct($pattern, $options = '', $delimiter = null)
{
if (null !== $delimiter) {

 $pattern = str_replace('\\'.$delimiter, $delimiter, $pattern);
}

$this->parsePattern($pattern);
$this->options = $options;
}




public function __toString()
{
return $this->render();
}




public function render()
{
return self::BOUNDARY
.$this->renderPattern()
.self::BOUNDARY
.$this->options;
}




public function renderPattern()
{
return ($this->startFlag ? self::START_FLAG : '')
.($this->startJoker ? self::JOKER : '')
.str_replace(self::BOUNDARY, '\\'.self::BOUNDARY, $this->pattern)
.($this->endJoker ? self::JOKER : '')
.($this->endFlag ? self::END_FLAG : '');
}




public function isCaseSensitive()
{
return !$this->hasOption('i');
}




public function getType()
{
return Expression::TYPE_REGEX;
}




public function prepend($expr)
{
$this->pattern = $expr.$this->pattern;

return $this;
}




public function append($expr)
{
$this->pattern .= $expr;

return $this;
}






public function hasOption($option)
{
return false !== strpos($this->options, $option);
}






public function addOption($option)
{
if (!$this->hasOption($option)) {
$this->options .= $option;
}

return $this;
}






public function removeOption($option)
{
$this->options = str_replace($option, '', $this->options);

return $this;
}






public function setStartFlag($startFlag)
{
$this->startFlag = $startFlag;

return $this;
}




public function hasStartFlag()
{
return $this->startFlag;
}






public function setEndFlag($endFlag)
{
$this->endFlag = (bool) $endFlag;

return $this;
}




public function hasEndFlag()
{
return $this->endFlag;
}






public function setStartJoker($startJoker)
{
$this->startJoker = $startJoker;

return $this;
}




public function hasStartJoker()
{
return $this->startJoker;
}






public function setEndJoker($endJoker)
{
$this->endJoker = (bool) $endJoker;

return $this;
}




public function hasEndJoker()
{
return $this->endJoker;
}






public function replaceJokers($replacement)
{
$replace = function ($subject) use ($replacement) {
$subject = $subject[0];
$replace = 0 === substr_count($subject, '\\') % 2;

return $replace ? str_replace('.', $replacement, $subject) : $subject;
};

$this->pattern = preg_replace_callback('~[\\\\]*\\.~', $replace, $this->pattern);

return $this;
}




private function parsePattern($pattern)
{
if ($this->startFlag = self::START_FLAG === substr($pattern, 0, 1)) {
$pattern = substr($pattern, 1);
}

if ($this->startJoker = self::JOKER === substr($pattern, 0, 2)) {
$pattern = substr($pattern, 2);
}

if ($this->endFlag = (self::END_FLAG === substr($pattern, -1) && self::ESCAPING !== substr($pattern, -2, -1))) {
$pattern = substr($pattern, 0, -1);
}

if ($this->endJoker = (self::JOKER === substr($pattern, -2) && self::ESCAPING !== substr($pattern, -3, -2))) {
$pattern = substr($pattern, 0, -2);
}

$this->pattern = $pattern;
}
}
<?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) {
if ($strictLeadingDot && '.' !== $car) {
$regex .= '(?=[^\.])';
}

$firstByte = false;
}

if ('/' === $car) {
$firstByte = true;
}

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\Adapter;

@trigger_error('The '.__NAMESPACE__.'\PhpAdapter class is deprecated since version 2.8 and will be removed in 3.0. Use directly the Finder class instead.', E_USER_DEPRECATED);

use Symfony\Component\Finder\Iterator;








class PhpAdapter extends AbstractAdapter
{



public function searchInDirectory($dir)
{
$flags = \RecursiveDirectoryIterator::SKIP_DOTS;

if ($this->followLinks) {
$flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS;
}

$iterator = new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs);

if ($this->exclude) {
$iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
}

$iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST);

if ($this->minDepth > 0 || $this->maxDepth < PHP_INT_MAX) {
$iterator = new Iterator\DepthRangeFilterIterator($iterator, $this->minDepth, $this->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 || $this->notPaths) {
$iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $this->notPaths);
}

if ($this->sort) {
$iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
$iterator = $iteratorAggregate->getIterator();
}

return $iterator;
}




public function getName()
{
return 'php';
}




protected function canBeUsed()
{
return true;
}
}
<?php










namespace Symfony\Component\Finder\Adapter;

@trigger_error('The '.__NAMESPACE__.'\AbstractFindAdapter class is deprecated since version 2.8 and will be removed in 3.0. Use directly the Finder class instead.', E_USER_DEPRECATED);

use Symfony\Component\Finder\Exception\AccessDeniedException;
use Symfony\Component\Finder\Iterator;
use Symfony\Component\Finder\Shell\Shell;
use Symfony\Component\Finder\Expression\Expression;
use Symfony\Component\Finder\Shell\Command;
use Symfony\Component\Finder\Comparator\NumberComparator;
use Symfony\Component\Finder\Comparator\DateComparator;








abstract class AbstractFindAdapter extends AbstractAdapter
{



protected $shell;




public function __construct()
{
$this->shell = new Shell();
}




public function searchInDirectory($dir)
{

 $dir = realpath($dir);


 if (Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES === $this->mode && ($this->contains || $this->notContains)) {
return new Iterator\FilePathsIterator(array(), $dir);
}

$command = Command::create();
$find = $this->buildFindCommand($command, $dir);

if ($this->followLinks) {
$find->add('-follow');
}

$find->add('-mindepth')->add($this->minDepth + 1);

if (PHP_INT_MAX !== $this->maxDepth) {
$find->add('-maxdepth')->add($this->maxDepth + 1);
}

if (Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES === $this->mode) {
$find->add('-type d');
} elseif (Iterator\FileTypeFilterIterator::ONLY_FILES === $this->mode) {
$find->add('-type f');
}

$this->buildNamesFiltering($find, $this->names);
$this->buildNamesFiltering($find, $this->notNames, true);
$this->buildPathsFiltering($find, $dir, $this->paths);
$this->buildPathsFiltering($find, $dir, $this->notPaths, true);
$this->buildSizesFiltering($find, $this->sizes);
$this->buildDatesFiltering($find, $this->dates);

$useGrep = $this->shell->testCommand('grep') && $this->shell->testCommand('xargs');
$useSort = is_int($this->sort) && $this->shell->testCommand('sort') && $this->shell->testCommand('cut');

if ($useGrep && ($this->contains || $this->notContains)) {
$grep = $command->ins('grep');
$this->buildContentFiltering($grep, $this->contains);
$this->buildContentFiltering($grep, $this->notContains, true);
}

if ($useSort) {
$this->buildSorting($command, $this->sort);
}

$command->setErrorHandler(
$this->ignoreUnreadableDirs

 ? function ($stderr) { }
: function ($stderr) { throw new AccessDeniedException($stderr); }
);

$paths = $this->shell->testCommand('uniq') ? $command->add('| uniq')->execute() : array_unique($command->execute());
$iterator = new Iterator\FilePathsIterator($paths, $dir);

if ($this->exclude) {
$iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
}

if (!$useGrep && ($this->contains || $this->notContains)) {
$iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
}

if ($this->filters) {
$iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
}

if (!$useSort && $this->sort) {
$iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
$iterator = $iteratorAggregate->getIterator();
}

return $iterator;
}




protected function canBeUsed()
{
return $this->shell->testCommand('find');
}







protected function buildFindCommand(Command $command, $dir)
{
return $command
->ins('find')
->add('find ')
->arg($dir)
->add('-noleaf'); 
 }






private function buildNamesFiltering(Command $command, array $names, $not = false)
{
if (0 === count($names)) {
return;
}

$command->add($not ? '-not' : null)->cmd('(');

foreach ($names as $i => $name) {
$expr = Expression::create($name);


 if ($expr->isGlob() && $expr->getGlob()->isExpandable()) {
$expr = Expression::create($expr->getGlob()->toRegex(false));
}


 
 
 if ($expr->isRegex()) {
$regex = $expr->getRegex();
$regex->prepend($regex->hasStartFlag() ? '/' : '/[^/]*')
->setStartFlag(false)
->setStartJoker(true)
->replaceJokers('[^/]');
if (!$regex->hasEndFlag() || $regex->hasEndJoker()) {
$regex->setEndJoker(false)->append('[^/]*');
}
}

$command
->add($i > 0 ? '-or' : null)
->add($expr->isRegex()
? ($expr->isCaseSensitive() ? '-regex' : '-iregex')
: ($expr->isCaseSensitive() ? '-name' : '-iname')
)
->arg($expr->renderPattern());
}

$command->cmd(')');
}







private function buildPathsFiltering(Command $command, $dir, array $paths, $not = false)
{
if (0 === count($paths)) {
return;
}

$command->add($not ? '-not' : null)->cmd('(');

foreach ($paths as $i => $path) {
$expr = Expression::create($path);


 if ($expr->isGlob() && $expr->getGlob()->isExpandable()) {
$expr = Expression::create($expr->getGlob()->toRegex(false));
}


 if ($expr->isRegex()) {
$regex = $expr->getRegex();
$regex->prepend($regex->hasStartFlag() ? preg_quote($dir).DIRECTORY_SEPARATOR : '.*')->setEndJoker(!$regex->hasEndFlag());
} else {
$expr->prepend('*')->append('*');
}

$command
->add($i > 0 ? '-or' : null)
->add($expr->isRegex()
? ($expr->isCaseSensitive() ? '-regex' : '-iregex')
: ($expr->isCaseSensitive() ? '-path' : '-ipath')
)
->arg($expr->renderPattern());
}

$command->cmd(')');
}





private function buildSizesFiltering(Command $command, array $sizes)
{
foreach ($sizes as $i => $size) {
$command->add($i > 0 ? '-and' : null);

switch ($size->getOperator()) {
case '<=':
$command->add('-size -'.($size->getTarget() + 1).'c');
break;
case '>=':
$command->add('-size +'.($size->getTarget() - 1).'c');
break;
case '>':
$command->add('-size +'.$size->getTarget().'c');
break;
case '!=':
$command->add('-size -'.$size->getTarget().'c');
$command->add('-size +'.$size->getTarget().'c');
break;
case '<':
default:
$command->add('-size -'.$size->getTarget().'c');
}
}
}





private function buildDatesFiltering(Command $command, array $dates)
{
foreach ($dates as $i => $date) {
$command->add($i > 0 ? '-and' : null);

$mins = (int) round((time() - $date->getTarget()) / 60);

if (0 > $mins) {

 $command->add(' -mmin -0');

 return;
}

switch ($date->getOperator()) {
case '<=':
$command->add('-mmin +'.($mins - 1));
break;
case '>=':
$command->add('-mmin -'.($mins + 1));
break;
case '>':
$command->add('-mmin -'.$mins);
break;
case '!=':
$command->add('-mmin +'.$mins.' -or -mmin -'.$mins);
break;
case '<':
default:
$command->add('-mmin +'.$mins);
}
}
}







private function buildSorting(Command $command, $sort)
{
$this->buildFormatSorting($command, $sort);
}





abstract protected function buildFormatSorting(Command $command, $sort);






abstract protected function buildContentFiltering(Command $command, array $contains, $not = false);
}
<?php










namespace Symfony\Component\Finder\Adapter;

@trigger_error('The '.__NAMESPACE__.'\BsdFindAdapter class is deprecated since version 2.8 and will be removed in 3.0. Use directly the Finder class instead.', E_USER_DEPRECATED);

use Symfony\Component\Finder\Shell\Shell;
use Symfony\Component\Finder\Shell\Command;
use Symfony\Component\Finder\Iterator\SortableIterator;
use Symfony\Component\Finder\Expression\Expression;








class BsdFindAdapter extends AbstractFindAdapter
{



public function getName()
{
return 'bsd_find';
}




protected function canBeUsed()
{
return in_array($this->shell->getType(), array(Shell::TYPE_BSD, Shell::TYPE_DARWIN)) && parent::canBeUsed();
}




protected function buildFormatSorting(Command $command, $sort)
{
switch ($sort) {
case SortableIterator::SORT_BY_NAME:
$command->ins('sort')->add('| sort');

return;
case SortableIterator::SORT_BY_TYPE:
$format = '%HT';
break;
case SortableIterator::SORT_BY_ACCESSED_TIME:
$format = '%a';
break;
case SortableIterator::SORT_BY_CHANGED_TIME:
$format = '%c';
break;
case SortableIterator::SORT_BY_MODIFIED_TIME:
$format = '%m';
break;
default:
throw new \InvalidArgumentException(sprintf('Unknown sort options: %s.', $sort));
}

$command
->add('-print0 | xargs -0 stat -f')
->arg($format.'%t%N')
->add('| sort | cut -f 2');
}




protected function buildFindCommand(Command $command, $dir)
{
parent::buildFindCommand($command, $dir)->addAtIndex('-E', 1);

return $command;
}




protected function buildContentFiltering(Command $command, array $contains, $not = false)
{
foreach ($contains as $contain) {
$expr = Expression::create($contain);


 $command
->add('| grep -v \'^$\'')
->add('| xargs -I{} grep -I')
->add($expr->isCaseSensitive() ? null : '-i')
->add($not ? '-L' : '-l')
->add('-Ee')->arg($expr->renderPattern())
->add('{}')
;
}
}
}
<?php










namespace Symfony\Component\Finder\Adapter;






interface AdapterInterface
{





public function setFollowLinks($followLinks);






public function setMode($mode);






public function setExclude(array $exclude);






public function setDepths(array $depths);






public function setNames(array $names);






public function setNotNames(array $notNames);






public function setContains(array $contains);






public function setNotContains(array $notContains);






public function setSizes(array $sizes);






public function setDates(array $dates);






public function setFilters(array $filters);






public function setSort($sort);






public function setPath(array $paths);






public function setNotPath(array $notPaths);






public function ignoreUnreadableDirs($ignore = true);






public function searchInDirectory($dir);






public function isSupported();






public function getName();
}
<?php










namespace Symfony\Component\Finder\Adapter;

@trigger_error('The '.__NAMESPACE__.'\AbstractAdapter class is deprecated since version 2.8 and will be removed in 3.0. Use directly the Finder class instead.', E_USER_DEPRECATED);








abstract class AbstractAdapter implements AdapterInterface
{
protected $followLinks = false;
protected $mode = 0;
protected $minDepth = 0;
protected $maxDepth = PHP_INT_MAX;
protected $exclude = array();
protected $names = array();
protected $notNames = array();
protected $contains = array();
protected $notContains = array();
protected $sizes = array();
protected $dates = array();
protected $filters = array();
protected $sort = false;
protected $paths = array();
protected $notPaths = array();
protected $ignoreUnreadableDirs = false;

private static $areSupported = array();




public function isSupported()
{
$name = $this->getName();

if (!array_key_exists($name, self::$areSupported)) {
self::$areSupported[$name] = $this->canBeUsed();
}

return self::$areSupported[$name];
}




public function setFollowLinks($followLinks)
{
$this->followLinks = $followLinks;

return $this;
}




public function setMode($mode)
{
$this->mode = $mode;

return $this;
}




public function setDepths(array $depths)
{
$this->minDepth = 0;
$this->maxDepth = PHP_INT_MAX;

foreach ($depths as $comparator) {
switch ($comparator->getOperator()) {
case '>':
$this->minDepth = $comparator->getTarget() + 1;
break;
case '>=':
$this->minDepth = $comparator->getTarget();
break;
case '<':
$this->maxDepth = $comparator->getTarget() - 1;
break;
case '<=':
$this->maxDepth = $comparator->getTarget();
break;
default:
$this->minDepth = $this->maxDepth = $comparator->getTarget();
}
}

return $this;
}




public function setExclude(array $exclude)
{
$this->exclude = $exclude;

return $this;
}




public function setNames(array $names)
{
$this->names = $names;

return $this;
}




public function setNotNames(array $notNames)
{
$this->notNames = $notNames;

return $this;
}




public function setContains(array $contains)
{
$this->contains = $contains;

return $this;
}




public function setNotContains(array $notContains)
{
$this->notContains = $notContains;

return $this;
}




public function setSizes(array $sizes)
{
$this->sizes = $sizes;

return $this;
}




public function setDates(array $dates)
{
$this->dates = $dates;

return $this;
}




public function setFilters(array $filters)
{
$this->filters = $filters;

return $this;
}




public function setSort($sort)
{
$this->sort = $sort;

return $this;
}




public function setPath(array $paths)
{
$this->paths = $paths;

return $this;
}




public function setNotPath(array $notPaths)
{
$this->notPaths = $notPaths;

return $this;
}




public function ignoreUnreadableDirs($ignore = true)
{
$this->ignoreUnreadableDirs = (bool) $ignore;

return $this;
}












abstract protected function canBeUsed();
}
<?php










namespace Symfony\Component\Finder\Adapter;

@trigger_error('The '.__NAMESPACE__.'\GnuFindAdapter class is deprecated since version 2.8 and will be removed in 3.0. Use directly the Finder class instead.', E_USER_DEPRECATED);

use Symfony\Component\Finder\Shell\Shell;
use Symfony\Component\Finder\Shell\Command;
use Symfony\Component\Finder\Iterator\SortableIterator;
use Symfony\Component\Finder\Expression\Expression;








class GnuFindAdapter extends AbstractFindAdapter
{



public function getName()
{
return 'gnu_find';
}




protected function buildFormatSorting(Command $command, $sort)
{
switch ($sort) {
case SortableIterator::SORT_BY_NAME:
$command->ins('sort')->add('| sort');

return;
case SortableIterator::SORT_BY_TYPE:
$format = '%y';
break;
case SortableIterator::SORT_BY_ACCESSED_TIME:
$format = '%A@';
break;
case SortableIterator::SORT_BY_CHANGED_TIME:
$format = '%C@';
break;
case SortableIterator::SORT_BY_MODIFIED_TIME:
$format = '%T@';
break;
default:
throw new \InvalidArgumentException(sprintf('Unknown sort options: %s.', $sort));
}

$command
->get('find')
->add('-printf')
->arg($format.' %h/%f\\n')
->add('| sort | cut')
->arg('-d ')
->arg('-f2-')
;
}




protected function canBeUsed()
{
return $this->shell->getType() === Shell::TYPE_UNIX && parent::canBeUsed();
}




protected function buildFindCommand(Command $command, $dir)
{
return parent::buildFindCommand($command, $dir)->add('-regextype posix-extended');
}




protected function buildContentFiltering(Command $command, array $contains, $not = false)
{
foreach ($contains as $contain) {
$expr = Expression::create($contain);


 $command
->add('| xargs -I{} -r grep -I')
->add($expr->isCaseSensitive() ? null : '-i')
->add($not ? '-L' : '-l')
->add('-Ee')->arg($expr->renderPattern())
->add('{}')
;
}
}
}
<?php










namespace Symfony\Component\Finder;

use Symfony\Component\Finder\Adapter\AdapterInterface;
use Symfony\Component\Finder\Adapter\GnuFindAdapter;
use Symfony\Component\Finder\Adapter\BsdFindAdapter;
use Symfony\Component\Finder\Adapter\PhpAdapter;
use Symfony\Component\Finder\Comparator\DateComparator;
use Symfony\Component\Finder\Comparator\NumberComparator;
use Symfony\Component\Finder\Exception\ExceptionInterface;
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\SizeRangeFilterIterator;
use Symfony\Component\Finder\Iterator\SortableIterator;














class Finder implements \IteratorAggregate, \Countable
{
const IGNORE_VCS_FILES = 1;
const IGNORE_DOT_FILES = 2;

private $mode = 0;
private $names = array();
private $notNames = array();
private $exclude = array();
private $filters = array();
private $depths = array();
private $sizes = array();
private $followLinks = false;
private $sort = false;
private $ignore = 0;
private $dirs = array();
private $dates = array();
private $iterators = array();
private $contains = array();
private $notContains = array();
private $adapters = null;
private $paths = array();
private $notPaths = array();
private $ignoreUnreadableDirs = false;

private static $vcsPatterns = array('.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 addAdapter(AdapterInterface $adapter, $priority = 0)
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);

$this->initDefaultAdapters();

$this->adapters[$adapter->getName()] = array(
'adapter' => $adapter,
'priority' => $priority,
'selected' => false,
);

return $this->sortAdapters();
}








public function useBestAdapter()
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);

$this->initDefaultAdapters();

$this->resetAdapterSelection();

return $this->sortAdapters();
}












public function setAdapter($name)
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);

$this->initDefaultAdapters();

if (!isset($this->adapters[$name])) {
throw new \InvalidArgumentException(sprintf('Adapter "%s" does not exist.', $name));
}

$this->resetAdapterSelection();
$this->adapters[$name]['selected'] = true;

return $this->sortAdapters();
}








public function removeAdapters()
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);

$this->adapters = array();

return $this;
}








public function getAdapters()
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);

$this->initDefaultAdapters();

return array_values(array_map(function (array $adapter) {
return $adapter['adapter'];
}, $this->adapters));
}






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($level)
{
$this->depths[] = new Comparator\NumberComparator($level);

return $this;
}



















public function date($date)
{
$this->dates[] = new Comparator\DateComparator($date);

return $this;
}
















public function name($pattern)
{
$this->names[] = $pattern;

return $this;
}










public function notName($pattern)
{
$this->notNames[] = $pattern;

return $this;
}















public function contains($pattern)
{
$this->contains[] = $pattern;

return $this;
}















public function notContains($pattern)
{
$this->notContains[] = $pattern;

return $this;
}

















public function path($pattern)
{
$this->paths[] = $pattern;

return $this;
}

















public function notPath($pattern)
{
$this->notPaths[] = $pattern;

return $this;
}















public function size($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 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()
{
$this->sort = 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 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 = array();

foreach ((array) $dirs as $dir) {
if (is_dir($dir)) {
$resolvedDirs[] = $dir;
} elseif ($glob = glob($dir, (defined('GLOB_BRACE') ? GLOB_BRACE : 0) | GLOB_ONLYDIR)) {
$resolvedDirs = array_merge($resolvedDirs, $glob);
} else {
throw new \InvalidArgumentException(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)) {
return $this->searchInDirectory($this->dirs[0]);
}

$iterator = new \AppendIterator();
foreach ($this->dirs as $dir) {
$iterator->append($this->searchInDirectory($dir));
}

foreach ($this->iterators as $it) {
$iterator->append($it);
}

return $iterator;
}












public function append($iterator)
{
if ($iterator instanceof \IteratorAggregate) {
$this->iterators[] = $iterator->getIterator();
} elseif ($iterator instanceof \Iterator) {
$this->iterators[] = $iterator;
} elseif ($iterator instanceof \Traversable || is_array($iterator)) {
$it = new \ArrayIterator();
foreach ($iterator as $file) {
$it->append($file instanceof \SplFileInfo ? $file : new \SplFileInfo($file));
}
$this->iterators[] = $it;
} else {
throw new \InvalidArgumentException('Finder::append() method wrong argument type.');
}

return $this;
}






public function count()
{
return iterator_count($this->getIterator());
}




private function sortAdapters()
{
uasort($this->adapters, function (array $a, array $b) {
if ($a['selected'] || $b['selected']) {
return $a['selected'] ? -1 : 1;
}

return $a['priority'] > $b['priority'] ? -1 : 1;
});

return $this;
}






private function searchInDirectory($dir)
{
if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) {
$this->exclude = array_merge($this->exclude, self::$vcsPatterns);
}

if (static::IGNORE_DOT_FILES === (static::IGNORE_DOT_FILES & $this->ignore)) {
$this->notPaths[] = '#(^|/)\..+(/|$)#';
}

if ($this->adapters) {
foreach ($this->adapters as $adapter) {
if ($adapter['adapter']->isSupported()) {
try {
return $this
->buildAdapter($adapter['adapter'])
->searchInDirectory($dir);
} catch (ExceptionInterface $e) {
}
}
}
}

$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 ($this->exclude) {
$iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->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 || $this->notPaths) {
$iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $this->notPaths);
}

if ($this->sort) {
$iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
$iterator = $iteratorAggregate->getIterator();
}

return $iterator;
}






private function buildAdapter(AdapterInterface $adapter)
{
return $adapter
->setFollowLinks($this->followLinks)
->setDepths($this->depths)
->setMode($this->mode)
->setExclude($this->exclude)
->setNames($this->names)
->setNotNames($this->notNames)
->setContains($this->contains)
->setNotContains($this->notContains)
->setSizes($this->sizes)
->setDates($this->dates)
->setFilters($this->filters)
->setSort($this->sort)
->setPath($this->paths)
->setNotPath($this->notPaths)
->ignoreUnreadableDirs($this->ignoreUnreadableDirs);
}




private function resetAdapterSelection()
{
$this->adapters = array_map(function (array $properties) {
$properties['selected'] = false;

return $properties;
}, $this->adapters);
}

private function initDefaultAdapters()
{
if (null === $this->adapters) {
$this->adapters = array();
$this
->addAdapter(new GnuFindAdapter())
->addAdapter(new BsdFindAdapter())
->addAdapter(new PhpAdapter(), -50)
->setAdapter('php')
;
}
}
}
<?php










namespace Symfony\Component\Finder\Shell;

@trigger_error('The '.__NAMESPACE__.'\Shell class is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);






class Shell
{
const TYPE_UNIX = 1;
const TYPE_DARWIN = 2;
const TYPE_CYGWIN = 3;
const TYPE_WINDOWS = 4;
const TYPE_BSD = 5;




private $type;






public function getType()
{
if (null === $this->type) {
$this->type = $this->guessType();
}

return $this->type;
}








public function testCommand($command)
{
if (!function_exists('exec')) {
return false;
}


 $testCommand = 'which ';
if (self::TYPE_WINDOWS === $this->type) {
$testCommand = 'where ';
}

$command = escapeshellcmd($command);

exec($testCommand.$command, $output, $code);

return 0 === $code && count($output) > 0;
}






private function guessType()
{
$os = strtolower(PHP_OS);

if (false !== strpos($os, 'cygwin')) {
return self::TYPE_CYGWIN;
}

if (false !== strpos($os, 'darwin')) {
return self::TYPE_DARWIN;
}

if (false !== strpos($os, 'bsd')) {
return self::TYPE_BSD;
}

if (0 === strpos($os, 'win')) {
return self::TYPE_WINDOWS;
}

return self::TYPE_UNIX;
}
}
<?php










namespace Symfony\Component\Finder\Shell;

@trigger_error('The '.__NAMESPACE__.'\Command class is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);






class Command
{



private $parent;




private $bits = array();




private $labels = array();




private $errorHandler;






public function __construct(Command $parent = null)
{
$this->parent = $parent;
}






public function __toString()
{
return $this->join();
}








public static function create(Command $parent = null)
{
return new self($parent);
}








public static function escape($input)
{
return escapeshellcmd($input);
}








public static function quote($input)
{
return escapeshellarg($input);
}








public function add($bit)
{
$this->bits[] = $bit;

return $this;
}








public function top($bit)
{
array_unshift($this->bits, $bit);

foreach ($this->labels as $label => $index) {
$this->labels[$label] += 1;
}

return $this;
}








public function arg($arg)
{
$this->bits[] = self::quote($arg);

return $this;
}








public function cmd($esc)
{
$this->bits[] = self::escape($esc);

return $this;
}










public function ins($label)
{
if (isset($this->labels[$label])) {
throw new \RuntimeException(sprintf('Label "%s" already exists.', $label));
}

$this->bits[] = self::create($this);
$this->labels[$label] = count($this->bits) - 1;

return $this->bits[$this->labels[$label]];
}










public function get($label)
{
if (!isset($this->labels[$label])) {
throw new \RuntimeException(sprintf('Label "%s" does not exist.', $label));
}

return $this->bits[$this->labels[$label]];
}








public function end()
{
if (null === $this->parent) {
throw new \RuntimeException('Calling end on root command doesn\'t make sense.');
}

return $this->parent;
}






public function length()
{
return count($this->bits);
}






public function setErrorHandler(\Closure $errorHandler)
{
$this->errorHandler = $errorHandler;

return $this;
}




public function getErrorHandler()
{
return $this->errorHandler;
}








public function execute()
{
if (null === $errorHandler = $this->errorHandler) {
exec($this->join(), $output);
} else {
$process = proc_open($this->join(), array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $pipes);
$output = preg_split('~(\r\n|\r|\n)~', stream_get_contents($pipes[1]), -1, PREG_SPLIT_NO_EMPTY);

if ($error = stream_get_contents($pipes[2])) {
$errorHandler($error);
}

proc_close($process);
}

return $output ?: array();
}






public function join()
{
return implode(' ', array_filter(
array_map(function ($bit) {
return $bit instanceof Command ? $bit->join() : ($bit ?: null);
}, $this->bits),
function ($bit) { return null !== $bit; }
));
}









public function addAtIndex($bit, $index)
{
array_splice($this->bits, $index, 0, $bit instanceof self ? array($bit) : $bit);

return $this;
}
}
<?php










namespace Symfony\Component\Finder\Iterator;






class DepthRangeFilterIterator extends FilterIterator
{
private $minDepth = 0;








public function __construct(\RecursiveIteratorIterator $iterator, $minDepth = 0, $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 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 CustomFilterIterator extends FilterIterator
{
private $filters = array();









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 === call_user_func($filter, $fileinfo)) {
return false;
}
}

return true;
}
}
<?php










namespace Symfony\Component\Finder\Iterator;

@trigger_error('The '.__NAMESPACE__.'\FilePathsIterator class is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);

use Symfony\Component\Finder\SplFileInfo;








class FilePathsIterator extends \ArrayIterator
{



private $baseDir;




private $baseDirLength;




private $subPath;




private $subPathname;




private $current;





public function __construct(array $paths, $baseDir)
{
$this->baseDir = $baseDir;
$this->baseDirLength = strlen($baseDir);

parent::__construct($paths);
}







public function __call($name, array $arguments)
{
return call_user_func_array(array($this->current(), $name), $arguments);
}






public function current()
{
return $this->current;
}




public function key()
{
return $this->current->getPathname();
}

public function next()
{
parent::next();
$this->buildProperties();
}

public function rewind()
{
parent::rewind();
$this->buildProperties();
}




public function getSubPath()
{
return $this->subPath;
}




public function getSubPathname()
{
return $this->subPathname;
}

private function buildProperties()
{
$absolutePath = parent::current();

if ($this->baseDir === substr($absolutePath, 0, $this->baseDirLength)) {
$this->subPathname = ltrim(substr($absolutePath, $this->baseDirLength), '/\\');
$dir = dirname($this->subPathname);
$this->subPath = '.' === $dir ? '' : $dir;
} else {
$this->subPath = $this->subPathname = '';
}

$this->current = new SplFileInfo(parent::current(), $this->subPath, $this->subPathname);
}
}
<?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($path, $flags, $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 = (string) $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();

return new SplFileInfo($this->rootPath.$this->directorySeparator.$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(array());
} else {
throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e);
}
}
}




public function rewind()
{
if (false === $this->isRewindable()) {
return;
}


 if (PHP_VERSION_ID < 50523 || PHP_VERSION_ID >= 50600 && PHP_VERSION_ID < 50607) {
parent::next();
}

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;






abstract class MultiplePcreFilterIterator extends FilterIterator
{
protected $matchRegexps = array();
protected $noMatchRegexps = array();








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 (array(array('{', '}'), array('(', ')'), array('[', ']'), array('<', '>')) 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 SortableIterator implements \IteratorAggregate
{
const SORT_BY_NAME = 1;
const SORT_BY_TYPE = 2;
const SORT_BY_ACCESSED_TIME = 3;
const SORT_BY_CHANGED_TIME = 4;
const SORT_BY_MODIFIED_TIME = 5;

private $iterator;
private $sort;









public function __construct(\Traversable $iterator, $sort)
{
$this->iterator = $iterator;

if (self::SORT_BY_NAME === $sort) {
$this->sort = function ($a, $b) {
return strcmp($a->getRealpath(), $b->getRealpath());
};
} elseif (self::SORT_BY_TYPE === $sort) {
$this->sort = function ($a, $b) {
if ($a->isDir() && $b->isFile()) {
return -1;
} elseif ($a->isFile() && $b->isDir()) {
return 1;
}

return strcmp($a->getRealpath(), $b->getRealpath());
};
} elseif (self::SORT_BY_ACCESSED_TIME === $sort) {
$this->sort = function ($a, $b) {
return $a->getATime() - $b->getATime();
};
} elseif (self::SORT_BY_CHANGED_TIME === $sort) {
$this->sort = function ($a, $b) {
return $a->getCTime() - $b->getCTime();
};
} elseif (self::SORT_BY_MODIFIED_TIME === $sort) {
$this->sort = function ($a, $b) {
return $a->getMTime() - $b->getMTime();
};
} elseif (is_callable($sort)) {
$this->sort = $sort;
} else {
throw new \InvalidArgumentException('The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument.');
}
}

public function getIterator()
{
$array = iterator_to_array($this->iterator, true);
uasort($array, $this->sort);

return new \ArrayIterator($array);
}
}
<?php










namespace Symfony\Component\Finder\Iterator;

use Symfony\Component\Finder\Comparator\NumberComparator;






class SizeRangeFilterIterator extends FilterIterator
{
private $comparators = array();







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;







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;

use Symfony\Component\Finder\Comparator\DateComparator;






class DateRangeFilterIterator extends FilterIterator
{
private $comparators = array();







public function __construct(\Iterator $iterator, array $comparators)
{
$this->comparators = $comparators;

parent::__construct($iterator);
}






public function accept()
{
$fileinfo = $this->current();

if (!file_exists($fileinfo->getRealPath())) {
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 ExcludeDirectoryFilterIterator extends FilterIterator implements \RecursiveIterator
{
private $iterator;
private $isRecursive;
private $excludedDirs = array();
private $excludedPattern;







public function __construct(\Iterator $iterator, array $directories)
{
$this->iterator = $iterator;
$this->isRecursive = $iterator instanceof \RecursiveIterator;
$patterns = array();
foreach ($directories as $directory) {
if (!$this->isRecursive || false !== strpos($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(), array());
$children->excludedDirs = $this->excludedDirs;
$children->excludedPattern = $this->excludedPattern;

return $children;
}
}
<?php










namespace Symfony\Component\Finder\Iterator;






class FileTypeFilterIterator extends FilterIterator
{
const ONLY_FILES = 1;
const ONLY_DIRECTORIES = 2;

private $mode;







public function __construct(\Iterator $iterator, $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;









abstract class FilterIterator extends \FilterIterator
{






public function rewind()
{
if (PHP_VERSION_ID > 50607 || (PHP_VERSION_ID > 50523 && PHP_VERSION_ID < 50600)) {
parent::rewind();

return;
}

$iterator = $this;
while ($iterator instanceof \OuterIterator) {
$innerIterator = $iterator->getInnerIterator();

if ($innerIterator instanceof RecursiveDirectoryIterator) {

 if ($innerIterator->isRewindable()) {
$innerIterator->next();
$innerIterator->rewind();
}
} elseif ($innerIterator instanceof \FilesystemIterator) {
$innerIterator->next();
$innerIterator->rewind();
}

$iterator = $innerIterator;
}

parent::rewind();
}
}
<?php










namespace Symfony\Component\Finder\Exception;




interface ExceptionInterface
{



public function getAdapter();
}
<?php










namespace Symfony\Component\Finder\Exception;




class AccessDeniedException extends \UnexpectedValueException
{
}
<?php










namespace Symfony\Component\Finder\Exception;

@trigger_error('The '.__NAMESPACE__.'\ShellCommandFailureException class is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);

use Symfony\Component\Finder\Adapter\AdapterInterface;
use Symfony\Component\Finder\Shell\Command;






class ShellCommandFailureException extends AdapterFailureException
{



private $command;






public function __construct(AdapterInterface $adapter, Command $command, \Exception $previous = null)
{
$this->command = $command;
parent::__construct($adapter, 'Shell command failed: "'.$command->join().'".', $previous);
}




public function getCommand()
{
return $this->command;
}
}
<?php










namespace Symfony\Component\Finder\Exception;

@trigger_error('The '.__NAMESPACE__.'\AdapterFailureException class is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);

use Symfony\Component\Finder\Adapter\AdapterInterface;








class AdapterFailureException extends \RuntimeException implements ExceptionInterface
{



private $adapter;






public function __construct(AdapterInterface $adapter, $message = null, \Exception $previous = null)
{
$this->adapter = $adapter;
parent::__construct($message ?: 'Search failed with "'.$adapter->getName().'" adapter.', $previous);
}




public function getAdapter()
{
return $this->adapter;
}
}
<?php










namespace Symfony\Component\Finder\Exception;

@trigger_error('The '.__NAMESPACE__.'\OperationNotPermitedException class is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);






class OperationNotPermitedException extends AdapterFailureException
{
}
<?php










namespace Symfony\Component\Finder;






class SplFileInfo extends \SplFileInfo
{
private $relativePath;
private $relativePathname;








public function __construct($file, $relativePath, $relativePathname)
{
parent::__construct($file);
$this->relativePath = $relativePath;
$this->relativePathname = $relativePathname;
}








public function getRelativePath()
{
return $this->relativePath;
}








public function getRelativePathname()
{
return $this->relativePathname;
}








public function getContents()
{
$level = error_reporting(0);
$content = file_get_contents($this->getPathname());
error_reporting($level);
if (false === $content) {
$error = error_get_last();
throw new \RuntimeException($error['message']);
}

return $content;
}
}
<?php










namespace Symfony\Component\Finder\Comparator;






















class NumberComparator extends Comparator
{







public function __construct($test)
{
if (!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));
}

$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(isset($matches[1]) ? $matches[1] : '==');
}
}
<?php










namespace Symfony\Component\Finder\Comparator;






class DateComparator extends Comparator
{







public function __construct($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 = isset($matches[1]) ? $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, array('>', '<', '>=', '<=', '==', '!='))) {
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\EventDispatcher;















class Event
{



private $propagationStopped = false;




private $dispatcher;




private $name;








public function isPropagationStopped()
{
return $this->propagationStopped;
}








public function stopPropagation()
{
$this->propagationStopped = true;
}








public function setDispatcher(EventDispatcherInterface $dispatcher)
{
$this->dispatcher = $dispatcher;
}








public function getDispatcher()
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.4 and will be removed in 3.0. The event dispatcher instance can be received in the listener call instead.', E_USER_DEPRECATED);

return $this->dispatcher;
}








public function getName()
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 2.4 and will be removed in 3.0. The event name can be received in the listener call instead.', E_USER_DEPRECATED);

return $this->name;
}








public function setName($name)
{
$this->name = $name;
}
}
<?php










namespace Symfony\Component\EventDispatcher\DependencyInjection;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;




class RegisterListenersPass implements CompilerPassInterface
{



protected $dispatcherService;




protected $listenerTag;




protected $subscriberTag;








public function __construct($dispatcherService = 'event_dispatcher', $listenerTag = 'kernel.event_listener', $subscriberTag = 'kernel.event_subscriber')
{
$this->dispatcherService = $dispatcherService;
$this->listenerTag = $listenerTag;
$this->subscriberTag = $subscriberTag;
}

public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition($this->dispatcherService) && !$container->hasAlias($this->dispatcherService)) {
return;
}

$definition = $container->findDefinition($this->dispatcherService);

foreach ($container->findTaggedServiceIds($this->listenerTag) as $id => $events) {
$def = $container->getDefinition($id);
if (!$def->isPublic()) {
throw new \InvalidArgumentException(sprintf('The service "%s" must be public as event listeners are lazy-loaded.', $id));
}

if ($def->isAbstract()) {
throw new \InvalidArgumentException(sprintf('The service "%s" must not be abstract as event listeners are lazy-loaded.', $id));
}

foreach ($events as $event) {
$priority = isset($event['priority']) ? $event['priority'] : 0;

if (!isset($event['event'])) {
throw new \InvalidArgumentException(sprintf('Service "%s" must define the "event" attribute on "%s" tags.', $id, $this->listenerTag));
}

if (!isset($event['method'])) {
$event['method'] = 'on'.preg_replace_callback(array(
'/(?<=\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']);
}

$definition->addMethodCall('addListenerService', array($event['event'], array($id, $event['method']), $priority));
}
}

foreach ($container->findTaggedServiceIds($this->subscriberTag) as $id => $attributes) {
$def = $container->getDefinition($id);
if (!$def->isPublic()) {
throw new \InvalidArgumentException(sprintf('The service "%s" must be public as event subscribers are lazy-loaded.', $id));
}

if ($def->isAbstract()) {
throw new \InvalidArgumentException(sprintf('The service "%s" must not be abstract as event subscribers are lazy-loaded.', $id));
}


 $class = $container->getParameterBag()->resolveValue($def->getClass());

$interface = 'Symfony\Component\EventDispatcher\EventSubscriberInterface';
if (!is_subclass_of($class, $interface)) {
throw new \InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, $interface));
}

$definition->addMethodCall('addSubscriberService', array($id, $class));
}
}
}
<?php










namespace Symfony\Component\EventDispatcher\Debug;

use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\Stopwatch\Stopwatch;
use Psr\Log\LoggerInterface;








class TraceableEventDispatcher implements TraceableEventDispatcherInterface
{
protected $logger;
protected $stopwatch;

private $called;
private $dispatcher;
private $wrappedListeners;








public function __construct(EventDispatcherInterface $dispatcher, Stopwatch $stopwatch, LoggerInterface $logger = null)
{
$this->dispatcher = $dispatcher;
$this->stopwatch = $stopwatch;
$this->logger = $logger;
$this->called = array();
$this->wrappedListeners = array();
}




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)
{
return $this->dispatcher->getListenerPriority($eventName, $listener);
}




public function hasListeners($eventName = null)
{
return $this->dispatcher->hasListeners($eventName);
}




public function dispatch($eventName, Event $event = null)
{
if (null === $event) {
$event = new Event();
}

$this->preProcess($eventName);
$this->preDispatch($eventName, $event);

$e = $this->stopwatch->start($eventName, 'section');

$this->dispatcher->dispatch($eventName, $event);

if ($e->isStarted()) {
$e->stop();
}

$this->postDispatch($eventName, $event);
$this->postProcess($eventName);

return $event;
}




public function getCalledListeners()
{
$called = array();
foreach ($this->called as $eventName => $listeners) {
foreach ($listeners as $listener) {
$info = $this->getListenerInfo($listener->getWrappedListener(), $eventName);
$called[$eventName.'.'.$info['pretty']] = $info;
}
}

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.', array('exception' => $e));
}


 return array();
}

$notCalled = array();
foreach ($allListeners as $eventName => $listeners) {
foreach ($listeners as $listener) {
$called = false;
if (isset($this->called[$eventName])) {
foreach ($this->called[$eventName] as $l) {
if ($l->getWrappedListener() === $listener) {
$called = true;

break;
}
}
}

if (!$called) {
$info = $this->getListenerInfo($listener, $eventName);
$notCalled[$eventName.'.'.$info['pretty']] = $info;
}
}
}

uasort($notCalled, array($this, 'sortListenersByPriority'));

return $notCalled;
}









public function __call($method, $arguments)
{
return call_user_func_array(array($this->dispatcher, $method), $arguments);
}







protected function preDispatch($eventName, Event $event)
{
}







protected function postDispatch($eventName, Event $event)
{
}

private function preProcess($eventName)
{
foreach ($this->dispatcher->getListeners($eventName) as $listener) {
$info = $this->getListenerInfo($listener, $eventName);
$name = isset($info['class']) ? $info['class'] : $info['type'];
$wrappedListener = new WrappedListener($listener, $name, $this->stopwatch, $this);
$this->wrappedListeners[$eventName][] = $wrappedListener;
$this->dispatcher->removeListener($eventName, $listener);
$this->dispatcher->addListener($eventName, $wrappedListener, $info['priority']);
}
}

private function postProcess($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);

$info = $this->getListenerInfo($listener->getWrappedListener(), $eventName);
if ($listener->wasCalled()) {
if (null !== $this->logger) {
$this->logger->debug(sprintf('Notified event "%s" to listener "%s".', $eventName, $info['pretty']));
}

if (!isset($this->called[$eventName])) {
$this->called[$eventName] = new \SplObjectStorage();
}

$this->called[$eventName]->attach($listener);
}

if (null !== $this->logger && $skipped) {
$this->logger->debug(sprintf('Listener "%s" was not called for event "%s".', $info['pretty'], $eventName));
}

if ($listener->stoppedPropagation()) {
if (null !== $this->logger) {
$this->logger->debug(sprintf('Listener "%s" stopped propagation of the event "%s".', $info['pretty'], $eventName));
}

$skipped = true;
}
}
}









private function getListenerInfo($listener, $eventName)
{
$info = array(
'event' => $eventName,
'priority' => $this->getListenerPriority($eventName, $listener),
);
if ($listener instanceof \Closure) {
$info += array(
'type' => 'Closure',
'pretty' => 'closure',
);
} elseif (is_string($listener)) {
try {
$r = new \ReflectionFunction($listener);
$file = $r->getFileName();
$line = $r->getStartLine();
} catch (\ReflectionException $e) {
$file = null;
$line = null;
}
$info += array(
'type' => 'Function',
'function' => $listener,
'file' => $file,
'line' => $line,
'pretty' => $listener,
);
} elseif (is_array($listener) || (is_object($listener) && is_callable($listener))) {
if (!is_array($listener)) {
$listener = array($listener, '__invoke');
}
$class = is_object($listener[0]) ? get_class($listener[0]) : $listener[0];
try {
$r = new \ReflectionMethod($class, $listener[1]);
$file = $r->getFileName();
$line = $r->getStartLine();
} catch (\ReflectionException $e) {
$file = null;
$line = null;
}
$info += array(
'type' => 'Method',
'class' => $class,
'method' => $listener[1],
'file' => $file,
'line' => $line,
'pretty' => $class.'::'.$listener[1],
);
}

return $info;
}

private function sortListenersByPriority($a, $b)
{
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 Symfony\Component\Stopwatch\Stopwatch;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;




class WrappedListener
{
private $listener;
private $name;
private $called;
private $stoppedPropagation;
private $stopwatch;
private $dispatcher;

public function __construct($listener, $name, Stopwatch $stopwatch, EventDispatcherInterface $dispatcher = null)
{
$this->listener = $listener;
$this->name = $name;
$this->stopwatch = $stopwatch;
$this->dispatcher = $dispatcher;
$this->called = false;
$this->stoppedPropagation = false;
}

public function getWrappedListener()
{
return $this->listener;
}

public function wasCalled()
{
return $this->called;
}

public function stoppedPropagation()
{
return $this->stoppedPropagation;
}

public function __invoke(Event $event, $eventName, EventDispatcherInterface $dispatcher)
{
$this->called = true;

$e = $this->stopwatch->start($this->name, 'event_listener');

call_user_func($this->listener, $event, $eventName, $this->dispatcher ?: $dispatcher);

if ($e->isStarted()) {
$e->stop();
}

if ($event->isPropagationStopped()) {
$this->stoppedPropagation = true;
}
}
}
<?php










namespace Symfony\Component\EventDispatcher\Debug;

use Symfony\Component\EventDispatcher\EventDispatcherInterface;




interface TraceableEventDispatcherInterface extends EventDispatcherInterface
{





public function getCalledListeners();






public function getNotCalledListeners();
}
<?php










namespace Symfony\Component\EventDispatcher;








class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate
{





protected $subject;






protected $arguments;







public function __construct($subject = null, array $arguments = array())
{
$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 = array())
{
$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;















class EventDispatcher implements EventDispatcherInterface
{
private $listeners = array();
private $sorted = array();




public function dispatch($eventName, Event $event = null)
{
if (null === $event) {
$event = new Event();
}

$event->setDispatcher($this);
$event->setName($eventName);

if ($listeners = $this->getListeners($eventName)) {
$this->doDispatch($listeners, $eventName, $event);
}

return $event;
}




public function getListeners($eventName = null)
{
if (null !== $eventName) {
if (!isset($this->listeners[$eventName])) {
return array();
}

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 (!isset($this->listeners[$eventName])) {
return;
}

foreach ($this->listeners[$eventName] as $priority => $listeners) {
if (false !== ($key = array_search($listener, $listeners, true))) {
return $priority;
}
}
}




public function hasListeners($eventName = null)
{
return (bool) count($this->getListeners($eventName));
}




public function addListener($eventName, $listener, $priority = 0)
{
$this->listeners[$eventName][$priority][] = $listener;
unset($this->sorted[$eventName]);
}




public function removeListener($eventName, $listener)
{
if (!isset($this->listeners[$eventName])) {
return;
}

foreach ($this->listeners[$eventName] as $priority => $listeners) {
if (false !== ($key = array_search($listener, $listeners, true))) {
unset($this->listeners[$eventName][$priority][$key], $this->sorted[$eventName]);
}
}
}




public function addSubscriber(EventSubscriberInterface $subscriber)
{
foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
if (is_string($params)) {
$this->addListener($eventName, array($subscriber, $params));
} elseif (is_string($params[0])) {
$this->addListener($eventName, array($subscriber, $params[0]), isset($params[1]) ? $params[1] : 0);
} else {
foreach ($params as $listener) {
$this->addListener($eventName, array($subscriber, $listener[0]), isset($listener[1]) ? $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, array($subscriber, $listener[0]));
}
} else {
$this->removeListener($eventName, array($subscriber, is_string($params) ? $params : $params[0]));
}
}
}











protected function doDispatch($listeners, $eventName, Event $event)
{
foreach ($listeners as $listener) {
call_user_func($listener, $event, $eventName, $this);
if ($event->isPropagationStopped()) {
break;
}
}
}






private function sortListeners($eventName)
{
krsort($this->listeners[$eventName]);
$this->sorted[$eventName] = call_user_func_array('array_merge', $this->listeners[$eventName]);
}
}
<?php










namespace Symfony\Component\EventDispatcher;






class ImmutableEventDispatcher implements EventDispatcherInterface
{





private $dispatcher;






public function __construct(EventDispatcherInterface $dispatcher)
{
$this->dispatcher = $dispatcher;
}




public function dispatch($eventName, Event $event = null)
{
return $this->dispatcher->dispatch($eventName, $event);
}




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;












interface EventSubscriberInterface
{


















public static function getSubscribedEvents();
}
<?php










namespace Symfony\Component\EventDispatcher;

use Symfony\Component\DependencyInjection\ContainerInterface;









class ContainerAwareEventDispatcher extends EventDispatcher
{





private $container;






private $listenerIds = array();






private $listeners = array();






public function __construct(ContainerInterface $container)
{
$this->container = $container;
}













public function addListenerService($eventName, $callback, $priority = 0)
{
if (!is_array($callback) || 2 !== count($callback)) {
throw new \InvalidArgumentException('Expected an array("service", "method") argument');
}

$this->listenerIds[$eventName][] = array($callback[0], $callback[1], $priority);
}

public function removeListener($eventName, $listener)
{
$this->lazyLoad($eventName);

if (isset($this->listenerIds[$eventName])) {
foreach ($this->listenerIds[$eventName] as $i => $args) {
list($serviceId, $method, $priority) = $args;
$key = $serviceId.'.'.$method;
if (isset($this->listeners[$eventName][$key]) && $listener === array($this->listeners[$eventName][$key], $method)) {
unset($this->listeners[$eventName][$key]);
if (empty($this->listeners[$eventName])) {
unset($this->listeners[$eventName]);
}
unset($this->listenerIds[$eventName][$i]);
if (empty($this->listenerIds[$eventName])) {
unset($this->listenerIds[$eventName]);
}
}
}
}

parent::removeListener($eventName, $listener);
}




public function hasListeners($eventName = null)
{
if (null === $eventName) {
return (bool) count($this->listenerIds) || (bool) count($this->listeners);
}

if (isset($this->listenerIds[$eventName])) {
return true;
}

return parent::hasListeners($eventName);
}




public function getListeners($eventName = null)
{
if (null === $eventName) {
foreach ($this->listenerIds as $serviceEventName => $args) {
$this->lazyLoad($serviceEventName);
}
} else {
$this->lazyLoad($eventName);
}

return parent::getListeners($eventName);
}




public function getListenerPriority($eventName, $listener)
{
$this->lazyLoad($eventName);

return parent::getListenerPriority($eventName, $listener);
}







public function addSubscriberService($serviceId, $class)
{
foreach ($class::getSubscribedEvents() as $eventName => $params) {
if (is_string($params)) {
$this->listenerIds[$eventName][] = array($serviceId, $params, 0);
} elseif (is_string($params[0])) {
$this->listenerIds[$eventName][] = array($serviceId, $params[0], isset($params[1]) ? $params[1] : 0);
} else {
foreach ($params as $listener) {
$this->listenerIds[$eventName][] = array($serviceId, $listener[0], isset($listener[1]) ? $listener[1] : 0);
}
}
}
}

public function getContainer()
{
return $this->container;
}









protected function lazyLoad($eventName)
{
if (isset($this->listenerIds[$eventName])) {
foreach ($this->listenerIds[$eventName] as $args) {
list($serviceId, $method, $priority) = $args;
$listener = $this->container->get($serviceId);

$key = $serviceId.'.'.$method;
if (!isset($this->listeners[$eventName][$key])) {
$this->addListener($eventName, array($listener, $method), $priority);
} elseif ($listener !== $this->listeners[$eventName][$key]) {
parent::removeListener($eventName, array($this->listeners[$eventName][$key], $method));
$this->addListener($eventName, array($listener, $method), $priority);
}

$this->listeners[$eventName][$key] = $listener;
}
}
}
}
<?php










namespace Symfony\Component\EventDispatcher;








interface EventDispatcherInterface
{











public function dispatch($eventName, Event $event = null);









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 hasListeners($eventName = null);
}
<?php










namespace Symfony\Component\DomCrawler;






class Link
{



protected $node;




protected $method;




protected $currentUri;










public function __construct(\DOMElement $node, $currentUri, $method = 'GET')
{
if (!in_array(strtolower(substr($currentUri, 0, 4)), array('http', 'file'))) {
throw new \InvalidArgumentException(sprintf('Current URI must be an absolute URL ("%s").', $currentUri));
}

$this->setNode($node);
$this->method = $method ? strtoupper($method) : null;
$this->currentUri = $currentUri;
}






public function getNode()
{
return $this->node;
}






public function getMethod()
{
return $this->method;
}






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 (0 === strpos($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;
}






protected function getRawUri()
{
return $this->node->getAttribute('href');
}








protected function canonicalizePath($path)
{
if ('' === $path || '/' === $path) {
return $path;
}

if ('.' === substr($path, -1)) {
$path .= '/';
}

$output = array();

foreach (explode('/', $path) as $segment) {
if ('..' === $segment) {
array_pop($output);
} elseif ('.' !== $segment) {
$output[] = $segment;
}
}

return implode('/', $output);
}








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;
}








private function cleanupUri($uri)
{
return $this->cleanupQuery($this->cleanupAnchor($uri));
}








private function cleanupQuery($uri)
{
if (false !== $pos = strpos($uri, '?')) {
return substr($uri, 0, $pos);
}

return $uri;
}








private function cleanupAnchor($uri)
{
if (false !== $pos = strpos($uri, '#')) {
return substr($uri, 0, $pos);
}

return $uri;
}
}
<?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, $currentUri, $method = null, $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 = array();
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(), array('POST', 'PUT', 'DELETE', 'PATCH'))) {
return array();
}

$files = array();

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 = array();
foreach ($this->getValues() as $name => $value) {
$qs = http_build_query(array($name => $value), '', '&');
if (!empty($qs)) {
parse_str($qs, $expandedValue);
$varName = substr($name, 0, strlen(key($expandedValue)));
$values = array_replace_recursive($values, array($varName => current($expandedValue)));
}
}

return $values;
}













public function getPhpFiles()
{
$values = array();
foreach ($this->getFiles() as $name => $value) {
$qs = http_build_query(array($name => $value), '', '&');
if (!empty($qs)) {
parse_str($qs, $expandedValue);
$varName = substr($name, 0, strlen(key($expandedValue)));
$values = array_replace_recursive($values, array($varName => current($expandedValue)));
}
}

return $values;
}










public function getUri()
{
$uri = parent::getUri();

if (!in_array($this->getMethod(), array('POST', 'PUT', 'DELETE', 'PATCH'))) {
$query = parse_url($uri, PHP_URL_QUERY);
$currentParameters = array();
if ($query) {
parse_str($query, $currentParameters);
}

$queryString = http_build_query(array_merge($currentParameters, $this->getValues()), null, '&');

$pos = strpos($uri, '?');
$base = false === $pos ? $uri : substr($uri, 0, $pos);
$uri = rtrim($base.'?'.$queryString, '?');
}

return $uri;
}

protected function getRawUri()
{
return $this->node->getAttribute('action');
}








public function getMethod()
{
if (null !== $this->method) {
return $this->method;
}

return $this->node->getAttribute('method') ? strtoupper($this->node->getAttribute('method')) : 'GET';
}








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')), array('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=%s] | descendant::textarea[@form=%s] | descendant::select[@form=%s] | //form[@id=%s]//input[not(@form)] | //form[@id=%s]//button[not(@form)] | //form[@id=%s]//textarea[not(@form)] | //form[@id=%s]//select[not(@form)]', $formId, $formId, $formId, $formId, $formId, $formId, $formId, $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)]', $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')), array('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 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));
}

if ('checkbox' === strtolower($this->node->getAttribute('type'))) {
throw new \LogicException('Checkboxes should be instances of ChoiceFormField.');
}

if ('file' === strtolower($this->node->getAttribute('type'))) {
throw new \LogicException('File inputs should be instances of FileFormField.');
}

$this->value = $this->node->getAttribute('value');
}
}
<?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, array('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 tick "%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 = array();
$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 = array();
$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)
{
$option = array();

$defaultValue = (isset($node->nodeValue) && !empty($node->nodeValue)) ? $node->nodeValue : 'on';
$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 = array();

foreach ($this->options as $option) {
$values[] = $option['value'];
}

return $values;
}






public function disableValidation()
{
$this->validationDisabled = true;

return $this;
}
}
<?php










namespace Symfony\Component\DomCrawler\Field;






class FileFormField extends FormField
{







public function setErrorCode($error)
{
$codes = array(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 = array('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().'/'.sha1(uniqid(mt_rand(), true));
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 = array('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\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 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;

use Symfony\Component\CssSelector\CssSelectorConverter;






class Crawler extends \SplObjectStorage
{



protected $uri;




private $defaultNamespacePrefix = 'default';




private $namespaces = array();




private $baseHref;




private $document;






private $isHtml = true;








public function __construct($node = null, $currentUri = null, $baseHref = null)
{
$this->uri = $currentUri;
$this->baseHref = $baseHref ?: $currentUri;

$this->add($node);
}




public function clear()
{
parent::removeAll($this);
$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 = 0 === strpos($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 = 'ISO-8859-1';
}

if ('x' === $xmlMatches[1]) {
$this->addXmlContent($content, $charset);
} else {
$this->addHtmlContent($content, $charset);
}
}














public function addHtmlContent($content, $charset = 'UTF-8')
{
$internalErrors = libxml_use_internal_errors(true);
$disableEntities = libxml_disable_entity_loader(true);

$dom = new \DOMDocument('1.0', $charset);
$dom->validateOnParse = true;

set_error_handler(function () {throw new \Exception();});

try {

 $content = mb_convert_encoding($content, 'HTML-ENTITIES', $charset);
} catch (\Exception $e) {
}

restore_error_handler();

if ('' !== trim($content)) {
@$dom->loadHTML($content);
}

libxml_use_internal_errors($internalErrors);
libxml_disable_entity_loader($disableEntities);

$this->addDocument($dom);

$base = $this->filterRelativeXPath('descendant-or-self::base')->extract(array('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);
$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);
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) {
@trigger_error('Attaching DOM nodes from multiple documents in a Crawler is deprecated as of 2.8 and will be forbidden in 3.0.', E_USER_DEPRECATED);
}

if (null === $this->document) {
$this->document = $node->ownerDocument;
}

parent::attach($node);
}


 public function unserialize($serialized)
{
throw new \BadMethodCallException('A Crawler cannot be serialized.');
}

public function serialize()
{
throw new \BadMethodCallException('A Crawler cannot be serialized.');
}








public function eq($position)
{
foreach ($this as $i => $node) {
if ($i == $position) {
return $this->createSubCrawler($node);
}
}

return $this->createSubCrawler(null);
}

















public function each(\Closure $closure)
{
$data = array();
foreach ($this as $i => $node) {
$data[] = $closure($this->createSubCrawler($node), $i);
}

return $data;
}









public function slice($offset = 0, $length = -1)
{
return $this->createSubCrawler(iterator_to_array(new \LimitIterator($this, $offset, $length)));
}










public function reduce(\Closure $closure)
{
$nodes = array();
foreach ($this 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) - 1);
}








public function siblings()
{
if (!count($this)) {
throw new \InvalidArgumentException('The current node list is empty.');
}

return $this->createSubCrawler($this->sibling($this->getNode(0)->parentNode->firstChild));
}








public function nextAll()
{
if (!count($this)) {
throw new \InvalidArgumentException('The current node list is empty.');
}

return $this->createSubCrawler($this->sibling($this->getNode(0)));
}








public function previousAll()
{
if (!count($this)) {
throw new \InvalidArgumentException('The current node list is empty.');
}

return $this->createSubCrawler($this->sibling($this->getNode(0), 'previousSibling'));
}








public function parents()
{
if (!count($this)) {
throw new \InvalidArgumentException('The current node list is empty.');
}

$node = $this->getNode(0);
$nodes = array();

while ($node = $node->parentNode) {
if (XML_ELEMENT_NODE === $node->nodeType) {
$nodes[] = $node;
}
}

return $this->createSubCrawler($nodes);
}








public function children()
{
if (!count($this)) {
throw new \InvalidArgumentException('The current node list is empty.');
}

$node = $this->getNode(0)->firstChild;

return $this->createSubCrawler($node ? $this->sibling($node) : array());
}










public function attr($attribute)
{
if (!count($this)) {
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 (!count($this)) {
throw new \InvalidArgumentException('The current node list is empty.');
}

return $this->getNode(0)->nodeName;
}








public function text()
{
if (!count($this)) {
throw new \InvalidArgumentException('The current node list is empty.');
}

return $this->getNode(0)->nodeValue;
}








public function html()
{
if (!count($this)) {
throw new \InvalidArgumentException('The current node list is empty.');
}

$html = '';
foreach ($this->getNode(0)->childNodes as $child) {
$html .= $child->ownerDocument->saveHTML($child);
}

return $html;
}














public function extract($attributes)
{
$attributes = (array) $attributes;
$count = count($attributes);

$data = array();
foreach ($this as $node) {
$elements = array();
foreach ($attributes as $attribute) {
if ('_text' === $attribute) {
$elements[] = $node->nodeValue;
} else {
$elements[] = $node->getAttribute($attribute);
}
}

$data[] = $count > 1 ? $elements : $elements[0];
}

return $data;
}













public function filterXPath($xpath)
{
$xpath = $this->relativize($xpath);


 if ('' === $xpath) {
return $this->createSubCrawler(null);
}

return $this->filterRelativeXPath($xpath);
}












public function filter($selector)
{
if (!class_exists('Symfony\\Component\\CssSelector\\CssSelectorConverter')) {
throw new \RuntimeException('Unable to filter with a CSS selector as the Symfony CssSelector 2.8+ is not installed (you can use filterXPath instead).');
}

$converter = new CssSelectorConverter($this->isHtml);


 return $this->filterRelativeXPath($converter->toXPath($selector));
}








public function selectLink($value)
{
$xpath = sprintf('descendant-or-self::a[contains(concat(\' \', normalize-space(string(.)), \' \'), %s) ', static::xpathLiteral(' '.$value.' ')).
sprintf('or ./img[contains(concat(\' \', normalize-space(string(@alt)), \' \'), %s)]]', static::xpathLiteral(' '.$value.' '));

return $this->filterRelativeXPath($xpath);
}








public function selectButton($value)
{
$translate = 'translate(@type, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz")';
$xpath = sprintf('descendant-or-self::input[((contains(%s, "submit") or contains(%s, "button")) and contains(concat(\' \', normalize-space(string(@value)), \' \'), %s)) ', $translate, $translate, static::xpathLiteral(' '.$value.' ')).
sprintf('or (contains(%s, "image") and contains(concat(\' \', normalize-space(string(@alt)), \' \'), %s)) or @id=%s or @name=%s] ', $translate, static::xpathLiteral(' '.$value.' '), static::xpathLiteral($value), static::xpathLiteral($value)).
sprintf('| descendant-or-self::button[contains(concat(\' \', normalize-space(string(.)), \' \'), %s) or @id=%s or @name=%s]', static::xpathLiteral(' '.$value.' '), static::xpathLiteral($value), static::xpathLiteral($value));

return $this->filterRelativeXPath($xpath);
}










public function link($method = 'get')
{
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 Link($node, $this->baseHref, $method);
}








public function links()
{
$links = array();
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)));
}

$links[] = new Link($node, $this->baseHref, 'get');
}

return $links;
}











public function form(array $values = null, $method = null)
{
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)));
}

$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 (false === strpos($s, "'")) {
return sprintf("'%s'", $s);
}

if (false === strpos($s, '"')) {
return sprintf('"%s"', $s);
}

$string = $s;
$parts = array();
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 attach($object, $data = null)
{
$this->triggerDeprecation(__METHOD__);

parent::attach($object, $data);
}




public function detach($object)
{
$this->triggerDeprecation(__METHOD__);

parent::detach($object);
}




public function contains($object)
{
$this->triggerDeprecation(__METHOD__);

return parent::contains($object);
}




public function addAll($storage)
{
$this->triggerDeprecation(__METHOD__);

parent::addAll($storage);
}




public function removeAll($storage)
{
$this->triggerDeprecation(__METHOD__);

parent::removeAll($storage);
}




public function removeAllExcept($storage)
{
$this->triggerDeprecation(__METHOD__);

parent::removeAllExcept($storage);
}




public function getInfo()
{
$this->triggerDeprecation(__METHOD__);

return parent::getInfo();
}




public function setInfo($data)
{
$this->triggerDeprecation(__METHOD__);

parent::setInfo($data);
}




public function offsetExists($object)
{
$this->triggerDeprecation(__METHOD__);

return parent::offsetExists($object);
}




public function offsetSet($object, $data = null)
{
$this->triggerDeprecation(__METHOD__);

parent::offsetSet($object, $data);
}




public function offsetUnset($object)
{
$this->triggerDeprecation(__METHOD__);

parent::offsetUnset($object);
}




public function offsetGet($object)
{
$this->triggerDeprecation(__METHOD__);

return parent::offsetGet($object);
}










private function filterRelativeXPath($xpath)
{
$prefixes = $this->findNamespacePrefixes($xpath);

$crawler = $this->createSubCrawler(null);

foreach ($this as $node) {
$domxpath = $this->createDOMXPath($node->ownerDocument, $prefixes);
$crawler->add($domxpath->query($xpath, $node));
}

return $crawler;
}











private function relativize($xpath)
{
$expressions = array();

$unionPattern = '/\|(?![^\[]*\])/';

 
 $nonMatchingExpression = 'a[name() = "b"]';


 foreach (preg_split($unionPattern, $xpath) as $expression) {
$expression = trim($expression);
$parenthesis = '';


 
 if (preg_match('/^[\(\s*]+/', $expression, $matches)) {
$parenthesis = $matches[0];
$expression = substr($expression, strlen($parenthesis));
}


 if (0 === strpos($expression, '/_root/')) {
@trigger_error('XPath expressions referencing the fake root node are deprecated since version 2.8 and will be unsupported in 3.0. Please use "./" instead of "/_root/".', E_USER_DEPRECATED);

$expression = './'.substr($expression, 7);
} elseif (0 === strpos($expression, 'self::*/')) {
$expression = './'.substr($expression, 8);
}


 if (empty($expression)) {
$expression = $nonMatchingExpression;
} elseif (0 === strpos($expression, '//')) {
$expression = 'descendant-or-self::'.substr($expression, 2);
} elseif (0 === strpos($expression, './/')) {
$expression = 'descendant-or-self::'.substr($expression, 3);
} elseif (0 === strpos($expression, './')) {
$expression = 'self::'.substr($expression, 2);
} elseif (0 === strpos($expression, 'child::')) {
$expression = 'self::'.substr($expression, 7);
} elseif ('/' === $expression[0] || 0 === strpos($expression, 'self::')) {

 
 $expression = $nonMatchingExpression;
} elseif ('.' === $expression[0]) {

 $expression = $nonMatchingExpression;
} elseif (0 === strpos($expression, 'descendant::')) {
$expression = 'descendant-or-self::'.substr($expression, strlen('descendant::'));
} elseif (preg_match('/^(ancestor|ancestor-or-self|attribute|following|following-sibling|namespace|parent|preceding|preceding-sibling)::/', $expression)) {

 $expression = $nonMatchingExpression;
} elseif (0 !== strpos($expression, 'descendant-or-self::')) {
$expression = 'self::'.$expression;
}
$expressions[] = $parenthesis.$expression;
}

return implode(' | ', $expressions);
}






public function getNode($position)
{
foreach ($this as $i => $node) {
if ($i == $position) {
return $node;
}
}
}







protected function sibling($node, $siblingDir = 'nextSibling')
{
$nodes = array();

do {
if ($node !== $this->getNode(0) && $node->nodeType === 1) {
$nodes[] = $node;
}
} while ($node = $node->$siblingDir);

return $nodes;
}









private function createDOMXPath(\DOMDocument $document, array $prefixes = array())
{
$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, $prefix)
{
if (isset($this->namespaces[$prefix])) {
return $this->namespaces[$prefix];
}


 $namespaces = $domxpath->query(sprintf('(//namespace::*[name()="%s"])[last()]', $this->defaultNamespacePrefix === $prefix ? '' : $prefix));

if ($node = $namespaces->item(0)) {
return $node->nodeValue;
}
}






private function findNamespacePrefixes($xpath)
{
if (preg_match_all('/(?P<prefix>[a-z_][a-z_0-9\-\.]*+):[^"\/:]/i', $xpath, $matches)) {
return array_unique($matches['prefix']);
}

return array();
}








private function createSubCrawler($nodes)
{
$crawler = new static($nodes, $this->uri, $this->baseHref);
$crawler->isHtml = $this->isHtml;
$crawler->document = $this->document;

return $crawler;
}

private function triggerDeprecation($methodName, $useTrace = false)
{
if ($useTrace || defined('HHVM_VERSION')) {
if (PHP_VERSION_ID >= 50400) {
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);
} else {
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
}


 
 if (isset($trace[2]['class']) && 'SplObjectStorage' === $trace[2]['class']) {
return;
}
}

@trigger_error('The '.$methodName.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
}
<?php










namespace Symfony\Component\DomCrawler;

use Symfony\Component\DomCrawler\Field\FormField;




class FormFieldRegistry
{
private $fields = array();

private $base;








public function add(FormField $field)
{
$segments = $this->getSegments($field->getName());

$target = &$this->fields;
while ($segments) {
if (!is_array($target)) {
$target = array();
}
$path = array_shift($segments);
if ('' === $path) {
$target = &$target[];
} else {
$target = &$target[$path];
}
}
$target = $field;
}








public function remove($name)
{
$segments = $this->getSegments($name);
$target = &$this->fields;
while (count($segments) > 1) {
$path = array_shift($segments);
if (!array_key_exists($path, $target)) {
return;
}
$target = &$target[$path];
}
unset($target[array_shift($segments)]);
}











public function &get($name)
{
$segments = $this->getSegments($name);
$target = &$this->fields;
while ($segments) {
$path = array_shift($segments);
if (!array_key_exists($path, $target)) {
throw new \InvalidArgumentException(sprintf('Unreachable field "%s"', $path));
}
$target = &$target[$path];
}

return $target;
}








public function has($name)
{
try {
$this->get($name);

return true;
} catch (\InvalidArgumentException $e) {
return false;
}
}










public function set($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)) {
$fields = self::create($name, $value);
foreach ($fields->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()
{
return $this->walk($this->fields, $this->base);
}












private static function create($base, array $values)
{
$registry = new static();
$registry->base = $base;
$registry->fields = $values;

return $registry;
}










private function walk(array $array, $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($name)
{
if (preg_match('/^(?P<base>[^[]+)(?P<extra>(\[.*)|$)/', $name, $m)) {
$segments = array($m['base']);
while (!empty($m['extra'])) {
if (preg_match('/^\[(?P<segment>.*?)\](?P<extra>.*)$/', $m['extra'], $m)) {
$segments[] = $m['segment'];
} else {
throw new \InvalidArgumentException(sprintf('Malformed field path "%s"', $name));
}
}

return $segments;
}

throw new \InvalidArgumentException(sprintf('Malformed field path "%s"', $name));
}
}
<?php










namespace Symfony\Component\Yaml;









class Unescaper
{








const ENCODING = 'UTF-8';




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($value)
{
return str_replace('\'\'', '\'', $value);
}








public function unescapeDoubleQuotedString($value)
{
$self = $this;
$callback = function ($match) use ($self) {
return $self->unescapeCharacter($match[0]);
};


 return preg_replace_callback('/'.self::REGEX_ESCAPED_CHARACTER.'/u', $callback, $value);
}











public function unescapeCharacter($value)
{
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:
@trigger_error('Not escaping a backslash in a double-quoted string is deprecated since Symfony 2.8 and will throw a ParseException in 3.0.', E_USER_DEPRECATED);

return $value;
}
}








private static function utf8chr($c)
{
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;









class Escaper
{

 const REGEX_CHARACTER_TO_ESCAPE = "[\\x00-\\x1f]|\xc2\x85|\xc2\xa0|\xe2\x80\xa8|\xe2\x80\xa9";


 
 
 
 private static $escapees = array('\\', '\\\\', '\\"', '"',
"\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",
"\xc2\x85", "\xc2\xa0", "\xe2\x80\xa8", "\xe2\x80\xa9");
private static $escaped = array('\\\\', '\\"', '\\\\', '\\"',
'\\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',
'\\N', '\\_', '\\L', '\\P');








public static function requiresDoubleQuoting($value)
{
return preg_match('/'.self::REGEX_CHARACTER_TO_ESCAPE.'/u', $value);
}








public static function escapeWithDoubleQuotes($value)
{
return sprintf('"%s"', str_replace(self::$escapees, self::$escaped, $value));
}








public static function requiresSingleQuoting($value)
{

 
 if (in_array(strtolower($value), array('null', '~', 'true', 'false', 'y', 'n', 'yes', 'no', 'on', 'off'))) {
return true;
}


 
 return preg_match('/[ \s \' " \: \{ \} \[ \] , & \* \# \?] | \A[ \- ? | < > = ! % @ ` ]/x', $value);
}








public static function escapeWithSingleQuotes($value)
{
return sprintf("'%s'", str_replace('\'', '\'\'', $value));
}
}
<?php










namespace Symfony\Component\Yaml;

use Symfony\Component\Yaml\Exception\ParseException;






class Parser
{
const BLOCK_SCALAR_HEADER_PATTERN = '(?P<separator>\||>)(?P<modifiers>\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P<comments> +#.*)?';

 const FOLDED_SCALAR_PATTERN = self::BLOCK_SCALAR_HEADER_PATTERN;

private $offset = 0;
private $lines = array();
private $currentLineNb = -1;
private $currentLine = '';
private $refs = array();






public function __construct($offset = 0)
{
$this->offset = $offset;
}













public function parse($value, $exceptionOnInvalidType = false, $objectSupport = false, $objectForMap = false)
{
if (!preg_match('//u', $value)) {
throw new ParseException('The YAML value does not appear to be valid UTF-8.');
}
$this->currentLineNb = -1;
$this->currentLine = '';
$value = $this->cleanup($value);
$this->lines = explode("\n", $value);

if (2  & (int) ini_get('mbstring.func_overload')) {
$mbEncoding = mb_internal_encoding();
mb_internal_encoding('UTF-8');
}

$data = array();
$context = null;
$allowOverwrite = false;
while ($this->moveToNextLine()) {
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);
}

$isRef = $mergeNode = false;
if (preg_match('#^\-((?P<leadspaces>\s+)(?P<value>.+?))?\s*$#u', $this->currentLine, $values)) {
if ($context && 'mapping' == $context) {
throw new ParseException('You cannot define a sequence item when in a mapping');
}
$context = 'sequence';

if (isset($values['value']) && preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#u', $values['value'], $matches)) {
$isRef = $matches['ref'];
$values['value'] = $matches['value'];
}


 if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) {
$c = $this->getRealCurrentLineNb() + 1;
$parser = new self($c);
$parser->refs = &$this->refs;
$data[] = $parser->parse($this->getNextEmbedBlock(null, true), $exceptionOnInvalidType, $objectSupport, $objectForMap);
} else {
if (isset($values['leadspaces'])
&& preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\{\[].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $values['value'], $matches)
) {

 $c = $this->getRealCurrentLineNb();
$parser = new self($c);
$parser->refs = &$this->refs;

$block = $values['value'];
if ($this->isNextLineIndented()) {
$block .= "\n".$this->getNextEmbedBlock($this->getCurrentLineIndentation() + strlen($values['leadspaces']) + 1);
}

$data[] = $parser->parse($block, $exceptionOnInvalidType, $objectSupport, $objectForMap);
} else {
$data[] = $this->parseValue($values['value'], $exceptionOnInvalidType, $objectSupport, $objectForMap, $context);
}
}
if ($isRef) {
$this->refs[$isRef] = end($data);
}
} elseif (preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\[\{].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $this->currentLine, $values) && (false === strpos($values['key'], ' #') || in_array($values['key'][0], array('"', "'")))) {
if ($context && 'sequence' == $context) {
throw new ParseException('You cannot define a mapping item when in a sequence');
}
$context = 'mapping';


 Inline::parse(null, $exceptionOnInvalidType, $objectSupport, $objectForMap, $this->refs);
try {
$key = Inline::parseScalar($values['key']);
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);

throw $e;
}


 if (is_float($key)) {
$key = (string) $key;
}

if ('<<' === $key) {
$mergeNode = true;
$allowOverwrite = true;
if (isset($values['value']) && 0 === strpos($values['value'], '*')) {
$refName = substr($values['value'], 1);
if (!array_key_exists($refName, $this->refs)) {
throw new ParseException(sprintf('Reference "%s" does not exist.', $refName), $this->getRealCurrentLineNb() + 1, $this->currentLine);
}

$refValue = $this->refs[$refName];

if (!is_array($refValue)) {
throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
}

foreach ($refValue as $key => $value) {
if (!isset($data[$key])) {
$data[$key] = $value;
}
}
} else {
if (isset($values['value']) && $values['value'] !== '') {
$value = $values['value'];
} else {
$value = $this->getNextEmbedBlock();
}
$c = $this->getRealCurrentLineNb() + 1;
$parser = new self($c);
$parser->refs = &$this->refs;
$parsed = $parser->parse($value, $exceptionOnInvalidType, $objectSupport, $objectForMap);

if (!is_array($parsed)) {
throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
}

if (isset($parsed[0])) {

 
 
 foreach ($parsed as $parsedItem) {
if (!is_array($parsedItem)) {
throw new ParseException('Merge items must be arrays.', $this->getRealCurrentLineNb() + 1, $parsedItem);
}

foreach ($parsedItem as $key => $value) {
if (!isset($data[$key])) {
$data[$key] = $value;
}
}
}
} else {

 
 foreach ($parsed as $key => $value) {
if (!isset($data[$key])) {
$data[$key] = $value;
}
}
}
}
} elseif (isset($values['value']) && preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#u', $values['value'], $matches)) {
$isRef = $matches['ref'];
$values['value'] = $matches['value'];
}

if ($mergeNode) {

 } elseif (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) {

 
 if (!$this->isNextLineIndented() && !$this->isNextLineUnIndentedCollection()) {

 
 if ($allowOverwrite || !isset($data[$key])) {
$data[$key] = null;
}
} else {
$c = $this->getRealCurrentLineNb() + 1;
$parser = new self($c);
$parser->refs = &$this->refs;
$value = $parser->parse($this->getNextEmbedBlock(), $exceptionOnInvalidType, $objectSupport, $objectForMap);

 
 if ($allowOverwrite || !isset($data[$key])) {
$data[$key] = $value;
}
}
} else {
$value = $this->parseValue($values['value'], $exceptionOnInvalidType, $objectSupport, $objectForMap, $context);

 
 if ($allowOverwrite || !isset($data[$key])) {
$data[$key] = $value;
}
}
if ($isRef) {
$this->refs[$isRef] = $data[$key];
}
} else {

 if ('---' === $this->currentLine) {
throw new ParseException('Multiple documents are not supported.');
}


 if (is_string($value) && $this->lines[0] === trim($value)) {
try {
$value = Inline::parse($this->lines[0], $exceptionOnInvalidType, $objectSupport, $objectForMap, $this->refs);
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);

throw $e;
}

if (is_array($value)) {
$first = reset($value);
if (is_string($first) && 0 === strpos($first, '*')) {
$data = array();
foreach ($value as $alias) {
$data[] = $this->refs[substr($alias, 1)];
}
$value = $data;
}
}

if (isset($mbEncoding)) {
mb_internal_encoding($mbEncoding);
}

return $value;
}

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 = 'Unable to parse.';
}

throw new ParseException($error, $this->getRealCurrentLineNb() + 1, $this->currentLine);
}
}

if (isset($mbEncoding)) {
mb_internal_encoding($mbEncoding);
}

if ($objectForMap && !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 getRealCurrentLineNb()
{
return $this->currentLineNb + $this->offset;
}






private function getCurrentLineIndentation()
{
return strlen($this->currentLine) - strlen(ltrim($this->currentLine, ' '));
}











private function getNextEmbedBlock($indentation = null, $inSequence = false)
{
$oldLineIndentation = $this->getCurrentLineIndentation();
$blockScalarIndentations = array();

if ($this->isBlockScalarHeader()) {
$blockScalarIndentations[] = $this->getCurrentLineIndentation();
}

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

if (null === $indentation) {
$newIndent = $this->getCurrentLineIndentation();

$unindentedEmbedBlock = $this->isStringUnIndentedCollectionItem();

if (!$this->isCurrentLineEmpty() && 0 === $newIndent && !$unindentedEmbedBlock) {
throw new ParseException('Indentation problem.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
}
} else {
$newIndent = $indentation;
}

$data = array();
if ($this->getCurrentLineIndentation() >= $newIndent) {
$data[] = substr($this->currentLine, $newIndent);
} else {
$this->moveToPreviousLine();

return;
}

if ($inSequence && $oldLineIndentation === $newIndent && isset($data[0][0]) && '-' === $data[0][0]) {

 
 $this->moveToPreviousLine();

return;
}

$isItUnindentedCollection = $this->isStringUnIndentedCollectionItem();

if (empty($blockScalarIndentations) && $this->isBlockScalarHeader()) {
$blockScalarIndentations[] = $this->getCurrentLineIndentation();
}

$previousLineIndentation = $this->getCurrentLineIndentation();

while ($this->moveToNextLine()) {
$indent = $this->getCurrentLineIndentation();


 if (!empty($blockScalarIndentations) && $indent < $previousLineIndentation && trim($this->currentLine) !== '') {
foreach ($blockScalarIndentations as $key => $blockScalarIndentation) {
if ($blockScalarIndentation >= $this->getCurrentLineIndentation()) {
unset($blockScalarIndentations[$key]);
}
}
}

if (empty($blockScalarIndentations) && !$this->isCurrentLineComment() && $this->isBlockScalarHeader()) {
$blockScalarIndentations[] = $this->getCurrentLineIndentation();
}

$previousLineIndentation = $indent;

if ($isItUnindentedCollection && !$this->isStringUnIndentedCollectionItem() && $newIndent === $indent) {
$this->moveToPreviousLine();
break;
}

if ($this->isCurrentLineBlank()) {
$data[] = substr($this->currentLine, $newIndent);
continue;
}


 if (empty($blockScalarIndentations) && $this->isCurrentLineComment()) {
continue;
}

if ($indent >= $newIndent) {
$data[] = substr($this->currentLine, $newIndent);
} elseif (0 == $indent) {
$this->moveToPreviousLine();

break;
} else {
throw new ParseException('Indentation problem.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
}
}

return implode("\n", $data);
}






private function moveToNextLine()
{
if ($this->currentLineNb >= count($this->lines) - 1) {
return false;
}

$this->currentLine = $this->lines[++$this->currentLineNb];

return true;
}




private function moveToPreviousLine()
{
$this->currentLine = $this->lines[--$this->currentLineNb];
}














private function parseValue($value, $exceptionOnInvalidType, $objectSupport, $objectForMap, $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)) {
throw new ParseException(sprintf('Reference "%s" does not exist.', $value), $this->currentLine);
}

return $this->refs[$value];
}

if (preg_match('/^'.self::BLOCK_SCALAR_HEADER_PATTERN.'$/', $value, $matches)) {
$modifiers = isset($matches['modifiers']) ? $matches['modifiers'] : '';

return $this->parseBlockScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), (int) abs($modifiers));
}

try {
$parsedValue = Inline::parse($value, $exceptionOnInvalidType, $objectSupport, $objectForMap, $this->refs);

if ('mapping' === $context && '"' !== $value[0] && "'" !== $value[0] && '[' !== $value[0] && '{' !== $value[0] && '!' !== $value[0] && false !== strpos($parsedValue, ': ')) {
@trigger_error(sprintf('Using a colon in the unquoted mapping value "%s" in line %d is deprecated since Symfony 2.8 and will throw a ParseException in 3.0.', $value, $this->getRealCurrentLineNb() + 1), E_USER_DEPRECATED);


 
 }

return $parsedValue;
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);

throw $e;
}
}










private function parseBlockScalar($style, $chomping = '', $indentation = 0)
{
$notEOF = $this->moveToNextLine();
if (!$notEOF) {
return '';
}

$isCurrentLineBlank = $this->isCurrentLineBlank();
$blockLines = array();


 while ($notEOF && $isCurrentLineBlank) {

 if ($notEOF = $this->moveToNextLine()) {
$blockLines[] = '';
$isCurrentLineBlank = $this->isCurrentLineBlank();
}
}


 if (0 === $indentation) {
if (preg_match('/^ +/', $this->currentLine, $matches)) {
$indentation = strlen($matches[0]);
}
}

if ($indentation > 0) {
$pattern = sprintf('/^ {%d}(.*)$/', $indentation);

while (
$notEOF && (
$isCurrentLineBlank ||
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();
}


 if ('>' === $style) {
$text = '';
$previousLineIndented = false;
$previousLineBlank = false;

for ($i = 0; $i < count($blockLines); ++$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()
{
$currentIndentation = $this->getCurrentLineIndentation();
$EOF = !$this->moveToNextLine();

while (!$EOF && $this->isCurrentLineEmpty()) {
$EOF = !$this->moveToNextLine();
}

if ($EOF) {
return false;
}

$ret = false;
if ($this->getCurrentLineIndentation() > $currentIndentation) {
$ret = true;
}

$this->moveToPreviousLine();

return $ret;
}






private function isCurrentLineEmpty()
{
return $this->isCurrentLineBlank() || $this->isCurrentLineComment();
}






private function isCurrentLineBlank()
{
return '' == trim($this->currentLine, ' ');
}






private function isCurrentLineComment()
{

 $ltrimmedLine = ltrim($this->currentLine, ' ');

return '' !== $ltrimmedLine && $ltrimmedLine[0] === '#';
}








private function cleanup($value)
{
$value = str_replace(array("\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 ($count == 1) {

 $this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n");
$value = $trimmedValue;
}


 $trimmedValue = preg_replace('#^\-\-\-.*?\n#s', '', $value, -1, $count);
if ($count == 1) {

 $this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n");
$value = $trimmedValue;


 $value = preg_replace('#\.\.\.\s*$#', '', $value);
}

return $value;
}






private function isNextLineUnIndentedCollection()
{
$currentIndentation = $this->getCurrentLineIndentation();
$notEOF = $this->moveToNextLine();

while ($notEOF && $this->isCurrentLineEmpty()) {
$notEOF = $this->moveToNextLine();
}

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

$ret = false;
if (
$this->getCurrentLineIndentation() == $currentIndentation
&&
$this->isStringUnIndentedCollectionItem()
) {
$ret = true;
}

$this->moveToPreviousLine();

return $ret;
}






private function isStringUnIndentedCollectionItem()
{
return 0 === strpos($this->currentLine, '- ');
}






private function isBlockScalarHeader()
{
return (bool) preg_match('~'.self::BLOCK_SCALAR_HEADER_PATTERN.'$~', $this->currentLine);
}
}
<?php










namespace Symfony\Component\Yaml;

use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Exception\DumpException;






class Inline
{
const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\']*(?:\'\'[^\']*)*)\')';

private static $exceptionOnInvalidType = false;
private static $objectSupport = false;
private static $objectForMap = false;














public static function parse($value, $exceptionOnInvalidType = false, $objectSupport = false, $objectForMap = false, $references = array())
{
self::$exceptionOnInvalidType = $exceptionOnInvalidType;
self::$objectSupport = $objectSupport;
self::$objectForMap = $objectForMap;

$value = trim($value);

if ('' === $value) {
return '';
}

if (2  & (int) ini_get('mbstring.func_overload')) {
$mbEncoding = mb_internal_encoding();
mb_internal_encoding('ASCII');
}

$i = 0;
switch ($value[0]) {
case '[':
$result = self::parseSequence($value, $i, $references);
++$i;
break;
case '{':
$result = self::parseMapping($value, $i, $references);
++$i;
break;
default:
$result = self::parseScalar($value, null, array('"', "'"), $i, true, $references);
}


 if (preg_replace('/\s+#.*$/A', '', substr($value, $i))) {
throw new ParseException(sprintf('Unexpected characters near "%s".', substr($value, $i)));
}

if (isset($mbEncoding)) {
mb_internal_encoding($mbEncoding);
}

return $result;
}












public static function dump($value, $exceptionOnInvalidType = false, $objectSupport = false)
{
switch (true) {
case is_resource($value):
if ($exceptionOnInvalidType) {
throw new DumpException(sprintf('Unable to dump PHP resources in a YAML file ("%s").', get_resource_type($value)));
}

return 'null';
case is_object($value):
if ($objectSupport) {
return '!php/object:'.serialize($value);
}

if ($exceptionOnInvalidType) {
throw new DumpException('Object support when dumping a YAML file has been disabled.');
}

return 'null';
case is_array($value):
return self::dumpArray($value, $exceptionOnInvalidType, $objectSupport);
case null === $value:
return 'null';
case true === $value:
return 'true';
case false === $value:
return 'false';
case ctype_digit($value):
return is_string($value) ? "'$value'" : (int) $value;
case is_numeric($value):
$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 Escaper::requiresDoubleQuoting($value):
return Escaper::escapeWithDoubleQuotes($value);
case Escaper::requiresSingleQuoting($value):
case preg_match(self::getHexRegex(), $value):
case preg_match(self::getTimestampRegex(), $value):
return Escaper::escapeWithSingleQuotes($value);
default:
return $value;
}
}










private static function dumpArray($value, $exceptionOnInvalidType, $objectSupport)
{

 $keys = array_keys($value);
$keysCount = count($keys);
if ((1 === $keysCount && '0' == $keys[0])
|| ($keysCount > 1 && array_reduce($keys, function ($v, $w) { return (int) $v + $w; }, 0) === $keysCount * ($keysCount - 1) / 2)
) {
$output = array();
foreach ($value as $val) {
$output[] = self::dump($val, $exceptionOnInvalidType, $objectSupport);
}

return sprintf('[%s]', implode(', ', $output));
}


 $output = array();
foreach ($value as $key => $val) {
$output[] = sprintf('%s: %s', self::dump($key, $exceptionOnInvalidType, $objectSupport), self::dump($val, $exceptionOnInvalidType, $objectSupport));
}

return sprintf('{ %s }', implode(', ', $output));
}

















public static function parseScalar($scalar, $delimiters = null, $stringDelimiters = array('"', "'"), &$i = 0, $evaluate = true, $references = array())
{
if (in_array($scalar[$i], $stringDelimiters)) {

 $output = self::parseQuotedScalar($scalar, $i);

if (null !== $delimiters) {
$tmp = ltrim(substr($scalar, $i), ' ');
if (!in_array($tmp[0], $delimiters)) {
throw new ParseException(sprintf('Unexpected characters (%s).', substr($scalar, $i)));
}
}
} else {

 if (!$delimiters) {
$output = substr($scalar, $i);
$i += strlen($output);


 if (preg_match('/[ \t]+#/', $output, $match, PREG_OFFSET_CAPTURE)) {
$output = substr($output, 0, $match[0][1]);
}
} elseif (preg_match('/^(.+?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match)) {
$output = $match[1];
$i += strlen($output);
} else {
throw new ParseException(sprintf('Malformed inline YAML string (%s).', $scalar));
}


 if ($output && ('@' === $output[0] || '`' === $output[0] || '|' === $output[0] || '>' === $output[0])) {
@trigger_error(sprintf('Not quoting the scalar "%s" starting with "%s" is deprecated since Symfony 2.8 and will throw a ParseException in 3.0.', $output, $output[0]), E_USER_DEPRECATED);


 
 }

if ($evaluate) {
$output = self::evaluateScalar($output, $references);
}
}

return $output;
}











private static function parseQuotedScalar($scalar, &$i)
{
if (!preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) {
throw new ParseException(sprintf('Malformed inline YAML string (%s).', substr($scalar, $i)));
}

$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($sequence, &$i = 0, $references = array())
{
$output = array();
$len = strlen($sequence);
++$i;


 while ($i < $len) {
switch ($sequence[$i]) {
case '[':

 $output[] = self::parseSequence($sequence, $i, $references);
break;
case '{':

 $output[] = self::parseMapping($sequence, $i, $references);
break;
case ']':
return $output;
case ',':
case ' ':
break;
default:
$isQuoted = in_array($sequence[$i], array('"', "'"));
$value = self::parseScalar($sequence, array(',', ']'), array('"', "'"), $i, true, $references);


 if (!is_array($value) && !$isQuoted && false !== strpos($value, ': ')) {

 try {
$pos = 0;
$value = self::parseMapping('{'.$value.'}', $pos, $references);
} catch (\InvalidArgumentException $e) {

 }
}

$output[] = $value;

--$i;
}

++$i;
}

throw new ParseException(sprintf('Malformed inline YAML string %s', $sequence));
}












private static function parseMapping($mapping, &$i = 0, $references = array())
{
$output = array();
$len = strlen($mapping);
++$i;


 while ($i < $len) {
switch ($mapping[$i]) {
case ' ':
case ',':
++$i;
continue 2;
case '}':
if (self::$objectForMap) {
return (object) $output;
}

return $output;
}


 $key = self::parseScalar($mapping, array(':', ' '), array('"', "'"), $i, false);


 $done = false;

while ($i < $len) {
switch ($mapping[$i]) {
case '[':

 $value = self::parseSequence($mapping, $i, $references);

 
 
 if (!isset($output[$key])) {
$output[$key] = $value;
}
$done = true;
break;
case '{':

 $value = self::parseMapping($mapping, $i, $references);

 
 
 if (!isset($output[$key])) {
$output[$key] = $value;
}
$done = true;
break;
case ':':
case ' ':
break;
default:
$value = self::parseScalar($mapping, array(',', '}'), array('"', "'"), $i, true, $references);

 
 
 if (!isset($output[$key])) {
$output[$key] = $value;
}
$done = true;
--$i;
}

++$i;

if ($done) {
continue 2;
}
}
}

throw new ParseException(sprintf('Malformed inline YAML string %s', $mapping));
}











private static function evaluateScalar($scalar, $references = array())
{
$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.');
}

if (!array_key_exists($value, $references)) {
throw new ParseException(sprintf('Reference "%s" does not exist.', $value));
}

return $references[$value];
}

switch (true) {
case 'null' === $scalarLower:
case '' === $scalar:
case '~' === $scalar:
return;
case 'true' === $scalarLower:
return true;
case 'false' === $scalarLower:
return false;

 case $scalar[0] === '+' || $scalar[0] === '-' || $scalar[0] === '.' || $scalar[0] === '!' || is_numeric($scalar[0]):
switch (true) {
case 0 === strpos($scalar, '!str'):
return (string) substr($scalar, 5);
case 0 === strpos($scalar, '! '):
return (int) self::parseScalar(substr($scalar, 2));
case 0 === strpos($scalar, '!php/object:'):
if (self::$objectSupport) {
return unserialize(substr($scalar, 12));
}

if (self::$exceptionOnInvalidType) {
throw new ParseException('Object support when parsing a YAML file has been disabled.');
}

return;
case 0 === strpos($scalar, '!!php/object:'):
if (self::$objectSupport) {
return unserialize(substr($scalar, 13));
}

if (self::$exceptionOnInvalidType) {
throw new ParseException('Object support when parsing a YAML file has been disabled.');
}

return;
case 0 === strpos($scalar, '!!float '):
return (float) substr($scalar, 8);
case ctype_digit($scalar):
$raw = $scalar;
$cast = (int) $scalar;

return '0' == $scalar[0] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw);
case '-' === $scalar[0] && ctype_digit(substr($scalar, 1)):
$raw = $scalar;
$cast = (int) $scalar;

return '0' == $scalar[1] ? octdec($scalar) : (((string) $raw === (string) $cast) ? $cast : $raw);
case is_numeric($scalar):
case preg_match(self::getHexRegex(), $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 preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar):
return (float) str_replace(',', '', $scalar);
case preg_match(self::getTimestampRegex(), $scalar):
$timeZone = date_default_timezone_get();
date_default_timezone_set('UTC');
$time = strtotime($scalar);
date_default_timezone_set($timeZone);

return $time;
}
default:
return (string) $scalar;
}
}








private static function getTimestampRegex()
{
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()
{
return '~^0x[0-9a-f]++$~i';
}
}
<?php










namespace Symfony\Component\Yaml;






class Dumper
{





protected $indentation = 4;






public function setIndentation($num)
{
if ($num < 1) {
throw new \InvalidArgumentException('The indentation must be greater than zero.');
}

$this->indentation = (int) $num;
}












public function dump($input, $inline = 0, $indent = 0, $exceptionOnInvalidType = false, $objectSupport = false)
{
$output = '';
$prefix = $indent ? str_repeat(' ', $indent) : '';

if ($inline <= 0 || !is_array($input) || empty($input)) {
$output .= $prefix.Inline::dump($input, $exceptionOnInvalidType, $objectSupport);
} else {
$isAHash = array_keys($input) !== range(0, count($input) - 1);

foreach ($input as $key => $value) {
$willBeInlined = $inline - 1 <= 0 || !is_array($value) || empty($value);

$output .= sprintf('%s%s%s%s',
$prefix,
$isAHash ? Inline::dump($key, $exceptionOnInvalidType, $objectSupport).':' : '-',
$willBeInlined ? ' ' : "\n",
$this->dump($value, $inline - 1, $willBeInlined ? 0 : $indent + $this->indentation, $exceptionOnInvalidType, $objectSupport)
).($willBeInlined ? "\n" : '');
}
}

return $output;
}
}
<?php










namespace Symfony\Component\Yaml\Exception;






class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
<?php










namespace Symfony\Component\Yaml\Exception;






interface ExceptionInterface
{
}
<?php










namespace Symfony\Component\Yaml\Exception;






class ParseException extends RuntimeException
{
private $parsedFile;
private $parsedLine;
private $snippet;
private $rawMessage;










public function __construct($message, $parsedLine = -1, $snippet = null, $parsedFile = null, \Exception $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) {
if (PHP_VERSION_ID >= 50400) {
$jsonOptions = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
} else {
$jsonOptions = 0;
}
$this->message .= sprintf(' in %s', json_encode($this->parsedFile, $jsonOptions));
}

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 DumpException extends RuntimeException
{
}
<?php










namespace Symfony\Component\Yaml;

use Symfony\Component\Yaml\Exception\ParseException;






class Yaml
{
























public static function parse($input, $exceptionOnInvalidType = false, $objectSupport = false, $objectForMap = false)
{

 $file = '';
if (strpos($input, "\n") === false && is_file($input)) {
@trigger_error('The ability to pass file names to the '.__METHOD__.' method is deprecated since version 2.2 and will be removed in 3.0. Pass the YAML contents of the file instead.', E_USER_DEPRECATED);

if (false === is_readable($input)) {
throw new ParseException(sprintf('Unable to parse "%s" as the file is not readable.', $input));
}

$file = $input;
$input = file_get_contents($file);
}

$yaml = new Parser();

try {
return $yaml->parse($input, $exceptionOnInvalidType, $objectSupport, $objectForMap);
} catch (ParseException $e) {
if ($file) {
$e->setParsedFile($file);
}

throw $e;
}
}















public static function dump($array, $inline = 2, $indent = 4, $exceptionOnInvalidType = false, $objectSupport = false)
{
if ($indent < 1) {
throw new \InvalidArgumentException('The indentation must be greater than zero.');
}

$yaml = new Dumper();
$yaml->setIndentation($indent);

return $yaml->dump($array, $inline, 0, $exceptionOnInvalidType, $objectSupport);
}
}
<?php










namespace Symfony\Component\BrowserKit;






class CookieJar
{
protected $cookieJar = array();






public function set(Cookie $cookie)
{
$this->cookieJar[$cookie->getDomain()][$cookie->getPath()][$cookie->getName()] = $cookie;
}















public function get($name, $path = '/', $domain = null)
{
$this->flushExpiredCookies();

if (!empty($domain)) {
foreach ($this->cookieJar as $cookieDomain => $pathCookies) {
if ($cookieDomain) {
$cookieDomain = '.'.ltrim($cookieDomain, '.');
if ($cookieDomain != substr('.'.$domain, -strlen($cookieDomain))) {
continue;
}
}

foreach ($pathCookies as $cookiePath => $namedCookies) {
if ($cookiePath != substr($path, 0, strlen($cookiePath))) {
continue;
}
if (isset($namedCookies[$name])) {
return $namedCookies[$name];
}
}
}

return;
}


 foreach ($this->cookieJar as $cookies) {
if (isset($cookies[$path][$name])) {
return $cookies[$path][$name];
}
}
}












public function expire($name, $path = '/', $domain = null)
{
if (null === $path) {
$path = '/';
}

if (empty($domain)) {

 
 $domains = array_keys($this->cookieJar);
} else {
$domains = array($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 = array();
}







public function updateFromSetCookie(array $setCookies, $uri = null)
{
$cookies = array();

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 = array();
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(array('path' => '/'), parse_url($uri));
$cookies = array();
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 Response
{
protected $content;
protected $status;
protected $headers;











public function __construct($content = '', $status = 200, array $headers = array())
{
$this->content = $content;
$this->status = $status;
$this->headers = $headers;
}






public function __toString()
{
$headers = '';
foreach ($this->headers as $name => $value) {
if (is_string($value)) {
$headers .= $this->buildHeader($name, $value);
} else {
foreach ($value as $headerValue) {
$headers .= $this->buildHeader($name, $headerValue);
}
}
}

return $headers."\n".$this->content;
}









protected function buildHeader($name, $value)
{
return sprintf("%s: %s\n", $name, $value);
}






public function getContent()
{
return $this->content;
}






public function getStatus()
{
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 : array($value);
}
}

return $first ? null : array();
}
}
<?php










namespace Symfony\Component\BrowserKit;

use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\DomCrawler\Link;
use Symfony\Component\DomCrawler\Form;
use Symfony\Component\Process\PhpProcess;











abstract class Client
{
protected $history;
protected $cookieJar;
protected $server = array();
protected $internalRequest;
protected $request;
protected $internalResponse;
protected $response;
protected $crawler;
protected $insulated = false;
protected $redirect;
protected $followRedirects = true;

private $maxRedirects = -1;
private $redirectCount = 0;
private $isMainRequest = true;








public function __construct(array $server = array(), 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 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')) {
throw new \RuntimeException('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(array(
'HTTP_USER_AGENT' => 'Symfony2 BrowserKit',
), $server);
}







public function setServerParameter($key, $value)
{
$this->server[$key] = $value;
}









public function getServerParameter($key, $default = '')
{
return isset($this->server[$key]) ? $this->server[$key] : $default;
}






public function getHistory()
{
return $this->history;
}






public function getCookieJar()
{
return $this->cookieJar;
}






public function getCrawler()
{
return $this->crawler;
}






public function getInternalResponse()
{
return $this->internalResponse;
}











public function getResponse()
{
return $this->response;
}






public function getInternalRequest()
{
return $this->internalRequest;
}











public function getRequest()
{
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 submit(Form $form, array $values = array())
{
$form->setValues($values);

return $this->request($form->getMethod(), $form->getUri(), $form->getPhpValues(), $form->getPhpFiles());
}














public function request($method, $uri, array $parameters = array(), array $files = array(), array $server = array(), $content = null, $changeHistory = true)
{
if ($this->isMainRequest) {
$this->redirectCount = 0;
} else {
++$this->redirectCount;
}

$uri = $this->getAbsoluteUri($uri);

$server = array_merge($this->server, $server);

if (isset($server['HTTPS'])) {
$uri = preg_replace('{^'.parse_url($uri, PHP_URL_SCHEME).'}', $server['HTTPS'] ? 'https' : 'http', $uri);
}

if (!$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->getStatus();

if ($status >= 300 && $status < 400) {
$this->redirect = $this->internalResponse->getHeader('Location');
} else {
$this->redirect = null;
}

if ($this->followRedirects && $this->redirect) {
return $this->crawler = $this->followRedirect();
}

return $this->crawler = $this->createCrawlerFromContent($this->internalRequest->getUri(), $this->internalResponse->getContent(), $this->internalResponse->getHeader('Content-Type'));
}










protected function doRequestInProcess($request)
{
$process = new PhpProcess($this->getScript($request), null, null);
$process->run();

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('Symfony\Component\DomCrawler\Crawler')) {
return;
}

$crawler = new Crawler(null, $uri);
$crawler->addContent($content, $type);

return $crawler;
}






public function back()
{
return $this->requestFromRequest($this->history->back(), false);
}






public function forward()
{
return $this->requestFromRequest($this->history->forward(), 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) {
throw new \LogicException(sprintf('The maximum number (%d) of redirections was reached.', $this->maxRedirects));
}
}

$request = $this->internalRequest;

if (in_array($this->internalResponse->getStatus(), array(302, 303))) {
$method = 'get';
$files = array();
$content = null;
} else {
$method = $request->getMethod();
$files = $request->getFiles();
$content = $request->getContent();
}

if ('get' === strtolower($method)) {

 $parameters = array();
} 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;
}






public function restart()
{
$this->cookieJar->clear();
$this->history->clear();
}








protected function getAbsoluteUri($uri)
{

 if (0 === strpos($uri, 'http://') || 0 === strpos($uri, 'https://')) {
return $uri;
}

if (!$this->history->isEmpty()) {
$currentUri = $this->history->current()->getUri();
} else {
$currentUri = sprintf('http%s://%s/',
isset($this->server['HTTPS']) ? 's' : '',
isset($this->server['HTTP_HOST']) ? $this->server['HTTP_HOST'] : 'localhost'
);
}


 if (0 === strpos($uri, '//')) {
return parse_url($currentUri, PHP_URL_SCHEME).':'.$uri;
}


 if (!$uri || '#' == $uri[0]) {
return preg_replace('/#.*?$/', '', $currentUri).$uri;
}

if ('/' !== $uri[0]) {
$path = parse_url($currentUri, PHP_URL_PATH);

if ('/' !== substr($path, -1)) {
$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($server, $uri)
{
$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($uri)
{
$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;






class Cookie
{






private static $dateFormats = array(
'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;













public function __construct($name, $value, $expires = null, $path = null, $domain = '', $secure = false, $httponly = true, $encodedValue = false)
{
if ($encodedValue) {
$this->value = urldecode($value);
$this->rawValue = $value;
} else {
$this->value = $value;
$this->rawValue = urlencode($value);
}
$this->name = $name;
$this->path = empty($path) ? '/' : $path;
$this->domain = $domain;
$this->secure = (bool) $secure;
$this->httponly = (bool) $httponly;

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->getTimestamp();
}
}








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::$dateFormats[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';
}

return $cookie;
}











public static function fromString($cookie, $url = null)
{
$parts = explode(';', $cookie);

if (false === strpos($parts[0], '=')) {
throw new \InvalidArgumentException(sprintf('The cookie string "%s" is not valid.', $parts[0]));
}

list($name, $value) = explode('=', array_shift($parts), 2);

$values = array(
'name' => trim($name),
'value' => trim($value),
'expires' => null,
'path' => '/',
'domain' => '',
'secure' => false,
'httponly' => false,
'passedRawValue' => true,
);

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']
);
}

private static function parseDate($dateValue)
{

 if (($length = strlen($dateValue)) > 1 && "'" === $dateValue[0] && "'" === $dateValue[$length - 1]) {
$dateValue = substr($dateValue, 1, -1);
}

foreach (self::$dateFormats as $dateFormat) {
if (false !== $date = \DateTime::createFromFormat($dateFormat, $dateValue, new \DateTimeZone('GMT'))) {
return $date->getTimestamp();
}
}


 if (false !== $date = date_create($dateValue, new \DateTimeZone('GMT'))) {
return $date->getTimestamp();
}

throw new \InvalidArgumentException(sprintf('Could not parse date "%s".', $dateValue));
}






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();
}
}
<?php










namespace Symfony\Component\BrowserKit;






class Request
{
protected $uri;
protected $method;
protected $parameters;
protected $files;
protected $cookies;
protected $server;
protected $content;












public function __construct($uri, $method, array $parameters = array(), array $files = array(), array $cookies = array(), array $server = array(), $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;






class History
{
protected $stack = array();
protected $position = -1;




public function clear()
{
$this->stack = array();
$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 count($this->stack) == 0;
}








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 Composer\Autoload;





























class ClassLoader
{

 private $prefixLengthsPsr4 = array();
private $prefixDirsPsr4 = array();
private $fallbackDirsPsr4 = array();


 private $prefixesPsr0 = array();
private $fallbackDirsPsr0 = array();

private $useIncludePath = false;
private $classMap = array();

private $classMapAuthoritative = false;

public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', $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 register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}




public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
}







public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);

return true;
}
}








public function findFile($class)
{

 if ('\\' == $class[0]) {
$class = substr($class, 1);
}


 if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative) {
return false;
}

$file = $this->findFileWithExtension($class, '.php');


 if ($file === null && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}

if ($file === null) {

 return $this->classMap[$class] = false;
}

return $file;
}

private function findFileWithExtension($class, $ext)
{

 $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;

$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
if (0 === strpos($class, $prefix)) {
foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
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;
}
}
}






function includeFile($file)
{
include $file;
}
<?php



class ComposerAutoloaderInitc4909e075a7b68a94b7e4489eb2bb42e
{
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;
}

spl_autoload_register(array('ComposerAutoloaderInitc4909e075a7b68a94b7e4489eb2bb42e', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInitc4909e075a7b68a94b7e4489eb2bb42e', 'loadClassLoader'));

$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);

$includeFiles = require __DIR__ . '/autoload_files.php';
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequirec4909e075a7b68a94b7e4489eb2bb42e($fileIdentifier, $file);
}

return $loader;
}
}

function composerRequirec4909e075a7b68a94b7e4489eb2bb42e($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(
'phpDocumentor' => array($vendorDir . '/phpdocumentor/reflection-docblock/src'),
'Psr\\Log\\' => array($vendorDir . '/psr/log'),
'Prophecy\\' => array($vendorDir . '/phpspec/prophecy/src'),
'Pheanstalk' => array($vendorDir . '/pda/pheanstalk/classes'),
'Flow\\JSONPath\\Test' => array($vendorDir . '/flow/jsonpath/tests'),
'Flow\\JSONPath' => array($vendorDir . '/flow/jsonpath/src'),
'Codeception\\' => array($vendorDir . '/codeception/specify/src'),
);
<?php



$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
'File_Iterator' => $vendorDir . '/phpunit/php-file-iterator/src/Iterator.php',
'File_Iterator_Facade' => $vendorDir . '/phpunit/php-file-iterator/src/Facade.php',
'File_Iterator_Factory' => $vendorDir . '/phpunit/php-file-iterator/src/Factory.php',
'PHPUnit_Exception' => $vendorDir . '/phpunit/phpunit/src/Exception.php',
'PHPUnit_Extensions_GroupTestSuite' => $vendorDir . '/phpunit/phpunit/src/Extensions/GroupTestSuite.php',
'PHPUnit_Extensions_PhptTestCase' => $vendorDir . '/phpunit/phpunit/src/Extensions/PhptTestCase.php',
'PHPUnit_Extensions_PhptTestSuite' => $vendorDir . '/phpunit/phpunit/src/Extensions/PhptTestSuite.php',
'PHPUnit_Extensions_RepeatedTest' => $vendorDir . '/phpunit/phpunit/src/Extensions/RepeatedTest.php',
'PHPUnit_Extensions_TestDecorator' => $vendorDir . '/phpunit/phpunit/src/Extensions/TestDecorator.php',
'PHPUnit_Extensions_TicketListener' => $vendorDir . '/phpunit/phpunit/src/Extensions/TicketListener.php',
'PHPUnit_Framework_Assert' => $vendorDir . '/phpunit/phpunit/src/Framework/Assert.php',
'PHPUnit_Framework_AssertionFailedError' => $vendorDir . '/phpunit/phpunit/src/Framework/AssertionFailedError.php',
'PHPUnit_Framework_BaseTestListener' => $vendorDir . '/phpunit/phpunit/src/Framework/BaseTestListener.php',
'PHPUnit_Framework_CodeCoverageException' => $vendorDir . '/phpunit/phpunit/src/Framework/CodeCoverageException.php',
'PHPUnit_Framework_Constraint' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint.php',
'PHPUnit_Framework_Constraint_And' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/And.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_Count' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Count.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_ExceptionMessageRegExp' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/ExceptionMessageRegExp.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_IsIdentical' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/IsIdentical.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_IsNull' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/IsNull.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_JsonMatches' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/JsonMatches.php',
'PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/JsonMatches/ErrorMessageProvider.php',
'PHPUnit_Framework_Constraint_LessThan' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/LessThan.php',
'PHPUnit_Framework_Constraint_Not' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Not.php',
'PHPUnit_Framework_Constraint_ObjectHasAttribute' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/ObjectHasAttribute.php',
'PHPUnit_Framework_Constraint_Or' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Or.php',
'PHPUnit_Framework_Constraint_PCREMatch' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/PCREMatch.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_StringMatches' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/StringMatches.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_TraversableContainsOnly' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/TraversableContainsOnly.php',
'PHPUnit_Framework_Constraint_Xor' => $vendorDir . '/phpunit/phpunit/src/Framework/Constraint/Xor.php',
'PHPUnit_Framework_Error' => $vendorDir . '/phpunit/phpunit/src/Framework/Error.php',
'PHPUnit_Framework_Error_Deprecated' => $vendorDir . '/phpunit/phpunit/src/Framework/Error/Deprecated.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.php',
'PHPUnit_Framework_ExceptionWrapper' => $vendorDir . '/phpunit/phpunit/src/Framework/ExceptionWrapper.php',
'PHPUnit_Framework_ExpectationFailedException' => $vendorDir . '/phpunit/phpunit/src/Framework/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/IncompleteTestError.php',
'PHPUnit_Framework_InvalidCoversTargetError' => $vendorDir . '/phpunit/phpunit/src/Framework/InvalidCoversTargetError.php',
'PHPUnit_Framework_InvalidCoversTargetException' => $vendorDir . '/phpunit/phpunit/src/Framework/InvalidCoversTargetException.php',
'PHPUnit_Framework_MockObject_BadMethodCallException' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Exception/BadMethodCallException.php',
'PHPUnit_Framework_MockObject_Builder_Identity' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Builder/Identity.php',
'PHPUnit_Framework_MockObject_Builder_InvocationMocker' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Builder/InvocationMocker.php',
'PHPUnit_Framework_MockObject_Builder_Match' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Builder/Match.php',
'PHPUnit_Framework_MockObject_Builder_MethodNameMatch' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Builder/MethodNameMatch.php',
'PHPUnit_Framework_MockObject_Builder_Namespace' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Builder/Namespace.php',
'PHPUnit_Framework_MockObject_Builder_ParametersMatch' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Builder/ParametersMatch.php',
'PHPUnit_Framework_MockObject_Builder_Stub' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Builder/Stub.php',
'PHPUnit_Framework_MockObject_Exception' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Exception/Exception.php',
'PHPUnit_Framework_MockObject_Generator' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Generator.php',
'PHPUnit_Framework_MockObject_Invocation' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Invocation.php',
'PHPUnit_Framework_MockObject_InvocationMocker' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/InvocationMocker.php',
'PHPUnit_Framework_MockObject_Invocation_Object' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Invocation/Object.php',
'PHPUnit_Framework_MockObject_Invocation_Static' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Invocation/Static.php',
'PHPUnit_Framework_MockObject_Invokable' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Invokable.php',
'PHPUnit_Framework_MockObject_Matcher' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher.php',
'PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/AnyInvokedCount.php',
'PHPUnit_Framework_MockObject_Matcher_AnyParameters' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/AnyParameters.php',
'PHPUnit_Framework_MockObject_Matcher_ConsecutiveParameters' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/ConsecutiveParameters.php',
'PHPUnit_Framework_MockObject_Matcher_Invocation' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/Invocation.php',
'PHPUnit_Framework_MockObject_Matcher_InvokedAtIndex' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/InvokedAtIndex.php',
'PHPUnit_Framework_MockObject_Matcher_InvokedAtLeastCount' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/InvokedAtLeastCount.php',
'PHPUnit_Framework_MockObject_Matcher_InvokedAtLeastOnce' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/InvokedAtLeastOnce.php',
'PHPUnit_Framework_MockObject_Matcher_InvokedAtMostCount' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/InvokedAtMostCount.php',
'PHPUnit_Framework_MockObject_Matcher_InvokedCount' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/InvokedCount.php',
'PHPUnit_Framework_MockObject_Matcher_InvokedRecorder' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/InvokedRecorder.php',
'PHPUnit_Framework_MockObject_Matcher_MethodName' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/MethodName.php',
'PHPUnit_Framework_MockObject_Matcher_Parameters' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/Parameters.php',
'PHPUnit_Framework_MockObject_Matcher_StatelessInvocation' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Matcher/StatelessInvocation.php',
'PHPUnit_Framework_MockObject_MockBuilder' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/MockBuilder.php',
'PHPUnit_Framework_MockObject_MockObject' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/MockObject.php',
'PHPUnit_Framework_MockObject_RuntimeException' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Exception/RuntimeException.php',
'PHPUnit_Framework_MockObject_Stub' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Stub.php',
'PHPUnit_Framework_MockObject_Stub_ConsecutiveCalls' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Stub/ConsecutiveCalls.php',
'PHPUnit_Framework_MockObject_Stub_Exception' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Stub/Exception.php',
'PHPUnit_Framework_MockObject_Stub_MatcherCollection' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Stub/MatcherCollection.php',
'PHPUnit_Framework_MockObject_Stub_Return' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Stub/Return.php',
'PHPUnit_Framework_MockObject_Stub_ReturnArgument' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Stub/ReturnArgument.php',
'PHPUnit_Framework_MockObject_Stub_ReturnCallback' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Stub/ReturnCallback.php',
'PHPUnit_Framework_MockObject_Stub_ReturnSelf' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Stub/ReturnSelf.php',
'PHPUnit_Framework_MockObject_Stub_ReturnValueMap' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Stub/ReturnValueMap.php',
'PHPUnit_Framework_MockObject_Verifiable' => $vendorDir . '/phpunit/phpunit-mock-objects/src/Framework/MockObject/Verifiable.php',
'PHPUnit_Framework_OutputError' => $vendorDir . '/phpunit/phpunit/src/Framework/OutputError.php',
'PHPUnit_Framework_RiskyTest' => $vendorDir . '/phpunit/phpunit/src/Framework/RiskyTest.php',
'PHPUnit_Framework_RiskyTestError' => $vendorDir . '/phpunit/phpunit/src/Framework/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/SkippedTestError.php',
'PHPUnit_Framework_SkippedTestSuiteError' => $vendorDir . '/phpunit/phpunit/src/Framework/SkippedTestSuiteError.php',
'PHPUnit_Framework_SyntheticError' => $vendorDir . '/phpunit/phpunit/src/Framework/SyntheticError.php',
'PHPUnit_Framework_Test' => $vendorDir . '/phpunit/phpunit/src/Framework/Test.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_TestResult' => $vendorDir . '/phpunit/phpunit/src/Framework/TestResult.php',
'PHPUnit_Framework_TestSuite' => $vendorDir . '/phpunit/phpunit/src/Framework/TestSuite.php',
'PHPUnit_Framework_TestSuite_DataProvider' => $vendorDir . '/phpunit/phpunit/src/Framework/TestSuite/DataProvider.php',
'PHPUnit_Framework_UnintentionallyCoveredCodeError' => $vendorDir . '/phpunit/phpunit/src/Framework/UnintentionallyCoveredCodeError.php',
'PHPUnit_Framework_Warning' => $vendorDir . '/phpunit/phpunit/src/Framework/Warning.php',
'PHPUnit_Runner_BaseTestRunner' => $vendorDir . '/phpunit/phpunit/src/Runner/BaseTestRunner.php',
'PHPUnit_Runner_Exception' => $vendorDir . '/phpunit/phpunit/src/Runner/Exception.php',
'PHPUnit_Runner_Filter_Factory' => $vendorDir . '/phpunit/phpunit/src/Runner/Filter/Factory.php',
'PHPUnit_Runner_Filter_GroupFilterIterator' => $vendorDir . '/phpunit/phpunit/src/Runner/Filter/Group.php',
'PHPUnit_Runner_Filter_Group_Exclude' => $vendorDir . '/phpunit/phpunit/src/Runner/Filter/Group/Exclude.php',
'PHPUnit_Runner_Filter_Group_Include' => $vendorDir . '/phpunit/phpunit/src/Runner/Filter/Group/Include.php',
'PHPUnit_Runner_Filter_Test' => $vendorDir . '/phpunit/phpunit/src/Runner/Filter/Test.php',
'PHPUnit_Runner_StandardTestSuiteLoader' => $vendorDir . '/phpunit/phpunit/src/Runner/StandardTestSuiteLoader.php',
'PHPUnit_Runner_TestSuiteLoader' => $vendorDir . '/phpunit/phpunit/src/Runner/TestSuiteLoader.php',
'PHPUnit_Runner_Version' => $vendorDir . '/phpunit/phpunit/src/Runner/Version.php',
'PHPUnit_TextUI_Command' => $vendorDir . '/phpunit/phpunit/src/TextUI/Command.php',
'PHPUnit_TextUI_ResultPrinter' => $vendorDir . '/phpunit/phpunit/src/TextUI/ResultPrinter.php',
'PHPUnit_TextUI_TestRunner' => $vendorDir . '/phpunit/phpunit/src/TextUI/TestRunner.php',
'PHPUnit_Util_Blacklist' => $vendorDir . '/phpunit/phpunit/src/Util/Blacklist.php',
'PHPUnit_Util_Configuration' => $vendorDir . '/phpunit/phpunit/src/Util/Configuration.php',
'PHPUnit_Util_ErrorHandler' => $vendorDir . '/phpunit/phpunit/src/Util/ErrorHandler.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_InvalidArgumentHelper' => $vendorDir . '/phpunit/phpunit/src/Util/InvalidArgumentHelper.php',
'PHPUnit_Util_Log_JSON' => $vendorDir . '/phpunit/phpunit/src/Util/Log/JSON.php',
'PHPUnit_Util_Log_JUnit' => $vendorDir . '/phpunit/phpunit/src/Util/Log/JUnit.php',
'PHPUnit_Util_Log_TAP' => $vendorDir . '/phpunit/phpunit/src/Util/Log/TAP.php',
'PHPUnit_Util_PHP' => $vendorDir . '/phpunit/phpunit/src/Util/PHP.php',
'PHPUnit_Util_PHP_Default' => $vendorDir . '/phpunit/phpunit/src/Util/PHP/Default.php',
'PHPUnit_Util_PHP_Windows' => $vendorDir . '/phpunit/phpunit/src/Util/PHP/Windows.php',
'PHPUnit_Util_Printer' => $vendorDir . '/phpunit/phpunit/src/Util/Printer.php',
'PHPUnit_Util_Regex' => $vendorDir . '/phpunit/phpunit/src/Util/Regex.php',
'PHPUnit_Util_String' => $vendorDir . '/phpunit/phpunit/src/Util/String.php',
'PHPUnit_Util_Test' => $vendorDir . '/phpunit/phpunit/src/Util/Test.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_ResultPrinter_HTML' => $vendorDir . '/phpunit/phpunit/src/Util/TestDox/ResultPrinter/HTML.php',
'PHPUnit_Util_TestDox_ResultPrinter_Text' => $vendorDir . '/phpunit/phpunit/src/Util/TestDox/ResultPrinter/Text.php',
'PHPUnit_Util_TestSuiteIterator' => $vendorDir . '/phpunit/phpunit/src/Util/TestSuiteIterator.php',
'PHPUnit_Util_Type' => $vendorDir . '/phpunit/phpunit/src/Util/Type.php',
'PHPUnit_Util_XML' => $vendorDir . '/phpunit/phpunit/src/Util/XML.php',
'PHP_CodeCoverage' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage.php',
'PHP_CodeCoverage_Driver' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Driver.php',
'PHP_CodeCoverage_Driver_HHVM' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Driver/HHVM.php',
'PHP_CodeCoverage_Driver_PHPDBG' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Driver/PHPDBG.php',
'PHP_CodeCoverage_Driver_Xdebug' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Driver/Xdebug.php',
'PHP_CodeCoverage_Exception' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Exception.php',
'PHP_CodeCoverage_Exception_UnintentionallyCoveredCode' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Exception/UnintentionallyCoveredCode.php',
'PHP_CodeCoverage_Filter' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Filter.php',
'PHP_CodeCoverage_Report_Clover' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Report/Clover.php',
'PHP_CodeCoverage_Report_Crap4j' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Report/Crap4j.php',
'PHP_CodeCoverage_Report_Factory' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Report/Factory.php',
'PHP_CodeCoverage_Report_HTML' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML.php',
'PHP_CodeCoverage_Report_HTML_Renderer' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer.php',
'PHP_CodeCoverage_Report_HTML_Renderer_Dashboard' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Dashboard.php',
'PHP_CodeCoverage_Report_HTML_Renderer_Directory' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/Directory.php',
'PHP_CodeCoverage_Report_HTML_Renderer_File' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/File.php',
'PHP_CodeCoverage_Report_Node' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Report/Node.php',
'PHP_CodeCoverage_Report_Node_Directory' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Report/Node/Directory.php',
'PHP_CodeCoverage_Report_Node_File' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Report/Node/File.php',
'PHP_CodeCoverage_Report_Node_Iterator' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Report/Node/Iterator.php',
'PHP_CodeCoverage_Report_PHP' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Report/PHP.php',
'PHP_CodeCoverage_Report_Text' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Report/Text.php',
'PHP_CodeCoverage_Report_XML' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Report/XML.php',
'PHP_CodeCoverage_Report_XML_Directory' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Report/XML/Directory.php',
'PHP_CodeCoverage_Report_XML_File' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Report/XML/File.php',
'PHP_CodeCoverage_Report_XML_File_Coverage' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Report/XML/File/Coverage.php',
'PHP_CodeCoverage_Report_XML_File_Method' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Report/XML/File/Method.php',
'PHP_CodeCoverage_Report_XML_File_Report' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Report/XML/File/Report.php',
'PHP_CodeCoverage_Report_XML_File_Unit' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Report/XML/File/Unit.php',
'PHP_CodeCoverage_Report_XML_Node' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Report/XML/Node.php',
'PHP_CodeCoverage_Report_XML_Project' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Report/XML/Project.php',
'PHP_CodeCoverage_Report_XML_Tests' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Report/XML/Tests.php',
'PHP_CodeCoverage_Report_XML_Totals' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Report/XML/Totals.php',
'PHP_CodeCoverage_Util' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Util.php',
'PHP_CodeCoverage_Util_InvalidArgumentHelper' => $vendorDir . '/phpunit/php-code-coverage/src/CodeCoverage/Util/InvalidArgumentHelper.php',
'PHP_Timer' => $vendorDir . '/phpunit/php-timer/src/Timer.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_ASYNC' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_AT' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_AWAIT' => $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_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_COMPILER_HALT_OFFSET' => $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_ENUM' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_EQUAL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_EQUALS' => $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_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_IN' => $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_JOIN' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_LAMBDA_ARROW' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_LAMBDA_CP' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_LAMBDA_OP' => $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_ONUMBER' => $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_SHAPE' => $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_TYPE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_TYPELIST_GT' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_TYPELIST_LT' => $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_VAR' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_VARIABLE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_WHERE' => $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_XHP_ATTRIBUTE' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_XHP_CATEGORY' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_XHP_CATEGORY_LABEL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_XHP_CHILDREN' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_XHP_LABEL' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_XHP_REQUIRED' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_XHP_TAG_GT' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_XHP_TAG_LT' => $vendorDir . '/phpunit/php-token-stream/src/Token.php',
'PHP_Token_XHP_TEXT' => $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',
'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\\Diff' => $vendorDir . '/sebastian/diff/src/Diff.php',
'SebastianBergmann\\Diff\\Differ' => $vendorDir . '/sebastian/diff/src/Differ.php',
'SebastianBergmann\\Diff\\LCS\\LongestCommonSubsequence' => $vendorDir . '/sebastian/diff/src/LCS/LongestCommonSubsequence.php',
'SebastianBergmann\\Diff\\LCS\\MemoryEfficientImplementation' => $vendorDir . '/sebastian/diff/src/LCS/MemoryEfficientLongestCommonSubsequenceImplementation.php',
'SebastianBergmann\\Diff\\LCS\\TimeEfficientImplementation' => $vendorDir . '/sebastian/diff/src/LCS/TimeEfficientLongestCommonSubsequenceImplementation.php',
'SebastianBergmann\\Diff\\Line' => $vendorDir . '/sebastian/diff/src/Line.php',
'SebastianBergmann\\Diff\\Parser' => $vendorDir . '/sebastian/diff/src/Parser.php',
'SebastianBergmann\\Environment\\Console' => $vendorDir . '/sebastian/environment/src/Console.php',
'SebastianBergmann\\Environment\\Runtime' => $vendorDir . '/sebastian/environment/src/Runtime.php',
'SebastianBergmann\\Exporter\\Exporter' => $vendorDir . '/sebastian/exporter/src/Exporter.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/Exception.php',
'SebastianBergmann\\GlobalState\\Restorer' => $vendorDir . '/sebastian/global-state/src/Restorer.php',
'SebastianBergmann\\GlobalState\\RuntimeException' => $vendorDir . '/sebastian/global-state/src/RuntimeException.php',
'SebastianBergmann\\GlobalState\\Snapshot' => $vendorDir . '/sebastian/global-state/src/Snapshot.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\\Version' => $vendorDir . '/sebastian/version/src/Version.php',
'Text_Template' => $vendorDir . '/phpunit/php-text-template/src/Template.php',
);
<?php



$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
'Symfony\\Component\\Yaml\\' => array($vendorDir . '/symfony/yaml'),
'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'),
'React\\Promise\\' => array($vendorDir . '/react/promise/src'),
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'),
'PhpAmqpLib\\' => array($vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib'),
'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'),
'GuzzleHttp\\Stream\\' => array($vendorDir . '/guzzlehttp/streams/src'),
'GuzzleHttp\\Ring\\' => array($vendorDir . '/guzzlehttp/ringphp/src'),
'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
'Facebook\\WebDriver\\' => array($vendorDir . '/facebook/webdriver/lib'),
'Facebook\\' => array($vendorDir . '/facebook/php-sdk-v4/src/Facebook'),
'Doctrine\\Instantiator\\' => array($vendorDir . '/doctrine/instantiator/src/Doctrine/Instantiator'),
'DeepCopy\\' => array($vendorDir . '/myclabs/deep-copy/src/DeepCopy'),
'Codeception\\Extension\\' => array($baseDir . '/ext'),
'Codeception\\' => array($baseDir . '/src/Codeception'),
);
<?php



$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'ad155f8f1cf0d418fe49e248db8c661b' => $vendorDir . '/react/promise/src/functions_include.php',
'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php',
);
<?php
namespace Codeception;

use Codeception\Specify\Config;
use Codeception\Specify\ConfigBuilder;

trait Specify {

private $beforeSpecify = array();
private $afterSpecify = array();




private $specifyConfig;




private $copier;

private function specifyInit()
{
if ($this->copier) return;
$this->copier = new \DeepCopy\DeepCopy();
$this->copier->skipUncloneable();
if (!$this->specifyConfig) $this->specifyConfig = Config::create();
}

function specify($specification, \Closure $callable = null, $params = [])
{
if (!$callable) return;
$this->specifyInit();

$test = $callable->bindTo($this);
$name = $this->getName();
$this->setName($this->getName().' | '.$specification);

$properties = get_object_vars($this);


 $throws = $this->getSpecifyExpectedException($params);
$examples = $this->getSpecifyExamples($params);

foreach ($examples as $idx => $example) {
$this->setName($name.' | '.$specification .' | examples index '. $idx);

 $this->specifyCloneProperties($properties);

if (!empty($this->beforeSpecify) && is_array($this->beforeSpecify)) {
foreach ($this->beforeSpecify as $closure) {
if ($closure instanceof \Closure) $closure->__invoke();
}
}
$this->specifyExecute($test, $throws, $example);


 foreach ($properties as $property => $val) {
if ($this->specifyConfig->propertyIgnored($property)) continue;
$this->$property = $val;
}
if (!empty($this->afterSpecify) && is_array($this->afterSpecify)) {
foreach ($this->afterSpecify as $closure) {
if ($closure instanceof \Closure) $closure->__invoke();
}
}
}


 $this->setName($name);
}






private function getSpecifyExamples($params)
{
if (isset($params['examples'])) {
if (!is_array($params['examples'])) throw new \RuntimeException("Examples should be an array");
return $params['examples'];
}
return [[]];
}

private function getSpecifyExpectedException($params)
{
if (isset($params['throws'])) {
$throws = (is_array($params['throws'])) ? $params['throws'][0] : $params['throws'];

if (is_object($throws)) {
$throws = get_class($throws);
}
if ($throws === 'fail') {
$throws = 'PHPUnit_Framework_AssertionFailedError';
}

$message = (is_array($params['throws']) && isset($params['throws'][1])) ? $params['throws'][1] : false;

return [$throws, $message];
}

return false;
}

private function specifyExecute($test, $throws = false, $examples = array())
{
$message = false;

if (is_array($throws)) {
$message = ($throws[1]) ? strtolower($throws[1]) : false;
$throws = $throws[0];
}

$result = $this->getTestResultObject();
try {
call_user_func_array($test, $examples);
} catch (\PHPUnit_Framework_AssertionFailedError $e) {
if ($throws !== get_class($e)){
$result->addFailure(clone($this), $e, $result->time());
}

if ($message !==false && $message !== strtolower($e->getMessage())) {
$f = new \PHPUnit_Framework_AssertionFailedError("exception message '$message' was expected, but '" . $e->getMessage() . "' was received");
$result->addFailure(clone($this), $f, $result->time());
}
} catch (\Exception $e) {
if ($throws) {
if ($throws !== get_class($e)) {
$f = new \PHPUnit_Framework_AssertionFailedError("exception '$throws' was expected, but " . get_class($e) . ' was thrown');
$result->addFailure(clone($this), $f, $result->time());
}

if ($message !==false && $message !== strtolower($e->getMessage())) {
$f = new \PHPUnit_Framework_AssertionFailedError("exception message '$message' was expected, but '" . $e->getMessage() . "' was received");
$result->addFailure(clone($this), $f, $result->time());
}
} else {
throw $e;
}
}

if ($throws) {
if (isset($e)) {
$this->assertTrue(true, 'exception handled');
} else {
$f = new \PHPUnit_Framework_AssertionFailedError("exception '$throws' was not thrown as expected");
$result->addFailure(clone($this), $f, $result->time());
}
}
}

public function specifyConfig()
{
if (!$this->specifyConfig) $this->specifyConfig = Config::create();
return new ConfigBuilder($this->specifyConfig);
}

function beforeSpecify(\Closure $callable = null)
{
$this->beforeSpecify[] = $callable->bindTo($this);
}

function afterSpecify(\Closure $callable = null)
{
$this->afterSpecify[] = $callable->bindTo($this);
}

function cleanSpecify()
{
$this->beforeSpecify = $this->afterSpecify = array();
}





private function specifyCloneProperties($properties)
{
foreach ($properties as $property => $val) {
if ($this->specifyConfig->propertyIgnored($property)) {
continue;
}
if ($this->specifyConfig->classIgnored($val)) {
continue;
}

if ($this->specifyConfig->propertyIsShallowCloned($property)) {
if (is_object($val)) {
$this->$property = clone $val;
} else {
$this->$property = $val;
}
}
if ($this->specifyConfig->propertyIsDeeplyCloned($property)) {
$this->$property = $this->copier->copy($val);
}
}
}
}
<?php
namespace Codeception\Specify;
















class ConfigBuilder
{



protected $config;

public function __construct(Config $config = null)
{
$this->config = $config;
if (!$config) {
$this->config = Config::create();
}
}


















public function ignore($properties = array())
{
if (!is_array($properties)) {
$properties = func_get_args();
}
$this->config->ignore = array_merge($this->config->ignore, $properties);
return $this;
}







public function ignoreClasses($classes = array())
{
$this->config->ignore_classes = array_merge($this->config->ignore_classes, $classes);
return $this;
}




























public function deepClone($properties = true)
{
if (is_bool($properties)) {
$this->config->is_deep = $properties;
return $this;
}
if (!is_array($properties)) {
$properties = func_get_args();
}
$this->config->deep = $properties;
return $this;
}




























public function shallowClone($properties = true)
{
if (is_bool($properties)) {
$this->config->is_deep = !$properties;
return $this;
}
if (!is_array($properties)) {
$properties = func_get_args();
}
$this->config->shallow = array_merge($this->config->shallow, $properties);
return $this;
}













public function cloneOnly($properties)
{
if (!is_array($properties)) {
$properties = func_get_args();
}
$this->config->only = $properties;
return $this;
}
} <?php
namespace Codeception\Specify;











class Config
{
protected static $ignoredClasses = [
'Codeception\Actor',
'Symfony\Component\EventDispatcher\EventDispatcher',
'Codeception\Scenario',
'Codeception\Lib\Parser'
];

protected static $ignoredProperties = [


 'backupGlobals',
'backupGlobalsBlacklist',
'backupStaticAttributes',
'backupStaticAttributesBlacklist',
'runTestInSeparateProcess',
'preserveGlobalState',


 'dependencies',
'dependencyInput',
'tester',
'guy',
'name'
];

protected static $deepClone = true;

public $is_deep = true;
public $ignore = array();
public $ignore_classes = array();
public $shallow = array();
public $deep = array();
public $only = null;

public function propertyIgnored($property)
{
if ($this->only) {
return !in_array($property, $this->only);
}
return in_array($property, $this->ignore);
}

public function classIgnored($value)
{
if (!is_object($value)) return false;
return in_array(get_class($value), $this->ignore_classes);
}

public function propertyIsShallowCloned($property)
{
if ($this->only and !$this->is_deep) {
return in_array($property, $this->only);
}
if (!$this->is_deep and !in_array($property, $this->deep)) {
return true;
}
return in_array($property, $this->shallow);
}

public function propertyIsDeeplyCloned($property)
{
if ($this->only and $this->is_deep) {
return in_array($property, $this->only);
}
if ($this->is_deep and !in_array($property, $this->shallow)) {
return true;
}
return in_array($property, $this->deep);
}







public static function setDeepClone($deepClone)
{
self::$deepClone = $deepClone;
}






public static function setIgnoredClasses($ignoredClasses)
{
self::$ignoredClasses = $ignoredClasses;
}











public static function setIgnoredProperties($ignoredProperties)
{
self::$ignoredProperties = $ignoredProperties;
}












public static function addIgnoredClasses($ignoredClasses)
{
self::$ignoredClasses = array_merge(self::$ignoredClasses, $ignoredClasses);
}

private function __construct()
{
}




static function create()
{
$config = new Config();
$config->is_deep = self::$deepClone;
$config->ignore = self::$ignoredProperties;
$config->ignore_classes = self::$ignoredClasses;
$config->shallow = array();
$config->deep = array();
$config->only = null;
return $config;
}
}<?php
require_once __DIR__.'/vendor/autoload.php';

class Robofile extends \Robo\Tasks
{
public function release()
{
$this->test();

$version = file_get_contents('VERSION');

$this->docs();


 $this->taskGitHubRelease($version)
->uri('Codeception/Specify')
->askDescription()
->run();
}

public function changed($description)
{
$this->taskChangelog()
->version(file_get_contents('VERSION'))
->change($description)
->run();
}

protected $docs = [
'docs/GlobalConfig.md' => '\Codeception\Specify\Config',
'docs/LocalConfig.md' => '\Codeception\Specify\ConfigBuilder',
];

public function docs()
{
foreach ($this->docs as $file => $class) {
class_exists($class, true);
$this->taskGenDoc($file)
->docClass($class)
->processProperty(false)
->run();
}
}


public function test()
{
$res = $this->taskPHPUnit()->run();
if (!$res) exit;
}
}
<?php











namespace phpDocumentor\Reflection\DocBlock;

use phpDocumentor\Reflection\DocBlock;








class Description implements \Reflector
{

protected $contents = '';


protected $parsedContents = null;


protected $docblock = null;







public function __construct($content, DocBlock $docblock = null)
{
$this->setContent($content)->setDocBlock($docblock);
}






public function getContents()
{
return $this->contents;
}








public function setContent($content)
{
$this->contents = trim($content);

$this->parsedContents = null;
return $this;
}







public function getParsedContents()
{
if (null === $this->parsedContents) {
$this->parsedContents = preg_split(
'/\{
                    # "{@}" 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',
$this->contents,
null,
PREG_SPLIT_DELIM_CAPTURE
);

$count = count($this->parsedContents);
for ($i=1; $i<$count; $i += 2) {
$this->parsedContents[$i] = Tag::createInstance(
$this->parsedContents[$i],
$this->docblock
);
}


 
 
 for ($i=0; $i<$count; $i += 2) {
$this->parsedContents[$i] = str_replace(
array('{@}', '{}'),
array('@', '}'),
$this->parsedContents[$i]
);
}
}
return $this->parsedContents;
}












public function getFormattedContents()
{
$result = $this->contents;


 
 
 if (strpos($result, '<code>') !== false) {
$result = str_replace(
array('<code>', "<code>\r\n", "<code>\n", "<code>\r", '</code>'),
array('<pre><code>', '<code>', '<code>', '<code>', '</code></pre>'),
$result
);
}

if (class_exists('Parsedown')) {
$markdown = \Parsedown::instance();
$result = $markdown->parse($result);
} elseif (class_exists('dflydev\markdown\MarkdownExtraParser')) {
$markdown = new \dflydev\markdown\MarkdownExtraParser();
$result = $markdown->transformMarkdown($result);
}

return trim($result);
}






public function getDocBlock()
{
return $this->docblock;
}









public function setDocBlock(DocBlock $docblock = null)
{
$this->docblock = $docblock;

return $this;
}










public static function export()
{
throw new \Exception('Not yet implemented');
}






public function __toString()
{
return $this->getContents();
}
}
<?php











namespace phpDocumentor\Reflection\DocBlock;








class Context
{

protected $namespace = '';


protected $namespace_aliases = array();


protected $lsen = '';










public function __construct(
$namespace = '',
array $namespace_aliases = array(),
$lsen = ''
) {
if (!empty($namespace)) {
$this->setNamespace($namespace);
}
$this->setNamespaceAliases($namespace_aliases);
$this->setLSEN($lsen);
}




public function getNamespace()
{
return $this->namespace;
}




public function getNamespaceAliases()
{
return $this->namespace_aliases;
}






public function getLSEN()
{
return $this->lsen;
}












public function setNamespace($namespace)
{
if ('global' !== $namespace
&& 'default' !== $namespace
) {

 $this->namespace = trim((string)$namespace, '\\');
} else {
$this->namespace = '';
}
return $this;
}









public function setNamespaceAliases(array $namespace_aliases)
{
$this->namespace_aliases = array();
foreach ($namespace_aliases as $alias => $fqnn) {
$this->setNamespaceAlias($alias, $fqnn);
}
return $this;
}












public function setNamespaceAlias($alias, $fqnn)
{
$this->namespace_aliases[$alias] = '\\' . trim((string)$fqnn, '\\');
return $this;
}












public function setLSEN($lsen)
{
$this->lsen = (string)$lsen;
return $this;
}
}
<?php











namespace phpDocumentor\Reflection\DocBlock\Tag;

use phpDocumentor\Reflection\DocBlock\Tag;








class SourceTag extends Tag
{




protected $startingLine = 1;





protected $lineCount = null;




public function getContent()
{
if (null === $this->content) {
$this->content
= "{$this->startingLine} {$this->lineCount} {$this->description}";
}

return $this->content;
}




public function setContent($content)
{
parent::setContent($content);
if (preg_match(
'/^
                # Starting line
                ([1-9]\d*)
                \s*
                # Number of lines
                (?:
                    ((?1))
                    \s+
                )?
                # Description
                (.*)
            $/sux',
$this->description,
$matches
)) {
$this->startingLine = (int)$matches[1];
if (isset($matches[2]) && '' !== $matches[2]) {
$this->lineCount = (int)$matches[2];
}
$this->setDescription($matches[3]);
$this->content = $content;
}

return $this;
}







public function getStartingLine()
{
return $this->startingLine;
}









public function setStartingLine($startingLine)
{
$this->startingLine = $startingLine;

$this->content = null;
return $this;
}







public function getLineCount()
{
return $this->lineCount;
}









public function setLineCount($lineCount)
{
$this->lineCount = $lineCount;

$this->content = null;
return $this;
}
}
<?php











namespace phpDocumentor\Reflection\DocBlock\Tag;








class ThrowsTag extends ReturnTag
{
}
<?php











namespace phpDocumentor\Reflection\DocBlock\Tag;








class CoversTag extends SeeTag
{
}
<?php











namespace phpDocumentor\Reflection\DocBlock\Tag;

use phpDocumentor\Reflection\DocBlock\Tag;








class LinkTag extends Tag
{

protected $link = '';




public function getContent()
{
if (null === $this->content) {
$this->content = "{$this->link} {$this->description}";
}

return $this->content;
}




public function setContent($content)
{
parent::setContent($content);
$parts = preg_split('/\s+/Su', $this->description, 2);

$this->link = $parts[0];

$this->setDescription(isset($parts[1]) ? $parts[1] : $parts[0]);

$this->content = $content;
return $this;
}






public function getLink()
{
return $this->link;
}








public function setLink($link)
{
$this->link = $link;

$this->content = null;
return $this;
}
}
<?php











namespace phpDocumentor\Reflection\DocBlock\Tag;

use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Type\Collection;








class ReturnTag extends Tag
{

protected $type = '';


protected $types = null;




public function getContent()
{
if (null === $this->content) {
$this->content = "{$this->type} {$this->description}";
}

return $this->content;
}




public function setContent($content)
{
parent::setContent($content);

$parts = preg_split('/\s+/Su', $this->description, 2);


 $this->type = $parts[0];
$this->types = null;

$this->setDescription(isset($parts[1]) ? $parts[1] : '');

$this->content = $content;
return $this;
}






public function getTypes()
{
return $this->getTypesCollection()->getArrayCopy();
}






public function getType()
{
return (string) $this->getTypesCollection();
}






protected function getTypesCollection()
{
if (null === $this->types) {
$this->types = new Collection(
array($this->type),
$this->docblock ? $this->docblock->getContext() : null
);
}
return $this->types;
}
}
<?php











namespace phpDocumentor\Reflection\DocBlock\Tag;

use phpDocumentor\Reflection\DocBlock\Tag;








class ParamTag extends ReturnTag
{

protected $variableName = '';


protected $isVariadic = false;




public function getContent()
{
if (null === $this->content) {
$this->content
= "{$this->type} {$this->variableName} {$this->description}";
}
return $this->content;
}



public function setContent($content)
{
Tag::setContent($content);
$parts = preg_split(
'/(\s+)/Su',
$this->description,
3,
PREG_SPLIT_DELIM_CAPTURE
);


 if (isset($parts[0])
&& (strlen($parts[0]) > 0)
&& ($parts[0][0] !== '$')
) {
$this->type = array_shift($parts);
array_shift($parts);
}


 if (isset($parts[0])
&& (strlen($parts[0]) > 0)
&& ($parts[0][0] == '$' || substr($parts[0], 0, 4) === '...$')
) {
$this->variableName = array_shift($parts);
array_shift($parts);

if (substr($this->variableName, 0, 3) === '...') {
$this->isVariadic = true;
$this->variableName = substr($this->variableName, 3);
}
}

$this->setDescription(implode('', $parts));

$this->content = $content;
return $this;
}






public function getVariableName()
{
return $this->variableName;
}








public function setVariableName($name)
{
$this->variableName = $name;

$this->content = null;
return $this;
}






public function isVariadic()
{
return $this->isVariadic;
}
}
<?php











namespace phpDocumentor\Reflection\DocBlock\Tag;

use phpDocumentor\Reflection\DocBlock\Tag;








class SeeTag extends Tag
{

protected $refers = null;




public function getContent()
{
if (null === $this->content) {
$this->content = "{$this->refers} {$this->description}";
}
return $this->content;
}




public function setContent($content)
{
parent::setContent($content);
$parts = preg_split('/\s+/Su', $this->description, 2);


 $this->refers = $parts[0];

$this->setDescription(isset($parts[1]) ? $parts[1] : '');

$this->content = $content;
return $this;
}






public function getReference()
{
return $this->refers;
}








public function setReference($refers)
{
$this->refers = $refers;

$this->content = null;
return $this;
}
}
<?php











namespace phpDocumentor\Reflection\DocBlock\Tag;








class VarTag extends ParamTag
{
}
<?php











namespace phpDocumentor\Reflection\DocBlock\Tag;

use phpDocumentor\Reflection\DocBlock\Tag\VersionTag;








class SinceTag extends VersionTag
{
}
<?php











namespace phpDocumentor\Reflection\DocBlock\Tag;








class UsesTag extends SeeTag
{
}
<?php











namespace phpDocumentor\Reflection\DocBlock\Tag;








class PropertyReadTag extends PropertyTag
{
}
<?php











namespace phpDocumentor\Reflection\DocBlock\Tag;

use phpDocumentor\Reflection\DocBlock\Tag;








class AuthorTag extends Tag
{



const REGEX_AUTHOR_NAME = '[^\<]*';




const REGEX_AUTHOR_EMAIL = '[^\>]*';


protected $authorName = '';


protected $authorEmail = '';

public function getContent()
{
if (null === $this->content) {
$this->content = $this->authorName;
if ('' != $this->authorEmail) {
$this->content .= "<{$this->authorEmail}>";
}
}

return $this->content;
}




public function setContent($content)
{
parent::setContent($content);
if (preg_match(
'/^(' . self::REGEX_AUTHOR_NAME .
')(\<(' . self::REGEX_AUTHOR_EMAIL .
')\>)?$/u',
$this->description,
$matches
)) {
$this->authorName = trim($matches[1]);
if (isset($matches[3])) {
$this->authorEmail = trim($matches[3]);
}
}

return $this;
}






public function getAuthorName()
{
return $this->authorName;
}









public function setAuthorName($authorName)
{
$this->content = null;
$this->authorName
= preg_match('/^' . self::REGEX_AUTHOR_NAME . '$/u', $authorName)
? $authorName : '';

return $this;
}






public function getAuthorEmail()
{
return $this->authorEmail;
}









public function setAuthorEmail($authorEmail)
{
$this->authorEmail
= preg_match('/^' . self::REGEX_AUTHOR_EMAIL . '$/u', $authorEmail)
? $authorEmail : '';

$this->content = null;
return $this;
}
}
<?php











namespace phpDocumentor\Reflection\DocBlock\Tag;








class PropertyTag extends ParamTag
{
}
<?php











namespace phpDocumentor\Reflection\DocBlock\Tag;

use phpDocumentor\Reflection\DocBlock\Tag;








class ExampleTag extends SourceTag
{




protected $filePath = '';





protected $isURI = false;




public function getContent()
{
if (null === $this->content) {
$filePath = '';
if ($this->isURI) {
if (false === strpos($this->filePath, ':')) {
$filePath = str_replace(
'%2F',
'/',
rawurlencode($this->filePath)
);
} else {
$filePath = $this->filePath;
}
} else {
$filePath = '"' . $this->filePath . '"';
}

$this->content = $filePath . ' ' . parent::getContent();
}

return $this->content;
}



public function setContent($content)
{
Tag::setContent($content);
if (preg_match(
'/^
                # File component
                (?:
                    # File path in quotes
                    \"([^\"]+)\"
                    |
                    # File URI
                    (\S+)
                )
                # Remaining content (parsed by SourceTag)
                (?:\s+(.*))?
            $/sux',
$this->description,
$matches
)) {
if ('' !== $matches[1]) {
$this->setFilePath($matches[1]);
} else {
$this->setFileURI($matches[2]);
}

if (isset($matches[3])) {
parent::setContent($matches[3]);
} else {
$this->setDescription('');
}
$this->content = $content;
}

return $this;
}







public function getFilePath()
{
return $this->filePath;
}








public function setFilePath($filePath)
{
$this->isURI = false;
$this->filePath = trim($filePath);

$this->content = null;
return $this;
}











public function setFileURI($uri)
{
$this->isURI = true;
if (false === strpos($uri, ':')) {

 $this->filePath = rawurldecode(
str_replace(array('/', '\\'), '%2F', $uri)
);
} else {

 $this->filePath = $uri;
}

$this->content = null;
return $this;
}
}
<?php











namespace phpDocumentor\Reflection\DocBlock\Tag;

use phpDocumentor\Reflection\DocBlock\Tag;








class MethodTag extends ReturnTag
{


protected $method_name = '';


protected $arguments = '';


protected $isStatic = false;




public function getContent()
{
if (null === $this->content) {
$this->content = '';
if ($this->isStatic) {
$this->content .= 'static ';
}
$this->content .= $this->type .
" {$this->method_name}({$this->arguments}) " .
$this->description;
}

return $this->content;
}




public function setContent($content)
{
Tag::setContent($content);

 
 
 
 
 
 
 
 
 if (preg_match(
'/^
                # Static keyword
                # Declates a static method ONLY if type is also present
                (?:
                    (static)
                    \s+
                )?
                # Return type
                (?:
                    ([\w\|_\\\\]+)
                    \s+
                )?
                # Legacy method name (not captured)
                (?:
                    [\w_]+\(\)\s+
                )?
                # Method name
                ([\w\|_\\\\]+)
                # Arguments
                \(([^\)]*)\)
                \s*
                # Description
                (.*)
            $/sux',
$this->description,
$matches
)) {
list(
,
$static,
$this->type,
$this->method_name,
$this->arguments,
$this->description
) = $matches;
if ($static) {
if (!$this->type) {
$this->type = 'static';
} else {
$this->isStatic = true;
}
} else {
if (!$this->type) {
$this->type = 'void';
}
}
$this->parsedDescription = null;
}

return $this;
}








public function setMethodName($method_name)
{
$this->method_name = $method_name;

$this->content = null;
return $this;
}






public function getMethodName()
{
return $this->method_name;
}








public function setArguments($arguments)
{
$this->arguments = $arguments;

$this->content = null;
return $this;
}









public function getArguments()
{
if (empty($this->arguments)) {
return array();
}

$arguments = explode(',', $this->arguments);
foreach ($arguments as $key => $value) {
$arguments[$key] = explode(' ', trim($value));
}

return $arguments;
}







public function isStatic()
{
return $this->isStatic;
}








public function setIsStatic($isStatic)
{
$this->isStatic = $isStatic;

$this->content = null;
return $this;
}
}
<?php











namespace phpDocumentor\Reflection\DocBlock\Tag;

use phpDocumentor\Reflection\DocBlock\Tag;








class VersionTag extends Tag
{




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*\$[^\$]+\$
    )';


protected $version = '';

public function getContent()
{
if (null === $this->content) {
$this->content = "{$this->version} {$this->description}";
}

return $this->content;
}




public function setContent($content)
{
parent::setContent($content);

if (preg_match(
'/^
                # The version vector
                (' . self::REGEX_VECTOR . ')
                \s*
                # The description
                (.+)?
            $/sux',
$this->description,
$matches
)) {
$this->version = $matches[1];
$this->setDescription(isset($matches[2]) ? $matches[2] : '');
$this->content = $content;
}

return $this;
}






public function getVersion()
{
return $this->version;
}









public function setVersion($version)
{
$this->version
= preg_match('/^' . self::REGEX_VECTOR . '$/ux', $version)
? $version
: '';

$this->content = null;
return $this;
}
}
<?php











namespace phpDocumentor\Reflection\DocBlock\Tag;

use phpDocumentor\Reflection\DocBlock\Tag\VersionTag;








class DeprecatedTag extends VersionTag
{
}
<?php











namespace phpDocumentor\Reflection\DocBlock\Tag;








class PropertyWriteTag extends PropertyTag
{
}
<?php











namespace phpDocumentor\Reflection\DocBlock;

use phpDocumentor\Reflection\DocBlock;








class Tag implements \Reflector
{



const REGEX_TAGNAME = '[\w\-\_\\\\]+';


protected $tag = '';





protected $content = '';


protected $description = '';





protected $parsedDescription = null;


protected $location = null;


protected $docblock = null;






private static $tagHandlerMappings = array(
'author'
=> '\phpDocumentor\Reflection\DocBlock\Tag\AuthorTag',
'covers'
=> '\phpDocumentor\Reflection\DocBlock\Tag\CoversTag',
'deprecated'
=> '\phpDocumentor\Reflection\DocBlock\Tag\DeprecatedTag',
'example'
=> '\phpDocumentor\Reflection\DocBlock\Tag\ExampleTag',
'link'
=> '\phpDocumentor\Reflection\DocBlock\Tag\LinkTag',
'method'
=> '\phpDocumentor\Reflection\DocBlock\Tag\MethodTag',
'param'
=> '\phpDocumentor\Reflection\DocBlock\Tag\ParamTag',
'property-read'
=> '\phpDocumentor\Reflection\DocBlock\Tag\PropertyReadTag',
'property'
=> '\phpDocumentor\Reflection\DocBlock\Tag\PropertyTag',
'property-write'
=> '\phpDocumentor\Reflection\DocBlock\Tag\PropertyWriteTag',
'return'
=> '\phpDocumentor\Reflection\DocBlock\Tag\ReturnTag',
'see'
=> '\phpDocumentor\Reflection\DocBlock\Tag\SeeTag',
'since'
=> '\phpDocumentor\Reflection\DocBlock\Tag\SinceTag',
'source'
=> '\phpDocumentor\Reflection\DocBlock\Tag\SourceTag',
'throw'
=> '\phpDocumentor\Reflection\DocBlock\Tag\ThrowsTag',
'throws'
=> '\phpDocumentor\Reflection\DocBlock\Tag\ThrowsTag',
'uses'
=> '\phpDocumentor\Reflection\DocBlock\Tag\UsesTag',
'var'
=> '\phpDocumentor\Reflection\DocBlock\Tag\VarTag',
'version'
=> '\phpDocumentor\Reflection\DocBlock\Tag\VersionTag'
);












final public static function createInstance(
$tag_line,
DocBlock $docblock = null,
Location $location = null
) {
if (!preg_match(
'/^@(' . self::REGEX_TAGNAME . ')(?:\s*([^\s].*)|$)?/us',
$tag_line,
$matches
)) {
throw new \InvalidArgumentException(
'Invalid tag_line detected: ' . $tag_line
);
}

$handler = __CLASS__;
if (isset(self::$tagHandlerMappings[$matches[1]])) {
$handler = self::$tagHandlerMappings[$matches[1]];
} elseif (isset($docblock)) {
$tagName = (string)new Type\Collection(
array($matches[1]),
$docblock->getContext()
);

if (isset(self::$tagHandlerMappings[$tagName])) {
$handler = self::$tagHandlerMappings[$tagName];
}
}

return new $handler(
$matches[1],
isset($matches[2]) ? $matches[2] : '',
$docblock,
$location
);
}















final public static function registerTagHandler($tag, $handler)
{
$tag = trim((string)$tag);

if (null === $handler) {
unset(self::$tagHandlerMappings[$tag]);
return true;
}

if ('' !== $tag
&& class_exists($handler, true)
&& is_subclass_of($handler, __CLASS__)
&& !strpos($tag, '\\') 
 ) {
self::$tagHandlerMappings[$tag] = $handler;
return true;
}

return false;
}









public function __construct(
$name,
$content,
DocBlock $docblock = null,
Location $location = null
) {
$this
->setName($name)
->setContent($content)
->setDocBlock($docblock)
->setLocation($location);
}






public function getName()
{
return $this->tag;
}









public function setName($name)
{
if (!preg_match('/^' . self::REGEX_TAGNAME . '$/u', $name)) {
throw new \InvalidArgumentException(
'Invalid tag name supplied: ' . $name
);
}

$this->tag = $name;

return $this;
}






public function getContent()
{
if (null === $this->content) {
$this->content = $this->description;
}

return $this->content;
}








public function setContent($content)
{
$this->setDescription($content);
$this->content = $content;

return $this;
}






public function getDescription()
{
return $this->description;
}








public function setDescription($description)
{
$this->content = null;
$this->parsedDescription = null;
$this->description = trim($description);

return $this;
}







public function getParsedDescription()
{
if (null === $this->parsedDescription) {
$description = new Description($this->description, $this->docblock);
$this->parsedDescription = $description->getParsedContents();
}
return $this->parsedDescription;
}






public function getDocBlock()
{
return $this->docblock;
}









public function setDocBlock(DocBlock $docblock = null)
{
$this->docblock = $docblock;

return $this;
}






public function getLocation()
{
return $this->location;
}








public function setLocation(Location $location = null)
{
$this->location = $location;

return $this;
}









public static function export()
{
throw new \Exception('Not yet implemented');
}






public function __toString()
{
return "@{$this->getName()} {$this->getContent()}";
}
}
<?php











namespace phpDocumentor\Reflection\DocBlock\Type;

use phpDocumentor\Reflection\DocBlock\Context;









class Collection extends \ArrayObject
{

const OPERATOR_OR = '|';


const OPERATOR_ARRAY = '[]';


const OPERATOR_NAMESPACE = '\\';


protected static $keywords = array(
'string', 'int', 'integer', 'bool', 'boolean', 'float', 'double',
'object', 'mixed', 'array', 'resource', 'void', 'null', 'scalar',
'callback', 'callable', 'false', 'true', 'self', '$this', 'static'
);









protected $context = null;









public function __construct(
array $types = array(),
Context $context = null
) {
$this->context = null === $context ? new Context() : $context;

foreach ($types as $type) {
$this->add($type);
}
}






public function getContext()
{
return $this->context;
}


















public function add($type)
{
if (!is_string($type)) {
throw new \InvalidArgumentException(
'A type should be represented by a string, received: '
.var_export($type, true)
);
}


 $type_parts = explode(self::OPERATOR_OR, $type);
foreach ($type_parts as $part) {
$expanded_type = $this->expand($part);
if ($expanded_type) {
$this[] = $expanded_type;
}
}
}







public function __toString()
{
return implode(self::OPERATOR_OR, $this->getArrayCopy());
}



















protected function expand($type)
{
$type = trim($type);
if (!$type) {
return '';
}

if ($this->isTypeAnArray($type)) {
return $this->expand(substr($type, 0, -2)) . self::OPERATOR_ARRAY;
}

if ($this->isRelativeType($type) && !$this->isTypeAKeyword($type)) {
$type_parts = explode(self::OPERATOR_NAMESPACE, $type, 2);

$namespace_aliases = $this->context->getNamespaceAliases();

 
 if (!isset($namespace_aliases[$type_parts[0]])) {
$namespace = $this->context->getNamespace();
if ('' !== $namespace) {
$namespace .= self::OPERATOR_NAMESPACE;
}
return self::OPERATOR_NAMESPACE . $namespace . $type;
}

$type_parts[0] = $namespace_aliases[$type_parts[0]];
$type = implode(self::OPERATOR_NAMESPACE, $type_parts);
}

return $type;
}









protected function isTypeAnArray($type)
{
return substr($type, -2) === self::OPERATOR_ARRAY;
}









protected function isTypeAKeyword($type)
{
return in_array(strtolower($type), static::$keywords, true);
}












protected function isRelativeType($type)
{
return ($type[0] !== self::OPERATOR_NAMESPACE)
|| $this->isTypeAKeyword($type);
}
}
<?php











namespace phpDocumentor\Reflection\DocBlock;

use phpDocumentor\Reflection\DocBlock;








class Serializer
{


protected $indentString = ' ';


protected $indent = 0;


protected $isFirstLineIndented = true;


protected $lineLength = null;











public function __construct(
$indent = 0,
$indentString = ' ',
$indentFirstLine = true,
$lineLength = null
) {
$this->setIndentationString($indentString);
$this->setIndent($indent);
$this->setIsFirstLineIndented($indentFirstLine);
$this->setLineLength($lineLength);
}








public function setIndentationString($indentString)
{
$this->indentString = (string)$indentString;
return $this;
}






public function getIndentationString()
{
return $this->indentString;
}








public function setIndent($indent)
{
$this->indent = (int)$indent;
return $this;
}






public function getIndent()
{
return $this->indent;
}











public function setIsFirstLineIndented($indentFirstLine)
{
$this->isFirstLineIndented = (bool)$indentFirstLine;
return $this;
}






public function isFirstLineIndented()
{
return $this->isFirstLineIndented;
}












public function setLineLength($lineLength)
{
$this->lineLength = null === $lineLength ? null : (int)$lineLength;
return $this;
}







public function getLineLength()
{
return $this->lineLength;
}








public function getDocComment(DocBlock $docblock)
{
$indent = str_repeat($this->indentString, $this->indent);
$firstIndent = $this->isFirstLineIndented ? $indent : '';

$text = $docblock->getText();
if ($this->lineLength) {

 $wrapLength = $this->lineLength - strlen($indent) - 3;
$text = wordwrap($text, $wrapLength);
}
$text = str_replace("\n", "\n{$indent} * ", $text);

$comment = "{$firstIndent}/**\n{$indent} * {$text}\n{$indent} *\n";


foreach ($docblock->getTags() as $tag) {
$tagText = (string) $tag;
if ($this->lineLength) {
$tagText = wordwrap($tagText, $wrapLength);
}
$tagText = str_replace("\n", "\n{$indent} * ", $tagText);

$comment .= "{$indent} * {$tagText}\n";
}

$comment .= $indent . ' */';

return $comment;
}
}
<?php











namespace phpDocumentor\Reflection\DocBlock;








class Location
{

protected $lineNumber = 0;


protected $columnNumber = 0;

public function __construct(
$lineNumber = 0,
$columnNumber = 0
) {
$this->setLineNumber($lineNumber)->setColumnNumber($columnNumber);
}




public function getLineNumber()
{
return $this->lineNumber;
}






public function setLineNumber($lineNumber)
{
$this->lineNumber = (int)$lineNumber;

return $this;
}




public function getColumnNumber()
{
return $this->columnNumber;
}






public function setColumnNumber($columnNumber)
{
$this->columnNumber = (int)$columnNumber;

return $this;
}
}
<?php











namespace phpDocumentor\Reflection;

use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Context;
use phpDocumentor\Reflection\DocBlock\Location;








class DocBlock implements \Reflector
{

protected $short_description = '';





protected $long_description = null;





protected $tags = array();


protected $context = null;


protected $location = null;


protected $isTemplateStart = false;


protected $isTemplateEnd = false;


















public function __construct(
$docblock,
Context $context = null,
Location $location = null
) {
if (is_object($docblock)) {
if (!method_exists($docblock, 'getDocComment')) {
throw new \InvalidArgumentException(
'Invalid object passed; the given reflector must support '
. 'the getDocComment method'
);
}

$docblock = $docblock->getDocComment();
}

$docblock = $this->cleanInput($docblock);

list($templateMarker, $short, $long, $tags) = $this->splitDocBlock($docblock);
$this->isTemplateStart = $templateMarker === '#@+';
$this->isTemplateEnd = $templateMarker === '#@-';
$this->short_description = $short;
$this->long_description = new DocBlock\Description($long, $this);
$this->parseTags($tags);

$this->context = $context;
$this->location = $location;
}








protected function cleanInput($comment)
{
$comment = trim(
preg_replace(
'#[ \t]*(?:\/\*\*|\*\/|\*)?[ \t]{0,1}(.*)?#u',
'$1',
$comment
)
);


 if (substr($comment, -2) == '*/') {
$comment = trim(substr($comment, 0, -2));
}


 $comment = str_replace(array("\r\n", "\r"), "\n", $comment);

return $comment;
}











protected function splitDocBlock($comment)
{

 
 
 if (strpos($comment, '@') === 0) {
return array('', '', '', $comment);
}


 $comment = preg_replace('/\h*$/Sum', '', $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;
}








protected function parseTags($tags)
{
$result = array();
$tags = trim($tags);
if ('' !== $tags) {
if ('@' !== $tags[0]) {
throw new \LogicException(
'A tag block started with text instead of an actual tag,'
. ' this makes the tag block invalid: ' . $tags
);
}
foreach (explode("\n", $tags) as $tag_line) {
if (isset($tag_line[0]) && ($tag_line[0] === '@')) {
$result[] = $tag_line;
} else {
$result[count($result) - 1] .= "\n" . $tag_line;
}
}


 foreach ($result as $key => $tag_line) {
$result[$key] = Tag::createInstance(trim($tag_line), $this);
}
}

$this->tags = $result;
}









public function getText()
{
$short = $this->getShortDescription();
$long = $this->getLongDescription()->getContents();

if ($long) {
return "{$short}\n\n{$long}";
} else {
return $short;
}
}











public function setText($comment)
{
list(,$short, $long) = $this->splitDocBlock($comment);
$this->short_description = $short;
$this->long_description = new DocBlock\Description($long, $this);
return $this;
}





public function getShortDescription()
{
return $this->short_description;
}






public function getLongDescription()
{
return $this->long_description;
}






















public function isTemplateStart()
{
return $this->isTemplateStart;
}








public function isTemplateEnd()
{
return $this->isTemplateEnd;
}






public function getContext()
{
return $this->context;
}






public function getLocation()
{
return $this->location;
}






public function getTags()
{
return $this->tags;
}









public function getTagsByName($name)
{
$result = array();


foreach ($this->getTags() as $tag) {
if ($tag->getName() != $name) {
continue;
}

$result[] = $tag;
}

return $result;
}








public function hasTag($name)
{

foreach ($this->getTags() as $tag) {
if ($tag->getName() == $name) {
return true;
}
}

return false;
}










public function appendTag(Tag $tag)
{
if (null === $tag->getDocBlock()) {
$tag->setDocBlock($this);
}

if ($tag->getDocBlock() === $this) {
$this->tags[] = $tag;
} else {
throw new \LogicException(
'This tag belongs to a different DocBlock object.'
);
}

return $tag;
}











public static function export()
{
throw new \Exception('Not yet implemented');
}








public function __toString()
{
return 'Not yet implemented';
}
}
<?php
namespace Flow\JSONPath;

class AccessHelper
{
public static function collectionKeys($collection)
{
if (is_object($collection)) {
return array_keys(get_object_vars($collection));
} else {
return array_keys($collection);
}
}

public static function isCollectionType($collection)
{
return is_array($collection) || is_object($collection);
}

public static function keyExists($collection, $key, $magicIsAllowed = false)
{
if ($magicIsAllowed && is_object($collection) && method_exists($collection, '__get')) {
return true;
}

if (is_array($collection) || $collection instanceof \ArrayAccess) {
return array_key_exists($key, $collection);
} else if (is_object($collection)) {
return property_exists($collection, $key);
}
}

public static function getValue($collection, $key, $magicIsAllowed = false)
{
if ($magicIsAllowed && is_object($collection) && method_exists($collection, '__get')) {
return $collection->__get($key);
}

if (is_object($collection) && ! $collection instanceof \ArrayAccess) {
return $collection->$key;
} else {
return $collection[$key];
}
}

public static function setValue(&$collection, $key, $value)
{
if (is_object($collection) && ! $collection instanceof \ArrayAccess) {
return $collection->$key = $value;
} else {
return $collection[$key] = $value;
}
}

public static function unsetValue(&$collection, $key)
{
if (is_object($collection) && ! $collection instanceof \ArrayAccess) {
unset($collection->$key);
} else {
unset($collection[$key]);
}
}

public static function arrayValues($collection)
{
if (is_array($collection)) {
return array_values($collection);
} else if (is_object($collection)) {
return array_values((array) $collection);
}

throw new JSONPathException("Invalid variable type for arrayValues");
}

}
<?php

namespace Flow\JSONPath;

class JSONPathLexer
{





const MATCH_INDEX = '\w+ | \*'; 
 const MATCH_INDEXES = '\s* \d+ [\d,\s]+'; 
 const MATCH_SLICE = '[-\d:]+ | :'; 
 const MATCH_QUERY_RESULT = '\s* \( .+? \) \s*'; 
 const MATCH_QUERY_MATCH = '\s* \?\(.+?\) \s*'; 
 const MATCH_INDEX_IN_SINGLE_QUOTES = '\s* \' (.+?) \' \s*'; 
 const MATCH_INDEX_IN_DOUBLE_QUOTES = '\s* " (.+?) " \s*'; 






protected $expression = '';






protected $expressionLength = 0;

public function __construct($expression)
{
$expression = trim($expression);

if (!strlen($expression)) {
return;
}

if ($expression[0] === '$') {
$expression = substr($expression, 1);
}

if ($expression[0] !== '.' && $expression[0] !== '[') {
$expression = '.' . $expression;
}

$this->expression = $expression;
$this->expressionLength = strlen($expression);
}

public function parseExpressionTokens()
{
$dotIndexDepth = 0;
$squareBracketDepth = 0;
$capturing = false;
$tokenValue = '';
$tokens = [];

for ($i = 0; $i < $this->expressionLength; $i++) {
$char = $this->expression[$i];

if ($squareBracketDepth === 0) {
if ($char === '.') {

if ($this->lookAhead($i, 1) === ".") {
$tokens[] = new JSONPathToken(JSONPathToken::T_RECURSIVE, null);
}

continue;
}
}

if ($char === '[') {
$squareBracketDepth += 1;

if ($squareBracketDepth === 1) {
continue;
}
}

if ($char === ']') {
$squareBracketDepth -= 1;

if ($squareBracketDepth === 0) {
continue;
}
}




if ($squareBracketDepth > 0) {
$tokenValue .= $char;
if ($this->lookAhead($i, 1) === ']' && $squareBracketDepth === 1) {
$tokens[] = $this->createToken($tokenValue);
$tokenValue = '';
}
}




if ($squareBracketDepth === 0) {
$tokenValue .= $char;


 if ($char === "." && $dotIndexDepth > 1) {
$tokens[] = $this->createToken($tokenValue);
$tokenValue = '';
continue;
}

if ($this->lookAhead($i, 1) === '.' || $this->lookAhead($i, 1) === '[' || $this->atEnd($i)) {
$tokens[] = $this->createToken($tokenValue);
$tokenValue = '';
$dotIndexDepth -= 1;
}
}

}

if ($tokenValue !== '') {
$tokens[] = $this->createToken($tokenValue);
$tokenValue = '';
}

return $tokens;
}

protected function lookAhead($pos, $forward = 1)
{
return isset($this->expression[$pos + $forward]) ? $this->expression[$pos + $forward] : null;
}

protected function atEnd($pos)
{
return $pos === $this->expressionLength;
}



public function parseExpression()
{
$tokens = $this->parseExpressionTokens();

return $tokens;
}





protected function createToken($value)
{
if (preg_match('/^(' . static::MATCH_INDEX . ')$/x', $value, $matches)) {
return new JSONPathToken(JSONPathToken::T_INDEX, $value);
}

if (preg_match('/^' . static::MATCH_INDEXES . '$/x', $value, $matches)) {
$value = explode(',', $value);

foreach ($value as $i => $v) {
$value[$i] = (int) trim($v);
}

return new JSONPathToken(JSONPathToken::T_INDEXES, $value);
}

if (preg_match('/^' . static::MATCH_SLICE . '$/x', $value, $matches)) {
$parts = explode(':', $value);

$value = [
'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,
];

return new JSONPathToken(JSONPathToken::T_SLICE, $value);
}

if (preg_match('/^' . static::MATCH_QUERY_RESULT . '$/x', $value)) {
$value = substr($value, 1, -1);

return new JSONPathToken(JSONPathToken::T_QUERY_RESULT, $value);
}

if (preg_match('/^' . static::MATCH_QUERY_MATCH . '$/x', $value)) {
$value = substr($value, 2, -1);

return new JSONPathToken(JSONPathToken::T_QUERY_MATCH, $value);
}

if (preg_match('/^' . static::MATCH_INDEX_IN_SINGLE_QUOTES . '$/x', $value, $matches)) {
$value = $matches[1];
$value = trim($value);

return new JSONPathToken(JSONPathToken::T_INDEX, $value);
}

if (preg_match('/^' . static::MATCH_INDEX_IN_DOUBLE_QUOTES . '$/x', $value, $matches)) {
$value = $matches[1];
$value = trim($value);

return new JSONPathToken(JSONPathToken::T_INDEX, $value);
}

throw new JSONPathException("Unable to parse token {$value} in expression: $this->expression");
}

}
<?php
namespace Flow\JSONPath;

use Exception;

class JSONPathException extends Exception
{

}
<?php
namespace Flow\JSONPath;

use ArrayAccess;
use Iterator;
use JsonSerializable;
use Flow\JsonPath\Filters\AbstractFilter;

class JSONPath implements ArrayAccess, Iterator, JsonSerializable
{
protected static $tokenCache = [];

protected $data;

protected $options;

const ALLOW_MAGIC = 1;





public function __construct($data, $options = 0)
{
$this->data = $data;
$this->options = $options;
}








public function find($expression)
{
$tokens = $this->parseTokens($expression);

$collectionData = [$this->data];

foreach ($tokens as $token) {
$filter = $token->buildFilter($this->options);

$filteredData = [];

foreach ($collectionData as $value) {
if (AccessHelper::isCollectionType($value)) {
$filteredValue = $filter->filter($value);
$filteredData = array_merge($filteredData, $filteredValue);
}
}

$collectionData = $filteredData;
}


return new static($collectionData, $this->options);
}




public function first()
{
$keys = AccessHelper::collectionKeys($this->data);

if (empty($keys)) {
return null;
}

$value = isset($this->data[$keys[0]]) ? $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)] ? $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($expression)
{
$cacheKey = md5($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 data()
{
return $this->data;
}

public function offsetExists($offset)
{
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)
{
if ($offset === null) {
$this->data[] = $value;
} else {
AccessHelper::setValue($this->data, $offset, $value);
}
}

public function offsetUnset($offset)
{
AccessHelper::unsetValue($this->data, $offset);
}

public function jsonSerialize()
{
return $this->data;
}




public function current()
{
$value = current($this->data);

return AccessHelper::isCollectionType($value) ? new static($value, $this->options) : $value;
}




public function next()
{
next($this->data);
}




public function key()
{
return key($this->data);
}




public function valid()
{
return key($this->data) !== null;
}




public function rewind()
{
reset($this->data);
}





public function __get($key)
{
return $this->offsetExists($key) ? $this->offsetGet($key) : null;
}

}
<?php
namespace Flow\JSONPath\Filters;

use Flow\JSONPath\AccessHelper;

class IndexesFilter extends AbstractFilter
{




public function filter($collection)
{
$return = [];
foreach ($this->token->value as $index) {
if (AccessHelper::keyExists($collection, $index, $this->magicIsAllowed)) {
$return[] = AccessHelper::getValue($collection, $index, $this->magicIsAllowed);
}
}
return $return;
}
}
<?php
namespace Flow\JSONPath\Filters;

use Flow\JSONPath\AccessHelper;
use Flow\JSONPath\JSONPathException;

class QueryResultFilter extends AbstractFilter
{





public function filter($collection)
{
$result = [];

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);
} else {
if ($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");
break;
}

if (AccessHelper::keyExists($collection, $resultKey, $this->magicIsAllowed)) {
$result[] = AccessHelper::getValue($collection, $resultKey, $this->magicIsAllowed);
}

return $result;
}
}
<?php
namespace Flow\JSONPath\Filters;

use Flow\JSONPath\AccessHelper;

class SliceFilter extends AbstractFilter
{





public function filter($collection)
{













$result = [];

$length = count($collection);
$start = $this->token->value['start'];
$end = $this->token->value['end'];
$step = $this->token->value['step'] ?: 1;

if ($start !== null && $end !== null) {

 }

if ($start !== null && $end === null) {

 $end = $start < 0 ? -1 : $length - 1;
}

if ($start === null && $end !== null) {
$start = 0;
}

if ($start === null && $end === null) {
$start = 0;
$end = $length - 1;
}

if ($end < 0 && $start >= 0) {
$end = ($length + $end) - 1;
}

if ($start < 0 && $end === null) {
$end = -1;
}

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
namespace Flow\JSONPath\Filters;

use Flow\JSONPath\AccessHelper;

class QueryMatchFilter extends AbstractFilter
{
const MATCH_QUERY_OPERATORS = '
    @(\.(?<key>\w+)|\[["\'](?<keySquare>.*?)["\']\])
    (\s*(?<operator>==|=|>|<)\s*(?<comparisonValue>\S.+))?
    ';






public function filter($collection)
{
$return = [];

preg_match('/^' . static::MATCH_QUERY_OPERATORS . '$/x', $this->token->value, $matches);

if (!isset($matches[1])) {
throw new \Exception("Malformed filter query");
}

$key = $matches['key'] ?: $matches['keySquare'];

if ($key === "") {
throw new \Exception("Malformed filter query: key was not set");
}

$operator = isset($matches['operator']) ? $matches['operator'] : null;
$comparisonValue = isset($matches['comparisonValue']) ? $matches['comparisonValue'] : null;

if (strtolower($comparisonValue) === "false") {
$comparisonValue = false;
}
if (strtolower($comparisonValue) === "true") {
$comparisonValue = true;
}
if (strtolower($comparisonValue) === "null") {
$comparisonValue = null;
}

$comparisonValue = preg_replace('/^[\'"]/', '', $comparisonValue);
$comparisonValue = preg_replace('/[\'"]$/', '', $comparisonValue);

foreach ($collection as $value) {
if (AccessHelper::keyExists($value, $key, $this->magicIsAllowed)) {
$value1 = AccessHelper::getValue($value, $key, $this->magicIsAllowed);

if ($operator === null && AccessHelper::keyExists($value, $key, $this->magicIsAllowed)) {
$return[] = $value;
}

if (($operator === "=" || $operator === "==") && $value1 == $comparisonValue) {
$return[] = $value;
}
if (($operator === "!=" || $operator === "!==") && $value1 != $comparisonValue) {
$return[] = $value;
}
if ($operator == ">" && $value1 > $comparisonValue) {
$return[] = $value;
}
if ($operator == "<" && $value1 < $comparisonValue) {
$return[] = $value;
}
}
}

return $return;
}
}
<?php
namespace Flow\JSONPath\Filters;

use Flow\JSONPath\JSONPath;
use Flow\JSONPath\JSONPathException;
use Flow\JSONPath\JSONPathToken;

abstract class AbstractFilter
{



protected $token;


protected $options;


protected $magicIsAllowed;

public function __construct(JSONPathToken $token, $options = 0)
{
$this->token = $token;
$this->options = $options;
$this->magicIsAllowed = $this->options & JSONPath::ALLOW_MAGIC;
}

public function isMagicAllowed()
{
return $this->magicIsAllowed;
}





abstract public function filter($collection);
}
<?php
namespace Flow\JSONPath\Filters;

use Flow\JSONPath\AccessHelper;
use Flow\Oauth2\Client\Token\Access;

class RecursiveFilter extends AbstractFilter
{




public function filter($collection)
{
$result = [];

$this->recurse($result, $collection);

return $result;
}

private function recurse(& $result, $data)
{
$result[] = $data;

if (AccessHelper::isCollectionType($data)) {
foreach (AccessHelper::arrayValues($data) as $key => $value) {
$results[] = $value;

if (AccessHelper::isCollectionType($value)) {
$this->recurse($result, $value);
}
}
}
}
}
<?php
namespace Flow\JSONPath\Filters;

use Flow\JSONPath\AccessHelper;

class IndexFilter extends AbstractFilter
{




public function filter($collection)
{
if (AccessHelper::keyExists($collection, $this->token->value, $this->magicIsAllowed)) {
return [
AccessHelper::getValue($collection, $this->token->value, $this->magicIsAllowed)
];
} else if ($this->token->value === "*") {
return AccessHelper::arrayValues($collection);
}

return [];
}

}
<?php







namespace Flow\JSONPath;


class JSONPathToken
{



const T_INDEX = 'index';
const T_RECURSIVE = 'recursive';
const T_QUERY_RESULT = 'queryResult';
const T_QUERY_MATCH = 'queryMatch';
const T_SLICE = 'slice';
const T_INDEXES = 'indexes';

public $type;
public $value;

public function __construct($type, $value)
{
$this->validateType($type);

$this->type = $type;
$this->value = $value;
}

public function validateType($type)
{
if (!in_array($type, static::getTypes(), true)) {
throw new JSONPathException('Invalid token: ' . $type);
}
}

public static function getTypes()
{
return [
static::T_INDEX,
static::T_RECURSIVE,
static::T_QUERY_RESULT,
static::T_QUERY_MATCH,
static::T_SLICE,
static::T_INDEXES,
];
}







public function buildFilter($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
// for phar
if (file_exists(__DIR__.'/vendor/autoload.php')) {
    require_once(__DIR__.'/vendor/autoload.php');
} elseif (file_exists(__DIR__.'/../../autoload.php')) {
    require_once __DIR__ . '/../../autoload.php';
}

// @codingStandardsIgnoreStart
// loading WebDriver aliases
if (!class_exists('RemoteWebDriver') and class_exists('Facebook\WebDriver\Remote\RemoteWebDriver')) {
    class RemoteWebDriver extends \Facebook\WebDriver\Remote\RemoteWebDriver {};
    class InvalidSelectorException extends Facebook\WebDriver\Exception\InvalidSelectorException {};
    class NoSuchElementException extends Facebook\WebDriver\Exception\NoSuchElementException {};
    class WebDriverCurlException extends Facebook\WebDriver\Exception\WebDriverCurlException {};
    class WebDriverActions extends Facebook\WebDriver\Interactions\WebDriverActions {};
    class LocalFileDetector extends Facebook\WebDriver\Remote\LocalFileDetector {};
    class WebDriverCapabilityType extends Facebook\WebDriver\Remote\WebDriverCapabilityType {};
    class WebDriverAlert extends Facebook\WebDriver\WebDriverAlert {};
    class WebDriverBy extends Facebook\WebDriver\WebDriverBy {};
    class WebDriverDimension extends Facebook\WebDriver\WebDriverDimension {};
    class RemoteWebElement extends Facebook\WebDriver\Remote\RemoteWebElement {};
    class WebDriverExpectedCondition extends Facebook\WebDriver\WebDriverExpectedCondition {};
    class WebDriverKeys extends Facebook\WebDriver\WebDriverKeys {};
    class WebDriverSelect extends Facebook\WebDriver\WebDriverSelect {};
    class WebDriverTimeouts extends Facebook\WebDriver\WebDriverTimeouts {};
    class WebDriverWindow extends Facebook\WebDriver\WebDriverWindow {};
    interface WebDriverElement extends Facebook\WebDriver\WebDriverElement {};
}

@include_once __DIR__ . DIRECTORY_SEPARATOR . 'symfony-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

if (!function_exists('json_last_error_msg')) {
    /**
     * Copied from http://php.net/manual/en/function.json-last-error-msg.php#117393
     * @return string
     */
    function json_last_error_msg()
    {
        static $errors = array(
            JSON_ERROR_NONE => 'No error',
            JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
            JSON_ERROR_STATE_MISMATCH => 'State mismatch (invalid or malformed JSON)',
            JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded',
            JSON_ERROR_SYNTAX => 'Syntax error',
            JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded'
        );

        $error = json_last_error();
        return isset($errors[$error]) ? $errors[$error] : 'Unknown error';
    }
}

// function not autoloaded in PHP, thus its a good place for them
function codecept_debug($data)
{
    \Codeception\Util\Debug::debug($data);
}

function codecept_root_dir($appendPath = '')
{
    return \Codeception\Configuration::projectDir() . $appendPath;
}

function codecept_output_dir($appendPath = '')
{
    return \Codeception\Configuration::outputDir() . $appendPath;
}

function codecept_log_dir($appendPath = '')
{
    return \Codeception\Configuration::outputDir() . $appendPath;
}

function codecept_data_dir($appendPath = '')
{
    return \Codeception\Configuration::dataDir() . $appendPath;
}

function codecept_relative_path($path)
{
    return substr($path, strlen(codecept_root_dir()));
}
<?php
/**
 * Codeception CLI
 */

use Symfony\Component\Console\Application,
    Symfony\Component\Console\Input\InputInterface,
    Symfony\Component\Console\Input\InputDefinition,
    Symfony\Component\Console\Input\InputOption;

 $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\Bootstrap('bootstrap'));
 $app->add(new Codeception\Command\Console('console'));
 $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\GeneratePhpUnit('generate:phpunit'));
 $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:group'));
 $app->add(new Codeception\Command\GeneratePageObject('generate:pageobject'));
 $app->add(new Codeception\Command\GenerateStepObject('generate:stepobject'));
 $app->add(new Codeception\Command\GenerateEnvironment('generate:environment'));

 // add only if within a phar archive.
 if ('phar:' === substr(__FILE__, 0, 5)) {
	 $app->add(new Codeception\Command\SelfUpdate('self-update'));
 }

 $app->run();
	uk}\c&NeG   GBMB