#!/usr/bin/env php
<?php

/*
 * Generated by Humbug Box 4.3.8@5534406.
 *
 * @link https://github.com/humbug/box
 */

Phar::mapPhar('box-auto-generated-alias-a47294517a29.phar');

require 'phar://box-auto-generated-alias-a47294517a29.phar/.box/bin/check-requirements.php';

require 'phar://box-auto-generated-alias-a47294517a29.phar/bin/civix';

__HALT_COMPILER(); ?>
Ž�  Þ              /   vendor/psr/container/src/ContainerInterface.phpS  §}ådS  Z¼Ø¤      7   vendor/psr/container/src/NotFoundExceptionInterface.php
  §}åd
  é“°Ù¤      8   vendor/psr/container/src/ContainerExceptionInterface.php  §}åd  ¢Î¢Ä¤      #   vendor/composer/autoload_static.phpU·  §}ådU·  (DÚ_¤      !   vendor/composer/autoload_real.phpû  §}ådû  afþ¤         vendor/composer/installed.phpº  §}ådº  gB@ê¤      %   vendor/composer/autoload_classmap.php˜—  §}åd˜—  5«bI¤      !   vendor/composer/autoload_psr4.php6  §}åd6  ÙÀ“É¤      "   vendor/composer/autoload_files.phpÔ  §}ådÔ  ž‡¤      %   vendor/composer/InstalledVersions.phpü:  §}ådü:  ƒÀ°¤      "   vendor/composer/platform_check.php�  §}åd�  äÍ%¾¤         vendor/composer/ClassLoader.phpÄ>  §}ådÄ>  Æ5Ky¤         vendor/composer/LICENSE.  §}åd.   Õ¤      '   vendor/composer/autoload_namespaces.php‹   §}åd‹   Š/t¤      <   vendor/symfony/polyfill-php80/Resources/stubs/ValueError.php>  §}åd>  g¦Žó¤      E   vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.phpG  §}ådG  Öˆ+¤      <   vendor/symfony/polyfill-php80/Resources/stubs/Stringable.phpŒ  §}ådŒ  t]\Ú¤      :   vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.phpw  §}ådw  =7T8¤      ;   vendor/symfony/polyfill-php80/Resources/stubs/Attribute.phpð  §}ådð  MKÜ<¤      *   vendor/symfony/polyfill-php80/PhpToken.php“  §}åd“  ð“ð¤      +   vendor/symfony/polyfill-php80/bootstrap.php™  §}åd™  $ýMÉ¤      '   vendor/symfony/polyfill-php80/Php80.php“  §}åd“  ³°&[¤      @   vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php	U  §}åd	U  ¯@Á?¤      @   vendor/symfony/polyfill-mbstring/Resources/unidata/upperCase.php V  §}åd V  D°ã©¤      F   vendor/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php  §}åd  þMÑO¤      0   vendor/symfony/polyfill-mbstring/bootstrap80.php %  §}åd %  ©àÿ!¤      -   vendor/symfony/polyfill-mbstring/Mbstring.phpFp  §}ådFp  ^�7G¤      .   vendor/symfony/polyfill-mbstring/bootstrap.phpç  §}ådç  ˜yj¤      '   vendor/symfony/polyfill-ctype/Ctype.php€  §}åd€  Óc&Æ¤      -   vendor/symfony/polyfill-ctype/bootstrap80.phpV  §}ådV  Ç’ÇE¤      +   vendor/symfony/polyfill-ctype/bootstrap.php  §}åd  ÓB¤      ;   vendor/symfony/service-contracts/ServiceSubscriberTrait.phpí  §}ådí  ÊbÅ¤      ?   vendor/symfony/service-contracts/ServiceSubscriberInterface.phpÒ  §}ådÒ  %;‘œ¤      3   vendor/symfony/service-contracts/ResetInterface.phpð  §}ådð  »‡%¤      8   vendor/symfony/service-contracts/ServiceLocatorTrait.phpà  §}ådà  õÀ|Z¤      =   vendor/symfony/service-contracts/ServiceProviderInterface.phpÍ  §}ådÍ  –Ë&:¤      9   vendor/symfony/templating/TemplateNameParserInterface.php  §}åd  Æ¤I½¤      6   vendor/symfony/templating/StreamingEngineInterface.php  §}åd  ±Gü,¤      8   vendor/symfony/templating/TemplateReferenceInterface.php  §}åd  ©J‚�¤      0   vendor/symfony/templating/TemplateNameParser.phpÊ  §}ådÊ  OÝÝ+¤      5   vendor/symfony/templating/Loader/FilesystemLoader.phpn  §}ådn  ŠñÛt¤      0   vendor/symfony/templating/Loader/ChainLoader.phpŸ  §}ådŸ  ¸üJ¤      +   vendor/symfony/templating/Loader/Loader.phpí  §}ådí  EX�p¤      4   vendor/symfony/templating/Loader/LoaderInterface.php  §}åd  åØÙ¤      0   vendor/symfony/templating/Loader/CacheLoader.phpG	  §}ådG	  j L¤      '   vendor/symfony/templating/PhpEngine.php‘5  §}åd‘5  ~×Œ¤      0   vendor/symfony/templating/Helper/SlotsHelper.php«  §}åd«  Šö¤      4   vendor/symfony/templating/Helper/HelperInterface.phpb  §}ådb  µ(¤      +   vendor/symfony/templating/Helper/Helper.phpÓ  §}ådÓ  ÀèÓ©¤      .   vendor/symfony/templating/DelegatingEngine.phpç	  §}ådç	  zØ—N¤      /   vendor/symfony/templating/TemplateReference.phpû  §}ådû  ™ecš¤      -   vendor/symfony/templating/EngineInterface.phpk  §}ådk  .ÞÀ”¤      3   vendor/symfony/templating/Storage/StringStorage.php‚  §}åd‚  @^b¤      1   vendor/symfony/templating/Storage/FileStorage.php˜  §}åd˜  Óô¸¤      -   vendor/symfony/templating/Storage/Storage.phpÑ  §}ådÑ  B	?¤      ,   vendor/symfony/console/Question/Question.phpD  §}ådD  v5�¤      2   vendor/symfony/console/Question/ChoiceQuestion.php·  §}åd·  > ü÷¤      8   vendor/symfony/console/Question/ConfirmationQuestion.php   §}åd   ¼:R¤      6   vendor/symfony/console/EventListener/ErrorListener.php  §}åd  i”Wñ¤      4   vendor/symfony/console/Descriptor/JsonDescriptor.php¡  §}åd¡  »”qt¤      <   vendor/symfony/console/Descriptor/ApplicationDescription.phpØ  §}ådØ  çQë¤      8   vendor/symfony/console/Descriptor/MarkdownDescriptor.phpn  §}ådn  d�WG¤      3   vendor/symfony/console/Descriptor/XmlDescriptor.phpN#  §}ådN#  ‰“‘¤      9   vendor/symfony/console/Descriptor/DescriptorInterface.php•  §}åd•  d77³¤      4   vendor/symfony/console/Descriptor/TextDescriptor.phpZ1  §}ådZ1  ¢î\P¤      0   vendor/symfony/console/Descriptor/Descriptor.phpÿ  §}ådÿ  ¤>¤      2   vendor/symfony/console/Event/ConsoleErrorEvent.phpý  §}ådý  kcÑ¤      -   vendor/symfony/console/Event/ConsoleEvent.phpé  §}ådé  @µqÂ¤      4   vendor/symfony/console/Event/ConsoleCommandEvent.phpS  §}ådS  IöŽ!¤      6   vendor/symfony/console/Event/ConsoleTerminateEvent.php  §}åd  ÕØB¤      F   vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.phpµ  §}ådµ  'hóv¤      9   vendor/symfony/console/Formatter/OutputFormatterStyle.php  §}åd  XŸMí¤      4   vendor/symfony/console/Formatter/OutputFormatter.php,  §}åd,  R­´¤      =   vendor/symfony/console/Formatter/OutputFormatterInterface.phpL  §}ådL  Eaú¤      >   vendor/symfony/console/Formatter/OutputFormatterStyleStack.php
  §}åd
  ">¿u¤      B   vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php@  §}åd@  �*4)¤      (   vendor/symfony/console/Output/Output.phpÈ  §}ådÈ  ÅkHP¤      0   vendor/symfony/console/Output/BufferedOutput.phpN  §}ådN  zwÀ³¤      6   vendor/symfony/console/Output/ConsoleSectionOutput.phpv  §}ådv  ¶Ë|¤      5   vendor/symfony/console/Output/TrimmedBufferOutput.phpG  §}ådG  á´ä6¤      ,   vendor/symfony/console/Output/NullOutput.php…  §}åd…  _¤uT¤      /   vendor/symfony/console/Output/ConsoleOutput.phpÇ  §}ådÇ  IRà„¤      .   vendor/symfony/console/Output/StreamOutput.phpì  §}ådì  Ñdx¤      8   vendor/symfony/console/Output/ConsoleOutputInterface.php<  §}åd<  &7ºV¤      1   vendor/symfony/console/Output/OutputInterface.phpb  §}ådb  ’rË¤      D   vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php  §}åd  …`�Ç¤      #   vendor/symfony/console/Terminal.php…  §}åd…  ØÖ¬‚¤      +   vendor/symfony/console/Helper/TableRows.php\  §}åd\  ½Í¢¤      2   vendor/symfony/console/Helper/DescriptorHelper.php{	  §}åd{	  ˆµØ¤      7   vendor/symfony/console/Helper/SymfonyQuestionHelper.php˜  §}åd˜  6Z°	¤      1   vendor/symfony/console/Helper/HelperInterface.phpw  §}ådw  —<Þ“¤      2   vendor/symfony/console/Helper/InputAwareHelper.php  §}åd  ˆj¿m¤      -   vendor/symfony/console/Helper/ProgressBar.phpçE  §}ådçE  n\ü¤      0   vendor/symfony/console/Helper/TableSeparator.php  §}åd  åS�€¤      +   vendor/symfony/console/Helper/HelperSet.phpº	  §}ådº	  šAZ¤      +   vendor/symfony/console/Helper/TableCell.php¾  §}åd¾  ¢y’-¤      3   vendor/symfony/console/Helper/ProgressIndicator.php   §}åd   =K”¤      0   vendor/symfony/console/Helper/QuestionHelper.phpŒC  §}ådŒC  îÙñ�¤      ,   vendor/symfony/console/Helper/TableStyle.phpõ;  §}ådõ;  ¿XV¤      1   vendor/symfony/console/Helper/FormatterHelper.php÷
  §}åd÷
  á+Î[¤      (   vendor/symfony/console/Helper/Dumper.php)  §}åd)  k€Çâ¤      /   vendor/symfony/console/Helper/ProcessHelper.php¯  §}åd¯  Ò+³¤      6   vendor/symfony/console/Helper/DebugFormatterHelper.phpù  §}ådù  Í¡¤      (   vendor/symfony/console/Helper/Helper.phpu  §}ådu  ¹ðE¤      '   vendor/symfony/console/Helper/Table.php…j  §}åd…j  ãHü‰¤      /   vendor/symfony/console/Tester/CommandTester.php\	  §}åd\	  ¬
d¤      3   vendor/symfony/console/Tester/ApplicationTester.phpŠ  §}ådŠ  \ãí[¤      -   vendor/symfony/console/Tester/TesterTrait.php\  §}åd\  ù¤uh¤      ?   vendor/symfony/console/CommandLoader/CommandLoaderInterface.phpº  §}ådº  Î	¦¤      ?   vendor/symfony/console/CommandLoader/ContainerCommandLoader.phpí  §}ådí  ´°Ö$¤      =   vendor/symfony/console/CommandLoader/FactoryCommandLoader.phpE  §}ådE  Lä°¤      3   vendor/symfony/console/Exception/LogicException.php³  §}åd³  MJ30¤      ?   vendor/symfony/console/Exception/NamespaceNotFoundException.phpã  §}ådã  �´uh¤      =   vendor/symfony/console/Exception/InvalidArgumentException.phpÇ  §}ådÇ  }}Ë ¤      5   vendor/symfony/console/Exception/RuntimeException.php·  §}åd·  KÚ$¤      7   vendor/symfony/console/Exception/ExceptionInterface.php²  §}åd²  Ñd•¤      ;   vendor/symfony/console/Exception/InvalidOptionException.php  §}åd  ßoë¤      :   vendor/symfony/console/Exception/MissingInputException.php÷  §}åd÷  #!1¤      =   vendor/symfony/console/Exception/CommandNotFoundException.phpå  §}ådå  
Ç4µ¤      &   vendor/symfony/console/Application.phpû¯  §}ådû¯  ¥Þ�¤      (   vendor/symfony/console/ConsoleEvents.phpG  §}ådG  >Êb¤      ,   vendor/symfony/console/Style/OutputStyle.php  §}åd  ùx…›¤      -   vendor/symfony/console/Style/SymfonyStyle.phpV9  §}ådV9  5Öu¤      /   vendor/symfony/console/Style/StyleInterface.php!  §}åd!  ï�ä¤      ,   vendor/symfony/console/Input/StringInput.phpû  §}ådû  «•²¤      0   vendor/symfony/console/Input/InputDefinition.php *  §}åd *  	on�¤      9   vendor/symfony/console/Input/StreamableInputInterface.phpq  §}ådq  \Úhõ¤      4   vendor/symfony/console/Input/InputAwareInterface.phpC  §}ådC  òÿX^¤      *   vendor/symfony/console/Input/ArgvInput.php),  §}åd),  ^N¤      /   vendor/symfony/console/Input/InputInterface.php¤  §}åd¤  <}?¤      +   vendor/symfony/console/Input/ArrayInput.phpÃ  §}ådÃ  (^gƒ¤      .   vendor/symfony/console/Input/InputArgument.php˜  §}åd˜  eÅ]u¤      &   vendor/symfony/console/Input/Input.php~  §}åd~  GI2¤      ,   vendor/symfony/console/Input/InputOption.php•  §}åd•  Ä$ú¤      .   vendor/symfony/console/Command/HelpCommand.phpÙ  §}ådÙ  _«
¤      *   vendor/symfony/console/Command/Command.php,L  §}åd,L  £¿MX¤      .   vendor/symfony/console/Command/ListCommand.php—	  §}åd—	  '²¸Ÿ¤      0   vendor/symfony/console/Command/LockableTrait.phpÖ  §}ådÖ  ÌºÙ‚¤      /   vendor/symfony/console/Logger/ConsoleLogger.php~  §}åd~   å-?¤      '   vendor/symfony/polyfill-php72/Php72.php(  §}åd(  4bÝ¤      +   vendor/symfony/polyfill-php72/bootstrap.phpE  §}ådE  �³¤h¤      '   vendor/symfony/var-dumper/VarDumper.phpó  §}ådó  ÃÄD¤      1   vendor/symfony/var-dumper/Caster/CutArrayStub.phpÁ  §}ådÁ  =.›Í¤      2   vendor/symfony/var-dumper/Caster/SymfonyCaster.phpë  §}ådë  4¼Ö¤      2   vendor/symfony/var-dumper/Caster/ImagineCaster.php—  §}åd—  rÇ£?¤      3   vendor/symfony/var-dumper/Caster/DoctrineCaster.phpÂ  §}ådÂ  þºÙ5¤      .   vendor/symfony/var-dumper/Caster/ConstStub.phpý  §}ådý  ì�G¤      .   vendor/symfony/var-dumper/Caster/SplCaster.php—  §}åd—  ÆÒß¥¤      /   vendor/symfony/var-dumper/Caster/StubCaster.phph  §}ådh  ®Õ˜3¤      0   vendor/symfony/var-dumper/Caster/PgSqlCaster.phpô  §}ådô  +B‘Û¤      /   vendor/symfony/var-dumper/Caster/DsPairStub.phpX  §}ådX  Ó7hî¤      /   vendor/symfony/var-dumper/Caster/UuidCaster.php£  §}åd£  ;m­×¤      ,   vendor/symfony/var-dumper/Caster/CutStub.php›  §}åd›  ÝÉæ¤      6   vendor/symfony/var-dumper/Caster/XmlResourceCaster.phpZ	  §}ådZ	  ì¾Ö¤      .   vendor/symfony/var-dumper/Caster/GmpCaster.php  §}åd  ›§÷¤      -   vendor/symfony/var-dumper/Caster/EnumStub.php�  §}åd�  ³÷xg¤      5   vendor/symfony/var-dumper/Caster/ReflectionCaster.php94  §}åd94  'œ?À¤      .   vendor/symfony/var-dumper/Caster/ClassStub.php(  §}åd(  2K0¤      7   vendor/symfony/var-dumper/Caster/ProxyManagerCaster.phpü  §}ådü  Y³>¤      .   vendor/symfony/var-dumper/Caster/DOMCaster.php3!  §}åd3!  Wa¸�¤      /   vendor/symfony/var-dumper/Caster/IntlCaster.php  §}åd  Øáõé¤      0   vendor/symfony/var-dumper/Caster/RedisCaster.php‰  §}åd‰  Ä¶5§¤      4   vendor/symfony/var-dumper/Caster/ExceptionCaster.php(?  §}åd(?  ;‘¤      .   vendor/symfony/var-dumper/Caster/PdoCaster.phpˆ  §}ådˆ  '¡¾¤      -   vendor/symfony/var-dumper/Caster/LinkStub.phph  §}ådh  ò=§¤      .   vendor/symfony/var-dumper/Caster/TraceStub.phpÕ  §}ådÕ  rìAµ¤      /   vendor/symfony/var-dumper/Caster/DateCaster.php®  §}åd®  gu¤      /   vendor/symfony/var-dumper/Caster/AmqpCaster.phpz  §}ådz  ÄCàJ¤      4   vendor/symfony/var-dumper/Caster/XmlReaderCaster.php9  §}åd9  Wf¹ø¤      3   vendor/symfony/var-dumper/Caster/ResourceCaster.phpW  §}ådW  ¡]&¤      .   vendor/symfony/var-dumper/Caster/FrameStub.phpî  §}ådî  ÜŸ—¥¤      -   vendor/symfony/var-dumper/Caster/DsCaster.php[  §}åd[  fŠe¤      4   vendor/symfony/var-dumper/Caster/MemcachedCaster.php	  §}åd	  CêŽ¤      -   vendor/symfony/var-dumper/Caster/ArgsStub.php	  §}åd	  Èà�5¤      +   vendor/symfony/var-dumper/Caster/Caster.php  §}åd  &5zŽ¤      ,   vendor/symfony/var-dumper/Caster/ImgStub.php�  §}åd�  í{§¤      6   vendor/symfony/var-dumper/Resources/functions/dump.phpZ  §}ådZ  Å…¡_¤      ?   vendor/symfony/var-dumper/Exception/ThrowingCasterException.phpž  §}ådž  ¢�¤      )   vendor/symfony/var-dumper/Cloner/Stub.php  §}åd  d¤      +   vendor/symfony/var-dumper/Cloner/Cursor.phpC  §}ådC  à¨œ’¤      4   vendor/symfony/var-dumper/Cloner/ClonerInterface.phpE  §}ådE  n	‚‹¤      3   vendor/symfony/var-dumper/Cloner/AbstractCloner.phpšO  §}ådšO  &xS¤      4   vendor/symfony/var-dumper/Cloner/DumperInterface.php  §}åd  ¶wf¤      .   vendor/symfony/var-dumper/Cloner/VarCloner.phpÜ8  §}ådÜ8  Þ³wþ¤      )   vendor/symfony/var-dumper/Cloner/Data.php7  §}åd7  CŽVh¤      ?   vendor/symfony/var-dumper/Command/Descriptor/HtmlDescriptor.php„  §}åd„  �»Tï¤      H   vendor/symfony/var-dumper/Command/Descriptor/DumpDescriptorInterface.php  §}åd  Ä×Ž¤      >   vendor/symfony/var-dumper/Command/Descriptor/CliDescriptor.php'  §}åd'  [»v¤      7   vendor/symfony/var-dumper/Command/ServerDumpCommand.phpd  §}ådd  |'è¤      /   vendor/symfony/var-dumper/Server/DumpServer.php2  §}åd2  ~q—w¤      /   vendor/symfony/var-dumper/Server/Connection.phpÛ
  §}ådÛ
  `í]¤      /   vendor/symfony/var-dumper/Dumper/HtmlDumper.phpÖƒ  §}ådÖƒ  Mö1¤      3   vendor/symfony/var-dumper/Dumper/AbstractDumper.phpµ  §}ådµ  S¼Fh¤      1   vendor/symfony/var-dumper/Dumper/ServerDumper.phpi  §}ådi  f9/¤      8   vendor/symfony/var-dumper/Dumper/DataDumperInterface.php  §}åd  ¹Ô¿¤      .   vendor/symfony/var-dumper/Dumper/CliDumper.phpòT  §}ådòT  ,¹¨¤      J   vendor/symfony/var-dumper/Dumper/ContextProvider/SourceContextProvider.phpZ  §}ådZ  0¶"Ø¤      G   vendor/symfony/var-dumper/Dumper/ContextProvider/CliContextProvider.php  §}åd  az¤¤      K   vendor/symfony/var-dumper/Dumper/ContextProvider/RequestContextProvider.php¢  §}åd¢  ‹}
È¤      M   vendor/symfony/var-dumper/Dumper/ContextProvider/ContextProviderInterface.phpƒ  §}ådƒ  «_@§¤      9   vendor/symfony/var-dumper/Dumper/ContextualizedDumper.php¯  §}åd¯  å·¤      @   vendor/symfony/filesystem/Exception/InvalidArgumentException.phpØ  §}ådØ  {H¹¤      <   vendor/symfony/filesystem/Exception/IOExceptionInterface.php¯  §}åd¯  ¤²
x¤      :   vendor/symfony/filesystem/Exception/ExceptionInterface.phpÙ  §}ådÙ  ‘è+¤      =   vendor/symfony/filesystem/Exception/FileNotFoundException.phpÒ  §}ådÒ  “¯¤      3   vendor/symfony/filesystem/Exception/IOException.phpÂ  §}ådÂ  u¤      (   vendor/symfony/filesystem/Filesystem.php,t  §}åd,t  |Ú„¤      ?   vendor/symfony/polyfill-php73/Resources/stubs/JsonException.phpW  §}ådW  3~ÊR¤      '   vendor/symfony/polyfill-php73/Php73.php}  §}åd}  p‹Lr¤      +   vendor/symfony/polyfill-php73/bootstrap.phpt  §}ådt  ·êì¤      ,   vendor/symfony/var-exporter/Instantiator.phpÁ  §}ådÁ  ÍR‘¤      +   vendor/symfony/var-exporter/VarExporter.php  §}åd  w÷‘M¤      @   vendor/symfony/var-exporter/Exception/ClassNotFoundException.php+  §}åd+  ·ž¤      <   vendor/symfony/var-exporter/Exception/ExceptionInterface.php_  §}åd_  2p–¤      F   vendor/symfony/var-exporter/Exception/NotInstantiableTypeException.php8  §}åd8  gH^¤      1   vendor/symfony/var-exporter/Internal/Exporter.php$>  §}åd$>  ýºÌ¤      /   vendor/symfony/var-exporter/Internal/Values.phpí  §}ådí  ­�{¤      1   vendor/symfony/var-exporter/Internal/Registry.phpK  §}ådK  °D²¤      2   vendor/symfony/var-exporter/Internal/Reference.php6  §}åd6  —µÑ*¤      1   vendor/symfony/var-exporter/Internal/Hydrator.php:  §}åd:  üÿA¤      %   vendor/symfony/process/PhpProcess.php_  §}åd_  ¦À‚ê¤      &   vendor/symfony/process/InputStream.php9	  §}åd9	  ôÍÿ¤      -   vendor/symfony/process/Pipes/WindowsPipes.phpi  §}ådi  h(S¤      *   vendor/symfony/process/Pipes/UnixPipes.phpÀ  §}ådÀ  H^Š¤      .   vendor/symfony/process/Pipes/AbstractPipes.php   §}åd   "ÚËq¤      /   vendor/symfony/process/Pipes/PipesInterface.phpá  §}ådá  H_¤      .   vendor/symfony/process/PhpExecutableFinder.phpy
  §}ådy
  ®3Ñ¤      +   vendor/symfony/process/ExecutableFinder.php
  §}åd
  OÚ7Ê¤      '   vendor/symfony/process/ProcessUtils.phpW  §}ådW  ’;©
¤      3   vendor/symfony/process/Exception/LogicException.phpÛ  §}ådÛ  %|œH¤      =   vendor/symfony/process/Exception/InvalidArgumentException.phpù  §}ådù  ›†ºE¤      ;   vendor/symfony/process/Exception/ProcessFailedException.php7  §}åd7  ƒÊŸ¤      =   vendor/symfony/process/Exception/ProcessSignaledException.phpÂ  §}ådÂ  qFŽ¤      =   vendor/symfony/process/Exception/ProcessTimedOutException.phpj  §}ådj  ™¥� ¤      5   vendor/symfony/process/Exception/RuntimeException.phpê  §}ådê  bYËË¤      7   vendor/symfony/process/Exception/ExceptionInterface.phpË  §}ådË  ¨	Õ¤      "   vendor/symfony/process/Process.php\Î  §}åd\Î  ®À­T¤      7   vendor/civicrm/composer-downloads-plugin/src/Plugin.php  §}åd  ÚBjÚ¤      D   vendor/civicrm/composer-downloads-plugin/src/Handler/BaseHandler.phpF  §}ådF  åð‡Å¤      D   vendor/civicrm/composer-downloads-plugin/src/Handler/FileHandler.phpD	  §}ådD	  üÍþ¸¤      D   vendor/civicrm/composer-downloads-plugin/src/Handler/PharHandler.php@  §}åd@  ªù•Y¤      G   vendor/civicrm/composer-downloads-plugin/src/Handler/ArchiveHandler.phpÒ
  §}ådÒ
  ¯%b±¤      @   vendor/civicrm/composer-downloads-plugin/src/DownloadsParser.phpl	  §}ådl	  �[¬v¤      <   vendor/civicrm/composer-downloads-plugin/src/GlobCleaner.phpÍ  §}ådÍ  ‘Åo4¤      ;   vendor/civicrm/composer-downloads-plugin/src/Subpackage.phpã  §}ådã  m˜eÌ¤      *   vendor/civicrm/cv-lib/src/ErrorHandler.php�  §}åd�  ŸÑŸ¦¤      ,   vendor/civicrm/cv-lib/src/BuildkitReader.phpˆ  §}ådˆ  :uXZ¤      *   vendor/civicrm/cv-lib/src/CmsBootstrap.phpFL  §}ådFL  Þ‡ô¤      0   vendor/civicrm/cv-lib/src/Log/InternalLogger.phpÐ  §}ådÐ  J  °¤      6   vendor/civicrm/cv-lib/src/Log/SymfonyConsoleLogger.phpS  §}ådS  ÐéÎ¥¤      (   vendor/civicrm/cv-lib/src/Log/Logger.phpI  §}ådI  ÐÞ×î¤      .   vendor/civicrm/cv-lib/src/Log/StderrLogger.phpÂ  §}ådÂ  –Ðüò¤      2   vendor/civicrm/cv-lib/src/Util/FilesystemTrait.phpp  §}ådp  Q)¹¤      ,   vendor/civicrm/cv-lib/src/Util/BootTrait.phpü)  §}ådü)  ZáôU¤      -   vendor/civicrm/cv-lib/src/Util/Filesystem.phpµ  §}ådµ  Á`	¤      5   vendor/civicrm/cv-lib/src/PharOut/PharPolicyTrait.php  §}åd  ³á8‘¤      -   vendor/civicrm/cv-lib/src/PharOut/PharOut.phpÀ  §}ådÀ  h»2+¤      '   vendor/civicrm/cv-lib/src/Bootstrap.php;L  §}åd;L  «W¤      .   vendor/civicrm/cv-lib/src/SiteConfigReader.php  §}åd  *nM¤      $   vendor/civicrm/cv-lib/src/Config.php)  §}åd)  >Ï¶ˆ¤         vendor/autoload.php)  §}åd)  #iê)¤      7   vendor/totten/lurkerlite/src/Lurker/ResourceWatcher.php€  §}åd€  ÛÈ ¤      H   vendor/totten/lurkerlite/src/Lurker/Tracker/RecursiveIteratorTracker.php³  §}åd³  è¢¤      @   vendor/totten/lurkerlite/src/Lurker/Tracker/TrackerInterface.php¨  §}åd¨  4±	¤      >   vendor/totten/lurkerlite/src/Lurker/Tracker/InotifyTracker.phpN  §}ådN  î$\¯¤      B   vendor/totten/lurkerlite/src/Lurker/Event/FilesystemEventTrait.phpy  §}ådy  IuÃ„¤      =   vendor/totten/lurkerlite/src/Lurker/Event/FilesystemEvent.php  §}åd  m”«¸¤      =   vendor/totten/lurkerlite/src/Lurker/Resource/FileResource.php&  §}åd&  ›8ç¤      @   vendor/totten/lurkerlite/src/Lurker/Resource/TrackedResource.php†  §}åd†  Üç|¤      B   vendor/totten/lurkerlite/src/Lurker/Resource/ResourceInterface.phpB  §}ådB  ¦Åì¤      B   vendor/totten/lurkerlite/src/Lurker/Resource/DirectoryResource.php{  §}åd{  Kˆ`Ë¤      J   vendor/totten/lurkerlite/src/Lurker/StateChecker/DirectoryStateChecker.phpž  §}ådž   ± ¤      E   vendor/totten/lurkerlite/src/Lurker/StateChecker/FileStateChecker.phpI  §}ådI  f(	*¤      J   vendor/totten/lurkerlite/src/Lurker/StateChecker/StateCheckerInterface.phpã  §}ådã  êÞHv¤      U   vendor/totten/lurkerlite/src/Lurker/StateChecker/Inotify/TopDirectoryStateChecker.php]  §}åd]  uGŒX¤      R   vendor/totten/lurkerlite/src/Lurker/StateChecker/Inotify/DirectoryStateChecker.php‘#  §}åd‘#  øÊ
¤      M   vendor/totten/lurkerlite/src/Lurker/StateChecker/Inotify/FileStateChecker.phpv  §}ådv  ËÃU>¤      G   vendor/totten/lurkerlite/src/Lurker/StateChecker/Inotify/CheckerBag.php  §}åd  ½®p¤      Q   vendor/totten/lurkerlite/src/Lurker/StateChecker/Inotify/ResourceStateChecker.php  §}åd  ´ß‰h¤      U   vendor/totten/lurkerlite/src/Lurker/StateChecker/Inotify/NewDirectoryStateChecker.php9  §}åd9  ç#;¤      I   vendor/totten/lurkerlite/src/Lurker/StateChecker/ResourceStateChecker.php²
  §}åd²
  Z¤      M   vendor/totten/lurkerlite/src/Lurker/StateChecker/NewDirectoryStateChecker.phpS  §}ådS  ždiF¤      J   vendor/totten/lurkerlite/src/Lurker/Exception/InvalidArgumentException.php*  §}åd*  ìæP¤      B   vendor/totten/lurkerlite/src/Lurker/Exception/RuntimeException.php  §}åd  ÖÜV!¤      D   vendor/totten/lurkerlite/src/Lurker/Exception/ExceptionInterface.phpÎ   §}ådÎ   ˆ?òÖ¤      P   vendor/totten/lurkerlite/src/Lurker/EventDispatcher/EventDispatcherInterface.phpV  §}ådV  u	¤      G   vendor/totten/lurkerlite/src/Lurker/EventDispatcher/EventDispatcher.php  §}åd  ‡“²E¤      :   vendor/totten/process-helper/src/ProcessErrorException.phpÁ  §}ådÁ  º5xï¤      2   vendor/totten/process-helper/src/ProcessHelper.php¿  §}åd¿  FÏm¤      6   vendor/totten/license-data/src/LicenseData/License.phpÀ  §}ådÀ  Ü•}Ä¤      9   vendor/totten/license-data/src/LicenseData/Repository.phpî  §}ådî  ˜Ì`å¤      $   vendor/totten/license-data/index.csvo  §}ådo  ¬Ó¤      0   vendor/totten/license-data/licenses/LGPL-3.0.txtŸ  §}ådŸ   Ç©z¤      4   vendor/totten/license-data/licenses/BSD-2-Clause.txt  §}åd  –.¤      1   vendor/totten/license-data/licenses/LGPL-2.1+.txtbh  §}ådbh  …6¤      /   vendor/totten/license-data/licenses/GPL-2.0.txtaG  §}ådaG  äF¶k¤      /   vendor/totten/license-data/licenses/GPL-3.0.txt Š  §}åd Š  q»/ð¤      0   vendor/totten/license-data/licenses/AGPL-3.0.txtŠ‡  §}ådŠ‡  -I¤      +   vendor/totten/license-data/licenses/MIT.txt%  §}åd%  óctb¤      0   vendor/totten/license-data/licenses/LGPL-2.1.txt^h  §}åd^h  d¿J¤      0   vendor/totten/license-data/licenses/GPL-2.0+.txteG  §}ådeG  Œb%¤      1   vendor/totten/license-data/licenses/LGPL-3.0+.txt£  §}åd£  ÑÙù¤      2   vendor/totten/license-data/licenses/Apache-2.0.txt -  §}åd -  htJï¤      0   vendor/totten/license-data/licenses/GPL-3.0+.txtŠ  §}ådŠ  &è9È¤      -   vendor/totten/license-data/licenses/WTFPL.txt%  §}åd%  eÇ›¤      <   vendor/togos/gitignore/src/main/php/TOGoS/GitIgnore/Util.phpå  §}ådå  [Ó5¤      B   vendor/togos/gitignore/src/main/php/TOGoS/GitIgnore/FileFinder.php«  §}åd«  Ñ¶¡8¤      ?   vendor/togos/gitignore/src/main/php/TOGoS/GitIgnore/Pattern.php=	  §}åd=	  ‰Ü.¤      <   vendor/togos/gitignore/src/main/php/TOGoS/GitIgnore/Rule.phpS  §}ådS  !«ç¤      ?   vendor/togos/gitignore/src/main/php/TOGoS/GitIgnore/Ruleset.php_  §}åd_  >mÉ°¤         images/placeholder.pngÿ-  §}ådÿ-  0UQ¤      "   extern/mixin/theme-php@1/mixin.phpÖ  §}ådÖ  î}ÞÕ¤         extern/mixin/polyfill.phpß  §}ådß  �Ô
l¤      )   extern/mixin/entity-types-php@1/mixin.php³  §}åd³  B½bà¤          extern/mixin/ang-php@1/mixin.php½  §}åd½  X;Ï ¤      !   extern/mixin/mgd-php@1/mixin.php~è  §}ådè  	Ãï¤          extern/mixin/mgd-php@1/mixin.phpè  §}ådè  	Ãï¤      "   extern/mixin/smarty-v2@1/mixin.phpï  §}ådï  ´{K¿¤      !   extern/mixin/case-xml@1/mixin.php…  §}åd…  ˜ŠÖƒ¤      !   extern/mixin/menu-xml@1/mixin.phpb  §}ådb  =n@ö¤      *   extern/mixin/afform-entity-php@1/mixin.phpj  §}ådj  ápy¤      $   extern/mixin/setting-php@1/mixin.php  §}åd  Ùf¿;¤      %   extern/mixin/scan-classes@1/mixin.php
  §}åd
  ’ÜTª¤         extern/src/Mixlib.php)#  §}åd)#  ›Õ®Ý¤      '   src/CRM/CivixBundle/RunMethodsTrait.phpß  §}ådß  )\µ¤      7   src/CRM/CivixBundle/Resources/views/Code/report.php.php—  §}åd—  vçM¿¤      ;   src/CRM/CivixBundle/Resources/views/Code/entity-bao.php.phpì   §}ådì   ;FY´¤      9   src/CRM/CivixBundle/Resources/views/Code/test-e2e.php.phpŠ  §}ådŠ  Æ�•Å¤      =   src/CRM/CivixBundle/Resources/views/Code/module.civix.php.php¦  §}åd¦  N©B"¤      <   src/CRM/CivixBundle/Resources/views/Code/angular-page.js.php	  §}åd	  çíbG¤      >   src/CRM/CivixBundle/Resources/views/Code/test-headless.php.phpS  §}ådS  ,ÇÈ$¤      >   src/CRM/CivixBundle/Resources/views/Code/angular-page.html.php  §}åd  Níûê¤      9   src/CRM/CivixBundle/Resources/views/Code/upgrader.php.phpÞ  §}ådÞ  ?K¾¤      5   src/CRM/CivixBundle/Resources/views/Code/form.tpl.phpž  §}ådž  £„Õõ¤      5   src/CRM/CivixBundle/Resources/views/Code/page.tpl.phpa  §}åda  Z™Ÿ¤      5   src/CRM/CivixBundle/Resources/views/Code/page.php.php+  §}åd+  ÄóÍ›¤      ;   src/CRM/CivixBundle/Resources/views/Code/entity-api.php.phpá  §}ådá  �Ç«¤      ?   src/CRM/CivixBundle/Resources/views/Code/test-headless.php.php~T  §}ådT  /—W¤      <   src/CRM/CivixBundle/Resources/views/Code/entity-api.php.php~â  §}ådâ  Ÿ’lî¤      =   src/CRM/CivixBundle/Resources/views/Code/test-phpunit.php.phpò  §}ådò  ×žîQ¤      =   src/CRM/CivixBundle/Resources/views/Code/angular-page.hlp.phpw   §}ådw   Ñú^Û¤      :   src/CRM/CivixBundle/Resources/views/Code/bootstrap.css.php…  §}åd…  8ÃÙè¤      >   src/CRM/CivixBundle/Resources/views/Code/entity-schema.xml.php;  §}åd;  î'_Ð¤      5   src/CRM/CivixBundle/Resources/views/Code/form.php.php¹  §}åd¹  ï¶¤      7   src/CRM/CivixBundle/Resources/views/Code/search.php.php?  §}åd?  `by—¤      7   src/CRM/CivixBundle/Resources/views/Code/module.php.php¥  §}åd¥  \á*¤      <   src/CRM/CivixBundle/Resources/views/Code/entity-api4.php.phpü   §}ådü   åßÎG¤      A   src/CRM/CivixBundle/Resources/views/Code/phpunit-boot-cv.php.php~ˆ  §}ådˆ  ˆ%ßm¤      A   src/CRM/CivixBundle/Resources/views/Code/entity-api3-test.php.php|  §}åd|  JToX¤      8   src/CRM/CivixBundle/Resources/views/Code/civicrm.css.php}  §}åd}  Þ�Æ_¤      ;   src/CRM/CivixBundle/Resources/views/Code/angular-dir.js.php¾  §}åd¾  ÇÒ¬f¤      4   src/CRM/CivixBundle/Resources/views/Code/api.php.phpT  §}ådT  <¥¤      :   src/CRM/CivixBundle/Resources/views/Code/case-type.xml.phpJ  §}ådJ  ìGÇw¤      9   src/CRM/CivixBundle/Resources/views/Code/test-api.php.phpù  §}ådù  xŒ‡¤      @   src/CRM/CivixBundle/Resources/views/Code/phpunit-boot-cv.php.phpX  §}ådX  ¾vž¦¤      7   src/CRM/CivixBundle/Resources/views/Code/readme.md.php~æ  §}ådæ  ƒWýž¤      <   src/CRM/CivixBundle/Resources/views/Code/test-legacy.php.php�  §}åd�  Nf¨U¤      7   src/CRM/CivixBundle/Resources/views/Code/report.tpl.phpB   §}ådB   …ÞGã¤      >   src/CRM/CivixBundle/Resources/views/Code/upgrader-base.php.php½(  §}åd½(  ÂÚÐŒ¤      6   src/CRM/CivixBundle/Resources/views/Code/readme.md.php  §}åd  \ÌºD¤      =   src/CRM/CivixBundle/Resources/views/Code/angular-dir.html.phpw   §}ådw   Œ™SÍ¤      =   src/CRM/CivixBundle/Resources/views/Code/phpunit-boot.php.phpW  §}ådW  NÛ¡Á¤      >   src/CRM/CivixBundle/Resources/views/Code/entity-api3-test.php~  §}åd  Û�À ¤      ?   src/CRM/CivixBundle/Resources/views/Code/angular-module.css.phpN   §}ådN   ´È3¤      >   src/CRM/CivixBundle/Resources/views/Code/angular-module.js.phpÆ   §}ådÆ   @¸º«¤      :   src/CRM/CivixBundle/Resources/translations/messages.fr.xlfu  §}ådu  0…K`¤      +   src/CRM/CivixBundle/Resources/doc/index.rst    §}åd        ¤      (   src/CRM/CivixBundle/Utils/Formatting.php  §}åd  ËÙøW¤      (   src/CRM/CivixBundle/Utils/Versioning.phpå  §}ådå  HºEû¤      #   src/CRM/CivixBundle/Utils/Files.phpj
  §}ådj
  èyç¤      "   src/CRM/CivixBundle/Utils/Path.phpn	  §}ådn	  C„ôq¤      $   src/CRM/CivixBundle/Utils/EvilEx.phpv  §}ådv  	…Ö¤      (   src/CRM/CivixBundle/Utils/NamingTest.phpƒ  §}ådƒ  Z¼·Q¤      '   src/CRM/CivixBundle/Utils/Functions.php‹  §}åd‹  ‹Ì{¤      $   src/CRM/CivixBundle/Utils/Naming.phps  §}åds  ‡€¨Á¤      &   src/CRM/CivixBundle/Utils/Commands.phpŸ  §}ådŸ  žè ¸¤      #   src/CRM/CivixBundle/UpgradeList.phpF  §}ådF  šÞ3@¤         src/CRM/CivixBundle/Builder.php  §}åd  M³íl¤      .   src/CRM/CivixBundle/SkippedMethodException.php^   §}åd^   	2#u¤      #   src/CRM/CivixBundle/Application.php`  §}åd`  š×!¤      '   src/CRM/CivixBundle/ComposerCompile.phpj  §}ådj  *‡`¤      8   src/CRM/CivixBundle/Builder/PHPUnitGenerateInitFiles.phpð  §}ådð  þø¤      -   src/CRM/CivixBundle/Builder/CustomDataXML.phpM  §}ådM  áÚ�Ñ¤      '   src/CRM/CivixBundle/Builder/License.phpË  §}ådË  z3¤      (   src/CRM/CivixBundle/Builder/Template.php:  §}åd:  £'i¤      &   src/CRM/CivixBundle/Builder/Mixins.php,%  §}åd,%  ¹t¿¹¤      #   src/CRM/CivixBundle/Builder/Ini.phpn  §}ådn  ;?Ÿ‘¤      )   src/CRM/CivixBundle/Builder/CopyClass.phpH  §}ådH  ¿‹g¤      *   src/CRM/CivixBundle/Builder/Collection.php˜  §}åd˜  ÷)`J¤      (   src/CRM/CivixBundle/Builder/CopyFile.phpB  §}ådB  ºð ¤      $   src/CRM/CivixBundle/Builder/Dirs.php  §}åd  ¥-•,¤      #   src/CRM/CivixBundle/Builder/XML.php5  §}åd5  ®ü¥¤      $   src/CRM/CivixBundle/Builder/Info.php‚$  §}åd‚$  ‘‚kW¤      $   src/CRM/CivixBundle/Builder/Menu.php÷  §}åd÷  ŸÓ=c¤      *   src/CRM/CivixBundle/Builder/PhpUnitXML.phpõ  §}ådõ  t´öM¤      &   src/CRM/CivixBundle/Builder/Module.phpÆ  §}ådÆ  6’ÀÐ¤      '   src/CRM/CivixBundle/Builder/PhpData.php½  §}åd½  �h¤          src/CRM/CivixBundle/Upgrader.phpA@  §}ådA@  …"8¤          src/CRM/CivixBundle/Services.phpÃ  §}ådÃ  CM|r¤      ,   src/CRM/CivixBundle/Command/MixinCommand.phpÛ  §}ådÛ  r't¤      :   src/CRM/CivixBundle/Command/AddAngularDirectiveCommand.php˜  §}åd˜  �4]¥¤      0   src/CRM/CivixBundle/Command/AddSearchCommand.php¤  §}åd¤  ¢ß›Ä¤      7   src/CRM/CivixBundle/Command/AddAngularModuleCommand.phpf  §}ådf  mžÇn¤      ,   src/CRM/CivixBundle/Command/BuildCommand.phpÚ  §}ådÚ  î²i§¤      4   src/CRM/CivixBundle/Command/AddCustomDataCommand.php³  §}åd³  O¥£¤      +   src/CRM/CivixBundle/Command/InitCommand.php,  §}åd,  •fîÒ¤      /   src/CRM/CivixBundle/Command/AbstractCommand.php€  §}åd€  j”·Ü¤      .   src/CRM/CivixBundle/Command/UpgradeCommand.phpI  §}ådI  ]Üÿ¼¤      -   src/CRM/CivixBundle/Command/AddApiCommand.phpÅ  §}ådÅ  ÃOH¤      .   src/CRM/CivixBundle/Command/InfoGetCommand.phpn  §}ådn  °(/§¤      .   src/CRM/CivixBundle/Command/TestRunCommand.php#  §}åd#  _à:%¤      .   src/CRM/CivixBundle/Command/InfoSetCommand.php}  §}åd}  ŸÜD¤      5   src/CRM/CivixBundle/Command/AddAngularPageCommand.phpì  §}ådì  íÇ”¤      0   src/CRM/CivixBundle/Command/ConfigSetCommand.php]  §}åd]  AP�Â¤      6   src/CRM/CivixBundle/Command/AddAngularPageCommand.php~  §}åd  )1e¤      0   src/CRM/CivixBundle/Command/AddEntityCommand.phpþ  §}ådþ  ¿y¤      /   src/CRM/CivixBundle/Command/AddThemeCommand.phpØ  §}ådØ  ò›ZR¤      .   src/CRM/CivixBundle/Command/AddFormCommand.phpÉ  §}ådÉ   Í%¤      ;   src/CRM/CivixBundle/Command/AddEntityBoilerplateCommand.phpG&  §}ådG&  =ªöT¤      2   src/CRM/CivixBundle/Command/AddCaseTypeCommand.phps
  §}åds
  7wÏ–¤      .   src/CRM/CivixBundle/Command/AddTestCommand.php^  §}åd^  Âu=¤      +   src/CRM/CivixBundle/Command/PingCommand.phpp  §}ådp  ëµïV¤      0   src/CRM/CivixBundle/Command/ConfigGetCommand.phpÆ  §}ådÆ  ÃÔ¦¤      6   src/CRM/CivixBundle/Command/AbstractAddPageCommand.php  §}åd  $èD¤      ;   src/CRM/CivixBundle/Command/AddAngularDirectiveCommand.php~W  §}ådW  KLÏ�¤      .   src/CRM/CivixBundle/Command/AddPageCommand.php±  §}åd±  �dÌ–¤      2   src/CRM/CivixBundle/Command/AddUpgraderCommand.phpæ  §}ådæ  ´«œ¤      0   src/CRM/CivixBundle/Command/AddReportCommand.php¥  §}åd¥  ½K¤         mixin-backports.php   §}åd   £œƒ¤         upgrades/22.10.0.up.phpJ  §}ådJ  à—“¤         upgrades/19.06.2.up.php©  §}åd©  h•ï¤         upgrades/22.12.1.up.phpÞ  §}ådÞ  y;˜¤         upgrades/22.05.2.up.phpœ
  §}ådœ
  Aã§¤         upgrades/23.02.1.up.phpÙ  §}ådÙ  Î	2�¤         upgrades/22.05.0.up.phpo  §}ådo  Ç†2¤         upgrades/23.01.0.up.phpV  §}ådV  ý‰¨B¤         upgrades/20.06.0.up.phpA  §}ådA  ŒÆ�s¤         upgrades/16.10.0.up.phpÈ  §}ådÈ  ~¦R«¤         upgrades/23.02.0.up.php$  §}åd$  òïŽ®¤      (   .box/vendor/composer/autoload_static.phpu  §}ådu  sgÇf¤      &   .box/vendor/composer/autoload_real.php   §}åd   ïƒ ¤      "   .box/vendor/composer/installed.phpÀ3  §}ådÀ3  KÂ‹¤      *   .box/vendor/composer/autoload_classmap.php’
  §}åd’
   =rë¤      &   .box/vendor/composer/autoload_psr4.php*  §}åd*  ÄG)¤      ,   .box/vendor/composer/semver/src/Interval.phpÎ  §}ådÎ  "à(l¤      1   .box/vendor/composer/semver/src/VersionParser.php1;  §}åd1;  6¶ v¤      4   .box/vendor/composer/semver/src/Constraint/Bound.phpn  §}ådn  ÈåÏ¤      9   .box/vendor/composer/semver/src/Constraint/Constraint.phpì&  §}ådì&  Sho¤      >   .box/vendor/composer/semver/src/Constraint/MultiConstraint.phpX  §}ådX  mt$õ¤      B   .box/vendor/composer/semver/src/Constraint/MatchNoneConstraint.phpY  §}ådY  °ÌÒ¤      A   .box/vendor/composer/semver/src/Constraint/MatchAllConstraint.php;  §}åd;  J€,È¤      B   .box/vendor/composer/semver/src/Constraint/ConstraintInterface.php¯  §}åd¯  tê$¤      .   .box/vendor/composer/semver/src/Comparator.php•  §}åd•  ÓP_2¤      *   .box/vendor/composer/semver/src/Semver.php‚  §}åd‚  Å!ä¡¤      -   .box/vendor/composer/semver/src/Intervals.phpþ9  §}ådþ9  –TÅ@¤      4   .box/vendor/composer/semver/src/CompilingMatcher.phpÉ  §}ådÉ  ¢‘´¤      #   .box/vendor/composer/semver/LICENSE  §}åd  Bhí¤      *   .box/vendor/composer/InstalledVersions.phpi  §}ådi  V±Ê4¤      $   .box/vendor/composer/ClassLoader.php�@  §}åd�@  >]×¤         .box/vendor/composer/LICENSE.  §}åd.   Õ¤      ,   .box/vendor/composer/autoload_namespaces.php‹   §}åd‹   Š/t¤         .box/vendor/autoload.phpï  §}ådï  .ó¸´¤         .box/src/Checker.php  §}åd  N(j£¤         .box/src/Printer.php¾  §}åd¾  +î¤         .box/src/Terminal.php9  §}åd9  hLƒr¤         .box/src/IO.php£  §}åd£  cŸb¤      "   .box/src/IsPhpVersionFulfilled.php‹  §}åd‹  Ê_×é¤         .box/src/Requirement.php¿  §}åd¿  m%Z¤      )   .box/src/IsExtensionConflictFulfilled.phpÍ  §}ådÍ  ¼�]¤      !   .box/src/IsExtensionFulfilled.php»  §}åd»  Ç#ì¼¤      "   .box/src/RequirementCollection.phpþ  §}ådþ  iä…g¤         .box/src/IsFulfilled.php–   §}åd–   R§‚¤         .box/.requirements.phpz  §}ådz  Nj‘¤         .box/bin/check-requirements.phpú  §}ådú  �MÔÚ¤         tmp/mixin-backports.php   §}åd   £œƒ¤         tmp/tmp/mixin-backports.php   §}åd   £œƒ¤         tmp/tmp/tmp/mixin-backports.php   §}åd   £œƒ¤      	   bin/civixx  §}ådx  å*!¤      <?php

/**
 * @license http://www.opensource.org/licenses/mit-license.php MIT (see the LICENSE file)
 */
namespace CivixPhar\Psr\Container;

/**
 * Describes the interface of a container that exposes methods to read its entries.
 */
interface ContainerInterface
{
    /**
     * Finds an entry of the container by its identifier and returns it.
     *
     * @param string $id Identifier of the entry to look for.
     *
     * @throws NotFoundExceptionInterface  No entry was found for **this** identifier.
     * @throws ContainerExceptionInterface Error while retrieving the entry.
     *
     * @return mixed Entry.
     */
    public function get($id);
    /**
     * Returns true if the container can return an entry for the given identifier.
     * Returns false otherwise.
     *
     * `has($id)` returning true does not mean that `get($id)` will not throw an exception.
     * It does however mean that `get($id)` will not throw a `NotFoundExceptionInterface`.
     *
     * @param string $id Identifier of the entry to look for.
     *
     * @return bool
     */
    public function has($id);
}
<?php

/**
 * @license http://www.opensource.org/licenses/mit-license.php MIT (see the LICENSE file)
 */
namespace CivixPhar\Psr\Container;

/**
 * No entry was found in the container.
 */
interface NotFoundExceptionInterface extends ContainerExceptionInterface
{
}
<?php

/**
 * @license http://www.opensource.org/licenses/mit-license.php MIT (see the LICENSE file)
 */
namespace CivixPhar\Psr\Container;

/**
 * Base interface representing a generic exception in a container.
 */
interface ContainerExceptionInterface
{
}
<?php

// autoload_static.php @generated by Composer

namespace Composer\Autoload;

class ComposerStaticInit3099b3329d998f64461a08224d3887b9
{
    public static $files = array (
        'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
        '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
        '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
        '25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php',
        '0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php',
        '667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php',
    );

    public static $prefixLengthsPsr4 = array (
        'C' => 
        array (
            'CivixPhar\\Symfony\\Polyfill\\Php80\\' => 33,
            'CivixPhar\\Symfony\\Polyfill\\Php73\\' => 33,
            'CivixPhar\\Symfony\\Polyfill\\Php72\\' => 33,
            'CivixPhar\\Symfony\\Polyfill\\Mbstring\\' => 36,
            'CivixPhar\\Symfony\\Polyfill\\Ctype\\' => 33,
            'CivixPhar\\Symfony\\Contracts\\Service\\' => 36,
            'CivixPhar\\Symfony\\Component\\VarExporter\\' => 40,
            'CivixPhar\\Symfony\\Component\\VarDumper\\' => 38,
            'CivixPhar\\Symfony\\Component\\Templating\\' => 39,
            'CivixPhar\\Symfony\\Component\\Process\\' => 36,
            'CivixPhar\\Symfony\\Component\\Filesystem\\' => 39,
            'CivixPhar\\Symfony\\Component\\Console\\' => 36,
            'CivixPhar\\Psr\\Container\\' => 24,
            'CivixPhar\\ProcessHelper\\' => 24,
            'CivixPhar\\Mixlib\\' => 17,
            'CivixPhar\\LicenseData\\' => 22,
            'CivixPhar\\LastCall\\DownloadsPlugin\\' => 35,
            'Civi\\Cv\\' => 8,
            'CRM\\CivixBundle\\' => 16,
        ),
    );

    public static $prefixDirsPsr4 = array (
        'CivixPhar\\Symfony\\Polyfill\\Php80\\' => 
        array (
            0 => __DIR__ . '/..' . '/symfony/polyfill-php80',
        ),
        'CivixPhar\\Symfony\\Polyfill\\Php73\\' => 
        array (
            0 => __DIR__ . '/..' . '/symfony/polyfill-php73',
        ),
        'CivixPhar\\Symfony\\Polyfill\\Php72\\' => 
        array (
            0 => __DIR__ . '/..' . '/symfony/polyfill-php72',
        ),
        'CivixPhar\\Symfony\\Polyfill\\Mbstring\\' => 
        array (
            0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
        ),
        'CivixPhar\\Symfony\\Polyfill\\Ctype\\' => 
        array (
            0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',
        ),
        'CivixPhar\\Symfony\\Contracts\\Service\\' => 
        array (
            0 => __DIR__ . '/..' . '/symfony/service-contracts',
        ),
        'CivixPhar\\Symfony\\Component\\VarExporter\\' => 
        array (
            0 => __DIR__ . '/..' . '/symfony/var-exporter',
        ),
        'CivixPhar\\Symfony\\Component\\VarDumper\\' => 
        array (
            0 => __DIR__ . '/..' . '/symfony/var-dumper',
        ),
        'CivixPhar\\Symfony\\Component\\Templating\\' => 
        array (
            0 => __DIR__ . '/..' . '/symfony/templating',
        ),
        'CivixPhar\\Symfony\\Component\\Process\\' => 
        array (
            0 => __DIR__ . '/..' . '/symfony/process',
        ),
        'CivixPhar\\Symfony\\Component\\Filesystem\\' => 
        array (
            0 => __DIR__ . '/..' . '/symfony/filesystem',
        ),
        'CivixPhar\\Symfony\\Component\\Console\\' => 
        array (
            0 => __DIR__ . '/..' . '/symfony/console',
        ),
        'CivixPhar\\Psr\\Container\\' => 
        array (
            0 => __DIR__ . '/..' . '/psr/container/src',
        ),
        'CivixPhar\\ProcessHelper\\' => 
        array (
            0 => __DIR__ . '/..' . '/totten/process-helper/src',
        ),
        'CivixPhar\\Mixlib\\' => 
        array (
            0 => __DIR__ . '/../..' . '/extern/src/Mixlib',
        ),
        'CivixPhar\\LicenseData\\' => 
        array (
            0 => __DIR__ . '/..' . '/totten/license-data/src/LicenseData',
        ),
        'CivixPhar\\LastCall\\DownloadsPlugin\\' => 
        array (
            0 => __DIR__ . '/..' . '/civicrm/composer-downloads-plugin/src',
        ),
        'Civi\\Cv\\' => 
        array (
            0 => __DIR__ . '/..' . '/civicrm/cv-lib/src',
        ),
        'CRM\\CivixBundle\\' => 
        array (
            0 => __DIR__ . '/../..' . '/src/CRM/CivixBundle',
        ),
    );

    public static $classMap = array (
        'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
        'CRM\\CivixBundle\\Application' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Application.php',
        'CRM\\CivixBundle\\Builder' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Builder.php',
        'CRM\\CivixBundle\\Builder\\Collection' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Builder/Collection.php',
        'CRM\\CivixBundle\\Builder\\CopyClass' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Builder/CopyClass.php',
        'CRM\\CivixBundle\\Builder\\CopyFile' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Builder/CopyFile.php',
        'CRM\\CivixBundle\\Builder\\CustomDataXML' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Builder/CustomDataXML.php',
        'CRM\\CivixBundle\\Builder\\Dirs' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Builder/Dirs.php',
        'CRM\\CivixBundle\\Builder\\Info' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Builder/Info.php',
        'CRM\\CivixBundle\\Builder\\Ini' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Builder/Ini.php',
        'CRM\\CivixBundle\\Builder\\License' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Builder/License.php',
        'CRM\\CivixBundle\\Builder\\Menu' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Builder/Menu.php',
        'CRM\\CivixBundle\\Builder\\Mixins' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Builder/Mixins.php',
        'CRM\\CivixBundle\\Builder\\Module' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Builder/Module.php',
        'CRM\\CivixBundle\\Builder\\PHPUnitGenerateInitFiles' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Builder/PHPUnitGenerateInitFiles.php',
        'CRM\\CivixBundle\\Builder\\PhpData' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Builder/PhpData.php',
        'CRM\\CivixBundle\\Builder\\PhpUnitXML' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Builder/PhpUnitXML.php',
        'CRM\\CivixBundle\\Builder\\Template' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Builder/Template.php',
        'CRM\\CivixBundle\\Builder\\XML' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Builder/XML.php',
        'CRM\\CivixBundle\\Command\\AbstractAddPageCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/AbstractAddPageCommand.php',
        'CRM\\CivixBundle\\Command\\AbstractCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/AbstractCommand.php',
        'CRM\\CivixBundle\\Command\\AddAngularDirectiveCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/AddAngularDirectiveCommand.php',
        'CRM\\CivixBundle\\Command\\AddAngularModuleCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/AddAngularModuleCommand.php',
        'CRM\\CivixBundle\\Command\\AddAngularPageCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/AddAngularPageCommand.php',
        'CRM\\CivixBundle\\Command\\AddApiCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/AddApiCommand.php',
        'CRM\\CivixBundle\\Command\\AddCaseTypeCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/AddCaseTypeCommand.php',
        'CRM\\CivixBundle\\Command\\AddCustomDataCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/AddCustomDataCommand.php',
        'CRM\\CivixBundle\\Command\\AddEntityBoilerplateCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/AddEntityBoilerplateCommand.php',
        'CRM\\CivixBundle\\Command\\AddEntityCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/AddEntityCommand.php',
        'CRM\\CivixBundle\\Command\\AddFormCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/AddFormCommand.php',
        'CRM\\CivixBundle\\Command\\AddPageCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/AddPageCommand.php',
        'CRM\\CivixBundle\\Command\\AddReportCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/AddReportCommand.php',
        'CRM\\CivixBundle\\Command\\AddSearchCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/AddSearchCommand.php',
        'CRM\\CivixBundle\\Command\\AddTestCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/AddTestCommand.php',
        'CRM\\CivixBundle\\Command\\AddThemeCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/AddThemeCommand.php',
        'CRM\\CivixBundle\\Command\\AddUpgraderCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/AddUpgraderCommand.php',
        'CRM\\CivixBundle\\Command\\BuildCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/BuildCommand.php',
        'CRM\\CivixBundle\\Command\\ConfigGetCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/ConfigGetCommand.php',
        'CRM\\CivixBundle\\Command\\ConfigSetCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/ConfigSetCommand.php',
        'CRM\\CivixBundle\\Command\\InfoGetCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/InfoGetCommand.php',
        'CRM\\CivixBundle\\Command\\InfoSetCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/InfoSetCommand.php',
        'CRM\\CivixBundle\\Command\\InitCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/InitCommand.php',
        'CRM\\CivixBundle\\Command\\MixinCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/MixinCommand.php',
        'CRM\\CivixBundle\\Command\\PingCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/PingCommand.php',
        'CRM\\CivixBundle\\Command\\TestRunCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/TestRunCommand.php',
        'CRM\\CivixBundle\\Command\\UpgradeCommand' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Command/UpgradeCommand.php',
        'CRM\\CivixBundle\\ComposerCompile' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/ComposerCompile.php',
        'CRM\\CivixBundle\\RunMethodsTrait' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/RunMethodsTrait.php',
        'CRM\\CivixBundle\\Services' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Services.php',
        'CRM\\CivixBundle\\SkippedMethodException' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/SkippedMethodException.php',
        'CRM\\CivixBundle\\UpgradeList' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/UpgradeList.php',
        'CRM\\CivixBundle\\Upgrader' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Upgrader.php',
        'CRM\\CivixBundle\\Utils\\Commands' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Utils/Commands.php',
        'CRM\\CivixBundle\\Utils\\EvilEx' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Utils/EvilEx.php',
        'CRM\\CivixBundle\\Utils\\Files' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Utils/Files.php',
        'CRM\\CivixBundle\\Utils\\Formatting' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Utils/Formatting.php',
        'CRM\\CivixBundle\\Utils\\Functions' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Utils/Functions.php',
        'CRM\\CivixBundle\\Utils\\Naming' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Utils/Naming.php',
        'CRM\\CivixBundle\\Utils\\NamingTest' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Utils/NamingTest.php',
        'CRM\\CivixBundle\\Utils\\Path' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Utils/Path.php',
        'CRM\\CivixBundle\\Utils\\Versioning' => __DIR__ . '/../..' . '/src/CRM/CivixBundle/Utils/Versioning.php',
        'Civi\\Cv\\Bootstrap' => __DIR__ . '/..' . '/civicrm/cv-lib/src/Bootstrap.php',
        'Civi\\Cv\\BuildkitReader' => __DIR__ . '/..' . '/civicrm/cv-lib/src/BuildkitReader.php',
        'Civi\\Cv\\CmsBootstrap' => __DIR__ . '/..' . '/civicrm/cv-lib/src/CmsBootstrap.php',
        'Civi\\Cv\\Config' => __DIR__ . '/..' . '/civicrm/cv-lib/src/Config.php',
        'Civi\\Cv\\ErrorHandler' => __DIR__ . '/..' . '/civicrm/cv-lib/src/ErrorHandler.php',
        'Civi\\Cv\\Log\\InternalLogger' => __DIR__ . '/..' . '/civicrm/cv-lib/src/Log/InternalLogger.php',
        'Civi\\Cv\\Log\\Logger' => __DIR__ . '/..' . '/civicrm/cv-lib/src/Log/Logger.php',
        'Civi\\Cv\\Log\\StderrLogger' => __DIR__ . '/..' . '/civicrm/cv-lib/src/Log/StderrLogger.php',
        'Civi\\Cv\\Log\\SymfonyConsoleLogger' => __DIR__ . '/..' . '/civicrm/cv-lib/src/Log/SymfonyConsoleLogger.php',
        'Civi\\Cv\\PharOut\\PharOut' => __DIR__ . '/..' . '/civicrm/cv-lib/src/PharOut/PharOut.php',
        'Civi\\Cv\\PharOut\\PharPolicyTrait' => __DIR__ . '/..' . '/civicrm/cv-lib/src/PharOut/PharPolicyTrait.php',
        'Civi\\Cv\\SiteConfigReader' => __DIR__ . '/..' . '/civicrm/cv-lib/src/SiteConfigReader.php',
        'Civi\\Cv\\Util\\BootTrait' => __DIR__ . '/..' . '/civicrm/cv-lib/src/Util/BootTrait.php',
        'Civi\\Cv\\Util\\Filesystem' => __DIR__ . '/..' . '/civicrm/cv-lib/src/Util/Filesystem.php',
        'Civi\\Cv\\Util\\FilesystemTrait' => __DIR__ . '/..' . '/civicrm/cv-lib/src/Util/FilesystemTrait.php',
        'CivixPhar\\JsonException' => __DIR__ . '/..' . '/symfony/polyfill-php73/Resources/stubs/JsonException.php',
        'CivixPhar\\LastCall\\DownloadsPlugin\\DownloadsParser' => __DIR__ . '/..' . '/civicrm/composer-downloads-plugin/src/DownloadsParser.php',
        'CivixPhar\\LastCall\\DownloadsPlugin\\GlobCleaner' => __DIR__ . '/..' . '/civicrm/composer-downloads-plugin/src/GlobCleaner.php',
        'CivixPhar\\LastCall\\DownloadsPlugin\\Handler\\ArchiveHandler' => __DIR__ . '/..' . '/civicrm/composer-downloads-plugin/src/Handler/ArchiveHandler.php',
        'CivixPhar\\LastCall\\DownloadsPlugin\\Handler\\BaseHandler' => __DIR__ . '/..' . '/civicrm/composer-downloads-plugin/src/Handler/BaseHandler.php',
        'CivixPhar\\LastCall\\DownloadsPlugin\\Handler\\FileHandler' => __DIR__ . '/..' . '/civicrm/composer-downloads-plugin/src/Handler/FileHandler.php',
        'CivixPhar\\LastCall\\DownloadsPlugin\\Handler\\PharHandler' => __DIR__ . '/..' . '/civicrm/composer-downloads-plugin/src/Handler/PharHandler.php',
        'CivixPhar\\LastCall\\DownloadsPlugin\\Plugin' => __DIR__ . '/..' . '/civicrm/composer-downloads-plugin/src/Plugin.php',
        'CivixPhar\\LastCall\\DownloadsPlugin\\Subpackage' => __DIR__ . '/..' . '/civicrm/composer-downloads-plugin/src/Subpackage.php',
        'CivixPhar\\LicenseData\\License' => __DIR__ . '/..' . '/totten/license-data/src/LicenseData/License.php',
        'CivixPhar\\LicenseData\\Repository' => __DIR__ . '/..' . '/totten/license-data/src/LicenseData/Repository.php',
        'CivixPhar\\ProcessHelper\\ProcessErrorException' => __DIR__ . '/..' . '/totten/process-helper/src/ProcessErrorException.php',
        'CivixPhar\\ProcessHelper\\ProcessHelper' => __DIR__ . '/..' . '/totten/process-helper/src/ProcessHelper.php',
        'CivixPhar\\Psr\\Container\\ContainerExceptionInterface' => __DIR__ . '/..' . '/psr/container/src/ContainerExceptionInterface.php',
        'CivixPhar\\Psr\\Container\\ContainerInterface' => __DIR__ . '/..' . '/psr/container/src/ContainerInterface.php',
        'CivixPhar\\Psr\\Container\\NotFoundExceptionInterface' => __DIR__ . '/..' . '/psr/container/src/NotFoundExceptionInterface.php',
        'CivixPhar\\Symfony\\Component\\Console\\Application' => __DIR__ . '/..' . '/symfony/console/Application.php',
        'CivixPhar\\Symfony\\Component\\Console\\CommandLoader\\CommandLoaderInterface' => __DIR__ . '/..' . '/symfony/console/CommandLoader/CommandLoaderInterface.php',
        'CivixPhar\\Symfony\\Component\\Console\\CommandLoader\\ContainerCommandLoader' => __DIR__ . '/..' . '/symfony/console/CommandLoader/ContainerCommandLoader.php',
        'CivixPhar\\Symfony\\Component\\Console\\CommandLoader\\FactoryCommandLoader' => __DIR__ . '/..' . '/symfony/console/CommandLoader/FactoryCommandLoader.php',
        'CivixPhar\\Symfony\\Component\\Console\\Command\\Command' => __DIR__ . '/..' . '/symfony/console/Command/Command.php',
        'CivixPhar\\Symfony\\Component\\Console\\Command\\HelpCommand' => __DIR__ . '/..' . '/symfony/console/Command/HelpCommand.php',
        'CivixPhar\\Symfony\\Component\\Console\\Command\\ListCommand' => __DIR__ . '/..' . '/symfony/console/Command/ListCommand.php',
        'CivixPhar\\Symfony\\Component\\Console\\Command\\LockableTrait' => __DIR__ . '/..' . '/symfony/console/Command/LockableTrait.php',
        'CivixPhar\\Symfony\\Component\\Console\\ConsoleEvents' => __DIR__ . '/..' . '/symfony/console/ConsoleEvents.php',
        'CivixPhar\\Symfony\\Component\\Console\\DependencyInjection\\AddConsoleCommandPass' => __DIR__ . '/..' . '/symfony/console/DependencyInjection/AddConsoleCommandPass.php',
        'CivixPhar\\Symfony\\Component\\Console\\Descriptor\\ApplicationDescription' => __DIR__ . '/..' . '/symfony/console/Descriptor/ApplicationDescription.php',
        'CivixPhar\\Symfony\\Component\\Console\\Descriptor\\Descriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/Descriptor.php',
        'CivixPhar\\Symfony\\Component\\Console\\Descriptor\\DescriptorInterface' => __DIR__ . '/..' . '/symfony/console/Descriptor/DescriptorInterface.php',
        'CivixPhar\\Symfony\\Component\\Console\\Descriptor\\JsonDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/JsonDescriptor.php',
        'CivixPhar\\Symfony\\Component\\Console\\Descriptor\\MarkdownDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/MarkdownDescriptor.php',
        'CivixPhar\\Symfony\\Component\\Console\\Descriptor\\TextDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/TextDescriptor.php',
        'CivixPhar\\Symfony\\Component\\Console\\Descriptor\\XmlDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/XmlDescriptor.php',
        'CivixPhar\\Symfony\\Component\\Console\\EventListener\\ErrorListener' => __DIR__ . '/..' . '/symfony/console/EventListener/ErrorListener.php',
        'CivixPhar\\Symfony\\Component\\Console\\Event\\ConsoleCommandEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleCommandEvent.php',
        'CivixPhar\\Symfony\\Component\\Console\\Event\\ConsoleErrorEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleErrorEvent.php',
        'CivixPhar\\Symfony\\Component\\Console\\Event\\ConsoleEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleEvent.php',
        'CivixPhar\\Symfony\\Component\\Console\\Event\\ConsoleTerminateEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleTerminateEvent.php',
        'CivixPhar\\Symfony\\Component\\Console\\Exception\\CommandNotFoundException' => __DIR__ . '/..' . '/symfony/console/Exception/CommandNotFoundException.php',
        'CivixPhar\\Symfony\\Component\\Console\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/console/Exception/ExceptionInterface.php',
        'CivixPhar\\Symfony\\Component\\Console\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/console/Exception/InvalidArgumentException.php',
        'CivixPhar\\Symfony\\Component\\Console\\Exception\\InvalidOptionException' => __DIR__ . '/..' . '/symfony/console/Exception/InvalidOptionException.php',
        'CivixPhar\\Symfony\\Component\\Console\\Exception\\LogicException' => __DIR__ . '/..' . '/symfony/console/Exception/LogicException.php',
        'CivixPhar\\Symfony\\Component\\Console\\Exception\\MissingInputException' => __DIR__ . '/..' . '/symfony/console/Exception/MissingInputException.php',
        'CivixPhar\\Symfony\\Component\\Console\\Exception\\NamespaceNotFoundException' => __DIR__ . '/..' . '/symfony/console/Exception/NamespaceNotFoundException.php',
        'CivixPhar\\Symfony\\Component\\Console\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/console/Exception/RuntimeException.php',
        'CivixPhar\\Symfony\\Component\\Console\\Formatter\\OutputFormatter' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatter.php',
        'CivixPhar\\Symfony\\Component\\Console\\Formatter\\OutputFormatterInterface' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatterInterface.php',
        'CivixPhar\\Symfony\\Component\\Console\\Formatter\\OutputFormatterStyle' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatterStyle.php',
        'CivixPhar\\Symfony\\Component\\Console\\Formatter\\OutputFormatterStyleInterface' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatterStyleInterface.php',
        'CivixPhar\\Symfony\\Component\\Console\\Formatter\\OutputFormatterStyleStack' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatterStyleStack.php',
        'CivixPhar\\Symfony\\Component\\Console\\Formatter\\WrappableOutputFormatterInterface' => __DIR__ . '/..' . '/symfony/console/Formatter/WrappableOutputFormatterInterface.php',
        'CivixPhar\\Symfony\\Component\\Console\\Helper\\DebugFormatterHelper' => __DIR__ . '/..' . '/symfony/console/Helper/DebugFormatterHelper.php',
        'CivixPhar\\Symfony\\Component\\Console\\Helper\\DescriptorHelper' => __DIR__ . '/..' . '/symfony/console/Helper/DescriptorHelper.php',
        'CivixPhar\\Symfony\\Component\\Console\\Helper\\Dumper' => __DIR__ . '/..' . '/symfony/console/Helper/Dumper.php',
        'CivixPhar\\Symfony\\Component\\Console\\Helper\\FormatterHelper' => __DIR__ . '/..' . '/symfony/console/Helper/FormatterHelper.php',
        'CivixPhar\\Symfony\\Component\\Console\\Helper\\Helper' => __DIR__ . '/..' . '/symfony/console/Helper/Helper.php',
        'CivixPhar\\Symfony\\Component\\Console\\Helper\\HelperInterface' => __DIR__ . '/..' . '/symfony/console/Helper/HelperInterface.php',
        'CivixPhar\\Symfony\\Component\\Console\\Helper\\HelperSet' => __DIR__ . '/..' . '/symfony/console/Helper/HelperSet.php',
        'CivixPhar\\Symfony\\Component\\Console\\Helper\\InputAwareHelper' => __DIR__ . '/..' . '/symfony/console/Helper/InputAwareHelper.php',
        'CivixPhar\\Symfony\\Component\\Console\\Helper\\ProcessHelper' => __DIR__ . '/..' . '/symfony/console/Helper/ProcessHelper.php',
        'CivixPhar\\Symfony\\Component\\Console\\Helper\\ProgressBar' => __DIR__ . '/..' . '/symfony/console/Helper/ProgressBar.php',
        'CivixPhar\\Symfony\\Component\\Console\\Helper\\ProgressIndicator' => __DIR__ . '/..' . '/symfony/console/Helper/ProgressIndicator.php',
        'CivixPhar\\Symfony\\Component\\Console\\Helper\\QuestionHelper' => __DIR__ . '/..' . '/symfony/console/Helper/QuestionHelper.php',
        'CivixPhar\\Symfony\\Component\\Console\\Helper\\SymfonyQuestionHelper' => __DIR__ . '/..' . '/symfony/console/Helper/SymfonyQuestionHelper.php',
        'CivixPhar\\Symfony\\Component\\Console\\Helper\\Table' => __DIR__ . '/..' . '/symfony/console/Helper/Table.php',
        'CivixPhar\\Symfony\\Component\\Console\\Helper\\TableCell' => __DIR__ . '/..' . '/symfony/console/Helper/TableCell.php',
        'CivixPhar\\Symfony\\Component\\Console\\Helper\\TableRows' => __DIR__ . '/..' . '/symfony/console/Helper/TableRows.php',
        'CivixPhar\\Symfony\\Component\\Console\\Helper\\TableSeparator' => __DIR__ . '/..' . '/symfony/console/Helper/TableSeparator.php',
        'CivixPhar\\Symfony\\Component\\Console\\Helper\\TableStyle' => __DIR__ . '/..' . '/symfony/console/Helper/TableStyle.php',
        'CivixPhar\\Symfony\\Component\\Console\\Input\\ArgvInput' => __DIR__ . '/..' . '/symfony/console/Input/ArgvInput.php',
        'CivixPhar\\Symfony\\Component\\Console\\Input\\ArrayInput' => __DIR__ . '/..' . '/symfony/console/Input/ArrayInput.php',
        'CivixPhar\\Symfony\\Component\\Console\\Input\\Input' => __DIR__ . '/..' . '/symfony/console/Input/Input.php',
        'CivixPhar\\Symfony\\Component\\Console\\Input\\InputArgument' => __DIR__ . '/..' . '/symfony/console/Input/InputArgument.php',
        'CivixPhar\\Symfony\\Component\\Console\\Input\\InputAwareInterface' => __DIR__ . '/..' . '/symfony/console/Input/InputAwareInterface.php',
        'CivixPhar\\Symfony\\Component\\Console\\Input\\InputDefinition' => __DIR__ . '/..' . '/symfony/console/Input/InputDefinition.php',
        'CivixPhar\\Symfony\\Component\\Console\\Input\\InputInterface' => __DIR__ . '/..' . '/symfony/console/Input/InputInterface.php',
        'CivixPhar\\Symfony\\Component\\Console\\Input\\InputOption' => __DIR__ . '/..' . '/symfony/console/Input/InputOption.php',
        'CivixPhar\\Symfony\\Component\\Console\\Input\\StreamableInputInterface' => __DIR__ . '/..' . '/symfony/console/Input/StreamableInputInterface.php',
        'CivixPhar\\Symfony\\Component\\Console\\Input\\StringInput' => __DIR__ . '/..' . '/symfony/console/Input/StringInput.php',
        'CivixPhar\\Symfony\\Component\\Console\\Logger\\ConsoleLogger' => __DIR__ . '/..' . '/symfony/console/Logger/ConsoleLogger.php',
        'CivixPhar\\Symfony\\Component\\Console\\Output\\BufferedOutput' => __DIR__ . '/..' . '/symfony/console/Output/BufferedOutput.php',
        'CivixPhar\\Symfony\\Component\\Console\\Output\\ConsoleOutput' => __DIR__ . '/..' . '/symfony/console/Output/ConsoleOutput.php',
        'CivixPhar\\Symfony\\Component\\Console\\Output\\ConsoleOutputInterface' => __DIR__ . '/..' . '/symfony/console/Output/ConsoleOutputInterface.php',
        'CivixPhar\\Symfony\\Component\\Console\\Output\\ConsoleSectionOutput' => __DIR__ . '/..' . '/symfony/console/Output/ConsoleSectionOutput.php',
        'CivixPhar\\Symfony\\Component\\Console\\Output\\NullOutput' => __DIR__ . '/..' . '/symfony/console/Output/NullOutput.php',
        'CivixPhar\\Symfony\\Component\\Console\\Output\\Output' => __DIR__ . '/..' . '/symfony/console/Output/Output.php',
        'CivixPhar\\Symfony\\Component\\Console\\Output\\OutputInterface' => __DIR__ . '/..' . '/symfony/console/Output/OutputInterface.php',
        'CivixPhar\\Symfony\\Component\\Console\\Output\\StreamOutput' => __DIR__ . '/..' . '/symfony/console/Output/StreamOutput.php',
        'CivixPhar\\Symfony\\Component\\Console\\Output\\TrimmedBufferOutput' => __DIR__ . '/..' . '/symfony/console/Output/TrimmedBufferOutput.php',
        'CivixPhar\\Symfony\\Component\\Console\\Question\\ChoiceQuestion' => __DIR__ . '/..' . '/symfony/console/Question/ChoiceQuestion.php',
        'CivixPhar\\Symfony\\Component\\Console\\Question\\ConfirmationQuestion' => __DIR__ . '/..' . '/symfony/console/Question/ConfirmationQuestion.php',
        'CivixPhar\\Symfony\\Component\\Console\\Question\\Question' => __DIR__ . '/..' . '/symfony/console/Question/Question.php',
        'CivixPhar\\Symfony\\Component\\Console\\Style\\OutputStyle' => __DIR__ . '/..' . '/symfony/console/Style/OutputStyle.php',
        'CivixPhar\\Symfony\\Component\\Console\\Style\\StyleInterface' => __DIR__ . '/..' . '/symfony/console/Style/StyleInterface.php',
        'CivixPhar\\Symfony\\Component\\Console\\Style\\SymfonyStyle' => __DIR__ . '/..' . '/symfony/console/Style/SymfonyStyle.php',
        'CivixPhar\\Symfony\\Component\\Console\\Terminal' => __DIR__ . '/..' . '/symfony/console/Terminal.php',
        'CivixPhar\\Symfony\\Component\\Console\\Tester\\ApplicationTester' => __DIR__ . '/..' . '/symfony/console/Tester/ApplicationTester.php',
        'CivixPhar\\Symfony\\Component\\Console\\Tester\\CommandTester' => __DIR__ . '/..' . '/symfony/console/Tester/CommandTester.php',
        'CivixPhar\\Symfony\\Component\\Console\\Tester\\TesterTrait' => __DIR__ . '/..' . '/symfony/console/Tester/TesterTrait.php',
        'CivixPhar\\Symfony\\Component\\Filesystem\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/filesystem/Exception/ExceptionInterface.php',
        'CivixPhar\\Symfony\\Component\\Filesystem\\Exception\\FileNotFoundException' => __DIR__ . '/..' . '/symfony/filesystem/Exception/FileNotFoundException.php',
        'CivixPhar\\Symfony\\Component\\Filesystem\\Exception\\IOException' => __DIR__ . '/..' . '/symfony/filesystem/Exception/IOException.php',
        'CivixPhar\\Symfony\\Component\\Filesystem\\Exception\\IOExceptionInterface' => __DIR__ . '/..' . '/symfony/filesystem/Exception/IOExceptionInterface.php',
        'CivixPhar\\Symfony\\Component\\Filesystem\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/filesystem/Exception/InvalidArgumentException.php',
        'CivixPhar\\Symfony\\Component\\Filesystem\\Filesystem' => __DIR__ . '/..' . '/symfony/filesystem/Filesystem.php',
        'CivixPhar\\Symfony\\Component\\Process\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/process/Exception/ExceptionInterface.php',
        'CivixPhar\\Symfony\\Component\\Process\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/process/Exception/InvalidArgumentException.php',
        'CivixPhar\\Symfony\\Component\\Process\\Exception\\LogicException' => __DIR__ . '/..' . '/symfony/process/Exception/LogicException.php',
        'CivixPhar\\Symfony\\Component\\Process\\Exception\\ProcessFailedException' => __DIR__ . '/..' . '/symfony/process/Exception/ProcessFailedException.php',
        'CivixPhar\\Symfony\\Component\\Process\\Exception\\ProcessSignaledException' => __DIR__ . '/..' . '/symfony/process/Exception/ProcessSignaledException.php',
        'CivixPhar\\Symfony\\Component\\Process\\Exception\\ProcessTimedOutException' => __DIR__ . '/..' . '/symfony/process/Exception/ProcessTimedOutException.php',
        'CivixPhar\\Symfony\\Component\\Process\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/process/Exception/RuntimeException.php',
        'CivixPhar\\Symfony\\Component\\Process\\ExecutableFinder' => __DIR__ . '/..' . '/symfony/process/ExecutableFinder.php',
        'CivixPhar\\Symfony\\Component\\Process\\InputStream' => __DIR__ . '/..' . '/symfony/process/InputStream.php',
        'CivixPhar\\Symfony\\Component\\Process\\PhpExecutableFinder' => __DIR__ . '/..' . '/symfony/process/PhpExecutableFinder.php',
        'CivixPhar\\Symfony\\Component\\Process\\PhpProcess' => __DIR__ . '/..' . '/symfony/process/PhpProcess.php',
        'CivixPhar\\Symfony\\Component\\Process\\Pipes\\AbstractPipes' => __DIR__ . '/..' . '/symfony/process/Pipes/AbstractPipes.php',
        'CivixPhar\\Symfony\\Component\\Process\\Pipes\\PipesInterface' => __DIR__ . '/..' . '/symfony/process/Pipes/PipesInterface.php',
        'CivixPhar\\Symfony\\Component\\Process\\Pipes\\UnixPipes' => __DIR__ . '/..' . '/symfony/process/Pipes/UnixPipes.php',
        'CivixPhar\\Symfony\\Component\\Process\\Pipes\\WindowsPipes' => __DIR__ . '/..' . '/symfony/process/Pipes/WindowsPipes.php',
        'CivixPhar\\Symfony\\Component\\Process\\Process' => __DIR__ . '/..' . '/symfony/process/Process.php',
        'CivixPhar\\Symfony\\Component\\Process\\ProcessUtils' => __DIR__ . '/..' . '/symfony/process/ProcessUtils.php',
        'CivixPhar\\Symfony\\Component\\Templating\\DelegatingEngine' => __DIR__ . '/..' . '/symfony/templating/DelegatingEngine.php',
        'CivixPhar\\Symfony\\Component\\Templating\\EngineInterface' => __DIR__ . '/..' . '/symfony/templating/EngineInterface.php',
        'CivixPhar\\Symfony\\Component\\Templating\\Helper\\Helper' => __DIR__ . '/..' . '/symfony/templating/Helper/Helper.php',
        'CivixPhar\\Symfony\\Component\\Templating\\Helper\\HelperInterface' => __DIR__ . '/..' . '/symfony/templating/Helper/HelperInterface.php',
        'CivixPhar\\Symfony\\Component\\Templating\\Helper\\SlotsHelper' => __DIR__ . '/..' . '/symfony/templating/Helper/SlotsHelper.php',
        'CivixPhar\\Symfony\\Component\\Templating\\Loader\\CacheLoader' => __DIR__ . '/..' . '/symfony/templating/Loader/CacheLoader.php',
        'CivixPhar\\Symfony\\Component\\Templating\\Loader\\ChainLoader' => __DIR__ . '/..' . '/symfony/templating/Loader/ChainLoader.php',
        'CivixPhar\\Symfony\\Component\\Templating\\Loader\\FilesystemLoader' => __DIR__ . '/..' . '/symfony/templating/Loader/FilesystemLoader.php',
        'CivixPhar\\Symfony\\Component\\Templating\\Loader\\Loader' => __DIR__ . '/..' . '/symfony/templating/Loader/Loader.php',
        'CivixPhar\\Symfony\\Component\\Templating\\Loader\\LoaderInterface' => __DIR__ . '/..' . '/symfony/templating/Loader/LoaderInterface.php',
        'CivixPhar\\Symfony\\Component\\Templating\\PhpEngine' => __DIR__ . '/..' . '/symfony/templating/PhpEngine.php',
        'CivixPhar\\Symfony\\Component\\Templating\\Storage\\FileStorage' => __DIR__ . '/..' . '/symfony/templating/Storage/FileStorage.php',
        'CivixPhar\\Symfony\\Component\\Templating\\Storage\\Storage' => __DIR__ . '/..' . '/symfony/templating/Storage/Storage.php',
        'CivixPhar\\Symfony\\Component\\Templating\\Storage\\StringStorage' => __DIR__ . '/..' . '/symfony/templating/Storage/StringStorage.php',
        'CivixPhar\\Symfony\\Component\\Templating\\StreamingEngineInterface' => __DIR__ . '/..' . '/symfony/templating/StreamingEngineInterface.php',
        'CivixPhar\\Symfony\\Component\\Templating\\TemplateNameParser' => __DIR__ . '/..' . '/symfony/templating/TemplateNameParser.php',
        'CivixPhar\\Symfony\\Component\\Templating\\TemplateNameParserInterface' => __DIR__ . '/..' . '/symfony/templating/TemplateNameParserInterface.php',
        'CivixPhar\\Symfony\\Component\\Templating\\TemplateReference' => __DIR__ . '/..' . '/symfony/templating/TemplateReference.php',
        'CivixPhar\\Symfony\\Component\\Templating\\TemplateReferenceInterface' => __DIR__ . '/..' . '/symfony/templating/TemplateReferenceInterface.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\AmqpCaster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/AmqpCaster.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ArgsStub' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/ArgsStub.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\Caster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/Caster.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ClassStub' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/ClassStub.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ConstStub' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/ConstStub.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\CutArrayStub' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/CutArrayStub.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\CutStub' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/CutStub.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DOMCaster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/DOMCaster.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DateCaster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/DateCaster.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DoctrineCaster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/DoctrineCaster.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DsCaster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/DsCaster.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DsPairStub' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/DsPairStub.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\EnumStub' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/EnumStub.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ExceptionCaster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/ExceptionCaster.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\FrameStub' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/FrameStub.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\GmpCaster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/GmpCaster.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ImagineCaster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/ImagineCaster.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ImgStub' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/ImgStub.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\IntlCaster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/IntlCaster.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\LinkStub' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/LinkStub.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\MemcachedCaster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/MemcachedCaster.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\PdoCaster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/PdoCaster.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\PgSqlCaster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/PgSqlCaster.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ProxyManagerCaster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/ProxyManagerCaster.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\RedisCaster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/RedisCaster.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ReflectionCaster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/ReflectionCaster.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ResourceCaster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/ResourceCaster.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\SplCaster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/SplCaster.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\StubCaster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/StubCaster.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\SymfonyCaster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/SymfonyCaster.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\TraceStub' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/TraceStub.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\UuidCaster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/UuidCaster.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\XmlReaderCaster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/XmlReaderCaster.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\XmlResourceCaster' => __DIR__ . '/..' . '/symfony/var-dumper/Caster/XmlResourceCaster.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Cloner\\AbstractCloner' => __DIR__ . '/..' . '/symfony/var-dumper/Cloner/AbstractCloner.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Cloner\\ClonerInterface' => __DIR__ . '/..' . '/symfony/var-dumper/Cloner/ClonerInterface.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Cloner\\Cursor' => __DIR__ . '/..' . '/symfony/var-dumper/Cloner/Cursor.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Cloner\\Data' => __DIR__ . '/..' . '/symfony/var-dumper/Cloner/Data.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Cloner\\DumperInterface' => __DIR__ . '/..' . '/symfony/var-dumper/Cloner/DumperInterface.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Cloner\\Stub' => __DIR__ . '/..' . '/symfony/var-dumper/Cloner/Stub.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Cloner\\VarCloner' => __DIR__ . '/..' . '/symfony/var-dumper/Cloner/VarCloner.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Command\\Descriptor\\CliDescriptor' => __DIR__ . '/..' . '/symfony/var-dumper/Command/Descriptor/CliDescriptor.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Command\\Descriptor\\DumpDescriptorInterface' => __DIR__ . '/..' . '/symfony/var-dumper/Command/Descriptor/DumpDescriptorInterface.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Command\\Descriptor\\HtmlDescriptor' => __DIR__ . '/..' . '/symfony/var-dumper/Command/Descriptor/HtmlDescriptor.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Command\\ServerDumpCommand' => __DIR__ . '/..' . '/symfony/var-dumper/Command/ServerDumpCommand.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Dumper\\AbstractDumper' => __DIR__ . '/..' . '/symfony/var-dumper/Dumper/AbstractDumper.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Dumper\\CliDumper' => __DIR__ . '/..' . '/symfony/var-dumper/Dumper/CliDumper.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Dumper\\ContextProvider\\CliContextProvider' => __DIR__ . '/..' . '/symfony/var-dumper/Dumper/ContextProvider/CliContextProvider.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Dumper\\ContextProvider\\ContextProviderInterface' => __DIR__ . '/..' . '/symfony/var-dumper/Dumper/ContextProvider/ContextProviderInterface.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Dumper\\ContextProvider\\RequestContextProvider' => __DIR__ . '/..' . '/symfony/var-dumper/Dumper/ContextProvider/RequestContextProvider.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Dumper\\ContextProvider\\SourceContextProvider' => __DIR__ . '/..' . '/symfony/var-dumper/Dumper/ContextProvider/SourceContextProvider.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Dumper\\ContextualizedDumper' => __DIR__ . '/..' . '/symfony/var-dumper/Dumper/ContextualizedDumper.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Dumper\\DataDumperInterface' => __DIR__ . '/..' . '/symfony/var-dumper/Dumper/DataDumperInterface.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Dumper\\HtmlDumper' => __DIR__ . '/..' . '/symfony/var-dumper/Dumper/HtmlDumper.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Dumper\\ServerDumper' => __DIR__ . '/..' . '/symfony/var-dumper/Dumper/ServerDumper.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Exception\\ThrowingCasterException' => __DIR__ . '/..' . '/symfony/var-dumper/Exception/ThrowingCasterException.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Server\\Connection' => __DIR__ . '/..' . '/symfony/var-dumper/Server/Connection.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\Server\\DumpServer' => __DIR__ . '/..' . '/symfony/var-dumper/Server/DumpServer.php',
        'CivixPhar\\Symfony\\Component\\VarDumper\\VarDumper' => __DIR__ . '/..' . '/symfony/var-dumper/VarDumper.php',
        'CivixPhar\\Symfony\\Component\\VarExporter\\Exception\\ClassNotFoundException' => __DIR__ . '/..' . '/symfony/var-exporter/Exception/ClassNotFoundException.php',
        'CivixPhar\\Symfony\\Component\\VarExporter\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/var-exporter/Exception/ExceptionInterface.php',
        'CivixPhar\\Symfony\\Component\\VarExporter\\Exception\\NotInstantiableTypeException' => __DIR__ . '/..' . '/symfony/var-exporter/Exception/NotInstantiableTypeException.php',
        'CivixPhar\\Symfony\\Component\\VarExporter\\Instantiator' => __DIR__ . '/..' . '/symfony/var-exporter/Instantiator.php',
        'CivixPhar\\Symfony\\Component\\VarExporter\\Internal\\Exporter' => __DIR__ . '/..' . '/symfony/var-exporter/Internal/Exporter.php',
        'CivixPhar\\Symfony\\Component\\VarExporter\\Internal\\Hydrator' => __DIR__ . '/..' . '/symfony/var-exporter/Internal/Hydrator.php',
        'CivixPhar\\Symfony\\Component\\VarExporter\\Internal\\Reference' => __DIR__ . '/..' . '/symfony/var-exporter/Internal/Reference.php',
        'CivixPhar\\Symfony\\Component\\VarExporter\\Internal\\Registry' => __DIR__ . '/..' . '/symfony/var-exporter/Internal/Registry.php',
        'CivixPhar\\Symfony\\Component\\VarExporter\\Internal\\Values' => __DIR__ . '/..' . '/symfony/var-exporter/Internal/Values.php',
        'CivixPhar\\Symfony\\Component\\VarExporter\\VarExporter' => __DIR__ . '/..' . '/symfony/var-exporter/VarExporter.php',
        'CivixPhar\\Symfony\\Contracts\\Service\\ResetInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ResetInterface.php',
        'CivixPhar\\Symfony\\Contracts\\Service\\ServiceLocatorTrait' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceLocatorTrait.php',
        'CivixPhar\\Symfony\\Contracts\\Service\\ServiceProviderInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceProviderInterface.php',
        'CivixPhar\\Symfony\\Contracts\\Service\\ServiceSubscriberInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceSubscriberInterface.php',
        'CivixPhar\\Symfony\\Contracts\\Service\\ServiceSubscriberTrait' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceSubscriberTrait.php',
        'CivixPhar\\Symfony\\Polyfill\\Ctype\\Ctype' => __DIR__ . '/..' . '/symfony/polyfill-ctype/Ctype.php',
        'CivixPhar\\Symfony\\Polyfill\\Mbstring\\Mbstring' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/Mbstring.php',
        'CivixPhar\\Symfony\\Polyfill\\Php72\\Php72' => __DIR__ . '/..' . '/symfony/polyfill-php72/Php72.php',
        'CivixPhar\\Symfony\\Polyfill\\Php73\\Php73' => __DIR__ . '/..' . '/symfony/polyfill-php73/Php73.php',
        'CivixPhar\\Symfony\\Polyfill\\Php80\\Php80' => __DIR__ . '/..' . '/symfony/polyfill-php80/Php80.php',
        'CivixPhar\\Symfony\\Polyfill\\Php80\\PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/PhpToken.php',
        'CivixPhar\\TOGoS_GitIgnore_FileFinder' => __DIR__ . '/..' . '/togos/gitignore/src/main/php/TOGoS/GitIgnore/FileFinder.php',
        'CivixPhar\\TOGoS_GitIgnore_Pattern' => __DIR__ . '/..' . '/togos/gitignore/src/main/php/TOGoS/GitIgnore/Pattern.php',
        'CivixPhar\\TOGoS_GitIgnore_Rule' => __DIR__ . '/..' . '/togos/gitignore/src/main/php/TOGoS/GitIgnore/Rule.php',
        'CivixPhar\\TOGoS_GitIgnore_Ruleset' => __DIR__ . '/..' . '/togos/gitignore/src/main/php/TOGoS/GitIgnore/Ruleset.php',
        'CivixPhar\\TOGoS_GitIgnore_Util' => __DIR__ . '/..' . '/togos/gitignore/src/main/php/TOGoS/GitIgnore/Util.php',
        'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
        'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
        'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
        'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
        'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
    );

    public static function getInitializer(ClassLoader $loader)
    {
        return \Closure::bind(function () use ($loader) {
            $loader->prefixLengthsPsr4 = ComposerStaticInit3099b3329d998f64461a08224d3887b9::$prefixLengthsPsr4;
            $loader->prefixDirsPsr4 = ComposerStaticInit3099b3329d998f64461a08224d3887b9::$prefixDirsPsr4;
            $loader->classMap = ComposerStaticInit3099b3329d998f64461a08224d3887b9::$classMap;

        }, null, ClassLoader::class);
    }
}
<?php

// autoload_real.php @generated by Composer

class ComposerAutoloaderInit3099b3329d998f64461a08224d3887b9
{
    private static $loader;

    public static function loadClassLoader($class)
    {
        if ('Composer\Autoload\ClassLoader' === $class) {
            require __DIR__ . '/ClassLoader.php';
        }
    }

    /**
     * @return \Composer\Autoload\ClassLoader
     */
    public static function getLoader()
    {
        if (null !== self::$loader) {
            return self::$loader;
        }

        require __DIR__ . '/platform_check.php';

        spl_autoload_register(array('ComposerAutoloaderInit3099b3329d998f64461a08224d3887b9', 'loadClassLoader'), true, true);
        self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
        spl_autoload_unregister(array('ComposerAutoloaderInit3099b3329d998f64461a08224d3887b9', 'loadClassLoader'));

        require __DIR__ . '/autoload_static.php';
        call_user_func(\Composer\Autoload\ComposerStaticInit3099b3329d998f64461a08224d3887b9::getInitializer($loader));

        $loader->setClassMapAuthoritative(true);
        $loader->register(true);

        $includeFiles = \Composer\Autoload\ComposerStaticInit3099b3329d998f64461a08224d3887b9::$files;
        foreach ($includeFiles as $fileIdentifier => $file) {
            composerRequire3099b3329d998f64461a08224d3887b9($fileIdentifier, $file);
        }

        return $loader;
    }
}

/**
 * @param string $fileIdentifier
 * @param string $file
 * @return void
 */
function composerRequire3099b3329d998f64461a08224d3887b9($fileIdentifier, $file)
{
    if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
        $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;

        require $file;
    }
}
<?php

namespace CivixPhar;

return array('root' => array('name' => 'civicrm/civix', 'pretty_version' => 'dev-master', 'version' => 'dev-master', 'reference' => '8d7509c5320eb8f5017c80080f214654d0659935', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev' => \false), 'versions' => array('civicrm/civix' => array('pretty_version' => 'dev-master', 'version' => 'dev-master', 'reference' => '8d7509c5320eb8f5017c80080f214654d0659935', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev_requirement' => \false), 'civicrm/composer-compile-plugin' => array('pretty_version' => 'v0.18', 'version' => '0.18.0.0', 'reference' => '158be6061320c2f481e1aa8f821be5c7e0eea220', 'type' => 'composer-plugin', 'install_path' => __DIR__ . '/../civicrm/composer-compile-plugin', 'aliases' => array(), 'dev_requirement' => \false), 'civicrm/composer-downloads-plugin' => array('pretty_version' => 'v3.0.1', 'version' => '3.0.1.0', 'reference' => '3aabb6d259a86158d01829fc2c62a2afb9618877', 'type' => 'composer-plugin', 'install_path' => __DIR__ . '/../civicrm/composer-downloads-plugin', 'aliases' => array(), 'dev_requirement' => \false), 'civicrm/cv-lib' => array('pretty_version' => 'v0.3.45', 'version' => '0.3.45.0', 'reference' => '40b85edaa8a1ceefe3230fe4cea8289ecc2ef9c7', 'type' => 'library', 'install_path' => __DIR__ . '/../civicrm/cv-lib', 'aliases' => array(), 'dev_requirement' => \false), 'henrikbjorn/lurker' => array('dev_requirement' => \false, 'replaced' => array(0 => '*')), 'psr/container' => array('pretty_version' => '1.0.0', 'version' => '1.0.0.0', 'reference' => 'b7ce3b176482dbbc1245ebf52b181af44c2cf55f', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/container', 'aliases' => array(), 'dev_requirement' => \false), 'psr/log-implementation' => array('dev_requirement' => \false, 'provided' => array(0 => '1.0|2.0')), 'symfony/console' => array('pretty_version' => 'v4.4.34', 'version' => '4.4.34.0', 'reference' => '329b3a75cc6b16d435ba1b1a41df54a53382a3f0', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/console', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/filesystem' => array('pretty_version' => 'v4.4.39', 'version' => '4.4.39.0', 'reference' => '72a5b35fecaa670b13954e6eaf414acbe2a67b35', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/filesystem', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/polyfill-ctype' => array('pretty_version' => 'v1.23.0', 'version' => '1.23.0.0', 'reference' => '46cd95797e9df938fdd2b03693b5fca5e64b01ce', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-ctype', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/polyfill-mbstring' => array('pretty_version' => 'v1.22.1', 'version' => '1.22.1.0', 'reference' => '5232de97ee3b75b0360528dae24e73db49566ab1', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/polyfill-php72' => array('pretty_version' => 'v1.22.1', 'version' => '1.22.1.0', 'reference' => 'cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-php72', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/polyfill-php73' => array('pretty_version' => 'v1.23.0', 'version' => '1.23.0.0', 'reference' => 'fba8933c384d6476ab14fb7b8526e5287ca7e010', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-php73', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/polyfill-php80' => array('pretty_version' => 'v1.27.0', 'version' => '1.27.0.0', 'reference' => '7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-php80', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/process' => array('pretty_version' => 'v4.4.35', 'version' => '4.4.35.0', 'reference' => 'c2098705326addae6e6742151dfade47ac71da1b', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/process', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/service-contracts' => array('pretty_version' => 'v1.1.11', 'version' => '1.1.11.0', 'reference' => '633df678bec3452e04a7b0337c9bcfe7354124b3', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/service-contracts', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/templating' => array('pretty_version' => 'v4.4.30', 'version' => '4.4.30.0', 'reference' => '43f2cd3cd55d9517a296f162fb8209ac7f1f0153', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/templating', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/var-dumper' => array('pretty_version' => 'v4.4.34', 'version' => '4.4.34.0', 'reference' => '2d0c056b2faaa3d785bdbd5adecc593a5be9c16e', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/var-dumper', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/var-exporter' => array('pretty_version' => 'v4.4.23', 'version' => '4.4.23.0', 'reference' => '11439b8e3264502293bd5e5ecd6957f70319f526', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/var-exporter', 'aliases' => array(), 'dev_requirement' => \false), 'togos/gitignore' => array('pretty_version' => '1.1.1', 'version' => '1.1.1.0', 'reference' => '32bc0830e4123f670adcbf5ddda5bef362f4f4d4', 'type' => 'library', 'install_path' => __DIR__ . '/../togos/gitignore', 'aliases' => array(), 'dev_requirement' => \false), 'totten/license-data' => array('pretty_version' => 'dev-master', 'version' => 'dev-master', 'reference' => '50c5d843de00af80774e89b8a4598a6a6d273b3a', 'type' => 'library', 'install_path' => __DIR__ . '/../totten/license-data', 'aliases' => array(0 => '9999999-dev'), 'dev_requirement' => \false), 'totten/lurkerlite' => array('pretty_version' => '1.3.0', 'version' => '1.3.0.0', 'reference' => 'a20c47142b486415b9117c76aa4c2117ff95b49a', 'type' => 'library', 'install_path' => __DIR__ . '/../totten/lurkerlite', 'aliases' => array(), 'dev_requirement' => \false), 'totten/process-helper' => array('pretty_version' => 'v1.0.1', 'version' => '1.0.1.0', 'reference' => '4cd78744c60ca8fff3a1a1e453e53a8e099d9c4e', 'type' => 'library', 'install_path' => __DIR__ . '/../totten/process-helper', 'aliases' => array(), 'dev_requirement' => \false)));
<?php

// autoload_classmap.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
    'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
    'CRM\\CivixBundle\\Application' => $baseDir . '/src/CRM/CivixBundle/Application.php',
    'CRM\\CivixBundle\\Builder' => $baseDir . '/src/CRM/CivixBundle/Builder.php',
    'CRM\\CivixBundle\\Builder\\Collection' => $baseDir . '/src/CRM/CivixBundle/Builder/Collection.php',
    'CRM\\CivixBundle\\Builder\\CopyClass' => $baseDir . '/src/CRM/CivixBundle/Builder/CopyClass.php',
    'CRM\\CivixBundle\\Builder\\CopyFile' => $baseDir . '/src/CRM/CivixBundle/Builder/CopyFile.php',
    'CRM\\CivixBundle\\Builder\\CustomDataXML' => $baseDir . '/src/CRM/CivixBundle/Builder/CustomDataXML.php',
    'CRM\\CivixBundle\\Builder\\Dirs' => $baseDir . '/src/CRM/CivixBundle/Builder/Dirs.php',
    'CRM\\CivixBundle\\Builder\\Info' => $baseDir . '/src/CRM/CivixBundle/Builder/Info.php',
    'CRM\\CivixBundle\\Builder\\Ini' => $baseDir . '/src/CRM/CivixBundle/Builder/Ini.php',
    'CRM\\CivixBundle\\Builder\\License' => $baseDir . '/src/CRM/CivixBundle/Builder/License.php',
    'CRM\\CivixBundle\\Builder\\Menu' => $baseDir . '/src/CRM/CivixBundle/Builder/Menu.php',
    'CRM\\CivixBundle\\Builder\\Mixins' => $baseDir . '/src/CRM/CivixBundle/Builder/Mixins.php',
    'CRM\\CivixBundle\\Builder\\Module' => $baseDir . '/src/CRM/CivixBundle/Builder/Module.php',
    'CRM\\CivixBundle\\Builder\\PHPUnitGenerateInitFiles' => $baseDir . '/src/CRM/CivixBundle/Builder/PHPUnitGenerateInitFiles.php',
    'CRM\\CivixBundle\\Builder\\PhpData' => $baseDir . '/src/CRM/CivixBundle/Builder/PhpData.php',
    'CRM\\CivixBundle\\Builder\\PhpUnitXML' => $baseDir . '/src/CRM/CivixBundle/Builder/PhpUnitXML.php',
    'CRM\\CivixBundle\\Builder\\Template' => $baseDir . '/src/CRM/CivixBundle/Builder/Template.php',
    'CRM\\CivixBundle\\Builder\\XML' => $baseDir . '/src/CRM/CivixBundle/Builder/XML.php',
    'CRM\\CivixBundle\\Command\\AbstractAddPageCommand' => $baseDir . '/src/CRM/CivixBundle/Command/AbstractAddPageCommand.php',
    'CRM\\CivixBundle\\Command\\AbstractCommand' => $baseDir . '/src/CRM/CivixBundle/Command/AbstractCommand.php',
    'CRM\\CivixBundle\\Command\\AddAngularDirectiveCommand' => $baseDir . '/src/CRM/CivixBundle/Command/AddAngularDirectiveCommand.php',
    'CRM\\CivixBundle\\Command\\AddAngularModuleCommand' => $baseDir . '/src/CRM/CivixBundle/Command/AddAngularModuleCommand.php',
    'CRM\\CivixBundle\\Command\\AddAngularPageCommand' => $baseDir . '/src/CRM/CivixBundle/Command/AddAngularPageCommand.php',
    'CRM\\CivixBundle\\Command\\AddApiCommand' => $baseDir . '/src/CRM/CivixBundle/Command/AddApiCommand.php',
    'CRM\\CivixBundle\\Command\\AddCaseTypeCommand' => $baseDir . '/src/CRM/CivixBundle/Command/AddCaseTypeCommand.php',
    'CRM\\CivixBundle\\Command\\AddCustomDataCommand' => $baseDir . '/src/CRM/CivixBundle/Command/AddCustomDataCommand.php',
    'CRM\\CivixBundle\\Command\\AddEntityBoilerplateCommand' => $baseDir . '/src/CRM/CivixBundle/Command/AddEntityBoilerplateCommand.php',
    'CRM\\CivixBundle\\Command\\AddEntityCommand' => $baseDir . '/src/CRM/CivixBundle/Command/AddEntityCommand.php',
    'CRM\\CivixBundle\\Command\\AddFormCommand' => $baseDir . '/src/CRM/CivixBundle/Command/AddFormCommand.php',
    'CRM\\CivixBundle\\Command\\AddPageCommand' => $baseDir . '/src/CRM/CivixBundle/Command/AddPageCommand.php',
    'CRM\\CivixBundle\\Command\\AddReportCommand' => $baseDir . '/src/CRM/CivixBundle/Command/AddReportCommand.php',
    'CRM\\CivixBundle\\Command\\AddSearchCommand' => $baseDir . '/src/CRM/CivixBundle/Command/AddSearchCommand.php',
    'CRM\\CivixBundle\\Command\\AddTestCommand' => $baseDir . '/src/CRM/CivixBundle/Command/AddTestCommand.php',
    'CRM\\CivixBundle\\Command\\AddThemeCommand' => $baseDir . '/src/CRM/CivixBundle/Command/AddThemeCommand.php',
    'CRM\\CivixBundle\\Command\\AddUpgraderCommand' => $baseDir . '/src/CRM/CivixBundle/Command/AddUpgraderCommand.php',
    'CRM\\CivixBundle\\Command\\BuildCommand' => $baseDir . '/src/CRM/CivixBundle/Command/BuildCommand.php',
    'CRM\\CivixBundle\\Command\\ConfigGetCommand' => $baseDir . '/src/CRM/CivixBundle/Command/ConfigGetCommand.php',
    'CRM\\CivixBundle\\Command\\ConfigSetCommand' => $baseDir . '/src/CRM/CivixBundle/Command/ConfigSetCommand.php',
    'CRM\\CivixBundle\\Command\\InfoGetCommand' => $baseDir . '/src/CRM/CivixBundle/Command/InfoGetCommand.php',
    'CRM\\CivixBundle\\Command\\InfoSetCommand' => $baseDir . '/src/CRM/CivixBundle/Command/InfoSetCommand.php',
    'CRM\\CivixBundle\\Command\\InitCommand' => $baseDir . '/src/CRM/CivixBundle/Command/InitCommand.php',
    'CRM\\CivixBundle\\Command\\MixinCommand' => $baseDir . '/src/CRM/CivixBundle/Command/MixinCommand.php',
    'CRM\\CivixBundle\\Command\\PingCommand' => $baseDir . '/src/CRM/CivixBundle/Command/PingCommand.php',
    'CRM\\CivixBundle\\Command\\TestRunCommand' => $baseDir . '/src/CRM/CivixBundle/Command/TestRunCommand.php',
    'CRM\\CivixBundle\\Command\\UpgradeCommand' => $baseDir . '/src/CRM/CivixBundle/Command/UpgradeCommand.php',
    'CRM\\CivixBundle\\ComposerCompile' => $baseDir . '/src/CRM/CivixBundle/ComposerCompile.php',
    'CRM\\CivixBundle\\RunMethodsTrait' => $baseDir . '/src/CRM/CivixBundle/RunMethodsTrait.php',
    'CRM\\CivixBundle\\Services' => $baseDir . '/src/CRM/CivixBundle/Services.php',
    'CRM\\CivixBundle\\SkippedMethodException' => $baseDir . '/src/CRM/CivixBundle/SkippedMethodException.php',
    'CRM\\CivixBundle\\UpgradeList' => $baseDir . '/src/CRM/CivixBundle/UpgradeList.php',
    'CRM\\CivixBundle\\Upgrader' => $baseDir . '/src/CRM/CivixBundle/Upgrader.php',
    'CRM\\CivixBundle\\Utils\\Commands' => $baseDir . '/src/CRM/CivixBundle/Utils/Commands.php',
    'CRM\\CivixBundle\\Utils\\EvilEx' => $baseDir . '/src/CRM/CivixBundle/Utils/EvilEx.php',
    'CRM\\CivixBundle\\Utils\\Files' => $baseDir . '/src/CRM/CivixBundle/Utils/Files.php',
    'CRM\\CivixBundle\\Utils\\Formatting' => $baseDir . '/src/CRM/CivixBundle/Utils/Formatting.php',
    'CRM\\CivixBundle\\Utils\\Functions' => $baseDir . '/src/CRM/CivixBundle/Utils/Functions.php',
    'CRM\\CivixBundle\\Utils\\Naming' => $baseDir . '/src/CRM/CivixBundle/Utils/Naming.php',
    'CRM\\CivixBundle\\Utils\\NamingTest' => $baseDir . '/src/CRM/CivixBundle/Utils/NamingTest.php',
    'CRM\\CivixBundle\\Utils\\Path' => $baseDir . '/src/CRM/CivixBundle/Utils/Path.php',
    'CRM\\CivixBundle\\Utils\\Versioning' => $baseDir . '/src/CRM/CivixBundle/Utils/Versioning.php',
    'Civi\\Cv\\Bootstrap' => $vendorDir . '/civicrm/cv-lib/src/Bootstrap.php',
    'Civi\\Cv\\BuildkitReader' => $vendorDir . '/civicrm/cv-lib/src/BuildkitReader.php',
    'Civi\\Cv\\CmsBootstrap' => $vendorDir . '/civicrm/cv-lib/src/CmsBootstrap.php',
    'Civi\\Cv\\Config' => $vendorDir . '/civicrm/cv-lib/src/Config.php',
    'Civi\\Cv\\ErrorHandler' => $vendorDir . '/civicrm/cv-lib/src/ErrorHandler.php',
    'Civi\\Cv\\Log\\InternalLogger' => $vendorDir . '/civicrm/cv-lib/src/Log/InternalLogger.php',
    'Civi\\Cv\\Log\\Logger' => $vendorDir . '/civicrm/cv-lib/src/Log/Logger.php',
    'Civi\\Cv\\Log\\StderrLogger' => $vendorDir . '/civicrm/cv-lib/src/Log/StderrLogger.php',
    'Civi\\Cv\\Log\\SymfonyConsoleLogger' => $vendorDir . '/civicrm/cv-lib/src/Log/SymfonyConsoleLogger.php',
    'Civi\\Cv\\PharOut\\PharOut' => $vendorDir . '/civicrm/cv-lib/src/PharOut/PharOut.php',
    'Civi\\Cv\\PharOut\\PharPolicyTrait' => $vendorDir . '/civicrm/cv-lib/src/PharOut/PharPolicyTrait.php',
    'Civi\\Cv\\SiteConfigReader' => $vendorDir . '/civicrm/cv-lib/src/SiteConfigReader.php',
    'Civi\\Cv\\Util\\BootTrait' => $vendorDir . '/civicrm/cv-lib/src/Util/BootTrait.php',
    'Civi\\Cv\\Util\\Filesystem' => $vendorDir . '/civicrm/cv-lib/src/Util/Filesystem.php',
    'Civi\\Cv\\Util\\FilesystemTrait' => $vendorDir . '/civicrm/cv-lib/src/Util/FilesystemTrait.php',
    'CivixPhar\\JsonException' => $vendorDir . '/symfony/polyfill-php73/Resources/stubs/JsonException.php',
    'CivixPhar\\LastCall\\DownloadsPlugin\\DownloadsParser' => $vendorDir . '/civicrm/composer-downloads-plugin/src/DownloadsParser.php',
    'CivixPhar\\LastCall\\DownloadsPlugin\\GlobCleaner' => $vendorDir . '/civicrm/composer-downloads-plugin/src/GlobCleaner.php',
    'CivixPhar\\LastCall\\DownloadsPlugin\\Handler\\ArchiveHandler' => $vendorDir . '/civicrm/composer-downloads-plugin/src/Handler/ArchiveHandler.php',
    'CivixPhar\\LastCall\\DownloadsPlugin\\Handler\\BaseHandler' => $vendorDir . '/civicrm/composer-downloads-plugin/src/Handler/BaseHandler.php',
    'CivixPhar\\LastCall\\DownloadsPlugin\\Handler\\FileHandler' => $vendorDir . '/civicrm/composer-downloads-plugin/src/Handler/FileHandler.php',
    'CivixPhar\\LastCall\\DownloadsPlugin\\Handler\\PharHandler' => $vendorDir . '/civicrm/composer-downloads-plugin/src/Handler/PharHandler.php',
    'CivixPhar\\LastCall\\DownloadsPlugin\\Plugin' => $vendorDir . '/civicrm/composer-downloads-plugin/src/Plugin.php',
    'CivixPhar\\LastCall\\DownloadsPlugin\\Subpackage' => $vendorDir . '/civicrm/composer-downloads-plugin/src/Subpackage.php',
    'CivixPhar\\LicenseData\\License' => $vendorDir . '/totten/license-data/src/LicenseData/License.php',
    'CivixPhar\\LicenseData\\Repository' => $vendorDir . '/totten/license-data/src/LicenseData/Repository.php',
    'CivixPhar\\ProcessHelper\\ProcessErrorException' => $vendorDir . '/totten/process-helper/src/ProcessErrorException.php',
    'CivixPhar\\ProcessHelper\\ProcessHelper' => $vendorDir . '/totten/process-helper/src/ProcessHelper.php',
    'CivixPhar\\Psr\\Container\\ContainerExceptionInterface' => $vendorDir . '/psr/container/src/ContainerExceptionInterface.php',
    'CivixPhar\\Psr\\Container\\ContainerInterface' => $vendorDir . '/psr/container/src/ContainerInterface.php',
    'CivixPhar\\Psr\\Container\\NotFoundExceptionInterface' => $vendorDir . '/psr/container/src/NotFoundExceptionInterface.php',
    'CivixPhar\\Symfony\\Component\\Console\\Application' => $vendorDir . '/symfony/console/Application.php',
    'CivixPhar\\Symfony\\Component\\Console\\CommandLoader\\CommandLoaderInterface' => $vendorDir . '/symfony/console/CommandLoader/CommandLoaderInterface.php',
    'CivixPhar\\Symfony\\Component\\Console\\CommandLoader\\ContainerCommandLoader' => $vendorDir . '/symfony/console/CommandLoader/ContainerCommandLoader.php',
    'CivixPhar\\Symfony\\Component\\Console\\CommandLoader\\FactoryCommandLoader' => $vendorDir . '/symfony/console/CommandLoader/FactoryCommandLoader.php',
    'CivixPhar\\Symfony\\Component\\Console\\Command\\Command' => $vendorDir . '/symfony/console/Command/Command.php',
    'CivixPhar\\Symfony\\Component\\Console\\Command\\HelpCommand' => $vendorDir . '/symfony/console/Command/HelpCommand.php',
    'CivixPhar\\Symfony\\Component\\Console\\Command\\ListCommand' => $vendorDir . '/symfony/console/Command/ListCommand.php',
    'CivixPhar\\Symfony\\Component\\Console\\Command\\LockableTrait' => $vendorDir . '/symfony/console/Command/LockableTrait.php',
    'CivixPhar\\Symfony\\Component\\Console\\ConsoleEvents' => $vendorDir . '/symfony/console/ConsoleEvents.php',
    'CivixPhar\\Symfony\\Component\\Console\\DependencyInjection\\AddConsoleCommandPass' => $vendorDir . '/symfony/console/DependencyInjection/AddConsoleCommandPass.php',
    'CivixPhar\\Symfony\\Component\\Console\\Descriptor\\ApplicationDescription' => $vendorDir . '/symfony/console/Descriptor/ApplicationDescription.php',
    'CivixPhar\\Symfony\\Component\\Console\\Descriptor\\Descriptor' => $vendorDir . '/symfony/console/Descriptor/Descriptor.php',
    'CivixPhar\\Symfony\\Component\\Console\\Descriptor\\DescriptorInterface' => $vendorDir . '/symfony/console/Descriptor/DescriptorInterface.php',
    'CivixPhar\\Symfony\\Component\\Console\\Descriptor\\JsonDescriptor' => $vendorDir . '/symfony/console/Descriptor/JsonDescriptor.php',
    'CivixPhar\\Symfony\\Component\\Console\\Descriptor\\MarkdownDescriptor' => $vendorDir . '/symfony/console/Descriptor/MarkdownDescriptor.php',
    'CivixPhar\\Symfony\\Component\\Console\\Descriptor\\TextDescriptor' => $vendorDir . '/symfony/console/Descriptor/TextDescriptor.php',
    'CivixPhar\\Symfony\\Component\\Console\\Descriptor\\XmlDescriptor' => $vendorDir . '/symfony/console/Descriptor/XmlDescriptor.php',
    'CivixPhar\\Symfony\\Component\\Console\\EventListener\\ErrorListener' => $vendorDir . '/symfony/console/EventListener/ErrorListener.php',
    'CivixPhar\\Symfony\\Component\\Console\\Event\\ConsoleCommandEvent' => $vendorDir . '/symfony/console/Event/ConsoleCommandEvent.php',
    'CivixPhar\\Symfony\\Component\\Console\\Event\\ConsoleErrorEvent' => $vendorDir . '/symfony/console/Event/ConsoleErrorEvent.php',
    'CivixPhar\\Symfony\\Component\\Console\\Event\\ConsoleEvent' => $vendorDir . '/symfony/console/Event/ConsoleEvent.php',
    'CivixPhar\\Symfony\\Component\\Console\\Event\\ConsoleTerminateEvent' => $vendorDir . '/symfony/console/Event/ConsoleTerminateEvent.php',
    'CivixPhar\\Symfony\\Component\\Console\\Exception\\CommandNotFoundException' => $vendorDir . '/symfony/console/Exception/CommandNotFoundException.php',
    'CivixPhar\\Symfony\\Component\\Console\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/console/Exception/ExceptionInterface.php',
    'CivixPhar\\Symfony\\Component\\Console\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/console/Exception/InvalidArgumentException.php',
    'CivixPhar\\Symfony\\Component\\Console\\Exception\\InvalidOptionException' => $vendorDir . '/symfony/console/Exception/InvalidOptionException.php',
    'CivixPhar\\Symfony\\Component\\Console\\Exception\\LogicException' => $vendorDir . '/symfony/console/Exception/LogicException.php',
    'CivixPhar\\Symfony\\Component\\Console\\Exception\\MissingInputException' => $vendorDir . '/symfony/console/Exception/MissingInputException.php',
    'CivixPhar\\Symfony\\Component\\Console\\Exception\\NamespaceNotFoundException' => $vendorDir . '/symfony/console/Exception/NamespaceNotFoundException.php',
    'CivixPhar\\Symfony\\Component\\Console\\Exception\\RuntimeException' => $vendorDir . '/symfony/console/Exception/RuntimeException.php',
    'CivixPhar\\Symfony\\Component\\Console\\Formatter\\OutputFormatter' => $vendorDir . '/symfony/console/Formatter/OutputFormatter.php',
    'CivixPhar\\Symfony\\Component\\Console\\Formatter\\OutputFormatterInterface' => $vendorDir . '/symfony/console/Formatter/OutputFormatterInterface.php',
    'CivixPhar\\Symfony\\Component\\Console\\Formatter\\OutputFormatterStyle' => $vendorDir . '/symfony/console/Formatter/OutputFormatterStyle.php',
    'CivixPhar\\Symfony\\Component\\Console\\Formatter\\OutputFormatterStyleInterface' => $vendorDir . '/symfony/console/Formatter/OutputFormatterStyleInterface.php',
    'CivixPhar\\Symfony\\Component\\Console\\Formatter\\OutputFormatterStyleStack' => $vendorDir . '/symfony/console/Formatter/OutputFormatterStyleStack.php',
    'CivixPhar\\Symfony\\Component\\Console\\Formatter\\WrappableOutputFormatterInterface' => $vendorDir . '/symfony/console/Formatter/WrappableOutputFormatterInterface.php',
    'CivixPhar\\Symfony\\Component\\Console\\Helper\\DebugFormatterHelper' => $vendorDir . '/symfony/console/Helper/DebugFormatterHelper.php',
    'CivixPhar\\Symfony\\Component\\Console\\Helper\\DescriptorHelper' => $vendorDir . '/symfony/console/Helper/DescriptorHelper.php',
    'CivixPhar\\Symfony\\Component\\Console\\Helper\\Dumper' => $vendorDir . '/symfony/console/Helper/Dumper.php',
    'CivixPhar\\Symfony\\Component\\Console\\Helper\\FormatterHelper' => $vendorDir . '/symfony/console/Helper/FormatterHelper.php',
    'CivixPhar\\Symfony\\Component\\Console\\Helper\\Helper' => $vendorDir . '/symfony/console/Helper/Helper.php',
    'CivixPhar\\Symfony\\Component\\Console\\Helper\\HelperInterface' => $vendorDir . '/symfony/console/Helper/HelperInterface.php',
    'CivixPhar\\Symfony\\Component\\Console\\Helper\\HelperSet' => $vendorDir . '/symfony/console/Helper/HelperSet.php',
    'CivixPhar\\Symfony\\Component\\Console\\Helper\\InputAwareHelper' => $vendorDir . '/symfony/console/Helper/InputAwareHelper.php',
    'CivixPhar\\Symfony\\Component\\Console\\Helper\\ProcessHelper' => $vendorDir . '/symfony/console/Helper/ProcessHelper.php',
    'CivixPhar\\Symfony\\Component\\Console\\Helper\\ProgressBar' => $vendorDir . '/symfony/console/Helper/ProgressBar.php',
    'CivixPhar\\Symfony\\Component\\Console\\Helper\\ProgressIndicator' => $vendorDir . '/symfony/console/Helper/ProgressIndicator.php',
    'CivixPhar\\Symfony\\Component\\Console\\Helper\\QuestionHelper' => $vendorDir . '/symfony/console/Helper/QuestionHelper.php',
    'CivixPhar\\Symfony\\Component\\Console\\Helper\\SymfonyQuestionHelper' => $vendorDir . '/symfony/console/Helper/SymfonyQuestionHelper.php',
    'CivixPhar\\Symfony\\Component\\Console\\Helper\\Table' => $vendorDir . '/symfony/console/Helper/Table.php',
    'CivixPhar\\Symfony\\Component\\Console\\Helper\\TableCell' => $vendorDir . '/symfony/console/Helper/TableCell.php',
    'CivixPhar\\Symfony\\Component\\Console\\Helper\\TableRows' => $vendorDir . '/symfony/console/Helper/TableRows.php',
    'CivixPhar\\Symfony\\Component\\Console\\Helper\\TableSeparator' => $vendorDir . '/symfony/console/Helper/TableSeparator.php',
    'CivixPhar\\Symfony\\Component\\Console\\Helper\\TableStyle' => $vendorDir . '/symfony/console/Helper/TableStyle.php',
    'CivixPhar\\Symfony\\Component\\Console\\Input\\ArgvInput' => $vendorDir . '/symfony/console/Input/ArgvInput.php',
    'CivixPhar\\Symfony\\Component\\Console\\Input\\ArrayInput' => $vendorDir . '/symfony/console/Input/ArrayInput.php',
    'CivixPhar\\Symfony\\Component\\Console\\Input\\Input' => $vendorDir . '/symfony/console/Input/Input.php',
    'CivixPhar\\Symfony\\Component\\Console\\Input\\InputArgument' => $vendorDir . '/symfony/console/Input/InputArgument.php',
    'CivixPhar\\Symfony\\Component\\Console\\Input\\InputAwareInterface' => $vendorDir . '/symfony/console/Input/InputAwareInterface.php',
    'CivixPhar\\Symfony\\Component\\Console\\Input\\InputDefinition' => $vendorDir . '/symfony/console/Input/InputDefinition.php',
    'CivixPhar\\Symfony\\Component\\Console\\Input\\InputInterface' => $vendorDir . '/symfony/console/Input/InputInterface.php',
    'CivixPhar\\Symfony\\Component\\Console\\Input\\InputOption' => $vendorDir . '/symfony/console/Input/InputOption.php',
    'CivixPhar\\Symfony\\Component\\Console\\Input\\StreamableInputInterface' => $vendorDir . '/symfony/console/Input/StreamableInputInterface.php',
    'CivixPhar\\Symfony\\Component\\Console\\Input\\StringInput' => $vendorDir . '/symfony/console/Input/StringInput.php',
    'CivixPhar\\Symfony\\Component\\Console\\Logger\\ConsoleLogger' => $vendorDir . '/symfony/console/Logger/ConsoleLogger.php',
    'CivixPhar\\Symfony\\Component\\Console\\Output\\BufferedOutput' => $vendorDir . '/symfony/console/Output/BufferedOutput.php',
    'CivixPhar\\Symfony\\Component\\Console\\Output\\ConsoleOutput' => $vendorDir . '/symfony/console/Output/ConsoleOutput.php',
    'CivixPhar\\Symfony\\Component\\Console\\Output\\ConsoleOutputInterface' => $vendorDir . '/symfony/console/Output/ConsoleOutputInterface.php',
    'CivixPhar\\Symfony\\Component\\Console\\Output\\ConsoleSectionOutput' => $vendorDir . '/symfony/console/Output/ConsoleSectionOutput.php',
    'CivixPhar\\Symfony\\Component\\Console\\Output\\NullOutput' => $vendorDir . '/symfony/console/Output/NullOutput.php',
    'CivixPhar\\Symfony\\Component\\Console\\Output\\Output' => $vendorDir . '/symfony/console/Output/Output.php',
    'CivixPhar\\Symfony\\Component\\Console\\Output\\OutputInterface' => $vendorDir . '/symfony/console/Output/OutputInterface.php',
    'CivixPhar\\Symfony\\Component\\Console\\Output\\StreamOutput' => $vendorDir . '/symfony/console/Output/StreamOutput.php',
    'CivixPhar\\Symfony\\Component\\Console\\Output\\TrimmedBufferOutput' => $vendorDir . '/symfony/console/Output/TrimmedBufferOutput.php',
    'CivixPhar\\Symfony\\Component\\Console\\Question\\ChoiceQuestion' => $vendorDir . '/symfony/console/Question/ChoiceQuestion.php',
    'CivixPhar\\Symfony\\Component\\Console\\Question\\ConfirmationQuestion' => $vendorDir . '/symfony/console/Question/ConfirmationQuestion.php',
    'CivixPhar\\Symfony\\Component\\Console\\Question\\Question' => $vendorDir . '/symfony/console/Question/Question.php',
    'CivixPhar\\Symfony\\Component\\Console\\Style\\OutputStyle' => $vendorDir . '/symfony/console/Style/OutputStyle.php',
    'CivixPhar\\Symfony\\Component\\Console\\Style\\StyleInterface' => $vendorDir . '/symfony/console/Style/StyleInterface.php',
    'CivixPhar\\Symfony\\Component\\Console\\Style\\SymfonyStyle' => $vendorDir . '/symfony/console/Style/SymfonyStyle.php',
    'CivixPhar\\Symfony\\Component\\Console\\Terminal' => $vendorDir . '/symfony/console/Terminal.php',
    'CivixPhar\\Symfony\\Component\\Console\\Tester\\ApplicationTester' => $vendorDir . '/symfony/console/Tester/ApplicationTester.php',
    'CivixPhar\\Symfony\\Component\\Console\\Tester\\CommandTester' => $vendorDir . '/symfony/console/Tester/CommandTester.php',
    'CivixPhar\\Symfony\\Component\\Console\\Tester\\TesterTrait' => $vendorDir . '/symfony/console/Tester/TesterTrait.php',
    'CivixPhar\\Symfony\\Component\\Filesystem\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/filesystem/Exception/ExceptionInterface.php',
    'CivixPhar\\Symfony\\Component\\Filesystem\\Exception\\FileNotFoundException' => $vendorDir . '/symfony/filesystem/Exception/FileNotFoundException.php',
    'CivixPhar\\Symfony\\Component\\Filesystem\\Exception\\IOException' => $vendorDir . '/symfony/filesystem/Exception/IOException.php',
    'CivixPhar\\Symfony\\Component\\Filesystem\\Exception\\IOExceptionInterface' => $vendorDir . '/symfony/filesystem/Exception/IOExceptionInterface.php',
    'CivixPhar\\Symfony\\Component\\Filesystem\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/filesystem/Exception/InvalidArgumentException.php',
    'CivixPhar\\Symfony\\Component\\Filesystem\\Filesystem' => $vendorDir . '/symfony/filesystem/Filesystem.php',
    'CivixPhar\\Symfony\\Component\\Process\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/process/Exception/ExceptionInterface.php',
    'CivixPhar\\Symfony\\Component\\Process\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/process/Exception/InvalidArgumentException.php',
    'CivixPhar\\Symfony\\Component\\Process\\Exception\\LogicException' => $vendorDir . '/symfony/process/Exception/LogicException.php',
    'CivixPhar\\Symfony\\Component\\Process\\Exception\\ProcessFailedException' => $vendorDir . '/symfony/process/Exception/ProcessFailedException.php',
    'CivixPhar\\Symfony\\Component\\Process\\Exception\\ProcessSignaledException' => $vendorDir . '/symfony/process/Exception/ProcessSignaledException.php',
    'CivixPhar\\Symfony\\Component\\Process\\Exception\\ProcessTimedOutException' => $vendorDir . '/symfony/process/Exception/ProcessTimedOutException.php',
    'CivixPhar\\Symfony\\Component\\Process\\Exception\\RuntimeException' => $vendorDir . '/symfony/process/Exception/RuntimeException.php',
    'CivixPhar\\Symfony\\Component\\Process\\ExecutableFinder' => $vendorDir . '/symfony/process/ExecutableFinder.php',
    'CivixPhar\\Symfony\\Component\\Process\\InputStream' => $vendorDir . '/symfony/process/InputStream.php',
    'CivixPhar\\Symfony\\Component\\Process\\PhpExecutableFinder' => $vendorDir . '/symfony/process/PhpExecutableFinder.php',
    'CivixPhar\\Symfony\\Component\\Process\\PhpProcess' => $vendorDir . '/symfony/process/PhpProcess.php',
    'CivixPhar\\Symfony\\Component\\Process\\Pipes\\AbstractPipes' => $vendorDir . '/symfony/process/Pipes/AbstractPipes.php',
    'CivixPhar\\Symfony\\Component\\Process\\Pipes\\PipesInterface' => $vendorDir . '/symfony/process/Pipes/PipesInterface.php',
    'CivixPhar\\Symfony\\Component\\Process\\Pipes\\UnixPipes' => $vendorDir . '/symfony/process/Pipes/UnixPipes.php',
    'CivixPhar\\Symfony\\Component\\Process\\Pipes\\WindowsPipes' => $vendorDir . '/symfony/process/Pipes/WindowsPipes.php',
    'CivixPhar\\Symfony\\Component\\Process\\Process' => $vendorDir . '/symfony/process/Process.php',
    'CivixPhar\\Symfony\\Component\\Process\\ProcessUtils' => $vendorDir . '/symfony/process/ProcessUtils.php',
    'CivixPhar\\Symfony\\Component\\Templating\\DelegatingEngine' => $vendorDir . '/symfony/templating/DelegatingEngine.php',
    'CivixPhar\\Symfony\\Component\\Templating\\EngineInterface' => $vendorDir . '/symfony/templating/EngineInterface.php',
    'CivixPhar\\Symfony\\Component\\Templating\\Helper\\Helper' => $vendorDir . '/symfony/templating/Helper/Helper.php',
    'CivixPhar\\Symfony\\Component\\Templating\\Helper\\HelperInterface' => $vendorDir . '/symfony/templating/Helper/HelperInterface.php',
    'CivixPhar\\Symfony\\Component\\Templating\\Helper\\SlotsHelper' => $vendorDir . '/symfony/templating/Helper/SlotsHelper.php',
    'CivixPhar\\Symfony\\Component\\Templating\\Loader\\CacheLoader' => $vendorDir . '/symfony/templating/Loader/CacheLoader.php',
    'CivixPhar\\Symfony\\Component\\Templating\\Loader\\ChainLoader' => $vendorDir . '/symfony/templating/Loader/ChainLoader.php',
    'CivixPhar\\Symfony\\Component\\Templating\\Loader\\FilesystemLoader' => $vendorDir . '/symfony/templating/Loader/FilesystemLoader.php',
    'CivixPhar\\Symfony\\Component\\Templating\\Loader\\Loader' => $vendorDir . '/symfony/templating/Loader/Loader.php',
    'CivixPhar\\Symfony\\Component\\Templating\\Loader\\LoaderInterface' => $vendorDir . '/symfony/templating/Loader/LoaderInterface.php',
    'CivixPhar\\Symfony\\Component\\Templating\\PhpEngine' => $vendorDir . '/symfony/templating/PhpEngine.php',
    'CivixPhar\\Symfony\\Component\\Templating\\Storage\\FileStorage' => $vendorDir . '/symfony/templating/Storage/FileStorage.php',
    'CivixPhar\\Symfony\\Component\\Templating\\Storage\\Storage' => $vendorDir . '/symfony/templating/Storage/Storage.php',
    'CivixPhar\\Symfony\\Component\\Templating\\Storage\\StringStorage' => $vendorDir . '/symfony/templating/Storage/StringStorage.php',
    'CivixPhar\\Symfony\\Component\\Templating\\StreamingEngineInterface' => $vendorDir . '/symfony/templating/StreamingEngineInterface.php',
    'CivixPhar\\Symfony\\Component\\Templating\\TemplateNameParser' => $vendorDir . '/symfony/templating/TemplateNameParser.php',
    'CivixPhar\\Symfony\\Component\\Templating\\TemplateNameParserInterface' => $vendorDir . '/symfony/templating/TemplateNameParserInterface.php',
    'CivixPhar\\Symfony\\Component\\Templating\\TemplateReference' => $vendorDir . '/symfony/templating/TemplateReference.php',
    'CivixPhar\\Symfony\\Component\\Templating\\TemplateReferenceInterface' => $vendorDir . '/symfony/templating/TemplateReferenceInterface.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\AmqpCaster' => $vendorDir . '/symfony/var-dumper/Caster/AmqpCaster.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ArgsStub' => $vendorDir . '/symfony/var-dumper/Caster/ArgsStub.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\Caster' => $vendorDir . '/symfony/var-dumper/Caster/Caster.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ClassStub' => $vendorDir . '/symfony/var-dumper/Caster/ClassStub.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ConstStub' => $vendorDir . '/symfony/var-dumper/Caster/ConstStub.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\CutArrayStub' => $vendorDir . '/symfony/var-dumper/Caster/CutArrayStub.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\CutStub' => $vendorDir . '/symfony/var-dumper/Caster/CutStub.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DOMCaster' => $vendorDir . '/symfony/var-dumper/Caster/DOMCaster.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DateCaster' => $vendorDir . '/symfony/var-dumper/Caster/DateCaster.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DoctrineCaster' => $vendorDir . '/symfony/var-dumper/Caster/DoctrineCaster.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DsCaster' => $vendorDir . '/symfony/var-dumper/Caster/DsCaster.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DsPairStub' => $vendorDir . '/symfony/var-dumper/Caster/DsPairStub.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\EnumStub' => $vendorDir . '/symfony/var-dumper/Caster/EnumStub.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ExceptionCaster' => $vendorDir . '/symfony/var-dumper/Caster/ExceptionCaster.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\FrameStub' => $vendorDir . '/symfony/var-dumper/Caster/FrameStub.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\GmpCaster' => $vendorDir . '/symfony/var-dumper/Caster/GmpCaster.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ImagineCaster' => $vendorDir . '/symfony/var-dumper/Caster/ImagineCaster.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ImgStub' => $vendorDir . '/symfony/var-dumper/Caster/ImgStub.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\IntlCaster' => $vendorDir . '/symfony/var-dumper/Caster/IntlCaster.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\LinkStub' => $vendorDir . '/symfony/var-dumper/Caster/LinkStub.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\MemcachedCaster' => $vendorDir . '/symfony/var-dumper/Caster/MemcachedCaster.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\PdoCaster' => $vendorDir . '/symfony/var-dumper/Caster/PdoCaster.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\PgSqlCaster' => $vendorDir . '/symfony/var-dumper/Caster/PgSqlCaster.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ProxyManagerCaster' => $vendorDir . '/symfony/var-dumper/Caster/ProxyManagerCaster.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\RedisCaster' => $vendorDir . '/symfony/var-dumper/Caster/RedisCaster.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ReflectionCaster' => $vendorDir . '/symfony/var-dumper/Caster/ReflectionCaster.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ResourceCaster' => $vendorDir . '/symfony/var-dumper/Caster/ResourceCaster.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\SplCaster' => $vendorDir . '/symfony/var-dumper/Caster/SplCaster.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\StubCaster' => $vendorDir . '/symfony/var-dumper/Caster/StubCaster.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\SymfonyCaster' => $vendorDir . '/symfony/var-dumper/Caster/SymfonyCaster.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\TraceStub' => $vendorDir . '/symfony/var-dumper/Caster/TraceStub.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\UuidCaster' => $vendorDir . '/symfony/var-dumper/Caster/UuidCaster.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\XmlReaderCaster' => $vendorDir . '/symfony/var-dumper/Caster/XmlReaderCaster.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\XmlResourceCaster' => $vendorDir . '/symfony/var-dumper/Caster/XmlResourceCaster.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Cloner\\AbstractCloner' => $vendorDir . '/symfony/var-dumper/Cloner/AbstractCloner.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Cloner\\ClonerInterface' => $vendorDir . '/symfony/var-dumper/Cloner/ClonerInterface.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Cloner\\Cursor' => $vendorDir . '/symfony/var-dumper/Cloner/Cursor.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Cloner\\Data' => $vendorDir . '/symfony/var-dumper/Cloner/Data.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Cloner\\DumperInterface' => $vendorDir . '/symfony/var-dumper/Cloner/DumperInterface.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Cloner\\Stub' => $vendorDir . '/symfony/var-dumper/Cloner/Stub.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Cloner\\VarCloner' => $vendorDir . '/symfony/var-dumper/Cloner/VarCloner.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Command\\Descriptor\\CliDescriptor' => $vendorDir . '/symfony/var-dumper/Command/Descriptor/CliDescriptor.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Command\\Descriptor\\DumpDescriptorInterface' => $vendorDir . '/symfony/var-dumper/Command/Descriptor/DumpDescriptorInterface.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Command\\Descriptor\\HtmlDescriptor' => $vendorDir . '/symfony/var-dumper/Command/Descriptor/HtmlDescriptor.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Command\\ServerDumpCommand' => $vendorDir . '/symfony/var-dumper/Command/ServerDumpCommand.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Dumper\\AbstractDumper' => $vendorDir . '/symfony/var-dumper/Dumper/AbstractDumper.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Dumper\\CliDumper' => $vendorDir . '/symfony/var-dumper/Dumper/CliDumper.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Dumper\\ContextProvider\\CliContextProvider' => $vendorDir . '/symfony/var-dumper/Dumper/ContextProvider/CliContextProvider.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Dumper\\ContextProvider\\ContextProviderInterface' => $vendorDir . '/symfony/var-dumper/Dumper/ContextProvider/ContextProviderInterface.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Dumper\\ContextProvider\\RequestContextProvider' => $vendorDir . '/symfony/var-dumper/Dumper/ContextProvider/RequestContextProvider.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Dumper\\ContextProvider\\SourceContextProvider' => $vendorDir . '/symfony/var-dumper/Dumper/ContextProvider/SourceContextProvider.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Dumper\\ContextualizedDumper' => $vendorDir . '/symfony/var-dumper/Dumper/ContextualizedDumper.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Dumper\\DataDumperInterface' => $vendorDir . '/symfony/var-dumper/Dumper/DataDumperInterface.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Dumper\\HtmlDumper' => $vendorDir . '/symfony/var-dumper/Dumper/HtmlDumper.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Dumper\\ServerDumper' => $vendorDir . '/symfony/var-dumper/Dumper/ServerDumper.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Exception\\ThrowingCasterException' => $vendorDir . '/symfony/var-dumper/Exception/ThrowingCasterException.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Server\\Connection' => $vendorDir . '/symfony/var-dumper/Server/Connection.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\Server\\DumpServer' => $vendorDir . '/symfony/var-dumper/Server/DumpServer.php',
    'CivixPhar\\Symfony\\Component\\VarDumper\\VarDumper' => $vendorDir . '/symfony/var-dumper/VarDumper.php',
    'CivixPhar\\Symfony\\Component\\VarExporter\\Exception\\ClassNotFoundException' => $vendorDir . '/symfony/var-exporter/Exception/ClassNotFoundException.php',
    'CivixPhar\\Symfony\\Component\\VarExporter\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/var-exporter/Exception/ExceptionInterface.php',
    'CivixPhar\\Symfony\\Component\\VarExporter\\Exception\\NotInstantiableTypeException' => $vendorDir . '/symfony/var-exporter/Exception/NotInstantiableTypeException.php',
    'CivixPhar\\Symfony\\Component\\VarExporter\\Instantiator' => $vendorDir . '/symfony/var-exporter/Instantiator.php',
    'CivixPhar\\Symfony\\Component\\VarExporter\\Internal\\Exporter' => $vendorDir . '/symfony/var-exporter/Internal/Exporter.php',
    'CivixPhar\\Symfony\\Component\\VarExporter\\Internal\\Hydrator' => $vendorDir . '/symfony/var-exporter/Internal/Hydrator.php',
    'CivixPhar\\Symfony\\Component\\VarExporter\\Internal\\Reference' => $vendorDir . '/symfony/var-exporter/Internal/Reference.php',
    'CivixPhar\\Symfony\\Component\\VarExporter\\Internal\\Registry' => $vendorDir . '/symfony/var-exporter/Internal/Registry.php',
    'CivixPhar\\Symfony\\Component\\VarExporter\\Internal\\Values' => $vendorDir . '/symfony/var-exporter/Internal/Values.php',
    'CivixPhar\\Symfony\\Component\\VarExporter\\VarExporter' => $vendorDir . '/symfony/var-exporter/VarExporter.php',
    'CivixPhar\\Symfony\\Contracts\\Service\\ResetInterface' => $vendorDir . '/symfony/service-contracts/ResetInterface.php',
    'CivixPhar\\Symfony\\Contracts\\Service\\ServiceLocatorTrait' => $vendorDir . '/symfony/service-contracts/ServiceLocatorTrait.php',
    'CivixPhar\\Symfony\\Contracts\\Service\\ServiceProviderInterface' => $vendorDir . '/symfony/service-contracts/ServiceProviderInterface.php',
    'CivixPhar\\Symfony\\Contracts\\Service\\ServiceSubscriberInterface' => $vendorDir . '/symfony/service-contracts/ServiceSubscriberInterface.php',
    'CivixPhar\\Symfony\\Contracts\\Service\\ServiceSubscriberTrait' => $vendorDir . '/symfony/service-contracts/ServiceSubscriberTrait.php',
    'CivixPhar\\Symfony\\Polyfill\\Ctype\\Ctype' => $vendorDir . '/symfony/polyfill-ctype/Ctype.php',
    'CivixPhar\\Symfony\\Polyfill\\Mbstring\\Mbstring' => $vendorDir . '/symfony/polyfill-mbstring/Mbstring.php',
    'CivixPhar\\Symfony\\Polyfill\\Php72\\Php72' => $vendorDir . '/symfony/polyfill-php72/Php72.php',
    'CivixPhar\\Symfony\\Polyfill\\Php73\\Php73' => $vendorDir . '/symfony/polyfill-php73/Php73.php',
    'CivixPhar\\Symfony\\Polyfill\\Php80\\Php80' => $vendorDir . '/symfony/polyfill-php80/Php80.php',
    'CivixPhar\\Symfony\\Polyfill\\Php80\\PhpToken' => $vendorDir . '/symfony/polyfill-php80/PhpToken.php',
    'CivixPhar\\TOGoS_GitIgnore_FileFinder' => $vendorDir . '/togos/gitignore/src/main/php/TOGoS/GitIgnore/FileFinder.php',
    'CivixPhar\\TOGoS_GitIgnore_Pattern' => $vendorDir . '/togos/gitignore/src/main/php/TOGoS/GitIgnore/Pattern.php',
    'CivixPhar\\TOGoS_GitIgnore_Rule' => $vendorDir . '/togos/gitignore/src/main/php/TOGoS/GitIgnore/Rule.php',
    'CivixPhar\\TOGoS_GitIgnore_Ruleset' => $vendorDir . '/togos/gitignore/src/main/php/TOGoS/GitIgnore/Ruleset.php',
    'CivixPhar\\TOGoS_GitIgnore_Util' => $vendorDir . '/togos/gitignore/src/main/php/TOGoS/GitIgnore/Util.php',
    'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
    'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
    'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
    'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
    'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
);
<?php

// autoload_psr4.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
    'CivixPhar\\Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
    'CivixPhar\\Symfony\\Polyfill\\Php73\\' => array($vendorDir . '/symfony/polyfill-php73'),
    'CivixPhar\\Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'),
    'CivixPhar\\Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
    'CivixPhar\\Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
    'CivixPhar\\Symfony\\Contracts\\Service\\' => array($vendorDir . '/symfony/service-contracts'),
    'CivixPhar\\Symfony\\Component\\VarExporter\\' => array($vendorDir . '/symfony/var-exporter'),
    'CivixPhar\\Symfony\\Component\\VarDumper\\' => array($vendorDir . '/symfony/var-dumper'),
    'CivixPhar\\Symfony\\Component\\Templating\\' => array($vendorDir . '/symfony/templating'),
    'CivixPhar\\Symfony\\Component\\Process\\' => array($vendorDir . '/symfony/process'),
    'CivixPhar\\Symfony\\Component\\Filesystem\\' => array($vendorDir . '/symfony/filesystem'),
    'CivixPhar\\Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'),
    'CivixPhar\\Psr\\Container\\' => array($vendorDir . '/psr/container/src'),
    'CivixPhar\\ProcessHelper\\' => array($vendorDir . '/totten/process-helper/src'),
    'CivixPhar\\Mixlib\\' => array($baseDir . '/extern/src/Mixlib'),
    'CivixPhar\\LicenseData\\' => array($vendorDir . '/totten/license-data/src/LicenseData'),
    'CivixPhar\\LastCall\\DownloadsPlugin\\' => array($vendorDir . '/civicrm/composer-downloads-plugin/src'),
    'Civi\\Cv\\' => array($vendorDir . '/civicrm/cv-lib/src'),
    'CRM\\CivixBundle\\' => array($baseDir . '/src/CRM/CivixBundle'),
);
<?php

// autoload_files.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
    'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
    '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
    '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
    '25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php',
    '0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php',
    '667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php',
);
<?php

/*
 * This file is part of Composer.
 *
 * (c) Nils Adermann <naderman@naderman.de>
 *     Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Composer;

use CivixPhar\Composer\Autoload\ClassLoader;
use CivixPhar\Composer\Semver\VersionParser;
/**
 * This class is copied in every Composer installed project and available to all
 *
 * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
 *
 * To require its presence, you can require `composer-runtime-api ^2.0`
 *
 * @final
 */
class InstalledVersions
{
    /**
     * @var mixed[]|null
     * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
     */
    private static $installed;
    /**
     * @var bool|null
     */
    private static $canGetVendors;
    /**
     * @var array[]
     * @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
     */
    private static $installedByVendor = array();
    /**
     * Returns a list of all package names which are present, either by being installed, replaced or provided
     *
     * @return string[]
     * @psalm-return list<string>
     */
    public static function getInstalledPackages()
    {
        $packages = array();
        foreach (self::getInstalled() as $installed) {
            $packages[] = \array_keys($installed['versions']);
        }
        if (1 === \count($packages)) {
            return $packages[0];
        }
        return \array_keys(\array_flip(\call_user_func_array('array_merge', $packages)));
    }
    /**
     * Returns a list of all package names with a specific type e.g. 'library'
     *
     * @param  string   $type
     * @return string[]
     * @psalm-return list<string>
     */
    public static function getInstalledPackagesByType($type)
    {
        $packagesByType = array();
        foreach (self::getInstalled() as $installed) {
            foreach ($installed['versions'] as $name => $package) {
                if (isset($package['type']) && $package['type'] === $type) {
                    $packagesByType[] = $name;
                }
            }
        }
        return $packagesByType;
    }
    /**
     * Checks whether the given package is installed
     *
     * This also returns true if the package name is provided or replaced by another package
     *
     * @param  string $packageName
     * @param  bool   $includeDevRequirements
     * @return bool
     */
    public static function isInstalled($packageName, $includeDevRequirements = \true)
    {
        foreach (self::getInstalled() as $installed) {
            if (isset($installed['versions'][$packageName])) {
                return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
            }
        }
        return \false;
    }
    /**
     * Checks whether the given package satisfies a version constraint
     *
     * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
     *
     *   Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
     *
     * @param  VersionParser $parser      Install composer/semver to have access to this class and functionality
     * @param  string        $packageName
     * @param  string|null   $constraint  A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
     * @return bool
     */
    public static function satisfies(VersionParser $parser, $packageName, $constraint)
    {
        $constraint = $parser->parseConstraints($constraint);
        $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
        return $provided->matches($constraint);
    }
    /**
     * Returns a version constraint representing all the range(s) which are installed for a given package
     *
     * It is easier to use this via isInstalled() with the $constraint argument if you need to check
     * whether a given version of a package is installed, and not just whether it exists
     *
     * @param  string $packageName
     * @return string Version constraint usable with composer/semver
     */
    public static function getVersionRanges($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }
            $ranges = array();
            if (isset($installed['versions'][$packageName]['pretty_version'])) {
                $ranges[] = $installed['versions'][$packageName]['pretty_version'];
            }
            if (\array_key_exists('aliases', $installed['versions'][$packageName])) {
                $ranges = \array_merge($ranges, $installed['versions'][$packageName]['aliases']);
            }
            if (\array_key_exists('replaced', $installed['versions'][$packageName])) {
                $ranges = \array_merge($ranges, $installed['versions'][$packageName]['replaced']);
            }
            if (\array_key_exists('provided', $installed['versions'][$packageName])) {
                $ranges = \array_merge($ranges, $installed['versions'][$packageName]['provided']);
            }
            return \implode(' || ', $ranges);
        }
        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }
    /**
     * @param  string      $packageName
     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
     */
    public static function getVersion($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }
            if (!isset($installed['versions'][$packageName]['version'])) {
                return null;
            }
            return $installed['versions'][$packageName]['version'];
        }
        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }
    /**
     * @param  string      $packageName
     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
     */
    public static function getPrettyVersion($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }
            if (!isset($installed['versions'][$packageName]['pretty_version'])) {
                return null;
            }
            return $installed['versions'][$packageName]['pretty_version'];
        }
        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }
    /**
     * @param  string      $packageName
     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
     */
    public static function getReference($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }
            if (!isset($installed['versions'][$packageName]['reference'])) {
                return null;
            }
            return $installed['versions'][$packageName]['reference'];
        }
        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }
    /**
     * @param  string      $packageName
     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
     */
    public static function getInstallPath($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }
            return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
        }
        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }
    /**
     * @return array
     * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
     */
    public static function getRootPackage()
    {
        $installed = self::getInstalled();
        return $installed[0]['root'];
    }
    /**
     * Returns the raw installed.php data for custom implementations
     *
     * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
     * @return array[]
     * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
     */
    public static function getRawData()
    {
        @\trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', \E_USER_DEPRECATED);
        if (null === self::$installed) {
            // only require the installed.php file if this file is loaded from its dumped location,
            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
            if (\substr(__DIR__, -8, 1) !== 'C') {
                self::$installed = (include __DIR__ . '/installed.php');
            } else {
                self::$installed = array();
            }
        }
        return self::$installed;
    }
    /**
     * Returns the raw data of all installed.php which are currently loaded for custom implementations
     *
     * @return array[]
     * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
     */
    public static function getAllRawData()
    {
        return self::getInstalled();
    }
    /**
     * Lets you reload the static array from another file
     *
     * This is only useful for complex integrations in which a project needs to use
     * this class but then also needs to execute another project's autoloader in process,
     * and wants to ensure both projects have access to their version of installed.php.
     *
     * A typical case would be PHPUnit, where it would need to make sure it reads all
     * the data it needs from this class, then call reload() with
     * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
     * the project in which it runs can then also use this class safely, without
     * interference between PHPUnit's dependencies and the project's dependencies.
     *
     * @param  array[] $data A vendor/composer/installed.php data set
     * @return void
     *
     * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
     */
    public static function reload($data)
    {
        self::$installed = $data;
        self::$installedByVendor = array();
    }
    /**
     * @return array[]
     * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
     */
    private static function getInstalled()
    {
        if (null === self::$canGetVendors) {
            self::$canGetVendors = \method_exists('CivixPhar\\Composer\\Autoload\\ClassLoader', 'getRegisteredLoaders');
        }
        $installed = array();
        if (self::$canGetVendors) {
            foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
                if (isset(self::$installedByVendor[$vendorDir])) {
                    $installed[] = self::$installedByVendor[$vendorDir];
                } elseif (\is_file($vendorDir . '/composer/installed.php')) {
                    $installed[] = self::$installedByVendor[$vendorDir] = (require $vendorDir . '/composer/installed.php');
                    if (null === self::$installed && \strtr($vendorDir . '/composer', '\\', '/') === \strtr(__DIR__, '\\', '/')) {
                        self::$installed = $installed[\count($installed) - 1];
                    }
                }
            }
        }
        if (null === self::$installed) {
            // only require the installed.php file if this file is loaded from its dumped location,
            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
            if (\substr(__DIR__, -8, 1) !== 'C') {
                self::$installed = (require __DIR__ . '/installed.php');
            } else {
                self::$installed = array();
            }
        }
        $installed[] = self::$installed;
        return $installed;
    }
}
<?php

// platform_check.php @generated by Composer

$issues = array();

if (!(PHP_VERSION_ID >= 70300)) {
    $issues[] = 'Your Composer dependencies require a PHP version ">= 7.3.0". You are running ' . PHP_VERSION . '.';
}

if ($issues) {
    if (!headers_sent()) {
        header('HTTP/1.1 500 Internal Server Error');
    }
    if (!ini_get('display_errors')) {
        if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
            fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
        } elseif (!headers_sent()) {
            echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
        }
    }
    trigger_error(
        'Composer detected issues in your platform: ' . implode(' ', $issues),
        E_USER_ERROR
    );
}
<?php

/*
 * This file is part of Composer.
 *
 * (c) Nils Adermann <naderman@naderman.de>
 *     Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Composer\Autoload;

/**
 * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
 *
 *     $loader = new \Composer\Autoload\ClassLoader();
 *
 *     // register classes with namespaces
 *     $loader->add('Symfony\Component', __DIR__.'/component');
 *     $loader->add('Symfony',           __DIR__.'/framework');
 *
 *     // activate the autoloader
 *     $loader->register();
 *
 *     // to enable searching the include path (eg. for PEAR packages)
 *     $loader->setUseIncludePath(true);
 *
 * In this example, if you try to use a class in the Symfony\Component
 * namespace or one of its children (Symfony\Component\Console for instance),
 * the autoloader will first look for the class under the component/
 * directory, and it will then fallback to the framework/ directory if not
 * found before giving up.
 *
 * This class is loosely based on the Symfony UniversalClassLoader.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Jordi Boggiano <j.boggiano@seld.be>
 * @see    https://www.php-fig.org/psr/psr-0/
 * @see    https://www.php-fig.org/psr/psr-4/
 */
class ClassLoader
{
    /** @var ?string */
    private $vendorDir;

    // PSR-4
    /**
     * @var array[]
     * @psalm-var array<string, array<string, int>>
     */
    private $prefixLengthsPsr4 = array();
    /**
     * @var array[]
     * @psalm-var array<string, array<int, string>>
     */
    private $prefixDirsPsr4 = array();
    /**
     * @var array[]
     * @psalm-var array<string, string>
     */
    private $fallbackDirsPsr4 = array();

    // PSR-0
    /**
     * @var array[]
     * @psalm-var array<string, array<string, string[]>>
     */
    private $prefixesPsr0 = array();
    /**
     * @var array[]
     * @psalm-var array<string, string>
     */
    private $fallbackDirsPsr0 = array();

    /** @var bool */
    private $useIncludePath = false;

    /**
     * @var string[]
     * @psalm-var array<string, string>
     */
    private $classMap = array();

    /** @var bool */
    private $classMapAuthoritative = false;

    /**
     * @var bool[]
     * @psalm-var array<string, bool>
     */
    private $missingClasses = array();

    /** @var ?string */
    private $apcuPrefix;

    /**
     * @var self[]
     */
    private static $registeredLoaders = array();

    /**
     * @param ?string $vendorDir
     */
    public function __construct($vendorDir = null)
    {
        $this->vendorDir = $vendorDir;
    }

    /**
     * @return string[]
     */
    public function getPrefixes()
    {
        if (!empty($this->prefixesPsr0)) {
            return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
        }

        return array();
    }

    /**
     * @return array[]
     * @psalm-return array<string, array<int, string>>
     */
    public function getPrefixesPsr4()
    {
        return $this->prefixDirsPsr4;
    }

    /**
     * @return array[]
     * @psalm-return array<string, string>
     */
    public function getFallbackDirs()
    {
        return $this->fallbackDirsPsr0;
    }

    /**
     * @return array[]
     * @psalm-return array<string, string>
     */
    public function getFallbackDirsPsr4()
    {
        return $this->fallbackDirsPsr4;
    }

    /**
     * @return string[] Array of classname => path
     * @psalm-return array<string, string>
     */
    public function getClassMap()
    {
        return $this->classMap;
    }

    /**
     * @param string[] $classMap Class to filename map
     * @psalm-param array<string, string> $classMap
     *
     * @return void
     */
    public function addClassMap(array $classMap)
    {
        if ($this->classMap) {
            $this->classMap = array_merge($this->classMap, $classMap);
        } else {
            $this->classMap = $classMap;
        }
    }

    /**
     * Registers a set of PSR-0 directories for a given prefix, either
     * appending or prepending to the ones previously set for this prefix.
     *
     * @param string          $prefix  The prefix
     * @param string[]|string $paths   The PSR-0 root directories
     * @param bool            $prepend Whether to prepend the directories
     *
     * @return void
     */
    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
            );
        }
    }

    /**
     * Registers a set of PSR-4 directories for a given namespace, either
     * appending or prepending to the ones previously set for this namespace.
     *
     * @param string          $prefix  The prefix/namespace, with trailing '\\'
     * @param string[]|string $paths   The PSR-4 base directories
     * @param bool            $prepend Whether to prepend the directories
     *
     * @throws \InvalidArgumentException
     *
     * @return void
     */
    public function addPsr4($prefix, $paths, $prepend = false)
    {
        if (!$prefix) {
            // Register directories for the root namespace.
            if ($prepend) {
                $this->fallbackDirsPsr4 = array_merge(
                    (array) $paths,
                    $this->fallbackDirsPsr4
                );
            } else {
                $this->fallbackDirsPsr4 = array_merge(
                    $this->fallbackDirsPsr4,
                    (array) $paths
                );
            }
        } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
            // Register directories for a new namespace.
            $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) {
            // Prepend directories for an already registered namespace.
            $this->prefixDirsPsr4[$prefix] = array_merge(
                (array) $paths,
                $this->prefixDirsPsr4[$prefix]
            );
        } else {
            // Append directories for an already registered namespace.
            $this->prefixDirsPsr4[$prefix] = array_merge(
                $this->prefixDirsPsr4[$prefix],
                (array) $paths
            );
        }
    }

    /**
     * Registers a set of PSR-0 directories for a given prefix,
     * replacing any others previously set for this prefix.
     *
     * @param string          $prefix The prefix
     * @param string[]|string $paths  The PSR-0 base directories
     *
     * @return void
     */
    public function set($prefix, $paths)
    {
        if (!$prefix) {
            $this->fallbackDirsPsr0 = (array) $paths;
        } else {
            $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
        }
    }

    /**
     * Registers a set of PSR-4 directories for a given namespace,
     * replacing any others previously set for this namespace.
     *
     * @param string          $prefix The prefix/namespace, with trailing '\\'
     * @param string[]|string $paths  The PSR-4 base directories
     *
     * @throws \InvalidArgumentException
     *
     * @return void
     */
    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;
        }
    }

    /**
     * Turns on searching the include path for class files.
     *
     * @param bool $useIncludePath
     *
     * @return void
     */
    public function setUseIncludePath($useIncludePath)
    {
        $this->useIncludePath = $useIncludePath;
    }

    /**
     * Can be used to check if the autoloader uses the include path to check
     * for classes.
     *
     * @return bool
     */
    public function getUseIncludePath()
    {
        return $this->useIncludePath;
    }

    /**
     * Turns off searching the prefix and fallback directories for classes
     * that have not been registered with the class map.
     *
     * @param bool $classMapAuthoritative
     *
     * @return void
     */
    public function setClassMapAuthoritative($classMapAuthoritative)
    {
        $this->classMapAuthoritative = $classMapAuthoritative;
    }

    /**
     * Should class lookup fail if not found in the current class map?
     *
     * @return bool
     */
    public function isClassMapAuthoritative()
    {
        return $this->classMapAuthoritative;
    }

    /**
     * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
     *
     * @param string|null $apcuPrefix
     *
     * @return void
     */
    public function setApcuPrefix($apcuPrefix)
    {
        $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
    }

    /**
     * The APCu prefix in use, or null if APCu caching is not enabled.
     *
     * @return string|null
     */
    public function getApcuPrefix()
    {
        return $this->apcuPrefix;
    }

    /**
     * Registers this instance as an autoloader.
     *
     * @param bool $prepend Whether to prepend the autoloader or not
     *
     * @return void
     */
    public function register($prepend = false)
    {
        spl_autoload_register(array($this, 'loadClass'), true, $prepend);

        if (null === $this->vendorDir) {
            return;
        }

        if ($prepend) {
            self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
        } else {
            unset(self::$registeredLoaders[$this->vendorDir]);
            self::$registeredLoaders[$this->vendorDir] = $this;
        }
    }

    /**
     * Unregisters this instance as an autoloader.
     *
     * @return void
     */
    public function unregister()
    {
        spl_autoload_unregister(array($this, 'loadClass'));

        if (null !== $this->vendorDir) {
            unset(self::$registeredLoaders[$this->vendorDir]);
        }
    }

    /**
     * Loads the given class or interface.
     *
     * @param  string    $class The name of the class
     * @return true|null True if loaded, null otherwise
     */
    public function loadClass($class)
    {
        if ($file = $this->findFile($class)) {
            includeFile($file);

            return true;
        }

        return null;
    }

    /**
     * Finds the path to the file where the class is defined.
     *
     * @param string $class The name of the class
     *
     * @return string|false The path if found, false otherwise
     */
    public function findFile($class)
    {
        // class map lookup
        if (isset($this->classMap[$class])) {
            return $this->classMap[$class];
        }
        if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
            return false;
        }
        if (null !== $this->apcuPrefix) {
            $file = apcu_fetch($this->apcuPrefix.$class, $hit);
            if ($hit) {
                return $file;
            }
        }

        $file = $this->findFileWithExtension($class, '.php');

        // Search for Hack files if we are running on HHVM
        if (false === $file && defined('HHVM_VERSION')) {
            $file = $this->findFileWithExtension($class, '.hh');
        }

        if (null !== $this->apcuPrefix) {
            apcu_add($this->apcuPrefix.$class, $file);
        }

        if (false === $file) {
            // Remember that this class does not exist.
            $this->missingClasses[$class] = true;
        }

        return $file;
    }

    /**
     * Returns the currently registered loaders indexed by their corresponding vendor directories.
     *
     * @return self[]
     */
    public static function getRegisteredLoaders()
    {
        return self::$registeredLoaders;
    }

    /**
     * @param  string       $class
     * @param  string       $ext
     * @return string|false
     */
    private function findFileWithExtension($class, $ext)
    {
        // PSR-4 lookup
        $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;

        $first = $class[0];
        if (isset($this->prefixLengthsPsr4[$first])) {
            $subPath = $class;
            while (false !== $lastPos = strrpos($subPath, '\\')) {
                $subPath = substr($subPath, 0, $lastPos);
                $search = $subPath . '\\';
                if (isset($this->prefixDirsPsr4[$search])) {
                    $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
                    foreach ($this->prefixDirsPsr4[$search] as $dir) {
                        if (file_exists($file = $dir . $pathEnd)) {
                            return $file;
                        }
                    }
                }
            }
        }

        // PSR-4 fallback dirs
        foreach ($this->fallbackDirsPsr4 as $dir) {
            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
                return $file;
            }
        }

        // PSR-0 lookup
        if (false !== $pos = strrpos($class, '\\')) {
            // namespaced class name
            $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
                . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
        } else {
            // PEAR-like class name
            $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;
                        }
                    }
                }
            }
        }

        // PSR-0 fallback dirs
        foreach ($this->fallbackDirsPsr0 as $dir) {
            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
                return $file;
            }
        }

        // PSR-0 include paths.
        if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
            return $file;
        }

        return false;
    }
}

/**
 * Scope isolated include.
 *
 * Prevents access to $this/self from included files.
 *
 * @param  string $file
 * @return void
 * @private
 */
function includeFile($file)
{
    include $file;
}

Copyright (c) Nils Adermann, Jordi Boggiano

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

<?php

// autoload_namespaces.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
);
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

if (\PHP_VERSION_ID < 80000) {
    class ValueError extends Error
    {
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

if (\PHP_VERSION_ID < 80000) {
    class UnhandledMatchError extends Error
    {
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

if (\PHP_VERSION_ID < 80000) {
    interface Stringable
    {
        /**
         * @return string
         */
        public function __toString();
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

if (\PHP_VERSION_ID < 80000 && extension_loaded('tokenizer')) {
    class PhpToken extends Symfony\Polyfill\Php80\PhpToken
    {
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#[Attribute(Attribute::TARGET_CLASS)]
final class Attribute
{
    public const TARGET_CLASS = 1;
    public const TARGET_FUNCTION = 2;
    public const TARGET_METHOD = 4;
    public const TARGET_PROPERTY = 8;
    public const TARGET_CLASS_CONSTANT = 16;
    public const TARGET_PARAMETER = 32;
    public const TARGET_ALL = 63;
    public const IS_REPEATABLE = 64;

    /** @var int */
    public $flags;

    public function __construct(int $flags = self::TARGET_ALL)
    {
        $this->flags = $flags;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Polyfill\Php80;

/**
 * @author Fedonyuk Anton <info@ensostudio.ru>
 *
 * @internal
 */
class PhpToken implements \Stringable
{
    /**
     * @var int
     */
    public $id;
    /**
     * @var string
     */
    public $text;
    /**
     * @var int
     */
    public $line;
    /**
     * @var int
     */
    public $pos;
    public function __construct(int $id, string $text, int $line = -1, int $position = -1)
    {
        $this->id = $id;
        $this->text = $text;
        $this->line = $line;
        $this->pos = $position;
    }
    public function getTokenName() : ?string
    {
        if ('UNKNOWN' === ($name = \token_name($this->id))) {
            $name = \strlen($this->text) > 1 || \ord($this->text) < 32 ? null : $this->text;
        }
        return $name;
    }
    /**
     * @param int|string|array $kind
     */
    public function is($kind) : bool
    {
        foreach ((array) $kind as $value) {
            if (\in_array($value, [$this->id, $this->text], \true)) {
                return \true;
            }
        }
        return \false;
    }
    public function isIgnorable() : bool
    {
        return \in_array($this->id, [\T_WHITESPACE, \T_COMMENT, \T_DOC_COMMENT, \T_OPEN_TAG], \true);
    }
    public function __toString() : string
    {
        return (string) $this->text;
    }
    /**
     * @return static[]
     */
    public static function tokenize(string $code, int $flags = 0) : array
    {
        $line = 1;
        $position = 0;
        $tokens = \token_get_all($code, $flags);
        foreach ($tokens as $index => $token) {
            if (\is_string($token)) {
                $id = \ord($token);
                $text = $token;
            } else {
                [$id, $text, $line] = $token;
            }
            $tokens[$index] = new static($id, $text, $line, $position);
            $position += \strlen($text);
        }
        return $tokens;
    }
}
<?php

namespace CivixPhar;

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
use CivixPhar\Symfony\Polyfill\Php80 as p;
if (\PHP_VERSION_ID >= 80000) {
    return;
}
if (!\defined('FILTER_VALIDATE_BOOL') && \defined('FILTER_VALIDATE_BOOLEAN')) {
    \define('FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN);
}
if (!\function_exists('fdiv')) {
    function fdiv(float $num1, float $num2) : float
    {
        return p\Php80::fdiv($num1, $num2);
    }
}
if (!\function_exists('preg_last_error_msg')) {
    function preg_last_error_msg() : string
    {
        return p\Php80::preg_last_error_msg();
    }
}
if (!\function_exists('str_contains')) {
    function str_contains(?string $haystack, ?string $needle) : bool
    {
        return p\Php80::str_contains($haystack ?? '', $needle ?? '');
    }
}
if (!\function_exists('str_starts_with')) {
    function str_starts_with(?string $haystack, ?string $needle) : bool
    {
        return p\Php80::str_starts_with($haystack ?? '', $needle ?? '');
    }
}
if (!\function_exists('str_ends_with')) {
    function str_ends_with(?string $haystack, ?string $needle) : bool
    {
        return p\Php80::str_ends_with($haystack ?? '', $needle ?? '');
    }
}
if (!\function_exists('get_debug_type')) {
    function get_debug_type($value) : string
    {
        return p\Php80::get_debug_type($value);
    }
}
if (!\function_exists('get_resource_id')) {
    function get_resource_id($resource) : int
    {
        return p\Php80::get_resource_id($resource);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Polyfill\Php80;

/**
 * @author Ion Bazan <ion.bazan@gmail.com>
 * @author Nico Oelgart <nicoswd@gmail.com>
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @internal
 */
final class Php80
{
    public static function fdiv(float $dividend, float $divisor) : float
    {
        return @($dividend / $divisor);
    }
    public static function get_debug_type($value) : string
    {
        switch (\true) {
            case null === $value:
                return 'null';
            case \is_bool($value):
                return 'bool';
            case \is_string($value):
                return 'string';
            case \is_array($value):
                return 'array';
            case \is_int($value):
                return 'int';
            case \is_float($value):
                return 'float';
            case \is_object($value):
                break;
            case $value instanceof \__PHP_Incomplete_Class:
                return '__PHP_Incomplete_Class';
            default:
                if (null === ($type = @\get_resource_type($value))) {
                    return 'unknown';
                }
                if ('Unknown' === $type) {
                    $type = 'closed';
                }
                return "resource ({$type})";
        }
        $class = \get_class($value);
        if (\false === \strpos($class, '@')) {
            return $class;
        }
        return ((\get_parent_class($class) ?: \key(\class_implements($class))) ?: 'class') . '@anonymous';
    }
    public static function get_resource_id($res) : int
    {
        if (!\is_resource($res) && null === @\get_resource_type($res)) {
            throw new \TypeError(\sprintf('Argument 1 passed to get_resource_id() must be of the type resource, %s given', \get_debug_type($res)));
        }
        return (int) $res;
    }
    public static function preg_last_error_msg() : string
    {
        switch (\preg_last_error()) {
            case \PREG_INTERNAL_ERROR:
                return 'Internal error';
            case \PREG_BAD_UTF8_ERROR:
                return 'Malformed UTF-8 characters, possibly incorrectly encoded';
            case \PREG_BAD_UTF8_OFFSET_ERROR:
                return 'The offset did not correspond to the beginning of a valid UTF-8 code point';
            case \PREG_BACKTRACK_LIMIT_ERROR:
                return 'Backtrack limit exhausted';
            case \PREG_RECURSION_LIMIT_ERROR:
                return 'Recursion limit exhausted';
            case \PREG_JIT_STACKLIMIT_ERROR:
                return 'JIT stack limit exhausted';
            case \PREG_NO_ERROR:
                return 'No error';
            default:
                return 'Unknown error';
        }
    }
    public static function str_contains(string $haystack, string $needle) : bool
    {
        return '' === $needle || \false !== \strpos($haystack, $needle);
    }
    public static function str_starts_with(string $haystack, string $needle) : bool
    {
        return 0 === \strncmp($haystack, $needle, \strlen($needle));
    }
    public static function str_ends_with(string $haystack, string $needle) : bool
    {
        if ('' === $needle || $needle === $haystack) {
            return \true;
        }
        if ('' === $haystack) {
            return \false;
        }
        $needleLength = \strlen($needle);
        return $needleLength <= \strlen($haystack) && 0 === \substr_compare($haystack, $needle, -$needleLength);
    }
}
<?php

namespace CivixPhar;

return array('A' => 'a', 'B' => 'b', 'C' => 'c', 'D' => 'd', 'E' => 'e', 'F' => 'f', 'G' => 'g', 'H' => 'h', 'I' => 'i', 'J' => 'j', 'K' => 'k', 'L' => 'l', 'M' => 'm', 'N' => 'n', 'O' => 'o', 'P' => 'p', 'Q' => 'q', 'R' => 'r', 'S' => 's', 'T' => 't', 'U' => 'u', 'V' => 'v', 'W' => 'w', 'X' => 'x', 'Y' => 'y', 'Z' => 'z', 'Ã€' => 'Ã ', 'Ã�' => 'Ã¡', 'Ã‚' => 'Ã¢', 'Ãƒ' => 'Ã£', 'Ã„' => 'Ã¤', 'Ã…' => 'Ã¥', 'Ã†' => 'Ã¦', 'Ã‡' => 'Ã§', 'Ãˆ' => 'Ã¨', 'Ã‰' => 'Ã©', 'ÃŠ' => 'Ãª', 'Ã‹' => 'Ã«', 'ÃŒ' => 'Ã¬', 'Ã�' => 'Ã­', 'ÃŽ' => 'Ã®', 'Ã�' => 'Ã¯', 'Ã�' => 'Ã°', 'Ã‘' => 'Ã±', 'Ã’' => 'Ã²', 'Ã“' => 'Ã³', 'Ã”' => 'Ã´', 'Ã•' => 'Ãµ', 'Ã–' => 'Ã¶', 'Ã˜' => 'Ã¸', 'Ã™' => 'Ã¹', 'Ãš' => 'Ãº', 'Ã›' => 'Ã»', 'Ãœ' => 'Ã¼', 'Ã�' => 'Ã½', 'Ãž' => 'Ã¾', 'Ä€' => 'Ä�', 'Ä‚' => 'Äƒ', 'Ä„' => 'Ä…', 'Ä†' => 'Ä‡', 'Äˆ' => 'Ä‰', 'ÄŠ' => 'Ä‹', 'ÄŒ' => 'Ä�', 'ÄŽ' => 'Ä�', 'Ä�' => 'Ä‘', 'Ä’' => 'Ä“', 'Ä”' => 'Ä•', 'Ä–' => 'Ä—', 'Ä˜' => 'Ä™', 'Äš' => 'Ä›', 'Äœ' => 'Ä�', 'Äž' => 'ÄŸ', 'Ä ' => 'Ä¡', 'Ä¢' => 'Ä£', 'Ä¤' => 'Ä¥', 'Ä¦' => 'Ä§', 'Ä¨' => 'Ä©', 'Äª' => 'Ä«', 'Ä¬' => 'Ä­', 'Ä®' => 'Ä¯', 'Ä°' => 'i', 'Ä²' => 'Ä³', 'Ä´' => 'Äµ', 'Ä¶' => 'Ä·', 'Ä¹' => 'Äº', 'Ä»' => 'Ä¼', 'Ä½' => 'Ä¾', 'Ä¿' => 'Å€', 'Å�' => 'Å‚', 'Åƒ' => 'Å„', 'Å…' => 'Å†', 'Å‡' => 'Åˆ', 'ÅŠ' => 'Å‹', 'ÅŒ' => 'Å�', 'ÅŽ' => 'Å�', 'Å�' => 'Å‘', 'Å’' => 'Å“', 'Å”' => 'Å•', 'Å–' => 'Å—', 'Å˜' => 'Å™', 'Åš' => 'Å›', 'Åœ' => 'Å�', 'Åž' => 'ÅŸ', 'Å ' => 'Å¡', 'Å¢' => 'Å£', 'Å¤' => 'Å¥', 'Å¦' => 'Å§', 'Å¨' => 'Å©', 'Åª' => 'Å«', 'Å¬' => 'Å­', 'Å®' => 'Å¯', 'Å°' => 'Å±', 'Å²' => 'Å³', 'Å´' => 'Åµ', 'Å¶' => 'Å·', 'Å¸' => 'Ã¿', 'Å¹' => 'Åº', 'Å»' => 'Å¼', 'Å½' => 'Å¾', 'Æ�' => 'É“', 'Æ‚' => 'Æƒ', 'Æ„' => 'Æ…', 'Æ†' => 'É”', 'Æ‡' => 'Æˆ', 'Æ‰' => 'É–', 'ÆŠ' => 'É—', 'Æ‹' => 'ÆŒ', 'ÆŽ' => 'Ç�', 'Æ�' => 'É™', 'Æ�' => 'É›', 'Æ‘' => 'Æ’', 'Æ“' => 'É ', 'Æ”' => 'É£', 'Æ–' => 'É©', 'Æ—' => 'É¨', 'Æ˜' => 'Æ™', 'Æœ' => 'É¯', 'Æ�' => 'É²', 'ÆŸ' => 'Éµ', 'Æ ' => 'Æ¡', 'Æ¢' => 'Æ£', 'Æ¤' => 'Æ¥', 'Æ¦' => 'Ê€', 'Æ§' => 'Æ¨', 'Æ©' => 'Êƒ', 'Æ¬' => 'Æ­', 'Æ®' => 'Êˆ', 'Æ¯' => 'Æ°', 'Æ±' => 'ÊŠ', 'Æ²' => 'Ê‹', 'Æ³' => 'Æ´', 'Æµ' => 'Æ¶', 'Æ·' => 'Ê’', 'Æ¸' => 'Æ¹', 'Æ¼' => 'Æ½', 'Ç„' => 'Ç†', 'Ç…' => 'Ç†', 'Ç‡' => 'Ç‰', 'Çˆ' => 'Ç‰', 'ÇŠ' => 'ÇŒ', 'Ç‹' => 'ÇŒ', 'Ç�' => 'ÇŽ', 'Ç�' => 'Ç�', 'Ç‘' => 'Ç’', 'Ç“' => 'Ç”', 'Ç•' => 'Ç–', 'Ç—' => 'Ç˜', 'Ç™' => 'Çš', 'Ç›' => 'Çœ', 'Çž' => 'ÇŸ', 'Ç ' => 'Ç¡', 'Ç¢' => 'Ç£', 'Ç¤' => 'Ç¥', 'Ç¦' => 'Ç§', 'Ç¨' => 'Ç©', 'Çª' => 'Ç«', 'Ç¬' => 'Ç­', 'Ç®' => 'Ç¯', 'Ç±' => 'Ç³', 'Ç²' => 'Ç³', 'Ç´' => 'Çµ', 'Ç¶' => 'Æ•', 'Ç·' => 'Æ¿', 'Ç¸' => 'Ç¹', 'Çº' => 'Ç»', 'Ç¼' => 'Ç½', 'Ç¾' => 'Ç¿', 'È€' => 'È�', 'È‚' => 'Èƒ', 'È„' => 'È…', 'È†' => 'È‡', 'Èˆ' => 'È‰', 'ÈŠ' => 'È‹', 'ÈŒ' => 'È�', 'ÈŽ' => 'È�', 'È�' => 'È‘', 'È’' => 'È“', 'È”' => 'È•', 'È–' => 'È—', 'È˜' => 'È™', 'Èš' => 'È›', 'Èœ' => 'È�', 'Èž' => 'ÈŸ', 'È ' => 'Æž', 'È¢' => 'È£', 'È¤' => 'È¥', 'È¦' => 'È§', 'È¨' => 'È©', 'Èª' => 'È«', 'È¬' => 'È­', 'È®' => 'È¯', 'È°' => 'È±', 'È²' => 'È³', 'Èº' => 'â±¥', 'È»' => 'È¼', 'È½' => 'Æš', 'È¾' => 'â±¦', 'É�' => 'É‚', 'Éƒ' => 'Æ€', 'É„' => 'Ê‰', 'É…' => 'ÊŒ', 'É†' => 'É‡', 'Éˆ' => 'É‰', 'ÉŠ' => 'É‹', 'ÉŒ' => 'É�', 'ÉŽ' => 'É�', 'Í°' => 'Í±', 'Í²' => 'Í³', 'Í¶' => 'Í·', 'Í¿' => 'Ï³', 'Î†' => 'Î¬', 'Îˆ' => 'Î­', 'Î‰' => 'Î®', 'ÎŠ' => 'Î¯', 'ÎŒ' => 'ÏŒ', 'ÎŽ' => 'Ï�', 'Î�' => 'ÏŽ', 'Î‘' => 'Î±', 'Î’' => 'Î²', 'Î“' => 'Î³', 'Î”' => 'Î´', 'Î•' => 'Îµ', 'Î–' => 'Î¶', 'Î—' => 'Î·', 'Î˜' => 'Î¸', 'Î™' => 'Î¹', 'Îš' => 'Îº', 'Î›' => 'Î»', 'Îœ' => 'Î¼', 'Î�' => 'Î½', 'Îž' => 'Î¾', 'ÎŸ' => 'Î¿', 'Î ' => 'Ï€', 'Î¡' => 'Ï�', 'Î£' => 'Ïƒ', 'Î¤' => 'Ï„', 'Î¥' => 'Ï…', 'Î¦' => 'Ï†', 'Î§' => 'Ï‡', 'Î¨' => 'Ïˆ', 'Î©' => 'Ï‰', 'Îª' => 'ÏŠ', 'Î«' => 'Ï‹', 'Ï�' => 'Ï—', 'Ï˜' => 'Ï™', 'Ïš' => 'Ï›', 'Ïœ' => 'Ï�', 'Ïž' => 'ÏŸ', 'Ï ' => 'Ï¡', 'Ï¢' => 'Ï£', 'Ï¤' => 'Ï¥', 'Ï¦' => 'Ï§', 'Ï¨' => 'Ï©', 'Ïª' => 'Ï«', 'Ï¬' => 'Ï­', 'Ï®' => 'Ï¯', 'Ï´' => 'Î¸', 'Ï·' => 'Ï¸', 'Ï¹' => 'Ï²', 'Ïº' => 'Ï»', 'Ï½' => 'Í»', 'Ï¾' => 'Í¼', 'Ï¿' => 'Í½', 'Ð€' => 'Ñ�', 'Ð�' => 'Ñ‘', 'Ð‚' => 'Ñ’', 'Ðƒ' => 'Ñ“', 'Ð„' => 'Ñ”', 'Ð…' => 'Ñ•', 'Ð†' => 'Ñ–', 'Ð‡' => 'Ñ—', 'Ðˆ' => 'Ñ˜', 'Ð‰' => 'Ñ™', 'ÐŠ' => 'Ñš', 'Ð‹' => 'Ñ›', 'ÐŒ' => 'Ñœ', 'Ð�' => 'Ñ�', 'ÐŽ' => 'Ñž', 'Ð�' => 'ÑŸ', 'Ð�' => 'Ð°', 'Ð‘' => 'Ð±', 'Ð’' => 'Ð²', 'Ð“' => 'Ð³', 'Ð”' => 'Ð´', 'Ð•' => 'Ðµ', 'Ð–' => 'Ð¶', 'Ð—' => 'Ð·', 'Ð˜' => 'Ð¸', 'Ð™' => 'Ð¹', 'Ðš' => 'Ðº', 'Ð›' => 'Ð»', 'Ðœ' => 'Ð¼', 'Ð�' => 'Ð½', 'Ðž' => 'Ð¾', 'ÐŸ' => 'Ð¿', 'Ð ' => 'Ñ€', 'Ð¡' => 'Ñ�', 'Ð¢' => 'Ñ‚', 'Ð£' => 'Ñƒ', 'Ð¤' => 'Ñ„', 'Ð¥' => 'Ñ…', 'Ð¦' => 'Ñ†', 'Ð§' => 'Ñ‡', 'Ð¨' => 'Ñˆ', 'Ð©' => 'Ñ‰', 'Ðª' => 'ÑŠ', 'Ð«' => 'Ñ‹', 'Ð¬' => 'ÑŒ', 'Ð­' => 'Ñ�', 'Ð®' => 'ÑŽ', 'Ð¯' => 'Ñ�', 'Ñ ' => 'Ñ¡', 'Ñ¢' => 'Ñ£', 'Ñ¤' => 'Ñ¥', 'Ñ¦' => 'Ñ§', 'Ñ¨' => 'Ñ©', 'Ñª' => 'Ñ«', 'Ñ¬' => 'Ñ­', 'Ñ®' => 'Ñ¯', 'Ñ°' => 'Ñ±', 'Ñ²' => 'Ñ³', 'Ñ´' => 'Ñµ', 'Ñ¶' => 'Ñ·', 'Ñ¸' => 'Ñ¹', 'Ñº' => 'Ñ»', 'Ñ¼' => 'Ñ½', 'Ñ¾' => 'Ñ¿', 'Ò€' => 'Ò�', 'ÒŠ' => 'Ò‹', 'ÒŒ' => 'Ò�', 'ÒŽ' => 'Ò�', 'Ò�' => 'Ò‘', 'Ò’' => 'Ò“', 'Ò”' => 'Ò•', 'Ò–' => 'Ò—', 'Ò˜' => 'Ò™', 'Òš' => 'Ò›', 'Òœ' => 'Ò�', 'Òž' => 'ÒŸ', 'Ò ' => 'Ò¡', 'Ò¢' => 'Ò£', 'Ò¤' => 'Ò¥', 'Ò¦' => 'Ò§', 'Ò¨' => 'Ò©', 'Òª' => 'Ò«', 'Ò¬' => 'Ò­', 'Ò®' => 'Ò¯', 'Ò°' => 'Ò±', 'Ò²' => 'Ò³', 'Ò´' => 'Òµ', 'Ò¶' => 'Ò·', 'Ò¸' => 'Ò¹', 'Òº' => 'Ò»', 'Ò¼' => 'Ò½', 'Ò¾' => 'Ò¿', 'Ó€' => 'Ó�', 'Ó�' => 'Ó‚', 'Óƒ' => 'Ó„', 'Ó…' => 'Ó†', 'Ó‡' => 'Óˆ', 'Ó‰' => 'ÓŠ', 'Ó‹' => 'ÓŒ', 'Ó�' => 'ÓŽ', 'Ó�' => 'Ó‘', 'Ó’' => 'Ó“', 'Ó”' => 'Ó•', 'Ó–' => 'Ó—', 'Ó˜' => 'Ó™', 'Óš' => 'Ó›', 'Óœ' => 'Ó�', 'Óž' => 'ÓŸ', 'Ó ' => 'Ó¡', 'Ó¢' => 'Ó£', 'Ó¤' => 'Ó¥', 'Ó¦' => 'Ó§', 'Ó¨' => 'Ó©', 'Óª' => 'Ó«', 'Ó¬' => 'Ó­', 'Ó®' => 'Ó¯', 'Ó°' => 'Ó±', 'Ó²' => 'Ó³', 'Ó´' => 'Óµ', 'Ó¶' => 'Ó·', 'Ó¸' => 'Ó¹', 'Óº' => 'Ó»', 'Ó¼' => 'Ó½', 'Ó¾' => 'Ó¿', 'Ô€' => 'Ô�', 'Ô‚' => 'Ôƒ', 'Ô„' => 'Ô…', 'Ô†' => 'Ô‡', 'Ôˆ' => 'Ô‰', 'ÔŠ' => 'Ô‹', 'ÔŒ' => 'Ô�', 'ÔŽ' => 'Ô�', 'Ô�' => 'Ô‘', 'Ô’' => 'Ô“', 'Ô”' => 'Ô•', 'Ô–' => 'Ô—', 'Ô˜' => 'Ô™', 'Ôš' => 'Ô›', 'Ôœ' => 'Ô�', 'Ôž' => 'ÔŸ', 'Ô ' => 'Ô¡', 'Ô¢' => 'Ô£', 'Ô¤' => 'Ô¥', 'Ô¦' => 'Ô§', 'Ô¨' => 'Ô©', 'Ôª' => 'Ô«', 'Ô¬' => 'Ô­', 'Ô®' => 'Ô¯', 'Ô±' => 'Õ¡', 'Ô²' => 'Õ¢', 'Ô³' => 'Õ£', 'Ô´' => 'Õ¤', 'Ôµ' => 'Õ¥', 'Ô¶' => 'Õ¦', 'Ô·' => 'Õ§', 'Ô¸' => 'Õ¨', 'Ô¹' => 'Õ©', 'Ôº' => 'Õª', 'Ô»' => 'Õ«', 'Ô¼' => 'Õ¬', 'Ô½' => 'Õ­', 'Ô¾' => 'Õ®', 'Ô¿' => 'Õ¯', 'Õ€' => 'Õ°', 'Õ�' => 'Õ±', 'Õ‚' => 'Õ²', 'Õƒ' => 'Õ³', 'Õ„' => 'Õ´', 'Õ…' => 'Õµ', 'Õ†' => 'Õ¶', 'Õ‡' => 'Õ·', 'Õˆ' => 'Õ¸', 'Õ‰' => 'Õ¹', 'ÕŠ' => 'Õº', 'Õ‹' => 'Õ»', 'ÕŒ' => 'Õ¼', 'Õ�' => 'Õ½', 'ÕŽ' => 'Õ¾', 'Õ�' => 'Õ¿', 'Õ�' => 'Ö€', 'Õ‘' => 'Ö�', 'Õ’' => 'Ö‚', 'Õ“' => 'Öƒ', 'Õ”' => 'Ö„', 'Õ•' => 'Ö…', 'Õ–' => 'Ö†', 'á‚ ' => 'â´€', 'á‚¡' => 'â´�', 'á‚¢' => 'â´‚', 'á‚£' => 'â´ƒ', 'á‚¤' => 'â´„', 'á‚¥' => 'â´…', 'á‚¦' => 'â´†', 'á‚§' => 'â´‡', 'á‚¨' => 'â´ˆ', 'á‚©' => 'â´‰', 'á‚ª' => 'â´Š', 'á‚«' => 'â´‹', 'á‚¬' => 'â´Œ', 'á‚­' => 'â´�', 'á‚®' => 'â´Ž', 'á‚¯' => 'â´�', 'á‚°' => 'â´�', 'á‚±' => 'â´‘', 'á‚²' => 'â´’', 'á‚³' => 'â´“', 'á‚´' => 'â´”', 'á‚µ' => 'â´•', 'á‚¶' => 'â´–', 'á‚·' => 'â´—', 'á‚¸' => 'â´˜', 'á‚¹' => 'â´™', 'á‚º' => 'â´š', 'á‚»' => 'â´›', 'á‚¼' => 'â´œ', 'á‚½' => 'â´�', 'á‚¾' => 'â´ž', 'á‚¿' => 'â´Ÿ', 'áƒ€' => 'â´ ', 'áƒ�' => 'â´¡', 'áƒ‚' => 'â´¢', 'áƒƒ' => 'â´£', 'áƒ„' => 'â´¤', 'áƒ…' => 'â´¥', 'áƒ‡' => 'â´§', 'áƒ�' => 'â´­', 'áŽ ' => 'ê­°', 'áŽ¡' => 'ê­±', 'áŽ¢' => 'ê­²', 'áŽ£' => 'ê­³', 'áŽ¤' => 'ê­´', 'áŽ¥' => 'ê­µ', 'áŽ¦' => 'ê­¶', 'áŽ§' => 'ê­·', 'áŽ¨' => 'ê­¸', 'áŽ©' => 'ê­¹', 'áŽª' => 'ê­º', 'áŽ«' => 'ê­»', 'áŽ¬' => 'ê­¼', 'áŽ­' => 'ê­½', 'áŽ®' => 'ê­¾', 'áŽ¯' => 'ê­¿', 'áŽ°' => 'ê®€', 'áŽ±' => 'ê®�', 'áŽ²' => 'ê®‚', 'áŽ³' => 'ê®ƒ', 'áŽ´' => 'ê®„', 'áŽµ' => 'ê®…', 'áŽ¶' => 'ê®†', 'áŽ·' => 'ê®‡', 'áŽ¸' => 'ê®ˆ', 'áŽ¹' => 'ê®‰', 'áŽº' => 'ê®Š', 'áŽ»' => 'ê®‹', 'áŽ¼' => 'ê®Œ', 'áŽ½' => 'ê®�', 'áŽ¾' => 'ê®Ž', 'áŽ¿' => 'ê®�', 'á�€' => 'ê®�', 'á��' => 'ê®‘', 'á�‚' => 'ê®’', 'á�ƒ' => 'ê®“', 'á�„' => 'ê®”', 'á�…' => 'ê®•', 'á�†' => 'ê®–', 'á�‡' => 'ê®—', 'á�ˆ' => 'ê®˜', 'á�‰' => 'ê®™', 'á�Š' => 'ê®š', 'á�‹' => 'ê®›', 'á�Œ' => 'ê®œ', 'á��' => 'ê®�', 'á�Ž' => 'ê®ž', 'á��' => 'ê®Ÿ', 'á��' => 'ê® ', 'á�‘' => 'ê®¡', 'á�’' => 'ê®¢', 'á�“' => 'ê®£', 'á�”' => 'ê®¤', 'á�•' => 'ê®¥', 'á�–' => 'ê®¦', 'á�—' => 'ê®§', 'á�˜' => 'ê®¨', 'á�™' => 'ê®©', 'á�š' => 'ê®ª', 'á�›' => 'ê®«', 'á�œ' => 'ê®¬', 'á��' => 'ê®­', 'á�ž' => 'ê®®', 'á�Ÿ' => 'ê®¯', 'á� ' => 'ê®°', 'á�¡' => 'ê®±', 'á�¢' => 'ê®²', 'á�£' => 'ê®³', 'á�¤' => 'ê®´', 'á�¥' => 'ê®µ', 'á�¦' => 'ê®¶', 'á�§' => 'ê®·', 'á�¨' => 'ê®¸', 'á�©' => 'ê®¹', 'á�ª' => 'ê®º', 'á�«' => 'ê®»', 'á�¬' => 'ê®¼', 'á�­' => 'ê®½', 'á�®' => 'ê®¾', 'á�¯' => 'ê®¿', 'á�°' => 'á�¸', 'á�±' => 'á�¹', 'á�²' => 'á�º', 'á�³' => 'á�»', 'á�´' => 'á�¼', 'á�µ' => 'á�½', 'á²�' => 'áƒ�', 'á²‘' => 'áƒ‘', 'á²’' => 'áƒ’', 'á²“' => 'áƒ“', 'á²”' => 'áƒ”', 'á²•' => 'áƒ•', 'á²–' => 'áƒ–', 'á²—' => 'áƒ—', 'á²˜' => 'áƒ˜', 'á²™' => 'áƒ™', 'á²š' => 'áƒš', 'á²›' => 'áƒ›', 'á²œ' => 'áƒœ', 'á²�' => 'áƒ�', 'á²ž' => 'áƒž', 'á²Ÿ' => 'áƒŸ', 'á² ' => 'áƒ ', 'á²¡' => 'áƒ¡', 'á²¢' => 'áƒ¢', 'á²£' => 'áƒ£', 'á²¤' => 'áƒ¤', 'á²¥' => 'áƒ¥', 'á²¦' => 'áƒ¦', 'á²§' => 'áƒ§', 'á²¨' => 'áƒ¨', 'á²©' => 'áƒ©', 'á²ª' => 'áƒª', 'á²«' => 'áƒ«', 'á²¬' => 'áƒ¬', 'á²­' => 'áƒ­', 'á²®' => 'áƒ®', 'á²¯' => 'áƒ¯', 'á²°' => 'áƒ°', 'á²±' => 'áƒ±', 'á²²' => 'áƒ²', 'á²³' => 'áƒ³', 'á²´' => 'áƒ´', 'á²µ' => 'áƒµ', 'á²¶' => 'áƒ¶', 'á²·' => 'áƒ·', 'á²¸' => 'áƒ¸', 'á²¹' => 'áƒ¹', 'á²º' => 'áƒº', 'á²½' => 'áƒ½', 'á²¾' => 'áƒ¾', 'á²¿' => 'áƒ¿', 'á¸€' => 'á¸�', 'á¸‚' => 'á¸ƒ', 'á¸„' => 'á¸…', 'á¸†' => 'á¸‡', 'á¸ˆ' => 'á¸‰', 'á¸Š' => 'á¸‹', 'á¸Œ' => 'á¸�', 'á¸Ž' => 'á¸�', 'á¸�' => 'á¸‘', 'á¸’' => 'á¸“', 'á¸”' => 'á¸•', 'á¸–' => 'á¸—', 'á¸˜' => 'á¸™', 'á¸š' => 'á¸›', 'á¸œ' => 'á¸�', 'á¸ž' => 'á¸Ÿ', 'á¸ ' => 'á¸¡', 'á¸¢' => 'á¸£', 'á¸¤' => 'á¸¥', 'á¸¦' => 'á¸§', 'á¸¨' => 'á¸©', 'á¸ª' => 'á¸«', 'á¸¬' => 'á¸­', 'á¸®' => 'á¸¯', 'á¸°' => 'á¸±', 'á¸²' => 'á¸³', 'á¸´' => 'á¸µ', 'á¸¶' => 'á¸·', 'á¸¸' => 'á¸¹', 'á¸º' => 'á¸»', 'á¸¼' => 'á¸½', 'á¸¾' => 'á¸¿', 'á¹€' => 'á¹�', 'á¹‚' => 'á¹ƒ', 'á¹„' => 'á¹…', 'á¹†' => 'á¹‡', 'á¹ˆ' => 'á¹‰', 'á¹Š' => 'á¹‹', 'á¹Œ' => 'á¹�', 'á¹Ž' => 'á¹�', 'á¹�' => 'á¹‘', 'á¹’' => 'á¹“', 'á¹”' => 'á¹•', 'á¹–' => 'á¹—', 'á¹˜' => 'á¹™', 'á¹š' => 'á¹›', 'á¹œ' => 'á¹�', 'á¹ž' => 'á¹Ÿ', 'á¹ ' => 'á¹¡', 'á¹¢' => 'á¹£', 'á¹¤' => 'á¹¥', 'á¹¦' => 'á¹§', 'á¹¨' => 'á¹©', 'á¹ª' => 'á¹«', 'á¹¬' => 'á¹­', 'á¹®' => 'á¹¯', 'á¹°' => 'á¹±', 'á¹²' => 'á¹³', 'á¹´' => 'á¹µ', 'á¹¶' => 'á¹·', 'á¹¸' => 'á¹¹', 'á¹º' => 'á¹»', 'á¹¼' => 'á¹½', 'á¹¾' => 'á¹¿', 'áº€' => 'áº�', 'áº‚' => 'áºƒ', 'áº„' => 'áº…', 'áº†' => 'áº‡', 'áºˆ' => 'áº‰', 'áºŠ' => 'áº‹', 'áºŒ' => 'áº�', 'áºŽ' => 'áº�', 'áº�' => 'áº‘', 'áº’' => 'áº“', 'áº”' => 'áº•', 'áºž' => 'ÃŸ', 'áº ' => 'áº¡', 'áº¢' => 'áº£', 'áº¤' => 'áº¥', 'áº¦' => 'áº§', 'áº¨' => 'áº©', 'áºª' => 'áº«', 'áº¬' => 'áº­', 'áº®' => 'áº¯', 'áº°' => 'áº±', 'áº²' => 'áº³', 'áº´' => 'áºµ', 'áº¶' => 'áº·', 'áº¸' => 'áº¹', 'áºº' => 'áº»', 'áº¼' => 'áº½', 'áº¾' => 'áº¿', 'á»€' => 'á»�', 'á»‚' => 'á»ƒ', 'á»„' => 'á»…', 'á»†' => 'á»‡', 'á»ˆ' => 'á»‰', 'á»Š' => 'á»‹', 'á»Œ' => 'á»�', 'á»Ž' => 'á»�', 'á»�' => 'á»‘', 'á»’' => 'á»“', 'á»”' => 'á»•', 'á»–' => 'á»—', 'á»˜' => 'á»™', 'á»š' => 'á»›', 'á»œ' => 'á»�', 'á»ž' => 'á»Ÿ', 'á» ' => 'á»¡', 'á»¢' => 'á»£', 'á»¤' => 'á»¥', 'á»¦' => 'á»§', 'á»¨' => 'á»©', 'á»ª' => 'á»«', 'á»¬' => 'á»­', 'á»®' => 'á»¯', 'á»°' => 'á»±', 'á»²' => 'á»³', 'á»´' => 'á»µ', 'á»¶' => 'á»·', 'á»¸' => 'á»¹', 'á»º' => 'á»»', 'á»¼' => 'á»½', 'á»¾' => 'á»¿', 'á¼ˆ' => 'á¼€', 'á¼‰' => 'á¼�', 'á¼Š' => 'á¼‚', 'á¼‹' => 'á¼ƒ', 'á¼Œ' => 'á¼„', 'á¼�' => 'á¼…', 'á¼Ž' => 'á¼†', 'á¼�' => 'á¼‡', 'á¼˜' => 'á¼�', 'á¼™' => 'á¼‘', 'á¼š' => 'á¼’', 'á¼›' => 'á¼“', 'á¼œ' => 'á¼”', 'á¼�' => 'á¼•', 'á¼¨' => 'á¼ ', 'á¼©' => 'á¼¡', 'á¼ª' => 'á¼¢', 'á¼«' => 'á¼£', 'á¼¬' => 'á¼¤', 'á¼­' => 'á¼¥', 'á¼®' => 'á¼¦', 'á¼¯' => 'á¼§', 'á¼¸' => 'á¼°', 'á¼¹' => 'á¼±', 'á¼º' => 'á¼²', 'á¼»' => 'á¼³', 'á¼¼' => 'á¼´', 'á¼½' => 'á¼µ', 'á¼¾' => 'á¼¶', 'á¼¿' => 'á¼·', 'á½ˆ' => 'á½€', 'á½‰' => 'á½�', 'á½Š' => 'á½‚', 'á½‹' => 'á½ƒ', 'á½Œ' => 'á½„', 'á½�' => 'á½…', 'á½™' => 'á½‘', 'á½›' => 'á½“', 'á½�' => 'á½•', 'á½Ÿ' => 'á½—', 'á½¨' => 'á½ ', 'á½©' => 'á½¡', 'á½ª' => 'á½¢', 'á½«' => 'á½£', 'á½¬' => 'á½¤', 'á½­' => 'á½¥', 'á½®' => 'á½¦', 'á½¯' => 'á½§', 'á¾ˆ' => 'á¾€', 'á¾‰' => 'á¾�', 'á¾Š' => 'á¾‚', 'á¾‹' => 'á¾ƒ', 'á¾Œ' => 'á¾„', 'á¾�' => 'á¾…', 'á¾Ž' => 'á¾†', 'á¾�' => 'á¾‡', 'á¾˜' => 'á¾�', 'á¾™' => 'á¾‘', 'á¾š' => 'á¾’', 'á¾›' => 'á¾“', 'á¾œ' => 'á¾”', 'á¾�' => 'á¾•', 'á¾ž' => 'á¾–', 'á¾Ÿ' => 'á¾—', 'á¾¨' => 'á¾ ', 'á¾©' => 'á¾¡', 'á¾ª' => 'á¾¢', 'á¾«' => 'á¾£', 'á¾¬' => 'á¾¤', 'á¾­' => 'á¾¥', 'á¾®' => 'á¾¦', 'á¾¯' => 'á¾§', 'á¾¸' => 'á¾°', 'á¾¹' => 'á¾±', 'á¾º' => 'á½°', 'á¾»' => 'á½±', 'á¾¼' => 'á¾³', 'á¿ˆ' => 'á½²', 'á¿‰' => 'á½³', 'á¿Š' => 'á½´', 'á¿‹' => 'á½µ', 'á¿Œ' => 'á¿ƒ', 'á¿˜' => 'á¿�', 'á¿™' => 'á¿‘', 'á¿š' => 'á½¶', 'á¿›' => 'á½·', 'á¿¨' => 'á¿ ', 'á¿©' => 'á¿¡', 'á¿ª' => 'á½º', 'á¿«' => 'á½»', 'á¿¬' => 'á¿¥', 'á¿¸' => 'á½¸', 'á¿¹' => 'á½¹', 'á¿º' => 'á½¼', 'á¿»' => 'á½½', 'á¿¼' => 'á¿³', 'â„¦' => 'Ï‰', 'â„ª' => 'k', 'â„«' => 'Ã¥', 'â„²' => 'â…Ž', 'â… ' => 'â…°', 'â…¡' => 'â…±', 'â…¢' => 'â…²', 'â…£' => 'â…³', 'â…¤' => 'â…´', 'â…¥' => 'â…µ', 'â…¦' => 'â…¶', 'â…§' => 'â…·', 'â…¨' => 'â…¸', 'â…©' => 'â…¹', 'â…ª' => 'â…º', 'â…«' => 'â…»', 'â…¬' => 'â…¼', 'â…­' => 'â…½', 'â…®' => 'â…¾', 'â…¯' => 'â…¿', 'â†ƒ' => 'â†„', 'â’¶' => 'â“�', 'â’·' => 'â“‘', 'â’¸' => 'â“’', 'â’¹' => 'â““', 'â’º' => 'â“”', 'â’»' => 'â“•', 'â’¼' => 'â“–', 'â’½' => 'â“—', 'â’¾' => 'â“˜', 'â’¿' => 'â“™', 'â“€' => 'â“š', 'â“�' => 'â“›', 'â“‚' => 'â“œ', 'â“ƒ' => 'â“�', 'â“„' => 'â“ž', 'â“…' => 'â“Ÿ', 'â“†' => 'â“ ', 'â“‡' => 'â“¡', 'â“ˆ' => 'â“¢', 'â“‰' => 'â“£', 'â“Š' => 'â“¤', 'â“‹' => 'â“¥', 'â“Œ' => 'â“¦', 'â“�' => 'â“§', 'â“Ž' => 'â“¨', 'â“�' => 'â“©', 'â°€' => 'â°°', 'â°�' => 'â°±', 'â°‚' => 'â°²', 'â°ƒ' => 'â°³', 'â°„' => 'â°´', 'â°…' => 'â°µ', 'â°†' => 'â°¶', 'â°‡' => 'â°·', 'â°ˆ' => 'â°¸', 'â°‰' => 'â°¹', 'â°Š' => 'â°º', 'â°‹' => 'â°»', 'â°Œ' => 'â°¼', 'â°�' => 'â°½', 'â°Ž' => 'â°¾', 'â°�' => 'â°¿', 'â°�' => 'â±€', 'â°‘' => 'â±�', 'â°’' => 'â±‚', 'â°“' => 'â±ƒ', 'â°”' => 'â±„', 'â°•' => 'â±…', 'â°–' => 'â±†', 'â°—' => 'â±‡', 'â°˜' => 'â±ˆ', 'â°™' => 'â±‰', 'â°š' => 'â±Š', 'â°›' => 'â±‹', 'â°œ' => 'â±Œ', 'â°�' => 'â±�', 'â°ž' => 'â±Ž', 'â°Ÿ' => 'â±�', 'â° ' => 'â±�', 'â°¡' => 'â±‘', 'â°¢' => 'â±’', 'â°£' => 'â±“', 'â°¤' => 'â±”', 'â°¥' => 'â±•', 'â°¦' => 'â±–', 'â°§' => 'â±—', 'â°¨' => 'â±˜', 'â°©' => 'â±™', 'â°ª' => 'â±š', 'â°«' => 'â±›', 'â°¬' => 'â±œ', 'â°­' => 'â±�', 'â°®' => 'â±ž', 'â± ' => 'â±¡', 'â±¢' => 'É«', 'â±£' => 'áµ½', 'â±¤' => 'É½', 'â±§' => 'â±¨', 'â±©' => 'â±ª', 'â±«' => 'â±¬', 'â±­' => 'É‘', 'â±®' => 'É±', 'â±¯' => 'É�', 'â±°' => 'É’', 'â±²' => 'â±³', 'â±µ' => 'â±¶', 'â±¾' => 'È¿', 'â±¿' => 'É€', 'â²€' => 'â²�', 'â²‚' => 'â²ƒ', 'â²„' => 'â²…', 'â²†' => 'â²‡', 'â²ˆ' => 'â²‰', 'â²Š' => 'â²‹', 'â²Œ' => 'â²�', 'â²Ž' => 'â²�', 'â²�' => 'â²‘', 'â²’' => 'â²“', 'â²”' => 'â²•', 'â²–' => 'â²—', 'â²˜' => 'â²™', 'â²š' => 'â²›', 'â²œ' => 'â²�', 'â²ž' => 'â²Ÿ', 'â² ' => 'â²¡', 'â²¢' => 'â²£', 'â²¤' => 'â²¥', 'â²¦' => 'â²§', 'â²¨' => 'â²©', 'â²ª' => 'â²«', 'â²¬' => 'â²­', 'â²®' => 'â²¯', 'â²°' => 'â²±', 'â²²' => 'â²³', 'â²´' => 'â²µ', 'â²¶' => 'â²·', 'â²¸' => 'â²¹', 'â²º' => 'â²»', 'â²¼' => 'â²½', 'â²¾' => 'â²¿', 'â³€' => 'â³�', 'â³‚' => 'â³ƒ', 'â³„' => 'â³…', 'â³†' => 'â³‡', 'â³ˆ' => 'â³‰', 'â³Š' => 'â³‹', 'â³Œ' => 'â³�', 'â³Ž' => 'â³�', 'â³�' => 'â³‘', 'â³’' => 'â³“', 'â³”' => 'â³•', 'â³–' => 'â³—', 'â³˜' => 'â³™', 'â³š' => 'â³›', 'â³œ' => 'â³�', 'â³ž' => 'â³Ÿ', 'â³ ' => 'â³¡', 'â³¢' => 'â³£', 'â³«' => 'â³¬', 'â³­' => 'â³®', 'â³²' => 'â³³', 'ê™€' => 'ê™�', 'ê™‚' => 'ê™ƒ', 'ê™„' => 'ê™…', 'ê™†' => 'ê™‡', 'ê™ˆ' => 'ê™‰', 'ê™Š' => 'ê™‹', 'ê™Œ' => 'ê™�', 'ê™Ž' => 'ê™�', 'ê™�' => 'ê™‘', 'ê™’' => 'ê™“', 'ê™”' => 'ê™•', 'ê™–' => 'ê™—', 'ê™˜' => 'ê™™', 'ê™š' => 'ê™›', 'ê™œ' => 'ê™�', 'ê™ž' => 'ê™Ÿ', 'ê™ ' => 'ê™¡', 'ê™¢' => 'ê™£', 'ê™¤' => 'ê™¥', 'ê™¦' => 'ê™§', 'ê™¨' => 'ê™©', 'ê™ª' => 'ê™«', 'ê™¬' => 'ê™­', 'êš€' => 'êš�', 'êš‚' => 'êšƒ', 'êš„' => 'êš…', 'êš†' => 'êš‡', 'êšˆ' => 'êš‰', 'êšŠ' => 'êš‹', 'êšŒ' => 'êš�', 'êšŽ' => 'êš�', 'êš�' => 'êš‘', 'êš’' => 'êš“', 'êš”' => 'êš•', 'êš–' => 'êš—', 'êš˜' => 'êš™', 'êšš' => 'êš›', 'êœ¢' => 'êœ£', 'êœ¤' => 'êœ¥', 'êœ¦' => 'êœ§', 'êœ¨' => 'êœ©', 'êœª' => 'êœ«', 'êœ¬' => 'êœ­', 'êœ®' => 'êœ¯', 'êœ²' => 'êœ³', 'êœ´' => 'êœµ', 'êœ¶' => 'êœ·', 'êœ¸' => 'êœ¹', 'êœº' => 'êœ»', 'êœ¼' => 'êœ½', 'êœ¾' => 'êœ¿', 'ê�€' => 'ê��', 'ê�‚' => 'ê�ƒ', 'ê�„' => 'ê�…', 'ê�†' => 'ê�‡', 'ê�ˆ' => 'ê�‰', 'ê�Š' => 'ê�‹', 'ê�Œ' => 'ê��', 'ê�Ž' => 'ê��', 'ê��' => 'ê�‘', 'ê�’' => 'ê�“', 'ê�”' => 'ê�•', 'ê�–' => 'ê�—', 'ê�˜' => 'ê�™', 'ê�š' => 'ê�›', 'ê�œ' => 'ê��', 'ê�ž' => 'ê�Ÿ', 'ê� ' => 'ê�¡', 'ê�¢' => 'ê�£', 'ê�¤' => 'ê�¥', 'ê�¦' => 'ê�§', 'ê�¨' => 'ê�©', 'ê�ª' => 'ê�«', 'ê�¬' => 'ê�­', 'ê�®' => 'ê�¯', 'ê�¹' => 'ê�º', 'ê�»' => 'ê�¼', 'ê�½' => 'áµ¹', 'ê�¾' => 'ê�¿', 'êž€' => 'êž�', 'êž‚' => 'êžƒ', 'êž„' => 'êž…', 'êž†' => 'êž‡', 'êž‹' => 'êžŒ', 'êž�' => 'É¥', 'êž�' => 'êž‘', 'êž’' => 'êž“', 'êž–' => 'êž—', 'êž˜' => 'êž™', 'êžš' => 'êž›', 'êžœ' => 'êž�', 'êžž' => 'êžŸ', 'êž ' => 'êž¡', 'êž¢' => 'êž£', 'êž¤' => 'êž¥', 'êž¦' => 'êž§', 'êž¨' => 'êž©', 'êžª' => 'É¦', 'êž«' => 'Éœ', 'êž¬' => 'É¡', 'êž­' => 'É¬', 'êž®' => 'Éª', 'êž°' => 'Êž', 'êž±' => 'Ê‡', 'êž²' => 'Ê�', 'êž³' => 'ê­“', 'êž´' => 'êžµ', 'êž¶' => 'êž·', 'êž¸' => 'êž¹', 'êžº' => 'êž»', 'êž¼' => 'êž½', 'êž¾' => 'êž¿', 'êŸ‚' => 'êŸƒ', 'êŸ„' => 'êž”', 'êŸ…' => 'Ê‚', 'êŸ†' => 'á¶Ž', 'êŸ‡' => 'êŸˆ', 'êŸ‰' => 'êŸŠ', 'êŸµ' => 'êŸ¶', 'ï¼¡' => 'ï½�', 'ï¼¢' => 'ï½‚', 'ï¼£' => 'ï½ƒ', 'ï¼¤' => 'ï½„', 'ï¼¥' => 'ï½…', 'ï¼¦' => 'ï½†', 'ï¼§' => 'ï½‡', 'ï¼¨' => 'ï½ˆ', 'ï¼©' => 'ï½‰', 'ï¼ª' => 'ï½Š', 'ï¼«' => 'ï½‹', 'ï¼¬' => 'ï½Œ', 'ï¼­' => 'ï½�', 'ï¼®' => 'ï½Ž', 'ï¼¯' => 'ï½�', 'ï¼°' => 'ï½�', 'ï¼±' => 'ï½‘', 'ï¼²' => 'ï½’', 'ï¼³' => 'ï½“', 'ï¼´' => 'ï½”', 'ï¼µ' => 'ï½•', 'ï¼¶' => 'ï½–', 'ï¼·' => 'ï½—', 'ï¼¸' => 'ï½˜', 'ï¼¹' => 'ï½™', 'ï¼º' => 'ï½š', 'ð��€' => 'ð��¨', 'ð���' => 'ð��©', 'ð��‚' => 'ð��ª', 'ð��ƒ' => 'ð��«', 'ð��„' => 'ð��¬', 'ð��…' => 'ð��­', 'ð��†' => 'ð��®', 'ð��‡' => 'ð��¯', 'ð��ˆ' => 'ð��°', 'ð��‰' => 'ð��±', 'ð��Š' => 'ð��²', 'ð��‹' => 'ð��³', 'ð��Œ' => 'ð��´', 'ð���' => 'ð��µ', 'ð��Ž' => 'ð��¶', 'ð���' => 'ð��·', 'ð���' => 'ð��¸', 'ð��‘' => 'ð��¹', 'ð��’' => 'ð��º', 'ð��“' => 'ð��»', 'ð��”' => 'ð��¼', 'ð��•' => 'ð��½', 'ð��–' => 'ð��¾', 'ð��—' => 'ð��¿', 'ð��˜' => 'ð�‘€', 'ð��™' => 'ð�‘�', 'ð��š' => 'ð�‘‚', 'ð��›' => 'ð�‘ƒ', 'ð��œ' => 'ð�‘„', 'ð���' => 'ð�‘…', 'ð��ž' => 'ð�‘†', 'ð��Ÿ' => 'ð�‘‡', 'ð�� ' => 'ð�‘ˆ', 'ð��¡' => 'ð�‘‰', 'ð��¢' => 'ð�‘Š', 'ð��£' => 'ð�‘‹', 'ð��¤' => 'ð�‘Œ', 'ð��¥' => 'ð�‘�', 'ð��¦' => 'ð�‘Ž', 'ð��§' => 'ð�‘�', 'ð�’°' => 'ð�“˜', 'ð�’±' => 'ð�“™', 'ð�’²' => 'ð�“š', 'ð�’³' => 'ð�“›', 'ð�’´' => 'ð�“œ', 'ð�’µ' => 'ð�“�', 'ð�’¶' => 'ð�“ž', 'ð�’·' => 'ð�“Ÿ', 'ð�’¸' => 'ð�“ ', 'ð�’¹' => 'ð�“¡', 'ð�’º' => 'ð�“¢', 'ð�’»' => 'ð�“£', 'ð�’¼' => 'ð�“¤', 'ð�’½' => 'ð�“¥', 'ð�’¾' => 'ð�“¦', 'ð�’¿' => 'ð�“§', 'ð�“€' => 'ð�“¨', 'ð�“�' => 'ð�“©', 'ð�“‚' => 'ð�“ª', 'ð�“ƒ' => 'ð�“«', 'ð�“„' => 'ð�“¬', 'ð�“…' => 'ð�“­', 'ð�“†' => 'ð�“®', 'ð�“‡' => 'ð�“¯', 'ð�“ˆ' => 'ð�“°', 'ð�“‰' => 'ð�“±', 'ð�“Š' => 'ð�“²', 'ð�“‹' => 'ð�“³', 'ð�“Œ' => 'ð�“´', 'ð�“�' => 'ð�“µ', 'ð�“Ž' => 'ð�“¶', 'ð�“�' => 'ð�“·', 'ð�“�' => 'ð�“¸', 'ð�“‘' => 'ð�“¹', 'ð�“’' => 'ð�“º', 'ð�““' => 'ð�“»', 'ð�²€' => 'ð�³€', 'ð�²�' => 'ð�³�', 'ð�²‚' => 'ð�³‚', 'ð�²ƒ' => 'ð�³ƒ', 'ð�²„' => 'ð�³„', 'ð�²…' => 'ð�³…', 'ð�²†' => 'ð�³†', 'ð�²‡' => 'ð�³‡', 'ð�²ˆ' => 'ð�³ˆ', 'ð�²‰' => 'ð�³‰', 'ð�²Š' => 'ð�³Š', 'ð�²‹' => 'ð�³‹', 'ð�²Œ' => 'ð�³Œ', 'ð�²�' => 'ð�³�', 'ð�²Ž' => 'ð�³Ž', 'ð�²�' => 'ð�³�', 'ð�²�' => 'ð�³�', 'ð�²‘' => 'ð�³‘', 'ð�²’' => 'ð�³’', 'ð�²“' => 'ð�³“', 'ð�²”' => 'ð�³”', 'ð�²•' => 'ð�³•', 'ð�²–' => 'ð�³–', 'ð�²—' => 'ð�³—', 'ð�²˜' => 'ð�³˜', 'ð�²™' => 'ð�³™', 'ð�²š' => 'ð�³š', 'ð�²›' => 'ð�³›', 'ð�²œ' => 'ð�³œ', 'ð�²�' => 'ð�³�', 'ð�²ž' => 'ð�³ž', 'ð�²Ÿ' => 'ð�³Ÿ', 'ð�² ' => 'ð�³ ', 'ð�²¡' => 'ð�³¡', 'ð�²¢' => 'ð�³¢', 'ð�²£' => 'ð�³£', 'ð�²¤' => 'ð�³¤', 'ð�²¥' => 'ð�³¥', 'ð�²¦' => 'ð�³¦', 'ð�²§' => 'ð�³§', 'ð�²¨' => 'ð�³¨', 'ð�²©' => 'ð�³©', 'ð�²ª' => 'ð�³ª', 'ð�²«' => 'ð�³«', 'ð�²¬' => 'ð�³¬', 'ð�²­' => 'ð�³­', 'ð�²®' => 'ð�³®', 'ð�²¯' => 'ð�³¯', 'ð�²°' => 'ð�³°', 'ð�²±' => 'ð�³±', 'ð�²²' => 'ð�³²', 'ð‘¢ ' => 'ð‘£€', 'ð‘¢¡' => 'ð‘£�', 'ð‘¢¢' => 'ð‘£‚', 'ð‘¢£' => 'ð‘£ƒ', 'ð‘¢¤' => 'ð‘£„', 'ð‘¢¥' => 'ð‘£…', 'ð‘¢¦' => 'ð‘£†', 'ð‘¢§' => 'ð‘£‡', 'ð‘¢¨' => 'ð‘£ˆ', 'ð‘¢©' => 'ð‘£‰', 'ð‘¢ª' => 'ð‘£Š', 'ð‘¢«' => 'ð‘£‹', 'ð‘¢¬' => 'ð‘£Œ', 'ð‘¢­' => 'ð‘£�', 'ð‘¢®' => 'ð‘£Ž', 'ð‘¢¯' => 'ð‘£�', 'ð‘¢°' => 'ð‘£�', 'ð‘¢±' => 'ð‘£‘', 'ð‘¢²' => 'ð‘£’', 'ð‘¢³' => 'ð‘£“', 'ð‘¢´' => 'ð‘£”', 'ð‘¢µ' => 'ð‘£•', 'ð‘¢¶' => 'ð‘£–', 'ð‘¢·' => 'ð‘£—', 'ð‘¢¸' => 'ð‘£˜', 'ð‘¢¹' => 'ð‘£™', 'ð‘¢º' => 'ð‘£š', 'ð‘¢»' => 'ð‘£›', 'ð‘¢¼' => 'ð‘£œ', 'ð‘¢½' => 'ð‘£�', 'ð‘¢¾' => 'ð‘£ž', 'ð‘¢¿' => 'ð‘£Ÿ', 'ð–¹€' => 'ð–¹ ', 'ð–¹�' => 'ð–¹¡', 'ð–¹‚' => 'ð–¹¢', 'ð–¹ƒ' => 'ð–¹£', 'ð–¹„' => 'ð–¹¤', 'ð–¹…' => 'ð–¹¥', 'ð–¹†' => 'ð–¹¦', 'ð–¹‡' => 'ð–¹§', 'ð–¹ˆ' => 'ð–¹¨', 'ð–¹‰' => 'ð–¹©', 'ð–¹Š' => 'ð–¹ª', 'ð–¹‹' => 'ð–¹«', 'ð–¹Œ' => 'ð–¹¬', 'ð–¹�' => 'ð–¹­', 'ð–¹Ž' => 'ð–¹®', 'ð–¹�' => 'ð–¹¯', 'ð–¹�' => 'ð–¹°', 'ð–¹‘' => 'ð–¹±', 'ð–¹’' => 'ð–¹²', 'ð–¹“' => 'ð–¹³', 'ð–¹”' => 'ð–¹´', 'ð–¹•' => 'ð–¹µ', 'ð–¹–' => 'ð–¹¶', 'ð–¹—' => 'ð–¹·', 'ð–¹˜' => 'ð–¹¸', 'ð–¹™' => 'ð–¹¹', 'ð–¹š' => 'ð–¹º', 'ð–¹›' => 'ð–¹»', 'ð–¹œ' => 'ð–¹¼', 'ð–¹�' => 'ð–¹½', 'ð–¹ž' => 'ð–¹¾', 'ð–¹Ÿ' => 'ð–¹¿', 'ðž¤€' => 'ðž¤¢', 'ðž¤�' => 'ðž¤£', 'ðž¤‚' => 'ðž¤¤', 'ðž¤ƒ' => 'ðž¤¥', 'ðž¤„' => 'ðž¤¦', 'ðž¤…' => 'ðž¤§', 'ðž¤†' => 'ðž¤¨', 'ðž¤‡' => 'ðž¤©', 'ðž¤ˆ' => 'ðž¤ª', 'ðž¤‰' => 'ðž¤«', 'ðž¤Š' => 'ðž¤¬', 'ðž¤‹' => 'ðž¤­', 'ðž¤Œ' => 'ðž¤®', 'ðž¤�' => 'ðž¤¯', 'ðž¤Ž' => 'ðž¤°', 'ðž¤�' => 'ðž¤±', 'ðž¤�' => 'ðž¤²', 'ðž¤‘' => 'ðž¤³', 'ðž¤’' => 'ðž¤´', 'ðž¤“' => 'ðž¤µ', 'ðž¤”' => 'ðž¤¶', 'ðž¤•' => 'ðž¤·', 'ðž¤–' => 'ðž¤¸', 'ðž¤—' => 'ðž¤¹', 'ðž¤˜' => 'ðž¤º', 'ðž¤™' => 'ðž¤»', 'ðž¤š' => 'ðž¤¼', 'ðž¤›' => 'ðž¤½', 'ðž¤œ' => 'ðž¤¾', 'ðž¤�' => 'ðž¤¿', 'ðž¤ž' => 'ðž¥€', 'ðž¤Ÿ' => 'ðž¥�', 'ðž¤ ' => 'ðž¥‚', 'ðž¤¡' => 'ðž¥ƒ');
<?php

namespace CivixPhar;

return array('a' => 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D', 'e' => 'E', 'f' => 'F', 'g' => 'G', 'h' => 'H', 'i' => 'I', 'j' => 'J', 'k' => 'K', 'l' => 'L', 'm' => 'M', 'n' => 'N', 'o' => 'O', 'p' => 'P', 'q' => 'Q', 'r' => 'R', 's' => 'S', 't' => 'T', 'u' => 'U', 'v' => 'V', 'w' => 'W', 'x' => 'X', 'y' => 'Y', 'z' => 'Z', 'Âµ' => 'Îœ', 'Ã ' => 'Ã€', 'Ã¡' => 'Ã�', 'Ã¢' => 'Ã‚', 'Ã£' => 'Ãƒ', 'Ã¤' => 'Ã„', 'Ã¥' => 'Ã…', 'Ã¦' => 'Ã†', 'Ã§' => 'Ã‡', 'Ã¨' => 'Ãˆ', 'Ã©' => 'Ã‰', 'Ãª' => 'ÃŠ', 'Ã«' => 'Ã‹', 'Ã¬' => 'ÃŒ', 'Ã­' => 'Ã�', 'Ã®' => 'ÃŽ', 'Ã¯' => 'Ã�', 'Ã°' => 'Ã�', 'Ã±' => 'Ã‘', 'Ã²' => 'Ã’', 'Ã³' => 'Ã“', 'Ã´' => 'Ã”', 'Ãµ' => 'Ã•', 'Ã¶' => 'Ã–', 'Ã¸' => 'Ã˜', 'Ã¹' => 'Ã™', 'Ãº' => 'Ãš', 'Ã»' => 'Ã›', 'Ã¼' => 'Ãœ', 'Ã½' => 'Ã�', 'Ã¾' => 'Ãž', 'Ã¿' => 'Å¸', 'Ä�' => 'Ä€', 'Äƒ' => 'Ä‚', 'Ä…' => 'Ä„', 'Ä‡' => 'Ä†', 'Ä‰' => 'Äˆ', 'Ä‹' => 'ÄŠ', 'Ä�' => 'ÄŒ', 'Ä�' => 'ÄŽ', 'Ä‘' => 'Ä�', 'Ä“' => 'Ä’', 'Ä•' => 'Ä”', 'Ä—' => 'Ä–', 'Ä™' => 'Ä˜', 'Ä›' => 'Äš', 'Ä�' => 'Äœ', 'ÄŸ' => 'Äž', 'Ä¡' => 'Ä ', 'Ä£' => 'Ä¢', 'Ä¥' => 'Ä¤', 'Ä§' => 'Ä¦', 'Ä©' => 'Ä¨', 'Ä«' => 'Äª', 'Ä­' => 'Ä¬', 'Ä¯' => 'Ä®', 'Ä±' => 'I', 'Ä³' => 'Ä²', 'Äµ' => 'Ä´', 'Ä·' => 'Ä¶', 'Äº' => 'Ä¹', 'Ä¼' => 'Ä»', 'Ä¾' => 'Ä½', 'Å€' => 'Ä¿', 'Å‚' => 'Å�', 'Å„' => 'Åƒ', 'Å†' => 'Å…', 'Åˆ' => 'Å‡', 'Å‹' => 'ÅŠ', 'Å�' => 'ÅŒ', 'Å�' => 'ÅŽ', 'Å‘' => 'Å�', 'Å“' => 'Å’', 'Å•' => 'Å”', 'Å—' => 'Å–', 'Å™' => 'Å˜', 'Å›' => 'Åš', 'Å�' => 'Åœ', 'ÅŸ' => 'Åž', 'Å¡' => 'Å ', 'Å£' => 'Å¢', 'Å¥' => 'Å¤', 'Å§' => 'Å¦', 'Å©' => 'Å¨', 'Å«' => 'Åª', 'Å­' => 'Å¬', 'Å¯' => 'Å®', 'Å±' => 'Å°', 'Å³' => 'Å²', 'Åµ' => 'Å´', 'Å·' => 'Å¶', 'Åº' => 'Å¹', 'Å¼' => 'Å»', 'Å¾' => 'Å½', 'Å¿' => 'S', 'Æ€' => 'Éƒ', 'Æƒ' => 'Æ‚', 'Æ…' => 'Æ„', 'Æˆ' => 'Æ‡', 'ÆŒ' => 'Æ‹', 'Æ’' => 'Æ‘', 'Æ•' => 'Ç¶', 'Æ™' => 'Æ˜', 'Æš' => 'È½', 'Æž' => 'È ', 'Æ¡' => 'Æ ', 'Æ£' => 'Æ¢', 'Æ¥' => 'Æ¤', 'Æ¨' => 'Æ§', 'Æ­' => 'Æ¬', 'Æ°' => 'Æ¯', 'Æ´' => 'Æ³', 'Æ¶' => 'Æµ', 'Æ¹' => 'Æ¸', 'Æ½' => 'Æ¼', 'Æ¿' => 'Ç·', 'Ç…' => 'Ç„', 'Ç†' => 'Ç„', 'Çˆ' => 'Ç‡', 'Ç‰' => 'Ç‡', 'Ç‹' => 'ÇŠ', 'ÇŒ' => 'ÇŠ', 'ÇŽ' => 'Ç�', 'Ç�' => 'Ç�', 'Ç’' => 'Ç‘', 'Ç”' => 'Ç“', 'Ç–' => 'Ç•', 'Ç˜' => 'Ç—', 'Çš' => 'Ç™', 'Çœ' => 'Ç›', 'Ç�' => 'ÆŽ', 'ÇŸ' => 'Çž', 'Ç¡' => 'Ç ', 'Ç£' => 'Ç¢', 'Ç¥' => 'Ç¤', 'Ç§' => 'Ç¦', 'Ç©' => 'Ç¨', 'Ç«' => 'Çª', 'Ç­' => 'Ç¬', 'Ç¯' => 'Ç®', 'Ç²' => 'Ç±', 'Ç³' => 'Ç±', 'Çµ' => 'Ç´', 'Ç¹' => 'Ç¸', 'Ç»' => 'Çº', 'Ç½' => 'Ç¼', 'Ç¿' => 'Ç¾', 'È�' => 'È€', 'Èƒ' => 'È‚', 'È…' => 'È„', 'È‡' => 'È†', 'È‰' => 'Èˆ', 'È‹' => 'ÈŠ', 'È�' => 'ÈŒ', 'È�' => 'ÈŽ', 'È‘' => 'È�', 'È“' => 'È’', 'È•' => 'È”', 'È—' => 'È–', 'È™' => 'È˜', 'È›' => 'Èš', 'È�' => 'Èœ', 'ÈŸ' => 'Èž', 'È£' => 'È¢', 'È¥' => 'È¤', 'È§' => 'È¦', 'È©' => 'È¨', 'È«' => 'Èª', 'È­' => 'È¬', 'È¯' => 'È®', 'È±' => 'È°', 'È³' => 'È²', 'È¼' => 'È»', 'È¿' => 'â±¾', 'É€' => 'â±¿', 'É‚' => 'É�', 'É‡' => 'É†', 'É‰' => 'Éˆ', 'É‹' => 'ÉŠ', 'É�' => 'ÉŒ', 'É�' => 'ÉŽ', 'É�' => 'â±¯', 'É‘' => 'â±­', 'É’' => 'â±°', 'É“' => 'Æ�', 'É”' => 'Æ†', 'É–' => 'Æ‰', 'É—' => 'ÆŠ', 'É™' => 'Æ�', 'É›' => 'Æ�', 'Éœ' => 'êž«', 'É ' => 'Æ“', 'É¡' => 'êž¬', 'É£' => 'Æ”', 'É¥' => 'êž�', 'É¦' => 'êžª', 'É¨' => 'Æ—', 'É©' => 'Æ–', 'Éª' => 'êž®', 'É«' => 'â±¢', 'É¬' => 'êž­', 'É¯' => 'Æœ', 'É±' => 'â±®', 'É²' => 'Æ�', 'Éµ' => 'ÆŸ', 'É½' => 'â±¤', 'Ê€' => 'Æ¦', 'Ê‚' => 'êŸ…', 'Êƒ' => 'Æ©', 'Ê‡' => 'êž±', 'Êˆ' => 'Æ®', 'Ê‰' => 'É„', 'ÊŠ' => 'Æ±', 'Ê‹' => 'Æ²', 'ÊŒ' => 'É…', 'Ê’' => 'Æ·', 'Ê�' => 'êž²', 'Êž' => 'êž°', 'Í…' => 'Î™', 'Í±' => 'Í°', 'Í³' => 'Í²', 'Í·' => 'Í¶', 'Í»' => 'Ï½', 'Í¼' => 'Ï¾', 'Í½' => 'Ï¿', 'Î¬' => 'Î†', 'Î­' => 'Îˆ', 'Î®' => 'Î‰', 'Î¯' => 'ÎŠ', 'Î±' => 'Î‘', 'Î²' => 'Î’', 'Î³' => 'Î“', 'Î´' => 'Î”', 'Îµ' => 'Î•', 'Î¶' => 'Î–', 'Î·' => 'Î—', 'Î¸' => 'Î˜', 'Î¹' => 'Î™', 'Îº' => 'Îš', 'Î»' => 'Î›', 'Î¼' => 'Îœ', 'Î½' => 'Î�', 'Î¾' => 'Îž', 'Î¿' => 'ÎŸ', 'Ï€' => 'Î ', 'Ï�' => 'Î¡', 'Ï‚' => 'Î£', 'Ïƒ' => 'Î£', 'Ï„' => 'Î¤', 'Ï…' => 'Î¥', 'Ï†' => 'Î¦', 'Ï‡' => 'Î§', 'Ïˆ' => 'Î¨', 'Ï‰' => 'Î©', 'ÏŠ' => 'Îª', 'Ï‹' => 'Î«', 'ÏŒ' => 'ÎŒ', 'Ï�' => 'ÎŽ', 'ÏŽ' => 'Î�', 'Ï�' => 'Î’', 'Ï‘' => 'Î˜', 'Ï•' => 'Î¦', 'Ï–' => 'Î ', 'Ï—' => 'Ï�', 'Ï™' => 'Ï˜', 'Ï›' => 'Ïš', 'Ï�' => 'Ïœ', 'ÏŸ' => 'Ïž', 'Ï¡' => 'Ï ', 'Ï£' => 'Ï¢', 'Ï¥' => 'Ï¤', 'Ï§' => 'Ï¦', 'Ï©' => 'Ï¨', 'Ï«' => 'Ïª', 'Ï­' => 'Ï¬', 'Ï¯' => 'Ï®', 'Ï°' => 'Îš', 'Ï±' => 'Î¡', 'Ï²' => 'Ï¹', 'Ï³' => 'Í¿', 'Ïµ' => 'Î•', 'Ï¸' => 'Ï·', 'Ï»' => 'Ïº', 'Ð°' => 'Ð�', 'Ð±' => 'Ð‘', 'Ð²' => 'Ð’', 'Ð³' => 'Ð“', 'Ð´' => 'Ð”', 'Ðµ' => 'Ð•', 'Ð¶' => 'Ð–', 'Ð·' => 'Ð—', 'Ð¸' => 'Ð˜', 'Ð¹' => 'Ð™', 'Ðº' => 'Ðš', 'Ð»' => 'Ð›', 'Ð¼' => 'Ðœ', 'Ð½' => 'Ð�', 'Ð¾' => 'Ðž', 'Ð¿' => 'ÐŸ', 'Ñ€' => 'Ð ', 'Ñ�' => 'Ð¡', 'Ñ‚' => 'Ð¢', 'Ñƒ' => 'Ð£', 'Ñ„' => 'Ð¤', 'Ñ…' => 'Ð¥', 'Ñ†' => 'Ð¦', 'Ñ‡' => 'Ð§', 'Ñˆ' => 'Ð¨', 'Ñ‰' => 'Ð©', 'ÑŠ' => 'Ðª', 'Ñ‹' => 'Ð«', 'ÑŒ' => 'Ð¬', 'Ñ�' => 'Ð­', 'ÑŽ' => 'Ð®', 'Ñ�' => 'Ð¯', 'Ñ�' => 'Ð€', 'Ñ‘' => 'Ð�', 'Ñ’' => 'Ð‚', 'Ñ“' => 'Ðƒ', 'Ñ”' => 'Ð„', 'Ñ•' => 'Ð…', 'Ñ–' => 'Ð†', 'Ñ—' => 'Ð‡', 'Ñ˜' => 'Ðˆ', 'Ñ™' => 'Ð‰', 'Ñš' => 'ÐŠ', 'Ñ›' => 'Ð‹', 'Ñœ' => 'ÐŒ', 'Ñ�' => 'Ð�', 'Ñž' => 'ÐŽ', 'ÑŸ' => 'Ð�', 'Ñ¡' => 'Ñ ', 'Ñ£' => 'Ñ¢', 'Ñ¥' => 'Ñ¤', 'Ñ§' => 'Ñ¦', 'Ñ©' => 'Ñ¨', 'Ñ«' => 'Ñª', 'Ñ­' => 'Ñ¬', 'Ñ¯' => 'Ñ®', 'Ñ±' => 'Ñ°', 'Ñ³' => 'Ñ²', 'Ñµ' => 'Ñ´', 'Ñ·' => 'Ñ¶', 'Ñ¹' => 'Ñ¸', 'Ñ»' => 'Ñº', 'Ñ½' => 'Ñ¼', 'Ñ¿' => 'Ñ¾', 'Ò�' => 'Ò€', 'Ò‹' => 'ÒŠ', 'Ò�' => 'ÒŒ', 'Ò�' => 'ÒŽ', 'Ò‘' => 'Ò�', 'Ò“' => 'Ò’', 'Ò•' => 'Ò”', 'Ò—' => 'Ò–', 'Ò™' => 'Ò˜', 'Ò›' => 'Òš', 'Ò�' => 'Òœ', 'ÒŸ' => 'Òž', 'Ò¡' => 'Ò ', 'Ò£' => 'Ò¢', 'Ò¥' => 'Ò¤', 'Ò§' => 'Ò¦', 'Ò©' => 'Ò¨', 'Ò«' => 'Òª', 'Ò­' => 'Ò¬', 'Ò¯' => 'Ò®', 'Ò±' => 'Ò°', 'Ò³' => 'Ò²', 'Òµ' => 'Ò´', 'Ò·' => 'Ò¶', 'Ò¹' => 'Ò¸', 'Ò»' => 'Òº', 'Ò½' => 'Ò¼', 'Ò¿' => 'Ò¾', 'Ó‚' => 'Ó�', 'Ó„' => 'Óƒ', 'Ó†' => 'Ó…', 'Óˆ' => 'Ó‡', 'ÓŠ' => 'Ó‰', 'ÓŒ' => 'Ó‹', 'ÓŽ' => 'Ó�', 'Ó�' => 'Ó€', 'Ó‘' => 'Ó�', 'Ó“' => 'Ó’', 'Ó•' => 'Ó”', 'Ó—' => 'Ó–', 'Ó™' => 'Ó˜', 'Ó›' => 'Óš', 'Ó�' => 'Óœ', 'ÓŸ' => 'Óž', 'Ó¡' => 'Ó ', 'Ó£' => 'Ó¢', 'Ó¥' => 'Ó¤', 'Ó§' => 'Ó¦', 'Ó©' => 'Ó¨', 'Ó«' => 'Óª', 'Ó­' => 'Ó¬', 'Ó¯' => 'Ó®', 'Ó±' => 'Ó°', 'Ó³' => 'Ó²', 'Óµ' => 'Ó´', 'Ó·' => 'Ó¶', 'Ó¹' => 'Ó¸', 'Ó»' => 'Óº', 'Ó½' => 'Ó¼', 'Ó¿' => 'Ó¾', 'Ô�' => 'Ô€', 'Ôƒ' => 'Ô‚', 'Ô…' => 'Ô„', 'Ô‡' => 'Ô†', 'Ô‰' => 'Ôˆ', 'Ô‹' => 'ÔŠ', 'Ô�' => 'ÔŒ', 'Ô�' => 'ÔŽ', 'Ô‘' => 'Ô�', 'Ô“' => 'Ô’', 'Ô•' => 'Ô”', 'Ô—' => 'Ô–', 'Ô™' => 'Ô˜', 'Ô›' => 'Ôš', 'Ô�' => 'Ôœ', 'ÔŸ' => 'Ôž', 'Ô¡' => 'Ô ', 'Ô£' => 'Ô¢', 'Ô¥' => 'Ô¤', 'Ô§' => 'Ô¦', 'Ô©' => 'Ô¨', 'Ô«' => 'Ôª', 'Ô­' => 'Ô¬', 'Ô¯' => 'Ô®', 'Õ¡' => 'Ô±', 'Õ¢' => 'Ô²', 'Õ£' => 'Ô³', 'Õ¤' => 'Ô´', 'Õ¥' => 'Ôµ', 'Õ¦' => 'Ô¶', 'Õ§' => 'Ô·', 'Õ¨' => 'Ô¸', 'Õ©' => 'Ô¹', 'Õª' => 'Ôº', 'Õ«' => 'Ô»', 'Õ¬' => 'Ô¼', 'Õ­' => 'Ô½', 'Õ®' => 'Ô¾', 'Õ¯' => 'Ô¿', 'Õ°' => 'Õ€', 'Õ±' => 'Õ�', 'Õ²' => 'Õ‚', 'Õ³' => 'Õƒ', 'Õ´' => 'Õ„', 'Õµ' => 'Õ…', 'Õ¶' => 'Õ†', 'Õ·' => 'Õ‡', 'Õ¸' => 'Õˆ', 'Õ¹' => 'Õ‰', 'Õº' => 'ÕŠ', 'Õ»' => 'Õ‹', 'Õ¼' => 'ÕŒ', 'Õ½' => 'Õ�', 'Õ¾' => 'ÕŽ', 'Õ¿' => 'Õ�', 'Ö€' => 'Õ�', 'Ö�' => 'Õ‘', 'Ö‚' => 'Õ’', 'Öƒ' => 'Õ“', 'Ö„' => 'Õ”', 'Ö…' => 'Õ•', 'Ö†' => 'Õ–', 'áƒ�' => 'á²�', 'áƒ‘' => 'á²‘', 'áƒ’' => 'á²’', 'áƒ“' => 'á²“', 'áƒ”' => 'á²”', 'áƒ•' => 'á²•', 'áƒ–' => 'á²–', 'áƒ—' => 'á²—', 'áƒ˜' => 'á²˜', 'áƒ™' => 'á²™', 'áƒš' => 'á²š', 'áƒ›' => 'á²›', 'áƒœ' => 'á²œ', 'áƒ�' => 'á²�', 'áƒž' => 'á²ž', 'áƒŸ' => 'á²Ÿ', 'áƒ ' => 'á² ', 'áƒ¡' => 'á²¡', 'áƒ¢' => 'á²¢', 'áƒ£' => 'á²£', 'áƒ¤' => 'á²¤', 'áƒ¥' => 'á²¥', 'áƒ¦' => 'á²¦', 'áƒ§' => 'á²§', 'áƒ¨' => 'á²¨', 'áƒ©' => 'á²©', 'áƒª' => 'á²ª', 'áƒ«' => 'á²«', 'áƒ¬' => 'á²¬', 'áƒ­' => 'á²­', 'áƒ®' => 'á²®', 'áƒ¯' => 'á²¯', 'áƒ°' => 'á²°', 'áƒ±' => 'á²±', 'áƒ²' => 'á²²', 'áƒ³' => 'á²³', 'áƒ´' => 'á²´', 'áƒµ' => 'á²µ', 'áƒ¶' => 'á²¶', 'áƒ·' => 'á²·', 'áƒ¸' => 'á²¸', 'áƒ¹' => 'á²¹', 'áƒº' => 'á²º', 'áƒ½' => 'á²½', 'áƒ¾' => 'á²¾', 'áƒ¿' => 'á²¿', 'á�¸' => 'á�°', 'á�¹' => 'á�±', 'á�º' => 'á�²', 'á�»' => 'á�³', 'á�¼' => 'á�´', 'á�½' => 'á�µ', 'á²€' => 'Ð’', 'á²�' => 'Ð”', 'á²‚' => 'Ðž', 'á²ƒ' => 'Ð¡', 'á²„' => 'Ð¢', 'á²…' => 'Ð¢', 'á²†' => 'Ðª', 'á²‡' => 'Ñ¢', 'á²ˆ' => 'ê™Š', 'áµ¹' => 'ê�½', 'áµ½' => 'â±£', 'á¶Ž' => 'êŸ†', 'á¸�' => 'á¸€', 'á¸ƒ' => 'á¸‚', 'á¸…' => 'á¸„', 'á¸‡' => 'á¸†', 'á¸‰' => 'á¸ˆ', 'á¸‹' => 'á¸Š', 'á¸�' => 'á¸Œ', 'á¸�' => 'á¸Ž', 'á¸‘' => 'á¸�', 'á¸“' => 'á¸’', 'á¸•' => 'á¸”', 'á¸—' => 'á¸–', 'á¸™' => 'á¸˜', 'á¸›' => 'á¸š', 'á¸�' => 'á¸œ', 'á¸Ÿ' => 'á¸ž', 'á¸¡' => 'á¸ ', 'á¸£' => 'á¸¢', 'á¸¥' => 'á¸¤', 'á¸§' => 'á¸¦', 'á¸©' => 'á¸¨', 'á¸«' => 'á¸ª', 'á¸­' => 'á¸¬', 'á¸¯' => 'á¸®', 'á¸±' => 'á¸°', 'á¸³' => 'á¸²', 'á¸µ' => 'á¸´', 'á¸·' => 'á¸¶', 'á¸¹' => 'á¸¸', 'á¸»' => 'á¸º', 'á¸½' => 'á¸¼', 'á¸¿' => 'á¸¾', 'á¹�' => 'á¹€', 'á¹ƒ' => 'á¹‚', 'á¹…' => 'á¹„', 'á¹‡' => 'á¹†', 'á¹‰' => 'á¹ˆ', 'á¹‹' => 'á¹Š', 'á¹�' => 'á¹Œ', 'á¹�' => 'á¹Ž', 'á¹‘' => 'á¹�', 'á¹“' => 'á¹’', 'á¹•' => 'á¹”', 'á¹—' => 'á¹–', 'á¹™' => 'á¹˜', 'á¹›' => 'á¹š', 'á¹�' => 'á¹œ', 'á¹Ÿ' => 'á¹ž', 'á¹¡' => 'á¹ ', 'á¹£' => 'á¹¢', 'á¹¥' => 'á¹¤', 'á¹§' => 'á¹¦', 'á¹©' => 'á¹¨', 'á¹«' => 'á¹ª', 'á¹­' => 'á¹¬', 'á¹¯' => 'á¹®', 'á¹±' => 'á¹°', 'á¹³' => 'á¹²', 'á¹µ' => 'á¹´', 'á¹·' => 'á¹¶', 'á¹¹' => 'á¹¸', 'á¹»' => 'á¹º', 'á¹½' => 'á¹¼', 'á¹¿' => 'á¹¾', 'áº�' => 'áº€', 'áºƒ' => 'áº‚', 'áº…' => 'áº„', 'áº‡' => 'áº†', 'áº‰' => 'áºˆ', 'áº‹' => 'áºŠ', 'áº�' => 'áºŒ', 'áº�' => 'áºŽ', 'áº‘' => 'áº�', 'áº“' => 'áº’', 'áº•' => 'áº”', 'áº›' => 'á¹ ', 'áº¡' => 'áº ', 'áº£' => 'áº¢', 'áº¥' => 'áº¤', 'áº§' => 'áº¦', 'áº©' => 'áº¨', 'áº«' => 'áºª', 'áº­' => 'áº¬', 'áº¯' => 'áº®', 'áº±' => 'áº°', 'áº³' => 'áº²', 'áºµ' => 'áº´', 'áº·' => 'áº¶', 'áº¹' => 'áº¸', 'áº»' => 'áºº', 'áº½' => 'áº¼', 'áº¿' => 'áº¾', 'á»�' => 'á»€', 'á»ƒ' => 'á»‚', 'á»…' => 'á»„', 'á»‡' => 'á»†', 'á»‰' => 'á»ˆ', 'á»‹' => 'á»Š', 'á»�' => 'á»Œ', 'á»�' => 'á»Ž', 'á»‘' => 'á»�', 'á»“' => 'á»’', 'á»•' => 'á»”', 'á»—' => 'á»–', 'á»™' => 'á»˜', 'á»›' => 'á»š', 'á»�' => 'á»œ', 'á»Ÿ' => 'á»ž', 'á»¡' => 'á» ', 'á»£' => 'á»¢', 'á»¥' => 'á»¤', 'á»§' => 'á»¦', 'á»©' => 'á»¨', 'á»«' => 'á»ª', 'á»­' => 'á»¬', 'á»¯' => 'á»®', 'á»±' => 'á»°', 'á»³' => 'á»²', 'á»µ' => 'á»´', 'á»·' => 'á»¶', 'á»¹' => 'á»¸', 'á»»' => 'á»º', 'á»½' => 'á»¼', 'á»¿' => 'á»¾', 'á¼€' => 'á¼ˆ', 'á¼�' => 'á¼‰', 'á¼‚' => 'á¼Š', 'á¼ƒ' => 'á¼‹', 'á¼„' => 'á¼Œ', 'á¼…' => 'á¼�', 'á¼†' => 'á¼Ž', 'á¼‡' => 'á¼�', 'á¼�' => 'á¼˜', 'á¼‘' => 'á¼™', 'á¼’' => 'á¼š', 'á¼“' => 'á¼›', 'á¼”' => 'á¼œ', 'á¼•' => 'á¼�', 'á¼ ' => 'á¼¨', 'á¼¡' => 'á¼©', 'á¼¢' => 'á¼ª', 'á¼£' => 'á¼«', 'á¼¤' => 'á¼¬', 'á¼¥' => 'á¼­', 'á¼¦' => 'á¼®', 'á¼§' => 'á¼¯', 'á¼°' => 'á¼¸', 'á¼±' => 'á¼¹', 'á¼²' => 'á¼º', 'á¼³' => 'á¼»', 'á¼´' => 'á¼¼', 'á¼µ' => 'á¼½', 'á¼¶' => 'á¼¾', 'á¼·' => 'á¼¿', 'á½€' => 'á½ˆ', 'á½�' => 'á½‰', 'á½‚' => 'á½Š', 'á½ƒ' => 'á½‹', 'á½„' => 'á½Œ', 'á½…' => 'á½�', 'á½‘' => 'á½™', 'á½“' => 'á½›', 'á½•' => 'á½�', 'á½—' => 'á½Ÿ', 'á½ ' => 'á½¨', 'á½¡' => 'á½©', 'á½¢' => 'á½ª', 'á½£' => 'á½«', 'á½¤' => 'á½¬', 'á½¥' => 'á½­', 'á½¦' => 'á½®', 'á½§' => 'á½¯', 'á½°' => 'á¾º', 'á½±' => 'á¾»', 'á½²' => 'á¿ˆ', 'á½³' => 'á¿‰', 'á½´' => 'á¿Š', 'á½µ' => 'á¿‹', 'á½¶' => 'á¿š', 'á½·' => 'á¿›', 'á½¸' => 'á¿¸', 'á½¹' => 'á¿¹', 'á½º' => 'á¿ª', 'á½»' => 'á¿«', 'á½¼' => 'á¿º', 'á½½' => 'á¿»', 'á¾€' => 'á¾ˆ', 'á¾�' => 'á¾‰', 'á¾‚' => 'á¾Š', 'á¾ƒ' => 'á¾‹', 'á¾„' => 'á¾Œ', 'á¾…' => 'á¾�', 'á¾†' => 'á¾Ž', 'á¾‡' => 'á¾�', 'á¾�' => 'á¾˜', 'á¾‘' => 'á¾™', 'á¾’' => 'á¾š', 'á¾“' => 'á¾›', 'á¾”' => 'á¾œ', 'á¾•' => 'á¾�', 'á¾–' => 'á¾ž', 'á¾—' => 'á¾Ÿ', 'á¾ ' => 'á¾¨', 'á¾¡' => 'á¾©', 'á¾¢' => 'á¾ª', 'á¾£' => 'á¾«', 'á¾¤' => 'á¾¬', 'á¾¥' => 'á¾­', 'á¾¦' => 'á¾®', 'á¾§' => 'á¾¯', 'á¾°' => 'á¾¸', 'á¾±' => 'á¾¹', 'á¾³' => 'á¾¼', 'á¾¾' => 'Î™', 'á¿ƒ' => 'á¿Œ', 'á¿�' => 'á¿˜', 'á¿‘' => 'á¿™', 'á¿ ' => 'á¿¨', 'á¿¡' => 'á¿©', 'á¿¥' => 'á¿¬', 'á¿³' => 'á¿¼', 'â…Ž' => 'â„²', 'â…°' => 'â… ', 'â…±' => 'â…¡', 'â…²' => 'â…¢', 'â…³' => 'â…£', 'â…´' => 'â…¤', 'â…µ' => 'â…¥', 'â…¶' => 'â…¦', 'â…·' => 'â…§', 'â…¸' => 'â…¨', 'â…¹' => 'â…©', 'â…º' => 'â…ª', 'â…»' => 'â…«', 'â…¼' => 'â…¬', 'â…½' => 'â…­', 'â…¾' => 'â…®', 'â…¿' => 'â…¯', 'â†„' => 'â†ƒ', 'â“�' => 'â’¶', 'â“‘' => 'â’·', 'â“’' => 'â’¸', 'â““' => 'â’¹', 'â“”' => 'â’º', 'â“•' => 'â’»', 'â“–' => 'â’¼', 'â“—' => 'â’½', 'â“˜' => 'â’¾', 'â“™' => 'â’¿', 'â“š' => 'â“€', 'â“›' => 'â“�', 'â“œ' => 'â“‚', 'â“�' => 'â“ƒ', 'â“ž' => 'â“„', 'â“Ÿ' => 'â“…', 'â“ ' => 'â“†', 'â“¡' => 'â“‡', 'â“¢' => 'â“ˆ', 'â“£' => 'â“‰', 'â“¤' => 'â“Š', 'â“¥' => 'â“‹', 'â“¦' => 'â“Œ', 'â“§' => 'â“�', 'â“¨' => 'â“Ž', 'â“©' => 'â“�', 'â°°' => 'â°€', 'â°±' => 'â°�', 'â°²' => 'â°‚', 'â°³' => 'â°ƒ', 'â°´' => 'â°„', 'â°µ' => 'â°…', 'â°¶' => 'â°†', 'â°·' => 'â°‡', 'â°¸' => 'â°ˆ', 'â°¹' => 'â°‰', 'â°º' => 'â°Š', 'â°»' => 'â°‹', 'â°¼' => 'â°Œ', 'â°½' => 'â°�', 'â°¾' => 'â°Ž', 'â°¿' => 'â°�', 'â±€' => 'â°�', 'â±�' => 'â°‘', 'â±‚' => 'â°’', 'â±ƒ' => 'â°“', 'â±„' => 'â°”', 'â±…' => 'â°•', 'â±†' => 'â°–', 'â±‡' => 'â°—', 'â±ˆ' => 'â°˜', 'â±‰' => 'â°™', 'â±Š' => 'â°š', 'â±‹' => 'â°›', 'â±Œ' => 'â°œ', 'â±�' => 'â°�', 'â±Ž' => 'â°ž', 'â±�' => 'â°Ÿ', 'â±�' => 'â° ', 'â±‘' => 'â°¡', 'â±’' => 'â°¢', 'â±“' => 'â°£', 'â±”' => 'â°¤', 'â±•' => 'â°¥', 'â±–' => 'â°¦', 'â±—' => 'â°§', 'â±˜' => 'â°¨', 'â±™' => 'â°©', 'â±š' => 'â°ª', 'â±›' => 'â°«', 'â±œ' => 'â°¬', 'â±�' => 'â°­', 'â±ž' => 'â°®', 'â±¡' => 'â± ', 'â±¥' => 'Èº', 'â±¦' => 'È¾', 'â±¨' => 'â±§', 'â±ª' => 'â±©', 'â±¬' => 'â±«', 'â±³' => 'â±²', 'â±¶' => 'â±µ', 'â²�' => 'â²€', 'â²ƒ' => 'â²‚', 'â²…' => 'â²„', 'â²‡' => 'â²†', 'â²‰' => 'â²ˆ', 'â²‹' => 'â²Š', 'â²�' => 'â²Œ', 'â²�' => 'â²Ž', 'â²‘' => 'â²�', 'â²“' => 'â²’', 'â²•' => 'â²”', 'â²—' => 'â²–', 'â²™' => 'â²˜', 'â²›' => 'â²š', 'â²�' => 'â²œ', 'â²Ÿ' => 'â²ž', 'â²¡' => 'â² ', 'â²£' => 'â²¢', 'â²¥' => 'â²¤', 'â²§' => 'â²¦', 'â²©' => 'â²¨', 'â²«' => 'â²ª', 'â²­' => 'â²¬', 'â²¯' => 'â²®', 'â²±' => 'â²°', 'â²³' => 'â²²', 'â²µ' => 'â²´', 'â²·' => 'â²¶', 'â²¹' => 'â²¸', 'â²»' => 'â²º', 'â²½' => 'â²¼', 'â²¿' => 'â²¾', 'â³�' => 'â³€', 'â³ƒ' => 'â³‚', 'â³…' => 'â³„', 'â³‡' => 'â³†', 'â³‰' => 'â³ˆ', 'â³‹' => 'â³Š', 'â³�' => 'â³Œ', 'â³�' => 'â³Ž', 'â³‘' => 'â³�', 'â³“' => 'â³’', 'â³•' => 'â³”', 'â³—' => 'â³–', 'â³™' => 'â³˜', 'â³›' => 'â³š', 'â³�' => 'â³œ', 'â³Ÿ' => 'â³ž', 'â³¡' => 'â³ ', 'â³£' => 'â³¢', 'â³¬' => 'â³«', 'â³®' => 'â³­', 'â³³' => 'â³²', 'â´€' => 'á‚ ', 'â´�' => 'á‚¡', 'â´‚' => 'á‚¢', 'â´ƒ' => 'á‚£', 'â´„' => 'á‚¤', 'â´…' => 'á‚¥', 'â´†' => 'á‚¦', 'â´‡' => 'á‚§', 'â´ˆ' => 'á‚¨', 'â´‰' => 'á‚©', 'â´Š' => 'á‚ª', 'â´‹' => 'á‚«', 'â´Œ' => 'á‚¬', 'â´�' => 'á‚­', 'â´Ž' => 'á‚®', 'â´�' => 'á‚¯', 'â´�' => 'á‚°', 'â´‘' => 'á‚±', 'â´’' => 'á‚²', 'â´“' => 'á‚³', 'â´”' => 'á‚´', 'â´•' => 'á‚µ', 'â´–' => 'á‚¶', 'â´—' => 'á‚·', 'â´˜' => 'á‚¸', 'â´™' => 'á‚¹', 'â´š' => 'á‚º', 'â´›' => 'á‚»', 'â´œ' => 'á‚¼', 'â´�' => 'á‚½', 'â´ž' => 'á‚¾', 'â´Ÿ' => 'á‚¿', 'â´ ' => 'áƒ€', 'â´¡' => 'áƒ�', 'â´¢' => 'áƒ‚', 'â´£' => 'áƒƒ', 'â´¤' => 'áƒ„', 'â´¥' => 'áƒ…', 'â´§' => 'áƒ‡', 'â´­' => 'áƒ�', 'ê™�' => 'ê™€', 'ê™ƒ' => 'ê™‚', 'ê™…' => 'ê™„', 'ê™‡' => 'ê™†', 'ê™‰' => 'ê™ˆ', 'ê™‹' => 'ê™Š', 'ê™�' => 'ê™Œ', 'ê™�' => 'ê™Ž', 'ê™‘' => 'ê™�', 'ê™“' => 'ê™’', 'ê™•' => 'ê™”', 'ê™—' => 'ê™–', 'ê™™' => 'ê™˜', 'ê™›' => 'ê™š', 'ê™�' => 'ê™œ', 'ê™Ÿ' => 'ê™ž', 'ê™¡' => 'ê™ ', 'ê™£' => 'ê™¢', 'ê™¥' => 'ê™¤', 'ê™§' => 'ê™¦', 'ê™©' => 'ê™¨', 'ê™«' => 'ê™ª', 'ê™­' => 'ê™¬', 'êš�' => 'êš€', 'êšƒ' => 'êš‚', 'êš…' => 'êš„', 'êš‡' => 'êš†', 'êš‰' => 'êšˆ', 'êš‹' => 'êšŠ', 'êš�' => 'êšŒ', 'êš�' => 'êšŽ', 'êš‘' => 'êš�', 'êš“' => 'êš’', 'êš•' => 'êš”', 'êš—' => 'êš–', 'êš™' => 'êš˜', 'êš›' => 'êšš', 'êœ£' => 'êœ¢', 'êœ¥' => 'êœ¤', 'êœ§' => 'êœ¦', 'êœ©' => 'êœ¨', 'êœ«' => 'êœª', 'êœ­' => 'êœ¬', 'êœ¯' => 'êœ®', 'êœ³' => 'êœ²', 'êœµ' => 'êœ´', 'êœ·' => 'êœ¶', 'êœ¹' => 'êœ¸', 'êœ»' => 'êœº', 'êœ½' => 'êœ¼', 'êœ¿' => 'êœ¾', 'ê��' => 'ê�€', 'ê�ƒ' => 'ê�‚', 'ê�…' => 'ê�„', 'ê�‡' => 'ê�†', 'ê�‰' => 'ê�ˆ', 'ê�‹' => 'ê�Š', 'ê��' => 'ê�Œ', 'ê��' => 'ê�Ž', 'ê�‘' => 'ê��', 'ê�“' => 'ê�’', 'ê�•' => 'ê�”', 'ê�—' => 'ê�–', 'ê�™' => 'ê�˜', 'ê�›' => 'ê�š', 'ê��' => 'ê�œ', 'ê�Ÿ' => 'ê�ž', 'ê�¡' => 'ê� ', 'ê�£' => 'ê�¢', 'ê�¥' => 'ê�¤', 'ê�§' => 'ê�¦', 'ê�©' => 'ê�¨', 'ê�«' => 'ê�ª', 'ê�­' => 'ê�¬', 'ê�¯' => 'ê�®', 'ê�º' => 'ê�¹', 'ê�¼' => 'ê�»', 'ê�¿' => 'ê�¾', 'êž�' => 'êž€', 'êžƒ' => 'êž‚', 'êž…' => 'êž„', 'êž‡' => 'êž†', 'êžŒ' => 'êž‹', 'êž‘' => 'êž�', 'êž“' => 'êž’', 'êž”' => 'êŸ„', 'êž—' => 'êž–', 'êž™' => 'êž˜', 'êž›' => 'êžš', 'êž�' => 'êžœ', 'êžŸ' => 'êžž', 'êž¡' => 'êž ', 'êž£' => 'êž¢', 'êž¥' => 'êž¤', 'êž§' => 'êž¦', 'êž©' => 'êž¨', 'êžµ' => 'êž´', 'êž·' => 'êž¶', 'êž¹' => 'êž¸', 'êž»' => 'êžº', 'êž½' => 'êž¼', 'êž¿' => 'êž¾', 'êŸƒ' => 'êŸ‚', 'êŸˆ' => 'êŸ‡', 'êŸŠ' => 'êŸ‰', 'êŸ¶' => 'êŸµ', 'ê­“' => 'êž³', 'ê­°' => 'áŽ ', 'ê­±' => 'áŽ¡', 'ê­²' => 'áŽ¢', 'ê­³' => 'áŽ£', 'ê­´' => 'áŽ¤', 'ê­µ' => 'áŽ¥', 'ê­¶' => 'áŽ¦', 'ê­·' => 'áŽ§', 'ê­¸' => 'áŽ¨', 'ê­¹' => 'áŽ©', 'ê­º' => 'áŽª', 'ê­»' => 'áŽ«', 'ê­¼' => 'áŽ¬', 'ê­½' => 'áŽ­', 'ê­¾' => 'áŽ®', 'ê­¿' => 'áŽ¯', 'ê®€' => 'áŽ°', 'ê®�' => 'áŽ±', 'ê®‚' => 'áŽ²', 'ê®ƒ' => 'áŽ³', 'ê®„' => 'áŽ´', 'ê®…' => 'áŽµ', 'ê®†' => 'áŽ¶', 'ê®‡' => 'áŽ·', 'ê®ˆ' => 'áŽ¸', 'ê®‰' => 'áŽ¹', 'ê®Š' => 'áŽº', 'ê®‹' => 'áŽ»', 'ê®Œ' => 'áŽ¼', 'ê®�' => 'áŽ½', 'ê®Ž' => 'áŽ¾', 'ê®�' => 'áŽ¿', 'ê®�' => 'á�€', 'ê®‘' => 'á��', 'ê®’' => 'á�‚', 'ê®“' => 'á�ƒ', 'ê®”' => 'á�„', 'ê®•' => 'á�…', 'ê®–' => 'á�†', 'ê®—' => 'á�‡', 'ê®˜' => 'á�ˆ', 'ê®™' => 'á�‰', 'ê®š' => 'á�Š', 'ê®›' => 'á�‹', 'ê®œ' => 'á�Œ', 'ê®�' => 'á��', 'ê®ž' => 'á�Ž', 'ê®Ÿ' => 'á��', 'ê® ' => 'á��', 'ê®¡' => 'á�‘', 'ê®¢' => 'á�’', 'ê®£' => 'á�“', 'ê®¤' => 'á�”', 'ê®¥' => 'á�•', 'ê®¦' => 'á�–', 'ê®§' => 'á�—', 'ê®¨' => 'á�˜', 'ê®©' => 'á�™', 'ê®ª' => 'á�š', 'ê®«' => 'á�›', 'ê®¬' => 'á�œ', 'ê®­' => 'á��', 'ê®®' => 'á�ž', 'ê®¯' => 'á�Ÿ', 'ê®°' => 'á� ', 'ê®±' => 'á�¡', 'ê®²' => 'á�¢', 'ê®³' => 'á�£', 'ê®´' => 'á�¤', 'ê®µ' => 'á�¥', 'ê®¶' => 'á�¦', 'ê®·' => 'á�§', 'ê®¸' => 'á�¨', 'ê®¹' => 'á�©', 'ê®º' => 'á�ª', 'ê®»' => 'á�«', 'ê®¼' => 'á�¬', 'ê®½' => 'á�­', 'ê®¾' => 'á�®', 'ê®¿' => 'á�¯', 'ï½�' => 'ï¼¡', 'ï½‚' => 'ï¼¢', 'ï½ƒ' => 'ï¼£', 'ï½„' => 'ï¼¤', 'ï½…' => 'ï¼¥', 'ï½†' => 'ï¼¦', 'ï½‡' => 'ï¼§', 'ï½ˆ' => 'ï¼¨', 'ï½‰' => 'ï¼©', 'ï½Š' => 'ï¼ª', 'ï½‹' => 'ï¼«', 'ï½Œ' => 'ï¼¬', 'ï½�' => 'ï¼­', 'ï½Ž' => 'ï¼®', 'ï½�' => 'ï¼¯', 'ï½�' => 'ï¼°', 'ï½‘' => 'ï¼±', 'ï½’' => 'ï¼²', 'ï½“' => 'ï¼³', 'ï½”' => 'ï¼´', 'ï½•' => 'ï¼µ', 'ï½–' => 'ï¼¶', 'ï½—' => 'ï¼·', 'ï½˜' => 'ï¼¸', 'ï½™' => 'ï¼¹', 'ï½š' => 'ï¼º', 'ð��¨' => 'ð��€', 'ð��©' => 'ð���', 'ð��ª' => 'ð��‚', 'ð��«' => 'ð��ƒ', 'ð��¬' => 'ð��„', 'ð��­' => 'ð��…', 'ð��®' => 'ð��†', 'ð��¯' => 'ð��‡', 'ð��°' => 'ð��ˆ', 'ð��±' => 'ð��‰', 'ð��²' => 'ð��Š', 'ð��³' => 'ð��‹', 'ð��´' => 'ð��Œ', 'ð��µ' => 'ð���', 'ð��¶' => 'ð��Ž', 'ð��·' => 'ð���', 'ð��¸' => 'ð���', 'ð��¹' => 'ð��‘', 'ð��º' => 'ð��’', 'ð��»' => 'ð��“', 'ð��¼' => 'ð��”', 'ð��½' => 'ð��•', 'ð��¾' => 'ð��–', 'ð��¿' => 'ð��—', 'ð�‘€' => 'ð��˜', 'ð�‘�' => 'ð��™', 'ð�‘‚' => 'ð��š', 'ð�‘ƒ' => 'ð��›', 'ð�‘„' => 'ð��œ', 'ð�‘…' => 'ð���', 'ð�‘†' => 'ð��ž', 'ð�‘‡' => 'ð��Ÿ', 'ð�‘ˆ' => 'ð�� ', 'ð�‘‰' => 'ð��¡', 'ð�‘Š' => 'ð��¢', 'ð�‘‹' => 'ð��£', 'ð�‘Œ' => 'ð��¤', 'ð�‘�' => 'ð��¥', 'ð�‘Ž' => 'ð��¦', 'ð�‘�' => 'ð��§', 'ð�“˜' => 'ð�’°', 'ð�“™' => 'ð�’±', 'ð�“š' => 'ð�’²', 'ð�“›' => 'ð�’³', 'ð�“œ' => 'ð�’´', 'ð�“�' => 'ð�’µ', 'ð�“ž' => 'ð�’¶', 'ð�“Ÿ' => 'ð�’·', 'ð�“ ' => 'ð�’¸', 'ð�“¡' => 'ð�’¹', 'ð�“¢' => 'ð�’º', 'ð�“£' => 'ð�’»', 'ð�“¤' => 'ð�’¼', 'ð�“¥' => 'ð�’½', 'ð�“¦' => 'ð�’¾', 'ð�“§' => 'ð�’¿', 'ð�“¨' => 'ð�“€', 'ð�“©' => 'ð�“�', 'ð�“ª' => 'ð�“‚', 'ð�“«' => 'ð�“ƒ', 'ð�“¬' => 'ð�“„', 'ð�“­' => 'ð�“…', 'ð�“®' => 'ð�“†', 'ð�“¯' => 'ð�“‡', 'ð�“°' => 'ð�“ˆ', 'ð�“±' => 'ð�“‰', 'ð�“²' => 'ð�“Š', 'ð�“³' => 'ð�“‹', 'ð�“´' => 'ð�“Œ', 'ð�“µ' => 'ð�“�', 'ð�“¶' => 'ð�“Ž', 'ð�“·' => 'ð�“�', 'ð�“¸' => 'ð�“�', 'ð�“¹' => 'ð�“‘', 'ð�“º' => 'ð�“’', 'ð�“»' => 'ð�““', 'ð�³€' => 'ð�²€', 'ð�³�' => 'ð�²�', 'ð�³‚' => 'ð�²‚', 'ð�³ƒ' => 'ð�²ƒ', 'ð�³„' => 'ð�²„', 'ð�³…' => 'ð�²…', 'ð�³†' => 'ð�²†', 'ð�³‡' => 'ð�²‡', 'ð�³ˆ' => 'ð�²ˆ', 'ð�³‰' => 'ð�²‰', 'ð�³Š' => 'ð�²Š', 'ð�³‹' => 'ð�²‹', 'ð�³Œ' => 'ð�²Œ', 'ð�³�' => 'ð�²�', 'ð�³Ž' => 'ð�²Ž', 'ð�³�' => 'ð�²�', 'ð�³�' => 'ð�²�', 'ð�³‘' => 'ð�²‘', 'ð�³’' => 'ð�²’', 'ð�³“' => 'ð�²“', 'ð�³”' => 'ð�²”', 'ð�³•' => 'ð�²•', 'ð�³–' => 'ð�²–', 'ð�³—' => 'ð�²—', 'ð�³˜' => 'ð�²˜', 'ð�³™' => 'ð�²™', 'ð�³š' => 'ð�²š', 'ð�³›' => 'ð�²›', 'ð�³œ' => 'ð�²œ', 'ð�³�' => 'ð�²�', 'ð�³ž' => 'ð�²ž', 'ð�³Ÿ' => 'ð�²Ÿ', 'ð�³ ' => 'ð�² ', 'ð�³¡' => 'ð�²¡', 'ð�³¢' => 'ð�²¢', 'ð�³£' => 'ð�²£', 'ð�³¤' => 'ð�²¤', 'ð�³¥' => 'ð�²¥', 'ð�³¦' => 'ð�²¦', 'ð�³§' => 'ð�²§', 'ð�³¨' => 'ð�²¨', 'ð�³©' => 'ð�²©', 'ð�³ª' => 'ð�²ª', 'ð�³«' => 'ð�²«', 'ð�³¬' => 'ð�²¬', 'ð�³­' => 'ð�²­', 'ð�³®' => 'ð�²®', 'ð�³¯' => 'ð�²¯', 'ð�³°' => 'ð�²°', 'ð�³±' => 'ð�²±', 'ð�³²' => 'ð�²²', 'ð‘£€' => 'ð‘¢ ', 'ð‘£�' => 'ð‘¢¡', 'ð‘£‚' => 'ð‘¢¢', 'ð‘£ƒ' => 'ð‘¢£', 'ð‘£„' => 'ð‘¢¤', 'ð‘£…' => 'ð‘¢¥', 'ð‘£†' => 'ð‘¢¦', 'ð‘£‡' => 'ð‘¢§', 'ð‘£ˆ' => 'ð‘¢¨', 'ð‘£‰' => 'ð‘¢©', 'ð‘£Š' => 'ð‘¢ª', 'ð‘£‹' => 'ð‘¢«', 'ð‘£Œ' => 'ð‘¢¬', 'ð‘£�' => 'ð‘¢­', 'ð‘£Ž' => 'ð‘¢®', 'ð‘£�' => 'ð‘¢¯', 'ð‘£�' => 'ð‘¢°', 'ð‘£‘' => 'ð‘¢±', 'ð‘£’' => 'ð‘¢²', 'ð‘£“' => 'ð‘¢³', 'ð‘£”' => 'ð‘¢´', 'ð‘£•' => 'ð‘¢µ', 'ð‘£–' => 'ð‘¢¶', 'ð‘£—' => 'ð‘¢·', 'ð‘£˜' => 'ð‘¢¸', 'ð‘£™' => 'ð‘¢¹', 'ð‘£š' => 'ð‘¢º', 'ð‘£›' => 'ð‘¢»', 'ð‘£œ' => 'ð‘¢¼', 'ð‘£�' => 'ð‘¢½', 'ð‘£ž' => 'ð‘¢¾', 'ð‘£Ÿ' => 'ð‘¢¿', 'ð–¹ ' => 'ð–¹€', 'ð–¹¡' => 'ð–¹�', 'ð–¹¢' => 'ð–¹‚', 'ð–¹£' => 'ð–¹ƒ', 'ð–¹¤' => 'ð–¹„', 'ð–¹¥' => 'ð–¹…', 'ð–¹¦' => 'ð–¹†', 'ð–¹§' => 'ð–¹‡', 'ð–¹¨' => 'ð–¹ˆ', 'ð–¹©' => 'ð–¹‰', 'ð–¹ª' => 'ð–¹Š', 'ð–¹«' => 'ð–¹‹', 'ð–¹¬' => 'ð–¹Œ', 'ð–¹­' => 'ð–¹�', 'ð–¹®' => 'ð–¹Ž', 'ð–¹¯' => 'ð–¹�', 'ð–¹°' => 'ð–¹�', 'ð–¹±' => 'ð–¹‘', 'ð–¹²' => 'ð–¹’', 'ð–¹³' => 'ð–¹“', 'ð–¹´' => 'ð–¹”', 'ð–¹µ' => 'ð–¹•', 'ð–¹¶' => 'ð–¹–', 'ð–¹·' => 'ð–¹—', 'ð–¹¸' => 'ð–¹˜', 'ð–¹¹' => 'ð–¹™', 'ð–¹º' => 'ð–¹š', 'ð–¹»' => 'ð–¹›', 'ð–¹¼' => 'ð–¹œ', 'ð–¹½' => 'ð–¹�', 'ð–¹¾' => 'ð–¹ž', 'ð–¹¿' => 'ð–¹Ÿ', 'ðž¤¢' => 'ðž¤€', 'ðž¤£' => 'ðž¤�', 'ðž¤¤' => 'ðž¤‚', 'ðž¤¥' => 'ðž¤ƒ', 'ðž¤¦' => 'ðž¤„', 'ðž¤§' => 'ðž¤…', 'ðž¤¨' => 'ðž¤†', 'ðž¤©' => 'ðž¤‡', 'ðž¤ª' => 'ðž¤ˆ', 'ðž¤«' => 'ðž¤‰', 'ðž¤¬' => 'ðž¤Š', 'ðž¤­' => 'ðž¤‹', 'ðž¤®' => 'ðž¤Œ', 'ðž¤¯' => 'ðž¤�', 'ðž¤°' => 'ðž¤Ž', 'ðž¤±' => 'ðž¤�', 'ðž¤²' => 'ðž¤�', 'ðž¤³' => 'ðž¤‘', 'ðž¤´' => 'ðž¤’', 'ðž¤µ' => 'ðž¤“', 'ðž¤¶' => 'ðž¤”', 'ðž¤·' => 'ðž¤•', 'ðž¤¸' => 'ðž¤–', 'ðž¤¹' => 'ðž¤—', 'ðž¤º' => 'ðž¤˜', 'ðž¤»' => 'ðž¤™', 'ðž¤¼' => 'ðž¤š', 'ðž¤½' => 'ðž¤›', 'ðž¤¾' => 'ðž¤œ', 'ðž¤¿' => 'ðž¤�', 'ðž¥€' => 'ðž¤ž', 'ðž¥�' => 'ðž¤Ÿ', 'ðž¥‚' => 'ðž¤ ', 'ðž¥ƒ' => 'ðž¤¡');
<?php

namespace CivixPhar;

// from Case_Ignorable in https://unicode.org/Public/UNIDATA/DerivedCoreProperties.txt
return '/(?<![\\x{0027}\\x{002E}\\x{003A}\\x{005E}\\x{0060}\\x{00A8}\\x{00AD}\\x{00AF}\\x{00B4}\\x{00B7}\\x{00B8}\\x{02B0}-\\x{02C1}\\x{02C2}-\\x{02C5}\\x{02C6}-\\x{02D1}\\x{02D2}-\\x{02DF}\\x{02E0}-\\x{02E4}\\x{02E5}-\\x{02EB}\\x{02EC}\\x{02ED}\\x{02EE}\\x{02EF}-\\x{02FF}\\x{0300}-\\x{036F}\\x{0374}\\x{0375}\\x{037A}\\x{0384}-\\x{0385}\\x{0387}\\x{0483}-\\x{0487}\\x{0488}-\\x{0489}\\x{0559}\\x{0591}-\\x{05BD}\\x{05BF}\\x{05C1}-\\x{05C2}\\x{05C4}-\\x{05C5}\\x{05C7}\\x{05F4}\\x{0600}-\\x{0605}\\x{0610}-\\x{061A}\\x{061C}\\x{0640}\\x{064B}-\\x{065F}\\x{0670}\\x{06D6}-\\x{06DC}\\x{06DD}\\x{06DF}-\\x{06E4}\\x{06E5}-\\x{06E6}\\x{06E7}-\\x{06E8}\\x{06EA}-\\x{06ED}\\x{070F}\\x{0711}\\x{0730}-\\x{074A}\\x{07A6}-\\x{07B0}\\x{07EB}-\\x{07F3}\\x{07F4}-\\x{07F5}\\x{07FA}\\x{07FD}\\x{0816}-\\x{0819}\\x{081A}\\x{081B}-\\x{0823}\\x{0824}\\x{0825}-\\x{0827}\\x{0828}\\x{0829}-\\x{082D}\\x{0859}-\\x{085B}\\x{08D3}-\\x{08E1}\\x{08E2}\\x{08E3}-\\x{0902}\\x{093A}\\x{093C}\\x{0941}-\\x{0948}\\x{094D}\\x{0951}-\\x{0957}\\x{0962}-\\x{0963}\\x{0971}\\x{0981}\\x{09BC}\\x{09C1}-\\x{09C4}\\x{09CD}\\x{09E2}-\\x{09E3}\\x{09FE}\\x{0A01}-\\x{0A02}\\x{0A3C}\\x{0A41}-\\x{0A42}\\x{0A47}-\\x{0A48}\\x{0A4B}-\\x{0A4D}\\x{0A51}\\x{0A70}-\\x{0A71}\\x{0A75}\\x{0A81}-\\x{0A82}\\x{0ABC}\\x{0AC1}-\\x{0AC5}\\x{0AC7}-\\x{0AC8}\\x{0ACD}\\x{0AE2}-\\x{0AE3}\\x{0AFA}-\\x{0AFF}\\x{0B01}\\x{0B3C}\\x{0B3F}\\x{0B41}-\\x{0B44}\\x{0B4D}\\x{0B56}\\x{0B62}-\\x{0B63}\\x{0B82}\\x{0BC0}\\x{0BCD}\\x{0C00}\\x{0C04}\\x{0C3E}-\\x{0C40}\\x{0C46}-\\x{0C48}\\x{0C4A}-\\x{0C4D}\\x{0C55}-\\x{0C56}\\x{0C62}-\\x{0C63}\\x{0C81}\\x{0CBC}\\x{0CBF}\\x{0CC6}\\x{0CCC}-\\x{0CCD}\\x{0CE2}-\\x{0CE3}\\x{0D00}-\\x{0D01}\\x{0D3B}-\\x{0D3C}\\x{0D41}-\\x{0D44}\\x{0D4D}\\x{0D62}-\\x{0D63}\\x{0DCA}\\x{0DD2}-\\x{0DD4}\\x{0DD6}\\x{0E31}\\x{0E34}-\\x{0E3A}\\x{0E46}\\x{0E47}-\\x{0E4E}\\x{0EB1}\\x{0EB4}-\\x{0EB9}\\x{0EBB}-\\x{0EBC}\\x{0EC6}\\x{0EC8}-\\x{0ECD}\\x{0F18}-\\x{0F19}\\x{0F35}\\x{0F37}\\x{0F39}\\x{0F71}-\\x{0F7E}\\x{0F80}-\\x{0F84}\\x{0F86}-\\x{0F87}\\x{0F8D}-\\x{0F97}\\x{0F99}-\\x{0FBC}\\x{0FC6}\\x{102D}-\\x{1030}\\x{1032}-\\x{1037}\\x{1039}-\\x{103A}\\x{103D}-\\x{103E}\\x{1058}-\\x{1059}\\x{105E}-\\x{1060}\\x{1071}-\\x{1074}\\x{1082}\\x{1085}-\\x{1086}\\x{108D}\\x{109D}\\x{10FC}\\x{135D}-\\x{135F}\\x{1712}-\\x{1714}\\x{1732}-\\x{1734}\\x{1752}-\\x{1753}\\x{1772}-\\x{1773}\\x{17B4}-\\x{17B5}\\x{17B7}-\\x{17BD}\\x{17C6}\\x{17C9}-\\x{17D3}\\x{17D7}\\x{17DD}\\x{180B}-\\x{180D}\\x{180E}\\x{1843}\\x{1885}-\\x{1886}\\x{18A9}\\x{1920}-\\x{1922}\\x{1927}-\\x{1928}\\x{1932}\\x{1939}-\\x{193B}\\x{1A17}-\\x{1A18}\\x{1A1B}\\x{1A56}\\x{1A58}-\\x{1A5E}\\x{1A60}\\x{1A62}\\x{1A65}-\\x{1A6C}\\x{1A73}-\\x{1A7C}\\x{1A7F}\\x{1AA7}\\x{1AB0}-\\x{1ABD}\\x{1ABE}\\x{1B00}-\\x{1B03}\\x{1B34}\\x{1B36}-\\x{1B3A}\\x{1B3C}\\x{1B42}\\x{1B6B}-\\x{1B73}\\x{1B80}-\\x{1B81}\\x{1BA2}-\\x{1BA5}\\x{1BA8}-\\x{1BA9}\\x{1BAB}-\\x{1BAD}\\x{1BE6}\\x{1BE8}-\\x{1BE9}\\x{1BED}\\x{1BEF}-\\x{1BF1}\\x{1C2C}-\\x{1C33}\\x{1C36}-\\x{1C37}\\x{1C78}-\\x{1C7D}\\x{1CD0}-\\x{1CD2}\\x{1CD4}-\\x{1CE0}\\x{1CE2}-\\x{1CE8}\\x{1CED}\\x{1CF4}\\x{1CF8}-\\x{1CF9}\\x{1D2C}-\\x{1D6A}\\x{1D78}\\x{1D9B}-\\x{1DBF}\\x{1DC0}-\\x{1DF9}\\x{1DFB}-\\x{1DFF}\\x{1FBD}\\x{1FBF}-\\x{1FC1}\\x{1FCD}-\\x{1FCF}\\x{1FDD}-\\x{1FDF}\\x{1FED}-\\x{1FEF}\\x{1FFD}-\\x{1FFE}\\x{200B}-\\x{200F}\\x{2018}\\x{2019}\\x{2024}\\x{2027}\\x{202A}-\\x{202E}\\x{2060}-\\x{2064}\\x{2066}-\\x{206F}\\x{2071}\\x{207F}\\x{2090}-\\x{209C}\\x{20D0}-\\x{20DC}\\x{20DD}-\\x{20E0}\\x{20E1}\\x{20E2}-\\x{20E4}\\x{20E5}-\\x{20F0}\\x{2C7C}-\\x{2C7D}\\x{2CEF}-\\x{2CF1}\\x{2D6F}\\x{2D7F}\\x{2DE0}-\\x{2DFF}\\x{2E2F}\\x{3005}\\x{302A}-\\x{302D}\\x{3031}-\\x{3035}\\x{303B}\\x{3099}-\\x{309A}\\x{309B}-\\x{309C}\\x{309D}-\\x{309E}\\x{30FC}-\\x{30FE}\\x{A015}\\x{A4F8}-\\x{A4FD}\\x{A60C}\\x{A66F}\\x{A670}-\\x{A672}\\x{A674}-\\x{A67D}\\x{A67F}\\x{A69C}-\\x{A69D}\\x{A69E}-\\x{A69F}\\x{A6F0}-\\x{A6F1}\\x{A700}-\\x{A716}\\x{A717}-\\x{A71F}\\x{A720}-\\x{A721}\\x{A770}\\x{A788}\\x{A789}-\\x{A78A}\\x{A7F8}-\\x{A7F9}\\x{A802}\\x{A806}\\x{A80B}\\x{A825}-\\x{A826}\\x{A8C4}-\\x{A8C5}\\x{A8E0}-\\x{A8F1}\\x{A8FF}\\x{A926}-\\x{A92D}\\x{A947}-\\x{A951}\\x{A980}-\\x{A982}\\x{A9B3}\\x{A9B6}-\\x{A9B9}\\x{A9BC}\\x{A9CF}\\x{A9E5}\\x{A9E6}\\x{AA29}-\\x{AA2E}\\x{AA31}-\\x{AA32}\\x{AA35}-\\x{AA36}\\x{AA43}\\x{AA4C}\\x{AA70}\\x{AA7C}\\x{AAB0}\\x{AAB2}-\\x{AAB4}\\x{AAB7}-\\x{AAB8}\\x{AABE}-\\x{AABF}\\x{AAC1}\\x{AADD}\\x{AAEC}-\\x{AAED}\\x{AAF3}-\\x{AAF4}\\x{AAF6}\\x{AB5B}\\x{AB5C}-\\x{AB5F}\\x{ABE5}\\x{ABE8}\\x{ABED}\\x{FB1E}\\x{FBB2}-\\x{FBC1}\\x{FE00}-\\x{FE0F}\\x{FE13}\\x{FE20}-\\x{FE2F}\\x{FE52}\\x{FE55}\\x{FEFF}\\x{FF07}\\x{FF0E}\\x{FF1A}\\x{FF3E}\\x{FF40}\\x{FF70}\\x{FF9E}-\\x{FF9F}\\x{FFE3}\\x{FFF9}-\\x{FFFB}\\x{101FD}\\x{102E0}\\x{10376}-\\x{1037A}\\x{10A01}-\\x{10A03}\\x{10A05}-\\x{10A06}\\x{10A0C}-\\x{10A0F}\\x{10A38}-\\x{10A3A}\\x{10A3F}\\x{10AE5}-\\x{10AE6}\\x{10D24}-\\x{10D27}\\x{10F46}-\\x{10F50}\\x{11001}\\x{11038}-\\x{11046}\\x{1107F}-\\x{11081}\\x{110B3}-\\x{110B6}\\x{110B9}-\\x{110BA}\\x{110BD}\\x{110CD}\\x{11100}-\\x{11102}\\x{11127}-\\x{1112B}\\x{1112D}-\\x{11134}\\x{11173}\\x{11180}-\\x{11181}\\x{111B6}-\\x{111BE}\\x{111C9}-\\x{111CC}\\x{1122F}-\\x{11231}\\x{11234}\\x{11236}-\\x{11237}\\x{1123E}\\x{112DF}\\x{112E3}-\\x{112EA}\\x{11300}-\\x{11301}\\x{1133B}-\\x{1133C}\\x{11340}\\x{11366}-\\x{1136C}\\x{11370}-\\x{11374}\\x{11438}-\\x{1143F}\\x{11442}-\\x{11444}\\x{11446}\\x{1145E}\\x{114B3}-\\x{114B8}\\x{114BA}\\x{114BF}-\\x{114C0}\\x{114C2}-\\x{114C3}\\x{115B2}-\\x{115B5}\\x{115BC}-\\x{115BD}\\x{115BF}-\\x{115C0}\\x{115DC}-\\x{115DD}\\x{11633}-\\x{1163A}\\x{1163D}\\x{1163F}-\\x{11640}\\x{116AB}\\x{116AD}\\x{116B0}-\\x{116B5}\\x{116B7}\\x{1171D}-\\x{1171F}\\x{11722}-\\x{11725}\\x{11727}-\\x{1172B}\\x{1182F}-\\x{11837}\\x{11839}-\\x{1183A}\\x{11A01}-\\x{11A0A}\\x{11A33}-\\x{11A38}\\x{11A3B}-\\x{11A3E}\\x{11A47}\\x{11A51}-\\x{11A56}\\x{11A59}-\\x{11A5B}\\x{11A8A}-\\x{11A96}\\x{11A98}-\\x{11A99}\\x{11C30}-\\x{11C36}\\x{11C38}-\\x{11C3D}\\x{11C3F}\\x{11C92}-\\x{11CA7}\\x{11CAA}-\\x{11CB0}\\x{11CB2}-\\x{11CB3}\\x{11CB5}-\\x{11CB6}\\x{11D31}-\\x{11D36}\\x{11D3A}\\x{11D3C}-\\x{11D3D}\\x{11D3F}-\\x{11D45}\\x{11D47}\\x{11D90}-\\x{11D91}\\x{11D95}\\x{11D97}\\x{11EF3}-\\x{11EF4}\\x{16AF0}-\\x{16AF4}\\x{16B30}-\\x{16B36}\\x{16B40}-\\x{16B43}\\x{16F8F}-\\x{16F92}\\x{16F93}-\\x{16F9F}\\x{16FE0}-\\x{16FE1}\\x{1BC9D}-\\x{1BC9E}\\x{1BCA0}-\\x{1BCA3}\\x{1D167}-\\x{1D169}\\x{1D173}-\\x{1D17A}\\x{1D17B}-\\x{1D182}\\x{1D185}-\\x{1D18B}\\x{1D1AA}-\\x{1D1AD}\\x{1D242}-\\x{1D244}\\x{1DA00}-\\x{1DA36}\\x{1DA3B}-\\x{1DA6C}\\x{1DA75}\\x{1DA84}\\x{1DA9B}-\\x{1DA9F}\\x{1DAA1}-\\x{1DAAF}\\x{1E000}-\\x{1E006}\\x{1E008}-\\x{1E018}\\x{1E01B}-\\x{1E021}\\x{1E023}-\\x{1E024}\\x{1E026}-\\x{1E02A}\\x{1E8D0}-\\x{1E8D6}\\x{1E944}-\\x{1E94A}\\x{1F3FB}-\\x{1F3FF}\\x{E0001}\\x{E0020}-\\x{E007F}\\x{E0100}-\\x{E01EF}])(\\pL)(\\pL*+)/u';
<?php

namespace CivixPhar;

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
use CivixPhar\Symfony\Polyfill\Mbstring as p;
if (!\function_exists('mb_convert_encoding')) {
    function mb_convert_encoding(array|string|null $string, ?string $to_encoding, array|string|null $from_encoding = null) : array|string|false
    {
        return p\Mbstring::mb_convert_encoding($string ?? '', (string) $to_encoding, $from_encoding);
    }
}
if (!\function_exists('mb_decode_mimeheader')) {
    function mb_decode_mimeheader(?string $string) : string
    {
        return p\Mbstring::mb_decode_mimeheader((string) $string);
    }
}
if (!\function_exists('mb_encode_mimeheader')) {
    function mb_encode_mimeheader(?string $string, ?string $charset = null, ?string $transfer_encoding = null, ?string $newline = "\r\n", ?int $indent = 0) : string
    {
        return p\Mbstring::mb_encode_mimeheader((string) $string, $charset, $transfer_encoding, (string) $newline, (int) $indent);
    }
}
if (!\function_exists('mb_decode_numericentity')) {
    function mb_decode_numericentity(?string $string, array $map, ?string $encoding = null) : string
    {
        return p\Mbstring::mb_decode_numericentity((string) $string, $map, $encoding);
    }
}
if (!\function_exists('mb_encode_numericentity')) {
    function mb_encode_numericentity(?string $string, array $map, ?string $encoding = null, ?bool $hex = \false) : string
    {
        return p\Mbstring::mb_encode_numericentity((string) $string, $map, $encoding, (bool) $hex);
    }
}
if (!\function_exists('mb_convert_case')) {
    function mb_convert_case(?string $string, ?int $mode, ?string $encoding = null) : string
    {
        return p\Mbstring::mb_convert_case((string) $string, (int) $mode, $encoding);
    }
}
if (!\function_exists('mb_internal_encoding')) {
    function mb_internal_encoding(?string $encoding = null) : string|bool
    {
        return p\Mbstring::mb_internal_encoding($encoding);
    }
}
if (!\function_exists('mb_language')) {
    function mb_language(?string $language = null) : string|bool
    {
        return p\Mbstring::mb_language($language);
    }
}
if (!\function_exists('mb_list_encodings')) {
    function mb_list_encodings() : array
    {
        return p\Mbstring::mb_list_encodings();
    }
}
if (!\function_exists('mb_encoding_aliases')) {
    function mb_encoding_aliases(?string $encoding) : array
    {
        return p\Mbstring::mb_encoding_aliases((string) $encoding);
    }
}
if (!\function_exists('mb_check_encoding')) {
    function mb_check_encoding(array|string|null $value = null, ?string $encoding = null) : bool
    {
        return p\Mbstring::mb_check_encoding($value, $encoding);
    }
}
if (!\function_exists('mb_detect_encoding')) {
    function mb_detect_encoding(?string $string, array|string|null $encodings = null, ?bool $strict = \false) : string|false
    {
        return p\Mbstring::mb_detect_encoding((string) $string, $encodings, (bool) $strict);
    }
}
if (!\function_exists('mb_detect_order')) {
    function mb_detect_order(array|string|null $encoding = null) : array|bool
    {
        return p\Mbstring::mb_detect_order((string) $encoding);
    }
}
if (!\function_exists('mb_parse_str')) {
    function mb_parse_str(?string $string, &$result = []) : bool
    {
        \parse_str((string) $string, $result);
    }
}
if (!\function_exists('mb_strlen')) {
    function mb_strlen(?string $string, ?string $encoding = null) : int
    {
        return p\Mbstring::mb_strlen((string) $string, $encoding);
    }
}
if (!\function_exists('mb_strpos')) {
    function mb_strpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null) : int|false
    {
        return p\Mbstring::mb_strpos((string) $haystack, (string) $needle, (int) $offset, $encoding);
    }
}
if (!\function_exists('mb_strtolower')) {
    function mb_strtolower(?string $string, ?string $encoding = null) : string
    {
        return p\Mbstring::mb_strtolower((string) $string, $encoding);
    }
}
if (!\function_exists('mb_strtoupper')) {
    function mb_strtoupper(?string $string, ?string $encoding = null) : string
    {
        return p\Mbstring::mb_strtoupper((string) $string, $encoding);
    }
}
if (!\function_exists('mb_substitute_character')) {
    function mb_substitute_character(string|int|null $substitute_character = null) : string|int|bool
    {
        return p\Mbstring::mb_substitute_character($substitute_character);
    }
}
if (!\function_exists('mb_substr')) {
    function mb_substr(?string $string, ?int $start, ?int $length = null, ?string $encoding = null) : string
    {
        return p\Mbstring::mb_substr((string) $string, (int) $start, $length, $encoding);
    }
}
if (!\function_exists('mb_stripos')) {
    function mb_stripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null) : int|false
    {
        return p\Mbstring::mb_stripos((string) $haystack, (string) $needle, (int) $offset, $encoding);
    }
}
if (!\function_exists('mb_stristr')) {
    function mb_stristr(?string $haystack, ?string $needle, ?bool $before_needle = \false, ?string $encoding = null) : string|false
    {
        return p\Mbstring::mb_stristr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding);
    }
}
if (!\function_exists('mb_strrchr')) {
    function mb_strrchr(?string $haystack, ?string $needle, ?bool $before_needle = \false, ?string $encoding = null) : string|false
    {
        return p\Mbstring::mb_strrchr((string) $haystack, (string) $needle, $before_needle, (bool) $encoding);
    }
}
if (!\function_exists('mb_strrichr')) {
    function mb_strrichr(?string $haystack, ?string $needle, ?bool $before_needle = \false, ?string $encoding = null) : string|false
    {
        return p\Mbstring::mb_strrichr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding);
    }
}
if (!\function_exists('mb_strripos')) {
    function mb_strripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null) : int|false
    {
        return p\Mbstring::mb_strripos((string) $haystack, (string) $needle, (int) $offset, $encoding);
    }
}
if (!\function_exists('mb_strrpos')) {
    function mb_strrpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null) : int|false
    {
        return p\Mbstring::mb_strrpos((string) $haystack, (string) $needle, (int) $offset, $encoding);
    }
}
if (!\function_exists('mb_strstr')) {
    function mb_strstr(?string $haystack, ?string $needle, ?bool $before_needle = \false, ?string $encoding = null) : string|false
    {
        return p\Mbstring::mb_strstr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding);
    }
}
if (!\function_exists('mb_get_info')) {
    function mb_get_info(?string $type = 'all') : array|string|int|false
    {
        return p\Mbstring::mb_get_info((string) $type);
    }
}
if (!\function_exists('mb_http_output')) {
    function mb_http_output(?string $encoding = null) : string|bool
    {
        return p\Mbstring::mb_http_output($encoding);
    }
}
if (!\function_exists('mb_strwidth')) {
    function mb_strwidth(?string $string, ?string $encoding = null) : int
    {
        return p\Mbstring::mb_strwidth((string) $string, $encoding);
    }
}
if (!\function_exists('mb_substr_count')) {
    function mb_substr_count(?string $haystack, ?string $needle, ?string $encoding = null) : int
    {
        return p\Mbstring::mb_substr_count((string) $haystack, (string) $needle, $encoding);
    }
}
if (!\function_exists('mb_output_handler')) {
    function mb_output_handler(?string $string, ?int $status) : string
    {
        return p\Mbstring::mb_output_handler((string) $string, (int) $status);
    }
}
if (!\function_exists('mb_http_input')) {
    function mb_http_input(?string $type = null) : array|string|false
    {
        return p\Mbstring::mb_http_input($type);
    }
}
if (!\function_exists('mb_convert_variables')) {
    function mb_convert_variables(?string $to_encoding, array|string|null $from_encoding, mixed &$var, mixed &...$vars) : string|false
    {
        return p\Mbstring::mb_convert_variables((string) $to_encoding, $from_encoding ?? '', $var, ...$vars);
    }
}
if (!\function_exists('mb_ord')) {
    function mb_ord(?string $string, ?string $encoding = null) : int|false
    {
        return p\Mbstring::mb_ord((string) $string, $encoding);
    }
}
if (!\function_exists('mb_chr')) {
    function mb_chr(?int $codepoint, ?string $encoding = null) : string|false
    {
        return p\Mbstring::mb_chr((int) $codepoint, $encoding);
    }
}
if (!\function_exists('mb_scrub')) {
    function mb_scrub(?string $string, ?string $encoding = null) : string
    {
        $encoding ??= \mb_internal_encoding();
        return \mb_convert_encoding((string) $string, $encoding, $encoding);
    }
}
if (!\function_exists('mb_str_split')) {
    function mb_str_split(?string $string, ?int $length = 1, ?string $encoding = null) : array
    {
        return p\Mbstring::mb_str_split((string) $string, (int) $length, $encoding);
    }
}
if (\extension_loaded('mbstring')) {
    return;
}
if (!\defined('MB_CASE_UPPER')) {
    \define('MB_CASE_UPPER', 0);
}
if (!\defined('MB_CASE_LOWER')) {
    \define('MB_CASE_LOWER', 1);
}
if (!\defined('MB_CASE_TITLE')) {
    \define('MB_CASE_TITLE', 2);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Polyfill\Mbstring;

/**
 * Partial mbstring implementation in PHP, iconv based, UTF-8 centric.
 *
 * Implemented:
 * - mb_chr                  - Returns a specific character from its Unicode code point
 * - mb_convert_encoding     - Convert character encoding
 * - mb_convert_variables    - Convert character code in variable(s)
 * - mb_decode_mimeheader    - Decode string in MIME header field
 * - mb_encode_mimeheader    - Encode string for MIME header XXX NATIVE IMPLEMENTATION IS REALLY BUGGED
 * - mb_decode_numericentity - Decode HTML numeric string reference to character
 * - mb_encode_numericentity - Encode character to HTML numeric string reference
 * - mb_convert_case         - Perform case folding on a string
 * - mb_detect_encoding      - Detect character encoding
 * - mb_get_info             - Get internal settings of mbstring
 * - mb_http_input           - Detect HTTP input character encoding
 * - mb_http_output          - Set/Get HTTP output character encoding
 * - mb_internal_encoding    - Set/Get internal character encoding
 * - mb_list_encodings       - Returns an array of all supported encodings
 * - mb_ord                  - Returns the Unicode code point of a character
 * - mb_output_handler       - Callback function converts character encoding in output buffer
 * - mb_scrub                - Replaces ill-formed byte sequences with substitute characters
 * - mb_strlen               - Get string length
 * - mb_strpos               - Find position of first occurrence of string in a string
 * - mb_strrpos              - Find position of last occurrence of a string in a string
 * - mb_str_split            - Convert a string to an array
 * - mb_strtolower           - Make a string lowercase
 * - mb_strtoupper           - Make a string uppercase
 * - mb_substitute_character - Set/Get substitution character
 * - mb_substr               - Get part of string
 * - mb_stripos              - Finds position of first occurrence of a string within another, case insensitive
 * - mb_stristr              - Finds first occurrence of a string within another, case insensitive
 * - mb_strrchr              - Finds the last occurrence of a character in a string within another
 * - mb_strrichr             - Finds the last occurrence of a character in a string within another, case insensitive
 * - mb_strripos             - Finds position of last occurrence of a string within another, case insensitive
 * - mb_strstr               - Finds first occurrence of a string within another
 * - mb_strwidth             - Return width of string
 * - mb_substr_count         - Count the number of substring occurrences
 *
 * Not implemented:
 * - mb_convert_kana         - Convert "kana" one from another ("zen-kaku", "han-kaku" and more)
 * - mb_ereg_*               - Regular expression with multibyte support
 * - mb_parse_str            - Parse GET/POST/COOKIE data and set global variable
 * - mb_preferred_mime_name  - Get MIME charset string
 * - mb_regex_encoding       - Returns current encoding for multibyte regex as string
 * - mb_regex_set_options    - Set/Get the default options for mbregex functions
 * - mb_send_mail            - Send encoded mail
 * - mb_split                - Split multibyte string using regular expression
 * - mb_strcut               - Get part of string
 * - mb_strimwidth           - Get truncated string with specified width
 *
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @internal
 */
final class Mbstring
{
    public const MB_CASE_FOLD = \PHP_INT_MAX;
    private static $encodingList = ['ASCII', 'UTF-8'];
    private static $language = 'neutral';
    private static $internalEncoding = 'UTF-8';
    private static $caseFold = [['Âµ', 'Å¿', "Í…", 'Ï‚', "Ï�", "Ï‘", "Ï•", "Ï–", "Ï°", "Ï±", "Ïµ", "áº›", "á¾¾"], ['Î¼', 's', 'Î¹', 'Ïƒ', 'Î²', 'Î¸', 'Ï†', 'Ï€', 'Îº', 'Ï�', 'Îµ', "á¹¡", 'Î¹']];
    public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null)
    {
        if (\is_array($fromEncoding) || \false !== \strpos($fromEncoding, ',')) {
            $fromEncoding = self::mb_detect_encoding($s, $fromEncoding);
        } else {
            $fromEncoding = self::getEncoding($fromEncoding);
        }
        $toEncoding = self::getEncoding($toEncoding);
        if ('BASE64' === $fromEncoding) {
            $s = \base64_decode($s);
            $fromEncoding = $toEncoding;
        }
        if ('BASE64' === $toEncoding) {
            return \base64_encode($s);
        }
        if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) {
            if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) {
                $fromEncoding = 'Windows-1252';
            }
            if ('UTF-8' !== $fromEncoding) {
                $s = \iconv($fromEncoding, 'UTF-8//IGNORE', $s);
            }
            return \preg_replace_callback('/[\\x80-\\xFF]+/', [__CLASS__, 'html_encoding_callback'], $s);
        }
        if ('HTML-ENTITIES' === $fromEncoding) {
            $s = \html_entity_decode($s, \ENT_COMPAT, 'UTF-8');
            $fromEncoding = 'UTF-8';
        }
        return \iconv($fromEncoding, $toEncoding . '//IGNORE', $s);
    }
    public static function mb_convert_variables($toEncoding, $fromEncoding, &...$vars)
    {
        $ok = \true;
        \array_walk_recursive($vars, function (&$v) use(&$ok, $toEncoding, $fromEncoding) {
            if (\false === ($v = self::mb_convert_encoding($v, $toEncoding, $fromEncoding))) {
                $ok = \false;
            }
        });
        return $ok ? $fromEncoding : \false;
    }
    public static function mb_decode_mimeheader($s)
    {
        return \iconv_mime_decode($s, 2, self::$internalEncoding);
    }
    public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null)
    {
        \trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', \E_USER_WARNING);
    }
    public static function mb_decode_numericentity($s, $convmap, $encoding = null)
    {
        if (null !== $s && !\is_scalar($s) && !(\is_object($s) && \method_exists($s, '__toString'))) {
            \trigger_error('mb_decode_numericentity() expects parameter 1 to be string, ' . \gettype($s) . ' given', \E_USER_WARNING);
            return null;
        }
        if (!\is_array($convmap) || 80000 > \PHP_VERSION_ID && !$convmap) {
            return \false;
        }
        if (null !== $encoding && !\is_scalar($encoding)) {
            \trigger_error('mb_decode_numericentity() expects parameter 3 to be string, ' . \gettype($s) . ' given', \E_USER_WARNING);
            return '';
            // Instead of null (cf. mb_encode_numericentity).
        }
        $s = (string) $s;
        if ('' === $s) {
            return '';
        }
        $encoding = self::getEncoding($encoding);
        if ('UTF-8' === $encoding) {
            $encoding = null;
            if (!\preg_match('//u', $s)) {
                $s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s);
            }
        } else {
            $s = \iconv($encoding, 'UTF-8//IGNORE', $s);
        }
        $cnt = \floor(\count($convmap) / 4) * 4;
        for ($i = 0; $i < $cnt; $i += 4) {
            // collector_decode_htmlnumericentity ignores $convmap[$i + 3]
            $convmap[$i] += $convmap[$i + 2];
            $convmap[$i + 1] += $convmap[$i + 2];
        }
        $s = \preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use($cnt, $convmap) {
            $c = isset($m[2]) ? (int) \hexdec($m[2]) : $m[1];
            for ($i = 0; $i < $cnt; $i += 4) {
                if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) {
                    return self::mb_chr($c - $convmap[$i + 2]);
                }
            }
            return $m[0];
        }, $s);
        if (null === $encoding) {
            return $s;
        }
        return \iconv('UTF-8', $encoding . '//IGNORE', $s);
    }
    public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = \false)
    {
        if (null !== $s && !\is_scalar($s) && !(\is_object($s) && \method_exists($s, '__toString'))) {
            \trigger_error('mb_encode_numericentity() expects parameter 1 to be string, ' . \gettype($s) . ' given', \E_USER_WARNING);
            return null;
        }
        if (!\is_array($convmap) || 80000 > \PHP_VERSION_ID && !$convmap) {
            return \false;
        }
        if (null !== $encoding && !\is_scalar($encoding)) {
            \trigger_error('mb_encode_numericentity() expects parameter 3 to be string, ' . \gettype($s) . ' given', \E_USER_WARNING);
            return null;
            // Instead of '' (cf. mb_decode_numericentity).
        }
        if (null !== $is_hex && !\is_scalar($is_hex)) {
            \trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, ' . \gettype($s) . ' given', \E_USER_WARNING);
            return null;
        }
        $s = (string) $s;
        if ('' === $s) {
            return '';
        }
        $encoding = self::getEncoding($encoding);
        if ('UTF-8' === $encoding) {
            $encoding = null;
            if (!\preg_match('//u', $s)) {
                $s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s);
            }
        } else {
            $s = \iconv($encoding, 'UTF-8//IGNORE', $s);
        }
        static $ulenMask = ["\xc0" => 2, "\xd0" => 2, "\xe0" => 3, "\xf0" => 4];
        $cnt = \floor(\count($convmap) / 4) * 4;
        $i = 0;
        $len = \strlen($s);
        $result = '';
        while ($i < $len) {
            $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xf0"];
            $uchr = \substr($s, $i, $ulen);
            $i += $ulen;
            $c = self::mb_ord($uchr);
            for ($j = 0; $j < $cnt; $j += 4) {
                if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) {
                    $cOffset = $c + $convmap[$j + 2] & $convmap[$j + 3];
                    $result .= $is_hex ? \sprintf('&#x%X;', $cOffset) : '&#' . $cOffset . ';';
                    continue 2;
                }
            }
            $result .= $uchr;
        }
        if (null === $encoding) {
            return $result;
        }
        return \iconv('UTF-8', $encoding . '//IGNORE', $result);
    }
    public static function mb_convert_case($s, $mode, $encoding = null)
    {
        $s = (string) $s;
        if ('' === $s) {
            return '';
        }
        $encoding = self::getEncoding($encoding);
        if ('UTF-8' === $encoding) {
            $encoding = null;
            if (!\preg_match('//u', $s)) {
                $s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s);
            }
        } else {
            $s = \iconv($encoding, 'UTF-8//IGNORE', $s);
        }
        if (\MB_CASE_TITLE == $mode) {
            static $titleRegexp = null;
            if (null === $titleRegexp) {
                $titleRegexp = self::getData('titleCaseRegexp');
            }
            $s = \preg_replace_callback($titleRegexp, [__CLASS__, 'title_case'], $s);
        } else {
            if (\MB_CASE_UPPER == $mode) {
                static $upper = null;
                if (null === $upper) {
                    $upper = self::getData('upperCase');
                }
                $map = $upper;
            } else {
                if (self::MB_CASE_FOLD === $mode) {
                    $s = \str_replace(self::$caseFold[0], self::$caseFold[1], $s);
                }
                static $lower = null;
                if (null === $lower) {
                    $lower = self::getData('lowerCase');
                }
                $map = $lower;
            }
            static $ulenMask = ["\xc0" => 2, "\xd0" => 2, "\xe0" => 3, "\xf0" => 4];
            $i = 0;
            $len = \strlen($s);
            while ($i < $len) {
                $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xf0"];
                $uchr = \substr($s, $i, $ulen);
                $i += $ulen;
                if (isset($map[$uchr])) {
                    $uchr = $map[$uchr];
                    $nlen = \strlen($uchr);
                    if ($nlen == $ulen) {
                        $nlen = $i;
                        do {
                            $s[--$nlen] = $uchr[--$ulen];
                        } while ($ulen);
                    } else {
                        $s = \substr_replace($s, $uchr, $i - $ulen, $ulen);
                        $len += $nlen - $ulen;
                        $i += $nlen - $ulen;
                    }
                }
            }
        }
        if (null === $encoding) {
            return $s;
        }
        return \iconv('UTF-8', $encoding . '//IGNORE', $s);
    }
    public static function mb_internal_encoding($encoding = null)
    {
        if (null === $encoding) {
            return self::$internalEncoding;
        }
        $normalizedEncoding = self::getEncoding($encoding);
        if ('UTF-8' === $normalizedEncoding || \false !== @\iconv($normalizedEncoding, $normalizedEncoding, ' ')) {
            self::$internalEncoding = $normalizedEncoding;
            return \true;
        }
        if (80000 > \PHP_VERSION_ID) {
            return \false;
        }
        throw new \ValueError(\sprintf('Argument #1 ($encoding) must be a valid encoding, "%s" given', $encoding));
    }
    public static function mb_language($lang = null)
    {
        if (null === $lang) {
            return self::$language;
        }
        switch ($normalizedLang = \strtolower($lang)) {
            case 'uni':
            case 'neutral':
                self::$language = $normalizedLang;
                return \true;
        }
        if (80000 > \PHP_VERSION_ID) {
            return \false;
        }
        throw new \ValueError(\sprintf('Argument #1 ($language) must be a valid language, "%s" given', $lang));
    }
    public static function mb_list_encodings()
    {
        return ['UTF-8'];
    }
    public static function mb_encoding_aliases($encoding)
    {
        switch (\strtoupper($encoding)) {
            case 'UTF8':
            case 'UTF-8':
                return ['utf8'];
        }
        return \false;
    }
    public static function mb_check_encoding($var = null, $encoding = null)
    {
        if (null === $encoding) {
            if (null === $var) {
                return \false;
            }
            $encoding = self::$internalEncoding;
        }
        return self::mb_detect_encoding($var, [$encoding]) || \false !== @\iconv($encoding, $encoding, $var);
    }
    public static function mb_detect_encoding($str, $encodingList = null, $strict = \false)
    {
        if (null === $encodingList) {
            $encodingList = self::$encodingList;
        } else {
            if (!\is_array($encodingList)) {
                $encodingList = \array_map('trim', \explode(',', $encodingList));
            }
            $encodingList = \array_map('strtoupper', $encodingList);
        }
        foreach ($encodingList as $enc) {
            switch ($enc) {
                case 'ASCII':
                    if (!\preg_match('/[\\x80-\\xFF]/', $str)) {
                        return $enc;
                    }
                    break;
                case 'UTF8':
                case 'UTF-8':
                    if (\preg_match('//u', $str)) {
                        return 'UTF-8';
                    }
                    break;
                default:
                    if (0 === \strncmp($enc, 'ISO-8859-', 9)) {
                        return $enc;
                    }
            }
        }
        return \false;
    }
    public static function mb_detect_order($encodingList = null)
    {
        if (null === $encodingList) {
            return self::$encodingList;
        }
        if (!\is_array($encodingList)) {
            $encodingList = \array_map('trim', \explode(',', $encodingList));
        }
        $encodingList = \array_map('strtoupper', $encodingList);
        foreach ($encodingList as $enc) {
            switch ($enc) {
                default:
                    if (\strncmp($enc, 'ISO-8859-', 9)) {
                        return \false;
                    }
                // no break
                case 'ASCII':
                case 'UTF8':
                case 'UTF-8':
            }
        }
        self::$encodingList = $encodingList;
        return \true;
    }
    public static function mb_strlen($s, $encoding = null)
    {
        $encoding = self::getEncoding($encoding);
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
            return \strlen($s);
        }
        return @\iconv_strlen($s, $encoding);
    }
    public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null)
    {
        $encoding = self::getEncoding($encoding);
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
            return \strpos($haystack, $needle, $offset);
        }
        $needle = (string) $needle;
        if ('' === $needle) {
            if (80000 > \PHP_VERSION_ID) {
                \trigger_error(__METHOD__ . ': Empty delimiter', \E_USER_WARNING);
                return \false;
            }
            return 0;
        }
        return \iconv_strpos($haystack, $needle, $offset, $encoding);
    }
    public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null)
    {
        $encoding = self::getEncoding($encoding);
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
            return \strrpos($haystack, $needle, $offset);
        }
        if ($offset != (int) $offset) {
            $offset = 0;
        } elseif ($offset = (int) $offset) {
            if ($offset < 0) {
                if (0 > ($offset += self::mb_strlen($needle))) {
                    $haystack = self::mb_substr($haystack, 0, $offset, $encoding);
                }
                $offset = 0;
            } else {
                $haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding);
            }
        }
        $pos = '' !== $needle || 80000 > \PHP_VERSION_ID ? \iconv_strrpos($haystack, $needle, $encoding) : self::mb_strlen($haystack, $encoding);
        return \false !== $pos ? $offset + $pos : \false;
    }
    public static function mb_str_split($string, $split_length = 1, $encoding = null)
    {
        if (null !== $string && !\is_scalar($string) && !(\is_object($string) && \method_exists($string, '__toString'))) {
            \trigger_error('mb_str_split() expects parameter 1 to be string, ' . \gettype($string) . ' given', \E_USER_WARNING);
            return null;
        }
        if (1 > ($split_length = (int) $split_length)) {
            if (80000 > \PHP_VERSION_ID) {
                \trigger_error('The length of each segment must be greater than zero', \E_USER_WARNING);
                return \false;
            }
            throw new \ValueError('Argument #2 ($length) must be greater than 0');
        }
        if (null === $encoding) {
            $encoding = \mb_internal_encoding();
        }
        if ('UTF-8' === ($encoding = self::getEncoding($encoding))) {
            $rx = '/(';
            while (65535 < $split_length) {
                $rx .= '.{65535}';
                $split_length -= 65535;
            }
            $rx .= '.{' . $split_length . '})/us';
            return \preg_split($rx, $string, null, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY);
        }
        $result = [];
        $length = \mb_strlen($string, $encoding);
        for ($i = 0; $i < $length; $i += $split_length) {
            $result[] = \mb_substr($string, $i, $split_length, $encoding);
        }
        return $result;
    }
    public static function mb_strtolower($s, $encoding = null)
    {
        return self::mb_convert_case($s, \MB_CASE_LOWER, $encoding);
    }
    public static function mb_strtoupper($s, $encoding = null)
    {
        return self::mb_convert_case($s, \MB_CASE_UPPER, $encoding);
    }
    public static function mb_substitute_character($c = null)
    {
        if (null === $c) {
            return 'none';
        }
        if (0 === \strcasecmp($c, 'none')) {
            return \true;
        }
        if (80000 > \PHP_VERSION_ID) {
            return \false;
        }
        throw new \ValueError('Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint');
    }
    public static function mb_substr($s, $start, $length = null, $encoding = null)
    {
        $encoding = self::getEncoding($encoding);
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
            return (string) \substr($s, $start, null === $length ? 2147483647 : $length);
        }
        if ($start < 0) {
            $start = \iconv_strlen($s, $encoding) + $start;
            if ($start < 0) {
                $start = 0;
            }
        }
        if (null === $length) {
            $length = 2147483647;
        } elseif ($length < 0) {
            $length = \iconv_strlen($s, $encoding) + $length - $start;
            if ($length < 0) {
                return '';
            }
        }
        return (string) \iconv_substr($s, $start, $length, $encoding);
    }
    public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null)
    {
        $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
        $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
        return self::mb_strpos($haystack, $needle, $offset, $encoding);
    }
    public static function mb_stristr($haystack, $needle, $part = \false, $encoding = null)
    {
        $pos = self::mb_stripos($haystack, $needle, 0, $encoding);
        return self::getSubpart($pos, $part, $haystack, $encoding);
    }
    public static function mb_strrchr($haystack, $needle, $part = \false, $encoding = null)
    {
        $encoding = self::getEncoding($encoding);
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
            $pos = \strrpos($haystack, $needle);
        } else {
            $needle = self::mb_substr($needle, 0, 1, $encoding);
            $pos = \iconv_strrpos($haystack, $needle, $encoding);
        }
        return self::getSubpart($pos, $part, $haystack, $encoding);
    }
    public static function mb_strrichr($haystack, $needle, $part = \false, $encoding = null)
    {
        $needle = self::mb_substr($needle, 0, 1, $encoding);
        $pos = self::mb_strripos($haystack, $needle, $encoding);
        return self::getSubpart($pos, $part, $haystack, $encoding);
    }
    public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null)
    {
        $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
        $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
        return self::mb_strrpos($haystack, $needle, $offset, $encoding);
    }
    public static function mb_strstr($haystack, $needle, $part = \false, $encoding = null)
    {
        $pos = \strpos($haystack, $needle);
        if (\false === $pos) {
            return \false;
        }
        if ($part) {
            return \substr($haystack, 0, $pos);
        }
        return \substr($haystack, $pos);
    }
    public static function mb_get_info($type = 'all')
    {
        $info = ['internal_encoding' => self::$internalEncoding, 'http_output' => 'pass', 'http_output_conv_mimetypes' => '^(text/|application/xhtml\\+xml)', 'func_overload' => 0, 'func_overload_list' => 'no overload', 'mail_charset' => 'UTF-8', 'mail_header_encoding' => 'BASE64', 'mail_body_encoding' => 'BASE64', 'illegal_chars' => 0, 'encoding_translation' => 'Off', 'language' => self::$language, 'detect_order' => self::$encodingList, 'substitute_character' => 'none', 'strict_detection' => 'Off'];
        if ('all' === $type) {
            return $info;
        }
        if (isset($info[$type])) {
            return $info[$type];
        }
        return \false;
    }
    public static function mb_http_input($type = '')
    {
        return \false;
    }
    public static function mb_http_output($encoding = null)
    {
        return null !== $encoding ? 'pass' === $encoding : 'pass';
    }
    public static function mb_strwidth($s, $encoding = null)
    {
        $encoding = self::getEncoding($encoding);
        if ('UTF-8' !== $encoding) {
            $s = \iconv($encoding, 'UTF-8//IGNORE', $s);
        }
        $s = \preg_replace('/[\\x{1100}-\\x{115F}\\x{2329}\\x{232A}\\x{2E80}-\\x{303E}\\x{3040}-\\x{A4CF}\\x{AC00}-\\x{D7A3}\\x{F900}-\\x{FAFF}\\x{FE10}-\\x{FE19}\\x{FE30}-\\x{FE6F}\\x{FF00}-\\x{FF60}\\x{FFE0}-\\x{FFE6}\\x{20000}-\\x{2FFFD}\\x{30000}-\\x{3FFFD}]/u', '', $s, -1, $wide);
        return ($wide << 1) + \iconv_strlen($s, 'UTF-8');
    }
    public static function mb_substr_count($haystack, $needle, $encoding = null)
    {
        return \substr_count($haystack, $needle);
    }
    public static function mb_output_handler($contents, $status)
    {
        return $contents;
    }
    public static function mb_chr($code, $encoding = null)
    {
        if (0x80 > ($code %= 0x200000)) {
            $s = \chr($code);
        } elseif (0x800 > $code) {
            $s = \chr(0xc0 | $code >> 6) . \chr(0x80 | $code & 0x3f);
        } elseif (0x10000 > $code) {
            $s = \chr(0xe0 | $code >> 12) . \chr(0x80 | $code >> 6 & 0x3f) . \chr(0x80 | $code & 0x3f);
        } else {
            $s = \chr(0xf0 | $code >> 18) . \chr(0x80 | $code >> 12 & 0x3f) . \chr(0x80 | $code >> 6 & 0x3f) . \chr(0x80 | $code & 0x3f);
        }
        if ('UTF-8' !== ($encoding = self::getEncoding($encoding))) {
            $s = \mb_convert_encoding($s, $encoding, 'UTF-8');
        }
        return $s;
    }
    public static function mb_ord($s, $encoding = null)
    {
        if ('UTF-8' !== ($encoding = self::getEncoding($encoding))) {
            $s = \mb_convert_encoding($s, 'UTF-8', $encoding);
        }
        if (1 === \strlen($s)) {
            return \ord($s);
        }
        $code = ($s = \unpack('C*', \substr($s, 0, 4))) ? $s[1] : 0;
        if (0xf0 <= $code) {
            return ($code - 0xf0 << 18) + ($s[2] - 0x80 << 12) + ($s[3] - 0x80 << 6) + $s[4] - 0x80;
        }
        if (0xe0 <= $code) {
            return ($code - 0xe0 << 12) + ($s[2] - 0x80 << 6) + $s[3] - 0x80;
        }
        if (0xc0 <= $code) {
            return ($code - 0xc0 << 6) + $s[2] - 0x80;
        }
        return $code;
    }
    private static function getSubpart($pos, $part, $haystack, $encoding)
    {
        if (\false === $pos) {
            return \false;
        }
        if ($part) {
            return self::mb_substr($haystack, 0, $pos, $encoding);
        }
        return self::mb_substr($haystack, $pos, null, $encoding);
    }
    private static function html_encoding_callback(array $m)
    {
        $i = 1;
        $entities = '';
        $m = \unpack('C*', \htmlentities($m[0], \ENT_COMPAT, 'UTF-8'));
        while (isset($m[$i])) {
            if (0x80 > $m[$i]) {
                $entities .= \chr($m[$i++]);
                continue;
            }
            if (0xf0 <= $m[$i]) {
                $c = ($m[$i++] - 0xf0 << 18) + ($m[$i++] - 0x80 << 12) + ($m[$i++] - 0x80 << 6) + $m[$i++] - 0x80;
            } elseif (0xe0 <= $m[$i]) {
                $c = ($m[$i++] - 0xe0 << 12) + ($m[$i++] - 0x80 << 6) + $m[$i++] - 0x80;
            } else {
                $c = ($m[$i++] - 0xc0 << 6) + $m[$i++] - 0x80;
            }
            $entities .= '&#' . $c . ';';
        }
        return $entities;
    }
    private static function title_case(array $s)
    {
        return self::mb_convert_case($s[1], \MB_CASE_UPPER, 'UTF-8') . self::mb_convert_case($s[2], \MB_CASE_LOWER, 'UTF-8');
    }
    private static function getData($file)
    {
        if (\file_exists($file = __DIR__ . '/Resources/unidata/' . $file . '.php')) {
            return require $file;
        }
        return \false;
    }
    private static function getEncoding($encoding)
    {
        if (null === $encoding) {
            return self::$internalEncoding;
        }
        if ('UTF-8' === $encoding) {
            return 'UTF-8';
        }
        $encoding = \strtoupper($encoding);
        if ('8BIT' === $encoding || 'BINARY' === $encoding) {
            return 'CP850';
        }
        if ('UTF8' === $encoding) {
            return 'UTF-8';
        }
        return $encoding;
    }
}
<?php

namespace CivixPhar;

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
use CivixPhar\Symfony\Polyfill\Mbstring as p;
if (\PHP_VERSION_ID >= 80000) {
    return require __DIR__ . '/bootstrap80.php';
}
if (!\function_exists('mb_convert_encoding')) {
    function mb_convert_encoding($string, $to_encoding, $from_encoding = null)
    {
        return p\Mbstring::mb_convert_encoding($string, $to_encoding, $from_encoding);
    }
}
if (!\function_exists('mb_decode_mimeheader')) {
    function mb_decode_mimeheader($string)
    {
        return p\Mbstring::mb_decode_mimeheader($string);
    }
}
if (!\function_exists('mb_encode_mimeheader')) {
    function mb_encode_mimeheader($string, $charset = null, $transfer_encoding = null, $newline = "\r\n", $indent = 0)
    {
        return p\Mbstring::mb_encode_mimeheader($string, $charset, $transfer_encoding, $newline, $indent);
    }
}
if (!\function_exists('mb_decode_numericentity')) {
    function mb_decode_numericentity($string, $map, $encoding = null)
    {
        return p\Mbstring::mb_decode_numericentity($string, $map, $encoding);
    }
}
if (!\function_exists('mb_encode_numericentity')) {
    function mb_encode_numericentity($string, $map, $encoding = null, $hex = \false)
    {
        return p\Mbstring::mb_encode_numericentity($string, $map, $encoding, $hex);
    }
}
if (!\function_exists('mb_convert_case')) {
    function mb_convert_case($string, $mode, $encoding = null)
    {
        return p\Mbstring::mb_convert_case($string, $mode, $encoding);
    }
}
if (!\function_exists('mb_internal_encoding')) {
    function mb_internal_encoding($encoding = null)
    {
        return p\Mbstring::mb_internal_encoding($encoding);
    }
}
if (!\function_exists('mb_language')) {
    function mb_language($language = null)
    {
        return p\Mbstring::mb_language($language);
    }
}
if (!\function_exists('mb_list_encodings')) {
    function mb_list_encodings()
    {
        return p\Mbstring::mb_list_encodings();
    }
}
if (!\function_exists('mb_encoding_aliases')) {
    function mb_encoding_aliases($encoding)
    {
        return p\Mbstring::mb_encoding_aliases($encoding);
    }
}
if (!\function_exists('mb_check_encoding')) {
    function mb_check_encoding($value = null, $encoding = null)
    {
        return p\Mbstring::mb_check_encoding($value, $encoding);
    }
}
if (!\function_exists('mb_detect_encoding')) {
    function mb_detect_encoding($string, $encodings = null, $strict = \false)
    {
        return p\Mbstring::mb_detect_encoding($string, $encodings, $strict);
    }
}
if (!\function_exists('mb_detect_order')) {
    function mb_detect_order($encoding = null)
    {
        return p\Mbstring::mb_detect_order($encoding);
    }
}
if (!\function_exists('mb_parse_str')) {
    function mb_parse_str($string, &$result = [])
    {
        \parse_str($string, $result);
    }
}
if (!\function_exists('mb_strlen')) {
    function mb_strlen($string, $encoding = null)
    {
        return p\Mbstring::mb_strlen($string, $encoding);
    }
}
if (!\function_exists('mb_strpos')) {
    function mb_strpos($haystack, $needle, $offset = 0, $encoding = null)
    {
        return p\Mbstring::mb_strpos($haystack, $needle, $offset, $encoding);
    }
}
if (!\function_exists('mb_strtolower')) {
    function mb_strtolower($string, $encoding = null)
    {
        return p\Mbstring::mb_strtolower($string, $encoding);
    }
}
if (!\function_exists('mb_strtoupper')) {
    function mb_strtoupper($string, $encoding = null)
    {
        return p\Mbstring::mb_strtoupper($string, $encoding);
    }
}
if (!\function_exists('mb_substitute_character')) {
    function mb_substitute_character($substitute_character = null)
    {
        return p\Mbstring::mb_substitute_character($substitute_character);
    }
}
if (!\function_exists('mb_substr')) {
    function mb_substr($string, $start, $length = 2147483647, $encoding = null)
    {
        return p\Mbstring::mb_substr($string, $start, $length, $encoding);
    }
}
if (!\function_exists('mb_stripos')) {
    function mb_stripos($haystack, $needle, $offset = 0, $encoding = null)
    {
        return p\Mbstring::mb_stripos($haystack, $needle, $offset, $encoding);
    }
}
if (!\function_exists('mb_stristr')) {
    function mb_stristr($haystack, $needle, $before_needle = \false, $encoding = null)
    {
        return p\Mbstring::mb_stristr($haystack, $needle, $before_needle, $encoding);
    }
}
if (!\function_exists('mb_strrchr')) {
    function mb_strrchr($haystack, $needle, $before_needle = \false, $encoding = null)
    {
        return p\Mbstring::mb_strrchr($haystack, $needle, $before_needle, $encoding);
    }
}
if (!\function_exists('mb_strrichr')) {
    function mb_strrichr($haystack, $needle, $before_needle = \false, $encoding = null)
    {
        return p\Mbstring::mb_strrichr($haystack, $needle, $before_needle, $encoding);
    }
}
if (!\function_exists('mb_strripos')) {
    function mb_strripos($haystack, $needle, $offset = 0, $encoding = null)
    {
        return p\Mbstring::mb_strripos($haystack, $needle, $offset, $encoding);
    }
}
if (!\function_exists('mb_strrpos')) {
    function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null)
    {
        return p\Mbstring::mb_strrpos($haystack, $needle, $offset, $encoding);
    }
}
if (!\function_exists('mb_strstr')) {
    function mb_strstr($haystack, $needle, $before_needle = \false, $encoding = null)
    {
        return p\Mbstring::mb_strstr($haystack, $needle, $before_needle, $encoding);
    }
}
if (!\function_exists('mb_get_info')) {
    function mb_get_info($type = 'all')
    {
        return p\Mbstring::mb_get_info($type);
    }
}
if (!\function_exists('mb_http_output')) {
    function mb_http_output($encoding = null)
    {
        return p\Mbstring::mb_http_output($encoding);
    }
}
if (!\function_exists('mb_strwidth')) {
    function mb_strwidth($string, $encoding = null)
    {
        return p\Mbstring::mb_strwidth($string, $encoding);
    }
}
if (!\function_exists('mb_substr_count')) {
    function mb_substr_count($haystack, $needle, $encoding = null)
    {
        return p\Mbstring::mb_substr_count($haystack, $needle, $encoding);
    }
}
if (!\function_exists('mb_output_handler')) {
    function mb_output_handler($string, $status)
    {
        return p\Mbstring::mb_output_handler($string, $status);
    }
}
if (!\function_exists('mb_http_input')) {
    function mb_http_input($type = null)
    {
        return p\Mbstring::mb_http_input($type);
    }
}
if (!\function_exists('mb_convert_variables')) {
    function mb_convert_variables($to_encoding, $from_encoding, &...$vars)
    {
        return p\Mbstring::mb_convert_variables($to_encoding, $from_encoding, ...$vars);
    }
}
if (!\function_exists('mb_ord')) {
    function mb_ord($string, $encoding = null)
    {
        return p\Mbstring::mb_ord($string, $encoding);
    }
}
if (!\function_exists('mb_chr')) {
    function mb_chr($codepoint, $encoding = null)
    {
        return p\Mbstring::mb_chr($codepoint, $encoding);
    }
}
if (!\function_exists('mb_scrub')) {
    function mb_scrub($string, $encoding = null)
    {
        $encoding = null === $encoding ? \mb_internal_encoding() : $encoding;
        return \mb_convert_encoding($string, $encoding, $encoding);
    }
}
if (!\function_exists('mb_str_split')) {
    function mb_str_split($string, $length = 1, $encoding = null)
    {
        return p\Mbstring::mb_str_split($string, $length, $encoding);
    }
}
if (\extension_loaded('mbstring')) {
    return;
}
if (!\defined('MB_CASE_UPPER')) {
    \define('MB_CASE_UPPER', 0);
}
if (!\defined('MB_CASE_LOWER')) {
    \define('MB_CASE_LOWER', 1);
}
if (!\defined('MB_CASE_TITLE')) {
    \define('MB_CASE_TITLE', 2);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Polyfill\Ctype;

/**
 * Ctype implementation through regex.
 *
 * @internal
 *
 * @author Gert de Pagter <BackEndTea@gmail.com>
 */
final class Ctype
{
    /**
     * Returns TRUE if every character in text is either a letter or a digit, FALSE otherwise.
     *
     * @see https://php.net/ctype-alnum
     *
     * @param string|int $text
     *
     * @return bool
     */
    public static function ctype_alnum($text)
    {
        $text = self::convert_int_to_char_for_ctype($text);
        return \is_string($text) && '' !== $text && !\preg_match('/[^A-Za-z0-9]/', $text);
    }
    /**
     * Returns TRUE if every character in text is a letter, FALSE otherwise.
     *
     * @see https://php.net/ctype-alpha
     *
     * @param string|int $text
     *
     * @return bool
     */
    public static function ctype_alpha($text)
    {
        $text = self::convert_int_to_char_for_ctype($text);
        return \is_string($text) && '' !== $text && !\preg_match('/[^A-Za-z]/', $text);
    }
    /**
     * Returns TRUE if every character in text is a control character from the current locale, FALSE otherwise.
     *
     * @see https://php.net/ctype-cntrl
     *
     * @param string|int $text
     *
     * @return bool
     */
    public static function ctype_cntrl($text)
    {
        $text = self::convert_int_to_char_for_ctype($text);
        return \is_string($text) && '' !== $text && !\preg_match('/[^\\x00-\\x1f\\x7f]/', $text);
    }
    /**
     * Returns TRUE if every character in the string text is a decimal digit, FALSE otherwise.
     *
     * @see https://php.net/ctype-digit
     *
     * @param string|int $text
     *
     * @return bool
     */
    public static function ctype_digit($text)
    {
        $text = self::convert_int_to_char_for_ctype($text);
        return \is_string($text) && '' !== $text && !\preg_match('/[^0-9]/', $text);
    }
    /**
     * Returns TRUE if every character in text is printable and actually creates visible output (no white space), FALSE otherwise.
     *
     * @see https://php.net/ctype-graph
     *
     * @param string|int $text
     *
     * @return bool
     */
    public static function ctype_graph($text)
    {
        $text = self::convert_int_to_char_for_ctype($text);
        return \is_string($text) && '' !== $text && !\preg_match('/[^!-~]/', $text);
    }
    /**
     * Returns TRUE if every character in text is a lowercase letter.
     *
     * @see https://php.net/ctype-lower
     *
     * @param string|int $text
     *
     * @return bool
     */
    public static function ctype_lower($text)
    {
        $text = self::convert_int_to_char_for_ctype($text);
        return \is_string($text) && '' !== $text && !\preg_match('/[^a-z]/', $text);
    }
    /**
     * Returns TRUE if every character in text will actually create output (including blanks). Returns FALSE if text contains control characters or characters that do not have any output or control function at all.
     *
     * @see https://php.net/ctype-print
     *
     * @param string|int $text
     *
     * @return bool
     */
    public static function ctype_print($text)
    {
        $text = self::convert_int_to_char_for_ctype($text);
        return \is_string($text) && '' !== $text && !\preg_match('/[^ -~]/', $text);
    }
    /**
     * Returns TRUE if every character in text is printable, but neither letter, digit or blank, FALSE otherwise.
     *
     * @see https://php.net/ctype-punct
     *
     * @param string|int $text
     *
     * @return bool
     */
    public static function ctype_punct($text)
    {
        $text = self::convert_int_to_char_for_ctype($text);
        return \is_string($text) && '' !== $text && !\preg_match('/[^!-\\/\\:-@\\[-`\\{-~]/', $text);
    }
    /**
     * Returns TRUE if every character in text creates some sort of white space, FALSE otherwise. Besides the blank character this also includes tab, vertical tab, line feed, carriage return and form feed characters.
     *
     * @see https://php.net/ctype-space
     *
     * @param string|int $text
     *
     * @return bool
     */
    public static function ctype_space($text)
    {
        $text = self::convert_int_to_char_for_ctype($text);
        return \is_string($text) && '' !== $text && !\preg_match('/[^\\s]/', $text);
    }
    /**
     * Returns TRUE if every character in text is an uppercase letter.
     *
     * @see https://php.net/ctype-upper
     *
     * @param string|int $text
     *
     * @return bool
     */
    public static function ctype_upper($text)
    {
        $text = self::convert_int_to_char_for_ctype($text);
        return \is_string($text) && '' !== $text && !\preg_match('/[^A-Z]/', $text);
    }
    /**
     * Returns TRUE if every character in text is a hexadecimal 'digit', that is a decimal digit or a character from [A-Fa-f] , FALSE otherwise.
     *
     * @see https://php.net/ctype-xdigit
     *
     * @param string|int $text
     *
     * @return bool
     */
    public static function ctype_xdigit($text)
    {
        $text = self::convert_int_to_char_for_ctype($text);
        return \is_string($text) && '' !== $text && !\preg_match('/[^A-Fa-f0-9]/', $text);
    }
    /**
     * Converts integers to their char versions according to normal ctype behaviour, if needed.
     *
     * If an integer between -128 and 255 inclusive is provided,
     * it is interpreted as the ASCII value of a single character
     * (negative values have 256 added in order to allow characters in the Extended ASCII range).
     * Any other integer is interpreted as a string containing the decimal digits of the integer.
     *
     * @param string|int $int
     *
     * @return mixed
     */
    private static function convert_int_to_char_for_ctype($int)
    {
        if (!\is_int($int)) {
            return $int;
        }
        if ($int < -128 || $int > 255) {
            return (string) $int;
        }
        if ($int < 0) {
            $int += 256;
        }
        return \chr($int);
    }
}
<?php

namespace CivixPhar;

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
use CivixPhar\Symfony\Polyfill\Ctype as p;
if (!\function_exists('ctype_alnum')) {
    function ctype_alnum(mixed $text) : bool
    {
        return p\Ctype::ctype_alnum($text);
    }
}
if (!\function_exists('ctype_alpha')) {
    function ctype_alpha(mixed $text) : bool
    {
        return p\Ctype::ctype_alpha($text);
    }
}
if (!\function_exists('ctype_cntrl')) {
    function ctype_cntrl(mixed $text) : bool
    {
        return p\Ctype::ctype_cntrl($text);
    }
}
if (!\function_exists('ctype_digit')) {
    function ctype_digit(mixed $text) : bool
    {
        return p\Ctype::ctype_digit($text);
    }
}
if (!\function_exists('ctype_graph')) {
    function ctype_graph(mixed $text) : bool
    {
        return p\Ctype::ctype_graph($text);
    }
}
if (!\function_exists('ctype_lower')) {
    function ctype_lower(mixed $text) : bool
    {
        return p\Ctype::ctype_lower($text);
    }
}
if (!\function_exists('ctype_print')) {
    function ctype_print(mixed $text) : bool
    {
        return p\Ctype::ctype_print($text);
    }
}
if (!\function_exists('ctype_punct')) {
    function ctype_punct(mixed $text) : bool
    {
        return p\Ctype::ctype_punct($text);
    }
}
if (!\function_exists('ctype_space')) {
    function ctype_space(mixed $text) : bool
    {
        return p\Ctype::ctype_space($text);
    }
}
if (!\function_exists('ctype_upper')) {
    function ctype_upper(mixed $text) : bool
    {
        return p\Ctype::ctype_upper($text);
    }
}
if (!\function_exists('ctype_xdigit')) {
    function ctype_xdigit(mixed $text) : bool
    {
        return p\Ctype::ctype_xdigit($text);
    }
}
<?php

namespace CivixPhar;

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
use CivixPhar\Symfony\Polyfill\Ctype as p;
if (\PHP_VERSION_ID >= 80000) {
    return require __DIR__ . '/bootstrap80.php';
}
if (!\function_exists('ctype_alnum')) {
    function ctype_alnum($text)
    {
        return p\Ctype::ctype_alnum($text);
    }
}
if (!\function_exists('ctype_alpha')) {
    function ctype_alpha($text)
    {
        return p\Ctype::ctype_alpha($text);
    }
}
if (!\function_exists('ctype_cntrl')) {
    function ctype_cntrl($text)
    {
        return p\Ctype::ctype_cntrl($text);
    }
}
if (!\function_exists('ctype_digit')) {
    function ctype_digit($text)
    {
        return p\Ctype::ctype_digit($text);
    }
}
if (!\function_exists('ctype_graph')) {
    function ctype_graph($text)
    {
        return p\Ctype::ctype_graph($text);
    }
}
if (!\function_exists('ctype_lower')) {
    function ctype_lower($text)
    {
        return p\Ctype::ctype_lower($text);
    }
}
if (!\function_exists('ctype_print')) {
    function ctype_print($text)
    {
        return p\Ctype::ctype_print($text);
    }
}
if (!\function_exists('ctype_punct')) {
    function ctype_punct($text)
    {
        return p\Ctype::ctype_punct($text);
    }
}
if (!\function_exists('ctype_space')) {
    function ctype_space($text)
    {
        return p\Ctype::ctype_space($text);
    }
}
if (!\function_exists('ctype_upper')) {
    function ctype_upper($text)
    {
        return p\Ctype::ctype_upper($text);
    }
}
if (!\function_exists('ctype_xdigit')) {
    function ctype_xdigit($text)
    {
        return p\Ctype::ctype_xdigit($text);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Contracts\Service;

use CivixPhar\Psr\Container\ContainerInterface;
/**
 * Implementation of ServiceSubscriberInterface that determines subscribed services from
 * private method return types. Service ids are available as "ClassName::methodName".
 *
 * @author Kevin Bond <kevinbond@gmail.com>
 */
trait ServiceSubscriberTrait
{
    /** @var ContainerInterface */
    protected $container;
    /**
     * {@inheritdoc}
     */
    public static function getSubscribedServices() : array
    {
        static $services;
        if (null !== $services) {
            return $services;
        }
        $services = \is_callable(['parent', __FUNCTION__]) ? parent::getSubscribedServices() : [];
        foreach ((new \ReflectionClass(self::class))->getMethods() as $method) {
            if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) {
                continue;
            }
            if (self::class !== $method->getDeclaringClass()->name) {
                continue;
            }
            if (!($returnType = $method->getReturnType()) instanceof \ReflectionNamedType) {
                continue;
            }
            if ($returnType->isBuiltin()) {
                continue;
            }
            $services[self::class . '::' . $method->name] = '?' . $returnType->getName();
        }
        return $services;
    }
    /**
     * @required
     *
     * @return ContainerInterface|null
     */
    public function setContainer(ContainerInterface $container)
    {
        $this->container = $container;
        if (\is_callable(['parent', __FUNCTION__])) {
            return parent::setContainer($container);
        }
        return null;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Contracts\Service;

/**
 * A ServiceSubscriber exposes its dependencies via the static {@link getSubscribedServices} method.
 *
 * The getSubscribedServices method returns an array of service types required by such instances,
 * optionally keyed by the service names used internally. Service types that start with an interrogation
 * mark "?" are optional, while the other ones are mandatory service dependencies.
 *
 * The injected service locators SHOULD NOT allow access to any other services not specified by the method.
 *
 * It is expected that ServiceSubscriber instances consume PSR-11-based service locators internally.
 * This interface does not dictate any injection method for these service locators, although constructor
 * injection is recommended.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
interface ServiceSubscriberInterface
{
    /**
     * Returns an array of service types required by such instances, optionally keyed by the service names used internally.
     *
     * For mandatory dependencies:
     *
     *  * ['logger' => 'Psr\Log\LoggerInterface'] means the objects use the "logger" name
     *    internally to fetch a service which must implement Psr\Log\LoggerInterface.
     *  * ['loggers' => 'Psr\Log\LoggerInterface[]'] means the objects use the "loggers" name
     *    internally to fetch an iterable of Psr\Log\LoggerInterface instances.
     *  * ['Psr\Log\LoggerInterface'] is a shortcut for
     *  * ['Psr\Log\LoggerInterface' => 'Psr\Log\LoggerInterface']
     *
     * otherwise:
     *
     *  * ['logger' => '?Psr\Log\LoggerInterface'] denotes an optional dependency
     *  * ['loggers' => '?Psr\Log\LoggerInterface[]'] denotes an optional iterable dependency
     *  * ['?Psr\Log\LoggerInterface'] is a shortcut for
     *  * ['Psr\Log\LoggerInterface' => '?Psr\Log\LoggerInterface']
     *
     * @return string[] The required service types, optionally keyed by service names
     */
    public static function getSubscribedServices();
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Contracts\Service;

/**
 * Provides a way to reset an object to its initial state.
 *
 * When calling the "reset()" method on an object, it should be put back to its
 * initial state. This usually means clearing any internal buffers and forwarding
 * the call to internal dependencies. All properties of the object should be put
 * back to the same state it had when it was first ready to use.
 *
 * This method could be called, for example, to recycle objects that are used as
 * services, so that they can be used to handle several requests in the same
 * process loop (note that we advise making your services stateless instead of
 * implementing this interface when possible.)
 */
interface ResetInterface
{
    public function reset();
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Contracts\Service;

use CivixPhar\Psr\Container\ContainerExceptionInterface;
use CivixPhar\Psr\Container\NotFoundExceptionInterface;
// Help opcache.preload discover always-needed symbols
\class_exists(ContainerExceptionInterface::class);
\class_exists(NotFoundExceptionInterface::class);
/**
 * A trait to help implement ServiceProviderInterface.
 *
 * @author Robin Chalas <robin.chalas@gmail.com>
 * @author Nicolas Grekas <p@tchwork.com>
 */
trait ServiceLocatorTrait
{
    private $factories;
    private $loading = [];
    private $providedTypes;
    /**
     * @param callable[] $factories
     */
    public function __construct(array $factories)
    {
        $this->factories = $factories;
    }
    /**
     * {@inheritdoc}
     *
     * @return bool
     */
    public function has($id)
    {
        return isset($this->factories[$id]);
    }
    /**
     * {@inheritdoc}
     *
     * @return mixed
     */
    public function get($id)
    {
        if (!isset($this->factories[$id])) {
            throw $this->createNotFoundException($id);
        }
        if (isset($this->loading[$id])) {
            $ids = \array_values($this->loading);
            $ids = \array_slice($this->loading, \array_search($id, $ids));
            $ids[] = $id;
            throw $this->createCircularReferenceException($id, $ids);
        }
        $this->loading[$id] = $id;
        try {
            return $this->factories[$id]($this);
        } finally {
            unset($this->loading[$id]);
        }
    }
    /**
     * {@inheritdoc}
     */
    public function getProvidedServices() : array
    {
        if (null === $this->providedTypes) {
            $this->providedTypes = [];
            foreach ($this->factories as $name => $factory) {
                if (!\is_callable($factory)) {
                    $this->providedTypes[$name] = '?';
                } else {
                    $type = (new \ReflectionFunction($factory))->getReturnType();
                    $this->providedTypes[$name] = $type ? ($type->allowsNull() ? '?' : '') . ($type instanceof \ReflectionNamedType ? $type->getName() : $type) : '?';
                }
            }
        }
        return $this->providedTypes;
    }
    private function createNotFoundException(string $id) : NotFoundExceptionInterface
    {
        if (!($alternatives = \array_keys($this->factories))) {
            $message = 'is empty...';
        } else {
            $last = \array_pop($alternatives);
            if ($alternatives) {
                $message = \sprintf('only knows about the "%s" and "%s" services.', \implode('", "', $alternatives), $last);
            } else {
                $message = \sprintf('only knows about the "%s" service.', $last);
            }
        }
        if ($this->loading) {
            $message = \sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', \end($this->loading), $id, $message);
        } else {
            $message = \sprintf('Service "%s" not found: the current service locator %s', $id, $message);
        }
        return new class($message) extends \InvalidArgumentException implements NotFoundExceptionInterface
        {
        };
    }
    private function createCircularReferenceException(string $id, array $path) : ContainerExceptionInterface
    {
        return new class(\sprintf('Circular reference detected for service "%s", path: "%s".', $id, \implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface
        {
        };
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Contracts\Service;

use CivixPhar\Psr\Container\ContainerInterface;
/**
 * A ServiceProviderInterface exposes the identifiers and the types of services provided by a container.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 * @author Mateusz Sip <mateusz.sip@gmail.com>
 */
interface ServiceProviderInterface extends ContainerInterface
{
    /**
     * Returns an associative array of service types keyed by the identifiers provided by the current container.
     *
     * Examples:
     *
     *  * ['logger' => 'Psr\Log\LoggerInterface'] means the object provides a service named "logger" that implements Psr\Log\LoggerInterface
     *  * ['foo' => '?'] means the container provides service name "foo" of unspecified type
     *  * ['bar' => '?Bar\Baz'] means the container provides a service "bar" of type Bar\Baz|null
     *
     * @return string[] The provided service types, keyed by service names
     */
    public function getProvidedServices() : array;
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Templating;

/**
 * TemplateNameParserInterface converts template names to TemplateReferenceInterface
 * instances.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
interface TemplateNameParserInterface
{
    /**
     * Convert a template name to a TemplateReferenceInterface instance.
     *
     * @param string|TemplateReferenceInterface $name A template name or a TemplateReferenceInterface instance
     *
     * @return TemplateReferenceInterface A template
     */
    public function parse($name);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Templating;

/**
 * StreamingEngineInterface provides a method that knows how to stream a template.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
interface StreamingEngineInterface
{
    /**
     * Streams a template.
     *
     * The implementation should output the content directly to the client.
     *
     * @param string|TemplateReferenceInterface $name       A template name or a TemplateReferenceInterface instance
     * @param array                             $parameters An array of parameters to pass to the template
     *
     * @throws \RuntimeException if the template cannot be rendered
     * @throws \LogicException   if the template cannot be streamed
     */
    public function stream($name, array $parameters = []);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Templating;

/**
 * Interface to be implemented by all templates.
 *
 * @author Victor Berchet <victor@suumit.com>
 */
interface TemplateReferenceInterface
{
    /**
     * Gets the template parameters.
     *
     * @return array An array of parameters
     */
    public function all();
    /**
     * Sets a template parameter.
     *
     * @param string $name  The parameter name
     * @param string $value The parameter value
     *
     * @return $this
     *
     * @throws \InvalidArgumentException if the parameter name is not supported
     */
    public function set($name, $value);
    /**
     * Gets a template parameter.
     *
     * @param string $name The parameter name
     *
     * @return string The parameter value
     *
     * @throws \InvalidArgumentException if the parameter name is not supported
     */
    public function get($name);
    /**
     * Returns the path to the template.
     *
     * By default, it just returns the template name.
     *
     * @return string A path to the template or a resource
     */
    public function getPath();
    /**
     * Returns the "logical" template name.
     *
     * The template name acts as a unique identifier for the template.
     *
     * @return string The template name
     */
    public function getLogicalName();
    /**
     * Returns the string representation as shortcut for getLogicalName().
     *
     * Alias of getLogicalName().
     *
     * @return string The template name
     */
    public function __toString();
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Templating;

/**
 * TemplateNameParser is the default implementation of TemplateNameParserInterface.
 *
 * This implementation takes everything as the template name
 * and the extension for the engine.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class TemplateNameParser implements TemplateNameParserInterface
{
    /**
     * {@inheritdoc}
     */
    public function parse($name)
    {
        if ($name instanceof TemplateReferenceInterface) {
            return $name;
        }
        $engine = null;
        if (\false !== ($pos = \strrpos($name, '.'))) {
            $engine = \substr($name, $pos + 1);
        }
        return new TemplateReference($name, $engine);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Templating\Loader;

use CivixPhar\Symfony\Component\Templating\Storage\FileStorage;
use CivixPhar\Symfony\Component\Templating\TemplateReferenceInterface;
/**
 * FilesystemLoader is a loader that read templates from the filesystem.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class FilesystemLoader extends Loader
{
    protected $templatePathPatterns;
    /**
     * @param string|string[] $templatePathPatterns An array of path patterns to look for templates
     */
    public function __construct($templatePathPatterns)
    {
        $this->templatePathPatterns = (array) $templatePathPatterns;
    }
    /**
     * {@inheritdoc}
     */
    public function load(TemplateReferenceInterface $template)
    {
        $file = $template->get('name');
        if (self::isAbsolutePath($file) && \is_file($file)) {
            return new FileStorage($file);
        }
        $replacements = [];
        foreach ($template->all() as $key => $value) {
            $replacements['%' . $key . '%'] = $value;
        }
        $fileFailures = [];
        foreach ($this->templatePathPatterns as $templatePathPattern) {
            if (\is_file($file = \strtr($templatePathPattern, $replacements)) && \is_readable($file)) {
                if (null !== $this->logger) {
                    $this->logger->debug('Loaded template file.', ['file' => $file]);
                }
                return new FileStorage($file);
            }
            if (null !== $this->logger) {
                $fileFailures[] = $file;
            }
        }
        // only log failures if no template could be loaded at all
        foreach ($fileFailures as $file) {
            if (null !== $this->logger) {
                $this->logger->debug('Failed loading template file.', ['file' => $file]);
            }
        }
        return \false;
    }
    /**
     * {@inheritdoc}
     */
    public function isFresh(TemplateReferenceInterface $template, $time)
    {
        if (\false === ($storage = $this->load($template))) {
            return \false;
        }
        return \filemtime((string) $storage) < $time;
    }
    /**
     * Returns true if the file is an existing absolute path.
     *
     * @param string $file A path
     *
     * @return bool true if the path exists and is absolute, false otherwise
     */
    protected static function isAbsolutePath($file)
    {
        if ('/' == $file[0] || '\\' == $file[0] || \strlen($file) > 3 && \ctype_alpha($file[0]) && ':' == $file[1] && ('\\' == $file[2] || '/' == $file[2]) || null !== \parse_url($file, \PHP_URL_SCHEME)) {
            return \true;
        }
        return \false;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Templating\Loader;

use CivixPhar\Symfony\Component\Templating\TemplateReferenceInterface;
/**
 * ChainLoader is a loader that calls other loaders to load templates.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class ChainLoader extends Loader
{
    protected $loaders = [];
    /**
     * @param LoaderInterface[] $loaders
     */
    public function __construct(array $loaders = [])
    {
        foreach ($loaders as $loader) {
            $this->addLoader($loader);
        }
    }
    public function addLoader(LoaderInterface $loader)
    {
        $this->loaders[] = $loader;
    }
    /**
     * {@inheritdoc}
     */
    public function load(TemplateReferenceInterface $template)
    {
        foreach ($this->loaders as $loader) {
            if (\false !== ($storage = $loader->load($template))) {
                return $storage;
            }
        }
        return \false;
    }
    /**
     * {@inheritdoc}
     */
    public function isFresh(TemplateReferenceInterface $template, $time)
    {
        foreach ($this->loaders as $loader) {
            return $loader->isFresh($template, $time);
        }
        return \false;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Templating\Loader;

use CivixPhar\Psr\Log\LoggerInterface;
/**
 * Loader is the base class for all template loader classes.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
abstract class Loader implements LoaderInterface
{
    /**
     * @var LoggerInterface|null
     */
    protected $logger;
    /**
     * Sets the debug logger to use for this loader.
     */
    public function setLogger(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Templating\Loader;

use CivixPhar\Symfony\Component\Templating\Storage\Storage;
use CivixPhar\Symfony\Component\Templating\TemplateReferenceInterface;
/**
 * LoaderInterface is the interface all loaders must implement.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
interface LoaderInterface
{
    /**
     * Loads a template.
     *
     * @return Storage|false false if the template cannot be loaded, a Storage instance otherwise
     */
    public function load(TemplateReferenceInterface $template);
    /**
     * Returns true if the template is still fresh.
     *
     * @param int $time The last modification time of the cached template (timestamp)
     *
     * @return bool
     */
    public function isFresh(TemplateReferenceInterface $template, $time);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Templating\Loader;

use CivixPhar\Symfony\Component\Templating\Storage\FileStorage;
use CivixPhar\Symfony\Component\Templating\TemplateReferenceInterface;
/**
 * CacheLoader is a loader that caches other loaders responses
 * on the filesystem.
 *
 * This cache only caches on disk to allow PHP accelerators to cache the opcodes.
 * All other mechanism would imply the use of `eval()`.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class CacheLoader extends Loader
{
    protected $loader;
    protected $dir;
    /**
     * @param string $dir The directory where to store the cache files
     */
    public function __construct(LoaderInterface $loader, string $dir)
    {
        $this->loader = $loader;
        $this->dir = $dir;
    }
    /**
     * {@inheritdoc}
     */
    public function load(TemplateReferenceInterface $template)
    {
        $key = \hash('sha256', $template->getLogicalName());
        $dir = $this->dir . \DIRECTORY_SEPARATOR . \substr($key, 0, 2);
        $file = \substr($key, 2) . '.tpl';
        $path = $dir . \DIRECTORY_SEPARATOR . $file;
        if (\is_file($path)) {
            if (null !== $this->logger) {
                $this->logger->debug('Fetching template from cache.', ['name' => $template->get('name')]);
            }
            return new FileStorage($path);
        }
        if (\false === ($storage = $this->loader->load($template))) {
            return \false;
        }
        $content = $storage->getContent();
        if (!\is_dir($dir) && !@\mkdir($dir, 0777, \true) && !\is_dir($dir)) {
            throw new \RuntimeException(\sprintf('Cache Loader was not able to create directory "%s".', $dir));
        }
        \file_put_contents($path, $content);
        if (null !== $this->logger) {
            $this->logger->debug('Storing template in cache.', ['name' => $template->get('name')]);
        }
        return new FileStorage($path);
    }
    /**
     * {@inheritdoc}
     */
    public function isFresh(TemplateReferenceInterface $template, $time)
    {
        return $this->loader->isFresh($template, $time);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Templating;

use CivixPhar\Symfony\Component\Templating\Helper\HelperInterface;
use CivixPhar\Symfony\Component\Templating\Loader\LoaderInterface;
use CivixPhar\Symfony\Component\Templating\Storage\FileStorage;
use CivixPhar\Symfony\Component\Templating\Storage\Storage;
use CivixPhar\Symfony\Component\Templating\Storage\StringStorage;
/**
 * PhpEngine is an engine able to render PHP templates.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class PhpEngine implements EngineInterface, \ArrayAccess
{
    protected $loader;
    protected $current;
    /**
     * @var HelperInterface[]
     */
    protected $helpers = [];
    protected $parents = [];
    protected $stack = [];
    protected $charset = 'UTF-8';
    protected $cache = [];
    protected $escapers = [];
    protected static $escaperCache = [];
    protected $globals = [];
    protected $parser;
    private $evalTemplate;
    private $evalParameters;
    /**
     * @param HelperInterface[] $helpers An array of helper instances
     */
    public function __construct(TemplateNameParserInterface $parser, LoaderInterface $loader, array $helpers = [])
    {
        $this->parser = $parser;
        $this->loader = $loader;
        $this->addHelpers($helpers);
        $this->initializeEscapers();
        foreach ($this->escapers as $context => $escaper) {
            $this->setEscaper($context, $escaper);
        }
    }
    /**
     * {@inheritdoc}
     *
     * @throws \InvalidArgumentException if the template does not exist
     */
    public function render($name, array $parameters = [])
    {
        $storage = $this->load($name);
        $key = \hash('sha256', \serialize($storage));
        $this->current = $key;
        $this->parents[$key] = null;
        // attach the global variables
        $parameters = \array_replace($this->getGlobals(), $parameters);
        // render
        if (\false === ($content = $this->evaluate($storage, $parameters))) {
            throw new \RuntimeException(\sprintf('The template "%s" cannot be rendered.', $this->parser->parse($name)));
        }
        // decorator
        if ($this->parents[$key]) {
            $slots = $this->get('slots');
            $this->stack[] = $slots->get('_content');
            $slots->set('_content', $content);
            $content = $this->render($this->parents[$key], $parameters);
            $slots->set('_content', \array_pop($this->stack));
        }
        return $content;
    }
    /**
     * {@inheritdoc}
     */
    public function exists($name)
    {
        try {
            $this->load($name);
        } catch (\InvalidArgumentException $e) {
            return \false;
        }
        return \true;
    }
    /**
     * {@inheritdoc}
     */
    public function supports($name)
    {
        $template = $this->parser->parse($name);
        return 'php' === $template->get('engine');
    }
    /**
     * Evaluates a template.
     *
     * @param array $parameters An array of parameters to pass to the template
     *
     * @return string|false The evaluated template, or false if the engine is unable to render the template
     *
     * @throws \InvalidArgumentException
     */
    protected function evaluate(Storage $template, array $parameters = [])
    {
        $this->evalTemplate = $template;
        $this->evalParameters = $parameters;
        unset($template, $parameters);
        if (isset($this->evalParameters['this'])) {
            throw new \InvalidArgumentException('Invalid parameter (this).');
        }
        if (isset($this->evalParameters['view'])) {
            throw new \InvalidArgumentException('Invalid parameter (view).');
        }
        // the view variable is exposed to the require file below
        $view = $this;
        if ($this->evalTemplate instanceof FileStorage) {
            \extract($this->evalParameters, \EXTR_SKIP);
            $this->evalParameters = null;
            \ob_start();
            require $this->evalTemplate;
            $this->evalTemplate = null;
            return \ob_get_clean();
        } elseif ($this->evalTemplate instanceof StringStorage) {
            \extract($this->evalParameters, \EXTR_SKIP);
            $this->evalParameters = null;
            \ob_start();
            eval('; ?>' . $this->evalTemplate . '<?php ;');
            $this->evalTemplate = null;
            return \ob_get_clean();
        }
        return \false;
    }
    /**
     * Gets a helper value.
     *
     * @param string $name The helper name
     *
     * @return HelperInterface The helper value
     *
     * @throws \InvalidArgumentException if the helper is not defined
     */
    #[\ReturnTypeWillChange]
    public function offsetGet($name)
    {
        return $this->get($name);
    }
    /**
     * Returns true if the helper is defined.
     *
     * @param string $name The helper name
     *
     * @return bool true if the helper is defined, false otherwise
     */
    #[\ReturnTypeWillChange]
    public function offsetExists($name)
    {
        return isset($this->helpers[$name]);
    }
    /**
     * Sets a helper.
     *
     * @param HelperInterface $name  The helper instance
     * @param string          $value An alias
     *
     * @return void
     */
    #[\ReturnTypeWillChange]
    public function offsetSet($name, $value)
    {
        $this->set($name, $value);
    }
    /**
     * Removes a helper.
     *
     * @param string $name The helper name
     *
     * @return void
     *
     * @throws \LogicException
     */
    #[\ReturnTypeWillChange]
    public function offsetUnset($name)
    {
        throw new \LogicException(\sprintf('You can\'t unset a helper (%s).', $name));
    }
    /**
     * Adds some helpers.
     *
     * @param HelperInterface[] $helpers An array of helper
     */
    public function addHelpers(array $helpers)
    {
        foreach ($helpers as $alias => $helper) {
            $this->set($helper, \is_int($alias) ? null : $alias);
        }
    }
    /**
     * Sets the helpers.
     *
     * @param HelperInterface[] $helpers An array of helper
     */
    public function setHelpers(array $helpers)
    {
        $this->helpers = [];
        $this->addHelpers($helpers);
    }
    /**
     * Sets a helper.
     *
     * @param string $alias An alias
     */
    public function set(HelperInterface $helper, $alias = null)
    {
        $this->helpers[$helper->getName()] = $helper;
        if (null !== $alias) {
            $this->helpers[$alias] = $helper;
        }
        $helper->setCharset($this->charset);
    }
    /**
     * Returns true if the helper if defined.
     *
     * @param string $name The helper name
     *
     * @return bool true if the helper is defined, false otherwise
     */
    public function has($name)
    {
        return isset($this->helpers[$name]);
    }
    /**
     * Gets a helper value.
     *
     * @param string $name The helper name
     *
     * @return HelperInterface The helper instance
     *
     * @throws \InvalidArgumentException if the helper is not defined
     */
    public function get($name)
    {
        if (!isset($this->helpers[$name])) {
            throw new \InvalidArgumentException(\sprintf('The helper "%s" is not defined.', $name));
        }
        return $this->helpers[$name];
    }
    /**
     * Decorates the current template with another one.
     *
     * @param string $template The decorator logical name
     */
    public function extend($template)
    {
        $this->parents[$this->current] = $template;
    }
    /**
     * Escapes a string by using the current charset.
     *
     * @param mixed  $value   A variable to escape
     * @param string $context The context name
     *
     * @return mixed The escaped value
     */
    public function escape($value, $context = 'html')
    {
        if (\is_numeric($value)) {
            return $value;
        }
        // If we deal with a scalar value, we can cache the result to increase
        // the performance when the same value is escaped multiple times (e.g. loops)
        if (\is_scalar($value)) {
            if (!isset(self::$escaperCache[$context][$value])) {
                self::$escaperCache[$context][$value] = $this->getEscaper($context)($value);
            }
            return self::$escaperCache[$context][$value];
        }
        return $this->getEscaper($context)($value);
    }
    /**
     * Sets the charset to use.
     *
     * @param string $charset The charset
     */
    public function setCharset($charset)
    {
        if ('UTF8' === ($charset = \strtoupper($charset))) {
            $charset = 'UTF-8';
            // iconv on Windows requires "UTF-8" instead of "UTF8"
        }
        $this->charset = $charset;
        foreach ($this->helpers as $helper) {
            $helper->setCharset($this->charset);
        }
    }
    /**
     * Gets the current charset.
     *
     * @return string The current charset
     */
    public function getCharset()
    {
        return $this->charset;
    }
    /**
     * Adds an escaper for the given context.
     *
     * @param string   $context The escaper context (html, js, ...)
     * @param callable $escaper A PHP callable
     */
    public function setEscaper($context, callable $escaper)
    {
        $this->escapers[$context] = $escaper;
        self::$escaperCache[$context] = [];
    }
    /**
     * Gets an escaper for a given context.
     *
     * @param string $context The context name
     *
     * @return callable A PHP callable
     *
     * @throws \InvalidArgumentException
     */
    public function getEscaper($context)
    {
        if (!isset($this->escapers[$context])) {
            throw new \InvalidArgumentException(\sprintf('No registered escaper for context "%s".', $context));
        }
        return $this->escapers[$context];
    }
    /**
     * @param string $name
     * @param mixed  $value
     */
    public function addGlobal($name, $value)
    {
        $this->globals[$name] = $value;
    }
    /**
     * Returns the assigned globals.
     *
     * @return array
     */
    public function getGlobals()
    {
        return $this->globals;
    }
    /**
     * Initializes the built-in escapers.
     *
     * Each function specifies a way for applying a transformation to a string
     * passed to it. The purpose is for the string to be "escaped" so it is
     * suitable for the format it is being displayed in.
     *
     * For example, the string: "It's required that you enter a username & password.\n"
     * If this were to be displayed as HTML it would be sensible to turn the
     * ampersand into '&amp;' and the apostrophe into '&aps;'. However if it were
     * going to be used as a string in JavaScript to be displayed in an alert box
     * it would be right to leave the string as-is, but c-escape the apostrophe and
     * the new line.
     *
     * For each function there is a define to avoid problems with strings being
     * incorrectly specified.
     */
    protected function initializeEscapers()
    {
        $flags = \ENT_QUOTES | \ENT_SUBSTITUTE;
        $this->escapers = ['html' => function ($value) use($flags) {
            // Numbers and Boolean values get turned into strings which can cause problems
            // with type comparisons (e.g. === or is_int() etc).
            return \is_string($value) ? \htmlspecialchars($value, $flags, $this->getCharset(), \false) : $value;
        }, 'js' => function ($value) {
            if ('UTF-8' != $this->getCharset()) {
                $value = \iconv($this->getCharset(), 'UTF-8', $value);
            }
            $callback = function ($matches) {
                $char = $matches[0];
                // \xHH
                if (!isset($char[1])) {
                    return '\\x' . \substr('00' . \bin2hex($char), -2);
                }
                // \uHHHH
                $char = \iconv('UTF-8', 'UTF-16BE', $char);
                return '\\u' . \substr('0000' . \bin2hex($char), -4);
            };
            if (null === ($value = \preg_replace_callback('#[^\\p{L}\\p{N} ]#u', $callback, $value))) {
                throw new \InvalidArgumentException('The string to escape is not a valid UTF-8 string.');
            }
            if ('UTF-8' != $this->getCharset()) {
                $value = \iconv('UTF-8', $this->getCharset(), $value);
            }
            return $value;
        }];
        self::$escaperCache = [];
    }
    /**
     * Gets the loader associated with this engine.
     *
     * @return LoaderInterface A LoaderInterface instance
     */
    public function getLoader()
    {
        return $this->loader;
    }
    /**
     * Loads the given template.
     *
     * @param string|TemplateReferenceInterface $name A template name or a TemplateReferenceInterface instance
     *
     * @return Storage A Storage instance
     *
     * @throws \InvalidArgumentException if the template cannot be found
     */
    protected function load($name)
    {
        $template = $this->parser->parse($name);
        $key = $template->getLogicalName();
        if (isset($this->cache[$key])) {
            return $this->cache[$key];
        }
        $storage = $this->loader->load($template);
        if (\false === $storage) {
            throw new \InvalidArgumentException(\sprintf('The template "%s" does not exist.', $template));
        }
        return $this->cache[$key] = $storage;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Templating\Helper;

/**
 * SlotsHelper manages template slots.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class SlotsHelper extends Helper
{
    protected $slots = [];
    protected $openSlots = [];
    /**
     * Starts a new slot.
     *
     * This method starts an output buffer that will be
     * closed when the stop() method is called.
     *
     * @param string $name The slot name
     *
     * @throws \InvalidArgumentException if a slot with the same name is already started
     */
    public function start($name)
    {
        if (\in_array($name, $this->openSlots)) {
            throw new \InvalidArgumentException(\sprintf('A slot named "%s" is already started.', $name));
        }
        $this->openSlots[] = $name;
        $this->slots[$name] = '';
        \ob_start();
        \ob_implicit_flush(0);
    }
    /**
     * Stops a slot.
     *
     * @throws \LogicException if no slot has been started
     */
    public function stop()
    {
        if (!$this->openSlots) {
            throw new \LogicException('No slot started.');
        }
        $name = \array_pop($this->openSlots);
        $this->slots[$name] = \ob_get_clean();
    }
    /**
     * Returns true if the slot exists.
     *
     * @param string $name The slot name
     *
     * @return bool
     */
    public function has($name)
    {
        return isset($this->slots[$name]);
    }
    /**
     * Gets the slot value.
     *
     * @param string      $name    The slot name
     * @param bool|string $default The default slot content
     *
     * @return string The slot content
     */
    public function get($name, $default = \false)
    {
        return $this->slots[$name] ?? $default;
    }
    /**
     * Sets a slot value.
     *
     * @param string $name    The slot name
     * @param string $content The slot content
     */
    public function set($name, $content)
    {
        $this->slots[$name] = $content;
    }
    /**
     * Outputs a slot.
     *
     * @param string      $name    The slot name
     * @param bool|string $default The default slot content
     *
     * @return bool true if the slot is defined or if a default content has been provided, false otherwise
     */
    public function output($name, $default = \false)
    {
        if (!isset($this->slots[$name])) {
            if (\false !== $default) {
                echo $default;
                return \true;
            }
            return \false;
        }
        echo $this->slots[$name];
        return \true;
    }
    /**
     * Returns the canonical name of this helper.
     *
     * @return string The canonical name
     */
    public function getName()
    {
        return 'slots';
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Templating\Helper;

/**
 * HelperInterface is the interface all helpers must implement.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
interface HelperInterface
{
    /**
     * Returns the canonical name of this helper.
     *
     * @return string The canonical name
     */
    public function getName();
    /**
     * Sets the default charset.
     *
     * @param string $charset The charset
     */
    public function setCharset($charset);
    /**
     * Gets the default charset.
     *
     * @return string The default charset
     */
    public function getCharset();
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Templating\Helper;

/**
 * Helper is the base class for all helper classes.
 *
 * Most of the time, a Helper is an adapter around an existing
 * class that exposes a read-only interface for templates.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
abstract class Helper implements HelperInterface
{
    protected $charset = 'UTF-8';
    /**
     * Sets the default charset.
     *
     * @param string $charset The charset
     */
    public function setCharset($charset)
    {
        $this->charset = $charset;
    }
    /**
     * Gets the default charset.
     *
     * @return string The default charset
     */
    public function getCharset()
    {
        return $this->charset;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Templating;

/**
 * DelegatingEngine selects an engine for a given template.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class DelegatingEngine implements EngineInterface, StreamingEngineInterface
{
    /**
     * @var EngineInterface[]
     */
    protected $engines = [];
    /**
     * @param EngineInterface[] $engines An array of EngineInterface instances to add
     */
    public function __construct(array $engines = [])
    {
        foreach ($engines as $engine) {
            $this->addEngine($engine);
        }
    }
    /**
     * {@inheritdoc}
     */
    public function render($name, array $parameters = [])
    {
        return $this->getEngine($name)->render($name, $parameters);
    }
    /**
     * {@inheritdoc}
     */
    public function stream($name, array $parameters = [])
    {
        $engine = $this->getEngine($name);
        if (!$engine instanceof StreamingEngineInterface) {
            throw new \LogicException(\sprintf('Template "%s" cannot be streamed as the engine supporting it does not implement StreamingEngineInterface.', $name));
        }
        $engine->stream($name, $parameters);
    }
    /**
     * {@inheritdoc}
     */
    public function exists($name)
    {
        return $this->getEngine($name)->exists($name);
    }
    public function addEngine(EngineInterface $engine)
    {
        $this->engines[] = $engine;
    }
    /**
     * {@inheritdoc}
     */
    public function supports($name)
    {
        try {
            $this->getEngine($name);
        } catch (\RuntimeException $e) {
            return \false;
        }
        return \true;
    }
    /**
     * Get an engine able to render the given template.
     *
     * @param string|TemplateReferenceInterface $name A template name or a TemplateReferenceInterface instance
     *
     * @return EngineInterface The engine
     *
     * @throws \RuntimeException if no engine able to work with the template is found
     */
    public function getEngine($name)
    {
        foreach ($this->engines as $engine) {
            if ($engine->supports($name)) {
                return $engine;
            }
        }
        throw new \RuntimeException(\sprintf('No engine is able to work with the template "%s".', $name));
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Templating;

/**
 * Internal representation of a template.
 *
 * @author Victor Berchet <victor@suumit.com>
 */
class TemplateReference implements TemplateReferenceInterface
{
    protected $parameters;
    public function __construct(string $name = null, string $engine = null)
    {
        $this->parameters = ['name' => $name, 'engine' => $engine];
    }
    /**
     * {@inheritdoc}
     */
    public function __toString()
    {
        return $this->getLogicalName();
    }
    /**
     * {@inheritdoc}
     */
    public function set($name, $value)
    {
        if (\array_key_exists($name, $this->parameters)) {
            $this->parameters[$name] = $value;
        } else {
            throw new \InvalidArgumentException(\sprintf('The template does not support the "%s" parameter.', $name));
        }
        return $this;
    }
    /**
     * {@inheritdoc}
     */
    public function get($name)
    {
        if (\array_key_exists($name, $this->parameters)) {
            return $this->parameters[$name];
        }
        throw new \InvalidArgumentException(\sprintf('The template does not support the "%s" parameter.', $name));
    }
    /**
     * {@inheritdoc}
     */
    public function all()
    {
        return $this->parameters;
    }
    /**
     * {@inheritdoc}
     */
    public function getPath()
    {
        return $this->parameters['name'];
    }
    /**
     * {@inheritdoc}
     */
    public function getLogicalName()
    {
        return $this->parameters['name'];
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Templating;

/**
 * EngineInterface is the interface each engine must implement.
 *
 * All methods rely on a template name. A template name is a
 * "logical" name for the template, and as such it does not refer to
 * a path on the filesystem (in fact, the template can be stored
 * anywhere, like in a database).
 *
 * The methods should accept any name. If the name is not an instance of
 * TemplateReferenceInterface, a TemplateNameParserInterface should be used to
 * convert the name to a TemplateReferenceInterface instance.
 *
 * Each template loader uses the logical template name to look for
 * the template.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
interface EngineInterface
{
    /**
     * Renders a template.
     *
     * @param string|TemplateReferenceInterface $name       A template name or a TemplateReferenceInterface instance
     * @param array                             $parameters An array of parameters to pass to the template
     *
     * @return string The evaluated template as a string
     *
     * @throws \RuntimeException if the template cannot be rendered
     */
    public function render($name, array $parameters = []);
    /**
     * Returns true if the template exists.
     *
     * @param string|TemplateReferenceInterface $name A template name or a TemplateReferenceInterface instance
     *
     * @return bool true if the template exists, false otherwise
     *
     * @throws \RuntimeException if the engine cannot handle the template name
     */
    public function exists($name);
    /**
     * Returns true if this class is able to render the given template.
     *
     * @param string|TemplateReferenceInterface $name A template name or a TemplateReferenceInterface instance
     *
     * @return bool true if this class supports the given template, false otherwise
     */
    public function supports($name);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Templating\Storage;

/**
 * StringStorage represents a template stored in a string.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class StringStorage extends Storage
{
    /**
     * Returns the content of the template.
     *
     * @return string The template content
     */
    public function getContent()
    {
        return $this->template;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Templating\Storage;

/**
 * FileStorage represents a template stored on the filesystem.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class FileStorage extends Storage
{
    /**
     * Returns the content of the template.
     *
     * @return string The template content
     */
    public function getContent()
    {
        return \file_get_contents($this->template);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Templating\Storage;

/**
 * Storage is the base class for all storage classes.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
abstract class Storage
{
    protected $template;
    /**
     * @param string $template The template name
     */
    public function __construct(string $template)
    {
        $this->template = $template;
    }
    /**
     * Returns the object string representation.
     *
     * @return string The template name
     */
    public function __toString()
    {
        return (string) $this->template;
    }
    /**
     * Returns the content of the template.
     *
     * @return string The template content
     */
    public abstract function getContent();
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Question;

use CivixPhar\Symfony\Component\Console\Exception\InvalidArgumentException;
use CivixPhar\Symfony\Component\Console\Exception\LogicException;
/**
 * Represents a Question.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class Question
{
    private $question;
    private $attempts;
    private $hidden = \false;
    private $hiddenFallback = \true;
    private $autocompleterCallback;
    private $validator;
    private $default;
    private $normalizer;
    private $trimmable = \true;
    /**
     * @param string                     $question The question to ask to the user
     * @param string|bool|int|float|null $default  The default answer to return if the user enters nothing
     */
    public function __construct(string $question, $default = null)
    {
        $this->question = $question;
        $this->default = $default;
    }
    /**
     * Returns the question.
     *
     * @return string
     */
    public function getQuestion()
    {
        return $this->question;
    }
    /**
     * Returns the default answer.
     *
     * @return string|bool|int|float|null
     */
    public function getDefault()
    {
        return $this->default;
    }
    /**
     * Returns whether the user response must be hidden.
     *
     * @return bool
     */
    public function isHidden()
    {
        return $this->hidden;
    }
    /**
     * Sets whether the user response must be hidden or not.
     *
     * @param bool $hidden
     *
     * @return $this
     *
     * @throws LogicException In case the autocompleter is also used
     */
    public function setHidden($hidden)
    {
        if ($this->autocompleterCallback) {
            throw new LogicException('A hidden question cannot use the autocompleter.');
        }
        $this->hidden = (bool) $hidden;
        return $this;
    }
    /**
     * In case the response can not be hidden, whether to fallback on non-hidden question or not.
     *
     * @return bool
     */
    public function isHiddenFallback()
    {
        return $this->hiddenFallback;
    }
    /**
     * Sets whether to fallback on non-hidden question if the response can not be hidden.
     *
     * @param bool $fallback
     *
     * @return $this
     */
    public function setHiddenFallback($fallback)
    {
        $this->hiddenFallback = (bool) $fallback;
        return $this;
    }
    /**
     * Gets values for the autocompleter.
     *
     * @return iterable|null
     */
    public function getAutocompleterValues()
    {
        $callback = $this->getAutocompleterCallback();
        return $callback ? $callback('') : null;
    }
    /**
     * Sets values for the autocompleter.
     *
     * @param iterable|null $values
     *
     * @return $this
     *
     * @throws InvalidArgumentException
     * @throws LogicException
     */
    public function setAutocompleterValues($values)
    {
        if (\is_array($values)) {
            $values = $this->isAssoc($values) ? \array_merge(\array_keys($values), \array_values($values)) : \array_values($values);
            $callback = static function () use($values) {
                return $values;
            };
        } elseif ($values instanceof \Traversable) {
            $valueCache = null;
            $callback = static function () use($values, &$valueCache) {
                return $valueCache ?? ($valueCache = \iterator_to_array($values, \false));
            };
        } elseif (null === $values) {
            $callback = null;
        } else {
            throw new InvalidArgumentException('Autocompleter values can be either an array, "null" or a "Traversable" object.');
        }
        return $this->setAutocompleterCallback($callback);
    }
    /**
     * Gets the callback function used for the autocompleter.
     */
    public function getAutocompleterCallback() : ?callable
    {
        return $this->autocompleterCallback;
    }
    /**
     * Sets the callback function used for the autocompleter.
     *
     * The callback is passed the user input as argument and should return an iterable of corresponding suggestions.
     *
     * @return $this
     */
    public function setAutocompleterCallback(callable $callback = null) : self
    {
        if ($this->hidden && null !== $callback) {
            throw new LogicException('A hidden question cannot use the autocompleter.');
        }
        $this->autocompleterCallback = $callback;
        return $this;
    }
    /**
     * Sets a validator for the question.
     *
     * @return $this
     */
    public function setValidator(callable $validator = null)
    {
        $this->validator = $validator;
        return $this;
    }
    /**
     * Gets the validator for the question.
     *
     * @return callable|null
     */
    public function getValidator()
    {
        return $this->validator;
    }
    /**
     * Sets the maximum number of attempts.
     *
     * Null means an unlimited number of attempts.
     *
     * @param int|null $attempts
     *
     * @return $this
     *
     * @throws InvalidArgumentException in case the number of attempts is invalid
     */
    public function setMaxAttempts($attempts)
    {
        if (null !== $attempts) {
            $attempts = (int) $attempts;
            if ($attempts < 1) {
                throw new InvalidArgumentException('Maximum number of attempts must be a positive value.');
            }
        }
        $this->attempts = $attempts;
        return $this;
    }
    /**
     * Gets the maximum number of attempts.
     *
     * Null means an unlimited number of attempts.
     *
     * @return int|null
     */
    public function getMaxAttempts()
    {
        return $this->attempts;
    }
    /**
     * Sets a normalizer for the response.
     *
     * The normalizer can be a callable (a string), a closure or a class implementing __invoke.
     *
     * @return $this
     */
    public function setNormalizer(callable $normalizer)
    {
        $this->normalizer = $normalizer;
        return $this;
    }
    /**
     * Gets the normalizer for the response.
     *
     * The normalizer can ba a callable (a string), a closure or a class implementing __invoke.
     *
     * @return callable|null
     */
    public function getNormalizer()
    {
        return $this->normalizer;
    }
    protected function isAssoc($array)
    {
        return (bool) \count(\array_filter(\array_keys($array), 'is_string'));
    }
    public function isTrimmable() : bool
    {
        return $this->trimmable;
    }
    /**
     * @return $this
     */
    public function setTrimmable(bool $trimmable) : self
    {
        $this->trimmable = $trimmable;
        return $this;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Question;

use CivixPhar\Symfony\Component\Console\Exception\InvalidArgumentException;
/**
 * Represents a choice question.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class ChoiceQuestion extends Question
{
    private $choices;
    private $multiselect = \false;
    private $prompt = ' > ';
    private $errorMessage = 'Value "%s" is invalid';
    /**
     * @param string $question The question to ask to the user
     * @param array  $choices  The list of available choices
     * @param mixed  $default  The default answer to return
     */
    public function __construct(string $question, array $choices, $default = null)
    {
        if (!$choices) {
            throw new \LogicException('Choice question must have at least 1 choice available.');
        }
        parent::__construct($question, $default);
        $this->choices = $choices;
        $this->setValidator($this->getDefaultValidator());
        $this->setAutocompleterValues($choices);
    }
    /**
     * Returns available choices.
     *
     * @return array
     */
    public function getChoices()
    {
        return $this->choices;
    }
    /**
     * Sets multiselect option.
     *
     * When multiselect is set to true, multiple choices can be answered.
     *
     * @param bool $multiselect
     *
     * @return $this
     */
    public function setMultiselect($multiselect)
    {
        $this->multiselect = $multiselect;
        $this->setValidator($this->getDefaultValidator());
        return $this;
    }
    /**
     * Returns whether the choices are multiselect.
     *
     * @return bool
     */
    public function isMultiselect()
    {
        return $this->multiselect;
    }
    /**
     * Gets the prompt for choices.
     *
     * @return string
     */
    public function getPrompt()
    {
        return $this->prompt;
    }
    /**
     * Sets the prompt for choices.
     *
     * @param string $prompt
     *
     * @return $this
     */
    public function setPrompt($prompt)
    {
        $this->prompt = $prompt;
        return $this;
    }
    /**
     * Sets the error message for invalid values.
     *
     * The error message has a string placeholder (%s) for the invalid value.
     *
     * @param string $errorMessage
     *
     * @return $this
     */
    public function setErrorMessage($errorMessage)
    {
        $this->errorMessage = $errorMessage;
        $this->setValidator($this->getDefaultValidator());
        return $this;
    }
    private function getDefaultValidator() : callable
    {
        $choices = $this->choices;
        $errorMessage = $this->errorMessage;
        $multiselect = $this->multiselect;
        $isAssoc = $this->isAssoc($choices);
        return function ($selected) use($choices, $errorMessage, $multiselect, $isAssoc) {
            if ($multiselect) {
                // Check for a separated comma values
                if (!\preg_match('/^[^,]+(?:,[^,]+)*$/', $selected, $matches)) {
                    throw new InvalidArgumentException(\sprintf($errorMessage, $selected));
                }
                $selectedChoices = \explode(',', $selected);
            } else {
                $selectedChoices = [$selected];
            }
            if ($this->isTrimmable()) {
                foreach ($selectedChoices as $k => $v) {
                    $selectedChoices[$k] = \trim($v);
                }
            }
            $multiselectChoices = [];
            foreach ($selectedChoices as $value) {
                $results = [];
                foreach ($choices as $key => $choice) {
                    if ($choice === $value) {
                        $results[] = $key;
                    }
                }
                if (\count($results) > 1) {
                    throw new InvalidArgumentException(\sprintf('The provided answer is ambiguous. Value should be one of "%s".', \implode('" or "', $results)));
                }
                $result = \array_search($value, $choices);
                if (!$isAssoc) {
                    if (\false !== $result) {
                        $result = $choices[$result];
                    } elseif (isset($choices[$value])) {
                        $result = $choices[$value];
                    }
                } elseif (\false === $result && isset($choices[$value])) {
                    $result = $value;
                }
                if (\false === $result) {
                    throw new InvalidArgumentException(\sprintf($errorMessage, $value));
                }
                $multiselectChoices[] = (string) $result;
            }
            if ($multiselect) {
                return $multiselectChoices;
            }
            return \current($multiselectChoices);
        };
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Question;

/**
 * Represents a yes/no question.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class ConfirmationQuestion extends Question
{
    private $trueAnswerRegex;
    /**
     * @param string $question        The question to ask to the user
     * @param bool   $default         The default answer to return, true or false
     * @param string $trueAnswerRegex A regex to match the "yes" answer
     */
    public function __construct(string $question, bool $default = \true, string $trueAnswerRegex = '/^y/i')
    {
        parent::__construct($question, $default);
        $this->trueAnswerRegex = $trueAnswerRegex;
        $this->setNormalizer($this->getDefaultNormalizer());
    }
    /**
     * Returns the default answer normalizer.
     */
    private function getDefaultNormalizer() : callable
    {
        $default = $this->getDefault();
        $regex = $this->trueAnswerRegex;
        return function ($answer) use($default, $regex) {
            if (\is_bool($answer)) {
                return $answer;
            }
            $answerIsTrue = (bool) \preg_match($regex, $answer);
            if (\false === $default) {
                return $answer && $answerIsTrue;
            }
            return '' === $answer || $answerIsTrue;
        };
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\EventListener;

use CivixPhar\Psr\Log\LoggerInterface;
use CivixPhar\Symfony\Component\Console\ConsoleEvents;
use CivixPhar\Symfony\Component\Console\Event\ConsoleErrorEvent;
use CivixPhar\Symfony\Component\Console\Event\ConsoleEvent;
use CivixPhar\Symfony\Component\Console\Event\ConsoleTerminateEvent;
use CivixPhar\Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
 * @author James Halsall <james.t.halsall@googlemail.com>
 * @author Robin Chalas <robin.chalas@gmail.com>
 */
class ErrorListener implements EventSubscriberInterface
{
    private $logger;
    public function __construct(LoggerInterface $logger = null)
    {
        $this->logger = $logger;
    }
    public function onConsoleError(ConsoleErrorEvent $event)
    {
        if (null === $this->logger) {
            return;
        }
        $error = $event->getError();
        if (!($inputString = $this->getInputString($event))) {
            $this->logger->critical('An error occurred while using the console. Message: "{message}"', ['exception' => $error, 'message' => $error->getMessage()]);
            return;
        }
        $this->logger->critical('Error thrown while running command "{command}". Message: "{message}"', ['exception' => $error, 'command' => $inputString, 'message' => $error->getMessage()]);
    }
    public function onConsoleTerminate(ConsoleTerminateEvent $event)
    {
        if (null === $this->logger) {
            return;
        }
        $exitCode = $event->getExitCode();
        if (0 === $exitCode) {
            return;
        }
        if (!($inputString = $this->getInputString($event))) {
            $this->logger->debug('The console exited with code "{code}"', ['code' => $exitCode]);
            return;
        }
        $this->logger->debug('Command "{command}" exited with code "{code}"', ['command' => $inputString, 'code' => $exitCode]);
    }
    public static function getSubscribedEvents()
    {
        return [ConsoleEvents::ERROR => ['onConsoleError', -128], ConsoleEvents::TERMINATE => ['onConsoleTerminate', -128]];
    }
    private static function getInputString(ConsoleEvent $event) : ?string
    {
        $commandName = $event->getCommand() ? $event->getCommand()->getName() : null;
        $input = $event->getInput();
        if (\method_exists($input, '__toString')) {
            if ($commandName) {
                return \str_replace(["'{$commandName}'", "\"{$commandName}\""], $commandName, (string) $input);
            }
            return (string) $input;
        }
        return $commandName;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Descriptor;

use CivixPhar\Symfony\Component\Console\Application;
use CivixPhar\Symfony\Component\Console\Command\Command;
use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputDefinition;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
/**
 * JSON descriptor.
 *
 * @author Jean-FranÃ§ois Simon <contact@jfsimon.fr>
 *
 * @internal
 */
class JsonDescriptor extends Descriptor
{
    /**
     * {@inheritdoc}
     */
    protected function describeInputArgument(InputArgument $argument, array $options = [])
    {
        $this->writeData($this->getInputArgumentData($argument), $options);
    }
    /**
     * {@inheritdoc}
     */
    protected function describeInputOption(InputOption $option, array $options = [])
    {
        $this->writeData($this->getInputOptionData($option), $options);
    }
    /**
     * {@inheritdoc}
     */
    protected function describeInputDefinition(InputDefinition $definition, array $options = [])
    {
        $this->writeData($this->getInputDefinitionData($definition), $options);
    }
    /**
     * {@inheritdoc}
     */
    protected function describeCommand(Command $command, array $options = [])
    {
        $this->writeData($this->getCommandData($command), $options);
    }
    /**
     * {@inheritdoc}
     */
    protected function describeApplication(Application $application, array $options = [])
    {
        $describedNamespace = $options['namespace'] ?? null;
        $description = new ApplicationDescription($application, $describedNamespace, \true);
        $commands = [];
        foreach ($description->getCommands() as $command) {
            $commands[] = $this->getCommandData($command);
        }
        $data = [];
        if ('UNKNOWN' !== $application->getName()) {
            $data['application']['name'] = $application->getName();
            if ('UNKNOWN' !== $application->getVersion()) {
                $data['application']['version'] = $application->getVersion();
            }
        }
        $data['commands'] = $commands;
        if ($describedNamespace) {
            $data['namespace'] = $describedNamespace;
        } else {
            $data['namespaces'] = \array_values($description->getNamespaces());
        }
        $this->writeData($data, $options);
    }
    /**
     * Writes data as json.
     */
    private function writeData(array $data, array $options)
    {
        $flags = $options['json_encoding'] ?? 0;
        $this->write(\json_encode($data, $flags));
    }
    private function getInputArgumentData(InputArgument $argument) : array
    {
        return ['name' => $argument->getName(), 'is_required' => $argument->isRequired(), 'is_array' => $argument->isArray(), 'description' => \preg_replace('/\\s*[\\r\\n]\\s*/', ' ', $argument->getDescription()), 'default' => \INF === $argument->getDefault() ? 'INF' : $argument->getDefault()];
    }
    private function getInputOptionData(InputOption $option) : array
    {
        return ['name' => '--' . $option->getName(), 'shortcut' => $option->getShortcut() ? '-' . \str_replace('|', '|-', $option->getShortcut()) : '', 'accept_value' => $option->acceptValue(), 'is_value_required' => $option->isValueRequired(), 'is_multiple' => $option->isArray(), 'description' => \preg_replace('/\\s*[\\r\\n]\\s*/', ' ', $option->getDescription()), 'default' => \INF === $option->getDefault() ? 'INF' : $option->getDefault()];
    }
    private function getInputDefinitionData(InputDefinition $definition) : array
    {
        $inputArguments = [];
        foreach ($definition->getArguments() as $name => $argument) {
            $inputArguments[$name] = $this->getInputArgumentData($argument);
        }
        $inputOptions = [];
        foreach ($definition->getOptions() as $name => $option) {
            $inputOptions[$name] = $this->getInputOptionData($option);
        }
        return ['arguments' => $inputArguments, 'options' => $inputOptions];
    }
    private function getCommandData(Command $command) : array
    {
        $command->getSynopsis();
        $command->mergeApplicationDefinition(\false);
        return ['name' => $command->getName(), 'usage' => \array_merge([$command->getSynopsis()], $command->getUsages(), $command->getAliases()), 'description' => $command->getDescription(), 'help' => $command->getProcessedHelp(), 'definition' => $this->getInputDefinitionData($command->getNativeDefinition()), 'hidden' => $command->isHidden()];
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Descriptor;

use CivixPhar\Symfony\Component\Console\Application;
use CivixPhar\Symfony\Component\Console\Command\Command;
use CivixPhar\Symfony\Component\Console\Exception\CommandNotFoundException;
/**
 * @author Jean-FranÃ§ois Simon <jeanfrancois.simon@sensiolabs.com>
 *
 * @internal
 */
class ApplicationDescription
{
    public const GLOBAL_NAMESPACE = '_global';
    private $application;
    private $namespace;
    private $showHidden;
    /**
     * @var array
     */
    private $namespaces;
    /**
     * @var Command[]
     */
    private $commands;
    /**
     * @var Command[]
     */
    private $aliases;
    public function __construct(Application $application, string $namespace = null, bool $showHidden = \false)
    {
        $this->application = $application;
        $this->namespace = $namespace;
        $this->showHidden = $showHidden;
    }
    public function getNamespaces() : array
    {
        if (null === $this->namespaces) {
            $this->inspectApplication();
        }
        return $this->namespaces;
    }
    /**
     * @return Command[]
     */
    public function getCommands() : array
    {
        if (null === $this->commands) {
            $this->inspectApplication();
        }
        return $this->commands;
    }
    /**
     * @throws CommandNotFoundException
     */
    public function getCommand(string $name) : Command
    {
        if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) {
            throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name));
        }
        return $this->commands[$name] ?? $this->aliases[$name];
    }
    private function inspectApplication()
    {
        $this->commands = [];
        $this->namespaces = [];
        $all = $this->application->all($this->namespace ? $this->application->findNamespace($this->namespace) : null);
        foreach ($this->sortCommands($all) as $namespace => $commands) {
            $names = [];
            /** @var Command $command */
            foreach ($commands as $name => $command) {
                if (!$command->getName() || !$this->showHidden && $command->isHidden()) {
                    continue;
                }
                if ($command->getName() === $name) {
                    $this->commands[$name] = $command;
                } else {
                    $this->aliases[$name] = $command;
                }
                $names[] = $name;
            }
            $this->namespaces[$namespace] = ['id' => $namespace, 'commands' => $names];
        }
    }
    private function sortCommands(array $commands) : array
    {
        $namespacedCommands = [];
        $globalCommands = [];
        $sortedCommands = [];
        foreach ($commands as $name => $command) {
            $key = $this->application->extractNamespace($name, 1);
            if (\in_array($key, ['', self::GLOBAL_NAMESPACE], \true)) {
                $globalCommands[$name] = $command;
            } else {
                $namespacedCommands[$key][$name] = $command;
            }
        }
        if ($globalCommands) {
            \ksort($globalCommands);
            $sortedCommands[self::GLOBAL_NAMESPACE] = $globalCommands;
        }
        if ($namespacedCommands) {
            \ksort($namespacedCommands);
            foreach ($namespacedCommands as $key => $commandsSet) {
                \ksort($commandsSet);
                $sortedCommands[$key] = $commandsSet;
            }
        }
        return $sortedCommands;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Descriptor;

use CivixPhar\Symfony\Component\Console\Application;
use CivixPhar\Symfony\Component\Console\Command\Command;
use CivixPhar\Symfony\Component\Console\Helper\Helper;
use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputDefinition;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
/**
 * Markdown descriptor.
 *
 * @author Jean-FranÃ§ois Simon <contact@jfsimon.fr>
 *
 * @internal
 */
class MarkdownDescriptor extends Descriptor
{
    /**
     * {@inheritdoc}
     */
    public function describe(OutputInterface $output, $object, array $options = [])
    {
        $decorated = $output->isDecorated();
        $output->setDecorated(\false);
        parent::describe($output, $object, $options);
        $output->setDecorated($decorated);
    }
    /**
     * {@inheritdoc}
     */
    protected function write($content, $decorated = \true)
    {
        parent::write($content, $decorated);
    }
    /**
     * {@inheritdoc}
     */
    protected function describeInputArgument(InputArgument $argument, array $options = [])
    {
        $this->write('#### `' . ($argument->getName() ?: '<none>') . "`\n\n" . ($argument->getDescription() ? \preg_replace('/\\s*[\\r\\n]\\s*/', "\n", $argument->getDescription()) . "\n\n" : '') . '* Is required: ' . ($argument->isRequired() ? 'yes' : 'no') . "\n" . '* Is array: ' . ($argument->isArray() ? 'yes' : 'no') . "\n" . '* Default: `' . \str_replace("\n", '', \var_export($argument->getDefault(), \true)) . '`');
    }
    /**
     * {@inheritdoc}
     */
    protected function describeInputOption(InputOption $option, array $options = [])
    {
        $name = '--' . $option->getName();
        if ($option->getShortcut()) {
            $name .= '|-' . \str_replace('|', '|-', $option->getShortcut()) . '';
        }
        $this->write('#### `' . $name . '`' . "\n\n" . ($option->getDescription() ? \preg_replace('/\\s*[\\r\\n]\\s*/', "\n", $option->getDescription()) . "\n\n" : '') . '* Accept value: ' . ($option->acceptValue() ? 'yes' : 'no') . "\n" . '* Is value required: ' . ($option->isValueRequired() ? 'yes' : 'no') . "\n" . '* Is multiple: ' . ($option->isArray() ? 'yes' : 'no') . "\n" . '* Default: `' . \str_replace("\n", '', \var_export($option->getDefault(), \true)) . '`');
    }
    /**
     * {@inheritdoc}
     */
    protected function describeInputDefinition(InputDefinition $definition, array $options = [])
    {
        if ($showArguments = \count($definition->getArguments()) > 0) {
            $this->write('### Arguments');
            foreach ($definition->getArguments() as $argument) {
                $this->write("\n\n");
                $this->write($this->describeInputArgument($argument));
            }
        }
        if (\count($definition->getOptions()) > 0) {
            if ($showArguments) {
                $this->write("\n\n");
            }
            $this->write('### Options');
            foreach ($definition->getOptions() as $option) {
                $this->write("\n\n");
                $this->write($this->describeInputOption($option));
            }
        }
    }
    /**
     * {@inheritdoc}
     */
    protected function describeCommand(Command $command, array $options = [])
    {
        $command->getSynopsis();
        $command->mergeApplicationDefinition(\false);
        $this->write('`' . $command->getName() . "`\n" . \str_repeat('-', Helper::strlen($command->getName()) + 2) . "\n\n" . ($command->getDescription() ? $command->getDescription() . "\n\n" : '') . '### Usage' . "\n\n" . \array_reduce(\array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), function ($carry, $usage) {
            return $carry . '* `' . $usage . '`' . "\n";
        }));
        if ($help = $command->getProcessedHelp()) {
            $this->write("\n");
            $this->write($help);
        }
        if ($command->getNativeDefinition()) {
            $this->write("\n\n");
            $this->describeInputDefinition($command->getNativeDefinition());
        }
    }
    /**
     * {@inheritdoc}
     */
    protected function describeApplication(Application $application, array $options = [])
    {
        $describedNamespace = $options['namespace'] ?? null;
        $description = new ApplicationDescription($application, $describedNamespace);
        $title = $this->getApplicationTitle($application);
        $this->write($title . "\n" . \str_repeat('=', Helper::strlen($title)));
        foreach ($description->getNamespaces() as $namespace) {
            if (ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) {
                $this->write("\n\n");
                $this->write('**' . $namespace['id'] . ':**');
            }
            $this->write("\n\n");
            $this->write(\implode("\n", \array_map(function ($commandName) use($description) {
                return \sprintf('* [`%s`](#%s)', $commandName, \str_replace(':', '', $description->getCommand($commandName)->getName()));
            }, $namespace['commands'])));
        }
        foreach ($description->getCommands() as $command) {
            $this->write("\n\n");
            $this->write($this->describeCommand($command));
        }
    }
    private function getApplicationTitle(Application $application) : string
    {
        if ('UNKNOWN' !== $application->getName()) {
            if ('UNKNOWN' !== $application->getVersion()) {
                return \sprintf('%s %s', $application->getName(), $application->getVersion());
            }
            return $application->getName();
        }
        return 'Console Tool';
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Descriptor;

use CivixPhar\Symfony\Component\Console\Application;
use CivixPhar\Symfony\Component\Console\Command\Command;
use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputDefinition;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
/**
 * XML descriptor.
 *
 * @author Jean-FranÃ§ois Simon <contact@jfsimon.fr>
 *
 * @internal
 */
class XmlDescriptor extends Descriptor
{
    public function getInputDefinitionDocument(InputDefinition $definition) : \DOMDocument
    {
        $dom = new \DOMDocument('1.0', 'UTF-8');
        $dom->appendChild($definitionXML = $dom->createElement('definition'));
        $definitionXML->appendChild($argumentsXML = $dom->createElement('arguments'));
        foreach ($definition->getArguments() as $argument) {
            $this->appendDocument($argumentsXML, $this->getInputArgumentDocument($argument));
        }
        $definitionXML->appendChild($optionsXML = $dom->createElement('options'));
        foreach ($definition->getOptions() as $option) {
            $this->appendDocument($optionsXML, $this->getInputOptionDocument($option));
        }
        return $dom;
    }
    public function getCommandDocument(Command $command) : \DOMDocument
    {
        $dom = new \DOMDocument('1.0', 'UTF-8');
        $dom->appendChild($commandXML = $dom->createElement('command'));
        $command->getSynopsis();
        $command->mergeApplicationDefinition(\false);
        $commandXML->setAttribute('id', $command->getName());
        $commandXML->setAttribute('name', $command->getName());
        $commandXML->setAttribute('hidden', $command->isHidden() ? 1 : 0);
        $commandXML->appendChild($usagesXML = $dom->createElement('usages'));
        foreach (\array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()) as $usage) {
            $usagesXML->appendChild($dom->createElement('usage', $usage));
        }
        $commandXML->appendChild($descriptionXML = $dom->createElement('description'));
        $descriptionXML->appendChild($dom->createTextNode(\str_replace("\n", "\n ", $command->getDescription())));
        $commandXML->appendChild($helpXML = $dom->createElement('help'));
        $helpXML->appendChild($dom->createTextNode(\str_replace("\n", "\n ", $command->getProcessedHelp())));
        $definitionXML = $this->getInputDefinitionDocument($command->getNativeDefinition());
        $this->appendDocument($commandXML, $definitionXML->getElementsByTagName('definition')->item(0));
        return $dom;
    }
    public function getApplicationDocument(Application $application, string $namespace = null) : \DOMDocument
    {
        $dom = new \DOMDocument('1.0', 'UTF-8');
        $dom->appendChild($rootXml = $dom->createElement('symfony'));
        if ('UNKNOWN' !== $application->getName()) {
            $rootXml->setAttribute('name', $application->getName());
            if ('UNKNOWN' !== $application->getVersion()) {
                $rootXml->setAttribute('version', $application->getVersion());
            }
        }
        $rootXml->appendChild($commandsXML = $dom->createElement('commands'));
        $description = new ApplicationDescription($application, $namespace, \true);
        if ($namespace) {
            $commandsXML->setAttribute('namespace', $namespace);
        }
        foreach ($description->getCommands() as $command) {
            $this->appendDocument($commandsXML, $this->getCommandDocument($command));
        }
        if (!$namespace) {
            $rootXml->appendChild($namespacesXML = $dom->createElement('namespaces'));
            foreach ($description->getNamespaces() as $namespaceDescription) {
                $namespacesXML->appendChild($namespaceArrayXML = $dom->createElement('namespace'));
                $namespaceArrayXML->setAttribute('id', $namespaceDescription['id']);
                foreach ($namespaceDescription['commands'] as $name) {
                    $namespaceArrayXML->appendChild($commandXML = $dom->createElement('command'));
                    $commandXML->appendChild($dom->createTextNode($name));
                }
            }
        }
        return $dom;
    }
    /**
     * {@inheritdoc}
     */
    protected function describeInputArgument(InputArgument $argument, array $options = [])
    {
        $this->writeDocument($this->getInputArgumentDocument($argument));
    }
    /**
     * {@inheritdoc}
     */
    protected function describeInputOption(InputOption $option, array $options = [])
    {
        $this->writeDocument($this->getInputOptionDocument($option));
    }
    /**
     * {@inheritdoc}
     */
    protected function describeInputDefinition(InputDefinition $definition, array $options = [])
    {
        $this->writeDocument($this->getInputDefinitionDocument($definition));
    }
    /**
     * {@inheritdoc}
     */
    protected function describeCommand(Command $command, array $options = [])
    {
        $this->writeDocument($this->getCommandDocument($command));
    }
    /**
     * {@inheritdoc}
     */
    protected function describeApplication(Application $application, array $options = [])
    {
        $this->writeDocument($this->getApplicationDocument($application, $options['namespace'] ?? null));
    }
    /**
     * Appends document children to parent node.
     */
    private function appendDocument(\DOMNode $parentNode, \DOMNode $importedParent)
    {
        foreach ($importedParent->childNodes as $childNode) {
            $parentNode->appendChild($parentNode->ownerDocument->importNode($childNode, \true));
        }
    }
    /**
     * Writes DOM document.
     */
    private function writeDocument(\DOMDocument $dom)
    {
        $dom->formatOutput = \true;
        $this->write($dom->saveXML());
    }
    private function getInputArgumentDocument(InputArgument $argument) : \DOMDocument
    {
        $dom = new \DOMDocument('1.0', 'UTF-8');
        $dom->appendChild($objectXML = $dom->createElement('argument'));
        $objectXML->setAttribute('name', $argument->getName());
        $objectXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0);
        $objectXML->setAttribute('is_array', $argument->isArray() ? 1 : 0);
        $objectXML->appendChild($descriptionXML = $dom->createElement('description'));
        $descriptionXML->appendChild($dom->createTextNode($argument->getDescription()));
        $objectXML->appendChild($defaultsXML = $dom->createElement('defaults'));
        $defaults = \is_array($argument->getDefault()) ? $argument->getDefault() : (\is_bool($argument->getDefault()) ? [\var_export($argument->getDefault(), \true)] : ($argument->getDefault() ? [$argument->getDefault()] : []));
        foreach ($defaults as $default) {
            $defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
            $defaultXML->appendChild($dom->createTextNode($default));
        }
        return $dom;
    }
    private function getInputOptionDocument(InputOption $option) : \DOMDocument
    {
        $dom = new \DOMDocument('1.0', 'UTF-8');
        $dom->appendChild($objectXML = $dom->createElement('option'));
        $objectXML->setAttribute('name', '--' . $option->getName());
        $pos = \strpos($option->getShortcut() ?? '', '|');
        if (\false !== $pos) {
            $objectXML->setAttribute('shortcut', '-' . \substr($option->getShortcut(), 0, $pos));
            $objectXML->setAttribute('shortcuts', '-' . \str_replace('|', '|-', $option->getShortcut()));
        } else {
            $objectXML->setAttribute('shortcut', $option->getShortcut() ? '-' . $option->getShortcut() : '');
        }
        $objectXML->setAttribute('accept_value', $option->acceptValue() ? 1 : 0);
        $objectXML->setAttribute('is_value_required', $option->isValueRequired() ? 1 : 0);
        $objectXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0);
        $objectXML->appendChild($descriptionXML = $dom->createElement('description'));
        $descriptionXML->appendChild($dom->createTextNode($option->getDescription()));
        if ($option->acceptValue()) {
            $defaults = \is_array($option->getDefault()) ? $option->getDefault() : (\is_bool($option->getDefault()) ? [\var_export($option->getDefault(), \true)] : ($option->getDefault() ? [$option->getDefault()] : []));
            $objectXML->appendChild($defaultsXML = $dom->createElement('defaults'));
            if (!empty($defaults)) {
                foreach ($defaults as $default) {
                    $defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
                    $defaultXML->appendChild($dom->createTextNode($default));
                }
            }
        }
        return $dom;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Descriptor;

use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
/**
 * Descriptor interface.
 *
 * @author Jean-FranÃ§ois Simon <contact@jfsimon.fr>
 */
interface DescriptorInterface
{
    /**
     * Describes an object if supported.
     *
     * @param object $object
     */
    public function describe(OutputInterface $output, $object, array $options = []);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Descriptor;

use CivixPhar\Symfony\Component\Console\Application;
use CivixPhar\Symfony\Component\Console\Command\Command;
use CivixPhar\Symfony\Component\Console\Formatter\OutputFormatter;
use CivixPhar\Symfony\Component\Console\Helper\Helper;
use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputDefinition;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
/**
 * Text descriptor.
 *
 * @author Jean-FranÃ§ois Simon <contact@jfsimon.fr>
 *
 * @internal
 */
class TextDescriptor extends Descriptor
{
    /**
     * {@inheritdoc}
     */
    protected function describeInputArgument(InputArgument $argument, array $options = [])
    {
        if (null !== $argument->getDefault() && (!\is_array($argument->getDefault()) || \count($argument->getDefault()))) {
            $default = \sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($argument->getDefault()));
        } else {
            $default = '';
        }
        $totalWidth = $options['total_width'] ?? Helper::strlen($argument->getName());
        $spacingWidth = $totalWidth - \strlen($argument->getName());
        $this->writeText(\sprintf(
            '  <info>%s</info>  %s%s%s',
            $argument->getName(),
            \str_repeat(' ', $spacingWidth),
            // + 4 = 2 spaces before <info>, 2 spaces after </info>
            \preg_replace('/\\s*[\\r\\n]\\s*/', "\n" . \str_repeat(' ', $totalWidth + 4), $argument->getDescription()),
            $default
        ), $options);
    }
    /**
     * {@inheritdoc}
     */
    protected function describeInputOption(InputOption $option, array $options = [])
    {
        if ($option->acceptValue() && null !== $option->getDefault() && (!\is_array($option->getDefault()) || \count($option->getDefault()))) {
            $default = \sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($option->getDefault()));
        } else {
            $default = '';
        }
        $value = '';
        if ($option->acceptValue()) {
            $value = '=' . \strtoupper($option->getName());
            if ($option->isValueOptional()) {
                $value = '[' . $value . ']';
            }
        }
        $totalWidth = $options['total_width'] ?? $this->calculateTotalWidthForOptions([$option]);
        $synopsis = \sprintf('%s%s', $option->getShortcut() ? \sprintf('-%s, ', $option->getShortcut()) : '    ', \sprintf('--%s%s', $option->getName(), $value));
        $spacingWidth = $totalWidth - Helper::strlen($synopsis);
        $this->writeText(\sprintf(
            '  <info>%s</info>  %s%s%s%s',
            $synopsis,
            \str_repeat(' ', $spacingWidth),
            // + 4 = 2 spaces before <info>, 2 spaces after </info>
            \preg_replace('/\\s*[\\r\\n]\\s*/', "\n" . \str_repeat(' ', $totalWidth + 4), $option->getDescription()),
            $default,
            $option->isArray() ? '<comment> (multiple values allowed)</comment>' : ''
        ), $options);
    }
    /**
     * {@inheritdoc}
     */
    protected function describeInputDefinition(InputDefinition $definition, array $options = [])
    {
        $totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions());
        foreach ($definition->getArguments() as $argument) {
            $totalWidth = \max($totalWidth, Helper::strlen($argument->getName()));
        }
        if ($definition->getArguments()) {
            $this->writeText('<comment>Arguments:</comment>', $options);
            $this->writeText("\n");
            foreach ($definition->getArguments() as $argument) {
                $this->describeInputArgument($argument, \array_merge($options, ['total_width' => $totalWidth]));
                $this->writeText("\n");
            }
        }
        if ($definition->getArguments() && $definition->getOptions()) {
            $this->writeText("\n");
        }
        if ($definition->getOptions()) {
            $laterOptions = [];
            $this->writeText('<comment>Options:</comment>', $options);
            foreach ($definition->getOptions() as $option) {
                if (\strlen($option->getShortcut() ?? '') > 1) {
                    $laterOptions[] = $option;
                    continue;
                }
                $this->writeText("\n");
                $this->describeInputOption($option, \array_merge($options, ['total_width' => $totalWidth]));
            }
            foreach ($laterOptions as $option) {
                $this->writeText("\n");
                $this->describeInputOption($option, \array_merge($options, ['total_width' => $totalWidth]));
            }
        }
    }
    /**
     * {@inheritdoc}
     */
    protected function describeCommand(Command $command, array $options = [])
    {
        $command->getSynopsis(\true);
        $command->getSynopsis(\false);
        $command->mergeApplicationDefinition(\false);
        if ($description = $command->getDescription()) {
            $this->writeText('<comment>Description:</comment>', $options);
            $this->writeText("\n");
            $this->writeText('  ' . $description);
            $this->writeText("\n\n");
        }
        $this->writeText('<comment>Usage:</comment>', $options);
        foreach (\array_merge([$command->getSynopsis(\true)], $command->getAliases(), $command->getUsages()) as $usage) {
            $this->writeText("\n");
            $this->writeText('  ' . OutputFormatter::escape($usage), $options);
        }
        $this->writeText("\n");
        $definition = $command->getNativeDefinition();
        if ($definition->getOptions() || $definition->getArguments()) {
            $this->writeText("\n");
            $this->describeInputDefinition($definition, $options);
            $this->writeText("\n");
        }
        $help = $command->getProcessedHelp();
        if ($help && $help !== $description) {
            $this->writeText("\n");
            $this->writeText('<comment>Help:</comment>', $options);
            $this->writeText("\n");
            $this->writeText('  ' . \str_replace("\n", "\n  ", $help), $options);
            $this->writeText("\n");
        }
    }
    /**
     * {@inheritdoc}
     */
    protected function describeApplication(Application $application, array $options = [])
    {
        $describedNamespace = $options['namespace'] ?? null;
        $description = new ApplicationDescription($application, $describedNamespace);
        if (isset($options['raw_text']) && $options['raw_text']) {
            $width = $this->getColumnWidth($description->getCommands());
            foreach ($description->getCommands() as $command) {
                $this->writeText(\sprintf("%-{$width}s %s", $command->getName(), $command->getDescription()), $options);
                $this->writeText("\n");
            }
        } else {
            if ('' != ($help = $application->getHelp())) {
                $this->writeText("{$help}\n\n", $options);
            }
            $this->writeText("<comment>Usage:</comment>\n", $options);
            $this->writeText("  command [options] [arguments]\n\n", $options);
            $this->describeInputDefinition(new InputDefinition($application->getDefinition()->getOptions()), $options);
            $this->writeText("\n");
            $this->writeText("\n");
            $commands = $description->getCommands();
            $namespaces = $description->getNamespaces();
            if ($describedNamespace && $namespaces) {
                // make sure all alias commands are included when describing a specific namespace
                $describedNamespaceInfo = \reset($namespaces);
                foreach ($describedNamespaceInfo['commands'] as $name) {
                    $commands[$name] = $description->getCommand($name);
                }
            }
            // calculate max. width based on available commands per namespace
            $width = $this->getColumnWidth(\array_merge(...\array_values(\array_map(function ($namespace) use($commands) {
                return \array_intersect($namespace['commands'], \array_keys($commands));
            }, \array_values($namespaces)))));
            if ($describedNamespace) {
                $this->writeText(\sprintf('<comment>Available commands for the "%s" namespace:</comment>', $describedNamespace), $options);
            } else {
                $this->writeText('<comment>Available commands:</comment>', $options);
            }
            foreach ($namespaces as $namespace) {
                $namespace['commands'] = \array_filter($namespace['commands'], function ($name) use($commands) {
                    return isset($commands[$name]);
                });
                if (!$namespace['commands']) {
                    continue;
                }
                if (!$describedNamespace && ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) {
                    $this->writeText("\n");
                    $this->writeText(' <comment>' . $namespace['id'] . '</comment>', $options);
                }
                foreach ($namespace['commands'] as $name) {
                    $this->writeText("\n");
                    $spacingWidth = $width - Helper::strlen($name);
                    $command = $commands[$name];
                    $commandAliases = $name === $command->getName() ? $this->getCommandAliasesText($command) : '';
                    $this->writeText(\sprintf('  <info>%s</info>%s%s', $name, \str_repeat(' ', $spacingWidth), $commandAliases . $command->getDescription()), $options);
                }
            }
            $this->writeText("\n");
        }
    }
    /**
     * {@inheritdoc}
     */
    private function writeText(string $content, array $options = [])
    {
        $this->write(isset($options['raw_text']) && $options['raw_text'] ? \strip_tags($content) : $content, isset($options['raw_output']) ? !$options['raw_output'] : \true);
    }
    /**
     * Formats command aliases to show them in the command description.
     */
    private function getCommandAliasesText(Command $command) : string
    {
        $text = '';
        $aliases = $command->getAliases();
        if ($aliases) {
            $text = '[' . \implode('|', $aliases) . '] ';
        }
        return $text;
    }
    /**
     * Formats input option/argument default value.
     *
     * @param mixed $default
     */
    private function formatDefaultValue($default) : string
    {
        if (\INF === $default) {
            return 'INF';
        }
        if (\is_string($default)) {
            $default = OutputFormatter::escape($default);
        } elseif (\is_array($default)) {
            foreach ($default as $key => $value) {
                if (\is_string($value)) {
                    $default[$key] = OutputFormatter::escape($value);
                }
            }
        }
        return \str_replace('\\\\', '\\', \json_encode($default, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE));
    }
    /**
     * @param array<Command|string> $commands
     */
    private function getColumnWidth(array $commands) : int
    {
        $widths = [];
        foreach ($commands as $command) {
            if ($command instanceof Command) {
                $widths[] = Helper::strlen($command->getName());
                foreach ($command->getAliases() as $alias) {
                    $widths[] = Helper::strlen($alias);
                }
            } else {
                $widths[] = Helper::strlen($command);
            }
        }
        return $widths ? \max($widths) + 2 : 0;
    }
    /**
     * @param InputOption[] $options
     */
    private function calculateTotalWidthForOptions(array $options) : int
    {
        $totalWidth = 0;
        foreach ($options as $option) {
            // "-" + shortcut + ", --" + name
            $nameLength = 1 + \max(Helper::strlen($option->getShortcut()), 1) + 4 + Helper::strlen($option->getName());
            if ($option->acceptValue()) {
                $valueLength = 1 + Helper::strlen($option->getName());
                // = + value
                $valueLength += $option->isValueOptional() ? 2 : 0;
                // [ + ]
                $nameLength += $valueLength;
            }
            $totalWidth = \max($totalWidth, $nameLength);
        }
        return $totalWidth;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Descriptor;

use CivixPhar\Symfony\Component\Console\Application;
use CivixPhar\Symfony\Component\Console\Command\Command;
use CivixPhar\Symfony\Component\Console\Exception\InvalidArgumentException;
use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputDefinition;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
/**
 * @author Jean-FranÃ§ois Simon <jeanfrancois.simon@sensiolabs.com>
 *
 * @internal
 */
abstract class Descriptor implements DescriptorInterface
{
    /**
     * @var OutputInterface
     */
    protected $output;
    /**
     * {@inheritdoc}
     */
    public function describe(OutputInterface $output, $object, array $options = [])
    {
        $this->output = $output;
        switch (\true) {
            case $object instanceof InputArgument:
                $this->describeInputArgument($object, $options);
                break;
            case $object instanceof InputOption:
                $this->describeInputOption($object, $options);
                break;
            case $object instanceof InputDefinition:
                $this->describeInputDefinition($object, $options);
                break;
            case $object instanceof Command:
                $this->describeCommand($object, $options);
                break;
            case $object instanceof Application:
                $this->describeApplication($object, $options);
                break;
            default:
                throw new InvalidArgumentException(\sprintf('Object of type "%s" is not describable.', \get_class($object)));
        }
    }
    /**
     * Writes content to output.
     *
     * @param string $content
     * @param bool   $decorated
     */
    protected function write($content, $decorated = \false)
    {
        $this->output->write($content, \false, $decorated ? OutputInterface::OUTPUT_NORMAL : OutputInterface::OUTPUT_RAW);
    }
    /**
     * Describes an InputArgument instance.
     */
    protected abstract function describeInputArgument(InputArgument $argument, array $options = []);
    /**
     * Describes an InputOption instance.
     */
    protected abstract function describeInputOption(InputOption $option, array $options = []);
    /**
     * Describes an InputDefinition instance.
     */
    protected abstract function describeInputDefinition(InputDefinition $definition, array $options = []);
    /**
     * Describes a Command instance.
     */
    protected abstract function describeCommand(Command $command, array $options = []);
    /**
     * Describes an Application instance.
     */
    protected abstract function describeApplication(Application $application, array $options = []);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Event;

use CivixPhar\Symfony\Component\Console\Command\Command;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
/**
 * Allows to handle throwables thrown while running a command.
 *
 * @author Wouter de Jong <wouter@wouterj.nl>
 */
final class ConsoleErrorEvent extends ConsoleEvent
{
    private $error;
    private $exitCode;
    public function __construct(InputInterface $input, OutputInterface $output, \Throwable $error, Command $command = null)
    {
        parent::__construct($command, $input, $output);
        $this->error = $error;
    }
    public function getError() : \Throwable
    {
        return $this->error;
    }
    public function setError(\Throwable $error) : void
    {
        $this->error = $error;
    }
    public function setExitCode(int $exitCode) : void
    {
        $this->exitCode = $exitCode;
        $r = new \ReflectionProperty($this->error, 'code');
        $r->setAccessible(\true);
        $r->setValue($this->error, $this->exitCode);
    }
    public function getExitCode() : int
    {
        return $this->exitCode ?? (\is_int($this->error->getCode()) && 0 !== $this->error->getCode() ? $this->error->getCode() : 1);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Event;

use CivixPhar\Symfony\Component\Console\Command\Command;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CivixPhar\Symfony\Component\EventDispatcher\Event;
/**
 * Allows to inspect input and output of a command.
 *
 * @author Francesco Levorato <git@flevour.net>
 */
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;
    }
    /**
     * Gets the command that is executed.
     *
     * @return Command|null A Command instance
     */
    public function getCommand()
    {
        return $this->command;
    }
    /**
     * Gets the input instance.
     *
     * @return InputInterface An InputInterface instance
     */
    public function getInput()
    {
        return $this->input;
    }
    /**
     * Gets the output instance.
     *
     * @return OutputInterface An OutputInterface instance
     */
    public function getOutput()
    {
        return $this->output;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Event;

/**
 * Allows to do things before the command is executed, like skipping the command or changing the input.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 *
 * @final since Symfony 4.4
 */
class ConsoleCommandEvent extends ConsoleEvent
{
    /**
     * The return code for skipped commands, this will also be passed into the terminate event.
     */
    public const RETURN_CODE_DISABLED = 113;
    /**
     * Indicates if the command should be run or skipped.
     */
    private $commandShouldRun = \true;
    /**
     * Disables the command, so it won't be run.
     *
     * @return bool
     */
    public function disableCommand()
    {
        return $this->commandShouldRun = \false;
    }
    /**
     * Enables the command.
     *
     * @return bool
     */
    public function enableCommand()
    {
        return $this->commandShouldRun = \true;
    }
    /**
     * Returns true if the command is runnable, false otherwise.
     *
     * @return bool
     */
    public function commandShouldRun()
    {
        return $this->commandShouldRun;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Event;

use CivixPhar\Symfony\Component\Console\Command\Command;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
/**
 * Allows to manipulate the exit code of a command after its execution.
 *
 * @author Francesco Levorato <git@flevour.net>
 *
 * @final since Symfony 4.4
 */
class ConsoleTerminateEvent extends ConsoleEvent
{
    private $exitCode;
    public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $exitCode)
    {
        parent::__construct($command, $input, $output);
        $this->setExitCode($exitCode);
    }
    /**
     * Sets the exit code.
     *
     * @param int $exitCode The command exit code
     */
    public function setExitCode($exitCode)
    {
        $this->exitCode = (int) $exitCode;
    }
    /**
     * Gets the exit code.
     *
     * @return int The command exit code
     */
    public function getExitCode()
    {
        return $this->exitCode;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Formatter;

/**
 * Formatter interface for console output that supports word wrapping.
 *
 * @author Roland Franssen <franssen.roland@gmail.com>
 */
interface WrappableOutputFormatterInterface extends OutputFormatterInterface
{
    /**
     * Formats a message according to the given styles, wrapping at `$width` (0 means no wrapping).
     */
    public function formatAndWrap(string $message, int $width);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Formatter;

use CivixPhar\Symfony\Component\Console\Exception\InvalidArgumentException;
/**
 * Formatter style class for defining styles.
 *
 * @author Konstantin Kudryashov <ever.zet@gmail.com>
 */
class OutputFormatterStyle implements OutputFormatterStyleInterface
{
    private static $availableForegroundColors = ['black' => ['set' => 30, 'unset' => 39], 'red' => ['set' => 31, 'unset' => 39], 'green' => ['set' => 32, 'unset' => 39], 'yellow' => ['set' => 33, 'unset' => 39], 'blue' => ['set' => 34, 'unset' => 39], 'magenta' => ['set' => 35, 'unset' => 39], 'cyan' => ['set' => 36, 'unset' => 39], 'white' => ['set' => 37, 'unset' => 39], 'default' => ['set' => 39, 'unset' => 39]];
    private static $availableBackgroundColors = ['black' => ['set' => 40, 'unset' => 49], 'red' => ['set' => 41, 'unset' => 49], 'green' => ['set' => 42, 'unset' => 49], 'yellow' => ['set' => 43, 'unset' => 49], 'blue' => ['set' => 44, 'unset' => 49], 'magenta' => ['set' => 45, 'unset' => 49], 'cyan' => ['set' => 46, 'unset' => 49], 'white' => ['set' => 47, 'unset' => 49], 'default' => ['set' => 49, 'unset' => 49]];
    private static $availableOptions = ['bold' => ['set' => 1, 'unset' => 22], 'underscore' => ['set' => 4, 'unset' => 24], 'blink' => ['set' => 5, 'unset' => 25], 'reverse' => ['set' => 7, 'unset' => 27], 'conceal' => ['set' => 8, 'unset' => 28]];
    private $foreground;
    private $background;
    private $href;
    private $options = [];
    private $handlesHrefGracefully;
    /**
     * Initializes output formatter style.
     *
     * @param string|null $foreground The style foreground color name
     * @param string|null $background The style background color name
     */
    public function __construct(string $foreground = null, string $background = null, array $options = [])
    {
        if (null !== $foreground) {
            $this->setForeground($foreground);
        }
        if (null !== $background) {
            $this->setBackground($background);
        }
        if (\count($options)) {
            $this->setOptions($options);
        }
    }
    /**
     * {@inheritdoc}
     */
    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];
    }
    /**
     * {@inheritdoc}
     */
    public function setBackground($color = null)
    {
        if (null === $color) {
            $this->background = null;
            return;
        }
        if (!isset(static::$availableBackgroundColors[$color])) {
            throw new InvalidArgumentException(\sprintf('Invalid background color specified: "%s". Expected one of (%s).', $color, \implode(', ', \array_keys(static::$availableBackgroundColors))));
        }
        $this->background = static::$availableBackgroundColors[$color];
    }
    public function setHref(string $url) : void
    {
        $this->href = $url;
    }
    /**
     * {@inheritdoc}
     */
    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];
        }
    }
    /**
     * {@inheritdoc}
     */
    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]);
        }
    }
    /**
     * {@inheritdoc}
     */
    public function setOptions(array $options)
    {
        $this->options = [];
        foreach ($options as $option) {
            $this->setOption($option);
        }
    }
    /**
     * {@inheritdoc}
     */
    public function apply($text)
    {
        $setCodes = [];
        $unsetCodes = [];
        if (null === $this->handlesHrefGracefully) {
            $this->handlesHrefGracefully = 'JetBrains-JediTerm' !== \getenv('TERMINAL_EMULATOR') && (!\getenv('KONSOLE_VERSION') || (int) \getenv('KONSOLE_VERSION') > 201100);
        }
        if (null !== $this->foreground) {
            $setCodes[] = $this->foreground['set'];
            $unsetCodes[] = $this->foreground['unset'];
        }
        if (null !== $this->background) {
            $setCodes[] = $this->background['set'];
            $unsetCodes[] = $this->background['unset'];
        }
        foreach ($this->options as $option) {
            $setCodes[] = $option['set'];
            $unsetCodes[] = $option['unset'];
        }
        if (null !== $this->href && $this->handlesHrefGracefully) {
            $text = "\x1b]8;;{$this->href}\x1b\\{$text}\x1b]8;;\x1b\\";
        }
        if (0 === \count($setCodes)) {
            return $text;
        }
        return \sprintf("\x1b[%sm%s\x1b[%sm", \implode(';', $setCodes), $text, \implode(';', $unsetCodes));
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Formatter;

use CivixPhar\Symfony\Component\Console\Exception\InvalidArgumentException;
/**
 * Formatter class for console output.
 *
 * @author Konstantin Kudryashov <ever.zet@gmail.com>
 * @author Roland Franssen <franssen.roland@gmail.com>
 */
class OutputFormatter implements WrappableOutputFormatterInterface
{
    private $decorated;
    private $styles = [];
    private $styleStack;
    public function __clone()
    {
        $this->styleStack = clone $this->styleStack;
        foreach ($this->styles as $key => $value) {
            $this->styles[$key] = clone $value;
        }
    }
    /**
     * Escapes "<" special char in given text.
     *
     * @param string $text Text to escape
     *
     * @return string Escaped text
     */
    public static function escape($text)
    {
        $text = \preg_replace('/([^\\\\]?)</', '$1\\<', $text);
        return self::escapeTrailingBackslash($text);
    }
    /**
     * Escapes trailing "\" in given text.
     *
     * @internal
     */
    public static function escapeTrailingBackslash(string $text) : string
    {
        if (\str_ends_with($text, '\\')) {
            $len = \strlen($text);
            $text = \rtrim($text, '\\');
            $text = \str_replace("\x00", '', $text);
            $text .= \str_repeat("\x00", $len - \strlen($text));
        }
        return $text;
    }
    /**
     * Initializes console output formatter.
     *
     * @param OutputFormatterStyleInterface[] $styles Array of "name => FormatterStyle" instances
     */
    public function __construct(bool $decorated = \false, array $styles = [])
    {
        $this->decorated = $decorated;
        $this->setStyle('error', new OutputFormatterStyle('white', 'red'));
        $this->setStyle('info', new OutputFormatterStyle('green'));
        $this->setStyle('comment', new OutputFormatterStyle('yellow'));
        $this->setStyle('question', new OutputFormatterStyle('black', 'cyan'));
        foreach ($styles as $name => $style) {
            $this->setStyle($name, $style);
        }
        $this->styleStack = new OutputFormatterStyleStack();
    }
    /**
     * {@inheritdoc}
     */
    public function setDecorated($decorated)
    {
        $this->decorated = (bool) $decorated;
    }
    /**
     * {@inheritdoc}
     */
    public function isDecorated()
    {
        return $this->decorated;
    }
    /**
     * {@inheritdoc}
     */
    public function setStyle($name, OutputFormatterStyleInterface $style)
    {
        $this->styles[\strtolower($name)] = $style;
    }
    /**
     * {@inheritdoc}
     */
    public function hasStyle($name)
    {
        return isset($this->styles[\strtolower($name)]);
    }
    /**
     * {@inheritdoc}
     */
    public function getStyle($name)
    {
        if (!$this->hasStyle($name)) {
            throw new InvalidArgumentException(\sprintf('Undefined style: "%s".', $name));
        }
        return $this->styles[\strtolower($name)];
    }
    /**
     * {@inheritdoc}
     */
    public function format($message)
    {
        return $this->formatAndWrap((string) $message, 0);
    }
    /**
     * {@inheritdoc}
     */
    public function formatAndWrap(string $message, int $width)
    {
        $offset = 0;
        $output = '';
        $tagRegex = '[a-z][^<>]*+';
        $currentLineLength = 0;
        \preg_match_all("#<(({$tagRegex}) | /({$tagRegex})?)>#ix", $message, $matches, \PREG_OFFSET_CAPTURE);
        foreach ($matches[0] as $i => $match) {
            $pos = $match[1];
            $text = $match[0];
            if (0 != $pos && '\\' == $message[$pos - 1]) {
                continue;
            }
            // add the text up to the next tag
            $output .= $this->applyCurrentStyle(\substr($message, $offset, $pos - $offset), $output, $width, $currentLineLength);
            $offset = $pos + \strlen($text);
            // opening tag?
            if ($open = '/' != $text[1]) {
                $tag = $matches[1][$i][0];
            } else {
                $tag = $matches[3][$i][0] ?? '';
            }
            if (!$open && !$tag) {
                // </>
                $this->styleStack->pop();
            } elseif (null === ($style = $this->createStyleFromString($tag))) {
                $output .= $this->applyCurrentStyle($text, $output, $width, $currentLineLength);
            } elseif ($open) {
                $this->styleStack->push($style);
            } else {
                $this->styleStack->pop($style);
            }
        }
        $output .= $this->applyCurrentStyle(\substr($message, $offset), $output, $width, $currentLineLength);
        if (\str_contains($output, "\x00")) {
            return \strtr($output, ["\x00" => '\\', '\\<' => '<']);
        }
        return \str_replace('\\<', '<', $output);
    }
    /**
     * @return OutputFormatterStyleStack
     */
    public function getStyleStack()
    {
        return $this->styleStack;
    }
    /**
     * Tries to create new style instance from string.
     */
    private function createStyleFromString(string $string) : ?OutputFormatterStyleInterface
    {
        if (isset($this->styles[$string])) {
            return $this->styles[$string];
        }
        if (!\preg_match_all('/([^=]+)=([^;]+)(;|$)/', $string, $matches, \PREG_SET_ORDER)) {
            return null;
        }
        $style = new OutputFormatterStyle();
        foreach ($matches as $match) {
            \array_shift($match);
            $match[0] = \strtolower($match[0]);
            if ('fg' == $match[0]) {
                $style->setForeground(\strtolower($match[1]));
            } elseif ('bg' == $match[0]) {
                $style->setBackground(\strtolower($match[1]));
            } elseif ('href' === $match[0]) {
                $style->setHref($match[1]);
            } elseif ('options' === $match[0]) {
                \preg_match_all('([^,;]+)', \strtolower($match[1]), $options);
                $options = \array_shift($options);
                foreach ($options as $option) {
                    $style->setOption($option);
                }
            } else {
                return null;
            }
        }
        return $style;
    }
    /**
     * Applies current style from stack to text, if must be applied.
     */
    private function applyCurrentStyle(string $text, string $current, int $width, int &$currentLineLength) : string
    {
        if ('' === $text) {
            return '';
        }
        if (!$width) {
            return $this->isDecorated() ? $this->styleStack->getCurrent()->apply($text) : $text;
        }
        if (!$currentLineLength && '' !== $current) {
            $text = \ltrim($text);
        }
        if ($currentLineLength) {
            $prefix = \substr($text, 0, $i = $width - $currentLineLength) . "\n";
            $text = \substr($text, $i);
        } else {
            $prefix = '';
        }
        \preg_match('~(\\n)$~', $text, $matches);
        $text = $prefix . \preg_replace('~([^\\n]{' . $width . '})\\ *~', "\$1\n", $text);
        $text = \rtrim($text, "\n") . ($matches[1] ?? '');
        if (!$currentLineLength && '' !== $current && "\n" !== \substr($current, -1)) {
            $text = "\n" . $text;
        }
        $lines = \explode("\n", $text);
        foreach ($lines as $line) {
            $currentLineLength += \strlen($line);
            if ($width <= $currentLineLength) {
                $currentLineLength = 0;
            }
        }
        if ($this->isDecorated()) {
            foreach ($lines as $i => $line) {
                $lines[$i] = $this->styleStack->getCurrent()->apply($line);
            }
        }
        return \implode("\n", $lines);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Formatter;

/**
 * Formatter interface for console output.
 *
 * @author Konstantin Kudryashov <ever.zet@gmail.com>
 */
interface OutputFormatterInterface
{
    /**
     * Sets the decorated flag.
     *
     * @param bool $decorated Whether to decorate the messages or not
     */
    public function setDecorated($decorated);
    /**
     * Gets the decorated flag.
     *
     * @return bool true if the output will decorate messages, false otherwise
     */
    public function isDecorated();
    /**
     * Sets a new style.
     *
     * @param string $name The style name
     */
    public function setStyle($name, OutputFormatterStyleInterface $style);
    /**
     * Checks if output formatter has style with specified name.
     *
     * @param string $name
     *
     * @return bool
     */
    public function hasStyle($name);
    /**
     * Gets style options from style with specified name.
     *
     * @param string $name
     *
     * @return OutputFormatterStyleInterface
     *
     * @throws \InvalidArgumentException When style isn't defined
     */
    public function getStyle($name);
    /**
     * Formats a message according to the given styles.
     *
     * @param string $message The message to style
     *
     * @return string The styled message
     */
    public function format($message);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Formatter;

use CivixPhar\Symfony\Component\Console\Exception\InvalidArgumentException;
use CivixPhar\Symfony\Contracts\Service\ResetInterface;
/**
 * @author Jean-FranÃ§ois Simon <contact@jfsimon.fr>
 */
class OutputFormatterStyleStack implements ResetInterface
{
    /**
     * @var OutputFormatterStyleInterface[]
     */
    private $styles;
    private $emptyStyle;
    public function __construct(OutputFormatterStyleInterface $emptyStyle = null)
    {
        $this->emptyStyle = $emptyStyle ?? new OutputFormatterStyle();
        $this->reset();
    }
    /**
     * Resets stack (ie. empty internal arrays).
     */
    public function reset()
    {
        $this->styles = [];
    }
    /**
     * Pushes a style in the stack.
     */
    public function push(OutputFormatterStyleInterface $style)
    {
        $this->styles[] = $style;
    }
    /**
     * Pops a style from the stack.
     *
     * @return OutputFormatterStyleInterface
     *
     * @throws InvalidArgumentException When style tags incorrectly nested
     */
    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.');
    }
    /**
     * Computes current style with stacks top codes.
     *
     * @return OutputFormatterStyle
     */
    public function getCurrent()
    {
        if (empty($this->styles)) {
            return $this->emptyStyle;
        }
        return $this->styles[\count($this->styles) - 1];
    }
    /**
     * @return $this
     */
    public function setEmptyStyle(OutputFormatterStyleInterface $emptyStyle)
    {
        $this->emptyStyle = $emptyStyle;
        return $this;
    }
    /**
     * @return OutputFormatterStyleInterface
     */
    public function getEmptyStyle()
    {
        return $this->emptyStyle;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Formatter;

/**
 * Formatter style interface for defining styles.
 *
 * @author Konstantin Kudryashov <ever.zet@gmail.com>
 */
interface OutputFormatterStyleInterface
{
    /**
     * Sets style foreground color.
     *
     * @param string|null $color The color name
     */
    public function setForeground($color = null);
    /**
     * Sets style background color.
     *
     * @param string $color The color name
     */
    public function setBackground($color = null);
    /**
     * Sets some specific style option.
     *
     * @param string $option The option name
     */
    public function setOption($option);
    /**
     * Unsets some specific style option.
     *
     * @param string $option The option name
     */
    public function unsetOption($option);
    /**
     * Sets multiple style options at once.
     */
    public function setOptions(array $options);
    /**
     * Applies the style to a given text.
     *
     * @param string $text The text to style
     *
     * @return string
     */
    public function apply($text);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Output;

use CivixPhar\Symfony\Component\Console\Formatter\OutputFormatter;
use CivixPhar\Symfony\Component\Console\Formatter\OutputFormatterInterface;
/**
 * Base class for output classes.
 *
 * There are five levels of verbosity:
 *
 *  * normal: no option passed (normal output)
 *  * verbose: -v (more output)
 *  * very verbose: -vv (highly extended output)
 *  * debug: -vvv (all debug output)
 *  * quiet: -q (no output)
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
abstract class Output implements OutputInterface
{
    private $verbosity;
    private $formatter;
    /**
     * @param int                           $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface)
     * @param bool                          $decorated Whether to decorate messages
     * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter)
     */
    public function __construct(?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = \false, OutputFormatterInterface $formatter = null)
    {
        $this->verbosity = null === $verbosity ? self::VERBOSITY_NORMAL : $verbosity;
        $this->formatter = $formatter ?? new OutputFormatter();
        $this->formatter->setDecorated($decorated);
    }
    /**
     * {@inheritdoc}
     */
    public function setFormatter(OutputFormatterInterface $formatter)
    {
        $this->formatter = $formatter;
    }
    /**
     * {@inheritdoc}
     */
    public function getFormatter()
    {
        return $this->formatter;
    }
    /**
     * {@inheritdoc}
     */
    public function setDecorated($decorated)
    {
        $this->formatter->setDecorated($decorated);
    }
    /**
     * {@inheritdoc}
     */
    public function isDecorated()
    {
        return $this->formatter->isDecorated();
    }
    /**
     * {@inheritdoc}
     */
    public function setVerbosity($level)
    {
        $this->verbosity = (int) $level;
    }
    /**
     * {@inheritdoc}
     */
    public function getVerbosity()
    {
        return $this->verbosity;
    }
    /**
     * {@inheritdoc}
     */
    public function isQuiet()
    {
        return self::VERBOSITY_QUIET === $this->verbosity;
    }
    /**
     * {@inheritdoc}
     */
    public function isVerbose()
    {
        return self::VERBOSITY_VERBOSE <= $this->verbosity;
    }
    /**
     * {@inheritdoc}
     */
    public function isVeryVerbose()
    {
        return self::VERBOSITY_VERY_VERBOSE <= $this->verbosity;
    }
    /**
     * {@inheritdoc}
     */
    public function isDebug()
    {
        return self::VERBOSITY_DEBUG <= $this->verbosity;
    }
    /**
     * {@inheritdoc}
     */
    public function writeln($messages, $options = self::OUTPUT_NORMAL)
    {
        $this->write($messages, \true, $options);
    }
    /**
     * {@inheritdoc}
     */
    public function write($messages, $newline = \false, $options = self::OUTPUT_NORMAL)
    {
        if (!\is_iterable($messages)) {
            $messages = [$messages];
        }
        $types = self::OUTPUT_NORMAL | self::OUTPUT_RAW | self::OUTPUT_PLAIN;
        $type = $types & $options ?: self::OUTPUT_NORMAL;
        $verbosities = self::VERBOSITY_QUIET | self::VERBOSITY_NORMAL | self::VERBOSITY_VERBOSE | self::VERBOSITY_VERY_VERBOSE | self::VERBOSITY_DEBUG;
        $verbosity = $verbosities & $options ?: self::VERBOSITY_NORMAL;
        if ($verbosity > $this->getVerbosity()) {
            return;
        }
        foreach ($messages as $message) {
            switch ($type) {
                case OutputInterface::OUTPUT_NORMAL:
                    $message = $this->formatter->format($message);
                    break;
                case OutputInterface::OUTPUT_RAW:
                    break;
                case OutputInterface::OUTPUT_PLAIN:
                    $message = \strip_tags($this->formatter->format($message));
                    break;
            }
            $this->doWrite($message ?? '', $newline);
        }
    }
    /**
     * Writes a message to the output.
     *
     * @param string $message A message to write to the output
     * @param bool   $newline Whether to add a newline or not
     */
    protected abstract function doWrite($message, $newline);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Output;

/**
 * @author Jean-FranÃ§ois Simon <contact@jfsimon.fr>
 */
class BufferedOutput extends Output
{
    private $buffer = '';
    /**
     * Empties buffer and returns its content.
     *
     * @return string
     */
    public function fetch()
    {
        $content = $this->buffer;
        $this->buffer = '';
        return $content;
    }
    /**
     * {@inheritdoc}
     */
    protected function doWrite($message, $newline)
    {
        $this->buffer .= $message;
        if ($newline) {
            $this->buffer .= \PHP_EOL;
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Output;

use CivixPhar\Symfony\Component\Console\Formatter\OutputFormatterInterface;
use CivixPhar\Symfony\Component\Console\Helper\Helper;
use CivixPhar\Symfony\Component\Console\Terminal;
/**
 * @author Pierre du Plessis <pdples@gmail.com>
 * @author Gabriel OstroluckÃ½ <gabriel.ostrolucky@gmail.com>
 */
class ConsoleSectionOutput extends StreamOutput
{
    private $content = [];
    private $lines = 0;
    private $sections;
    private $terminal;
    /**
     * @param resource               $stream
     * @param ConsoleSectionOutput[] $sections
     */
    public function __construct($stream, array &$sections, int $verbosity, bool $decorated, OutputFormatterInterface $formatter)
    {
        parent::__construct($stream, $verbosity, $decorated, $formatter);
        \array_unshift($sections, $this);
        $this->sections =& $sections;
        $this->terminal = new Terminal();
    }
    /**
     * Clears previous output for this section.
     *
     * @param int $lines Number of lines to clear. If null, then the entire output of this section is cleared
     */
    public function clear(int $lines = null)
    {
        if (empty($this->content) || !$this->isDecorated()) {
            return;
        }
        if ($lines) {
            \array_splice($this->content, -($lines * 2));
            // Multiply lines by 2 to cater for each new line added between content
        } else {
            $lines = $this->lines;
            $this->content = [];
        }
        $this->lines -= $lines;
        parent::doWrite($this->popStreamContentUntilCurrentSection($lines), \false);
    }
    /**
     * Overwrites the previous output with a new message.
     *
     * @param array|string $message
     */
    public function overwrite($message)
    {
        $this->clear();
        $this->writeln($message);
    }
    public function getContent() : string
    {
        return \implode('', $this->content);
    }
    /**
     * @internal
     */
    public function addContent(string $input)
    {
        foreach (\explode(\PHP_EOL, $input) as $lineContent) {
            $this->lines += \ceil($this->getDisplayLength($lineContent) / $this->terminal->getWidth()) ?: 1;
            $this->content[] = $lineContent;
            $this->content[] = \PHP_EOL;
        }
    }
    /**
     * {@inheritdoc}
     */
    protected function doWrite($message, $newline)
    {
        if (!$this->isDecorated()) {
            parent::doWrite($message, $newline);
            return;
        }
        $erasedContent = $this->popStreamContentUntilCurrentSection();
        $this->addContent($message);
        parent::doWrite($message, \true);
        parent::doWrite($erasedContent, \false);
    }
    /**
     * At initial stage, cursor is at the end of stream output. This method makes cursor crawl upwards until it hits
     * current section. Then it erases content it crawled through. Optionally, it erases part of current section too.
     */
    private function popStreamContentUntilCurrentSection(int $numberOfLinesToClearFromCurrentSection = 0) : string
    {
        $numberOfLinesToClear = $numberOfLinesToClearFromCurrentSection;
        $erasedContent = [];
        foreach ($this->sections as $section) {
            if ($section === $this) {
                break;
            }
            $numberOfLinesToClear += $section->lines;
            $erasedContent[] = $section->getContent();
        }
        if ($numberOfLinesToClear > 0) {
            // move cursor up n lines
            parent::doWrite(\sprintf("\x1b[%dA", $numberOfLinesToClear), \false);
            // erase to end of screen
            parent::doWrite("\x1b[0J", \false);
        }
        return \implode('', \array_reverse($erasedContent));
    }
    private function getDisplayLength(string $text) : string
    {
        return Helper::strlenWithoutDecoration($this->getFormatter(), \str_replace("\t", '        ', $text));
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Output;

use CivixPhar\Symfony\Component\Console\Exception\InvalidArgumentException;
use CivixPhar\Symfony\Component\Console\Formatter\OutputFormatterInterface;
/**
 * A BufferedOutput that keeps only the last N chars.
 *
 * @author JÃ©rÃ©my DerussÃ© <jeremy@derusse.com>
 */
class TrimmedBufferOutput extends Output
{
    private $maxLength;
    private $buffer = '';
    public function __construct(int $maxLength, ?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = \false, OutputFormatterInterface $formatter = null)
    {
        if ($maxLength <= 0) {
            throw new InvalidArgumentException(\sprintf('"%s()" expects a strictly positive maxLength. Got %d.', __METHOD__, $maxLength));
        }
        parent::__construct($verbosity, $decorated, $formatter);
        $this->maxLength = $maxLength;
    }
    /**
     * Empties buffer and returns its content.
     *
     * @return string
     */
    public function fetch()
    {
        $content = $this->buffer;
        $this->buffer = '';
        return $content;
    }
    /**
     * {@inheritdoc}
     */
    protected function doWrite($message, $newline)
    {
        $this->buffer .= $message;
        if ($newline) {
            $this->buffer .= \PHP_EOL;
        }
        $this->buffer = \substr($this->buffer, 0 - $this->maxLength);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Output;

use CivixPhar\Symfony\Component\Console\Formatter\OutputFormatter;
use CivixPhar\Symfony\Component\Console\Formatter\OutputFormatterInterface;
/**
 * NullOutput suppresses all output.
 *
 *     $output = new NullOutput();
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Tobias Schultze <http://tobion.de>
 */
class NullOutput implements OutputInterface
{
    /**
     * {@inheritdoc}
     */
    public function setFormatter(OutputFormatterInterface $formatter)
    {
        // do nothing
    }
    /**
     * {@inheritdoc}
     */
    public function getFormatter()
    {
        // to comply with the interface we must return a OutputFormatterInterface
        return new OutputFormatter();
    }
    /**
     * {@inheritdoc}
     */
    public function setDecorated($decorated)
    {
        // do nothing
    }
    /**
     * {@inheritdoc}
     */
    public function isDecorated()
    {
        return \false;
    }
    /**
     * {@inheritdoc}
     */
    public function setVerbosity($level)
    {
        // do nothing
    }
    /**
     * {@inheritdoc}
     */
    public function getVerbosity()
    {
        return self::VERBOSITY_QUIET;
    }
    /**
     * {@inheritdoc}
     */
    public function isQuiet()
    {
        return \true;
    }
    /**
     * {@inheritdoc}
     */
    public function isVerbose()
    {
        return \false;
    }
    /**
     * {@inheritdoc}
     */
    public function isVeryVerbose()
    {
        return \false;
    }
    /**
     * {@inheritdoc}
     */
    public function isDebug()
    {
        return \false;
    }
    /**
     * {@inheritdoc}
     */
    public function writeln($messages, $options = self::OUTPUT_NORMAL)
    {
        // do nothing
    }
    /**
     * {@inheritdoc}
     */
    public function write($messages, $newline = \false, $options = self::OUTPUT_NORMAL)
    {
        // do nothing
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Output;

use CivixPhar\Symfony\Component\Console\Formatter\OutputFormatterInterface;
/**
 * ConsoleOutput is the default class for all CLI output. It uses STDOUT and STDERR.
 *
 * This class is a convenient wrapper around `StreamOutput` for both STDOUT and STDERR.
 *
 *     $output = new ConsoleOutput();
 *
 * This is equivalent to:
 *
 *     $output = new StreamOutput(fopen('php://stdout', 'w'));
 *     $stdErr = new StreamOutput(fopen('php://stderr', 'w'));
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
{
    private $stderr;
    private $consoleSectionOutputs = [];
    /**
     * @param int                           $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface)
     * @param bool|null                     $decorated Whether to decorate messages (null for auto-guessing)
     * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter)
     */
    public function __construct(int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = null, OutputFormatterInterface $formatter = null)
    {
        parent::__construct($this->openOutputStream(), $verbosity, $decorated, $formatter);
        if (null === $formatter) {
            // for BC reasons, stdErr has it own Formatter only when user don't inject a specific formatter.
            $this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated);
            return;
        }
        $actualDecorated = $this->isDecorated();
        $this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated, $this->getFormatter());
        if (null === $decorated) {
            $this->setDecorated($actualDecorated && $this->stderr->isDecorated());
        }
    }
    /**
     * Creates a new output section.
     */
    public function section() : ConsoleSectionOutput
    {
        return new ConsoleSectionOutput($this->getStream(), $this->consoleSectionOutputs, $this->getVerbosity(), $this->isDecorated(), $this->getFormatter());
    }
    /**
     * {@inheritdoc}
     */
    public function setDecorated($decorated)
    {
        parent::setDecorated($decorated);
        $this->stderr->setDecorated($decorated);
    }
    /**
     * {@inheritdoc}
     */
    public function setFormatter(OutputFormatterInterface $formatter)
    {
        parent::setFormatter($formatter);
        $this->stderr->setFormatter($formatter);
    }
    /**
     * {@inheritdoc}
     */
    public function setVerbosity($level)
    {
        parent::setVerbosity($level);
        $this->stderr->setVerbosity($level);
    }
    /**
     * {@inheritdoc}
     */
    public function getErrorOutput()
    {
        return $this->stderr;
    }
    /**
     * {@inheritdoc}
     */
    public function setErrorOutput(OutputInterface $error)
    {
        $this->stderr = $error;
    }
    /**
     * Returns true if current environment supports writing console output to
     * STDOUT.
     *
     * @return bool
     */
    protected function hasStdoutSupport()
    {
        return \false === $this->isRunningOS400();
    }
    /**
     * Returns true if current environment supports writing console output to
     * STDERR.
     *
     * @return bool
     */
    protected function hasStderrSupport()
    {
        return \false === $this->isRunningOS400();
    }
    /**
     * Checks if current executing environment is IBM iSeries (OS400), which
     * doesn't properly convert character-encodings between ASCII to EBCDIC.
     */
    private function isRunningOS400() : bool
    {
        $checks = [\function_exists('php_uname') ? \php_uname('s') : '', \getenv('OSTYPE'), \PHP_OS];
        return \false !== \stripos(\implode(';', $checks), 'OS400');
    }
    /**
     * @return resource
     */
    private function openOutputStream()
    {
        if (!$this->hasStdoutSupport()) {
            return \fopen('php://output', 'w');
        }
        return @\fopen('php://stdout', 'w') ?: \fopen('php://output', 'w');
    }
    /**
     * @return resource
     */
    private function openErrorStream()
    {
        return \fopen($this->hasStderrSupport() ? 'php://stderr' : 'php://output', 'w');
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Output;

use CivixPhar\Symfony\Component\Console\Exception\InvalidArgumentException;
use CivixPhar\Symfony\Component\Console\Formatter\OutputFormatterInterface;
/**
 * StreamOutput writes the output to a given stream.
 *
 * Usage:
 *
 *     $output = new StreamOutput(fopen('php://stdout', 'w'));
 *
 * As `StreamOutput` can use any stream, you can also use a file:
 *
 *     $output = new StreamOutput(fopen('/path/to/output.log', 'a', false));
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class StreamOutput extends Output
{
    private $stream;
    /**
     * @param resource                      $stream    A stream resource
     * @param int                           $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface)
     * @param bool|null                     $decorated Whether to decorate messages (null for auto-guessing)
     * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter)
     *
     * @throws InvalidArgumentException When first argument is not a real stream
     */
    public function __construct($stream, int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = null, OutputFormatterInterface $formatter = null)
    {
        if (!\is_resource($stream) || 'stream' !== \get_resource_type($stream)) {
            throw new InvalidArgumentException('The StreamOutput class needs a stream as its first argument.');
        }
        $this->stream = $stream;
        if (null === $decorated) {
            $decorated = $this->hasColorSupport();
        }
        parent::__construct($verbosity, $decorated, $formatter);
    }
    /**
     * Gets the stream attached to this StreamOutput instance.
     *
     * @return resource A stream resource
     */
    public function getStream()
    {
        return $this->stream;
    }
    /**
     * {@inheritdoc}
     */
    protected function doWrite($message, $newline)
    {
        if ($newline) {
            $message .= \PHP_EOL;
        }
        @\fwrite($this->stream, $message);
        \fflush($this->stream);
    }
    /**
     * Returns true if the stream supports colorization.
     *
     * Colorization is disabled if not supported by the stream:
     *
     * This is tricky on Windows, because Cygwin, Msys2 etc emulate pseudo
     * terminals via named pipes, so we can only check the environment.
     *
     * Reference: Composer\XdebugHandler\Process::supportsColor
     * https://github.com/composer/xdebug-handler
     *
     * @return bool true if the stream supports colorization, false otherwise
     */
    protected function hasColorSupport()
    {
        // Follow https://no-color.org/
        if (isset($_SERVER['NO_COLOR']) || \false !== \getenv('NO_COLOR')) {
            return \false;
        }
        if ('Hyper' === \getenv('TERM_PROGRAM')) {
            return \true;
        }
        if (\DIRECTORY_SEPARATOR === '\\') {
            return \function_exists('sapi_windows_vt100_support') && @\sapi_windows_vt100_support($this->stream) || \false !== \getenv('ANSICON') || 'ON' === \getenv('ConEmuANSI') || 'xterm' === \getenv('TERM');
        }
        if (\function_exists('stream_isatty')) {
            return @\stream_isatty($this->stream);
        }
        if (\function_exists('posix_isatty')) {
            return @\posix_isatty($this->stream);
        }
        $stat = @\fstat($this->stream);
        // Check if formatted mode is S_IFCHR
        return $stat ? 020000 === ($stat['mode'] & 0170000) : \false;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Output;

/**
 * ConsoleOutputInterface is the interface implemented by ConsoleOutput class.
 * This adds information about stderr and section output stream.
 *
 * @author Dariusz GÃ³recki <darek.krk@gmail.com>
 *
 * @method ConsoleSectionOutput section() Creates a new output section
 */
interface ConsoleOutputInterface extends OutputInterface
{
    /**
     * Gets the OutputInterface for errors.
     *
     * @return OutputInterface
     */
    public function getErrorOutput();
    public function setErrorOutput(OutputInterface $error);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Output;

use CivixPhar\Symfony\Component\Console\Formatter\OutputFormatterInterface;
/**
 * OutputInterface is the interface implemented by all Output classes.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
interface OutputInterface
{
    public const VERBOSITY_QUIET = 16;
    public const VERBOSITY_NORMAL = 32;
    public const VERBOSITY_VERBOSE = 64;
    public const VERBOSITY_VERY_VERBOSE = 128;
    public const VERBOSITY_DEBUG = 256;
    public const OUTPUT_NORMAL = 1;
    public const OUTPUT_RAW = 2;
    public const OUTPUT_PLAIN = 4;
    /**
     * Writes a message to the output.
     *
     * @param string|iterable $messages The message as an iterable of strings or a single string
     * @param bool            $newline  Whether to add a newline
     * @param int             $options  A bitmask of options (one of the OUTPUT or VERBOSITY constants), 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL
     */
    public function write($messages, $newline = \false, $options = 0);
    /**
     * Writes a message to the output and adds a newline at the end.
     *
     * @param string|iterable $messages The message as an iterable of strings or a single string
     * @param int             $options  A bitmask of options (one of the OUTPUT or VERBOSITY constants), 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL
     */
    public function writeln($messages, $options = 0);
    /**
     * Sets the verbosity of the output.
     *
     * @param int $level The level of verbosity (one of the VERBOSITY constants)
     */
    public function setVerbosity($level);
    /**
     * Gets the current verbosity of the output.
     *
     * @return int The current level of verbosity (one of the VERBOSITY constants)
     */
    public function getVerbosity();
    /**
     * Returns whether verbosity is quiet (-q).
     *
     * @return bool true if verbosity is set to VERBOSITY_QUIET, false otherwise
     */
    public function isQuiet();
    /**
     * Returns whether verbosity is verbose (-v).
     *
     * @return bool true if verbosity is set to VERBOSITY_VERBOSE, false otherwise
     */
    public function isVerbose();
    /**
     * Returns whether verbosity is very verbose (-vv).
     *
     * @return bool true if verbosity is set to VERBOSITY_VERY_VERBOSE, false otherwise
     */
    public function isVeryVerbose();
    /**
     * Returns whether verbosity is debug (-vvv).
     *
     * @return bool true if verbosity is set to VERBOSITY_DEBUG, false otherwise
     */
    public function isDebug();
    /**
     * Sets the decorated flag.
     *
     * @param bool $decorated Whether to decorate the messages
     */
    public function setDecorated($decorated);
    /**
     * Gets the decorated flag.
     *
     * @return bool true if the output will decorate messages, false otherwise
     */
    public function isDecorated();
    public function setFormatter(OutputFormatterInterface $formatter);
    /**
     * Returns current output formatter instance.
     *
     * @return OutputFormatterInterface
     */
    public function getFormatter();
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\DependencyInjection;

use CivixPhar\Symfony\Component\Console\Command\Command;
use CivixPhar\Symfony\Component\Console\CommandLoader\ContainerCommandLoader;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\TypedReference;
/**
 * Registers console commands.
 *
 * @author GrÃ©goire Pineau <lyrixx@lyrixx.info>
 */
class AddConsoleCommandPass implements CompilerPassInterface
{
    private $commandLoaderServiceId;
    private $commandTag;
    public function __construct(string $commandLoaderServiceId = 'console.command_loader', string $commandTag = 'console.command')
    {
        $this->commandLoaderServiceId = $commandLoaderServiceId;
        $this->commandTag = $commandTag;
    }
    public function process(ContainerBuilder $container)
    {
        $commandServices = $container->findTaggedServiceIds($this->commandTag, \true);
        $lazyCommandMap = [];
        $lazyCommandRefs = [];
        $serviceIds = [];
        foreach ($commandServices as $id => $tags) {
            $definition = $container->getDefinition($id);
            $class = $container->getParameterBag()->resolveValue($definition->getClass());
            if (isset($tags[0]['command'])) {
                $commandName = $tags[0]['command'];
            } else {
                if (!($r = $container->getReflectionClass($class))) {
                    throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
                }
                if (!$r->isSubclassOf(Command::class)) {
                    throw new InvalidArgumentException(\sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, $this->commandTag, Command::class));
                }
                $commandName = $class::getDefaultName();
            }
            if (null === $commandName) {
                if (!$definition->isPublic() || $definition->isPrivate()) {
                    $commandId = 'console.command.public_alias.' . $id;
                    $container->setAlias($commandId, $id)->setPublic(\true);
                    $id = $commandId;
                }
                $serviceIds[] = $id;
                continue;
            }
            unset($tags[0]);
            $lazyCommandMap[$commandName] = $id;
            $lazyCommandRefs[$id] = new TypedReference($id, $class);
            $aliases = [];
            foreach ($tags as $tag) {
                if (isset($tag['command'])) {
                    $aliases[] = $tag['command'];
                    $lazyCommandMap[$tag['command']] = $id;
                }
            }
            $definition->addMethodCall('setName', [$commandName]);
            if ($aliases) {
                $definition->addMethodCall('setAliases', [$aliases]);
            }
        }
        $container->register($this->commandLoaderServiceId, ContainerCommandLoader::class)->setPublic(\true)->setArguments([ServiceLocatorTagPass::register($container, $lazyCommandRefs), $lazyCommandMap]);
        $container->setParameter('console.command.ids', $serviceIds);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console;

class Terminal
{
    private static $width;
    private static $height;
    private static $stty;
    /**
     * Gets the terminal width.
     *
     * @return int
     */
    public function getWidth()
    {
        $width = \getenv('COLUMNS');
        if (\false !== $width) {
            return (int) \trim($width);
        }
        if (null === self::$width) {
            self::initDimensions();
        }
        return self::$width ?: 80;
    }
    /**
     * Gets the terminal height.
     *
     * @return int
     */
    public function getHeight()
    {
        $height = \getenv('LINES');
        if (\false !== $height) {
            return (int) \trim($height);
        }
        if (null === self::$height) {
            self::initDimensions();
        }
        return self::$height ?: 50;
    }
    /**
     * @internal
     *
     * @return bool
     */
    public static function hasSttyAvailable()
    {
        if (null !== self::$stty) {
            return self::$stty;
        }
        // skip check if exec function is disabled
        if (!\function_exists('exec')) {
            return \false;
        }
        \exec('stty 2>&1', $output, $exitcode);
        return self::$stty = 0 === $exitcode;
    }
    private static function initDimensions()
    {
        if ('\\' === \DIRECTORY_SEPARATOR) {
            if (\preg_match('/^(\\d+)x(\\d+)(?: \\((\\d+)x(\\d+)\\))?$/', \trim(\getenv('ANSICON')), $matches)) {
                // extract [w, H] from "wxh (WxH)"
                // or [w, h] from "wxh"
                self::$width = (int) $matches[1];
                self::$height = isset($matches[4]) ? (int) $matches[4] : (int) $matches[2];
            } elseif (!self::hasVt100Support() && self::hasSttyAvailable()) {
                // only use stty on Windows if the terminal does not support vt100 (e.g. Windows 7 + git-bash)
                // testing for stty in a Windows 10 vt100-enabled console will implicitly disable vt100 support on STDOUT
                self::initDimensionsUsingStty();
            } elseif (null !== ($dimensions = self::getConsoleMode())) {
                // extract [w, h] from "wxh"
                self::$width = (int) $dimensions[0];
                self::$height = (int) $dimensions[1];
            }
        } else {
            self::initDimensionsUsingStty();
        }
    }
    /**
     * Returns whether STDOUT has vt100 support (some Windows 10+ configurations).
     */
    private static function hasVt100Support() : bool
    {
        return \function_exists('sapi_windows_vt100_support') && \sapi_windows_vt100_support(\fopen('php://stdout', 'w'));
    }
    /**
     * Initializes dimensions using the output of an stty columns line.
     */
    private static function initDimensionsUsingStty()
    {
        if ($sttyString = self::getSttyColumns()) {
            if (\preg_match('/rows.(\\d+);.columns.(\\d+);/i', $sttyString, $matches)) {
                // extract [w, h] from "rows h; columns w;"
                self::$width = (int) $matches[2];
                self::$height = (int) $matches[1];
            } elseif (\preg_match('/;.(\\d+).rows;.(\\d+).columns/i', $sttyString, $matches)) {
                // extract [w, h] from "; h rows; w columns"
                self::$width = (int) $matches[2];
                self::$height = (int) $matches[1];
            }
        }
    }
    /**
     * Runs and parses mode CON if it's available, suppressing any error output.
     *
     * @return int[]|null An array composed of the width and the height or null if it could not be parsed
     */
    private static function getConsoleMode() : ?array
    {
        $info = self::readFromProcess('mode CON');
        if (null === $info || !\preg_match('/--------+\\r?\\n.+?(\\d+)\\r?\\n.+?(\\d+)\\r?\\n/', $info, $matches)) {
            return null;
        }
        return [(int) $matches[2], (int) $matches[1]];
    }
    /**
     * Runs and parses stty -a if it's available, suppressing any error output.
     */
    private static function getSttyColumns() : ?string
    {
        return self::readFromProcess('stty -a | grep columns');
    }
    private static function readFromProcess(string $command) : ?string
    {
        if (!\function_exists('proc_open')) {
            return null;
        }
        $descriptorspec = [1 => ['pipe', 'w'], 2 => ['pipe', 'w']];
        $process = \proc_open($command, $descriptorspec, $pipes, null, null, ['suppress_errors' => \true]);
        if (!\is_resource($process)) {
            return null;
        }
        $info = \stream_get_contents($pipes[1]);
        \fclose($pipes[1]);
        \fclose($pipes[2]);
        \proc_close($process);
        return $info;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Helper;

/**
 * @internal
 */
class TableRows implements \IteratorAggregate
{
    private $generator;
    public function __construct(callable $generator)
    {
        $this->generator = $generator;
    }
    public function getIterator() : \Traversable
    {
        $g = $this->generator;
        return $g();
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Helper;

use CivixPhar\Symfony\Component\Console\Descriptor\DescriptorInterface;
use CivixPhar\Symfony\Component\Console\Descriptor\JsonDescriptor;
use CivixPhar\Symfony\Component\Console\Descriptor\MarkdownDescriptor;
use CivixPhar\Symfony\Component\Console\Descriptor\TextDescriptor;
use CivixPhar\Symfony\Component\Console\Descriptor\XmlDescriptor;
use CivixPhar\Symfony\Component\Console\Exception\InvalidArgumentException;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
/**
 * This class adds helper method to describe objects in various formats.
 *
 * @author Jean-FranÃ§ois Simon <contact@jfsimon.fr>
 */
class DescriptorHelper extends Helper
{
    /**
     * @var DescriptorInterface[]
     */
    private $descriptors = [];
    public function __construct()
    {
        $this->register('txt', new TextDescriptor())->register('xml', new XmlDescriptor())->register('json', new JsonDescriptor())->register('md', new MarkdownDescriptor());
    }
    /**
     * Describes an object if supported.
     *
     * Available options are:
     * * format: string, the output format name
     * * raw_text: boolean, sets output type as raw
     *
     * @param object $object
     *
     * @throws InvalidArgumentException when the given format is not supported
     */
    public function describe(OutputInterface $output, $object, array $options = [])
    {
        $options = \array_merge(['raw_text' => \false, 'format' => 'txt'], $options);
        if (!isset($this->descriptors[$options['format']])) {
            throw new InvalidArgumentException(\sprintf('Unsupported format "%s".', $options['format']));
        }
        $descriptor = $this->descriptors[$options['format']];
        $descriptor->describe($output, $object, $options);
    }
    /**
     * Registers a descriptor.
     *
     * @param string $format
     *
     * @return $this
     */
    public function register($format, DescriptorInterface $descriptor)
    {
        $this->descriptors[$format] = $descriptor;
        return $this;
    }
    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return 'descriptor';
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Helper;

use CivixPhar\Symfony\Component\Console\Formatter\OutputFormatter;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CivixPhar\Symfony\Component\Console\Question\ChoiceQuestion;
use CivixPhar\Symfony\Component\Console\Question\ConfirmationQuestion;
use CivixPhar\Symfony\Component\Console\Question\Question;
use CivixPhar\Symfony\Component\Console\Style\SymfonyStyle;
/**
 * Symfony Style Guide compliant question helper.
 *
 * @author Kevin Bond <kevinbond@gmail.com>
 */
class SymfonyQuestionHelper extends QuestionHelper
{
    /**
     * {@inheritdoc}
     */
    protected function writePrompt(OutputInterface $output, Question $question)
    {
        $text = OutputFormatter::escapeTrailingBackslash($question->getQuestion());
        $default = $question->getDefault();
        switch (\true) {
            case null === $default:
                $text = \sprintf(' <info>%s</info>:', $text);
                break;
            case $question instanceof ConfirmationQuestion:
                $text = \sprintf(' <info>%s (yes/no)</info> [<comment>%s</comment>]:', $text, $default ? 'yes' : 'no');
                break;
            case $question instanceof ChoiceQuestion && $question->isMultiselect():
                $choices = $question->getChoices();
                $default = \explode(',', $default);
                foreach ($default as $key => $value) {
                    $default[$key] = $choices[\trim($value)];
                }
                $text = \sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape(\implode(', ', $default)));
                break;
            case $question instanceof ChoiceQuestion:
                $choices = $question->getChoices();
                $text = \sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape($choices[$default] ?? $default));
                break;
            default:
                $text = \sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape($default));
        }
        $output->writeln($text);
        $prompt = ' > ';
        if ($question instanceof ChoiceQuestion) {
            $output->writeln($this->formatChoiceQuestionChoices($question, 'comment'));
            $prompt = $question->getPrompt();
        }
        $output->write($prompt);
    }
    /**
     * {@inheritdoc}
     */
    protected function writeError(OutputInterface $output, \Exception $error)
    {
        if ($output instanceof SymfonyStyle) {
            $output->newLine();
            $output->error($error->getMessage());
            return;
        }
        parent::writeError($output, $error);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Helper;

/**
 * HelperInterface is the interface all helpers must implement.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
interface HelperInterface
{
    /**
     * Sets the helper set associated with this helper.
     */
    public function setHelperSet(HelperSet $helperSet = null);
    /**
     * Gets the helper set associated with this helper.
     *
     * @return HelperSet A HelperSet instance
     */
    public function getHelperSet();
    /**
     * Returns the canonical name of this helper.
     *
     * @return string The canonical name
     */
    public function getName();
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Helper;

use CivixPhar\Symfony\Component\Console\Input\InputAwareInterface;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
/**
 * An implementation of InputAwareInterface for Helpers.
 *
 * @author Wouter J <waldio.webdesign@gmail.com>
 */
abstract class InputAwareHelper extends Helper implements InputAwareInterface
{
    protected $input;
    /**
     * {@inheritdoc}
     */
    public function setInput(InputInterface $input)
    {
        $this->input = $input;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Helper;

use CivixPhar\Symfony\Component\Console\Exception\LogicException;
use CivixPhar\Symfony\Component\Console\Output\ConsoleOutputInterface;
use CivixPhar\Symfony\Component\Console\Output\ConsoleSectionOutput;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CivixPhar\Symfony\Component\Console\Terminal;
/**
 * The ProgressBar provides helpers to display progress output.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Chris Jones <leeked@gmail.com>
 */
final class ProgressBar
{
    private $barWidth = 28;
    private $barChar;
    private $emptyBarChar = '-';
    private $progressChar = '>';
    private $format;
    private $internalFormat;
    private $redrawFreq = 1;
    private $writeCount;
    private $lastWriteTime;
    private $minSecondsBetweenRedraws = 0;
    private $maxSecondsBetweenRedraws = 1;
    private $output;
    private $step = 0;
    private $max;
    private $startTime;
    private $stepWidth;
    private $percent = 0.0;
    private $formatLineCount;
    private $messages = [];
    private $overwrite = \true;
    private $terminal;
    private $previousMessage;
    private static $formatters;
    private static $formats;
    /**
     * @param int $max Maximum steps (0 if unknown)
     */
    public function __construct(OutputInterface $output, int $max = 0, float $minSecondsBetweenRedraws = 0.1)
    {
        if ($output instanceof ConsoleOutputInterface) {
            $output = $output->getErrorOutput();
        }
        $this->output = $output;
        $this->setMaxSteps($max);
        $this->terminal = new Terminal();
        if (0 < $minSecondsBetweenRedraws) {
            $this->redrawFreq = null;
            $this->minSecondsBetweenRedraws = $minSecondsBetweenRedraws;
        }
        if (!$this->output->isDecorated()) {
            // disable overwrite when output does not support ANSI codes.
            $this->overwrite = \false;
            // set a reasonable redraw frequency so output isn't flooded
            $this->redrawFreq = null;
        }
        $this->startTime = \time();
    }
    /**
     * Sets a placeholder formatter for a given name.
     *
     * This method also allow you to override an existing placeholder.
     *
     * @param string   $name     The placeholder name (including the delimiter char like %)
     * @param callable $callable A PHP callable
     */
    public static function setPlaceholderFormatterDefinition(string $name, callable $callable) : void
    {
        if (!self::$formatters) {
            self::$formatters = self::initPlaceholderFormatters();
        }
        self::$formatters[$name] = $callable;
    }
    /**
     * Gets the placeholder formatter for a given name.
     *
     * @param string $name The placeholder name (including the delimiter char like %)
     *
     * @return callable|null A PHP callable
     */
    public static function getPlaceholderFormatterDefinition(string $name) : ?callable
    {
        if (!self::$formatters) {
            self::$formatters = self::initPlaceholderFormatters();
        }
        return self::$formatters[$name] ?? null;
    }
    /**
     * Sets a format for a given name.
     *
     * This method also allow you to override an existing format.
     *
     * @param string $name   The format name
     * @param string $format A format string
     */
    public static function setFormatDefinition(string $name, string $format) : void
    {
        if (!self::$formats) {
            self::$formats = self::initFormats();
        }
        self::$formats[$name] = $format;
    }
    /**
     * Gets the format for a given name.
     *
     * @param string $name The format name
     *
     * @return string|null A format string
     */
    public static function getFormatDefinition(string $name) : ?string
    {
        if (!self::$formats) {
            self::$formats = self::initFormats();
        }
        return self::$formats[$name] ?? null;
    }
    /**
     * Associates a text with a named placeholder.
     *
     * The text is displayed when the progress bar is rendered but only
     * when the corresponding placeholder is part of the custom format line
     * (by wrapping the name with %).
     *
     * @param string $message The text to associate with the placeholder
     * @param string $name    The name of the placeholder
     */
    public function setMessage(string $message, string $name = 'message')
    {
        $this->messages[$name] = $message;
    }
    public function getMessage(string $name = 'message')
    {
        return $this->messages[$name];
    }
    public function getStartTime() : int
    {
        return $this->startTime;
    }
    public function getMaxSteps() : int
    {
        return $this->max;
    }
    public function getProgress() : int
    {
        return $this->step;
    }
    private function getStepWidth() : int
    {
        return $this->stepWidth;
    }
    public function getProgressPercent() : float
    {
        return $this->percent;
    }
    public function getBarOffset() : int
    {
        return \floor($this->max ? $this->percent * $this->barWidth : (null === $this->redrawFreq ? (int) (\min(5, $this->barWidth / 15) * $this->writeCount) : $this->step) % $this->barWidth);
    }
    public function setBarWidth(int $size)
    {
        $this->barWidth = \max(1, $size);
    }
    public function getBarWidth() : int
    {
        return $this->barWidth;
    }
    public function setBarCharacter(string $char)
    {
        $this->barChar = $char;
    }
    public function getBarCharacter() : string
    {
        if (null === $this->barChar) {
            return $this->max ? '=' : $this->emptyBarChar;
        }
        return $this->barChar;
    }
    public function setEmptyBarCharacter(string $char)
    {
        $this->emptyBarChar = $char;
    }
    public function getEmptyBarCharacter() : string
    {
        return $this->emptyBarChar;
    }
    public function setProgressCharacter(string $char)
    {
        $this->progressChar = $char;
    }
    public function getProgressCharacter() : string
    {
        return $this->progressChar;
    }
    public function setFormat(string $format)
    {
        $this->format = null;
        $this->internalFormat = $format;
    }
    /**
     * Sets the redraw frequency.
     *
     * @param int|null $freq The frequency in steps
     */
    public function setRedrawFrequency(?int $freq)
    {
        $this->redrawFreq = null !== $freq ? \max(1, $freq) : null;
    }
    public function minSecondsBetweenRedraws(float $seconds) : void
    {
        $this->minSecondsBetweenRedraws = $seconds;
    }
    public function maxSecondsBetweenRedraws(float $seconds) : void
    {
        $this->maxSecondsBetweenRedraws = $seconds;
    }
    /**
     * Returns an iterator that will automatically update the progress bar when iterated.
     *
     * @param int|null $max Number of steps to complete the bar (0 if indeterminate), if null it will be inferred from $iterable
     */
    public function iterate(iterable $iterable, int $max = null) : iterable
    {
        $this->start($max ?? (\is_countable($iterable) ? \count($iterable) : 0));
        foreach ($iterable as $key => $value) {
            (yield $key => $value);
            $this->advance();
        }
        $this->finish();
    }
    /**
     * Starts the progress output.
     *
     * @param int|null $max Number of steps to complete the bar (0 if indeterminate), null to leave unchanged
     */
    public function start(int $max = null)
    {
        $this->startTime = \time();
        $this->step = 0;
        $this->percent = 0.0;
        if (null !== $max) {
            $this->setMaxSteps($max);
        }
        $this->display();
    }
    /**
     * Advances the progress output X steps.
     *
     * @param int $step Number of steps to advance
     */
    public function advance(int $step = 1)
    {
        $this->setProgress($this->step + $step);
    }
    /**
     * Sets whether to overwrite the progressbar, false for new line.
     */
    public function setOverwrite(bool $overwrite)
    {
        $this->overwrite = $overwrite;
    }
    public function setProgress(int $step)
    {
        if ($this->max && $step > $this->max) {
            $this->max = $step;
        } elseif ($step < 0) {
            $step = 0;
        }
        $redrawFreq = $this->redrawFreq ?? ($this->max ?: 10) / 10;
        $prevPeriod = (int) ($this->step / $redrawFreq);
        $currPeriod = (int) ($step / $redrawFreq);
        $this->step = $step;
        $this->percent = $this->max ? (float) $this->step / $this->max : 0;
        $timeInterval = \microtime(\true) - $this->lastWriteTime;
        // Draw regardless of other limits
        if ($this->max === $step) {
            $this->display();
            return;
        }
        // Throttling
        if ($timeInterval < $this->minSecondsBetweenRedraws) {
            return;
        }
        // Draw each step period, but not too late
        if ($prevPeriod !== $currPeriod || $timeInterval >= $this->maxSecondsBetweenRedraws) {
            $this->display();
        }
    }
    public function setMaxSteps(int $max)
    {
        $this->format = null;
        $this->max = \max(0, $max);
        $this->stepWidth = $this->max ? Helper::strlen((string) $this->max) : 4;
    }
    /**
     * Finishes the progress output.
     */
    public function finish() : void
    {
        if (!$this->max) {
            $this->max = $this->step;
        }
        if ($this->step === $this->max && !$this->overwrite) {
            // prevent double 100% output
            return;
        }
        $this->setProgress($this->max);
    }
    /**
     * Outputs the current progress string.
     */
    public function display() : void
    {
        if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
            return;
        }
        if (null === $this->format) {
            $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());
        }
        $this->overwrite($this->buildLine());
    }
    /**
     * Removes the progress bar from the current line.
     *
     * This is useful if you wish to write some output
     * while a progress bar is running.
     * Call display() to show the progress bar again.
     */
    public function clear() : void
    {
        if (!$this->overwrite) {
            return;
        }
        if (null === $this->format) {
            $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());
        }
        $this->overwrite('');
    }
    private function setRealFormat(string $format)
    {
        // try to use the _nomax variant if available
        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");
    }
    /**
     * Overwrites a previous message to the output.
     */
    private function overwrite(string $message) : void
    {
        if ($this->previousMessage === $message) {
            return;
        }
        $originalMessage = $message;
        if ($this->overwrite) {
            if (null !== $this->previousMessage) {
                if ($this->output instanceof ConsoleSectionOutput) {
                    $messageLines = \explode("\n", $message);
                    $lineCount = \count($messageLines);
                    foreach ($messageLines as $messageLine) {
                        $messageLineLength = Helper::strlenWithoutDecoration($this->output->getFormatter(), $messageLine);
                        if ($messageLineLength > $this->terminal->getWidth()) {
                            $lineCount += \floor($messageLineLength / $this->terminal->getWidth());
                        }
                    }
                    $this->output->clear($lineCount);
                } else {
                    // Erase previous lines
                    if ($this->formatLineCount > 0) {
                        $message = \str_repeat("\x1b[1A\x1b[2K", $this->formatLineCount) . $message;
                    }
                    // Move the cursor to the beginning of the line and erase the line
                    $message = "\r\x1b[2K{$message}";
                }
            }
        } elseif ($this->step > 0) {
            $message = \PHP_EOL . $message;
        }
        $this->previousMessage = $originalMessage;
        $this->lastWriteTime = \microtime(\true);
        $this->output->write($message);
        ++$this->writeCount;
    }
    private function determineBestFormat() : string
    {
        switch ($this->output->getVerbosity()) {
            // OutputInterface::VERBOSITY_QUIET: display is disabled anyway
            case OutputInterface::VERBOSITY_VERBOSE:
                return $this->max ? 'verbose' : 'verbose_nomax';
            case OutputInterface::VERBOSITY_VERY_VERBOSE:
                return $this->max ? 'very_verbose' : 'very_verbose_nomax';
            case OutputInterface::VERBOSITY_DEBUG:
                return $this->max ? 'debug' : 'debug_nomax';
            default:
                return $this->max ? 'normal' : 'normal_nomax';
        }
    }
    private static function initPlaceholderFormatters() : array
    {
        return ['bar' => function (self $bar, OutputInterface $output) {
            $completeBars = $bar->getBarOffset();
            $display = \str_repeat($bar->getBarCharacter(), $completeBars);
            if ($completeBars < $bar->getBarWidth()) {
                $emptyBars = $bar->getBarWidth() - $completeBars - Helper::strlenWithoutDecoration($output->getFormatter(), $bar->getProgressCharacter());
                $display .= $bar->getProgressCharacter() . \str_repeat($bar->getEmptyBarCharacter(), $emptyBars);
            }
            return $display;
        }, 'elapsed' => function (self $bar) {
            return Helper::formatTime(\time() - $bar->getStartTime());
        }, 'remaining' => function (self $bar) {
            if (!$bar->getMaxSteps()) {
                throw new LogicException('Unable to display the remaining time if the maximum number of steps is not set.');
            }
            if (!$bar->getProgress()) {
                $remaining = 0;
            } else {
                $remaining = \round((\time() - $bar->getStartTime()) / $bar->getProgress() * ($bar->getMaxSteps() - $bar->getProgress()));
            }
            return Helper::formatTime($remaining);
        }, 'estimated' => function (self $bar) {
            if (!$bar->getMaxSteps()) {
                throw new LogicException('Unable to display the estimated time if the maximum number of steps is not set.');
            }
            if (!$bar->getProgress()) {
                $estimated = 0;
            } else {
                $estimated = \round((\time() - $bar->getStartTime()) / $bar->getProgress() * $bar->getMaxSteps());
            }
            return Helper::formatTime($estimated);
        }, 'memory' => function (self $bar) {
            return Helper::formatMemory(\memory_get_usage(\true));
        }, 'current' => function (self $bar) {
            return \str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', \STR_PAD_LEFT);
        }, 'max' => function (self $bar) {
            return $bar->getMaxSteps();
        }, 'percent' => function (self $bar) {
            return \floor($bar->getProgressPercent() * 100);
        }];
    }
    private static function initFormats() : array
    {
        return ['normal' => ' %current%/%max% [%bar%] %percent:3s%%', 'normal_nomax' => ' %current% [%bar%]', 'verbose' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%', 'verbose_nomax' => ' %current% [%bar%] %elapsed:6s%', 'very_verbose' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%', 'very_verbose_nomax' => ' %current% [%bar%] %elapsed:6s%', 'debug' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%', 'debug_nomax' => ' %current% [%bar%] %elapsed:6s% %memory:6s%'];
    }
    private function buildLine() : string
    {
        $regex = "{%([a-z\\-_]+)(?:\\:([^%]+))?%}i";
        $callback = function ($matches) {
            if ($formatter = $this::getPlaceholderFormatterDefinition($matches[1])) {
                $text = $formatter($this, $this->output);
            } elseif (isset($this->messages[$matches[1]])) {
                $text = $this->messages[$matches[1]];
            } else {
                return $matches[0];
            }
            if (isset($matches[2])) {
                $text = \sprintf('%' . $matches[2], $text);
            }
            return $text;
        };
        $line = \preg_replace_callback($regex, $callback, $this->format);
        // gets string length for each sub line with multiline format
        $linesLength = \array_map(function ($subLine) {
            return Helper::strlenWithoutDecoration($this->output->getFormatter(), \rtrim($subLine, "\r"));
        }, \explode("\n", $line));
        $linesWidth = \max($linesLength);
        $terminalWidth = $this->terminal->getWidth();
        if ($linesWidth <= $terminalWidth) {
            return $line;
        }
        $this->setBarWidth($this->barWidth - $linesWidth + $terminalWidth);
        return \preg_replace_callback($regex, $callback, $this->format);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Helper;

/**
 * Marks a row as being a separator.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class TableSeparator extends TableCell
{
    public function __construct(array $options = [])
    {
        parent::__construct('', $options);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Helper;

use CivixPhar\Symfony\Component\Console\Command\Command;
use CivixPhar\Symfony\Component\Console\Exception\InvalidArgumentException;
/**
 * HelperSet represents a set of helpers to be used with a command.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class HelperSet implements \IteratorAggregate
{
    /**
     * @var Helper[]
     */
    private $helpers = [];
    private $command;
    /**
     * @param Helper[] $helpers An array of helper
     */
    public function __construct(array $helpers = [])
    {
        foreach ($helpers as $alias => $helper) {
            $this->set($helper, \is_int($alias) ? null : $alias);
        }
    }
    /**
     * Sets a helper.
     *
     * @param string $alias An alias
     */
    public function set(HelperInterface $helper, $alias = null)
    {
        $this->helpers[$helper->getName()] = $helper;
        if (null !== $alias) {
            $this->helpers[$alias] = $helper;
        }
        $helper->setHelperSet($this);
    }
    /**
     * Returns true if the helper if defined.
     *
     * @param string $name The helper name
     *
     * @return bool true if the helper is defined, false otherwise
     */
    public function has($name)
    {
        return isset($this->helpers[$name]);
    }
    /**
     * Gets a helper value.
     *
     * @param string $name The helper name
     *
     * @return HelperInterface The helper instance
     *
     * @throws InvalidArgumentException if the helper is not defined
     */
    public function get($name)
    {
        if (!$this->has($name)) {
            throw new InvalidArgumentException(\sprintf('The helper "%s" is not defined.', $name));
        }
        return $this->helpers[$name];
    }
    public function setCommand(Command $command = null)
    {
        $this->command = $command;
    }
    /**
     * Gets the command associated with this helper set.
     *
     * @return Command A Command instance
     */
    public function getCommand()
    {
        return $this->command;
    }
    /**
     * @return \Traversable<Helper>
     */
    #[\ReturnTypeWillChange]
    public function getIterator()
    {
        return new \ArrayIterator($this->helpers);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Helper;

use CivixPhar\Symfony\Component\Console\Exception\InvalidArgumentException;
/**
 * @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
 */
class TableCell
{
    private $value;
    private $options = ['rowspan' => 1, 'colspan' => 1];
    public function __construct(string $value = '', array $options = [])
    {
        $this->value = $value;
        // check option names
        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);
    }
    /**
     * Returns the cell value.
     *
     * @return string
     */
    public function __toString()
    {
        return $this->value;
    }
    /**
     * Gets number of colspan.
     *
     * @return int
     */
    public function getColspan()
    {
        return (int) $this->options['colspan'];
    }
    /**
     * Gets number of rowspan.
     *
     * @return int
     */
    public function getRowspan()
    {
        return (int) $this->options['rowspan'];
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Helper;

use CivixPhar\Symfony\Component\Console\Exception\InvalidArgumentException;
use CivixPhar\Symfony\Component\Console\Exception\LogicException;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
/**
 * @author Kevin Bond <kevinbond@gmail.com>
 */
class ProgressIndicator
{
    private $output;
    private $startTime;
    private $format;
    private $message;
    private $indicatorValues;
    private $indicatorCurrent;
    private $indicatorChangeInterval;
    private $indicatorUpdateTime;
    private $started = \false;
    private static $formatters;
    private static $formats;
    /**
     * @param string|null $format                  Indicator format
     * @param int         $indicatorChangeInterval Change interval in milliseconds
     * @param array|null  $indicatorValues         Animated indicator characters
     */
    public function __construct(OutputInterface $output, string $format = null, int $indicatorChangeInterval = 100, array $indicatorValues = null)
    {
        $this->output = $output;
        if (null === $format) {
            $format = $this->determineBestFormat();
        }
        if (null === $indicatorValues) {
            $indicatorValues = ['-', '\\', '|', '/'];
        }
        $indicatorValues = \array_values($indicatorValues);
        if (2 > \count($indicatorValues)) {
            throw new InvalidArgumentException('Must have at least 2 indicator value characters.');
        }
        $this->format = self::getFormatDefinition($format);
        $this->indicatorChangeInterval = $indicatorChangeInterval;
        $this->indicatorValues = $indicatorValues;
        $this->startTime = \time();
    }
    /**
     * Sets the current indicator message.
     *
     * @param string|null $message
     */
    public function setMessage($message)
    {
        $this->message = $message;
        $this->display();
    }
    /**
     * Starts the indicator output.
     *
     * @param $message
     */
    public function start($message)
    {
        if ($this->started) {
            throw new LogicException('Progress indicator already started.');
        }
        $this->message = $message;
        $this->started = \true;
        $this->startTime = \time();
        $this->indicatorUpdateTime = $this->getCurrentTimeInMilliseconds() + $this->indicatorChangeInterval;
        $this->indicatorCurrent = 0;
        $this->display();
    }
    /**
     * Advances the indicator.
     */
    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();
    }
    /**
     * Finish the indicator with message.
     *
     * @param $message
     */
    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;
    }
    /**
     * Gets the format for a given name.
     *
     * @param string $name The format name
     *
     * @return string|null A format string
     */
    public static function getFormatDefinition($name)
    {
        if (!self::$formats) {
            self::$formats = self::initFormats();
        }
        return self::$formats[$name] ?? null;
    }
    /**
     * Sets a placeholder formatter for a given name.
     *
     * This method also allow you to override an existing placeholder.
     *
     * @param string   $name     The placeholder name (including the delimiter char like %)
     * @param callable $callable A PHP callable
     */
    public static function setPlaceholderFormatterDefinition($name, $callable)
    {
        if (!self::$formatters) {
            self::$formatters = self::initPlaceholderFormatters();
        }
        self::$formatters[$name] = $callable;
    }
    /**
     * Gets the placeholder formatter for a given name.
     *
     * @param string $name The placeholder name (including the delimiter char like %)
     *
     * @return callable|null A PHP callable
     */
    public static function getPlaceholderFormatterDefinition($name)
    {
        if (!self::$formatters) {
            self::$formatters = self::initPlaceholderFormatters();
        }
        return self::$formatters[$name] ?? null;
    }
    private function display()
    {
        if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
            return;
        }
        $this->overwrite(\preg_replace_callback("{%([a-z\\-_]+)(?:\\:([^%]+))?%}i", function ($matches) {
            if ($formatter = self::getPlaceholderFormatterDefinition($matches[1])) {
                return $formatter($this);
            }
            return $matches[0];
        }, $this->format ?? ''));
    }
    private function determineBestFormat() : string
    {
        switch ($this->output->getVerbosity()) {
            // OutputInterface::VERBOSITY_QUIET: display is disabled anyway
            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';
        }
    }
    /**
     * Overwrites a previous message to the output.
     */
    private function overwrite(string $message)
    {
        if ($this->output->isDecorated()) {
            $this->output->write("\r\x1b[2K");
            $this->output->write($message);
        } else {
            $this->output->writeln($message);
        }
    }
    private function getCurrentTimeInMilliseconds() : float
    {
        return \round(\microtime(\true) * 1000);
    }
    private static function initPlaceholderFormatters() : array
    {
        return ['indicator' => function (self $indicator) {
            return $indicator->indicatorValues[$indicator->indicatorCurrent % \count($indicator->indicatorValues)];
        }, 'message' => function (self $indicator) {
            return $indicator->message;
        }, 'elapsed' => function (self $indicator) {
            return Helper::formatTime(\time() - $indicator->startTime);
        }, 'memory' => function () {
            return Helper::formatMemory(\memory_get_usage(\true));
        }];
    }
    private static function initFormats() : array
    {
        return ['normal' => ' %indicator% %message%', 'normal_no_ansi' => ' %message%', 'verbose' => ' %indicator% %message% (%elapsed:6s%)', 'verbose_no_ansi' => ' %message% (%elapsed:6s%)', 'very_verbose' => ' %indicator% %message% (%elapsed:6s%, %memory:6s%)', 'very_verbose_no_ansi' => ' %message% (%elapsed:6s%, %memory:6s%)'];
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Helper;

use CivixPhar\Symfony\Component\Console\Exception\MissingInputException;
use CivixPhar\Symfony\Component\Console\Exception\RuntimeException;
use CivixPhar\Symfony\Component\Console\Formatter\OutputFormatter;
use CivixPhar\Symfony\Component\Console\Formatter\OutputFormatterStyle;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Input\StreamableInputInterface;
use CivixPhar\Symfony\Component\Console\Output\ConsoleOutputInterface;
use CivixPhar\Symfony\Component\Console\Output\ConsoleSectionOutput;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CivixPhar\Symfony\Component\Console\Question\ChoiceQuestion;
use CivixPhar\Symfony\Component\Console\Question\Question;
use CivixPhar\Symfony\Component\Console\Terminal;
/**
 * The QuestionHelper class provides helpers to interact with the user.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class QuestionHelper extends Helper
{
    private $inputStream;
    private static $shell;
    private static $stty = \true;
    private static $stdinIsInteractive;
    /**
     * Asks a question to the user.
     *
     * @return mixed The user answer
     *
     * @throws RuntimeException If there is no data to read in the input stream
     */
    public function ask(InputInterface $input, OutputInterface $output, Question $question)
    {
        if ($output instanceof ConsoleOutputInterface) {
            $output = $output->getErrorOutput();
        }
        if (!$input->isInteractive()) {
            return $this->getDefaultAnswer($question);
        }
        if ($input instanceof StreamableInputInterface && ($stream = $input->getStream())) {
            $this->inputStream = $stream;
        }
        try {
            if (!$question->getValidator()) {
                return $this->doAsk($output, $question);
            }
            $interviewer = function () use($output, $question) {
                return $this->doAsk($output, $question);
            };
            return $this->validateAttempts($interviewer, $output, $question);
        } catch (MissingInputException $exception) {
            $input->setInteractive(\false);
            if (null === ($fallbackOutput = $this->getDefaultAnswer($question))) {
                throw $exception;
            }
            return $fallbackOutput;
        }
    }
    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return 'question';
    }
    /**
     * Prevents usage of stty.
     */
    public static function disableStty()
    {
        self::$stty = \false;
    }
    /**
     * Asks the question to the user.
     *
     * @return mixed
     *
     * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden
     */
    private function doAsk(OutputInterface $output, Question $question)
    {
        $this->writePrompt($output, $question);
        $inputStream = $this->inputStream ?: \STDIN;
        $autocomplete = $question->getAutocompleterCallback();
        if (null === $autocomplete || !self::$stty || !Terminal::hasSttyAvailable()) {
            $ret = \false;
            if ($question->isHidden()) {
                try {
                    $hiddenResponse = $this->getHiddenResponse($output, $inputStream, $question->isTrimmable());
                    $ret = $question->isTrimmable() ? \trim($hiddenResponse) : $hiddenResponse;
                } catch (RuntimeException $e) {
                    if (!$question->isHiddenFallback()) {
                        throw $e;
                    }
                }
            }
            if (\false === $ret) {
                $cp = $this->setIOCodepage();
                $ret = \fgets($inputStream, 4096);
                $ret = $this->resetIOCodepage($cp, $ret);
                if (\false === $ret) {
                    throw new MissingInputException('Aborted.');
                }
                if ($question->isTrimmable()) {
                    $ret = \trim($ret);
                }
            }
        } else {
            $autocomplete = $this->autocomplete($output, $question, $inputStream, $autocomplete);
            $ret = $question->isTrimmable() ? \trim($autocomplete) : $autocomplete;
        }
        if ($output instanceof ConsoleSectionOutput) {
            $output->addContent($ret);
        }
        $ret = \strlen($ret) > 0 ? $ret : $question->getDefault();
        if ($normalizer = $question->getNormalizer()) {
            return $normalizer($ret);
        }
        return $ret;
    }
    /**
     * @return mixed
     */
    private function getDefaultAnswer(Question $question)
    {
        $default = $question->getDefault();
        if (null === $default) {
            return $default;
        }
        if ($validator = $question->getValidator()) {
            return \call_user_func($question->getValidator(), $default);
        } elseif ($question instanceof ChoiceQuestion) {
            $choices = $question->getChoices();
            if (!$question->isMultiselect()) {
                return $choices[$default] ?? $default;
            }
            $default = \explode(',', $default);
            foreach ($default as $k => $v) {
                $v = $question->isTrimmable() ? \trim($v) : $v;
                $default[$k] = $choices[$v] ?? $v;
            }
        }
        return $default;
    }
    /**
     * Outputs the question prompt.
     */
    protected function writePrompt(OutputInterface $output, Question $question)
    {
        $message = $question->getQuestion();
        if ($question instanceof ChoiceQuestion) {
            $output->writeln(\array_merge([$question->getQuestion()], $this->formatChoiceQuestionChoices($question, 'info')));
            $message = $question->getPrompt();
        }
        $output->write($message);
    }
    /**
     * @param string $tag
     *
     * @return string[]
     */
    protected function formatChoiceQuestionChoices(ChoiceQuestion $question, $tag)
    {
        $messages = [];
        $maxWidth = \max(\array_map([__CLASS__, 'strlen'], \array_keys($choices = $question->getChoices())));
        foreach ($choices as $key => $value) {
            $padding = \str_repeat(' ', $maxWidth - self::strlen($key));
            $messages[] = \sprintf("  [<{$tag}>%s{$padding}</{$tag}>] %s", $key, $value);
        }
        return $messages;
    }
    /**
     * Outputs an error 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);
    }
    /**
     * Autocompletes a question.
     *
     * @param resource $inputStream
     */
    private function autocomplete(OutputInterface $output, Question $question, $inputStream, callable $autocomplete) : string
    {
        $fullChoice = '';
        $ret = '';
        $i = 0;
        $ofs = -1;
        $matches = $autocomplete($ret);
        $numMatches = \count($matches);
        $sttyMode = \shell_exec('stty -g');
        // Disable icanon (so we can fread each keypress) and echo (we'll do echoing here instead)
        \shell_exec('stty -icanon -echo');
        // Add highlighted text style
        $output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white'));
        // Read a keypress
        while (!\feof($inputStream)) {
            $c = \fread($inputStream, 1);
            // as opposed to fgets(), fread() returns an empty string when the stream content is empty, not false.
            if (\false === $c || '' === $ret && '' === $c && null === $question->getDefault()) {
                \shell_exec(\sprintf('stty %s', $sttyMode));
                throw new MissingInputException('Aborted.');
            } elseif ("" === $c) {
                // Backspace Character
                if (0 === $numMatches && 0 !== $i) {
                    --$i;
                    $fullChoice = self::substr($fullChoice, 0, $i);
                    // Move cursor backwards
                    $output->write("\x1b[1D");
                }
                if (0 === $i) {
                    $ofs = -1;
                    $matches = $autocomplete($ret);
                    $numMatches = \count($matches);
                } else {
                    $numMatches = 0;
                }
                // Pop the last character off the end of our string
                $ret = self::substr($ret, 0, $i);
            } elseif ("\x1b" === $c) {
                // Did we read an escape sequence?
                $c .= \fread($inputStream, 2);
                // A = Up Arrow. B = Down Arrow
                if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) {
                    if ('A' === $c[2] && -1 === $ofs) {
                        $ofs = 0;
                    }
                    if (0 === $numMatches) {
                        continue;
                    }
                    $ofs += 'A' === $c[2] ? -1 : 1;
                    $ofs = ($numMatches + $ofs) % $numMatches;
                }
            } elseif (\ord($c) < 32) {
                if ("\t" === $c || "\n" === $c) {
                    if ($numMatches > 0 && -1 !== $ofs) {
                        $ret = (string) $matches[$ofs];
                        // Echo out remaining chars for current match
                        $remainingCharacters = \substr($ret, \strlen(\trim($this->mostRecentlyEnteredValue($fullChoice))));
                        $output->write($remainingCharacters);
                        $fullChoice .= $remainingCharacters;
                        $i = \false === ($encoding = \mb_detect_encoding($fullChoice, null, \true)) ? \strlen($fullChoice) : \mb_strlen($fullChoice, $encoding);
                        $matches = \array_filter($autocomplete($ret), function ($match) use($ret) {
                            return '' === $ret || \str_starts_with($match, $ret);
                        });
                        $numMatches = \count($matches);
                        $ofs = -1;
                    }
                    if ("\n" === $c) {
                        $output->write($c);
                        break;
                    }
                    $numMatches = 0;
                }
                continue;
            } else {
                if ("\x80" <= $c) {
                    $c .= \fread($inputStream, ["\xc0" => 1, "\xd0" => 1, "\xe0" => 2, "\xf0" => 3][$c & "\xf0"]);
                }
                $output->write($c);
                $ret .= $c;
                $fullChoice .= $c;
                ++$i;
                $tempRet = $ret;
                if ($question instanceof ChoiceQuestion && $question->isMultiselect()) {
                    $tempRet = $this->mostRecentlyEnteredValue($fullChoice);
                }
                $numMatches = 0;
                $ofs = 0;
                foreach ($autocomplete($ret) as $value) {
                    // If typed characters match the beginning chunk of value (e.g. [AcmeDe]moBundle)
                    if (\str_starts_with($value, $tempRet)) {
                        $matches[$numMatches++] = $value;
                    }
                }
            }
            // Erase characters from cursor to end of line
            $output->write("\x1b[K");
            if ($numMatches > 0 && -1 !== $ofs) {
                // Save cursor position
                $output->write("\x1b7");
                // Write highlighted text, complete the partially entered response
                $charactersEntered = \strlen(\trim($this->mostRecentlyEnteredValue($fullChoice)));
                $output->write('<hl>' . OutputFormatter::escapeTrailingBackslash(\substr($matches[$ofs], $charactersEntered)) . '</hl>');
                // Restore cursor position
                $output->write("\x1b8");
            }
        }
        // Reset stty so it behaves normally again
        \shell_exec(\sprintf('stty %s', $sttyMode));
        return $fullChoice;
    }
    private function mostRecentlyEnteredValue(string $entered) : string
    {
        // Determine the most recent value that the user entered
        if (!\str_contains($entered, ',')) {
            return $entered;
        }
        $choices = \explode(',', $entered);
        if ('' !== ($lastChoice = \trim($choices[\count($choices) - 1]))) {
            return $lastChoice;
        }
        return $entered;
    }
    /**
     * Gets a hidden response from user.
     *
     * @param resource $inputStream The handler resource
     * @param bool     $trimmable   Is the answer trimmable
     *
     * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden
     */
    private function getHiddenResponse(OutputInterface $output, $inputStream, bool $trimmable = \true) : string
    {
        if ('\\' === \DIRECTORY_SEPARATOR) {
            $exe = __DIR__ . '/../Resources/bin/hiddeninput.exe';
            // handle code running from a phar
            if ('phar:' === \substr(__FILE__, 0, 5)) {
                $tmpExe = \sys_get_temp_dir() . '/hiddeninput.exe';
                \copy($exe, $tmpExe);
                $exe = $tmpExe;
            }
            $sExec = \shell_exec('"' . $exe . '"');
            $value = $trimmable ? \rtrim($sExec) : $sExec;
            $output->writeln('');
            if (isset($tmpExe)) {
                \unlink($tmpExe);
            }
            return $value;
        }
        if (self::$stty && Terminal::hasSttyAvailable()) {
            $sttyMode = \shell_exec('stty -g');
            \shell_exec('stty -echo');
        } elseif ($this->isInteractiveInput($inputStream)) {
            throw new RuntimeException('Unable to hide the response.');
        }
        $value = \fgets($inputStream, 4096);
        if (self::$stty && Terminal::hasSttyAvailable()) {
            \shell_exec(\sprintf('stty %s', $sttyMode));
        }
        if (\false === $value) {
            throw new MissingInputException('Aborted.');
        }
        if ($trimmable) {
            $value = \trim($value);
        }
        $output->writeln('');
        return $value;
    }
    /**
     * Validates an attempt.
     *
     * @param callable $interviewer A callable that will ask for a question and return the result
     *
     * @return mixed The validated response
     *
     * @throws \Exception In case the max number of attempts has been reached and no valid response has been given
     */
    private function validateAttempts(callable $interviewer, OutputInterface $output, Question $question)
    {
        $error = null;
        $attempts = $question->getMaxAttempts();
        while (null === $attempts || $attempts--) {
            if (null !== $error) {
                $this->writeError($output, $error);
            }
            try {
                return $question->getValidator()($interviewer());
            } catch (RuntimeException $e) {
                throw $e;
            } catch (\Exception $error) {
            }
        }
        throw $error;
    }
    private function isInteractiveInput($inputStream) : bool
    {
        if ('php://stdin' !== (\stream_get_meta_data($inputStream)['uri'] ?? null)) {
            return \false;
        }
        if (null !== self::$stdinIsInteractive) {
            return self::$stdinIsInteractive;
        }
        if (\function_exists('stream_isatty')) {
            return self::$stdinIsInteractive = \stream_isatty(\fopen('php://stdin', 'r'));
        }
        if (\function_exists('posix_isatty')) {
            return self::$stdinIsInteractive = \posix_isatty(\fopen('php://stdin', 'r'));
        }
        if (!\function_exists('exec')) {
            return self::$stdinIsInteractive = \true;
        }
        \exec('stty 2> /dev/null', $output, $status);
        return self::$stdinIsInteractive = 1 !== $status;
    }
    /**
     * Sets console I/O to the host code page.
     *
     * @return int Previous code page in IBM/EBCDIC format
     */
    private function setIOCodepage() : int
    {
        if (\function_exists('sapi_windows_cp_set')) {
            $cp = \sapi_windows_cp_get();
            \sapi_windows_cp_set(\sapi_windows_cp_get('oem'));
            return $cp;
        }
        return 0;
    }
    /**
     * Sets console I/O to the specified code page and converts the user input.
     *
     * @param string|false $input
     *
     * @return string|false
     */
    private function resetIOCodepage(int $cp, $input)
    {
        if (0 !== $cp) {
            \sapi_windows_cp_set($cp);
            if (\false !== $input && '' !== $input) {
                $input = \sapi_windows_cp_conv(\sapi_windows_cp_get('oem'), $cp, $input);
            }
        }
        return $input;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Helper;

use CivixPhar\Symfony\Component\Console\Exception\InvalidArgumentException;
use CivixPhar\Symfony\Component\Console\Exception\LogicException;
/**
 * Defines the styles for a Table.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Ð¡Ð°ÑˆÐ° Ð¡Ñ‚Ð°Ð¼ÐµÐ½ÐºÐ¾Ð²Ð¸Ñ› <umpirsky@gmail.com>
 * @author Dany Maillard <danymaillard93b@gmail.com>
 */
class TableStyle
{
    private $paddingChar = ' ';
    private $horizontalOutsideBorderChar = '-';
    private $horizontalInsideBorderChar = '-';
    private $verticalOutsideBorderChar = '|';
    private $verticalInsideBorderChar = '|';
    private $crossingChar = '+';
    private $crossingTopRightChar = '+';
    private $crossingTopMidChar = '+';
    private $crossingTopLeftChar = '+';
    private $crossingMidRightChar = '+';
    private $crossingBottomRightChar = '+';
    private $crossingBottomMidChar = '+';
    private $crossingBottomLeftChar = '+';
    private $crossingMidLeftChar = '+';
    private $crossingTopLeftBottomChar = '+';
    private $crossingTopMidBottomChar = '+';
    private $crossingTopRightBottomChar = '+';
    private $headerTitleFormat = '<fg=black;bg=white;options=bold> %s </>';
    private $footerTitleFormat = '<fg=black;bg=white;options=bold> %s </>';
    private $cellHeaderFormat = '<info>%s</info>';
    private $cellRowFormat = '%s';
    private $cellRowContentFormat = ' %s ';
    private $borderFormat = '%s';
    private $padType = \STR_PAD_RIGHT;
    /**
     * Sets padding character, used for cell padding.
     *
     * @param string $paddingChar
     *
     * @return $this
     */
    public function setPaddingChar($paddingChar)
    {
        if (!$paddingChar) {
            throw new LogicException('The padding char must not be empty.');
        }
        $this->paddingChar = $paddingChar;
        return $this;
    }
    /**
     * Gets padding character, used for cell padding.
     *
     * @return string
     */
    public function getPaddingChar()
    {
        return $this->paddingChar;
    }
    /**
     * Sets horizontal border characters.
     *
     * <code>
     * â•”â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•¤â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•¤â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•—
     * 1 ISBN          2 Title                    â”‚ Author           â•‘
     * â• â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•ªâ•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•ªâ•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•£
     * â•‘ 99921-58-10-7 â”‚ Divine Comedy            â”‚ Dante Alighieri  â•‘
     * â•‘ 9971-5-0210-0 â”‚ A Tale of Two Cities     â”‚ Charles Dickens  â•‘
     * â•‘ 960-425-059-0 â”‚ The Lord of the Rings    â”‚ J. R. R. Tolkien â•‘
     * â•‘ 80-902734-1-6 â”‚ And Then There Were None â”‚ Agatha Christie  â•‘
     * â•šâ•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•§â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•§â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
     * </code>
     *
     * @param string      $outside Outside border char (see #1 of example)
     * @param string|null $inside  Inside border char (see #2 of example), equals $outside if null
     */
    public function setHorizontalBorderChars(string $outside, string $inside = null) : self
    {
        $this->horizontalOutsideBorderChar = $outside;
        $this->horizontalInsideBorderChar = $inside ?? $outside;
        return $this;
    }
    /**
     * Sets horizontal border character.
     *
     * @param string $horizontalBorderChar
     *
     * @return $this
     *
     * @deprecated since Symfony 4.1, use {@link setHorizontalBorderChars()} instead.
     */
    public function setHorizontalBorderChar($horizontalBorderChar)
    {
        @\trigger_error(\sprintf('The "%s()" method is deprecated since Symfony 4.1, use setHorizontalBorderChars() instead.', __METHOD__), \E_USER_DEPRECATED);
        return $this->setHorizontalBorderChars($horizontalBorderChar, $horizontalBorderChar);
    }
    /**
     * Gets horizontal border character.
     *
     * @return string
     *
     * @deprecated since Symfony 4.1, use {@link getBorderChars()} instead.
     */
    public function getHorizontalBorderChar()
    {
        @\trigger_error(\sprintf('The "%s()" method is deprecated since Symfony 4.1, use getBorderChars() instead.', __METHOD__), \E_USER_DEPRECATED);
        return $this->horizontalOutsideBorderChar;
    }
    /**
     * Sets vertical border characters.
     *
     * <code>
     * â•”â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•¤â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•¤â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•—
     * â•‘ ISBN          â”‚ Title                    â”‚ Author           â•‘
     * â• â•�â•�â•�â•�â•�â•�â•�1â•�â•�â•�â•�â•�â•�â•�â•ªâ•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•ªâ•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•£
     * â•‘ 99921-58-10-7 â”‚ Divine Comedy            â”‚ Dante Alighieri  â•‘
     * â•‘ 9971-5-0210-0 â”‚ A Tale of Two Cities     â”‚ Charles Dickens  â•‘
     * â•Ÿâ”€â”€â”€â”€â”€â”€â”€2â”€â”€â”€â”€â”€â”€â”€â”¼â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¼â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â•¢
     * â•‘ 960-425-059-0 â”‚ The Lord of the Rings    â”‚ J. R. R. Tolkien â•‘
     * â•‘ 80-902734-1-6 â”‚ And Then There Were None â”‚ Agatha Christie  â•‘
     * â•šâ•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•§â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•§â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�
     * </code>
     *
     * @param string      $outside Outside border char (see #1 of example)
     * @param string|null $inside  Inside border char (see #2 of example), equals $outside if null
     */
    public function setVerticalBorderChars(string $outside, string $inside = null) : self
    {
        $this->verticalOutsideBorderChar = $outside;
        $this->verticalInsideBorderChar = $inside ?? $outside;
        return $this;
    }
    /**
     * Sets vertical border character.
     *
     * @param string $verticalBorderChar
     *
     * @return $this
     *
     * @deprecated since Symfony 4.1, use {@link setVerticalBorderChars()} instead.
     */
    public function setVerticalBorderChar($verticalBorderChar)
    {
        @\trigger_error(\sprintf('The "%s()" method is deprecated since Symfony 4.1, use setVerticalBorderChars() instead.', __METHOD__), \E_USER_DEPRECATED);
        return $this->setVerticalBorderChars($verticalBorderChar, $verticalBorderChar);
    }
    /**
     * Gets vertical border character.
     *
     * @return string
     *
     * @deprecated since Symfony 4.1, use {@link getBorderChars()} instead.
     */
    public function getVerticalBorderChar()
    {
        @\trigger_error(\sprintf('The "%s()" method is deprecated since Symfony 4.1, use getBorderChars() instead.', __METHOD__), \E_USER_DEPRECATED);
        return $this->verticalOutsideBorderChar;
    }
    /**
     * Gets border characters.
     *
     * @internal
     */
    public function getBorderChars() : array
    {
        return [$this->horizontalOutsideBorderChar, $this->verticalOutsideBorderChar, $this->horizontalInsideBorderChar, $this->verticalInsideBorderChar];
    }
    /**
     * Sets crossing characters.
     *
     * Example:
     * <code>
     * 1â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�2â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�2â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�3
     * â•‘ ISBN          â”‚ Title                    â”‚ Author           â•‘
     * 8'â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�0'â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�0'â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�4'
     * â•‘ 99921-58-10-7 â”‚ Divine Comedy            â”‚ Dante Alighieri  â•‘
     * â•‘ 9971-5-0210-0 â”‚ A Tale of Two Cities     â”‚ Charles Dickens  â•‘
     * 8â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€0â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€0â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€4
     * â•‘ 960-425-059-0 â”‚ The Lord of the Rings    â”‚ J. R. R. Tolkien â•‘
     * â•‘ 80-902734-1-6 â”‚ And Then There Were None â”‚ Agatha Christie  â•‘
     * 7â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�6â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�6â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�â•�5
     * </code>
     *
     * @param string      $cross          Crossing char (see #0 of example)
     * @param string      $topLeft        Top left char (see #1 of example)
     * @param string      $topMid         Top mid char (see #2 of example)
     * @param string      $topRight       Top right char (see #3 of example)
     * @param string      $midRight       Mid right char (see #4 of example)
     * @param string      $bottomRight    Bottom right char (see #5 of example)
     * @param string      $bottomMid      Bottom mid char (see #6 of example)
     * @param string      $bottomLeft     Bottom left char (see #7 of example)
     * @param string      $midLeft        Mid left char (see #8 of example)
     * @param string|null $topLeftBottom  Top left bottom char (see #8' of example), equals to $midLeft if null
     * @param string|null $topMidBottom   Top mid bottom char (see #0' of example), equals to $cross if null
     * @param string|null $topRightBottom Top right bottom char (see #4' of example), equals to $midRight if null
     */
    public function setCrossingChars(string $cross, string $topLeft, string $topMid, string $topRight, string $midRight, string $bottomRight, string $bottomMid, string $bottomLeft, string $midLeft, string $topLeftBottom = null, string $topMidBottom = null, string $topRightBottom = null) : self
    {
        $this->crossingChar = $cross;
        $this->crossingTopLeftChar = $topLeft;
        $this->crossingTopMidChar = $topMid;
        $this->crossingTopRightChar = $topRight;
        $this->crossingMidRightChar = $midRight;
        $this->crossingBottomRightChar = $bottomRight;
        $this->crossingBottomMidChar = $bottomMid;
        $this->crossingBottomLeftChar = $bottomLeft;
        $this->crossingMidLeftChar = $midLeft;
        $this->crossingTopLeftBottomChar = $topLeftBottom ?? $midLeft;
        $this->crossingTopMidBottomChar = $topMidBottom ?? $cross;
        $this->crossingTopRightBottomChar = $topRightBottom ?? $midRight;
        return $this;
    }
    /**
     * Sets default crossing character used for each cross.
     *
     * @see {@link setCrossingChars()} for setting each crossing individually.
     */
    public function setDefaultCrossingChar(string $char) : self
    {
        return $this->setCrossingChars($char, $char, $char, $char, $char, $char, $char, $char, $char);
    }
    /**
     * Sets crossing character.
     *
     * @param string $crossingChar
     *
     * @return $this
     *
     * @deprecated since Symfony 4.1. Use {@link setDefaultCrossingChar()} instead.
     */
    public function setCrossingChar($crossingChar)
    {
        @\trigger_error(\sprintf('The "%s()" method is deprecated since Symfony 4.1. Use setDefaultCrossingChar() instead.', __METHOD__), \E_USER_DEPRECATED);
        return $this->setDefaultCrossingChar($crossingChar);
    }
    /**
     * Gets crossing character.
     *
     * @return string
     */
    public function getCrossingChar()
    {
        return $this->crossingChar;
    }
    /**
     * Gets crossing characters.
     *
     * @internal
     */
    public function getCrossingChars() : array
    {
        return [$this->crossingChar, $this->crossingTopLeftChar, $this->crossingTopMidChar, $this->crossingTopRightChar, $this->crossingMidRightChar, $this->crossingBottomRightChar, $this->crossingBottomMidChar, $this->crossingBottomLeftChar, $this->crossingMidLeftChar, $this->crossingTopLeftBottomChar, $this->crossingTopMidBottomChar, $this->crossingTopRightBottomChar];
    }
    /**
     * Sets header cell format.
     *
     * @param string $cellHeaderFormat
     *
     * @return $this
     */
    public function setCellHeaderFormat($cellHeaderFormat)
    {
        $this->cellHeaderFormat = $cellHeaderFormat;
        return $this;
    }
    /**
     * Gets header cell format.
     *
     * @return string
     */
    public function getCellHeaderFormat()
    {
        return $this->cellHeaderFormat;
    }
    /**
     * Sets row cell format.
     *
     * @param string $cellRowFormat
     *
     * @return $this
     */
    public function setCellRowFormat($cellRowFormat)
    {
        $this->cellRowFormat = $cellRowFormat;
        return $this;
    }
    /**
     * Gets row cell format.
     *
     * @return string
     */
    public function getCellRowFormat()
    {
        return $this->cellRowFormat;
    }
    /**
     * Sets row cell content format.
     *
     * @param string $cellRowContentFormat
     *
     * @return $this
     */
    public function setCellRowContentFormat($cellRowContentFormat)
    {
        $this->cellRowContentFormat = $cellRowContentFormat;
        return $this;
    }
    /**
     * Gets row cell content format.
     *
     * @return string
     */
    public function getCellRowContentFormat()
    {
        return $this->cellRowContentFormat;
    }
    /**
     * Sets table border format.
     *
     * @param string $borderFormat
     *
     * @return $this
     */
    public function setBorderFormat($borderFormat)
    {
        $this->borderFormat = $borderFormat;
        return $this;
    }
    /**
     * Gets table border format.
     *
     * @return string
     */
    public function getBorderFormat()
    {
        return $this->borderFormat;
    }
    /**
     * Sets cell padding type.
     *
     * @param int $padType STR_PAD_*
     *
     * @return $this
     */
    public function setPadType($padType)
    {
        if (!\in_array($padType, [\STR_PAD_LEFT, \STR_PAD_RIGHT, \STR_PAD_BOTH], \true)) {
            throw new InvalidArgumentException('Invalid padding type. Expected one of (STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH).');
        }
        $this->padType = $padType;
        return $this;
    }
    /**
     * Gets cell padding type.
     *
     * @return int
     */
    public function getPadType()
    {
        return $this->padType;
    }
    public function getHeaderTitleFormat() : string
    {
        return $this->headerTitleFormat;
    }
    public function setHeaderTitleFormat(string $format) : self
    {
        $this->headerTitleFormat = $format;
        return $this;
    }
    public function getFooterTitleFormat() : string
    {
        return $this->footerTitleFormat;
    }
    public function setFooterTitleFormat(string $format) : self
    {
        $this->footerTitleFormat = $format;
        return $this;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Helper;

use CivixPhar\Symfony\Component\Console\Formatter\OutputFormatter;
/**
 * The Formatter class provides helpers to format messages.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class FormatterHelper extends Helper
{
    /**
     * Formats a message within a section.
     *
     * @param string $section The section name
     * @param string $message The message
     * @param string $style   The style to apply to the section
     *
     * @return string The format section
     */
    public function formatSection($section, $message, $style = 'info')
    {
        return \sprintf('<%s>[%s]</%s> %s', $style, $section, $style, $message);
    }
    /**
     * Formats a message as a block of text.
     *
     * @param string|array $messages The message to write in the block
     * @param string       $style    The style to apply to the whole block
     * @param bool         $large    Whether to return a large block
     *
     * @return string The formatter message
     */
    public function formatBlock($messages, $style, $large = \false)
    {
        if (!\is_array($messages)) {
            $messages = [$messages];
        }
        $len = 0;
        $lines = [];
        foreach ($messages as $message) {
            $message = OutputFormatter::escape($message);
            $lines[] = \sprintf($large ? '  %s  ' : ' %s ', $message);
            $len = \max(self::strlen($message) + ($large ? 4 : 2), $len);
        }
        $messages = $large ? [\str_repeat(' ', $len)] : [];
        for ($i = 0; isset($lines[$i]); ++$i) {
            $messages[] = $lines[$i] . \str_repeat(' ', $len - self::strlen($lines[$i]));
        }
        if ($large) {
            $messages[] = \str_repeat(' ', $len);
        }
        for ($i = 0; isset($messages[$i]); ++$i) {
            $messages[$i] = \sprintf('<%s>%s</%s>', $style, $messages[$i], $style);
        }
        return \implode("\n", $messages);
    }
    /**
     * Truncates a message to the given length.
     *
     * @param string $message
     * @param int    $length
     * @param string $suffix
     *
     * @return string
     */
    public function truncate($message, $length, $suffix = '...')
    {
        $computedLength = $length - self::strlen($suffix);
        if ($computedLength > self::strlen($message)) {
            return $message;
        }
        return self::substr($message, 0, $length) . $suffix;
    }
    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return 'formatter';
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Helper;

use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CivixPhar\Symfony\Component\VarDumper\Cloner\ClonerInterface;
use CivixPhar\Symfony\Component\VarDumper\Cloner\VarCloner;
use CivixPhar\Symfony\Component\VarDumper\Dumper\CliDumper;
/**
 * @author Roland Franssen <franssen.roland@gmail.com>
 */
final class Dumper
{
    private $output;
    private $dumper;
    private $cloner;
    private $handler;
    public function __construct(OutputInterface $output, CliDumper $dumper = null, ClonerInterface $cloner = null)
    {
        $this->output = $output;
        $this->dumper = $dumper;
        $this->cloner = $cloner;
        if (\class_exists(CliDumper::class)) {
            $this->handler = function ($var) : string {
                $dumper = $this->dumper ?? ($this->dumper = new CliDumper(null, null, CliDumper::DUMP_LIGHT_ARRAY | CliDumper::DUMP_COMMA_SEPARATOR));
                $dumper->setColors($this->output->isDecorated());
                return \rtrim($dumper->dump(($this->cloner ?? ($this->cloner = new VarCloner()))->cloneVar($var)->withRefHandles(\false), \true));
            };
        } else {
            $this->handler = function ($var) : string {
                switch (\true) {
                    case null === $var:
                        return 'null';
                    case \true === $var:
                        return 'true';
                    case \false === $var:
                        return 'false';
                    case \is_string($var):
                        return '"' . $var . '"';
                    default:
                        return \rtrim(\print_r($var, \true));
                }
            };
        }
    }
    public function __invoke($var) : string
    {
        return ($this->handler)($var);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Helper;

use CivixPhar\Symfony\Component\Console\Output\ConsoleOutputInterface;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CivixPhar\Symfony\Component\Process\Exception\ProcessFailedException;
use CivixPhar\Symfony\Component\Process\Process;
/**
 * The ProcessHelper class provides helpers to run external processes.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 *
 * @final since Symfony 4.2
 */
class ProcessHelper extends Helper
{
    /**
     * Runs an external process.
     *
     * @param array|Process $cmd       An instance of Process or an array of the command and arguments
     * @param string|null   $error     An error message that must be displayed if something went wrong
     * @param callable|null $callback  A PHP callback to run whenever there is some
     *                                 output available on STDOUT or STDERR
     * @param int           $verbosity The threshold for verbosity
     *
     * @return Process The process that ran
     */
    public function run(OutputInterface $output, $cmd, $error = null, callable $callback = null, $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE)
    {
        if (!\class_exists(Process::class)) {
            throw new \LogicException('The ProcessHelper cannot be run as the Process component is not installed. Try running "compose require symfony/process".');
        }
        if ($output instanceof ConsoleOutputInterface) {
            $output = $output->getErrorOutput();
        }
        $formatter = $this->getHelperSet()->get('debug_formatter');
        if ($cmd instanceof Process) {
            $cmd = [$cmd];
        }
        if (!\is_array($cmd)) {
            @\trigger_error(\sprintf('Passing a command as a string to "%s()" is deprecated since Symfony 4.2, pass it the command as an array of arguments instead.', __METHOD__), \E_USER_DEPRECATED);
            $cmd = [\method_exists(Process::class, 'fromShellCommandline') ? Process::fromShellCommandline($cmd) : new Process($cmd)];
        }
        if (\is_string($cmd[0] ?? null)) {
            $process = new Process($cmd);
            $cmd = [];
        } elseif (($cmd[0] ?? null) instanceof Process) {
            $process = $cmd[0];
            unset($cmd[0]);
        } else {
            throw new \InvalidArgumentException(\sprintf('Invalid command provided to "%s()": the command should be an array whose first element is either the path to the binary to run or a "Process" object.', __METHOD__));
        }
        if ($verbosity <= $output->getVerbosity()) {
            $output->write($formatter->start(\spl_object_hash($process), $this->escapeString($process->getCommandLine())));
        }
        if ($output->isDebug()) {
            $callback = $this->wrapCallback($output, $process, $callback);
        }
        $process->run($callback, $cmd);
        if ($verbosity <= $output->getVerbosity()) {
            $message = $process->isSuccessful() ? 'Command ran successfully' : \sprintf('%s Command did not run successfully', $process->getExitCode());
            $output->write($formatter->stop(\spl_object_hash($process), $message, $process->isSuccessful()));
        }
        if (!$process->isSuccessful() && null !== $error) {
            $output->writeln(\sprintf('<error>%s</error>', $this->escapeString($error)));
        }
        return $process;
    }
    /**
     * Runs the process.
     *
     * This is identical to run() except that an exception is thrown if the process
     * exits with a non-zero exit code.
     *
     * @param string|Process $cmd      An instance of Process or a command to run
     * @param string|null    $error    An error message that must be displayed if something went wrong
     * @param callable|null  $callback A PHP callback to run whenever there is some
     *                                 output available on STDOUT or STDERR
     *
     * @return Process The process that ran
     *
     * @throws ProcessFailedException
     *
     * @see run()
     */
    public function mustRun(OutputInterface $output, $cmd, $error = null, callable $callback = null)
    {
        $process = $this->run($output, $cmd, $error, $callback);
        if (!$process->isSuccessful()) {
            throw new ProcessFailedException($process);
        }
        return $process;
    }
    /**
     * Wraps a Process callback to add debugging output.
     *
     * @return callable
     */
    public function wrapCallback(OutputInterface $output, Process $process, callable $callback = null)
    {
        if ($output instanceof ConsoleOutputInterface) {
            $output = $output->getErrorOutput();
        }
        $formatter = $this->getHelperSet()->get('debug_formatter');
        return function ($type, $buffer) use($output, $process, $callback, $formatter) {
            $output->write($formatter->progress(\spl_object_hash($process), $this->escapeString($buffer), Process::ERR === $type));
            if (null !== $callback) {
                $callback($type, $buffer);
            }
        };
    }
    private function escapeString(string $str) : string
    {
        return \str_replace('<', '\\<', $str);
    }
    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return 'process';
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Helper;

/**
 * Helps outputting debug information when running an external program from a command.
 *
 * An external program can be a Process, an HTTP request, or anything else.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class DebugFormatterHelper extends Helper
{
    private $colors = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'default'];
    private $started = [];
    private $count = -1;
    /**
     * Starts a debug formatting session.
     *
     * @param string $id      The id of the formatting session
     * @param string $message The message to display
     * @param string $prefix  The prefix to use
     *
     * @return string
     */
    public function start($id, $message, $prefix = 'RUN')
    {
        $this->started[$id] = ['border' => ++$this->count % \count($this->colors)];
        return \sprintf("%s<bg=blue;fg=white> %s </> <fg=blue>%s</>\n", $this->getBorder($id), $prefix, $message);
    }
    /**
     * Adds progress to a formatting session.
     *
     * @param string $id          The id of the formatting session
     * @param string $buffer      The message to display
     * @param bool   $error       Whether to consider the buffer as error
     * @param string $prefix      The prefix for output
     * @param string $errorPrefix The prefix for error output
     *
     * @return string
     */
    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;
    }
    /**
     * Stops a formatting session.
     *
     * @param string $id         The id of the formatting session
     * @param string $message    The message to display
     * @param bool   $successful Whether to consider the result as success
     * @param string $prefix     The prefix for the end output
     *
     * @return string
     */
    public function stop($id, $message, $successful, $prefix = 'RES')
    {
        $trailingEOL = isset($this->started[$id]['out']) || isset($this->started[$id]['err']) ? "\n" : '';
        if ($successful) {
            return \sprintf("%s%s<bg=green;fg=white> %s </> <fg=green>%s</>\n", $trailingEOL, $this->getBorder($id), $prefix, $message);
        }
        $message = \sprintf("%s%s<bg=red;fg=white> %s </> <fg=red>%s</>\n", $trailingEOL, $this->getBorder($id), $prefix, $message);
        unset($this->started[$id]['out'], $this->started[$id]['err']);
        return $message;
    }
    private function getBorder(string $id) : string
    {
        return \sprintf('<bg=%s> </>', $this->colors[$this->started[$id]['border']]);
    }
    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return 'debug_formatter';
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Helper;

use CivixPhar\Symfony\Component\Console\Formatter\OutputFormatterInterface;
/**
 * Helper is the base class for all helper classes.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
abstract class Helper implements HelperInterface
{
    protected $helperSet = null;
    /**
     * {@inheritdoc}
     */
    public function setHelperSet(HelperSet $helperSet = null)
    {
        $this->helperSet = $helperSet;
    }
    /**
     * {@inheritdoc}
     */
    public function getHelperSet()
    {
        return $this->helperSet;
    }
    /**
     * Returns the length of a string, using mb_strwidth if it is available.
     *
     * @param string $string The string to check its length
     *
     * @return int The length of the string
     */
    public static function strlen($string)
    {
        $string = (string) $string;
        if (\false === ($encoding = \mb_detect_encoding($string, null, \true))) {
            return \strlen($string);
        }
        return \mb_strwidth($string, $encoding);
    }
    /**
     * Returns the subset of a string, using mb_substr if it is available.
     *
     * @param string   $string String to subset
     * @param int      $from   Start offset
     * @param int|null $length Length to read
     *
     * @return string The string subset
     */
    public static function substr($string, $from, $length = null)
    {
        $string = (string) $string;
        if (\false === ($encoding = \mb_detect_encoding($string, null, \true))) {
            return \substr($string, $from, $length);
        }
        return \mb_substr($string, $from, $length, $encoding);
    }
    public static function formatTime($secs)
    {
        static $timeFormats = [[0, '< 1 sec'], [1, '1 sec'], [2, 'secs', 1], [60, '1 min'], [120, 'mins', 60], [3600, '1 hr'], [7200, 'hrs', 3600], [86400, '1 day'], [172800, 'days', 86400]];
        foreach ($timeFormats as $index => $format) {
            if ($secs >= $format[0]) {
                if (isset($timeFormats[$index + 1]) && $secs < $timeFormats[$index + 1][0] || $index == \count($timeFormats) - 1) {
                    if (2 == \count($format)) {
                        return $format[1];
                    }
                    return \floor($secs / $format[2]) . ' ' . $format[1];
                }
            }
        }
    }
    public static function formatMemory($memory)
    {
        if ($memory >= 1024 * 1024 * 1024) {
            return \sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024);
        }
        if ($memory >= 1024 * 1024) {
            return \sprintf('%.1f MiB', $memory / 1024 / 1024);
        }
        if ($memory >= 1024) {
            return \sprintf('%d KiB', $memory / 1024);
        }
        return \sprintf('%d B', $memory);
    }
    public static function strlenWithoutDecoration(OutputFormatterInterface $formatter, $string)
    {
        return self::strlen(self::removeDecoration($formatter, $string));
    }
    public static function removeDecoration(OutputFormatterInterface $formatter, $string)
    {
        $isDecorated = $formatter->isDecorated();
        $formatter->setDecorated(\false);
        // remove <...> formatting
        $string = $formatter->format($string);
        // remove already formatted characters
        $string = \preg_replace("/\x1b\\[[^m]*m/", '', $string);
        $formatter->setDecorated($isDecorated);
        return $string;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Helper;

use CivixPhar\Symfony\Component\Console\Exception\InvalidArgumentException;
use CivixPhar\Symfony\Component\Console\Exception\RuntimeException;
use CivixPhar\Symfony\Component\Console\Formatter\OutputFormatter;
use CivixPhar\Symfony\Component\Console\Formatter\WrappableOutputFormatterInterface;
use CivixPhar\Symfony\Component\Console\Output\ConsoleSectionOutput;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
/**
 * Provides helpers to display a table.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Ð¡Ð°ÑˆÐ° Ð¡Ñ‚Ð°Ð¼ÐµÐ½ÐºÐ¾Ð²Ð¸Ñ› <umpirsky@gmail.com>
 * @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
 * @author Max Grigorian <maxakawizard@gmail.com>
 * @author Dany Maillard <danymaillard93b@gmail.com>
 */
class Table
{
    private const SEPARATOR_TOP = 0;
    private const SEPARATOR_TOP_BOTTOM = 1;
    private const SEPARATOR_MID = 2;
    private const SEPARATOR_BOTTOM = 3;
    private const BORDER_OUTSIDE = 0;
    private const BORDER_INSIDE = 1;
    private $headerTitle;
    private $footerTitle;
    /**
     * Table headers.
     */
    private $headers = [];
    /**
     * Table rows.
     */
    private $rows = [];
    private $horizontal = \false;
    /**
     * Column widths cache.
     */
    private $effectiveColumnWidths = [];
    /**
     * Number of columns cache.
     *
     * @var int
     */
    private $numberOfColumns;
    /**
     * @var OutputInterface
     */
    private $output;
    /**
     * @var TableStyle
     */
    private $style;
    /**
     * @var array
     */
    private $columnStyles = [];
    /**
     * User set column widths.
     *
     * @var array
     */
    private $columnWidths = [];
    private $columnMaxWidths = [];
    private static $styles;
    private $rendered = \false;
    public function __construct(OutputInterface $output)
    {
        $this->output = $output;
        if (!self::$styles) {
            self::$styles = self::initStyles();
        }
        $this->setStyle('default');
    }
    /**
     * Sets a style definition.
     *
     * @param string $name The style name
     */
    public static function setStyleDefinition($name, TableStyle $style)
    {
        if (!self::$styles) {
            self::$styles = self::initStyles();
        }
        self::$styles[$name] = $style;
    }
    /**
     * Gets a style definition by name.
     *
     * @param string $name The style name
     *
     * @return TableStyle
     */
    public static function getStyleDefinition($name)
    {
        if (!self::$styles) {
            self::$styles = self::initStyles();
        }
        if (isset(self::$styles[$name])) {
            return self::$styles[$name];
        }
        throw new InvalidArgumentException(\sprintf('Style "%s" is not defined.', $name));
    }
    /**
     * Sets table style.
     *
     * @param TableStyle|string $name The style name or a TableStyle instance
     *
     * @return $this
     */
    public function setStyle($name)
    {
        $this->style = $this->resolveStyle($name);
        return $this;
    }
    /**
     * Gets the current table style.
     *
     * @return TableStyle
     */
    public function getStyle()
    {
        return $this->style;
    }
    /**
     * Sets table column style.
     *
     * @param int               $columnIndex Column index
     * @param TableStyle|string $name        The style name or a TableStyle instance
     *
     * @return $this
     */
    public function setColumnStyle($columnIndex, $name)
    {
        $columnIndex = (int) $columnIndex;
        $this->columnStyles[$columnIndex] = $this->resolveStyle($name);
        return $this;
    }
    /**
     * Gets the current style for a column.
     *
     * If style was not set, it returns the global table style.
     *
     * @param int $columnIndex Column index
     *
     * @return TableStyle
     */
    public function getColumnStyle($columnIndex)
    {
        return $this->columnStyles[$columnIndex] ?? $this->getStyle();
    }
    /**
     * Sets the minimum width of a column.
     *
     * @param int $columnIndex Column index
     * @param int $width       Minimum column width in characters
     *
     * @return $this
     */
    public function setColumnWidth($columnIndex, $width)
    {
        $this->columnWidths[(int) $columnIndex] = (int) $width;
        return $this;
    }
    /**
     * Sets the minimum width of all columns.
     *
     * @return $this
     */
    public function setColumnWidths(array $widths)
    {
        $this->columnWidths = [];
        foreach ($widths as $index => $width) {
            $this->setColumnWidth($index, $width);
        }
        return $this;
    }
    /**
     * Sets the maximum width of a column.
     *
     * Any cell within this column which contents exceeds the specified width will be wrapped into multiple lines, while
     * formatted strings are preserved.
     *
     * @return $this
     */
    public function setColumnMaxWidth(int $columnIndex, int $width) : self
    {
        if (!$this->output->getFormatter() instanceof WrappableOutputFormatterInterface) {
            throw new \LogicException(\sprintf('Setting a maximum column width is only supported when using a "%s" formatter, got "%s".', WrappableOutputFormatterInterface::class, \get_class($this->output->getFormatter())));
        }
        $this->columnMaxWidths[$columnIndex] = $width;
        return $this;
    }
    public function setHeaders(array $headers)
    {
        $headers = \array_values($headers);
        if (!empty($headers) && !\is_array($headers[0])) {
            $headers = [$headers];
        }
        $this->headers = $headers;
        return $this;
    }
    public function setRows(array $rows)
    {
        $this->rows = [];
        return $this->addRows($rows);
    }
    public function addRows(array $rows)
    {
        foreach ($rows as $row) {
            $this->addRow($row);
        }
        return $this;
    }
    public function addRow($row)
    {
        if ($row instanceof TableSeparator) {
            $this->rows[] = $row;
            return $this;
        }
        if (!\is_array($row)) {
            throw new InvalidArgumentException('A row must be an array or a TableSeparator instance.');
        }
        $this->rows[] = \array_values($row);
        return $this;
    }
    /**
     * Adds a row to the table, and re-renders the table.
     */
    public function appendRow($row) : self
    {
        if (!$this->output instanceof ConsoleSectionOutput) {
            throw new RuntimeException(\sprintf('Output should be an instance of "%s" when calling "%s".', ConsoleSectionOutput::class, __METHOD__));
        }
        if ($this->rendered) {
            $this->output->clear($this->calculateRowCount());
        }
        $this->addRow($row);
        $this->render();
        return $this;
    }
    public function setRow($column, array $row)
    {
        $this->rows[$column] = $row;
        return $this;
    }
    public function setHeaderTitle(?string $title) : self
    {
        $this->headerTitle = $title;
        return $this;
    }
    public function setFooterTitle(?string $title) : self
    {
        $this->footerTitle = $title;
        return $this;
    }
    public function setHorizontal(bool $horizontal = \true) : self
    {
        $this->horizontal = $horizontal;
        return $this;
    }
    /**
     * Renders table to output.
     *
     * Example:
     *
     *     +---------------+-----------------------+------------------+
     *     | ISBN          | Title                 | Author           |
     *     +---------------+-----------------------+------------------+
     *     | 99921-58-10-7 | Divine Comedy         | Dante Alighieri  |
     *     | 9971-5-0210-0 | A Tale of Two Cities  | Charles Dickens  |
     *     | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien |
     *     +---------------+-----------------------+------------------+
     */
    public function render()
    {
        $divider = new TableSeparator();
        if ($this->horizontal) {
            $rows = [];
            foreach ($this->headers[0] ?? [] as $i => $header) {
                $rows[$i] = [$header];
                foreach ($this->rows as $row) {
                    if ($row instanceof TableSeparator) {
                        continue;
                    }
                    if (isset($row[$i])) {
                        $rows[$i][] = $row[$i];
                    } elseif ($rows[$i][0] instanceof TableCell && $rows[$i][0]->getColspan() >= 2) {
                        // Noop, there is a "title"
                    } else {
                        $rows[$i][] = null;
                    }
                }
            }
        } else {
            $rows = \array_merge($this->headers, [$divider], $this->rows);
        }
        $this->calculateNumberOfColumns($rows);
        $rows = $this->buildTableRows($rows);
        $this->calculateColumnsWidth($rows);
        $isHeader = !$this->horizontal;
        $isFirstRow = $this->horizontal;
        $hasTitle = (bool) $this->headerTitle;
        foreach ($rows as $row) {
            if ($divider === $row) {
                $isHeader = \false;
                $isFirstRow = \true;
                continue;
            }
            if ($row instanceof TableSeparator) {
                $this->renderRowSeparator();
                continue;
            }
            if (!$row) {
                continue;
            }
            if ($isHeader || $isFirstRow) {
                $this->renderRowSeparator($isHeader ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM, $hasTitle ? $this->headerTitle : null, $hasTitle ? $this->style->getHeaderTitleFormat() : null);
                $isFirstRow = \false;
                $hasTitle = \false;
            }
            if ($this->horizontal) {
                $this->renderRow($row, $this->style->getCellRowFormat(), $this->style->getCellHeaderFormat());
            } else {
                $this->renderRow($row, $isHeader ? $this->style->getCellHeaderFormat() : $this->style->getCellRowFormat());
            }
        }
        $this->renderRowSeparator(self::SEPARATOR_BOTTOM, $this->footerTitle, $this->style->getFooterTitleFormat());
        $this->cleanup();
        $this->rendered = \true;
    }
    /**
     * Renders horizontal header separator.
     *
     * Example:
     *
     *     +-----+-----------+-------+
     */
    private function renderRowSeparator(int $type = self::SEPARATOR_MID, string $title = null, string $titleFormat = null)
    {
        if (0 === ($count = $this->numberOfColumns)) {
            return;
        }
        $borders = $this->style->getBorderChars();
        if (!$borders[0] && !$borders[2] && !$this->style->getCrossingChar()) {
            return;
        }
        $crossings = $this->style->getCrossingChars();
        if (self::SEPARATOR_MID === $type) {
            [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[2], $crossings[8], $crossings[0], $crossings[4]];
        } elseif (self::SEPARATOR_TOP === $type) {
            [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[1], $crossings[2], $crossings[3]];
        } elseif (self::SEPARATOR_TOP_BOTTOM === $type) {
            [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[9], $crossings[10], $crossings[11]];
        } else {
            [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[7], $crossings[6], $crossings[5]];
        }
        $markup = $leftChar;
        for ($column = 0; $column < $count; ++$column) {
            $markup .= \str_repeat($horizontal, $this->effectiveColumnWidths[$column]);
            $markup .= $column === $count - 1 ? $rightChar : $midChar;
        }
        if (null !== $title) {
            $titleLength = Helper::strlenWithoutDecoration($formatter = $this->output->getFormatter(), $formattedTitle = \sprintf($titleFormat, $title));
            $markupLength = Helper::strlen($markup);
            if ($titleLength > ($limit = $markupLength - 4)) {
                $titleLength = $limit;
                $formatLength = Helper::strlenWithoutDecoration($formatter, \sprintf($titleFormat, ''));
                $formattedTitle = \sprintf($titleFormat, Helper::substr($title, 0, $limit - $formatLength - 3) . '...');
            }
            $titleStart = \intdiv($markupLength - $titleLength, 2);
            if (\false === \mb_detect_encoding($markup, null, \true)) {
                $markup = \substr_replace($markup, $formattedTitle, $titleStart, $titleLength);
            } else {
                $markup = \mb_substr($markup, 0, $titleStart) . $formattedTitle . \mb_substr($markup, $titleStart + $titleLength);
            }
        }
        $this->output->writeln(\sprintf($this->style->getBorderFormat(), $markup));
    }
    /**
     * Renders vertical column separator.
     */
    private function renderColumnSeparator(int $type = self::BORDER_OUTSIDE) : string
    {
        $borders = $this->style->getBorderChars();
        return \sprintf($this->style->getBorderFormat(), self::BORDER_OUTSIDE === $type ? $borders[1] : $borders[3]);
    }
    /**
     * Renders table row.
     *
     * Example:
     *
     *     | 9971-5-0210-0 | A Tale of Two Cities  | Charles Dickens  |
     */
    private function renderRow(array $row, string $cellFormat, string $firstCellFormat = null)
    {
        $rowContent = $this->renderColumnSeparator(self::BORDER_OUTSIDE);
        $columns = $this->getRowColumns($row);
        $last = \count($columns) - 1;
        foreach ($columns as $i => $column) {
            if ($firstCellFormat && 0 === $i) {
                $rowContent .= $this->renderCell($row, $column, $firstCellFormat);
            } else {
                $rowContent .= $this->renderCell($row, $column, $cellFormat);
            }
            $rowContent .= $this->renderColumnSeparator($last === $i ? self::BORDER_OUTSIDE : self::BORDER_INSIDE);
        }
        $this->output->writeln($rowContent);
    }
    /**
     * Renders table cell with padding.
     */
    private function renderCell(array $row, int $column, string $cellFormat) : string
    {
        $cell = $row[$column] ?? '';
        $width = $this->effectiveColumnWidths[$column];
        if ($cell instanceof TableCell && $cell->getColspan() > 1) {
            // add the width of the following columns(numbers of colspan).
            foreach (\range($column + 1, $column + $cell->getColspan() - 1) as $nextColumn) {
                $width += $this->getColumnSeparatorWidth() + $this->effectiveColumnWidths[$nextColumn];
            }
        }
        // str_pad won't work properly with multi-byte strings, we need to fix the padding
        if (\false !== ($encoding = \mb_detect_encoding($cell, null, \true))) {
            $width += \strlen($cell) - \mb_strwidth($cell, $encoding);
        }
        $style = $this->getColumnStyle($column);
        if ($cell instanceof TableSeparator) {
            return \sprintf($style->getBorderFormat(), \str_repeat($style->getBorderChars()[2], $width));
        }
        $width += Helper::strlen($cell) - Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
        $content = \sprintf($style->getCellRowContentFormat(), $cell);
        return \sprintf($cellFormat, \str_pad($content, $width, $style->getPaddingChar(), $style->getPadType()));
    }
    /**
     * Calculate number of columns for this table.
     */
    private function calculateNumberOfColumns(array $rows)
    {
        $columns = [0];
        foreach ($rows as $row) {
            if ($row instanceof TableSeparator) {
                continue;
            }
            $columns[] = $this->getNumberOfColumns($row);
        }
        $this->numberOfColumns = \max($columns);
    }
    private function buildTableRows(array $rows) : TableRows
    {
        /** @var WrappableOutputFormatterInterface $formatter */
        $formatter = $this->output->getFormatter();
        $unmergedRows = [];
        for ($rowKey = 0; $rowKey < \count($rows); ++$rowKey) {
            $rows = $this->fillNextRows($rows, $rowKey);
            // Remove any new line breaks and replace it with a new line
            foreach ($rows[$rowKey] as $column => $cell) {
                $colspan = $cell instanceof TableCell ? $cell->getColspan() : 1;
                if (isset($this->columnMaxWidths[$column]) && Helper::strlenWithoutDecoration($formatter, $cell) > $this->columnMaxWidths[$column]) {
                    $cell = $formatter->formatAndWrap($cell, $this->columnMaxWidths[$column] * $colspan);
                }
                if (!\strstr($cell ?? '', "\n")) {
                    continue;
                }
                $escaped = \implode("\n", \array_map([OutputFormatter::class, 'escapeTrailingBackslash'], \explode("\n", $cell)));
                $cell = $cell instanceof TableCell ? new TableCell($escaped, ['colspan' => $cell->getColspan()]) : $escaped;
                $lines = \explode("\n", \str_replace("\n", "<fg=default;bg=default>\n</>", $cell));
                foreach ($lines as $lineKey => $line) {
                    if ($colspan > 1) {
                        $line = new TableCell($line, ['colspan' => $colspan]);
                    }
                    if (0 === $lineKey) {
                        $rows[$rowKey][$column] = $line;
                    } else {
                        if (!\array_key_exists($rowKey, $unmergedRows) || !\array_key_exists($lineKey, $unmergedRows[$rowKey])) {
                            $unmergedRows[$rowKey][$lineKey] = $this->copyRow($rows, $rowKey);
                        }
                        $unmergedRows[$rowKey][$lineKey][$column] = $line;
                    }
                }
            }
        }
        return new TableRows(function () use($rows, $unmergedRows) : \Traversable {
            foreach ($rows as $rowKey => $row) {
                (yield $row instanceof TableSeparator ? $row : $this->fillCells($row));
                if (isset($unmergedRows[$rowKey])) {
                    foreach ($unmergedRows[$rowKey] as $row) {
                        (yield $row instanceof TableSeparator ? $row : $this->fillCells($row));
                    }
                }
            }
        });
    }
    private function calculateRowCount() : int
    {
        $numberOfRows = \count(\iterator_to_array($this->buildTableRows(\array_merge($this->headers, [new TableSeparator()], $this->rows))));
        if ($this->headers) {
            ++$numberOfRows;
            // Add row for header separator
        }
        if (\count($this->rows) > 0) {
            ++$numberOfRows;
            // Add row for footer separator
        }
        return $numberOfRows;
    }
    /**
     * fill rows that contains rowspan > 1.
     *
     * @throws InvalidArgumentException
     */
    private function fillNextRows(array $rows, int $line) : array
    {
        $unmergedRows = [];
        foreach ($rows[$line] as $column => $cell) {
            if (null !== $cell && !$cell instanceof TableCell && !\is_scalar($cell) && !(\is_object($cell) && \method_exists($cell, '__toString'))) {
                throw new InvalidArgumentException(\sprintf('A cell must be a TableCell, a scalar or an object implementing "__toString()", "%s" given.', \gettype($cell)));
            }
            if ($cell instanceof TableCell && $cell->getRowspan() > 1) {
                $nbLines = $cell->getRowspan() - 1;
                $lines = [$cell];
                if (\strstr($cell, "\n")) {
                    $lines = \explode("\n", \str_replace("\n", "<fg=default;bg=default>\n</>", $cell));
                    $nbLines = \count($lines) > $nbLines ? \substr_count($cell, "\n") : $nbLines;
                    $rows[$line][$column] = new TableCell($lines[0], ['colspan' => $cell->getColspan()]);
                    unset($lines[0]);
                }
                // create a two dimensional array (rowspan x colspan)
                $unmergedRows = \array_replace_recursive(\array_fill($line + 1, $nbLines, []), $unmergedRows);
                foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) {
                    $value = $lines[$unmergedRowKey - $line] ?? '';
                    $unmergedRows[$unmergedRowKey][$column] = new TableCell($value, ['colspan' => $cell->getColspan()]);
                    if ($nbLines === $unmergedRowKey - $line) {
                        break;
                    }
                }
            }
        }
        foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) {
            // we need to know if $unmergedRow will be merged or inserted into $rows
            if (isset($rows[$unmergedRowKey]) && \is_array($rows[$unmergedRowKey]) && $this->getNumberOfColumns($rows[$unmergedRowKey]) + $this->getNumberOfColumns($unmergedRows[$unmergedRowKey]) <= $this->numberOfColumns) {
                foreach ($unmergedRow as $cellKey => $cell) {
                    // insert cell into row at cellKey position
                    \array_splice($rows[$unmergedRowKey], $cellKey, 0, [$cell]);
                }
            } else {
                $row = $this->copyRow($rows, $unmergedRowKey - 1);
                foreach ($unmergedRow as $column => $cell) {
                    if (!empty($cell)) {
                        $row[$column] = $unmergedRow[$column];
                    }
                }
                \array_splice($rows, $unmergedRowKey, 0, [$row]);
            }
        }
        return $rows;
    }
    /**
     * fill cells for a row that contains colspan > 1.
     */
    private function fillCells(iterable $row)
    {
        $newRow = [];
        foreach ($row as $column => $cell) {
            $newRow[] = $cell;
            if ($cell instanceof TableCell && $cell->getColspan() > 1) {
                foreach (\range($column + 1, $column + $cell->getColspan() - 1) as $position) {
                    // insert empty value at column position
                    $newRow[] = '';
                }
            }
        }
        return $newRow ?: $row;
    }
    private function copyRow(array $rows, int $line) : array
    {
        $row = $rows[$line];
        foreach ($row as $cellKey => $cellValue) {
            $row[$cellKey] = '';
            if ($cellValue instanceof TableCell) {
                $row[$cellKey] = new TableCell('', ['colspan' => $cellValue->getColspan()]);
            }
        }
        return $row;
    }
    /**
     * Gets number of columns by row.
     */
    private function getNumberOfColumns(array $row) : int
    {
        $columns = \count($row);
        foreach ($row as $column) {
            $columns += $column instanceof TableCell ? $column->getColspan() - 1 : 0;
        }
        return $columns;
    }
    /**
     * Gets list of columns for the given row.
     */
    private function getRowColumns(array $row) : array
    {
        $columns = \range(0, $this->numberOfColumns - 1);
        foreach ($row as $cellKey => $cell) {
            if ($cell instanceof TableCell && $cell->getColspan() > 1) {
                // exclude grouped columns.
                $columns = \array_diff($columns, \range($cellKey + 1, $cellKey + $cell->getColspan() - 1));
            }
        }
        return $columns;
    }
    /**
     * Calculates columns widths.
     */
    private function calculateColumnsWidth(iterable $rows)
    {
        for ($column = 0; $column < $this->numberOfColumns; ++$column) {
            $lengths = [];
            foreach ($rows as $row) {
                if ($row instanceof TableSeparator) {
                    continue;
                }
                foreach ($row as $i => $cell) {
                    if ($cell instanceof TableCell) {
                        $textContent = Helper::removeDecoration($this->output->getFormatter(), $cell);
                        $textLength = Helper::strlen($textContent);
                        if ($textLength > 0) {
                            $contentColumns = \str_split($textContent, \ceil($textLength / $cell->getColspan()));
                            foreach ($contentColumns as $position => $content) {
                                $row[$i + $position] = $content;
                            }
                        }
                    }
                }
                $lengths[] = $this->getCellWidth($row, $column);
            }
            $this->effectiveColumnWidths[$column] = \max($lengths) + Helper::strlen($this->style->getCellRowContentFormat()) - 2;
        }
    }
    private function getColumnSeparatorWidth() : int
    {
        return Helper::strlen(\sprintf($this->style->getBorderFormat(), $this->style->getBorderChars()[3]));
    }
    private function getCellWidth(array $row, int $column) : int
    {
        $cellWidth = 0;
        if (isset($row[$column])) {
            $cell = $row[$column];
            $cellWidth = Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
        }
        $columnWidth = $this->columnWidths[$column] ?? 0;
        $cellWidth = \max($cellWidth, $columnWidth);
        return isset($this->columnMaxWidths[$column]) ? \min($this->columnMaxWidths[$column], $cellWidth) : $cellWidth;
    }
    /**
     * Called after rendering to cleanup cache data.
     */
    private function cleanup()
    {
        $this->effectiveColumnWidths = [];
        $this->numberOfColumns = null;
    }
    private static function initStyles() : array
    {
        $borderless = new TableStyle();
        $borderless->setHorizontalBorderChars('=')->setVerticalBorderChars(' ')->setDefaultCrossingChar(' ');
        $compact = new TableStyle();
        $compact->setHorizontalBorderChars('')->setVerticalBorderChars(' ')->setDefaultCrossingChar('')->setCellRowContentFormat('%s');
        $styleGuide = new TableStyle();
        $styleGuide->setHorizontalBorderChars('-')->setVerticalBorderChars(' ')->setDefaultCrossingChar(' ')->setCellHeaderFormat('%s');
        $box = (new TableStyle())->setHorizontalBorderChars('â”€')->setVerticalBorderChars('â”‚')->setCrossingChars('â”¼', 'â”Œ', 'â”¬', 'â”�', 'â”¤', 'â”˜', 'â”´', 'â””', 'â”œ');
        $boxDouble = (new TableStyle())->setHorizontalBorderChars('â•�', 'â”€')->setVerticalBorderChars('â•‘', 'â”‚')->setCrossingChars('â”¼', 'â•”', 'â•¤', 'â•—', 'â•¢', 'â•�', 'â•§', 'â•š', 'â•Ÿ', 'â• ', 'â•ª', 'â•£');
        return ['default' => new TableStyle(), 'borderless' => $borderless, 'compact' => $compact, 'symfony-style-guide' => $styleGuide, 'box' => $box, 'box-double' => $boxDouble];
    }
    private function resolveStyle($name) : TableStyle
    {
        if ($name instanceof TableStyle) {
            return $name;
        }
        if (isset(self::$styles[$name])) {
            return self::$styles[$name];
        }
        throw new InvalidArgumentException(\sprintf('Style "%s" is not defined.', $name));
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Tester;

use CivixPhar\Symfony\Component\Console\Command\Command;
use CivixPhar\Symfony\Component\Console\Input\ArrayInput;
/**
 * Eases the testing of console commands.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Robin Chalas <robin.chalas@gmail.com>
 */
class CommandTester
{
    use TesterTrait;
    private $command;
    private $input;
    private $statusCode;
    public function __construct(Command $command)
    {
        $this->command = $command;
    }
    /**
     * Executes the command.
     *
     * Available execution options:
     *
     *  * interactive:               Sets the input interactive flag
     *  * decorated:                 Sets the output decorated flag
     *  * verbosity:                 Sets the output verbosity flag
     *  * capture_stderr_separately: Make output of stdOut and stdErr separately available
     *
     * @param array $input   An array of command arguments and options
     * @param array $options An array of execution options
     *
     * @return int The command exit code
     */
    public function execute(array $input, array $options = [])
    {
        // set the command name automatically if the application requires
        // this argument and no command name was passed
        if (!isset($input['command']) && null !== ($application = $this->command->getApplication()) && $application->getDefinition()->hasArgument('command')) {
            $input = \array_merge(['command' => $this->command->getName()], $input);
        }
        $this->input = new ArrayInput($input);
        // Use an in-memory input stream even if no inputs are set so that QuestionHelper::ask() does not rely on the blocking STDIN.
        $this->input->setStream(self::createStream($this->inputs));
        if (isset($options['interactive'])) {
            $this->input->setInteractive($options['interactive']);
        }
        if (!isset($options['decorated'])) {
            $options['decorated'] = \false;
        }
        $this->initOutput($options);
        return $this->statusCode = $this->command->run($this->input, $this->output);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Tester;

use CivixPhar\Symfony\Component\Console\Application;
use CivixPhar\Symfony\Component\Console\Input\ArrayInput;
/**
 * Eases the testing of console applications.
 *
 * When testing an application, don't forget to disable the auto exit flag:
 *
 *     $application = new Application();
 *     $application->setAutoExit(false);
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class ApplicationTester
{
    use TesterTrait;
    private $application;
    private $input;
    private $statusCode;
    public function __construct(Application $application)
    {
        $this->application = $application;
    }
    /**
     * Executes the application.
     *
     * Available options:
     *
     *  * interactive:               Sets the input interactive flag
     *  * decorated:                 Sets the output decorated flag
     *  * verbosity:                 Sets the output verbosity flag
     *  * capture_stderr_separately: Make output of stdOut and stdErr separately available
     *
     * @param array $input   An array of arguments and options
     * @param array $options An array of options
     *
     * @return int The command exit code
     */
    public function run(array $input, $options = [])
    {
        $this->input = new ArrayInput($input);
        if (isset($options['interactive'])) {
            $this->input->setInteractive($options['interactive']);
        }
        if ($this->inputs) {
            $this->input->setStream(self::createStream($this->inputs));
        }
        $this->initOutput($options);
        return $this->statusCode = $this->application->run($this->input, $this->output);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Tester;

use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Output\ConsoleOutput;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CivixPhar\Symfony\Component\Console\Output\StreamOutput;
/**
 * @author Amrouche Hamza <hamza.simperfit@gmail.com>
 */
trait TesterTrait
{
    /** @var StreamOutput */
    private $output;
    private $inputs = [];
    private $captureStreamsIndependently = \false;
    /**
     * Gets the display returned by the last execution of the command or application.
     *
     * @param bool $normalize Whether to normalize end of lines to \n or not
     *
     * @return string The display
     */
    public function getDisplay($normalize = \false)
    {
        if (null === $this->output) {
            throw new \RuntimeException('Output not initialized, did you execute the command before requesting the display?');
        }
        \rewind($this->output->getStream());
        $display = \stream_get_contents($this->output->getStream());
        if ($normalize) {
            $display = \str_replace(\PHP_EOL, "\n", $display);
        }
        return $display;
    }
    /**
     * Gets the output written to STDERR by the application.
     *
     * @param bool $normalize Whether to normalize end of lines to \n or not
     *
     * @return string
     */
    public function getErrorOutput($normalize = \false)
    {
        if (!$this->captureStreamsIndependently) {
            throw new \LogicException('The error output is not available when the tester is run without "capture_stderr_separately" option set.');
        }
        \rewind($this->output->getErrorOutput()->getStream());
        $display = \stream_get_contents($this->output->getErrorOutput()->getStream());
        if ($normalize) {
            $display = \str_replace(\PHP_EOL, "\n", $display);
        }
        return $display;
    }
    /**
     * Gets the input instance used by the last execution of the command or application.
     *
     * @return InputInterface The current input instance
     */
    public function getInput()
    {
        return $this->input;
    }
    /**
     * Gets the output instance used by the last execution of the command or application.
     *
     * @return OutputInterface The current output instance
     */
    public function getOutput()
    {
        return $this->output;
    }
    /**
     * Gets the status code returned by the last execution of the command or application.
     *
     * @return int The status code
     */
    public function getStatusCode()
    {
        return $this->statusCode;
    }
    /**
     * Sets the user inputs.
     *
     * @param array $inputs An array of strings representing each input
     *                      passed to the command input stream
     *
     * @return $this
     */
    public function setInputs(array $inputs)
    {
        $this->inputs = $inputs;
        return $this;
    }
    /**
     * Initializes the output property.
     *
     * Available options:
     *
     *  * decorated:                 Sets the output decorated flag
     *  * verbosity:                 Sets the output verbosity flag
     *  * capture_stderr_separately: Make output of stdOut and stdErr separately available
     */
    private function initOutput(array $options)
    {
        $this->captureStreamsIndependently = \array_key_exists('capture_stderr_separately', $options) && $options['capture_stderr_separately'];
        if (!$this->captureStreamsIndependently) {
            $this->output = new StreamOutput(\fopen('php://memory', 'w', \false));
            if (isset($options['decorated'])) {
                $this->output->setDecorated($options['decorated']);
            }
            if (isset($options['verbosity'])) {
                $this->output->setVerbosity($options['verbosity']);
            }
        } else {
            $this->output = new ConsoleOutput($options['verbosity'] ?? ConsoleOutput::VERBOSITY_NORMAL, $options['decorated'] ?? null);
            $errorOutput = new StreamOutput(\fopen('php://memory', 'w', \false));
            $errorOutput->setFormatter($this->output->getFormatter());
            $errorOutput->setVerbosity($this->output->getVerbosity());
            $errorOutput->setDecorated($this->output->isDecorated());
            $reflectedOutput = new \ReflectionObject($this->output);
            $strErrProperty = $reflectedOutput->getProperty('stderr');
            $strErrProperty->setAccessible(\true);
            $strErrProperty->setValue($this->output, $errorOutput);
            $reflectedParent = $reflectedOutput->getParentClass();
            $streamProperty = $reflectedParent->getProperty('stream');
            $streamProperty->setAccessible(\true);
            $streamProperty->setValue($this->output, \fopen('php://memory', 'w', \false));
        }
    }
    /**
     * @return resource
     */
    private static function createStream(array $inputs)
    {
        $stream = \fopen('php://memory', 'r+', \false);
        foreach ($inputs as $input) {
            \fwrite($stream, $input . \PHP_EOL);
        }
        \rewind($stream);
        return $stream;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\CommandLoader;

use CivixPhar\Symfony\Component\Console\Command\Command;
use CivixPhar\Symfony\Component\Console\Exception\CommandNotFoundException;
/**
 * @author Robin Chalas <robin.chalas@gmail.com>
 */
interface CommandLoaderInterface
{
    /**
     * Loads a command.
     *
     * @param string $name
     *
     * @return Command
     *
     * @throws CommandNotFoundException
     */
    public function get($name);
    /**
     * Checks if a command exists.
     *
     * @param string $name
     *
     * @return bool
     */
    public function has($name);
    /**
     * @return string[] All registered command names
     */
    public function getNames();
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\CommandLoader;

use CivixPhar\Psr\Container\ContainerInterface;
use CivixPhar\Symfony\Component\Console\Exception\CommandNotFoundException;
/**
 * Loads commands from a PSR-11 container.
 *
 * @author Robin Chalas <robin.chalas@gmail.com>
 */
class ContainerCommandLoader implements CommandLoaderInterface
{
    private $container;
    private $commandMap;
    /**
     * @param array $commandMap An array with command names as keys and service ids as values
     */
    public function __construct(ContainerInterface $container, array $commandMap)
    {
        $this->container = $container;
        $this->commandMap = $commandMap;
    }
    /**
     * {@inheritdoc}
     */
    public function get($name)
    {
        if (!$this->has($name)) {
            throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name));
        }
        return $this->container->get($this->commandMap[$name]);
    }
    /**
     * {@inheritdoc}
     */
    public function has($name)
    {
        return isset($this->commandMap[$name]) && $this->container->has($this->commandMap[$name]);
    }
    /**
     * {@inheritdoc}
     */
    public function getNames()
    {
        return \array_keys($this->commandMap);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\CommandLoader;

use CivixPhar\Symfony\Component\Console\Exception\CommandNotFoundException;
/**
 * A simple command loader using factories to instantiate commands lazily.
 *
 * @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
 */
class FactoryCommandLoader implements CommandLoaderInterface
{
    private $factories;
    /**
     * @param callable[] $factories Indexed by command names
     */
    public function __construct(array $factories)
    {
        $this->factories = $factories;
    }
    /**
     * {@inheritdoc}
     */
    public function has($name)
    {
        return isset($this->factories[$name]);
    }
    /**
     * {@inheritdoc}
     */
    public function get($name)
    {
        if (!isset($this->factories[$name])) {
            throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name));
        }
        $factory = $this->factories[$name];
        return $factory();
    }
    /**
     * {@inheritdoc}
     */
    public function getNames()
    {
        return \array_keys($this->factories);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Exception;

/**
 * @author JÃ©rÃ´me Tamarelle <jerome@tamarelle.net>
 */
class LogicException extends \LogicException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Exception;

/**
 * Represents an incorrect namespace typed in the console.
 *
 * @author Pierre du Plessis <pdples@gmail.com>
 */
class NamespaceNotFoundException extends CommandNotFoundException
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Exception;

/**
 * @author JÃ©rÃ´me Tamarelle <jerome@tamarelle.net>
 */
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Exception;

/**
 * @author JÃ©rÃ´me Tamarelle <jerome@tamarelle.net>
 */
class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Exception;

/**
 * ExceptionInterface.
 *
 * @author JÃ©rÃ´me Tamarelle <jerome@tamarelle.net>
 */
interface ExceptionInterface extends \Throwable
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Exception;

/**
 * Represents an incorrect option name typed in the console.
 *
 * @author JÃ©rÃ´me Tamarelle <jerome@tamarelle.net>
 */
class InvalidOptionException extends \InvalidArgumentException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Exception;

/**
 * Represents failure to read input from stdin.
 *
 * @author Gabriel OstroluckÃ½ <gabriel.ostrolucky@gmail.com>
 */
class MissingInputException extends RuntimeException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Exception;

/**
 * Represents an incorrect command name typed in the console.
 *
 * @author JÃ©rÃ´me Tamarelle <jerome@tamarelle.net>
 */
class CommandNotFoundException extends \InvalidArgumentException implements ExceptionInterface
{
    private $alternatives;
    /**
     * @param string          $message      Exception message to throw
     * @param string[]        $alternatives List of similar defined names
     * @param int             $code         Exception code
     * @param \Throwable|null $previous     Previous exception used for the exception chaining
     */
    public function __construct(string $message, array $alternatives = [], int $code = 0, \Throwable $previous = null)
    {
        parent::__construct($message, $code, $previous);
        $this->alternatives = $alternatives;
    }
    /**
     * @return string[] A list of similar defined names
     */
    public function getAlternatives()
    {
        return $this->alternatives;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console;

use CivixPhar\Symfony\Component\Console\Command\Command;
use CivixPhar\Symfony\Component\Console\Command\HelpCommand;
use CivixPhar\Symfony\Component\Console\Command\ListCommand;
use CivixPhar\Symfony\Component\Console\CommandLoader\CommandLoaderInterface;
use CivixPhar\Symfony\Component\Console\Event\ConsoleCommandEvent;
use CivixPhar\Symfony\Component\Console\Event\ConsoleErrorEvent;
use CivixPhar\Symfony\Component\Console\Event\ConsoleTerminateEvent;
use CivixPhar\Symfony\Component\Console\Exception\CommandNotFoundException;
use CivixPhar\Symfony\Component\Console\Exception\ExceptionInterface;
use CivixPhar\Symfony\Component\Console\Exception\LogicException;
use CivixPhar\Symfony\Component\Console\Exception\NamespaceNotFoundException;
use CivixPhar\Symfony\Component\Console\Formatter\OutputFormatter;
use CivixPhar\Symfony\Component\Console\Helper\DebugFormatterHelper;
use CivixPhar\Symfony\Component\Console\Helper\FormatterHelper;
use CivixPhar\Symfony\Component\Console\Helper\Helper;
use CivixPhar\Symfony\Component\Console\Helper\HelperSet;
use CivixPhar\Symfony\Component\Console\Helper\ProcessHelper;
use CivixPhar\Symfony\Component\Console\Helper\QuestionHelper;
use CivixPhar\Symfony\Component\Console\Input\ArgvInput;
use CivixPhar\Symfony\Component\Console\Input\ArrayInput;
use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputAwareInterface;
use CivixPhar\Symfony\Component\Console\Input\InputDefinition;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
use CivixPhar\Symfony\Component\Console\Output\ConsoleOutput;
use CivixPhar\Symfony\Component\Console\Output\ConsoleOutputInterface;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CivixPhar\Symfony\Component\Console\Style\SymfonyStyle;
use CivixPhar\Symfony\Component\Debug\ErrorHandler as LegacyErrorHandler;
use CivixPhar\Symfony\Component\Debug\Exception\FatalThrowableError;
use CivixPhar\Symfony\Component\ErrorHandler\ErrorHandler;
use CivixPhar\Symfony\Component\EventDispatcher\EventDispatcherInterface;
use CivixPhar\Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy;
use CivixPhar\Symfony\Contracts\Service\ResetInterface;
/**
 * An Application is the container for a collection of commands.
 *
 * It is the main entry point of a Console application.
 *
 * This class is optimized for a standard CLI environment.
 *
 * Usage:
 *
 *     $app = new Application('myapp', '1.0 (stable)');
 *     $app->add(new SimpleCommand());
 *     $app->run();
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class Application implements ResetInterface
{
    private $commands = [];
    private $wantHelps = \false;
    private $runningCommand;
    private $name;
    private $version;
    private $commandLoader;
    private $catchExceptions = \true;
    private $autoExit = \true;
    private $definition;
    private $helperSet;
    private $dispatcher;
    private $terminal;
    private $defaultCommand;
    private $singleCommand = \false;
    private $initialized;
    /**
     * @param string $name    The name of the application
     * @param string $version The version of the application
     */
    public function __construct(string $name = 'UNKNOWN', string $version = 'UNKNOWN')
    {
        $this->name = $name;
        $this->version = $version;
        $this->terminal = new Terminal();
        $this->defaultCommand = 'list';
    }
    /**
     * @final since Symfony 4.3, the type-hint will be updated to the interface from symfony/contracts in 5.0
     */
    public function setDispatcher(EventDispatcherInterface $dispatcher)
    {
        $this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher);
    }
    public function setCommandLoader(CommandLoaderInterface $commandLoader)
    {
        $this->commandLoader = $commandLoader;
    }
    /**
     * Runs the current application.
     *
     * @return int 0 if everything went fine, or an error code
     *
     * @throws \Exception When running fails. Bypass this when {@link setCatchExceptions()}.
     */
    public function run(InputInterface $input = null, OutputInterface $output = null)
    {
        if (\function_exists('putenv')) {
            @\putenv('LINES=' . $this->terminal->getHeight());
            @\putenv('COLUMNS=' . $this->terminal->getWidth());
        }
        if (null === $input) {
            $input = new ArgvInput();
        }
        if (null === $output) {
            $output = new ConsoleOutput();
        }
        $renderException = function (\Throwable $e) use($output) {
            if ($output instanceof ConsoleOutputInterface) {
                $this->renderThrowable($e, $output->getErrorOutput());
            } else {
                $this->renderThrowable($e, $output);
            }
        };
        if ($phpHandler = \set_exception_handler($renderException)) {
            \restore_exception_handler();
            if (!\is_array($phpHandler) || !$phpHandler[0] instanceof ErrorHandler && !$phpHandler[0] instanceof LegacyErrorHandler) {
                $errorHandler = \true;
            } elseif ($errorHandler = $phpHandler[0]->setExceptionHandler($renderException)) {
                $phpHandler[0]->setExceptionHandler($errorHandler);
            }
        }
        $this->configureIO($input, $output);
        try {
            $exitCode = $this->doRun($input, $output);
        } catch (\Exception $e) {
            if (!$this->catchExceptions) {
                throw $e;
            }
            $renderException($e);
            $exitCode = $e->getCode();
            if (\is_numeric($exitCode)) {
                $exitCode = (int) $exitCode;
                if (0 === $exitCode) {
                    $exitCode = 1;
                }
            } else {
                $exitCode = 1;
            }
        } finally {
            // if the exception handler changed, keep it
            // otherwise, unregister $renderException
            if (!$phpHandler) {
                if (\set_exception_handler($renderException) === $renderException) {
                    \restore_exception_handler();
                }
                \restore_exception_handler();
            } elseif (!$errorHandler) {
                $finalHandler = $phpHandler[0]->setExceptionHandler(null);
                if ($finalHandler !== $renderException) {
                    $phpHandler[0]->setExceptionHandler($finalHandler);
                }
            }
        }
        if ($this->autoExit) {
            if ($exitCode > 255) {
                $exitCode = 255;
            }
            exit($exitCode);
        }
        return $exitCode;
    }
    /**
     * Runs the current application.
     *
     * @return int 0 if everything went fine, or an error code
     */
    public function doRun(InputInterface $input, OutputInterface $output)
    {
        if (\true === $input->hasParameterOption(['--version', '-V'], \true)) {
            $output->writeln($this->getLongVersion());
            return 0;
        }
        try {
            // Makes ArgvInput::getFirstArgument() able to distinguish an option from an argument.
            $input->bind($this->getDefinition());
        } catch (ExceptionInterface $e) {
            // Errors must be ignored, full binding/validation happens later when the command is known.
        }
        $name = $this->getCommandName($input);
        if (\true === $input->hasParameterOption(['--help', '-h'], \true)) {
            if (!$name) {
                $name = 'help';
                $input = new ArrayInput(['command_name' => $this->defaultCommand]);
            } else {
                $this->wantHelps = \true;
            }
        }
        if (!$name) {
            $name = $this->defaultCommand;
            $definition = $this->getDefinition();
            $definition->setArguments(\array_merge($definition->getArguments(), ['command' => new InputArgument('command', InputArgument::OPTIONAL, $definition->getArgument('command')->getDescription(), $name)]));
        }
        try {
            $this->runningCommand = null;
            // the command name MUST be the first element of the input
            $command = $this->find($name);
        } catch (\Throwable $e) {
            if (!($e instanceof CommandNotFoundException && !$e instanceof NamespaceNotFoundException) || 1 !== \count($alternatives = $e->getAlternatives()) || !$input->isInteractive()) {
                if (null !== $this->dispatcher) {
                    $event = new ConsoleErrorEvent($input, $output, $e);
                    $this->dispatcher->dispatch($event, ConsoleEvents::ERROR);
                    if (0 === $event->getExitCode()) {
                        return 0;
                    }
                    $e = $event->getError();
                }
                throw $e;
            }
            $alternative = $alternatives[0];
            $style = new SymfonyStyle($input, $output);
            $style->block(\sprintf("\nCommand \"%s\" is not defined.\n", $name), null, 'error');
            if (!$style->confirm(\sprintf('Do you want to run "%s" instead? ', $alternative), \false)) {
                if (null !== $this->dispatcher) {
                    $event = new ConsoleErrorEvent($input, $output, $e);
                    $this->dispatcher->dispatch($event, ConsoleEvents::ERROR);
                    return $event->getExitCode();
                }
                return 1;
            }
            $command = $this->find($alternative);
        }
        $this->runningCommand = $command;
        $exitCode = $this->doRunCommand($command, $input, $output);
        $this->runningCommand = null;
        return $exitCode;
    }
    /**
     * {@inheritdoc}
     */
    public function reset()
    {
    }
    public function setHelperSet(HelperSet $helperSet)
    {
        $this->helperSet = $helperSet;
    }
    /**
     * Get the helper set associated with the command.
     *
     * @return HelperSet The HelperSet instance associated with this command
     */
    public function getHelperSet()
    {
        if (!$this->helperSet) {
            $this->helperSet = $this->getDefaultHelperSet();
        }
        return $this->helperSet;
    }
    public function setDefinition(InputDefinition $definition)
    {
        $this->definition = $definition;
    }
    /**
     * Gets the InputDefinition related to this Application.
     *
     * @return InputDefinition The InputDefinition instance
     */
    public function getDefinition()
    {
        if (!$this->definition) {
            $this->definition = $this->getDefaultInputDefinition();
        }
        if ($this->singleCommand) {
            $inputDefinition = $this->definition;
            $inputDefinition->setArguments();
            return $inputDefinition;
        }
        return $this->definition;
    }
    /**
     * Gets the help message.
     *
     * @return string A help message
     */
    public function getHelp()
    {
        return $this->getLongVersion();
    }
    /**
     * Gets whether to catch exceptions or not during commands execution.
     *
     * @return bool Whether to catch exceptions or not during commands execution
     */
    public function areExceptionsCaught()
    {
        return $this->catchExceptions;
    }
    /**
     * Sets whether to catch exceptions or not during commands execution.
     *
     * @param bool $boolean Whether to catch exceptions or not during commands execution
     */
    public function setCatchExceptions($boolean)
    {
        $this->catchExceptions = (bool) $boolean;
    }
    /**
     * Gets whether to automatically exit after a command execution or not.
     *
     * @return bool Whether to automatically exit after a command execution or not
     */
    public function isAutoExitEnabled()
    {
        return $this->autoExit;
    }
    /**
     * Sets whether to automatically exit after a command execution or not.
     *
     * @param bool $boolean Whether to automatically exit after a command execution or not
     */
    public function setAutoExit($boolean)
    {
        $this->autoExit = (bool) $boolean;
    }
    /**
     * Gets the name of the application.
     *
     * @return string The application name
     */
    public function getName()
    {
        return $this->name;
    }
    /**
     * Sets the application name.
     *
     * @param string $name The application name
     */
    public function setName($name)
    {
        $this->name = $name;
    }
    /**
     * Gets the application version.
     *
     * @return string The application version
     */
    public function getVersion()
    {
        return $this->version;
    }
    /**
     * Sets the application version.
     *
     * @param string $version The application version
     */
    public function setVersion($version)
    {
        $this->version = $version;
    }
    /**
     * Returns the long version of the application.
     *
     * @return string The long application version
     */
    public function getLongVersion()
    {
        if ('UNKNOWN' !== $this->getName()) {
            if ('UNKNOWN' !== $this->getVersion()) {
                return \sprintf('%s <info>%s</info>', $this->getName(), $this->getVersion());
            }
            return $this->getName();
        }
        return 'Console Tool';
    }
    /**
     * Registers a new command.
     *
     * @param string $name The command name
     *
     * @return Command The newly created command
     */
    public function register($name)
    {
        return $this->add(new Command($name));
    }
    /**
     * Adds an array of command objects.
     *
     * If a Command is not enabled it will not be added.
     *
     * @param Command[] $commands An array of commands
     */
    public function addCommands(array $commands)
    {
        foreach ($commands as $command) {
            $this->add($command);
        }
    }
    /**
     * Adds a command object.
     *
     * If a command with the same name already exists, it will be overridden.
     * If the command is not enabled it will not be added.
     *
     * @return Command|null The registered command if enabled or null
     */
    public function add(Command $command)
    {
        $this->init();
        $command->setApplication($this);
        if (!$command->isEnabled()) {
            $command->setApplication(null);
            return null;
        }
        // Will throw if the command is not correctly initialized.
        $command->getDefinition();
        if (!$command->getName()) {
            throw new LogicException(\sprintf('The command defined in "%s" cannot have an empty name.', \get_class($command)));
        }
        $this->commands[$command->getName()] = $command;
        foreach ($command->getAliases() as $alias) {
            $this->commands[$alias] = $command;
        }
        return $command;
    }
    /**
     * Returns a registered command by name or alias.
     *
     * @param string $name The command name or alias
     *
     * @return Command A Command object
     *
     * @throws CommandNotFoundException When given command name does not exist
     */
    public function get($name)
    {
        $this->init();
        if (!$this->has($name)) {
            throw new CommandNotFoundException(\sprintf('The command "%s" does not exist.', $name));
        }
        // When the command has a different name than the one used at the command loader level
        if (!isset($this->commands[$name])) {
            throw new CommandNotFoundException(\sprintf('The "%s" command cannot be found because it is registered under multiple names. Make sure you don\'t set a different name via constructor or "setName()".', $name));
        }
        $command = $this->commands[$name];
        if ($this->wantHelps) {
            $this->wantHelps = \false;
            $helpCommand = $this->get('help');
            $helpCommand->setCommand($command);
            return $helpCommand;
        }
        return $command;
    }
    /**
     * Returns true if the command exists, false otherwise.
     *
     * @param string $name The command name or alias
     *
     * @return bool true if the command exists, false otherwise
     */
    public function has($name)
    {
        $this->init();
        return isset($this->commands[$name]) || $this->commandLoader && $this->commandLoader->has($name) && $this->add($this->commandLoader->get($name));
    }
    /**
     * Returns an array of all unique namespaces used by currently registered commands.
     *
     * It does not return the global namespace which always exists.
     *
     * @return string[] An array of namespaces
     */
    public function getNamespaces()
    {
        $namespaces = [];
        foreach ($this->all() as $command) {
            if ($command->isHidden()) {
                continue;
            }
            $namespaces = \array_merge($namespaces, $this->extractAllNamespaces($command->getName()));
            foreach ($command->getAliases() as $alias) {
                $namespaces = \array_merge($namespaces, $this->extractAllNamespaces($alias));
            }
        }
        return \array_values(\array_unique(\array_filter($namespaces)));
    }
    /**
     * Finds a registered namespace by a name or an abbreviation.
     *
     * @param string $namespace A namespace or abbreviation to search for
     *
     * @return string A registered namespace
     *
     * @throws NamespaceNotFoundException When namespace is incorrect or ambiguous
     */
    public function findNamespace($namespace)
    {
        $allNamespaces = $this->getNamespaces();
        $expr = \preg_replace_callback('{([^:]+|)}', function ($matches) {
            return \preg_quote($matches[1]) . '[^:]*';
        }, $namespace);
        $namespaces = \preg_grep('{^' . $expr . '}', $allNamespaces);
        if (empty($namespaces)) {
            $message = \sprintf('There are no commands defined in the "%s" namespace.', $namespace);
            if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) {
                if (1 == \count($alternatives)) {
                    $message .= "\n\nDid you mean this?\n    ";
                } else {
                    $message .= "\n\nDid you mean one of these?\n    ";
                }
                $message .= \implode("\n    ", $alternatives);
            }
            throw new NamespaceNotFoundException($message, $alternatives);
        }
        $exact = \in_array($namespace, $namespaces, \true);
        if (\count($namespaces) > 1 && !$exact) {
            throw new NamespaceNotFoundException(\sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $namespace, $this->getAbbreviationSuggestions(\array_values($namespaces))), \array_values($namespaces));
        }
        return $exact ? $namespace : \reset($namespaces);
    }
    /**
     * Finds a command by name or alias.
     *
     * Contrary to get, this command tries to find the best
     * match if you give it an abbreviation of a name or alias.
     *
     * @param string $name A command name or a command alias
     *
     * @return Command A Command instance
     *
     * @throws CommandNotFoundException When command name is incorrect or ambiguous
     */
    public function find($name)
    {
        $this->init();
        $aliases = [];
        foreach ($this->commands as $command) {
            foreach ($command->getAliases() as $alias) {
                if (!$this->has($alias)) {
                    $this->commands[$alias] = $command;
                }
            }
        }
        if ($this->has($name)) {
            return $this->get($name);
        }
        $allCommands = $this->commandLoader ? \array_merge($this->commandLoader->getNames(), \array_keys($this->commands)) : \array_keys($this->commands);
        $expr = \preg_replace_callback('{([^:]+|)}', function ($matches) {
            return \preg_quote($matches[1]) . '[^:]*';
        }, $name);
        $commands = \preg_grep('{^' . $expr . '}', $allCommands);
        if (empty($commands)) {
            $commands = \preg_grep('{^' . $expr . '}i', $allCommands);
        }
        // if no commands matched or we just matched namespaces
        if (empty($commands) || \count(\preg_grep('{^' . $expr . '$}i', $commands)) < 1) {
            if (\false !== ($pos = \strrpos($name, ':'))) {
                // check if a namespace exists and contains commands
                $this->findNamespace(\substr($name, 0, $pos));
            }
            $message = \sprintf('Command "%s" is not defined.', $name);
            if ($alternatives = $this->findAlternatives($name, $allCommands)) {
                // remove hidden commands
                $alternatives = \array_filter($alternatives, function ($name) {
                    return !$this->get($name)->isHidden();
                });
                if (1 == \count($alternatives)) {
                    $message .= "\n\nDid you mean this?\n    ";
                } else {
                    $message .= "\n\nDid you mean one of these?\n    ";
                }
                $message .= \implode("\n    ", $alternatives);
            }
            throw new CommandNotFoundException($message, \array_values($alternatives));
        }
        // filter out aliases for commands which are already on the list
        if (\count($commands) > 1) {
            $commandList = $this->commandLoader ? \array_merge(\array_flip($this->commandLoader->getNames()), $this->commands) : $this->commands;
            $commands = \array_unique(\array_filter($commands, function ($nameOrAlias) use(&$commandList, $commands, &$aliases) {
                if (!$commandList[$nameOrAlias] instanceof Command) {
                    $commandList[$nameOrAlias] = $this->commandLoader->get($nameOrAlias);
                }
                $commandName = $commandList[$nameOrAlias]->getName();
                $aliases[$nameOrAlias] = $commandName;
                return $commandName === $nameOrAlias || !\in_array($commandName, $commands);
            }));
        }
        if (\count($commands) > 1) {
            $usableWidth = $this->terminal->getWidth() - 10;
            $abbrevs = \array_values($commands);
            $maxLen = 0;
            foreach ($abbrevs as $abbrev) {
                $maxLen = \max(Helper::strlen($abbrev), $maxLen);
            }
            $abbrevs = \array_map(function ($cmd) use($commandList, $usableWidth, $maxLen, &$commands) {
                if ($commandList[$cmd]->isHidden()) {
                    unset($commands[\array_search($cmd, $commands)]);
                    return \false;
                }
                $abbrev = \str_pad($cmd, $maxLen, ' ') . ' ' . $commandList[$cmd]->getDescription();
                return Helper::strlen($abbrev) > $usableWidth ? Helper::substr($abbrev, 0, $usableWidth - 3) . '...' : $abbrev;
            }, \array_values($commands));
            if (\count($commands) > 1) {
                $suggestions = $this->getAbbreviationSuggestions(\array_filter($abbrevs));
                throw new CommandNotFoundException(\sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $name, $suggestions), \array_values($commands));
            }
        }
        $command = $this->get(\reset($commands));
        if ($command->isHidden()) {
            @\trigger_error(\sprintf('Command "%s" is hidden, finding it using an abbreviation is deprecated since Symfony 4.4, use its full name instead.', $command->getName()), \E_USER_DEPRECATED);
        }
        return $command;
    }
    /**
     * Gets the commands (registered in the given namespace if provided).
     *
     * The array keys are the full names and the values the command instances.
     *
     * @param string $namespace A namespace name
     *
     * @return Command[] An array of Command instances
     */
    public function all($namespace = null)
    {
        $this->init();
        if (null === $namespace) {
            if (!$this->commandLoader) {
                return $this->commands;
            }
            $commands = $this->commands;
            foreach ($this->commandLoader->getNames() as $name) {
                if (!isset($commands[$name]) && $this->has($name)) {
                    $commands[$name] = $this->get($name);
                }
            }
            return $commands;
        }
        $commands = [];
        foreach ($this->commands as $name => $command) {
            if ($namespace === $this->extractNamespace($name, \substr_count($namespace, ':') + 1)) {
                $commands[$name] = $command;
            }
        }
        if ($this->commandLoader) {
            foreach ($this->commandLoader->getNames() as $name) {
                if (!isset($commands[$name]) && $namespace === $this->extractNamespace($name, \substr_count($namespace, ':') + 1) && $this->has($name)) {
                    $commands[$name] = $this->get($name);
                }
            }
        }
        return $commands;
    }
    /**
     * Returns an array of possible abbreviations given a set of names.
     *
     * @param array $names An array of names
     *
     * @return array An array of abbreviations
     */
    public static function getAbbreviations($names)
    {
        $abbrevs = [];
        foreach ($names as $name) {
            for ($len = \strlen($name); $len > 0; --$len) {
                $abbrev = \substr($name, 0, $len);
                $abbrevs[$abbrev][] = $name;
            }
        }
        return $abbrevs;
    }
    /**
     * Renders a caught exception.
     *
     * @deprecated since Symfony 4.4, use "renderThrowable()" instead
     */
    public function renderException(\Exception $e, OutputInterface $output)
    {
        @\trigger_error(\sprintf('The "%s::renderException()" method is deprecated since Symfony 4.4, use "renderThrowable()" instead.', __CLASS__), \E_USER_DEPRECATED);
        $output->writeln('', OutputInterface::VERBOSITY_QUIET);
        $this->doRenderException($e, $output);
        $this->finishRenderThrowableOrException($output);
    }
    public function renderThrowable(\Throwable $e, OutputInterface $output) : void
    {
        if (__CLASS__ !== static::class && __CLASS__ === (new \ReflectionMethod($this, 'renderThrowable'))->getDeclaringClass()->getName() && __CLASS__ !== (new \ReflectionMethod($this, 'renderException'))->getDeclaringClass()->getName()) {
            @\trigger_error(\sprintf('The "%s::renderException()" method is deprecated since Symfony 4.4, use "renderThrowable()" instead.', __CLASS__), \E_USER_DEPRECATED);
            if (!$e instanceof \Exception) {
                $e = \class_exists(FatalThrowableError::class) ? new FatalThrowableError($e) : new \ErrorException($e->getMessage(), $e->getCode(), \E_ERROR, $e->getFile(), $e->getLine());
            }
            $this->renderException($e, $output);
            return;
        }
        $output->writeln('', OutputInterface::VERBOSITY_QUIET);
        $this->doRenderThrowable($e, $output);
        $this->finishRenderThrowableOrException($output);
    }
    private function finishRenderThrowableOrException(OutputInterface $output) : void
    {
        if (null !== $this->runningCommand) {
            $output->writeln(\sprintf('<info>%s</info>', OutputFormatter::escape(\sprintf($this->runningCommand->getSynopsis(), $this->getName()))), OutputInterface::VERBOSITY_QUIET);
            $output->writeln('', OutputInterface::VERBOSITY_QUIET);
        }
    }
    /**
     * @deprecated since Symfony 4.4, use "doRenderThrowable()" instead
     */
    protected function doRenderException(\Exception $e, OutputInterface $output)
    {
        @\trigger_error(\sprintf('The "%s::doRenderException()" method is deprecated since Symfony 4.4, use "doRenderThrowable()" instead.', __CLASS__), \E_USER_DEPRECATED);
        $this->doActuallyRenderThrowable($e, $output);
    }
    protected function doRenderThrowable(\Throwable $e, OutputInterface $output) : void
    {
        if (__CLASS__ !== static::class && __CLASS__ === (new \ReflectionMethod($this, 'doRenderThrowable'))->getDeclaringClass()->getName() && __CLASS__ !== (new \ReflectionMethod($this, 'doRenderException'))->getDeclaringClass()->getName()) {
            @\trigger_error(\sprintf('The "%s::doRenderException()" method is deprecated since Symfony 4.4, use "doRenderThrowable()" instead.', __CLASS__), \E_USER_DEPRECATED);
            if (!$e instanceof \Exception) {
                $e = \class_exists(FatalThrowableError::class) ? new FatalThrowableError($e) : new \ErrorException($e->getMessage(), $e->getCode(), \E_ERROR, $e->getFile(), $e->getLine());
            }
            $this->doRenderException($e, $output);
            return;
        }
        $this->doActuallyRenderThrowable($e, $output);
    }
    private function doActuallyRenderThrowable(\Throwable $e, OutputInterface $output) : void
    {
        do {
            $message = \trim($e->getMessage());
            if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
                $class = \get_debug_type($e);
                $title = \sprintf('  [%s%s]  ', $class, 0 !== ($code = $e->getCode()) ? ' (' . $code . ')' : '');
                $len = Helper::strlen($title);
            } else {
                $len = 0;
            }
            if (\str_contains($message, "@anonymous\x00")) {
                $message = \preg_replace_callback('/[a-zA-Z_\\x7f-\\xff][\\\\a-zA-Z0-9_\\x7f-\\xff]*+@anonymous\\x00.*?\\.php(?:0x?|:[0-9]++\\$)[0-9a-fA-F]++/', function ($m) {
                    return \class_exists($m[0], \false) ? ((\get_parent_class($m[0]) ?: \key(\class_implements($m[0]))) ?: 'class') . '@anonymous' : $m[0];
                }, $message);
            }
            $width = $this->terminal->getWidth() ? $this->terminal->getWidth() - 1 : \PHP_INT_MAX;
            $lines = [];
            foreach ('' !== $message ? \preg_split('/\\r?\\n/', $message) : [] as $line) {
                foreach ($this->splitStringByWidth($line, $width - 4) as $line) {
                    // pre-format lines to get the right string length
                    $lineLength = Helper::strlen($line) + 4;
                    $lines[] = [$line, $lineLength];
                    $len = \max($lineLength, $len);
                }
            }
            $messages = [];
            if (!$e instanceof ExceptionInterface || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
                $messages[] = \sprintf('<comment>%s</comment>', OutputFormatter::escape(\sprintf('In %s line %s:', \basename($e->getFile()) ?: 'n/a', $e->getLine() ?: 'n/a')));
            }
            $messages[] = $emptyLine = \sprintf('<error>%s</error>', \str_repeat(' ', $len));
            if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
                $messages[] = \sprintf('<error>%s%s</error>', $title, \str_repeat(' ', \max(0, $len - Helper::strlen($title))));
            }
            foreach ($lines as $line) {
                $messages[] = \sprintf('<error>  %s  %s</error>', OutputFormatter::escape($line[0]), \str_repeat(' ', $len - $line[1]));
            }
            $messages[] = $emptyLine;
            $messages[] = '';
            $output->writeln($messages, OutputInterface::VERBOSITY_QUIET);
            if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
                $output->writeln('<comment>Exception trace:</comment>', OutputInterface::VERBOSITY_QUIET);
                // exception related properties
                $trace = $e->getTrace();
                \array_unshift($trace, ['function' => '', 'file' => $e->getFile() ?: 'n/a', 'line' => $e->getLine() ?: 'n/a', 'args' => []]);
                for ($i = 0, $count = \count($trace); $i < $count; ++$i) {
                    $class = $trace[$i]['class'] ?? '';
                    $type = $trace[$i]['type'] ?? '';
                    $function = $trace[$i]['function'] ?? '';
                    $file = $trace[$i]['file'] ?? 'n/a';
                    $line = $trace[$i]['line'] ?? 'n/a';
                    $output->writeln(\sprintf(' %s%s at <info>%s:%s</info>', $class, $function ? $type . $function . '()' : '', $file, $line), OutputInterface::VERBOSITY_QUIET);
                }
                $output->writeln('', OutputInterface::VERBOSITY_QUIET);
            }
        } while ($e = $e->getPrevious());
    }
    /**
     * Configures the input and output instances based on the user arguments and options.
     */
    protected function configureIO(InputInterface $input, OutputInterface $output)
    {
        if (\true === $input->hasParameterOption(['--ansi'], \true)) {
            $output->setDecorated(\true);
        } elseif (\true === $input->hasParameterOption(['--no-ansi'], \true)) {
            $output->setDecorated(\false);
        }
        if (\true === $input->hasParameterOption(['--no-interaction', '-n'], \true)) {
            $input->setInteractive(\false);
        }
        switch ($shellVerbosity = (int) \getenv('SHELL_VERBOSITY')) {
            case -1:
                $output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
                break;
            case 1:
                $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
                break;
            case 2:
                $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE);
                break;
            case 3:
                $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG);
                break;
            default:
                $shellVerbosity = 0;
                break;
        }
        if (\true === $input->hasParameterOption(['--quiet', '-q'], \true)) {
            $output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
            $shellVerbosity = -1;
        } else {
            if ($input->hasParameterOption('-vvv', \true) || $input->hasParameterOption('--verbose=3', \true) || 3 === $input->getParameterOption('--verbose', \false, \true)) {
                $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG);
                $shellVerbosity = 3;
            } elseif ($input->hasParameterOption('-vv', \true) || $input->hasParameterOption('--verbose=2', \true) || 2 === $input->getParameterOption('--verbose', \false, \true)) {
                $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE);
                $shellVerbosity = 2;
            } elseif ($input->hasParameterOption('-v', \true) || $input->hasParameterOption('--verbose=1', \true) || $input->hasParameterOption('--verbose', \true) || $input->getParameterOption('--verbose', \false, \true)) {
                $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
                $shellVerbosity = 1;
            }
        }
        if (-1 === $shellVerbosity) {
            $input->setInteractive(\false);
        }
        if (\function_exists('putenv')) {
            @\putenv('SHELL_VERBOSITY=' . $shellVerbosity);
        }
        $_ENV['SHELL_VERBOSITY'] = $shellVerbosity;
        $_SERVER['SHELL_VERBOSITY'] = $shellVerbosity;
    }
    /**
     * Runs the current command.
     *
     * If an event dispatcher has been attached to the application,
     * events are also dispatched during the life-cycle of the command.
     *
     * @return int 0 if everything went fine, or an error code
     */
    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);
        }
        // bind before the console.command event, so the listeners have access to input options/arguments
        try {
            $command->mergeApplicationDefinition();
            $input->bind($command->getDefinition());
        } catch (ExceptionInterface $e) {
            // ignore invalid options/arguments for now, to allow the event listeners to customize the InputDefinition
        }
        $event = new ConsoleCommandEvent($command, $input, $output);
        $e = null;
        try {
            $this->dispatcher->dispatch($event, ConsoleEvents::COMMAND);
            if ($event->commandShouldRun()) {
                $exitCode = $command->run($input, $output);
            } else {
                $exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED;
            }
        } catch (\Throwable $e) {
            $event = new ConsoleErrorEvent($input, $output, $e, $command);
            $this->dispatcher->dispatch($event, ConsoleEvents::ERROR);
            $e = $event->getError();
            if (0 === ($exitCode = $event->getExitCode())) {
                $e = null;
            }
        }
        $event = new ConsoleTerminateEvent($command, $input, $output, $exitCode);
        $this->dispatcher->dispatch($event, ConsoleEvents::TERMINATE);
        if (null !== $e) {
            throw $e;
        }
        return $event->getExitCode();
    }
    /**
     * Gets the name of the command based on input.
     *
     * @return string|null
     */
    protected function getCommandName(InputInterface $input)
    {
        return $this->singleCommand ? $this->defaultCommand : $input->getFirstArgument();
    }
    /**
     * Gets the default input definition.
     *
     * @return InputDefinition An InputDefinition instance
     */
    protected function getDefaultInputDefinition()
    {
        return new InputDefinition([new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'), new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display this help message'), new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'), new InputOption('--verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'), new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this application version'), new InputOption('--ansi', '', InputOption::VALUE_NONE, 'Force ANSI output'), new InputOption('--no-ansi', '', InputOption::VALUE_NONE, 'Disable ANSI output'), new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question')]);
    }
    /**
     * Gets the default commands that should always be available.
     *
     * @return Command[] An array of default Command instances
     */
    protected function getDefaultCommands()
    {
        return [new HelpCommand(), new ListCommand()];
    }
    /**
     * Gets the default helper set with the helpers that should always be available.
     *
     * @return HelperSet A HelperSet instance
     */
    protected function getDefaultHelperSet()
    {
        return new HelperSet([new FormatterHelper(), new DebugFormatterHelper(), new ProcessHelper(), new QuestionHelper()]);
    }
    /**
     * Returns abbreviated suggestions in string format.
     */
    private function getAbbreviationSuggestions(array $abbrevs) : string
    {
        return '    ' . \implode("\n    ", $abbrevs);
    }
    /**
     * Returns the namespace part of the command name.
     *
     * This method is not part of public API and should not be used directly.
     *
     * @param string $name  The full name of the command
     * @param string $limit The maximum number of parts of the namespace
     *
     * @return string The namespace of the command
     */
    public function extractNamespace($name, $limit = null)
    {
        $parts = \explode(':', $name, -1);
        return \implode(':', null === $limit ? $parts : \array_slice($parts, 0, $limit));
    }
    /**
     * Finds alternative of $name among $collection,
     * if nothing is found in $collection, try in $abbrevs.
     *
     * @return string[] A sorted array of similar string
     */
    private function findAlternatives(string $name, iterable $collection) : array
    {
        $threshold = 1000.0;
        $alternatives = [];
        $collectionParts = [];
        foreach ($collection as $item) {
            $collectionParts[$item] = \explode(':', $item);
        }
        foreach (\explode(':', $name) as $i => $subname) {
            foreach ($collectionParts as $collectionName => $parts) {
                $exists = isset($alternatives[$collectionName]);
                if (!isset($parts[$i]) && $exists) {
                    $alternatives[$collectionName] += $threshold;
                    continue;
                } elseif (!isset($parts[$i])) {
                    continue;
                }
                $lev = \levenshtein($subname, $parts[$i]);
                if ($lev <= \strlen($subname) / 3 || '' !== $subname && \str_contains($parts[$i], $subname)) {
                    $alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev;
                } elseif ($exists) {
                    $alternatives[$collectionName] += $threshold;
                }
            }
        }
        foreach ($collection as $item) {
            $lev = \levenshtein($name, $item);
            if ($lev <= \strlen($name) / 3 || \str_contains($item, $name)) {
                $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev;
            }
        }
        $alternatives = \array_filter($alternatives, function ($lev) use($threshold) {
            return $lev < 2 * $threshold;
        });
        \ksort($alternatives, \SORT_NATURAL | \SORT_FLAG_CASE);
        return \array_keys($alternatives);
    }
    /**
     * Sets the default Command name.
     *
     * @param string $commandName     The Command name
     * @param bool   $isSingleCommand Set to true if there is only one command in this application
     *
     * @return self
     */
    public function setDefaultCommand($commandName, $isSingleCommand = \false)
    {
        $this->defaultCommand = $commandName;
        if ($isSingleCommand) {
            // Ensure the command exist
            $this->find($commandName);
            $this->singleCommand = \true;
        }
        return $this;
    }
    /**
     * @internal
     */
    public function isSingleCommand() : bool
    {
        return $this->singleCommand;
    }
    private function splitStringByWidth(string $string, int $width) : array
    {
        // str_split is not suitable for multi-byte characters, we should use preg_split to get char array properly.
        // additionally, array_slice() is not enough as some character has doubled width.
        // we need a function to split string not by character count but by string width
        if (\false === ($encoding = \mb_detect_encoding($string, null, \true))) {
            return \str_split($string, $width);
        }
        $utf8String = \mb_convert_encoding($string, 'utf8', $encoding);
        $lines = [];
        $line = '';
        $offset = 0;
        while (\preg_match('/.{1,10000}/u', $utf8String, $m, 0, $offset)) {
            $offset += \strlen($m[0]);
            foreach (\preg_split('//u', $m[0]) as $char) {
                // test if $char could be appended to current line
                if (\mb_strwidth($line . $char, 'utf8') <= $width) {
                    $line .= $char;
                    continue;
                }
                // if not, push current line to array and make new line
                $lines[] = \str_pad($line, $width);
                $line = $char;
            }
        }
        $lines[] = \count($lines) ? \str_pad($line, $width) : $line;
        \mb_convert_variables($encoding, 'utf8', $lines);
        return $lines;
    }
    /**
     * Returns all namespaces of the command name.
     *
     * @return string[] The namespaces of the command
     */
    private function extractAllNamespaces(string $name) : array
    {
        // -1 as third argument is needed to skip the command short name when exploding
        $parts = \explode(':', $name, -1);
        $namespaces = [];
        foreach ($parts as $part) {
            if (\count($namespaces)) {
                $namespaces[] = \end($namespaces) . ':' . $part;
            } else {
                $namespaces[] = $part;
            }
        }
        return $namespaces;
    }
    private function init()
    {
        if ($this->initialized) {
            return;
        }
        $this->initialized = \true;
        foreach ($this->getDefaultCommands() as $command) {
            $this->add($command);
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console;

/**
 * Contains all events dispatched by an Application.
 *
 * @author Francesco Levorato <git@flevour.net>
 */
final class ConsoleEvents
{
    /**
     * The COMMAND event allows you to attach listeners before any command is
     * executed by the console. It also allows you to modify the command, input and output
     * before they are handed to the command.
     *
     * @Event("Symfony\Component\Console\Event\ConsoleCommandEvent")
     */
    public const COMMAND = 'console.command';
    /**
     * The TERMINATE event allows you to attach listeners after a command is
     * executed by the console.
     *
     * @Event("Symfony\Component\Console\Event\ConsoleTerminateEvent")
     */
    public const TERMINATE = 'console.terminate';
    /**
     * The ERROR event occurs when an uncaught exception or error appears.
     *
     * This event allows you to deal with the exception/error or
     * to modify the thrown exception.
     *
     * @Event("Symfony\Component\Console\Event\ConsoleErrorEvent")
     */
    public const ERROR = 'console.error';
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Style;

use CivixPhar\Symfony\Component\Console\Formatter\OutputFormatterInterface;
use CivixPhar\Symfony\Component\Console\Helper\ProgressBar;
use CivixPhar\Symfony\Component\Console\Output\ConsoleOutputInterface;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
/**
 * Decorates output to add console style guide helpers.
 *
 * @author Kevin Bond <kevinbond@gmail.com>
 */
abstract class OutputStyle implements OutputInterface, StyleInterface
{
    private $output;
    public function __construct(OutputInterface $output)
    {
        $this->output = $output;
    }
    /**
     * {@inheritdoc}
     */
    public function newLine($count = 1)
    {
        $this->output->write(\str_repeat(\PHP_EOL, $count));
    }
    /**
     * @param int $max
     *
     * @return ProgressBar
     */
    public function createProgressBar($max = 0)
    {
        return new ProgressBar($this->output, $max);
    }
    /**
     * {@inheritdoc}
     */
    public function write($messages, $newline = \false, $type = self::OUTPUT_NORMAL)
    {
        $this->output->write($messages, $newline, $type);
    }
    /**
     * {@inheritdoc}
     */
    public function writeln($messages, $type = self::OUTPUT_NORMAL)
    {
        $this->output->writeln($messages, $type);
    }
    /**
     * {@inheritdoc}
     */
    public function setVerbosity($level)
    {
        $this->output->setVerbosity($level);
    }
    /**
     * {@inheritdoc}
     */
    public function getVerbosity()
    {
        return $this->output->getVerbosity();
    }
    /**
     * {@inheritdoc}
     */
    public function setDecorated($decorated)
    {
        $this->output->setDecorated($decorated);
    }
    /**
     * {@inheritdoc}
     */
    public function isDecorated()
    {
        return $this->output->isDecorated();
    }
    /**
     * {@inheritdoc}
     */
    public function setFormatter(OutputFormatterInterface $formatter)
    {
        $this->output->setFormatter($formatter);
    }
    /**
     * {@inheritdoc}
     */
    public function getFormatter()
    {
        return $this->output->getFormatter();
    }
    /**
     * {@inheritdoc}
     */
    public function isQuiet()
    {
        return $this->output->isQuiet();
    }
    /**
     * {@inheritdoc}
     */
    public function isVerbose()
    {
        return $this->output->isVerbose();
    }
    /**
     * {@inheritdoc}
     */
    public function isVeryVerbose()
    {
        return $this->output->isVeryVerbose();
    }
    /**
     * {@inheritdoc}
     */
    public function isDebug()
    {
        return $this->output->isDebug();
    }
    protected function getErrorOutput()
    {
        if (!$this->output instanceof ConsoleOutputInterface) {
            return $this->output;
        }
        return $this->output->getErrorOutput();
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Style;

use CivixPhar\Symfony\Component\Console\Exception\InvalidArgumentException;
use CivixPhar\Symfony\Component\Console\Exception\RuntimeException;
use CivixPhar\Symfony\Component\Console\Formatter\OutputFormatter;
use CivixPhar\Symfony\Component\Console\Helper\Helper;
use CivixPhar\Symfony\Component\Console\Helper\ProgressBar;
use CivixPhar\Symfony\Component\Console\Helper\SymfonyQuestionHelper;
use CivixPhar\Symfony\Component\Console\Helper\Table;
use CivixPhar\Symfony\Component\Console\Helper\TableCell;
use CivixPhar\Symfony\Component\Console\Helper\TableSeparator;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CivixPhar\Symfony\Component\Console\Output\TrimmedBufferOutput;
use CivixPhar\Symfony\Component\Console\Question\ChoiceQuestion;
use CivixPhar\Symfony\Component\Console\Question\ConfirmationQuestion;
use CivixPhar\Symfony\Component\Console\Question\Question;
use CivixPhar\Symfony\Component\Console\Terminal;
/**
 * Output decorator helpers for the Symfony Style Guide.
 *
 * @author Kevin Bond <kevinbond@gmail.com>
 */
class SymfonyStyle extends OutputStyle
{
    public const MAX_LINE_LENGTH = 120;
    private $input;
    private $questionHelper;
    private $progressBar;
    private $lineLength;
    private $bufferedOutput;
    public function __construct(InputInterface $input, OutputInterface $output)
    {
        $this->input = $input;
        $this->bufferedOutput = new TrimmedBufferOutput(\DIRECTORY_SEPARATOR === '\\' ? 4 : 2, $output->getVerbosity(), \false, clone $output->getFormatter());
        // Windows cmd wraps lines as soon as the terminal width is reached, whether there are following chars or not.
        $width = (new Terminal())->getWidth() ?: self::MAX_LINE_LENGTH;
        $this->lineLength = \min($width - (int) (\DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH);
        parent::__construct($output);
    }
    /**
     * Formats a message as a block of text.
     *
     * @param string|array $messages The message to write in the block
     * @param string|null  $type     The block type (added in [] on first line)
     * @param string|null  $style    The style to apply to the whole block
     * @param string       $prefix   The prefix for the block
     * @param bool         $padding  Whether to add vertical padding
     * @param bool         $escape   Whether to escape the message
     */
    public function block($messages, $type = null, $style = null, $prefix = ' ', $padding = \false, $escape = \true)
    {
        $messages = \is_array($messages) ? \array_values($messages) : [$messages];
        $this->autoPrependBlock();
        $this->writeln($this->createBlock($messages, $type, $style, $prefix, $padding, $escape));
        $this->newLine();
    }
    /**
     * {@inheritdoc}
     */
    public function title($message)
    {
        $this->autoPrependBlock();
        $this->writeln([\sprintf('<comment>%s</>', OutputFormatter::escapeTrailingBackslash($message)), \sprintf('<comment>%s</>', \str_repeat('=', Helper::strlenWithoutDecoration($this->getFormatter(), $message)))]);
        $this->newLine();
    }
    /**
     * {@inheritdoc}
     */
    public function section($message)
    {
        $this->autoPrependBlock();
        $this->writeln([\sprintf('<comment>%s</>', OutputFormatter::escapeTrailingBackslash($message)), \sprintf('<comment>%s</>', \str_repeat('-', Helper::strlenWithoutDecoration($this->getFormatter(), $message)))]);
        $this->newLine();
    }
    /**
     * {@inheritdoc}
     */
    public function listing(array $elements)
    {
        $this->autoPrependText();
        $elements = \array_map(function ($element) {
            return \sprintf(' * %s', $element);
        }, $elements);
        $this->writeln($elements);
        $this->newLine();
    }
    /**
     * {@inheritdoc}
     */
    public function text($message)
    {
        $this->autoPrependText();
        $messages = \is_array($message) ? \array_values($message) : [$message];
        foreach ($messages as $message) {
            $this->writeln(\sprintf(' %s', $message));
        }
    }
    /**
     * Formats a command comment.
     *
     * @param string|array $message
     */
    public function comment($message)
    {
        $this->block($message, null, null, '<fg=default;bg=default> // </>', \false, \false);
    }
    /**
     * {@inheritdoc}
     */
    public function success($message)
    {
        $this->block($message, 'OK', 'fg=black;bg=green', ' ', \true);
    }
    /**
     * {@inheritdoc}
     */
    public function error($message)
    {
        $this->block($message, 'ERROR', 'fg=white;bg=red', ' ', \true);
    }
    /**
     * {@inheritdoc}
     */
    public function warning($message)
    {
        $this->block($message, 'WARNING', 'fg=black;bg=yellow', ' ', \true);
    }
    /**
     * {@inheritdoc}
     */
    public function note($message)
    {
        $this->block($message, 'NOTE', 'fg=yellow', ' ! ');
    }
    /**
     * {@inheritdoc}
     */
    public function caution($message)
    {
        $this->block($message, 'CAUTION', 'fg=white;bg=red', ' ! ', \true);
    }
    /**
     * {@inheritdoc}
     */
    public function table(array $headers, array $rows)
    {
        $style = clone Table::getStyleDefinition('symfony-style-guide');
        $style->setCellHeaderFormat('<info>%s</info>');
        $table = new Table($this);
        $table->setHeaders($headers);
        $table->setRows($rows);
        $table->setStyle($style);
        $table->render();
        $this->newLine();
    }
    /**
     * Formats a horizontal table.
     */
    public function horizontalTable(array $headers, array $rows)
    {
        $style = clone Table::getStyleDefinition('symfony-style-guide');
        $style->setCellHeaderFormat('<info>%s</info>');
        $table = new Table($this);
        $table->setHeaders($headers);
        $table->setRows($rows);
        $table->setStyle($style);
        $table->setHorizontal(\true);
        $table->render();
        $this->newLine();
    }
    /**
     * Formats a list of key/value horizontally.
     *
     * Each row can be one of:
     * * 'A title'
     * * ['key' => 'value']
     * * new TableSeparator()
     *
     * @param string|array|TableSeparator ...$list
     */
    public function definitionList(...$list)
    {
        $style = clone Table::getStyleDefinition('symfony-style-guide');
        $style->setCellHeaderFormat('<info>%s</info>');
        $table = new Table($this);
        $headers = [];
        $row = [];
        foreach ($list as $value) {
            if ($value instanceof TableSeparator) {
                $headers[] = $value;
                $row[] = $value;
                continue;
            }
            if (\is_string($value)) {
                $headers[] = new TableCell($value, ['colspan' => 2]);
                $row[] = null;
                continue;
            }
            if (!\is_array($value)) {
                throw new InvalidArgumentException('Value should be an array, string, or an instance of TableSeparator.');
            }
            $headers[] = \key($value);
            $row[] = \current($value);
        }
        $table->setHeaders($headers);
        $table->setRows([$row]);
        $table->setHorizontal();
        $table->setStyle($style);
        $table->render();
        $this->newLine();
    }
    /**
     * {@inheritdoc}
     */
    public function ask($question, $default = null, $validator = null)
    {
        $question = new Question($question, $default);
        $question->setValidator($validator);
        return $this->askQuestion($question);
    }
    /**
     * {@inheritdoc}
     */
    public function askHidden($question, $validator = null)
    {
        $question = new Question($question);
        $question->setHidden(\true);
        $question->setValidator($validator);
        return $this->askQuestion($question);
    }
    /**
     * {@inheritdoc}
     */
    public function confirm($question, $default = \true)
    {
        return $this->askQuestion(new ConfirmationQuestion($question, $default));
    }
    /**
     * {@inheritdoc}
     */
    public function choice($question, array $choices, $default = null)
    {
        if (null !== $default) {
            $values = \array_flip($choices);
            $default = $values[$default] ?? $default;
        }
        return $this->askQuestion(new ChoiceQuestion($question, $choices, $default));
    }
    /**
     * {@inheritdoc}
     */
    public function progressStart($max = 0)
    {
        $this->progressBar = $this->createProgressBar($max);
        $this->progressBar->start();
    }
    /**
     * {@inheritdoc}
     */
    public function progressAdvance($step = 1)
    {
        $this->getProgressBar()->advance($step);
    }
    /**
     * {@inheritdoc}
     */
    public function progressFinish()
    {
        $this->getProgressBar()->finish();
        $this->newLine(2);
        $this->progressBar = null;
    }
    /**
     * {@inheritdoc}
     */
    public function createProgressBar($max = 0)
    {
        $progressBar = parent::createProgressBar($max);
        if ('\\' !== \DIRECTORY_SEPARATOR || 'Hyper' === \getenv('TERM_PROGRAM')) {
            $progressBar->setEmptyBarCharacter('â–‘');
            // light shade character \u2591
            $progressBar->setProgressCharacter('');
            $progressBar->setBarCharacter('â–“');
            // dark shade character \u2593
        }
        return $progressBar;
    }
    /**
     * @return mixed
     */
    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;
    }
    /**
     * {@inheritdoc}
     */
    public function writeln($messages, $type = self::OUTPUT_NORMAL)
    {
        if (!\is_iterable($messages)) {
            $messages = [$messages];
        }
        foreach ($messages as $message) {
            parent::writeln($message, $type);
            $this->writeBuffer($message, \true, $type);
        }
    }
    /**
     * {@inheritdoc}
     */
    public function write($messages, $newline = \false, $type = self::OUTPUT_NORMAL)
    {
        if (!\is_iterable($messages)) {
            $messages = [$messages];
        }
        foreach ($messages as $message) {
            parent::write($message, $newline, $type);
            $this->writeBuffer($message, $newline, $type);
        }
    }
    /**
     * {@inheritdoc}
     */
    public function newLine($count = 1)
    {
        parent::newLine($count);
        $this->bufferedOutput->write(\str_repeat("\n", $count));
    }
    /**
     * Returns a new instance which makes use of stderr if available.
     *
     * @return self
     */
    public function getErrorStyle()
    {
        return new self($this->input, $this->getErrorOutput());
    }
    private function getProgressBar() : ProgressBar
    {
        if (!$this->progressBar) {
            throw new RuntimeException('The ProgressBar is not started.');
        }
        return $this->progressBar;
    }
    private function autoPrependBlock() : void
    {
        $chars = \substr(\str_replace(\PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2);
        if (!isset($chars[0])) {
            $this->newLine();
            //empty history, so we should start with a new line.
            return;
        }
        //Prepend new line for each non LF chars (This means no blank line was output before)
        $this->newLine(2 - \substr_count($chars, "\n"));
    }
    private function autoPrependText() : void
    {
        $fetched = $this->bufferedOutput->fetch();
        //Prepend new line if last char isn't EOL:
        if (!\str_ends_with($fetched, "\n")) {
            $this->newLine();
        }
    }
    private function writeBuffer(string $message, bool $newLine, int $type) : void
    {
        // We need to know if the last chars are PHP_EOL
        $this->bufferedOutput->write($message, $newLine, $type);
    }
    private function createBlock(iterable $messages, string $type = null, string $style = null, string $prefix = ' ', bool $padding = \false, bool $escape = \false) : array
    {
        $indentLength = 0;
        $prefixLength = Helper::strlenWithoutDecoration($this->getFormatter(), $prefix);
        $lines = [];
        if (null !== $type) {
            $type = \sprintf('[%s] ', $type);
            $indentLength = \strlen($type);
            $lineIndentation = \str_repeat(' ', $indentLength);
        }
        // wrap and add newlines for each element
        foreach ($messages as $key => $message) {
            if ($escape) {
                $message = OutputFormatter::escape($message);
            }
            $decorationLength = Helper::strlen($message) - Helper::strlenWithoutDecoration($this->getFormatter(), $message);
            $messageLineLength = \min($this->lineLength - $prefixLength - $indentLength + $decorationLength, $this->lineLength);
            $messageLines = \explode(\PHP_EOL, \wordwrap($message, $messageLineLength, \PHP_EOL, \true));
            foreach ($messageLines as $messageLine) {
                $lines[] = $messageLine;
            }
            if (\count($messages) > 1 && $key < \count($messages) - 1) {
                $lines[] = '';
            }
        }
        $firstLineIndex = 0;
        if ($padding && $this->isDecorated()) {
            $firstLineIndex = 1;
            \array_unshift($lines, '');
            $lines[] = '';
        }
        foreach ($lines as $i => &$line) {
            if (null !== $type) {
                $line = $firstLineIndex === $i ? $type . $line : $lineIndentation . $line;
            }
            $line = $prefix . $line;
            $line .= \str_repeat(' ', \max($this->lineLength - Helper::strlenWithoutDecoration($this->getFormatter(), $line), 0));
            if ($style) {
                $line = \sprintf('<%s>%s</>', $style, $line);
            }
        }
        return $lines;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Style;

/**
 * Output style helpers.
 *
 * @author Kevin Bond <kevinbond@gmail.com>
 */
interface StyleInterface
{
    /**
     * Formats a command title.
     *
     * @param string $message
     */
    public function title($message);
    /**
     * Formats a section title.
     *
     * @param string $message
     */
    public function section($message);
    /**
     * Formats a list.
     */
    public function listing(array $elements);
    /**
     * Formats informational text.
     *
     * @param string|array $message
     */
    public function text($message);
    /**
     * Formats a success result bar.
     *
     * @param string|array $message
     */
    public function success($message);
    /**
     * Formats an error result bar.
     *
     * @param string|array $message
     */
    public function error($message);
    /**
     * Formats an warning result bar.
     *
     * @param string|array $message
     */
    public function warning($message);
    /**
     * Formats a note admonition.
     *
     * @param string|array $message
     */
    public function note($message);
    /**
     * Formats a caution admonition.
     *
     * @param string|array $message
     */
    public function caution($message);
    /**
     * Formats a table.
     */
    public function table(array $headers, array $rows);
    /**
     * Asks a question.
     *
     * @param string        $question
     * @param string|null   $default
     * @param callable|null $validator
     *
     * @return mixed
     */
    public function ask($question, $default = null, $validator = null);
    /**
     * Asks a question with the user input hidden.
     *
     * @param string        $question
     * @param callable|null $validator
     *
     * @return mixed
     */
    public function askHidden($question, $validator = null);
    /**
     * Asks for confirmation.
     *
     * @param string $question
     * @param bool   $default
     *
     * @return bool
     */
    public function confirm($question, $default = \true);
    /**
     * Asks a choice question.
     *
     * @param string          $question
     * @param string|int|null $default
     *
     * @return mixed
     */
    public function choice($question, array $choices, $default = null);
    /**
     * Add newline(s).
     *
     * @param int $count The number of newlines
     */
    public function newLine($count = 1);
    /**
     * Starts the progress output.
     *
     * @param int $max Maximum steps (0 if unknown)
     */
    public function progressStart($max = 0);
    /**
     * Advances the progress output X steps.
     *
     * @param int $step Number of steps to advance
     */
    public function progressAdvance($step = 1);
    /**
     * Finishes the progress output.
     */
    public function progressFinish();
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Input;

use CivixPhar\Symfony\Component\Console\Exception\InvalidArgumentException;
/**
 * StringInput represents an input provided as a string.
 *
 * Usage:
 *
 *     $input = new StringInput('foo --bar="foobar"');
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class StringInput extends ArgvInput
{
    public const REGEX_STRING = '([^\\s]+?)(?:\\s|(?<!\\\\)"|(?<!\\\\)\'|$)';
    public const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')';
    /**
     * @param string $input A string representing the parameters from the CLI
     */
    public function __construct(string $input)
    {
        parent::__construct([]);
        $this->setTokens($this->tokenize($input));
    }
    /**
     * Tokenizes a string.
     *
     * @throws InvalidArgumentException When unable to parse input (should never happen)
     */
    private function tokenize(string $input) : array
    {
        $tokens = [];
        $length = \strlen($input);
        $cursor = 0;
        while ($cursor < $length) {
            if (\preg_match('/\\s+/A', $input, $match, 0, $cursor)) {
            } elseif (\preg_match('/([^="\'\\s]+?)(=?)(' . self::REGEX_QUOTED_STRING . '+)/A', $input, $match, 0, $cursor)) {
                $tokens[] = $match[1] . $match[2] . \stripcslashes(\str_replace(['"\'', '\'"', '\'\'', '""'], '', \substr($match[3], 1, -1)));
            } elseif (\preg_match('/' . self::REGEX_QUOTED_STRING . '/A', $input, $match, 0, $cursor)) {
                $tokens[] = \stripcslashes(\substr($match[0], 1, -1));
            } elseif (\preg_match('/' . self::REGEX_STRING . '/A', $input, $match, 0, $cursor)) {
                $tokens[] = \stripcslashes($match[1]);
            } else {
                // should never happen
                throw new InvalidArgumentException(\sprintf('Unable to parse input near "... %s ...".', \substr($input, $cursor, 10)));
            }
            $cursor += \strlen($match[0]);
        }
        return $tokens;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Input;

use CivixPhar\Symfony\Component\Console\Exception\InvalidArgumentException;
use CivixPhar\Symfony\Component\Console\Exception\LogicException;
/**
 * A InputDefinition represents a set of valid command line arguments and options.
 *
 * Usage:
 *
 *     $definition = new InputDefinition([
 *         new InputArgument('name', InputArgument::REQUIRED),
 *         new InputOption('foo', 'f', InputOption::VALUE_REQUIRED),
 *     ]);
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class InputDefinition
{
    private $arguments;
    private $requiredCount;
    private $hasAnArrayArgument = \false;
    private $hasOptional;
    private $options;
    private $shortcuts;
    /**
     * @param array $definition An array of InputArgument and InputOption instance
     */
    public function __construct(array $definition = [])
    {
        $this->setDefinition($definition);
    }
    /**
     * Sets the definition of the input.
     */
    public function setDefinition(array $definition)
    {
        $arguments = [];
        $options = [];
        foreach ($definition as $item) {
            if ($item instanceof InputOption) {
                $options[] = $item;
            } else {
                $arguments[] = $item;
            }
        }
        $this->setArguments($arguments);
        $this->setOptions($options);
    }
    /**
     * Sets the InputArgument objects.
     *
     * @param InputArgument[] $arguments An array of InputArgument objects
     */
    public function setArguments($arguments = [])
    {
        $this->arguments = [];
        $this->requiredCount = 0;
        $this->hasOptional = \false;
        $this->hasAnArrayArgument = \false;
        $this->addArguments($arguments);
    }
    /**
     * Adds an array of InputArgument objects.
     *
     * @param InputArgument[] $arguments An array of InputArgument objects
     */
    public function addArguments($arguments = [])
    {
        if (null !== $arguments) {
            foreach ($arguments as $argument) {
                $this->addArgument($argument);
            }
        }
    }
    /**
     * @throws LogicException When incorrect argument is given
     */
    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;
    }
    /**
     * Returns an InputArgument by name or by position.
     *
     * @param string|int $name The InputArgument name or position
     *
     * @return InputArgument An InputArgument object
     *
     * @throws InvalidArgumentException When argument given doesn't exist
     */
    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];
    }
    /**
     * Returns true if an InputArgument object exists by name or position.
     *
     * @param string|int $name The InputArgument name or position
     *
     * @return bool true if the InputArgument object exists, false otherwise
     */
    public function hasArgument($name)
    {
        $arguments = \is_int($name) ? \array_values($this->arguments) : $this->arguments;
        return isset($arguments[$name]);
    }
    /**
     * Gets the array of InputArgument objects.
     *
     * @return InputArgument[] An array of InputArgument objects
     */
    public function getArguments()
    {
        return $this->arguments;
    }
    /**
     * Returns the number of InputArguments.
     *
     * @return int The number of InputArguments
     */
    public function getArgumentCount()
    {
        return $this->hasAnArrayArgument ? \PHP_INT_MAX : \count($this->arguments);
    }
    /**
     * Returns the number of required InputArguments.
     *
     * @return int The number of required InputArguments
     */
    public function getArgumentRequiredCount()
    {
        return $this->requiredCount;
    }
    /**
     * @return array<string|bool|int|float|array|null>
     */
    public function getArgumentDefaults()
    {
        $values = [];
        foreach ($this->arguments as $argument) {
            $values[$argument->getName()] = $argument->getDefault();
        }
        return $values;
    }
    /**
     * Sets the InputOption objects.
     *
     * @param InputOption[] $options An array of InputOption objects
     */
    public function setOptions($options = [])
    {
        $this->options = [];
        $this->shortcuts = [];
        $this->addOptions($options);
    }
    /**
     * Adds an array of InputOption objects.
     *
     * @param InputOption[] $options An array of InputOption objects
     */
    public function addOptions($options = [])
    {
        foreach ($options as $option) {
            $this->addOption($option);
        }
    }
    /**
     * @throws LogicException When option given already exist
     */
    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();
            }
        }
    }
    /**
     * Returns an InputOption by name.
     *
     * @param string $name The InputOption name
     *
     * @return InputOption A InputOption object
     *
     * @throws InvalidArgumentException When option given doesn't exist
     */
    public function getOption($name)
    {
        if (!$this->hasOption($name)) {
            throw new InvalidArgumentException(\sprintf('The "--%s" option does not exist.', $name));
        }
        return $this->options[$name];
    }
    /**
     * Returns true if an InputOption object exists by name.
     *
     * This method can't be used to check if the user included the option when
     * executing the command (use getOption() instead).
     *
     * @param string $name The InputOption name
     *
     * @return bool true if the InputOption object exists, false otherwise
     */
    public function hasOption($name)
    {
        return isset($this->options[$name]);
    }
    /**
     * Gets the array of InputOption objects.
     *
     * @return InputOption[] An array of InputOption objects
     */
    public function getOptions()
    {
        return $this->options;
    }
    /**
     * Returns true if an InputOption object exists by shortcut.
     *
     * @param string $name The InputOption shortcut
     *
     * @return bool true if the InputOption object exists, false otherwise
     */
    public function hasShortcut($name)
    {
        return isset($this->shortcuts[$name]);
    }
    /**
     * Gets an InputOption by shortcut.
     *
     * @param string $shortcut The Shortcut name
     *
     * @return InputOption An InputOption object
     */
    public function getOptionForShortcut($shortcut)
    {
        return $this->getOption($this->shortcutToName($shortcut));
    }
    /**
     * @return array<string|bool|int|float|array|null>
     */
    public function getOptionDefaults()
    {
        $values = [];
        foreach ($this->options as $option) {
            $values[$option->getName()] = $option->getDefault();
        }
        return $values;
    }
    /**
     * Returns the InputOption name given a shortcut.
     *
     * @throws InvalidArgumentException When option given does not exist
     *
     * @internal
     */
    public function shortcutToName(string $shortcut) : string
    {
        if (!isset($this->shortcuts[$shortcut])) {
            throw new InvalidArgumentException(\sprintf('The "-%s" option does not exist.', $shortcut));
        }
        return $this->shortcuts[$shortcut];
    }
    /**
     * Gets the synopsis.
     *
     * @param bool $short Whether to return the short version (with options folded) or not
     *
     * @return string The synopsis
     */
    public function getSynopsis($short = \false)
    {
        $elements = [];
        if ($short && $this->getOptions()) {
            $elements[] = '[options]';
        } elseif (!$short) {
            foreach ($this->getOptions() as $option) {
                $value = '';
                if ($option->acceptValue()) {
                    $value = \sprintf(' %s%s%s', $option->isValueOptional() ? '[' : '', \strtoupper($option->getName()), $option->isValueOptional() ? ']' : '');
                }
                $shortcut = $option->getShortcut() ? \sprintf('-%s|', $option->getShortcut()) : '';
                $elements[] = \sprintf('[%s--%s%s]', $shortcut, $option->getName(), $value);
            }
        }
        if (\count($elements) && $this->getArguments()) {
            $elements[] = '[--]';
        }
        $tail = '';
        foreach ($this->getArguments() as $argument) {
            $element = '<' . $argument->getName() . '>';
            if ($argument->isArray()) {
                $element .= '...';
            }
            if (!$argument->isRequired()) {
                $element = '[' . $element;
                $tail .= ']';
            }
            $elements[] = $element;
        }
        return \implode(' ', $elements) . $tail;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Input;

/**
 * StreamableInputInterface is the interface implemented by all input classes
 * that have an input stream.
 *
 * @author Robin Chalas <robin.chalas@gmail.com>
 */
interface StreamableInputInterface extends InputInterface
{
    /**
     * Sets the input stream to read from when interacting with the user.
     *
     * This is mainly useful for testing purpose.
     *
     * @param resource $stream The input stream
     */
    public function setStream($stream);
    /**
     * Returns the input stream.
     *
     * @return resource|null
     */
    public function getStream();
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Input;

/**
 * InputAwareInterface should be implemented by classes that depends on the
 * Console Input.
 *
 * @author Wouter J <waldio.webdesign@gmail.com>
 */
interface InputAwareInterface
{
    /**
     * Sets the Console Input.
     */
    public function setInput(InputInterface $input);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Input;

use CivixPhar\Symfony\Component\Console\Exception\RuntimeException;
/**
 * ArgvInput represents an input coming from the CLI arguments.
 *
 * Usage:
 *
 *     $input = new ArgvInput();
 *
 * By default, the `$_SERVER['argv']` array is used for the input values.
 *
 * This can be overridden by explicitly passing the input values in the constructor:
 *
 *     $input = new ArgvInput($_SERVER['argv']);
 *
 * If you pass it yourself, don't forget that the first element of the array
 * is the name of the running application.
 *
 * When passing an argument to the constructor, be sure that it respects
 * the same rules as the argv one. It's almost always better to use the
 * `StringInput` when you want to provide your own input.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 *
 * @see http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
 * @see http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html#tag_12_02
 */
class ArgvInput extends Input
{
    private $tokens;
    private $parsed;
    /**
     * @param array|null $argv An array of parameters from the CLI (in the argv format)
     */
    public function __construct(array $argv = null, InputDefinition $definition = null)
    {
        $argv = $argv ?? $_SERVER['argv'] ?? [];
        // strip the application name
        \array_shift($argv);
        $this->tokens = $argv;
        parent::__construct($definition);
    }
    protected function setTokens(array $tokens)
    {
        $this->tokens = $tokens;
    }
    /**
     * {@inheritdoc}
     */
    protected function parse()
    {
        $parseOptions = \true;
        $this->parsed = $this->tokens;
        while (null !== ($token = \array_shift($this->parsed))) {
            if ($parseOptions && '' == $token) {
                $this->parseArgument($token);
            } elseif ($parseOptions && '--' == $token) {
                $parseOptions = \false;
            } elseif ($parseOptions && \str_starts_with($token, '--')) {
                $this->parseLongOption($token);
            } elseif ($parseOptions && '-' === $token[0] && '-' !== $token) {
                $this->parseShortOption($token);
            } else {
                $this->parseArgument($token);
            }
        }
    }
    /**
     * Parses a short option.
     */
    private function parseShortOption(string $token)
    {
        $name = \substr($token, 1);
        if (\strlen($name) > 1) {
            if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptValue()) {
                // an option with a value (with no space)
                $this->addShortOption($name[0], \substr($name, 1));
            } else {
                $this->parseShortOptionSet($name);
            }
        } else {
            $this->addShortOption($name, null);
        }
    }
    /**
     * Parses a short option set.
     *
     * @throws RuntimeException When option given doesn't exist
     */
    private function parseShortOptionSet(string $name)
    {
        $len = \strlen($name);
        for ($i = 0; $i < $len; ++$i) {
            if (!$this->definition->hasShortcut($name[$i])) {
                $encoding = \mb_detect_encoding($name, null, \true);
                throw new RuntimeException(\sprintf('The "-%s" option does not exist.', \false === $encoding ? $name[$i] : \mb_substr($name, $i, 1, $encoding)));
            }
            $option = $this->definition->getOptionForShortcut($name[$i]);
            if ($option->acceptValue()) {
                $this->addLongOption($option->getName(), $i === $len - 1 ? null : \substr($name, $i + 1));
                break;
            } else {
                $this->addLongOption($option->getName(), null);
            }
        }
    }
    /**
     * Parses a long option.
     */
    private function parseLongOption(string $token)
    {
        $name = \substr($token, 2);
        if (\false !== ($pos = \strpos($name, '='))) {
            if ('' === ($value = \substr($name, $pos + 1))) {
                \array_unshift($this->parsed, $value);
            }
            $this->addLongOption(\substr($name, 0, $pos), $value);
        } else {
            $this->addLongOption($name, null);
        }
    }
    /**
     * Parses an argument.
     *
     * @throws RuntimeException When too many arguments are given
     */
    private function parseArgument(string $token)
    {
        $c = \count($this->arguments);
        // if input is expecting another argument, add it
        if ($this->definition->hasArgument($c)) {
            $arg = $this->definition->getArgument($c);
            $this->arguments[$arg->getName()] = $arg->isArray() ? [$token] : $token;
            // if last argument isArray(), append token to last argument
        } elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) {
            $arg = $this->definition->getArgument($c - 1);
            $this->arguments[$arg->getName()][] = $token;
            // unexpected argument
        } else {
            $all = $this->definition->getArguments();
            if (\count($all)) {
                throw new RuntimeException(\sprintf('Too many arguments, expected arguments "%s".', \implode('" "', \array_keys($all))));
            }
            throw new RuntimeException(\sprintf('No arguments expected, got "%s".', $token));
        }
    }
    /**
     * Adds a short option value.
     *
     * @throws RuntimeException When option given doesn't exist
     */
    private function addShortOption(string $shortcut, $value)
    {
        if (!$this->definition->hasShortcut($shortcut)) {
            throw new RuntimeException(\sprintf('The "-%s" option does not exist.', $shortcut));
        }
        $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
    }
    /**
     * Adds a long option value.
     *
     * @throws RuntimeException When option given doesn't exist
     */
    private function addLongOption(string $name, $value)
    {
        if (!$this->definition->hasOption($name)) {
            throw new RuntimeException(\sprintf('The "--%s" option does not exist.', $name));
        }
        $option = $this->definition->getOption($name);
        if (null !== $value && !$option->acceptValue()) {
            throw new RuntimeException(\sprintf('The "--%s" option does not accept a value.', $name));
        }
        if (\in_array($value, ['', null], \true) && $option->acceptValue() && \count($this->parsed)) {
            // if option accepts an optional or mandatory argument
            // let's see if there is one provided
            $next = \array_shift($this->parsed);
            if (isset($next[0]) && '-' !== $next[0] || \in_array($next, ['', null], \true)) {
                $value = $next;
            } else {
                \array_unshift($this->parsed, $next);
            }
        }
        if (null === $value) {
            if ($option->isValueRequired()) {
                throw new RuntimeException(\sprintf('The "--%s" option requires a value.', $name));
            }
            if (!$option->isArray() && !$option->isValueOptional()) {
                $value = \true;
            }
        }
        if ($option->isArray()) {
            $this->options[$name][] = $value;
        } else {
            $this->options[$name] = $value;
        }
    }
    /**
     * {@inheritdoc}
     */
    public function getFirstArgument()
    {
        $isOption = \false;
        foreach ($this->tokens as $i => $token) {
            if ($token && '-' === $token[0]) {
                if (\str_contains($token, '=') || !isset($this->tokens[$i + 1])) {
                    continue;
                }
                // If it's a long option, consider that everything after "--" is the option name.
                // Otherwise, use the last char (if it's a short option set, only the last one can take a value with space separator)
                $name = '-' === $token[1] ? \substr($token, 2) : \substr($token, -1);
                if (!isset($this->options[$name]) && !$this->definition->hasShortcut($name)) {
                    // noop
                } elseif ((isset($this->options[$name]) || isset($this->options[$name = $this->definition->shortcutToName($name)])) && $this->tokens[$i + 1] === $this->options[$name]) {
                    $isOption = \true;
                }
                continue;
            }
            if ($isOption) {
                $isOption = \false;
                continue;
            }
            return $token;
        }
        return null;
    }
    /**
     * {@inheritdoc}
     */
    public function hasParameterOption($values, $onlyParams = \false)
    {
        $values = (array) $values;
        foreach ($this->tokens as $token) {
            if ($onlyParams && '--' === $token) {
                return \false;
            }
            foreach ($values as $value) {
                // Options with values:
                //   For long options, test for '--option=' at beginning
                //   For short options, test for '-o' at beginning
                $leading = \str_starts_with($value, '--') ? $value . '=' : $value;
                if ($token === $value || '' !== $leading && \str_starts_with($token, $leading)) {
                    return \true;
                }
            }
        }
        return \false;
    }
    /**
     * {@inheritdoc}
     */
    public function getParameterOption($values, $default = \false, $onlyParams = \false)
    {
        $values = (array) $values;
        $tokens = $this->tokens;
        while (0 < \count($tokens)) {
            $token = \array_shift($tokens);
            if ($onlyParams && '--' === $token) {
                return $default;
            }
            foreach ($values as $value) {
                if ($token === $value) {
                    return \array_shift($tokens);
                }
                // Options with values:
                //   For long options, test for '--option=' at beginning
                //   For short options, test for '-o' at beginning
                $leading = \str_starts_with($value, '--') ? $value . '=' : $value;
                if ('' !== $leading && \str_starts_with($token, $leading)) {
                    return \substr($token, \strlen($leading));
                }
            }
        }
        return $default;
    }
    /**
     * Returns a stringified representation of the args passed to the command.
     *
     * @return string
     */
    public function __toString()
    {
        $tokens = \array_map(function ($token) {
            if (\preg_match('{^(-[^=]+=)(.+)}', $token, $match)) {
                return $match[1] . $this->escapeToken($match[2]);
            }
            if ($token && '-' !== $token[0]) {
                return $this->escapeToken($token);
            }
            return $token;
        }, $this->tokens);
        return \implode(' ', $tokens);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Input;

use CivixPhar\Symfony\Component\Console\Exception\InvalidArgumentException;
use CivixPhar\Symfony\Component\Console\Exception\RuntimeException;
/**
 * InputInterface is the interface implemented by all input classes.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
interface InputInterface
{
    /**
     * Returns the first argument from the raw parameters (not parsed).
     *
     * @return string|null The value of the first argument or null otherwise
     */
    public function getFirstArgument();
    /**
     * Returns true if the raw parameters (not parsed) contain a value.
     *
     * This method is to be used to introspect the input parameters
     * before they have been validated. It must be used carefully.
     * Does not necessarily return the correct result for short options
     * when multiple flags are combined in the same option.
     *
     * @param string|array $values     The values to look for in the raw parameters (can be an array)
     * @param bool         $onlyParams Only check real parameters, skip those following an end of options (--) signal
     *
     * @return bool true if the value is contained in the raw parameters
     */
    public function hasParameterOption($values, $onlyParams = \false);
    /**
     * Returns the value of a raw option (not parsed).
     *
     * This method is to be used to introspect the input parameters
     * before they have been validated. It must be used carefully.
     * Does not necessarily return the correct result for short options
     * when multiple flags are combined in the same option.
     *
     * @param string|array                     $values     The value(s) to look for in the raw parameters (can be an array)
     * @param string|bool|int|float|array|null $default    The default value to return if no result is found
     * @param bool                             $onlyParams Only check real parameters, skip those following an end of options (--) signal
     *
     * @return mixed The option value
     */
    public function getParameterOption($values, $default = \false, $onlyParams = \false);
    /**
     * Binds the current Input instance with the given arguments and options.
     *
     * @throws RuntimeException
     */
    public function bind(InputDefinition $definition);
    /**
     * Validates the input.
     *
     * @throws RuntimeException When not enough arguments are given
     */
    public function validate();
    /**
     * Returns all the given arguments merged with the default values.
     *
     * @return array<string|bool|int|float|array|null>
     */
    public function getArguments();
    /**
     * Returns the argument value for a given argument name.
     *
     * @param string $name The argument name
     *
     * @return mixed
     *
     * @throws InvalidArgumentException When argument given doesn't exist
     */
    public function getArgument($name);
    /**
     * Sets an argument value by name.
     *
     * @param string $name  The argument name
     * @param mixed  $value The argument value
     *
     * @throws InvalidArgumentException When argument given doesn't exist
     */
    public function setArgument($name, $value);
    /**
     * Returns true if an InputArgument object exists by name or position.
     *
     * @param string $name The argument name
     *
     * @return bool true if the InputArgument object exists, false otherwise
     */
    public function hasArgument($name);
    /**
     * Returns all the given options merged with the default values.
     *
     * @return array<string|bool|int|float|array|null>
     */
    public function getOptions();
    /**
     * Returns the option value for a given option name.
     *
     * @param string $name The option name
     *
     * @return mixed
     *
     * @throws InvalidArgumentException When option given doesn't exist
     */
    public function getOption($name);
    /**
     * Sets an option value by name.
     *
     * @param string $name  The option name
     * @param mixed  $value The option value
     *
     * @throws InvalidArgumentException When option given doesn't exist
     */
    public function setOption($name, $value);
    /**
     * Returns true if an InputOption object exists by name.
     *
     * @param string $name The InputOption name
     *
     * @return bool true if the InputOption object exists, false otherwise
     */
    public function hasOption($name);
    /**
     * Is this input means interactive?
     *
     * @return bool
     */
    public function isInteractive();
    /**
     * Sets the input interactivity.
     *
     * @param bool $interactive If the input should be interactive
     */
    public function setInteractive($interactive);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Input;

use CivixPhar\Symfony\Component\Console\Exception\InvalidArgumentException;
use CivixPhar\Symfony\Component\Console\Exception\InvalidOptionException;
/**
 * ArrayInput represents an input provided as an array.
 *
 * Usage:
 *
 *     $input = new ArrayInput(['command' => 'foo:bar', 'foo' => 'bar', '--bar' => 'foobar']);
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class ArrayInput extends Input
{
    private $parameters;
    public function __construct(array $parameters, InputDefinition $definition = null)
    {
        $this->parameters = $parameters;
        parent::__construct($definition);
    }
    /**
     * {@inheritdoc}
     */
    public function getFirstArgument()
    {
        foreach ($this->parameters as $param => $value) {
            if ($param && \is_string($param) && '-' === $param[0]) {
                continue;
            }
            return $value;
        }
        return null;
    }
    /**
     * {@inheritdoc}
     */
    public function hasParameterOption($values, $onlyParams = \false)
    {
        $values = (array) $values;
        foreach ($this->parameters as $k => $v) {
            if (!\is_int($k)) {
                $v = $k;
            }
            if ($onlyParams && '--' === $v) {
                return \false;
            }
            if (\in_array($v, $values)) {
                return \true;
            }
        }
        return \false;
    }
    /**
     * {@inheritdoc}
     */
    public function getParameterOption($values, $default = \false, $onlyParams = \false)
    {
        $values = (array) $values;
        foreach ($this->parameters as $k => $v) {
            if ($onlyParams && ('--' === $k || \is_int($k) && '--' === $v)) {
                return $default;
            }
            if (\is_int($k)) {
                if (\in_array($v, $values)) {
                    return \true;
                }
            } elseif (\in_array($k, $values)) {
                return $v;
            }
        }
        return $default;
    }
    /**
     * Returns a stringified representation of the args passed to the command.
     *
     * @return string
     */
    public function __toString()
    {
        $params = [];
        foreach ($this->parameters as $param => $val) {
            if ($param && \is_string($param) && '-' === $param[0]) {
                $glue = '-' === $param[1] ? '=' : ' ';
                if (\is_array($val)) {
                    foreach ($val as $v) {
                        $params[] = $param . ('' != $v ? $glue . $this->escapeToken($v) : '');
                    }
                } else {
                    $params[] = $param . ('' != $val ? $glue . $this->escapeToken($val) : '');
                }
            } else {
                $params[] = \is_array($val) ? \implode(' ', \array_map([$this, 'escapeToken'], $val)) : $this->escapeToken($val);
            }
        }
        return \implode(' ', $params);
    }
    /**
     * {@inheritdoc}
     */
    protected function parse()
    {
        foreach ($this->parameters as $key => $value) {
            if ('--' === $key) {
                return;
            }
            if (\str_starts_with($key, '--')) {
                $this->addLongOption(\substr($key, 2), $value);
            } elseif (\str_starts_with($key, '-')) {
                $this->addShortOption(\substr($key, 1), $value);
            } else {
                $this->addArgument($key, $value);
            }
        }
    }
    /**
     * Adds a short option value.
     *
     * @throws InvalidOptionException When option given doesn't exist
     */
    private function addShortOption(string $shortcut, $value)
    {
        if (!$this->definition->hasShortcut($shortcut)) {
            throw new InvalidOptionException(\sprintf('The "-%s" option does not exist.', $shortcut));
        }
        $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
    }
    /**
     * Adds a long option value.
     *
     * @throws InvalidOptionException When option given doesn't exist
     * @throws InvalidOptionException When a required value is missing
     */
    private function addLongOption(string $name, $value)
    {
        if (!$this->definition->hasOption($name)) {
            throw new InvalidOptionException(\sprintf('The "--%s" option does not exist.', $name));
        }
        $option = $this->definition->getOption($name);
        if (null === $value) {
            if ($option->isValueRequired()) {
                throw new InvalidOptionException(\sprintf('The "--%s" option requires a value.', $name));
            }
            if (!$option->isValueOptional()) {
                $value = \true;
            }
        }
        $this->options[$name] = $value;
    }
    /**
     * Adds an argument value.
     *
     * @param string|int $name  The argument name
     * @param mixed      $value The value for the argument
     *
     * @throws InvalidArgumentException When argument given doesn't exist
     */
    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

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Input;

use CivixPhar\Symfony\Component\Console\Exception\InvalidArgumentException;
use CivixPhar\Symfony\Component\Console\Exception\LogicException;
/**
 * Represents a command line argument.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class InputArgument
{
    public const REQUIRED = 1;
    public const OPTIONAL = 2;
    public const IS_ARRAY = 4;
    private $name;
    private $mode;
    private $default;
    private $description;
    /**
     * @param string                           $name        The argument name
     * @param int|null                         $mode        The argument mode: self::REQUIRED or self::OPTIONAL
     * @param string                           $description A description text
     * @param string|bool|int|float|array|null $default     The default value (for self::OPTIONAL mode only)
     *
     * @throws InvalidArgumentException When argument mode is not valid
     */
    public function __construct(string $name, int $mode = null, string $description = '', $default = null)
    {
        if (null === $mode) {
            $mode = self::OPTIONAL;
        } elseif ($mode > 7 || $mode < 1) {
            throw new InvalidArgumentException(\sprintf('Argument mode "%s" is not valid.', $mode));
        }
        $this->name = $name;
        $this->mode = $mode;
        $this->description = $description;
        $this->setDefault($default);
    }
    /**
     * Returns the argument name.
     *
     * @return string The argument name
     */
    public function getName()
    {
        return $this->name;
    }
    /**
     * Returns true if the argument is required.
     *
     * @return bool true if parameter mode is self::REQUIRED, false otherwise
     */
    public function isRequired()
    {
        return self::REQUIRED === (self::REQUIRED & $this->mode);
    }
    /**
     * Returns true if the argument can take multiple values.
     *
     * @return bool true if mode is self::IS_ARRAY, false otherwise
     */
    public function isArray()
    {
        return self::IS_ARRAY === (self::IS_ARRAY & $this->mode);
    }
    /**
     * Sets the default value.
     *
     * @param string|bool|int|float|array|null $default
     *
     * @throws LogicException When incorrect default value is given
     */
    public function setDefault($default = null)
    {
        if (self::REQUIRED === $this->mode && null !== $default) {
            throw new LogicException('Cannot set a default value except for InputArgument::OPTIONAL mode.');
        }
        if ($this->isArray()) {
            if (null === $default) {
                $default = [];
            } elseif (!\is_array($default)) {
                throw new LogicException('A default value for an array argument must be an array.');
            }
        }
        $this->default = $default;
    }
    /**
     * Returns the default value.
     *
     * @return string|bool|int|float|array|null
     */
    public function getDefault()
    {
        return $this->default;
    }
    /**
     * Returns the description text.
     *
     * @return string The description text
     */
    public function getDescription()
    {
        return $this->description;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Input;

use CivixPhar\Symfony\Component\Console\Exception\InvalidArgumentException;
use CivixPhar\Symfony\Component\Console\Exception\RuntimeException;
/**
 * Input is the base class for all concrete Input classes.
 *
 * Three concrete classes are provided by default:
 *
 *  * `ArgvInput`: The input comes from the CLI arguments (argv)
 *  * `StringInput`: The input is provided as a string
 *  * `ArrayInput`: The input is provided as an array
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
abstract class Input implements InputInterface, StreamableInputInterface
{
    protected $definition;
    protected $stream;
    protected $options = [];
    protected $arguments = [];
    protected $interactive = \true;
    public function __construct(InputDefinition $definition = null)
    {
        if (null === $definition) {
            $this->definition = new InputDefinition();
        } else {
            $this->bind($definition);
            $this->validate();
        }
    }
    /**
     * {@inheritdoc}
     */
    public function bind(InputDefinition $definition)
    {
        $this->arguments = [];
        $this->options = [];
        $this->definition = $definition;
        $this->parse();
    }
    /**
     * Processes command line arguments.
     */
    protected abstract function parse();
    /**
     * {@inheritdoc}
     */
    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)));
        }
    }
    /**
     * {@inheritdoc}
     */
    public function isInteractive()
    {
        return $this->interactive;
    }
    /**
     * {@inheritdoc}
     */
    public function setInteractive($interactive)
    {
        $this->interactive = (bool) $interactive;
    }
    /**
     * {@inheritdoc}
     */
    public function getArguments()
    {
        return \array_merge($this->definition->getArgumentDefaults(), $this->arguments);
    }
    /**
     * {@inheritdoc}
     */
    public function getArgument($name)
    {
        if (!$this->definition->hasArgument((string) $name)) {
            throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name));
        }
        return $this->arguments[$name] ?? $this->definition->getArgument($name)->getDefault();
    }
    /**
     * {@inheritdoc}
     */
    public function setArgument($name, $value)
    {
        if (!$this->definition->hasArgument((string) $name)) {
            throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name));
        }
        $this->arguments[$name] = $value;
    }
    /**
     * {@inheritdoc}
     */
    public function hasArgument($name)
    {
        return $this->definition->hasArgument((string) $name);
    }
    /**
     * {@inheritdoc}
     */
    public function getOptions()
    {
        return \array_merge($this->definition->getOptionDefaults(), $this->options);
    }
    /**
     * {@inheritdoc}
     */
    public function getOption($name)
    {
        if (!$this->definition->hasOption($name)) {
            throw new InvalidArgumentException(\sprintf('The "%s" option does not exist.', $name));
        }
        return \array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault();
    }
    /**
     * {@inheritdoc}
     */
    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;
    }
    /**
     * {@inheritdoc}
     */
    public function hasOption($name)
    {
        return $this->definition->hasOption($name);
    }
    /**
     * Escapes a token through escapeshellarg if it contains unsafe chars.
     *
     * @param string $token
     *
     * @return string
     */
    public function escapeToken($token)
    {
        return \preg_match('{^[\\w-]+$}', $token) ? $token : \escapeshellarg($token);
    }
    /**
     * {@inheritdoc}
     */
    public function setStream($stream)
    {
        $this->stream = $stream;
    }
    /**
     * {@inheritdoc}
     */
    public function getStream()
    {
        return $this->stream;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Input;

use CivixPhar\Symfony\Component\Console\Exception\InvalidArgumentException;
use CivixPhar\Symfony\Component\Console\Exception\LogicException;
/**
 * Represents a command line option.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class InputOption
{
    /**
     * Do not accept input for the option (e.g. --yell). This is the default behavior of options.
     */
    public const VALUE_NONE = 1;
    /**
     * A value must be passed when the option is used (e.g. --iterations=5 or -i5).
     */
    public const VALUE_REQUIRED = 2;
    /**
     * The option may or may not have a value (e.g. --yell or --yell=loud).
     */
    public const VALUE_OPTIONAL = 4;
    /**
     * The option accepts multiple values (e.g. --dir=/foo --dir=/bar).
     */
    public const VALUE_IS_ARRAY = 8;
    private $name;
    private $shortcut;
    private $mode;
    private $default;
    private $description;
    /**
     * @param string                           $name        The option name
     * @param string|array|null                $shortcut    The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
     * @param int|null                         $mode        The option mode: One of the VALUE_* constants
     * @param string                           $description A description text
     * @param string|bool|int|float|array|null $default     The default value (must be null for self::VALUE_NONE)
     *
     * @throws InvalidArgumentException If option mode is invalid or incompatible
     */
    public function __construct(string $name, $shortcut = null, int $mode = null, string $description = '', $default = null)
    {
        if (\str_starts_with($name, '--')) {
            $name = \substr($name, 2);
        }
        if (empty($name)) {
            throw new InvalidArgumentException('An option name cannot be empty.');
        }
        if (empty($shortcut)) {
            $shortcut = null;
        }
        if (null !== $shortcut) {
            if (\is_array($shortcut)) {
                $shortcut = \implode('|', $shortcut);
            }
            $shortcuts = \preg_split('{(\\|)-?}', \ltrim($shortcut, '-'));
            $shortcuts = \array_filter($shortcuts);
            $shortcut = \implode('|', $shortcuts);
            if (empty($shortcut)) {
                throw new InvalidArgumentException('An option shortcut cannot be empty.');
            }
        }
        if (null === $mode) {
            $mode = self::VALUE_NONE;
        } elseif ($mode > 15 || $mode < 1) {
            throw new InvalidArgumentException(\sprintf('Option mode "%s" is not valid.', $mode));
        }
        $this->name = $name;
        $this->shortcut = $shortcut;
        $this->mode = $mode;
        $this->description = $description;
        if ($this->isArray() && !$this->acceptValue()) {
            throw new InvalidArgumentException('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.');
        }
        $this->setDefault($default);
    }
    /**
     * Returns the option shortcut.
     *
     * @return string|null The shortcut
     */
    public function getShortcut()
    {
        return $this->shortcut;
    }
    /**
     * Returns the option name.
     *
     * @return string The name
     */
    public function getName()
    {
        return $this->name;
    }
    /**
     * Returns true if the option accepts a value.
     *
     * @return bool true if value mode is not self::VALUE_NONE, false otherwise
     */
    public function acceptValue()
    {
        return $this->isValueRequired() || $this->isValueOptional();
    }
    /**
     * Returns true if the option requires a value.
     *
     * @return bool true if value mode is self::VALUE_REQUIRED, false otherwise
     */
    public function isValueRequired()
    {
        return self::VALUE_REQUIRED === (self::VALUE_REQUIRED & $this->mode);
    }
    /**
     * Returns true if the option takes an optional value.
     *
     * @return bool true if value mode is self::VALUE_OPTIONAL, false otherwise
     */
    public function isValueOptional()
    {
        return self::VALUE_OPTIONAL === (self::VALUE_OPTIONAL & $this->mode);
    }
    /**
     * Returns true if the option can take multiple values.
     *
     * @return bool true if mode is self::VALUE_IS_ARRAY, false otherwise
     */
    public function isArray()
    {
        return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode);
    }
    /**
     * @param string|bool|int|float|array|null $default
     */
    public function setDefault($default = null)
    {
        if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) {
            throw new LogicException('Cannot set a default value when using InputOption::VALUE_NONE mode.');
        }
        if ($this->isArray()) {
            if (null === $default) {
                $default = [];
            } elseif (!\is_array($default)) {
                throw new LogicException('A default value for an array option must be an array.');
            }
        }
        $this->default = $this->acceptValue() ? $default : \false;
    }
    /**
     * Returns the default value.
     *
     * @return string|bool|int|float|array|null
     */
    public function getDefault()
    {
        return $this->default;
    }
    /**
     * Returns the description text.
     *
     * @return string The description text
     */
    public function getDescription()
    {
        return $this->description;
    }
    /**
     * Checks whether the given option equals this one.
     *
     * @return bool
     */
    public function equals(self $option)
    {
        return $option->getName() === $this->getName() && $option->getShortcut() === $this->getShortcut() && $option->getDefault() === $this->getDefault() && $option->isArray() === $this->isArray() && $option->isValueRequired() === $this->isValueRequired() && $option->isValueOptional() === $this->isValueOptional();
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Command;

use CivixPhar\Symfony\Component\Console\Helper\DescriptorHelper;
use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
/**
 * HelpCommand displays the help for a given command.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class HelpCommand extends Command
{
    private $command;
    /**
     * {@inheritdoc}
     */
    protected function configure()
    {
        $this->ignoreValidationErrors();
        $this->setName('help')->setDefinition([new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'), new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'), new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help')])->setDescription('Display help for a command')->setHelp(<<<'EOF'
The <info>%command.name%</info> command displays help for a given command:

  <info>php %command.full_name% list</info>

You can also output the help in other formats by using the <comment>--format</comment> option:

  <info>php %command.full_name% --format=xml list</info>

To display the list of available commands, please use the <info>list</info> command.
EOF
);
    }
    public function setCommand(Command $command)
    {
        $this->command = $command;
    }
    /**
     * {@inheritdoc}
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        if (null === $this->command) {
            $this->command = $this->getApplication()->find($input->getArgument('command_name'));
        }
        $helper = new DescriptorHelper();
        $helper->describe($output, $this->command, ['format' => $input->getOption('format'), 'raw_text' => $input->getOption('raw')]);
        $this->command = null;
        return 0;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Command;

use CivixPhar\Symfony\Component\Console\Application;
use CivixPhar\Symfony\Component\Console\Exception\ExceptionInterface;
use CivixPhar\Symfony\Component\Console\Exception\InvalidArgumentException;
use CivixPhar\Symfony\Component\Console\Exception\LogicException;
use CivixPhar\Symfony\Component\Console\Helper\HelperSet;
use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputDefinition;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
/**
 * Base class for all commands.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class Command
{
    /**
     * @var string|null The default command name
     */
    protected static $defaultName;
    private $application;
    private $name;
    private $processTitle;
    private $aliases = [];
    private $definition;
    private $hidden = \false;
    private $help = '';
    private $description = '';
    private $ignoreValidationErrors = \false;
    private $applicationDefinitionMerged = \false;
    private $applicationDefinitionMergedWithArgs = \false;
    private $code;
    private $synopsis = [];
    private $usages = [];
    private $helperSet;
    /**
     * @return string|null The default command name or null when no default name is set
     */
    public static function getDefaultName()
    {
        $class = static::class;
        $r = new \ReflectionProperty($class, 'defaultName');
        return $class === $r->class ? static::$defaultName : null;
    }
    /**
     * @param string|null $name The name of the command; passing null means it must be set in configure()
     *
     * @throws LogicException When the command name is empty
     */
    public function __construct(string $name = null)
    {
        $this->definition = new InputDefinition();
        if (null !== $name || null !== ($name = static::getDefaultName())) {
            $this->setName($name);
        }
        $this->configure();
    }
    /**
     * Ignores validation errors.
     *
     * This is mainly useful for the help command.
     */
    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;
    }
    /**
     * Gets the helper set.
     *
     * @return HelperSet|null A HelperSet instance
     */
    public function getHelperSet()
    {
        return $this->helperSet;
    }
    /**
     * Gets the application instance for this command.
     *
     * @return Application|null An Application instance
     */
    public function getApplication()
    {
        return $this->application;
    }
    /**
     * Checks whether the command is enabled or not in the current environment.
     *
     * Override this to check for x or y and return false if the command can not
     * run properly under the current conditions.
     *
     * @return bool
     */
    public function isEnabled()
    {
        return \true;
    }
    /**
     * Configures the current command.
     */
    protected function configure()
    {
    }
    /**
     * Executes the current command.
     *
     * This method is not abstract because you can use this class
     * as a concrete class. In this case, instead of defining the
     * execute() method, you set the code to execute by passing
     * a Closure to the setCode() method.
     *
     * @return int 0 if everything went fine, or an exit code
     *
     * @throws LogicException When this abstract method is not implemented
     *
     * @see setCode()
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        throw new LogicException('You must override the execute() method in the concrete command class.');
    }
    /**
     * Interacts with the user.
     *
     * This method is executed before the InputDefinition is validated.
     * This means that this is the only place where the command can
     * interactively ask for values of missing required arguments.
     */
    protected function interact(InputInterface $input, OutputInterface $output)
    {
    }
    /**
     * Initializes the command after the input has been bound and before the input
     * is validated.
     *
     * This is mainly useful when a lot of commands extends one main command
     * where some things need to be initialized based on the input arguments and options.
     *
     * @see InputInterface::bind()
     * @see InputInterface::validate()
     */
    protected function initialize(InputInterface $input, OutputInterface $output)
    {
    }
    /**
     * Runs the command.
     *
     * The code to execute is either defined directly with the
     * setCode() method or by overriding the execute() method
     * in a sub-class.
     *
     * @return int The command exit code
     *
     * @throws \Exception When binding input fails. Bypass this by calling {@link ignoreValidationErrors()}.
     *
     * @see setCode()
     * @see execute()
     */
    public function run(InputInterface $input, OutputInterface $output)
    {
        // force the creation of the synopsis before the merge with the app definition
        $this->getSynopsis(\true);
        $this->getSynopsis(\false);
        // add the application arguments and options
        $this->mergeApplicationDefinition();
        // bind the input against the command specific arguments/options
        try {
            $input->bind($this->definition);
        } catch (ExceptionInterface $e) {
            if (!$this->ignoreValidationErrors) {
                throw $e;
            }
        }
        $this->initialize($input, $output);
        if (null !== $this->processTitle) {
            if (\function_exists('cli_set_process_title')) {
                if (!@\cli_set_process_title($this->processTitle)) {
                    if ('Darwin' === \PHP_OS) {
                        $output->writeln('<comment>Running "cli_set_process_title" as an unprivileged user is not supported on MacOS.</comment>', OutputInterface::VERBOSITY_VERY_VERBOSE);
                    } else {
                        \cli_set_process_title($this->processTitle);
                    }
                }
            } elseif (\function_exists('CivixPhar\\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);
        }
        // The command name argument is often omitted when a command is executed directly with its run() method.
        // It would fail the validation if we didn't make sure the command argument is present,
        // since it's required by the application.
        if ($input->hasArgument('command') && null === $input->getArgument('command')) {
            $input->setArgument('command', $this->getName());
        }
        $input->validate();
        if ($this->code) {
            $statusCode = ($this->code)($input, $output);
        } else {
            $statusCode = $this->execute($input, $output);
            if (!\is_int($statusCode)) {
                @\trigger_error(\sprintf('Return value of "%s::execute()" should always be of the type int since Symfony 4.4, %s returned.', static::class, \gettype($statusCode)), \E_USER_DEPRECATED);
            }
        }
        return \is_numeric($statusCode) ? (int) $statusCode : 0;
    }
    /**
     * Sets the code to execute when running this command.
     *
     * If this method is used, it overrides the code defined
     * in the execute() method.
     *
     * @param callable $code A callable(InputInterface $input, OutputInterface $output)
     *
     * @return $this
     *
     * @throws InvalidArgumentException
     *
     * @see execute()
     */
    public function setCode(callable $code)
    {
        if ($code instanceof \Closure) {
            $r = new \ReflectionFunction($code);
            if (null === $r->getClosureThis()) {
                \set_error_handler(static function () {
                });
                try {
                    if ($c = \Closure::bind($code, $this)) {
                        $code = $c;
                    }
                } finally {
                    \restore_error_handler();
                }
            }
        }
        $this->code = $code;
        return $this;
    }
    /**
     * Merges the application definition with the command definition.
     *
     * This method is not part of public API and should not be used directly.
     *
     * @param bool $mergeArgs Whether to merge or not the Application definition arguments to Command definition arguments
     */
    public function mergeApplicationDefinition($mergeArgs = \true)
    {
        if (null === $this->application || \true === $this->applicationDefinitionMerged && ($this->applicationDefinitionMergedWithArgs || !$mergeArgs)) {
            return;
        }
        $this->definition->addOptions($this->application->getDefinition()->getOptions());
        $this->applicationDefinitionMerged = \true;
        if ($mergeArgs) {
            $currentArguments = $this->definition->getArguments();
            $this->definition->setArguments($this->application->getDefinition()->getArguments());
            $this->definition->addArguments($currentArguments);
            $this->applicationDefinitionMergedWithArgs = \true;
        }
    }
    /**
     * Sets an array of argument and option instances.
     *
     * @param array|InputDefinition $definition An array of argument and option instances or a definition instance
     *
     * @return $this
     */
    public function setDefinition($definition)
    {
        if ($definition instanceof InputDefinition) {
            $this->definition = $definition;
        } else {
            $this->definition->setDefinition($definition);
        }
        $this->applicationDefinitionMerged = \false;
        return $this;
    }
    /**
     * Gets the InputDefinition attached to this Command.
     *
     * @return InputDefinition An InputDefinition instance
     */
    public function getDefinition()
    {
        if (null === $this->definition) {
            throw new LogicException(\sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', static::class));
        }
        return $this->definition;
    }
    /**
     * Gets the InputDefinition to be used to create representations of this Command.
     *
     * Can be overridden to provide the original command representation when it would otherwise
     * be changed by merging with the application InputDefinition.
     *
     * This method is not part of public API and should not be used directly.
     *
     * @return InputDefinition An InputDefinition instance
     */
    public function getNativeDefinition()
    {
        return $this->getDefinition();
    }
    /**
     * Adds an argument.
     *
     * @param string   $name        The argument name
     * @param int|null $mode        The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL
     * @param string   $description A description text
     * @param mixed    $default     The default value (for InputArgument::OPTIONAL mode only)
     *
     * @throws InvalidArgumentException When argument mode is not valid
     *
     * @return $this
     */
    public function addArgument($name, $mode = null, $description = '', $default = null)
    {
        $this->definition->addArgument(new InputArgument($name, $mode, $description, $default));
        return $this;
    }
    /**
     * Adds an option.
     *
     * @param string            $name        The option name
     * @param string|array|null $shortcut    The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
     * @param int|null          $mode        The option mode: One of the InputOption::VALUE_* constants
     * @param string            $description A description text
     * @param mixed             $default     The default value (must be null for InputOption::VALUE_NONE)
     *
     * @throws InvalidArgumentException If option mode is invalid or incompatible
     *
     * @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;
    }
    /**
     * Sets the name of the command.
     *
     * This method can set both the namespace and the name if
     * you separate them by a colon (:)
     *
     *     $command->setName('foo:bar');
     *
     * @param string $name The command name
     *
     * @return $this
     *
     * @throws InvalidArgumentException When the name is invalid
     */
    public function setName($name)
    {
        $this->validateName($name);
        $this->name = $name;
        return $this;
    }
    /**
     * Sets the process title of the command.
     *
     * This feature should be used only when creating a long process command,
     * like a daemon.
     *
     * @param string $title The process title
     *
     * @return $this
     */
    public function setProcessTitle($title)
    {
        $this->processTitle = $title;
        return $this;
    }
    /**
     * Returns the command name.
     *
     * @return string|null
     */
    public function getName()
    {
        return $this->name;
    }
    /**
     * @param bool $hidden Whether or not the command should be hidden from the list of commands
     *
     * @return $this
     */
    public function setHidden($hidden)
    {
        $this->hidden = (bool) $hidden;
        return $this;
    }
    /**
     * @return bool whether the command should be publicly shown or not
     */
    public function isHidden()
    {
        return $this->hidden;
    }
    /**
     * Sets the description for the command.
     *
     * @param string $description The description for the command
     *
     * @return $this
     */
    public function setDescription($description)
    {
        $this->description = $description;
        return $this;
    }
    /**
     * Returns the description for the command.
     *
     * @return string The description for the command
     */
    public function getDescription()
    {
        return $this->description;
    }
    /**
     * Sets the help for the command.
     *
     * @param string $help The help for the command
     *
     * @return $this
     */
    public function setHelp($help)
    {
        $this->help = $help;
        return $this;
    }
    /**
     * Returns the help for the command.
     *
     * @return string The help for the command
     */
    public function getHelp()
    {
        return $this->help;
    }
    /**
     * Returns the processed help for the command replacing the %command.name% and
     * %command.full_name% patterns with the real values dynamically.
     *
     * @return string The processed help for the command
     */
    public function getProcessedHelp()
    {
        $name = $this->name;
        $isSingleCommand = $this->application && $this->application->isSingleCommand();
        $placeholders = ['%command.name%', '%command.full_name%'];
        $replacements = [$name, $isSingleCommand ? $_SERVER['PHP_SELF'] : $_SERVER['PHP_SELF'] . ' ' . $name];
        return \str_replace($placeholders, $replacements, $this->getHelp() ?: $this->getDescription());
    }
    /**
     * Sets the aliases for the command.
     *
     * @param string[] $aliases An array of aliases for the command
     *
     * @return $this
     *
     * @throws InvalidArgumentException When an alias is invalid
     */
    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;
    }
    /**
     * Returns the aliases for the command.
     *
     * @return array An array of aliases for the command
     */
    public function getAliases()
    {
        return $this->aliases;
    }
    /**
     * Returns the synopsis for the command.
     *
     * @param bool $short Whether to show the short version of the synopsis (with options folded) or not
     *
     * @return string The synopsis
     */
    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];
    }
    /**
     * Add a command usage example.
     *
     * @param string $usage The usage, it'll be prefixed with the command name
     *
     * @return $this
     */
    public function addUsage($usage)
    {
        if (!\str_starts_with($usage, $this->name)) {
            $usage = \sprintf('%s %s', $this->name, $usage);
        }
        $this->usages[] = $usage;
        return $this;
    }
    /**
     * Returns alternative usages of the command.
     *
     * @return array
     */
    public function getUsages()
    {
        return $this->usages;
    }
    /**
     * Gets a helper instance by name.
     *
     * @param string $name The helper name
     *
     * @return mixed The helper value
     *
     * @throws LogicException           if no HelperSet is defined
     * @throws InvalidArgumentException if the helper is not defined
     */
    public function getHelper($name)
    {
        if (null === $this->helperSet) {
            throw new LogicException(\sprintf('Cannot retrieve helper "%s" because there is no HelperSet defined. Did you forget to add your command to the application or to set the application on the command using the setApplication() method? You can also set the HelperSet directly using the setHelperSet() method.', $name));
        }
        return $this->helperSet->get($name);
    }
    /**
     * Validates a command name.
     *
     * It must be non-empty and parts can optionally be separated by ":".
     *
     * @throws InvalidArgumentException When the name is invalid
     */
    private function validateName(string $name)
    {
        if (!\preg_match('/^[^\\:]++(\\:[^\\:]++)*$/', $name)) {
            throw new InvalidArgumentException(\sprintf('Command name "%s" is invalid.', $name));
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Command;

use CivixPhar\Symfony\Component\Console\Helper\DescriptorHelper;
use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputDefinition;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
/**
 * ListCommand displays the list of all available commands for the application.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class ListCommand extends Command
{
    /**
     * {@inheritdoc}
     */
    protected function configure()
    {
        $this->setName('list')->setDefinition($this->createDefinition())->setDescription('List commands')->setHelp(<<<'EOF'
The <info>%command.name%</info> command lists all commands:

  <info>php %command.full_name%</info>

You can also display the commands for a specific namespace:

  <info>php %command.full_name% test</info>

You can also output the information in other formats by using the <comment>--format</comment> option:

  <info>php %command.full_name% --format=xml</info>

It's also possible to get raw list of commands (useful for embedding command runner):

  <info>php %command.full_name% --raw</info>
EOF
);
    }
    /**
     * {@inheritdoc}
     */
    public function getNativeDefinition()
    {
        return $this->createDefinition();
    }
    /**
     * {@inheritdoc}
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $helper = new DescriptorHelper();
        $helper->describe($output, $this->getApplication(), ['format' => $input->getOption('format'), 'raw_text' => $input->getOption('raw'), 'namespace' => $input->getArgument('namespace')]);
        return 0;
    }
    private function createDefinition() : InputDefinition
    {
        return new InputDefinition([new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'), new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'), new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt')]);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Command;

use CivixPhar\Symfony\Component\Console\Exception\LogicException;
use CivixPhar\Symfony\Component\Lock\Lock;
use CivixPhar\Symfony\Component\Lock\LockFactory;
use CivixPhar\Symfony\Component\Lock\Store\FlockStore;
use CivixPhar\Symfony\Component\Lock\Store\SemaphoreStore;
/**
 * Basic lock feature for commands.
 *
 * @author Geoffrey Brier <geoffrey.brier@gmail.com>
 */
trait LockableTrait
{
    /** @var Lock */
    private $lock;
    /**
     * Locks a command.
     */
    private function lock(string $name = null, bool $blocking = \false) : bool
    {
        if (!\class_exists(SemaphoreStore::class)) {
            throw new LogicException('To enable the locking feature you must install the symfony/lock component.');
        }
        if (null !== $this->lock) {
            throw new LogicException('A lock is already in place.');
        }
        if (SemaphoreStore::isSupported()) {
            $store = new SemaphoreStore();
        } else {
            $store = new FlockStore();
        }
        $this->lock = (new LockFactory($store))->createLock($name ?: $this->getName());
        if (!$this->lock->acquire($blocking)) {
            $this->lock = null;
            return \false;
        }
        return \true;
    }
    /**
     * Releases the command lock if there is one.
     */
    private function release()
    {
        if ($this->lock) {
            $this->lock->release();
            $this->lock = null;
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Console\Logger;

use CivixPhar\Psr\Log\AbstractLogger;
use CivixPhar\Psr\Log\InvalidArgumentException;
use CivixPhar\Psr\Log\LogLevel;
use CivixPhar\Symfony\Component\Console\Output\ConsoleOutputInterface;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
/**
 * PSR-3 compliant console logger.
 *
 * @author KÃ©vin Dunglas <dunglas@gmail.com>
 *
 * @see https://www.php-fig.org/psr/psr-3/
 */
class ConsoleLogger extends AbstractLogger
{
    public const INFO = 'info';
    public const ERROR = 'error';
    private $output;
    private $verbosityLevelMap = [LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL, LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL, LogLevel::CRITICAL => OutputInterface::VERBOSITY_NORMAL, LogLevel::ERROR => OutputInterface::VERBOSITY_NORMAL, LogLevel::WARNING => OutputInterface::VERBOSITY_NORMAL, LogLevel::NOTICE => OutputInterface::VERBOSITY_VERBOSE, LogLevel::INFO => OutputInterface::VERBOSITY_VERY_VERBOSE, LogLevel::DEBUG => OutputInterface::VERBOSITY_DEBUG];
    private $formatLevelMap = [LogLevel::EMERGENCY => self::ERROR, LogLevel::ALERT => self::ERROR, LogLevel::CRITICAL => self::ERROR, LogLevel::ERROR => self::ERROR, LogLevel::WARNING => self::INFO, LogLevel::NOTICE => self::INFO, LogLevel::INFO => self::INFO, LogLevel::DEBUG => self::INFO];
    private $errored = \false;
    public function __construct(OutputInterface $output, array $verbosityLevelMap = [], array $formatLevelMap = [])
    {
        $this->output = $output;
        $this->verbosityLevelMap = $verbosityLevelMap + $this->verbosityLevelMap;
        $this->formatLevelMap = $formatLevelMap + $this->formatLevelMap;
    }
    /**
     * {@inheritdoc}
     *
     * @return void
     */
    public function log($level, $message, array $context = [])
    {
        if (!isset($this->verbosityLevelMap[$level])) {
            throw new InvalidArgumentException(\sprintf('The log level "%s" does not exist.', $level));
        }
        $output = $this->output;
        // Write to the error output if necessary and available
        if (self::ERROR === $this->formatLevelMap[$level]) {
            if ($this->output instanceof ConsoleOutputInterface) {
                $output = $output->getErrorOutput();
            }
            $this->errored = \true;
        }
        // the if condition check isn't necessary -- it's the same one that $output will do internally anyway.
        // We only do it for efficiency here as the message formatting is relatively expensive.
        if ($output->getVerbosity() >= $this->verbosityLevelMap[$level]) {
            $output->writeln(\sprintf('<%1$s>[%2$s] %3$s</%1$s>', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)), $this->verbosityLevelMap[$level]);
        }
    }
    /**
     * Returns true when any messages have been logged at error levels.
     *
     * @return bool
     */
    public function hasErrored()
    {
        return $this->errored;
    }
    /**
     * Interpolates context values into the message placeholders.
     *
     * @author PHP Framework Interoperability Group
     */
    private function interpolate(string $message, array $context) : string
    {
        if (!\str_contains($message, '{')) {
            return $message;
        }
        $replacements = [];
        foreach ($context as $key => $val) {
            if (null === $val || \is_scalar($val) || \is_object($val) && \method_exists($val, '__toString')) {
                $replacements["{{$key}}"] = $val;
            } elseif ($val instanceof \DateTimeInterface) {
                $replacements["{{$key}}"] = $val->format(\DateTime::RFC3339);
            } elseif (\is_object($val)) {
                $replacements["{{$key}}"] = '[object ' . \get_class($val) . ']';
            } else {
                $replacements["{{$key}}"] = '[' . \gettype($val) . ']';
            }
        }
        return \strtr($message, $replacements);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Polyfill\Php72;

/**
 * @author Nicolas Grekas <p@tchwork.com>
 * @author Dariusz RumiÅ„ski <dariusz.ruminski@gmail.com>
 *
 * @internal
 */
final class Php72
{
    private static $hashMask;
    public static function utf8_encode($s)
    {
        $s .= $s;
        $len = \strlen($s);
        for ($i = $len >> 1, $j = 0; $i < $len; ++$i, ++$j) {
            switch (\true) {
                case $s[$i] < "\x80":
                    $s[$j] = $s[$i];
                    break;
                case $s[$i] < "\xc0":
                    $s[$j] = "\xc2";
                    $s[++$j] = $s[$i];
                    break;
                default:
                    $s[$j] = "\xc3";
                    $s[++$j] = \chr(\ord($s[$i]) - 64);
                    break;
            }
        }
        return \substr($s, 0, $j);
    }
    public static function utf8_decode($s)
    {
        $s = (string) $s;
        $len = \strlen($s);
        for ($i = 0, $j = 0; $i < $len; ++$i, ++$j) {
            switch ($s[$i] & "\xf0") {
                case "\xc0":
                case "\xd0":
                    $c = \ord($s[$i] & "\x1f") << 6 | \ord($s[++$i] & "?");
                    $s[$j] = $c < 256 ? \chr($c) : '?';
                    break;
                case "\xf0":
                    ++$i;
                // no break
                case "\xe0":
                    $s[$j] = '?';
                    $i += 2;
                    break;
                default:
                    $s[$j] = $s[$i];
            }
        }
        return \substr($s, 0, $j);
    }
    public static function php_os_family()
    {
        if ('\\' === \DIRECTORY_SEPARATOR) {
            return 'Windows';
        }
        $map = ['Darwin' => 'Darwin', 'DragonFly' => 'BSD', 'FreeBSD' => 'BSD', 'NetBSD' => 'BSD', 'OpenBSD' => 'BSD', 'Linux' => 'Linux', 'SunOS' => 'Solaris'];
        return isset($map[\PHP_OS]) ? $map[\PHP_OS] : 'Unknown';
    }
    public static function spl_object_id($object)
    {
        if (null === self::$hashMask) {
            self::initHashMask();
        }
        if (null === ($hash = \spl_object_hash($object))) {
            return;
        }
        // On 32-bit systems, PHP_INT_SIZE is 4,
        return self::$hashMask ^ \hexdec(\substr($hash, 16 - (\PHP_INT_SIZE * 2 - 1), \PHP_INT_SIZE * 2 - 1));
    }
    public static function sapi_windows_vt100_support($stream, $enable = null)
    {
        if (!\is_resource($stream)) {
            \trigger_error('sapi_windows_vt100_support() expects parameter 1 to be resource, ' . \gettype($stream) . ' given', \E_USER_WARNING);
            return \false;
        }
        $meta = \stream_get_meta_data($stream);
        if ('STDIO' !== $meta['stream_type']) {
            \trigger_error('sapi_windows_vt100_support() was not able to analyze the specified stream', \E_USER_WARNING);
            return \false;
        }
        // We cannot actually disable vt100 support if it is set
        if (\false === $enable || !self::stream_isatty($stream)) {
            return \false;
        }
        // The native function does not apply to stdin
        $meta = \array_map('strtolower', $meta);
        $stdin = 'php://stdin' === $meta['uri'] || 'php://fd/0' === $meta['uri'];
        return !$stdin && (\false !== \getenv('ANSICON') || 'ON' === \getenv('ConEmuANSI') || 'xterm' === \getenv('TERM') || 'Hyper' === \getenv('TERM_PROGRAM'));
    }
    public static function stream_isatty($stream)
    {
        if (!\is_resource($stream)) {
            \trigger_error('stream_isatty() expects parameter 1 to be resource, ' . \gettype($stream) . ' given', \E_USER_WARNING);
            return \false;
        }
        if ('\\' === \DIRECTORY_SEPARATOR) {
            $stat = @\fstat($stream);
            // Check if formatted mode is S_IFCHR
            return $stat ? 020000 === ($stat['mode'] & 0170000) : \false;
        }
        return \function_exists('posix_isatty') && @\posix_isatty($stream);
    }
    private static function initHashMask()
    {
        $obj = (object) [];
        self::$hashMask = -1;
        // check if we are nested in an output buffering handler to prevent a fatal error with ob_start() below
        $obFuncs = ['ob_clean', 'ob_end_clean', 'ob_flush', 'ob_end_flush', 'ob_get_contents', 'ob_get_flush'];
        foreach (\debug_backtrace(\PHP_VERSION_ID >= 50400 ? \DEBUG_BACKTRACE_IGNORE_ARGS : \false) as $frame) {
            if (isset($frame['function'][0]) && !isset($frame['class']) && 'o' === $frame['function'][0] && \in_array($frame['function'], $obFuncs)) {
                $frame['line'] = 0;
                break;
            }
        }
        if (!empty($frame['line'])) {
            \ob_start();
            \debug_zval_dump($obj);
            self::$hashMask = (int) \substr(\ob_get_clean(), 17);
        }
        self::$hashMask ^= \hexdec(\substr(\spl_object_hash($obj), 16 - (\PHP_INT_SIZE * 2 - 1), \PHP_INT_SIZE * 2 - 1));
    }
    public static function mb_chr($code, $encoding = null)
    {
        if (0x80 > ($code %= 0x200000)) {
            $s = \chr($code);
        } elseif (0x800 > $code) {
            $s = \chr(0xc0 | $code >> 6) . \chr(0x80 | $code & 0x3f);
        } elseif (0x10000 > $code) {
            $s = \chr(0xe0 | $code >> 12) . \chr(0x80 | $code >> 6 & 0x3f) . \chr(0x80 | $code & 0x3f);
        } else {
            $s = \chr(0xf0 | $code >> 18) . \chr(0x80 | $code >> 12 & 0x3f) . \chr(0x80 | $code >> 6 & 0x3f) . \chr(0x80 | $code & 0x3f);
        }
        if ('UTF-8' !== $encoding) {
            $s = \mb_convert_encoding($s, $encoding, 'UTF-8');
        }
        return $s;
    }
    public static function mb_ord($s, $encoding = null)
    {
        if (null === $encoding) {
            $s = \mb_convert_encoding($s, 'UTF-8');
        } elseif ('UTF-8' !== $encoding) {
            $s = \mb_convert_encoding($s, 'UTF-8', $encoding);
        }
        if (1 === \strlen($s)) {
            return \ord($s);
        }
        $code = ($s = \unpack('C*', \substr($s, 0, 4))) ? $s[1] : 0;
        if (0xf0 <= $code) {
            return ($code - 0xf0 << 18) + ($s[2] - 0x80 << 12) + ($s[3] - 0x80 << 6) + $s[4] - 0x80;
        }
        if (0xe0 <= $code) {
            return ($code - 0xe0 << 12) + ($s[2] - 0x80 << 6) + $s[3] - 0x80;
        }
        if (0xc0 <= $code) {
            return ($code - 0xc0 << 6) + $s[2] - 0x80;
        }
        return $code;
    }
}
<?php

namespace CivixPhar;

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
use CivixPhar\Symfony\Polyfill\Php72 as p;
if (\PHP_VERSION_ID >= 70200) {
    return;
}
if (!\defined('PHP_FLOAT_DIG')) {
    \define('PHP_FLOAT_DIG', 15);
}
if (!\defined('PHP_FLOAT_EPSILON')) {
    \define('PHP_FLOAT_EPSILON', 2.2204460492503E-16);
}
if (!\defined('PHP_FLOAT_MIN')) {
    \define('PHP_FLOAT_MIN', 2.2250738585072E-308);
}
if (!\defined('PHP_FLOAT_MAX')) {
    \define('PHP_FLOAT_MAX', 1.7976931348623157E+308);
}
if (!\defined('PHP_OS_FAMILY')) {
    \define('PHP_OS_FAMILY', p\Php72::php_os_family());
}
if ('\\' === \DIRECTORY_SEPARATOR && !\function_exists('sapi_windows_vt100_support')) {
    function sapi_windows_vt100_support($stream, $enable = null)
    {
        return p\Php72::sapi_windows_vt100_support($stream, $enable);
    }
}
if (!\function_exists('stream_isatty')) {
    function stream_isatty($stream)
    {
        return p\Php72::stream_isatty($stream);
    }
}
if (!\function_exists('utf8_encode')) {
    function utf8_encode($string)
    {
        return p\Php72::utf8_encode($string);
    }
}
if (!\function_exists('utf8_decode')) {
    function utf8_decode($string)
    {
        return p\Php72::utf8_decode($string);
    }
}
if (!\function_exists('spl_object_id')) {
    function spl_object_id($object)
    {
        return p\Php72::spl_object_id($object);
    }
}
if (!\function_exists('mb_ord')) {
    function mb_ord($string, $encoding = null)
    {
        return p\Php72::mb_ord($string, $encoding);
    }
}
if (!\function_exists('mb_chr')) {
    function mb_chr($codepoint, $encoding = null)
    {
        return p\Php72::mb_chr($codepoint, $encoding);
    }
}
if (!\function_exists('mb_scrub')) {
    function mb_scrub($string, $encoding = null)
    {
        $encoding = null === $encoding ? \mb_internal_encoding() : $encoding;
        return \mb_convert_encoding($string, $encoding, $encoding);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper;

use CivixPhar\Symfony\Component\VarDumper\Caster\ReflectionCaster;
use CivixPhar\Symfony\Component\VarDumper\Cloner\VarCloner;
use CivixPhar\Symfony\Component\VarDumper\Dumper\CliDumper;
use CivixPhar\Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider;
use CivixPhar\Symfony\Component\VarDumper\Dumper\ContextualizedDumper;
use CivixPhar\Symfony\Component\VarDumper\Dumper\HtmlDumper;
// Load the global dump() function
require_once __DIR__ . '/Resources/functions/dump.php';
/**
 * @author Nicolas Grekas <p@tchwork.com>
 */
class VarDumper
{
    private static $handler;
    public static function dump($var)
    {
        if (null === self::$handler) {
            $cloner = new VarCloner();
            $cloner->addCasters(ReflectionCaster::UNSET_CLOSURE_FILE_INFO);
            if (isset($_SERVER['VAR_DUMPER_FORMAT'])) {
                $dumper = 'html' === $_SERVER['VAR_DUMPER_FORMAT'] ? new HtmlDumper() : new CliDumper();
            } else {
                $dumper = \in_array(\PHP_SAPI, ['cli', 'phpdbg']) ? new CliDumper() : new HtmlDumper();
            }
            $dumper = new ContextualizedDumper($dumper, [new SourceContextProvider()]);
            self::$handler = function ($var) use($cloner, $dumper) {
                $dumper->dump($cloner->cloneVar($var));
            };
        }
        return (self::$handler)($var);
    }
    public static function setHandler(callable $callable = null)
    {
        $prevHandler = self::$handler;
        // Prevent replacing the handler with expected format as soon as the env var was set:
        if (isset($_SERVER['VAR_DUMPER_FORMAT'])) {
            return $prevHandler;
        }
        self::$handler = $callable;
        return $prevHandler;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

/**
 * Represents a cut array.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
class CutArrayStub extends CutStub
{
    public $preservedSubset;
    public function __construct(array $value, array $preservedKeys)
    {
        parent::__construct($value);
        $this->preservedSubset = \array_intersect_key($value, \array_flip($preservedKeys));
        $this->cut -= \count($this->preservedSubset);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use Symfony\Component\HttpFoundation\Request;
use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * @final since Symfony 4.4
 */
class SymfonyCaster
{
    private const REQUEST_GETTERS = ['pathInfo' => 'getPathInfo', 'requestUri' => 'getRequestUri', 'baseUrl' => 'getBaseUrl', 'basePath' => 'getBasePath', 'method' => 'getMethod', 'format' => 'getRequestFormat'];
    public static function castRequest(Request $request, array $a, Stub $stub, $isNested)
    {
        $clone = null;
        foreach (self::REQUEST_GETTERS as $prop => $getter) {
            $key = Caster::PREFIX_PROTECTED . $prop;
            if (\array_key_exists($key, $a) && null === $a[$key]) {
                if (null === $clone) {
                    $clone = clone $request;
                }
                $a[Caster::PREFIX_VIRTUAL . $prop] = $clone->{$getter}();
            }
        }
        return $a;
    }
    public static function castHttpClient($client, array $a, Stub $stub, $isNested)
    {
        $multiKey = \sprintf("\x00%s\x00multi", \get_class($client));
        if (isset($a[$multiKey])) {
            $a[$multiKey] = new CutStub($a[$multiKey]);
        }
        return $a;
    }
    public static function castHttpClientResponse($response, array $a, Stub $stub, $isNested)
    {
        $stub->cut += \count($a);
        $a = [];
        foreach ($response->getInfo() as $k => $v) {
            $a[Caster::PREFIX_VIRTUAL . $k] = $v;
        }
        return $a;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Imagine\Image\ImageInterface;
use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * @author GrÃ©goire Pineau <lyrixx@lyrixx.info>
 */
final class ImagineCaster
{
    public static function castImage(ImageInterface $c, array $a, Stub $stub, bool $isNested) : array
    {
        $imgData = $c->get('png');
        if (\strlen($imgData) > 1 * 1000 * 1000) {
            $a += [Caster::PREFIX_VIRTUAL . 'image' => new ConstStub($c->getSize())];
        } else {
            $a += [Caster::PREFIX_VIRTUAL . 'image' => new ImgStub($imgData, 'image/png', $c->getSize())];
        }
        return $a;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Doctrine\Common\Proxy\Proxy as CommonProxy;
use CivixPhar\Doctrine\ORM\PersistentCollection;
use CivixPhar\Doctrine\ORM\Proxy\Proxy as OrmProxy;
use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * Casts Doctrine related classes to array representation.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @final since Symfony 4.4
 */
class DoctrineCaster
{
    public static function castCommonProxy(CommonProxy $proxy, array $a, Stub $stub, $isNested)
    {
        foreach (['__cloner__', '__initializer__'] as $k) {
            if (\array_key_exists($k, $a)) {
                unset($a[$k]);
                ++$stub->cut;
            }
        }
        return $a;
    }
    public static function castOrmProxy(OrmProxy $proxy, array $a, Stub $stub, $isNested)
    {
        foreach (['_entityPersister', '_identifier'] as $k) {
            if (\array_key_exists($k = "\x00Doctrine\\ORM\\Proxy\\Proxy\x00" . $k, $a)) {
                unset($a[$k]);
                ++$stub->cut;
            }
        }
        return $a;
    }
    public static function castPersistentCollection(PersistentCollection $coll, array $a, Stub $stub, $isNested)
    {
        foreach (['snapshot', 'association', 'typeClass'] as $k) {
            if (\array_key_exists($k = "\x00Doctrine\\ORM\\PersistentCollection\x00" . $k, $a)) {
                $a[$k] = new CutStub($a[$k]);
            }
        }
        return $a;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * Represents a PHP constant and its value.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
class ConstStub extends Stub
{
    public function __construct(string $name, $value = null)
    {
        $this->class = $name;
        $this->value = 1 < \func_num_args() ? $value : $name;
    }
    /**
     * @return string
     */
    public function __toString()
    {
        return (string) $this->value;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * Casts SPL related classes to array representation.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @final since Symfony 4.4
 */
class SplCaster
{
    private const SPL_FILE_OBJECT_FLAGS = [\SplFileObject::DROP_NEW_LINE => 'DROP_NEW_LINE', \SplFileObject::READ_AHEAD => 'READ_AHEAD', \SplFileObject::SKIP_EMPTY => 'SKIP_EMPTY', \SplFileObject::READ_CSV => 'READ_CSV'];
    public static function castArrayObject(\ArrayObject $c, array $a, Stub $stub, $isNested)
    {
        return self::castSplArray($c, $a, $stub, $isNested);
    }
    public static function castArrayIterator(\ArrayIterator $c, array $a, Stub $stub, $isNested)
    {
        return self::castSplArray($c, $a, $stub, $isNested);
    }
    public static function castHeap(\Iterator $c, array $a, Stub $stub, $isNested)
    {
        $a += [Caster::PREFIX_VIRTUAL . 'heap' => \iterator_to_array(clone $c)];
        return $a;
    }
    public static function castDoublyLinkedList(\SplDoublyLinkedList $c, array $a, Stub $stub, $isNested)
    {
        $prefix = Caster::PREFIX_VIRTUAL;
        $mode = $c->getIteratorMode();
        $c->setIteratorMode(\SplDoublyLinkedList::IT_MODE_KEEP | $mode & ~\SplDoublyLinkedList::IT_MODE_DELETE);
        $a += [$prefix . 'mode' => new ConstStub(($mode & \SplDoublyLinkedList::IT_MODE_LIFO ? 'IT_MODE_LIFO' : 'IT_MODE_FIFO') . ' | ' . ($mode & \SplDoublyLinkedList::IT_MODE_DELETE ? 'IT_MODE_DELETE' : 'IT_MODE_KEEP'), $mode), $prefix . 'dllist' => \iterator_to_array($c)];
        $c->setIteratorMode($mode);
        return $a;
    }
    public static function castFileInfo(\SplFileInfo $c, array $a, Stub $stub, $isNested)
    {
        static $map = ['path' => 'getPath', 'filename' => 'getFilename', 'basename' => 'getBasename', 'pathname' => 'getPathname', 'extension' => 'getExtension', 'realPath' => 'getRealPath', 'aTime' => 'getATime', 'mTime' => 'getMTime', 'cTime' => 'getCTime', 'inode' => 'getInode', 'size' => 'getSize', 'perms' => 'getPerms', 'owner' => 'getOwner', 'group' => 'getGroup', 'type' => 'getType', 'writable' => 'isWritable', 'readable' => 'isReadable', 'executable' => 'isExecutable', 'file' => 'isFile', 'dir' => 'isDir', 'link' => 'isLink', 'linkTarget' => 'getLinkTarget'];
        $prefix = Caster::PREFIX_VIRTUAL;
        unset($a["\x00SplFileInfo\x00fileName"]);
        unset($a["\x00SplFileInfo\x00pathName"]);
        if (\PHP_VERSION_ID < 80000) {
            if (\false === $c->getPathname()) {
                $a[$prefix . 'âš '] = 'The parent constructor was not called: the object is in an invalid state';
                return $a;
            }
        } else {
            try {
                $c->isReadable();
            } catch (\RuntimeException $e) {
                if ('Object not initialized' !== $e->getMessage()) {
                    throw $e;
                }
                $a[$prefix . 'âš '] = 'The parent constructor was not called: the object is in an invalid state';
                return $a;
            } catch (\Error $e) {
                if ('Object not initialized' !== $e->getMessage()) {
                    throw $e;
                }
                $a[$prefix . 'âš '] = 'The parent constructor was not called: the object is in an invalid state';
                return $a;
            }
        }
        foreach ($map as $key => $accessor) {
            try {
                $a[$prefix . $key] = $c->{$accessor}();
            } catch (\Exception $e) {
            }
        }
        if ($a[$prefix . 'realPath'] ?? \false) {
            $a[$prefix . 'realPath'] = new LinkStub($a[$prefix . 'realPath']);
        }
        if (isset($a[$prefix . 'perms'])) {
            $a[$prefix . 'perms'] = new ConstStub(\sprintf('0%o', $a[$prefix . 'perms']), $a[$prefix . 'perms']);
        }
        static $mapDate = ['aTime', 'mTime', 'cTime'];
        foreach ($mapDate as $key) {
            if (isset($a[$prefix . $key])) {
                $a[$prefix . $key] = new ConstStub(\date('Y-m-d H:i:s', $a[$prefix . $key]), $a[$prefix . $key]);
            }
        }
        return $a;
    }
    public static function castFileObject(\SplFileObject $c, array $a, Stub $stub, $isNested)
    {
        static $map = ['csvControl' => 'getCsvControl', 'flags' => 'getFlags', 'maxLineLen' => 'getMaxLineLen', 'fstat' => 'fstat', 'eof' => 'eof', 'key' => 'key'];
        $prefix = Caster::PREFIX_VIRTUAL;
        foreach ($map as $key => $accessor) {
            try {
                $a[$prefix . $key] = $c->{$accessor}();
            } catch (\Exception $e) {
            }
        }
        if (isset($a[$prefix . 'flags'])) {
            $flagsArray = [];
            foreach (self::SPL_FILE_OBJECT_FLAGS as $value => $name) {
                if ($a[$prefix . 'flags'] & $value) {
                    $flagsArray[] = $name;
                }
            }
            $a[$prefix . 'flags'] = new ConstStub(\implode('|', $flagsArray), $a[$prefix . 'flags']);
        }
        if (isset($a[$prefix . 'fstat'])) {
            $a[$prefix . 'fstat'] = new CutArrayStub($a[$prefix . 'fstat'], ['dev', 'ino', 'nlink', 'rdev', 'blksize', 'blocks']);
        }
        return $a;
    }
    public static function castObjectStorage(\SplObjectStorage $c, array $a, Stub $stub, $isNested)
    {
        $storage = [];
        unset($a[Caster::PREFIX_DYNAMIC . "\x00gcdata"]);
        // Don't hit https://bugs.php.net/65967
        unset($a["\x00SplObjectStorage\x00storage"]);
        $clone = clone $c;
        foreach ($clone as $obj) {
            $storage[] = ['object' => $obj, 'info' => $clone->getInfo()];
        }
        $a += [Caster::PREFIX_VIRTUAL . 'storage' => $storage];
        return $a;
    }
    public static function castOuterIterator(\OuterIterator $c, array $a, Stub $stub, $isNested)
    {
        $a[Caster::PREFIX_VIRTUAL . 'innerIterator'] = $c->getInnerIterator();
        return $a;
    }
    public static function castWeakReference(\WeakReference $c, array $a, Stub $stub, $isNested)
    {
        $a[Caster::PREFIX_VIRTUAL . 'object'] = $c->get();
        return $a;
    }
    private static function castSplArray($c, array $a, Stub $stub, bool $isNested) : array
    {
        $prefix = Caster::PREFIX_VIRTUAL;
        $flags = $c->getFlags();
        if (!($flags & \ArrayObject::STD_PROP_LIST)) {
            $c->setFlags(\ArrayObject::STD_PROP_LIST);
            $a = Caster::castObject($c, \get_class($c), \method_exists($c, '__debugInfo'), $stub->class);
            $c->setFlags($flags);
        }
        if (\PHP_VERSION_ID < 70400) {
            $a[$prefix . 'storage'] = $c->getArrayCopy();
        }
        $a += [$prefix . 'flag::STD_PROP_LIST' => (bool) ($flags & \ArrayObject::STD_PROP_LIST), $prefix . 'flag::ARRAY_AS_PROPS' => (bool) ($flags & \ArrayObject::ARRAY_AS_PROPS)];
        if ($c instanceof \ArrayObject) {
            $a[$prefix . 'iteratorClass'] = new ClassStub($c->getIteratorClass());
        }
        return $a;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * Casts a caster's Stub.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @final since Symfony 4.4
 */
class StubCaster
{
    public static function castStub(Stub $c, array $a, Stub $stub, $isNested)
    {
        if ($isNested) {
            $stub->type = $c->type;
            $stub->class = $c->class;
            $stub->value = $c->value;
            $stub->handle = $c->handle;
            $stub->cut = $c->cut;
            $stub->attr = $c->attr;
            if (Stub::TYPE_REF === $c->type && !$c->class && \is_string($c->value) && !\preg_match('//u', $c->value)) {
                $stub->type = Stub::TYPE_STRING;
                $stub->class = Stub::STRING_BINARY;
            }
            $a = [];
        }
        return $a;
    }
    public static function castCutArray(CutArrayStub $c, array $a, Stub $stub, $isNested)
    {
        return $isNested ? $c->preservedSubset : $a;
    }
    public static function cutInternals($obj, array $a, Stub $stub, $isNested)
    {
        if ($isNested) {
            $stub->cut += \count($a);
            return [];
        }
        return $a;
    }
    public static function castEnum(EnumStub $c, array $a, Stub $stub, $isNested)
    {
        if ($isNested) {
            $stub->class = $c->dumpKeys ? '' : null;
            $stub->handle = 0;
            $stub->value = null;
            $stub->cut = $c->cut;
            $stub->attr = $c->attr;
            $a = [];
            if ($c->value) {
                foreach (\array_keys($c->value) as $k) {
                    $keys[] = !isset($k[0]) || "\x00" !== $k[0] ? Caster::PREFIX_VIRTUAL . $k : $k;
                }
                // Preserve references with array_combine()
                $a = \array_combine($keys, $c->value);
            }
        }
        return $a;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * Casts pqsql resources to array representation.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @final since Symfony 4.4
 */
class PgSqlCaster
{
    private const PARAM_CODES = ['server_encoding', 'client_encoding', 'is_superuser', 'session_authorization', 'DateStyle', 'TimeZone', 'IntervalStyle', 'integer_datetimes', 'application_name', 'standard_conforming_strings'];
    private const TRANSACTION_STATUS = [\PGSQL_TRANSACTION_IDLE => 'PGSQL_TRANSACTION_IDLE', \PGSQL_TRANSACTION_ACTIVE => 'PGSQL_TRANSACTION_ACTIVE', \PGSQL_TRANSACTION_INTRANS => 'PGSQL_TRANSACTION_INTRANS', \PGSQL_TRANSACTION_INERROR => 'PGSQL_TRANSACTION_INERROR', \PGSQL_TRANSACTION_UNKNOWN => 'PGSQL_TRANSACTION_UNKNOWN'];
    private const RESULT_STATUS = [\PGSQL_EMPTY_QUERY => 'PGSQL_EMPTY_QUERY', \PGSQL_COMMAND_OK => 'PGSQL_COMMAND_OK', \PGSQL_TUPLES_OK => 'PGSQL_TUPLES_OK', \PGSQL_COPY_OUT => 'PGSQL_COPY_OUT', \PGSQL_COPY_IN => 'PGSQL_COPY_IN', \PGSQL_BAD_RESPONSE => 'PGSQL_BAD_RESPONSE', \PGSQL_NONFATAL_ERROR => 'PGSQL_NONFATAL_ERROR', \PGSQL_FATAL_ERROR => 'PGSQL_FATAL_ERROR'];
    private const DIAG_CODES = ['severity' => \PGSQL_DIAG_SEVERITY, 'sqlstate' => \PGSQL_DIAG_SQLSTATE, 'message' => \PGSQL_DIAG_MESSAGE_PRIMARY, 'detail' => \PGSQL_DIAG_MESSAGE_DETAIL, 'hint' => \PGSQL_DIAG_MESSAGE_HINT, 'statement position' => \PGSQL_DIAG_STATEMENT_POSITION, 'internal position' => \PGSQL_DIAG_INTERNAL_POSITION, 'internal query' => \PGSQL_DIAG_INTERNAL_QUERY, 'context' => \PGSQL_DIAG_CONTEXT, 'file' => \PGSQL_DIAG_SOURCE_FILE, 'line' => \PGSQL_DIAG_SOURCE_LINE, 'function' => \PGSQL_DIAG_SOURCE_FUNCTION];
    public static function castLargeObject($lo, array $a, Stub $stub, $isNested)
    {
        $a['seek position'] = \pg_lo_tell($lo);
        return $a;
    }
    public static function castLink($link, array $a, Stub $stub, $isNested)
    {
        $a['status'] = \pg_connection_status($link);
        $a['status'] = new ConstStub(\PGSQL_CONNECTION_OK === $a['status'] ? 'PGSQL_CONNECTION_OK' : 'PGSQL_CONNECTION_BAD', $a['status']);
        $a['busy'] = \pg_connection_busy($link);
        $a['transaction'] = \pg_transaction_status($link);
        if (isset(self::TRANSACTION_STATUS[$a['transaction']])) {
            $a['transaction'] = new ConstStub(self::TRANSACTION_STATUS[$a['transaction']], $a['transaction']);
        }
        $a['pid'] = \pg_get_pid($link);
        $a['last error'] = \pg_last_error($link);
        $a['last notice'] = \pg_last_notice($link);
        $a['host'] = \pg_host($link);
        $a['port'] = \pg_port($link);
        $a['dbname'] = \pg_dbname($link);
        $a['options'] = \pg_options($link);
        $a['version'] = \pg_version($link);
        foreach (self::PARAM_CODES as $v) {
            if (\false !== ($s = \pg_parameter_status($link, $v))) {
                $a['param'][$v] = $s;
            }
        }
        $a['param']['client_encoding'] = \pg_client_encoding($link);
        $a['param'] = new EnumStub($a['param']);
        return $a;
    }
    public static function castResult($result, array $a, Stub $stub, $isNested)
    {
        $a['num rows'] = \pg_num_rows($result);
        $a['status'] = \pg_result_status($result);
        if (isset(self::RESULT_STATUS[$a['status']])) {
            $a['status'] = new ConstStub(self::RESULT_STATUS[$a['status']], $a['status']);
        }
        $a['command-completion tag'] = \pg_result_status($result, \PGSQL_STATUS_STRING);
        if (-1 === $a['num rows']) {
            foreach (self::DIAG_CODES as $k => $v) {
                $a['error'][$k] = \pg_result_error_field($result, $v);
            }
        }
        $a['affected rows'] = \pg_affected_rows($result);
        $a['last OID'] = \pg_last_oid($result);
        $fields = \pg_num_fields($result);
        for ($i = 0; $i < $fields; ++$i) {
            $field = ['name' => \pg_field_name($result, $i), 'table' => \sprintf('%s (OID: %s)', \pg_field_table($result, $i), \pg_field_table($result, $i, \true)), 'type' => \sprintf('%s (OID: %s)', \pg_field_type($result, $i), \pg_field_type_oid($result, $i)), 'nullable' => (bool) \pg_field_is_null($result, $i), 'storage' => \pg_field_size($result, $i) . ' bytes', 'display' => \pg_field_prtlen($result, $i) . ' chars'];
            if (' (OID: )' === $field['table']) {
                $field['table'] = null;
            }
            if ('-1 bytes' === $field['storage']) {
                $field['storage'] = 'variable size';
            } elseif ('1 bytes' === $field['storage']) {
                $field['storage'] = '1 byte';
            }
            if ('1 chars' === $field['display']) {
                $field['display'] = '1 char';
            }
            $a['fields'][] = new EnumStub($field);
        }
        return $a;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * @author Nicolas Grekas <p@tchwork.com>
 */
class DsPairStub extends Stub
{
    public function __construct($key, $value)
    {
        $this->value = [Caster::PREFIX_VIRTUAL . 'key' => $key, Caster::PREFIX_VIRTUAL . 'value' => $value];
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Ramsey\Uuid\UuidInterface;
use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * @author GrÃ©goire Pineau <lyrixx@lyrixx.info>
 */
final class UuidCaster
{
    public static function castRamseyUuid(UuidInterface $c, array $a, Stub $stub, bool $isNested) : array
    {
        $a += [Caster::PREFIX_VIRTUAL . 'uuid' => (string) $c];
        return $a;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * Represents the main properties of a PHP variable, pre-casted by a caster.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
class CutStub extends Stub
{
    public function __construct($value)
    {
        $this->value = $value;
        switch (\gettype($value)) {
            case 'object':
                $this->type = self::TYPE_OBJECT;
                $this->class = \get_class($value);
                if ($value instanceof \Closure) {
                    ReflectionCaster::castClosure($value, [], $this, \true, Caster::EXCLUDE_VERBOSE);
                }
                $this->cut = -1;
                break;
            case 'array':
                $this->type = self::TYPE_ARRAY;
                $this->class = self::ARRAY_ASSOC;
                $this->cut = $this->value = \count($value);
                break;
            case 'resource':
            case 'unknown type':
            case 'resource (closed)':
                $this->type = self::TYPE_RESOURCE;
                $this->handle = (int) $value;
                if ('Unknown' === ($this->class = @\get_resource_type($value))) {
                    $this->class = 'Closed';
                }
                $this->cut = -1;
                break;
            case 'string':
                $this->type = self::TYPE_STRING;
                $this->class = \preg_match('//u', $value) ? self::STRING_UTF8 : self::STRING_BINARY;
                $this->cut = self::STRING_BINARY === $this->class ? \strlen($value) : \mb_strlen($value, 'UTF-8');
                $this->value = '';
                break;
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * Casts XML resources to array representation.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @final since Symfony 4.4
 */
class XmlResourceCaster
{
    private const XML_ERRORS = [\XML_ERROR_NONE => 'XML_ERROR_NONE', \XML_ERROR_NO_MEMORY => 'XML_ERROR_NO_MEMORY', \XML_ERROR_SYNTAX => 'XML_ERROR_SYNTAX', \XML_ERROR_NO_ELEMENTS => 'XML_ERROR_NO_ELEMENTS', \XML_ERROR_INVALID_TOKEN => 'XML_ERROR_INVALID_TOKEN', \XML_ERROR_UNCLOSED_TOKEN => 'XML_ERROR_UNCLOSED_TOKEN', \XML_ERROR_PARTIAL_CHAR => 'XML_ERROR_PARTIAL_CHAR', \XML_ERROR_TAG_MISMATCH => 'XML_ERROR_TAG_MISMATCH', \XML_ERROR_DUPLICATE_ATTRIBUTE => 'XML_ERROR_DUPLICATE_ATTRIBUTE', \XML_ERROR_JUNK_AFTER_DOC_ELEMENT => 'XML_ERROR_JUNK_AFTER_DOC_ELEMENT', \XML_ERROR_PARAM_ENTITY_REF => 'XML_ERROR_PARAM_ENTITY_REF', \XML_ERROR_UNDEFINED_ENTITY => 'XML_ERROR_UNDEFINED_ENTITY', \XML_ERROR_RECURSIVE_ENTITY_REF => 'XML_ERROR_RECURSIVE_ENTITY_REF', \XML_ERROR_ASYNC_ENTITY => 'XML_ERROR_ASYNC_ENTITY', \XML_ERROR_BAD_CHAR_REF => 'XML_ERROR_BAD_CHAR_REF', \XML_ERROR_BINARY_ENTITY_REF => 'XML_ERROR_BINARY_ENTITY_REF', \XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF => 'XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF', \XML_ERROR_MISPLACED_XML_PI => 'XML_ERROR_MISPLACED_XML_PI', \XML_ERROR_UNKNOWN_ENCODING => 'XML_ERROR_UNKNOWN_ENCODING', \XML_ERROR_INCORRECT_ENCODING => 'XML_ERROR_INCORRECT_ENCODING', \XML_ERROR_UNCLOSED_CDATA_SECTION => 'XML_ERROR_UNCLOSED_CDATA_SECTION', \XML_ERROR_EXTERNAL_ENTITY_HANDLING => 'XML_ERROR_EXTERNAL_ENTITY_HANDLING'];
    public static function castXml($h, array $a, Stub $stub, $isNested)
    {
        $a['current_byte_index'] = \xml_get_current_byte_index($h);
        $a['current_column_number'] = \xml_get_current_column_number($h);
        $a['current_line_number'] = \xml_get_current_line_number($h);
        $a['error_code'] = \xml_get_error_code($h);
        if (isset(self::XML_ERRORS[$a['error_code']])) {
            $a['error_code'] = new ConstStub(self::XML_ERRORS[$a['error_code']], $a['error_code']);
        }
        return $a;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * Casts GMP objects to array representation.
 *
 * @author Hamza Amrouche <hamza.simperfit@gmail.com>
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @final since Symfony 4.4
 */
class GmpCaster
{
    public static function castGmp(\GMP $gmp, array $a, Stub $stub, $isNested, $filter) : array
    {
        $a[Caster::PREFIX_VIRTUAL . 'value'] = new ConstStub(\gmp_strval($gmp), \gmp_strval($gmp));
        return $a;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * Represents an enumeration of values.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
class EnumStub extends Stub
{
    public $dumpKeys = \true;
    public function __construct(array $values, bool $dumpKeys = \true)
    {
        $this->value = $values;
        $this->dumpKeys = $dumpKeys;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * Casts Reflector related classes to array representation.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @final since Symfony 4.4
 */
class ReflectionCaster
{
    public const UNSET_CLOSURE_FILE_INFO = ['Closure' => __CLASS__ . '::unsetClosureFileInfo'];
    private const EXTRA_MAP = ['docComment' => 'getDocComment', 'extension' => 'getExtensionName', 'isDisabled' => 'isDisabled', 'isDeprecated' => 'isDeprecated', 'isInternal' => 'isInternal', 'isUserDefined' => 'isUserDefined', 'isGenerator' => 'isGenerator', 'isVariadic' => 'isVariadic'];
    public static function castClosure(\Closure $c, array $a, Stub $stub, $isNested, $filter = 0)
    {
        $prefix = Caster::PREFIX_VIRTUAL;
        $c = new \ReflectionFunction($c);
        $a = static::castFunctionAbstract($c, $a, $stub, $isNested, $filter);
        if (!\str_contains($c->name, '{closure}')) {
            $stub->class = isset($a[$prefix . 'class']) ? $a[$prefix . 'class']->value . '::' . $c->name : $c->name;
            unset($a[$prefix . 'class']);
        }
        unset($a[$prefix . 'extra']);
        $stub->class .= self::getSignature($a);
        if ($f = $c->getFileName()) {
            $stub->attr['file'] = $f;
            $stub->attr['line'] = $c->getStartLine();
        }
        unset($a[$prefix . 'parameters']);
        if ($filter & Caster::EXCLUDE_VERBOSE) {
            $stub->cut += ($c->getFileName() ? 2 : 0) + \count($a);
            return [];
        }
        if ($f) {
            $a[$prefix . 'file'] = new LinkStub($f, $c->getStartLine());
            $a[$prefix . 'line'] = $c->getStartLine() . ' to ' . $c->getEndLine();
        }
        return $a;
    }
    public static function unsetClosureFileInfo(\Closure $c, array $a)
    {
        unset($a[Caster::PREFIX_VIRTUAL . 'file'], $a[Caster::PREFIX_VIRTUAL . 'line']);
        return $a;
    }
    public static function castGenerator(\Generator $c, array $a, Stub $stub, $isNested)
    {
        // Cannot create ReflectionGenerator based on a terminated Generator
        try {
            $reflectionGenerator = new \ReflectionGenerator($c);
        } catch (\Exception $e) {
            $a[Caster::PREFIX_VIRTUAL . 'closed'] = \true;
            return $a;
        }
        return self::castReflectionGenerator($reflectionGenerator, $a, $stub, $isNested);
    }
    public static function castType(\ReflectionType $c, array $a, Stub $stub, $isNested)
    {
        $prefix = Caster::PREFIX_VIRTUAL;
        if ($c instanceof \ReflectionNamedType || \PHP_VERSION_ID < 80000) {
            $a += [$prefix . 'name' => $c instanceof \ReflectionNamedType ? $c->getName() : (string) $c, $prefix . 'allowsNull' => $c->allowsNull(), $prefix . 'isBuiltin' => $c->isBuiltin()];
        } elseif ($c instanceof \ReflectionUnionType || $c instanceof \ReflectionIntersectionType) {
            $a[$prefix . 'allowsNull'] = $c->allowsNull();
            self::addMap($a, $c, ['types' => 'getTypes']);
        } else {
            $a[$prefix . 'allowsNull'] = $c->allowsNull();
        }
        return $a;
    }
    public static function castReflectionGenerator(\ReflectionGenerator $c, array $a, Stub $stub, $isNested)
    {
        $prefix = Caster::PREFIX_VIRTUAL;
        if ($c->getThis()) {
            $a[$prefix . 'this'] = new CutStub($c->getThis());
        }
        $function = $c->getFunction();
        $frame = ['class' => $function->class ?? null, 'type' => isset($function->class) ? $function->isStatic() ? '::' : '->' : null, 'function' => $function->name, 'file' => $c->getExecutingFile(), 'line' => $c->getExecutingLine()];
        if ($trace = $c->getTrace(\DEBUG_BACKTRACE_IGNORE_ARGS)) {
            $function = new \ReflectionGenerator($c->getExecutingGenerator());
            \array_unshift($trace, ['function' => 'yield', 'file' => $function->getExecutingFile(), 'line' => $function->getExecutingLine() - 1]);
            $trace[] = $frame;
            $a[$prefix . 'trace'] = new TraceStub($trace, \false, 0, -1, -1);
        } else {
            $function = new FrameStub($frame, \false, \true);
            $function = ExceptionCaster::castFrameStub($function, [], $function, \true);
            $a[$prefix . 'executing'] = $function[$prefix . 'src'];
        }
        $a[Caster::PREFIX_VIRTUAL . 'closed'] = \false;
        return $a;
    }
    public static function castClass(\ReflectionClass $c, array $a, Stub $stub, $isNested, $filter = 0)
    {
        $prefix = Caster::PREFIX_VIRTUAL;
        if ($n = \Reflection::getModifierNames($c->getModifiers())) {
            $a[$prefix . 'modifiers'] = \implode(' ', $n);
        }
        self::addMap($a, $c, ['extends' => 'getParentClass', 'implements' => 'getInterfaceNames', 'constants' => 'getConstants']);
        foreach ($c->getProperties() as $n) {
            $a[$prefix . 'properties'][$n->name] = $n;
        }
        foreach ($c->getMethods() as $n) {
            $a[$prefix . 'methods'][$n->name] = $n;
        }
        if (!($filter & Caster::EXCLUDE_VERBOSE) && !$isNested) {
            self::addExtra($a, $c);
        }
        return $a;
    }
    public static function castFunctionAbstract(\ReflectionFunctionAbstract $c, array $a, Stub $stub, $isNested, $filter = 0)
    {
        $prefix = Caster::PREFIX_VIRTUAL;
        self::addMap($a, $c, ['returnsReference' => 'returnsReference', 'returnType' => 'getReturnType', 'class' => 'getClosureScopeClass', 'this' => 'getClosureThis']);
        if (isset($a[$prefix . 'returnType'])) {
            $v = $a[$prefix . 'returnType'];
            $v = $v instanceof \ReflectionNamedType ? $v->getName() : (string) $v;
            $a[$prefix . 'returnType'] = new ClassStub($a[$prefix . 'returnType'] instanceof \ReflectionNamedType && $a[$prefix . 'returnType']->allowsNull() && 'mixed' !== $v ? '?' . $v : $v, [\class_exists($v, \false) || \interface_exists($v, \false) || \trait_exists($v, \false) ? $v : '', '']);
        }
        if (isset($a[$prefix . 'class'])) {
            $a[$prefix . 'class'] = new ClassStub($a[$prefix . 'class']);
        }
        if (isset($a[$prefix . 'this'])) {
            $a[$prefix . 'this'] = new CutStub($a[$prefix . 'this']);
        }
        foreach ($c->getParameters() as $v) {
            $k = '$' . $v->name;
            if ($v->isVariadic()) {
                $k = '...' . $k;
            }
            if ($v->isPassedByReference()) {
                $k = '&' . $k;
            }
            $a[$prefix . 'parameters'][$k] = $v;
        }
        if (isset($a[$prefix . 'parameters'])) {
            $a[$prefix . 'parameters'] = new EnumStub($a[$prefix . 'parameters']);
        }
        if (!($filter & Caster::EXCLUDE_VERBOSE) && ($v = $c->getStaticVariables())) {
            foreach ($v as $k => &$v) {
                if (\is_object($v)) {
                    $a[$prefix . 'use']['$' . $k] = new CutStub($v);
                } else {
                    $a[$prefix . 'use']['$' . $k] =& $v;
                }
            }
            unset($v);
            $a[$prefix . 'use'] = new EnumStub($a[$prefix . 'use']);
        }
        if (!($filter & Caster::EXCLUDE_VERBOSE) && !$isNested) {
            self::addExtra($a, $c);
        }
        return $a;
    }
    public static function castMethod(\ReflectionMethod $c, array $a, Stub $stub, $isNested)
    {
        $a[Caster::PREFIX_VIRTUAL . 'modifiers'] = \implode(' ', \Reflection::getModifierNames($c->getModifiers()));
        return $a;
    }
    public static function castParameter(\ReflectionParameter $c, array $a, Stub $stub, $isNested)
    {
        $prefix = Caster::PREFIX_VIRTUAL;
        self::addMap($a, $c, ['position' => 'getPosition', 'isVariadic' => 'isVariadic', 'byReference' => 'isPassedByReference', 'allowsNull' => 'allowsNull']);
        if ($v = $c->getType()) {
            $a[$prefix . 'typeHint'] = $v instanceof \ReflectionNamedType ? $v->getName() : (string) $v;
        }
        if (isset($a[$prefix . 'typeHint'])) {
            $v = $a[$prefix . 'typeHint'];
            $a[$prefix . 'typeHint'] = new ClassStub($v, [\class_exists($v, \false) || \interface_exists($v, \false) || \trait_exists($v, \false) ? $v : '', '']);
        } else {
            unset($a[$prefix . 'allowsNull']);
        }
        try {
            $a[$prefix . 'default'] = $v = $c->getDefaultValue();
            if ($c->isDefaultValueConstant()) {
                $a[$prefix . 'default'] = new ConstStub($c->getDefaultValueConstantName(), $v);
            }
            if (null === $v) {
                unset($a[$prefix . 'allowsNull']);
            }
        } catch (\ReflectionException $e) {
        }
        return $a;
    }
    public static function castProperty(\ReflectionProperty $c, array $a, Stub $stub, $isNested)
    {
        $a[Caster::PREFIX_VIRTUAL . 'modifiers'] = \implode(' ', \Reflection::getModifierNames($c->getModifiers()));
        self::addExtra($a, $c);
        return $a;
    }
    public static function castReference(\ReflectionReference $c, array $a, Stub $stub, $isNested)
    {
        $a[Caster::PREFIX_VIRTUAL . 'id'] = $c->getId();
        return $a;
    }
    public static function castExtension(\ReflectionExtension $c, array $a, Stub $stub, $isNested)
    {
        self::addMap($a, $c, ['version' => 'getVersion', 'dependencies' => 'getDependencies', 'iniEntries' => 'getIniEntries', 'isPersistent' => 'isPersistent', 'isTemporary' => 'isTemporary', 'constants' => 'getConstants', 'functions' => 'getFunctions', 'classes' => 'getClasses']);
        return $a;
    }
    public static function castZendExtension(\ReflectionZendExtension $c, array $a, Stub $stub, $isNested)
    {
        self::addMap($a, $c, ['version' => 'getVersion', 'author' => 'getAuthor', 'copyright' => 'getCopyright', 'url' => 'getURL']);
        return $a;
    }
    public static function getSignature(array $a)
    {
        $prefix = Caster::PREFIX_VIRTUAL;
        $signature = '';
        if (isset($a[$prefix . 'parameters'])) {
            foreach ($a[$prefix . 'parameters']->value as $k => $param) {
                $signature .= ', ';
                if ($type = $param->getType()) {
                    if (!$type instanceof \ReflectionNamedType) {
                        $signature .= $type . ' ';
                    } else {
                        if (!$param->isOptional() && $param->allowsNull() && 'mixed' !== $type->getName()) {
                            $signature .= '?';
                        }
                        $signature .= \substr(\strrchr('\\' . $type->getName(), '\\'), 1) . ' ';
                    }
                }
                $signature .= $k;
                if (!$param->isDefaultValueAvailable()) {
                    continue;
                }
                $v = $param->getDefaultValue();
                $signature .= ' = ';
                if ($param->isDefaultValueConstant()) {
                    $signature .= \substr(\strrchr('\\' . $param->getDefaultValueConstantName(), '\\'), 1);
                } elseif (null === $v) {
                    $signature .= 'null';
                } elseif (\is_array($v)) {
                    $signature .= $v ? '[â€¦' . \count($v) . ']' : '[]';
                } elseif (\is_string($v)) {
                    $signature .= 10 > \strlen($v) && !\str_contains($v, '\\') ? "'{$v}'" : "'â€¦" . \strlen($v) . "'";
                } elseif (\is_bool($v)) {
                    $signature .= $v ? 'true' : 'false';
                } elseif (\is_object($v)) {
                    $signature .= 'new ' . \substr(\strrchr('\\' . \get_debug_type($v), '\\'), 1);
                } else {
                    $signature .= $v;
                }
            }
        }
        $signature = (empty($a[$prefix . 'returnsReference']) ? '' : '&') . '(' . \substr($signature, 2) . ')';
        if (isset($a[$prefix . 'returnType'])) {
            $signature .= ': ' . \substr(\strrchr('\\' . $a[$prefix . 'returnType'], '\\'), 1);
        }
        return $signature;
    }
    private static function addExtra(array &$a, \Reflector $c)
    {
        $x = isset($a[Caster::PREFIX_VIRTUAL . 'extra']) ? $a[Caster::PREFIX_VIRTUAL . 'extra']->value : [];
        if (\method_exists($c, 'getFileName') && ($m = $c->getFileName())) {
            $x['file'] = new LinkStub($m, $c->getStartLine());
            $x['line'] = $c->getStartLine() . ' to ' . $c->getEndLine();
        }
        self::addMap($x, $c, self::EXTRA_MAP, '');
        if ($x) {
            $a[Caster::PREFIX_VIRTUAL . 'extra'] = new EnumStub($x);
        }
    }
    private static function addMap(array &$a, $c, array $map, string $prefix = Caster::PREFIX_VIRTUAL)
    {
        foreach ($map as $k => $m) {
            if (\PHP_VERSION_ID >= 80000 && 'isDisabled' === $k) {
                continue;
            }
            if (\method_exists($c, $m) && \false !== ($m = $c->{$m}()) && null !== $m) {
                $a[$prefix . $k] = $m instanceof \Reflector ? $m->name : $m;
            }
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * Represents a PHP class identifier.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
class ClassStub extends ConstStub
{
    /**
     * @param string   $identifier A PHP identifier, e.g. a class, method, interface, etc. name
     * @param callable $callable   The callable targeted by the identifier when it is ambiguous or not a real PHP identifier
     */
    public function __construct(string $identifier, $callable = null)
    {
        $this->value = $identifier;
        try {
            if (null !== $callable) {
                if ($callable instanceof \Closure) {
                    $r = new \ReflectionFunction($callable);
                } elseif (\is_object($callable)) {
                    $r = [$callable, '__invoke'];
                } elseif (\is_array($callable)) {
                    $r = $callable;
                } elseif (\false !== ($i = \strpos($callable, '::'))) {
                    $r = [\substr($callable, 0, $i), \substr($callable, 2 + $i)];
                } else {
                    $r = new \ReflectionFunction($callable);
                }
            } elseif (0 < ($i = \strpos($identifier, '::') ?: \strpos($identifier, '->'))) {
                $r = [\substr($identifier, 0, $i), \substr($identifier, 2 + $i)];
            } else {
                $r = new \ReflectionClass($identifier);
            }
            if (\is_array($r)) {
                try {
                    $r = new \ReflectionMethod($r[0], $r[1]);
                } catch (\ReflectionException $e) {
                    $r = new \ReflectionClass($r[0]);
                }
            }
            if (\str_contains($identifier, "@anonymous\x00")) {
                $this->value = $identifier = \preg_replace_callback('/[a-zA-Z_\\x7f-\\xff][\\\\a-zA-Z0-9_\\x7f-\\xff]*+@anonymous\\x00.*?\\.php(?:0x?|:[0-9]++\\$)[0-9a-fA-F]++/', function ($m) {
                    return \class_exists($m[0], \false) ? ((\get_parent_class($m[0]) ?: \key(\class_implements($m[0]))) ?: 'class') . '@anonymous' : $m[0];
                }, $identifier);
            }
            if (null !== $callable && $r instanceof \ReflectionFunctionAbstract) {
                $s = ReflectionCaster::castFunctionAbstract($r, [], new Stub(), \true, Caster::EXCLUDE_VERBOSE);
                $s = ReflectionCaster::getSignature($s);
                if (\str_ends_with($identifier, '()')) {
                    $this->value = \substr_replace($identifier, $s, -2);
                } else {
                    $this->value .= $s;
                }
            }
        } catch (\ReflectionException $e) {
            return;
        } finally {
            if (0 < ($i = \strrpos($this->value, '\\'))) {
                $this->attr['ellipsis'] = \strlen($this->value) - $i;
                $this->attr['ellipsis-type'] = 'class';
                $this->attr['ellipsis-tail'] = 1;
            }
        }
        if ($f = $r->getFileName()) {
            $this->attr['file'] = $f;
            $this->attr['line'] = $r->getStartLine();
        }
    }
    public static function wrapCallable($callable)
    {
        if (\is_object($callable) || !\is_callable($callable)) {
            return $callable;
        }
        if (!\is_array($callable)) {
            $callable = new static($callable, $callable);
        } elseif (\is_string($callable[0])) {
            $callable[0] = new static($callable[0], $callable);
        } else {
            $callable[1] = new static($callable[1], $callable);
        }
        return $callable;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\ProxyManager\Proxy\ProxyInterface;
use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @final since Symfony 4.4
 */
class ProxyManagerCaster
{
    public static function castProxy(ProxyInterface $c, array $a, Stub $stub, $isNested)
    {
        if ($parent = \get_parent_class($c)) {
            $stub->class .= ' - ' . $parent;
        }
        $stub->class .= '@proxy';
        return $a;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * Casts DOM related classes to array representation.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @final since Symfony 4.4
 */
class DOMCaster
{
    private const ERROR_CODES = [\DOM_PHP_ERR => 'DOM_PHP_ERR', \DOM_INDEX_SIZE_ERR => 'DOM_INDEX_SIZE_ERR', \DOMSTRING_SIZE_ERR => 'DOMSTRING_SIZE_ERR', \DOM_HIERARCHY_REQUEST_ERR => 'DOM_HIERARCHY_REQUEST_ERR', \DOM_WRONG_DOCUMENT_ERR => 'DOM_WRONG_DOCUMENT_ERR', \DOM_INVALID_CHARACTER_ERR => 'DOM_INVALID_CHARACTER_ERR', \DOM_NO_DATA_ALLOWED_ERR => 'DOM_NO_DATA_ALLOWED_ERR', \DOM_NO_MODIFICATION_ALLOWED_ERR => 'DOM_NO_MODIFICATION_ALLOWED_ERR', \DOM_NOT_FOUND_ERR => 'DOM_NOT_FOUND_ERR', \DOM_NOT_SUPPORTED_ERR => 'DOM_NOT_SUPPORTED_ERR', \DOM_INUSE_ATTRIBUTE_ERR => 'DOM_INUSE_ATTRIBUTE_ERR', \DOM_INVALID_STATE_ERR => 'DOM_INVALID_STATE_ERR', \DOM_SYNTAX_ERR => 'DOM_SYNTAX_ERR', \DOM_INVALID_MODIFICATION_ERR => 'DOM_INVALID_MODIFICATION_ERR', \DOM_NAMESPACE_ERR => 'DOM_NAMESPACE_ERR', \DOM_INVALID_ACCESS_ERR => 'DOM_INVALID_ACCESS_ERR', \DOM_VALIDATION_ERR => 'DOM_VALIDATION_ERR'];
    private const NODE_TYPES = [\XML_ELEMENT_NODE => 'XML_ELEMENT_NODE', \XML_ATTRIBUTE_NODE => 'XML_ATTRIBUTE_NODE', \XML_TEXT_NODE => 'XML_TEXT_NODE', \XML_CDATA_SECTION_NODE => 'XML_CDATA_SECTION_NODE', \XML_ENTITY_REF_NODE => 'XML_ENTITY_REF_NODE', \XML_ENTITY_NODE => 'XML_ENTITY_NODE', \XML_PI_NODE => 'XML_PI_NODE', \XML_COMMENT_NODE => 'XML_COMMENT_NODE', \XML_DOCUMENT_NODE => 'XML_DOCUMENT_NODE', \XML_DOCUMENT_TYPE_NODE => 'XML_DOCUMENT_TYPE_NODE', \XML_DOCUMENT_FRAG_NODE => 'XML_DOCUMENT_FRAG_NODE', \XML_NOTATION_NODE => 'XML_NOTATION_NODE', \XML_HTML_DOCUMENT_NODE => 'XML_HTML_DOCUMENT_NODE', \XML_DTD_NODE => 'XML_DTD_NODE', \XML_ELEMENT_DECL_NODE => 'XML_ELEMENT_DECL_NODE', \XML_ATTRIBUTE_DECL_NODE => 'XML_ATTRIBUTE_DECL_NODE', \XML_ENTITY_DECL_NODE => 'XML_ENTITY_DECL_NODE', \XML_NAMESPACE_DECL_NODE => 'XML_NAMESPACE_DECL_NODE'];
    public static function castException(\DOMException $e, array $a, Stub $stub, $isNested)
    {
        $k = Caster::PREFIX_PROTECTED . 'code';
        if (isset($a[$k], self::ERROR_CODES[$a[$k]])) {
            $a[$k] = new ConstStub(self::ERROR_CODES[$a[$k]], $a[$k]);
        }
        return $a;
    }
    public static function castLength($dom, array $a, Stub $stub, $isNested)
    {
        $a += ['length' => $dom->length];
        return $a;
    }
    public static function castImplementation($dom, array $a, Stub $stub, $isNested)
    {
        $a += [Caster::PREFIX_VIRTUAL . 'Core' => '1.0', Caster::PREFIX_VIRTUAL . 'XML' => '2.0'];
        return $a;
    }
    public static function castNode(\DOMNode $dom, array $a, Stub $stub, $isNested)
    {
        $a += ['nodeName' => $dom->nodeName, 'nodeValue' => new CutStub($dom->nodeValue), 'nodeType' => new ConstStub(self::NODE_TYPES[$dom->nodeType], $dom->nodeType), 'parentNode' => new CutStub($dom->parentNode), 'childNodes' => $dom->childNodes, 'firstChild' => new CutStub($dom->firstChild), 'lastChild' => new CutStub($dom->lastChild), 'previousSibling' => new CutStub($dom->previousSibling), 'nextSibling' => new CutStub($dom->nextSibling), 'attributes' => $dom->attributes, 'ownerDocument' => new CutStub($dom->ownerDocument), 'namespaceURI' => $dom->namespaceURI, 'prefix' => $dom->prefix, 'localName' => $dom->localName, 'baseURI' => $dom->baseURI ? new LinkStub($dom->baseURI) : $dom->baseURI, 'textContent' => new CutStub($dom->textContent)];
        return $a;
    }
    public static function castNameSpaceNode(\DOMNameSpaceNode $dom, array $a, Stub $stub, $isNested)
    {
        $a += ['nodeName' => $dom->nodeName, 'nodeValue' => new CutStub($dom->nodeValue), 'nodeType' => new ConstStub(self::NODE_TYPES[$dom->nodeType], $dom->nodeType), 'prefix' => $dom->prefix, 'localName' => $dom->localName, 'namespaceURI' => $dom->namespaceURI, 'ownerDocument' => new CutStub($dom->ownerDocument), 'parentNode' => new CutStub($dom->parentNode)];
        return $a;
    }
    public static function castDocument(\DOMDocument $dom, array $a, Stub $stub, $isNested, $filter = 0)
    {
        $a += ['doctype' => $dom->doctype, 'implementation' => $dom->implementation, 'documentElement' => new CutStub($dom->documentElement), 'actualEncoding' => $dom->actualEncoding, 'encoding' => $dom->encoding, 'xmlEncoding' => $dom->xmlEncoding, 'standalone' => $dom->standalone, 'xmlStandalone' => $dom->xmlStandalone, 'version' => $dom->version, 'xmlVersion' => $dom->xmlVersion, 'strictErrorChecking' => $dom->strictErrorChecking, 'documentURI' => $dom->documentURI ? new LinkStub($dom->documentURI) : $dom->documentURI, 'config' => $dom->config, 'formatOutput' => $dom->formatOutput, 'validateOnParse' => $dom->validateOnParse, 'resolveExternals' => $dom->resolveExternals, 'preserveWhiteSpace' => $dom->preserveWhiteSpace, 'recover' => $dom->recover, 'substituteEntities' => $dom->substituteEntities];
        if (!($filter & Caster::EXCLUDE_VERBOSE)) {
            $formatOutput = $dom->formatOutput;
            $dom->formatOutput = \true;
            $a += [Caster::PREFIX_VIRTUAL . 'xml' => $dom->saveXML()];
            $dom->formatOutput = $formatOutput;
        }
        return $a;
    }
    public static function castCharacterData(\DOMCharacterData $dom, array $a, Stub $stub, $isNested)
    {
        $a += ['data' => $dom->data, 'length' => $dom->length];
        return $a;
    }
    public static function castAttr(\DOMAttr $dom, array $a, Stub $stub, $isNested)
    {
        $a += ['name' => $dom->name, 'specified' => $dom->specified, 'value' => $dom->value, 'ownerElement' => $dom->ownerElement, 'schemaTypeInfo' => $dom->schemaTypeInfo];
        return $a;
    }
    public static function castElement(\DOMElement $dom, array $a, Stub $stub, $isNested)
    {
        $a += ['tagName' => $dom->tagName, 'schemaTypeInfo' => $dom->schemaTypeInfo];
        return $a;
    }
    public static function castText(\DOMText $dom, array $a, Stub $stub, $isNested)
    {
        $a += ['wholeText' => $dom->wholeText];
        return $a;
    }
    public static function castTypeinfo(\DOMTypeinfo $dom, array $a, Stub $stub, $isNested)
    {
        $a += ['typeName' => $dom->typeName, 'typeNamespace' => $dom->typeNamespace];
        return $a;
    }
    public static function castDomError(\DOMDomError $dom, array $a, Stub $stub, $isNested)
    {
        $a += ['severity' => $dom->severity, 'message' => $dom->message, 'type' => $dom->type, 'relatedException' => $dom->relatedException, 'related_data' => $dom->related_data, 'location' => $dom->location];
        return $a;
    }
    public static function castLocator(\DOMLocator $dom, array $a, Stub $stub, $isNested)
    {
        $a += ['lineNumber' => $dom->lineNumber, 'columnNumber' => $dom->columnNumber, 'offset' => $dom->offset, 'relatedNode' => $dom->relatedNode, 'uri' => $dom->uri ? new LinkStub($dom->uri, $dom->lineNumber) : $dom->uri];
        return $a;
    }
    public static function castDocumentType(\DOMDocumentType $dom, array $a, Stub $stub, $isNested)
    {
        $a += ['name' => $dom->name, 'entities' => $dom->entities, 'notations' => $dom->notations, 'publicId' => $dom->publicId, 'systemId' => $dom->systemId, 'internalSubset' => $dom->internalSubset];
        return $a;
    }
    public static function castNotation(\DOMNotation $dom, array $a, Stub $stub, $isNested)
    {
        $a += ['publicId' => $dom->publicId, 'systemId' => $dom->systemId];
        return $a;
    }
    public static function castEntity(\DOMEntity $dom, array $a, Stub $stub, $isNested)
    {
        $a += ['publicId' => $dom->publicId, 'systemId' => $dom->systemId, 'notationName' => $dom->notationName, 'actualEncoding' => $dom->actualEncoding, 'encoding' => $dom->encoding, 'version' => $dom->version];
        return $a;
    }
    public static function castProcessingInstruction(\DOMProcessingInstruction $dom, array $a, Stub $stub, $isNested)
    {
        $a += ['target' => $dom->target, 'data' => $dom->data];
        return $a;
    }
    public static function castXPath(\DOMXPath $dom, array $a, Stub $stub, $isNested)
    {
        $a += ['document' => $dom->document];
        return $a;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * @author Nicolas Grekas <p@tchwork.com>
 * @author Jan SchÃ¤dlich <jan.schaedlich@sensiolabs.de>
 *
 * @final since Symfony 4.4
 */
class IntlCaster
{
    public static function castMessageFormatter(\MessageFormatter $c, array $a, Stub $stub, $isNested)
    {
        $a += [Caster::PREFIX_VIRTUAL . 'locale' => $c->getLocale(), Caster::PREFIX_VIRTUAL . 'pattern' => $c->getPattern()];
        return self::castError($c, $a);
    }
    public static function castNumberFormatter(\NumberFormatter $c, array $a, Stub $stub, $isNested, $filter = 0)
    {
        $a += [Caster::PREFIX_VIRTUAL . 'locale' => $c->getLocale(), Caster::PREFIX_VIRTUAL . 'pattern' => $c->getPattern()];
        if ($filter & Caster::EXCLUDE_VERBOSE) {
            $stub->cut += 3;
            return self::castError($c, $a);
        }
        $a += [Caster::PREFIX_VIRTUAL . 'attributes' => new EnumStub(['PARSE_INT_ONLY' => $c->getAttribute(\NumberFormatter::PARSE_INT_ONLY), 'GROUPING_USED' => $c->getAttribute(\NumberFormatter::GROUPING_USED), 'DECIMAL_ALWAYS_SHOWN' => $c->getAttribute(\NumberFormatter::DECIMAL_ALWAYS_SHOWN), 'MAX_INTEGER_DIGITS' => $c->getAttribute(\NumberFormatter::MAX_INTEGER_DIGITS), 'MIN_INTEGER_DIGITS' => $c->getAttribute(\NumberFormatter::MIN_INTEGER_DIGITS), 'INTEGER_DIGITS' => $c->getAttribute(\NumberFormatter::INTEGER_DIGITS), 'MAX_FRACTION_DIGITS' => $c->getAttribute(\NumberFormatter::MAX_FRACTION_DIGITS), 'MIN_FRACTION_DIGITS' => $c->getAttribute(\NumberFormatter::MIN_FRACTION_DIGITS), 'FRACTION_DIGITS' => $c->getAttribute(\NumberFormatter::FRACTION_DIGITS), 'MULTIPLIER' => $c->getAttribute(\NumberFormatter::MULTIPLIER), 'GROUPING_SIZE' => $c->getAttribute(\NumberFormatter::GROUPING_SIZE), 'ROUNDING_MODE' => $c->getAttribute(\NumberFormatter::ROUNDING_MODE), 'ROUNDING_INCREMENT' => $c->getAttribute(\NumberFormatter::ROUNDING_INCREMENT), 'FORMAT_WIDTH' => $c->getAttribute(\NumberFormatter::FORMAT_WIDTH), 'PADDING_POSITION' => $c->getAttribute(\NumberFormatter::PADDING_POSITION), 'SECONDARY_GROUPING_SIZE' => $c->getAttribute(\NumberFormatter::SECONDARY_GROUPING_SIZE), 'SIGNIFICANT_DIGITS_USED' => $c->getAttribute(\NumberFormatter::SIGNIFICANT_DIGITS_USED), 'MIN_SIGNIFICANT_DIGITS' => $c->getAttribute(\NumberFormatter::MIN_SIGNIFICANT_DIGITS), 'MAX_SIGNIFICANT_DIGITS' => $c->getAttribute(\NumberFormatter::MAX_SIGNIFICANT_DIGITS), 'LENIENT_PARSE' => $c->getAttribute(\NumberFormatter::LENIENT_PARSE)]), Caster::PREFIX_VIRTUAL . 'text_attributes' => new EnumStub(['POSITIVE_PREFIX' => $c->getTextAttribute(\NumberFormatter::POSITIVE_PREFIX), 'POSITIVE_SUFFIX' => $c->getTextAttribute(\NumberFormatter::POSITIVE_SUFFIX), 'NEGATIVE_PREFIX' => $c->getTextAttribute(\NumberFormatter::NEGATIVE_PREFIX), 'NEGATIVE_SUFFIX' => $c->getTextAttribute(\NumberFormatter::NEGATIVE_SUFFIX), 'PADDING_CHARACTER' => $c->getTextAttribute(\NumberFormatter::PADDING_CHARACTER), 'CURRENCY_CODE' => $c->getTextAttribute(\NumberFormatter::CURRENCY_CODE), 'DEFAULT_RULESET' => $c->getTextAttribute(\NumberFormatter::DEFAULT_RULESET), 'PUBLIC_RULESETS' => $c->getTextAttribute(\NumberFormatter::PUBLIC_RULESETS)]), Caster::PREFIX_VIRTUAL . 'symbols' => new EnumStub(['DECIMAL_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::DECIMAL_SEPARATOR_SYMBOL), 'GROUPING_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::GROUPING_SEPARATOR_SYMBOL), 'PATTERN_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::PATTERN_SEPARATOR_SYMBOL), 'PERCENT_SYMBOL' => $c->getSymbol(\NumberFormatter::PERCENT_SYMBOL), 'ZERO_DIGIT_SYMBOL' => $c->getSymbol(\NumberFormatter::ZERO_DIGIT_SYMBOL), 'DIGIT_SYMBOL' => $c->getSymbol(\NumberFormatter::DIGIT_SYMBOL), 'MINUS_SIGN_SYMBOL' => $c->getSymbol(\NumberFormatter::MINUS_SIGN_SYMBOL), 'PLUS_SIGN_SYMBOL' => $c->getSymbol(\NumberFormatter::PLUS_SIGN_SYMBOL), 'CURRENCY_SYMBOL' => $c->getSymbol(\NumberFormatter::CURRENCY_SYMBOL), 'INTL_CURRENCY_SYMBOL' => $c->getSymbol(\NumberFormatter::INTL_CURRENCY_SYMBOL), 'MONETARY_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::MONETARY_SEPARATOR_SYMBOL), 'EXPONENTIAL_SYMBOL' => $c->getSymbol(\NumberFormatter::EXPONENTIAL_SYMBOL), 'PERMILL_SYMBOL' => $c->getSymbol(\NumberFormatter::PERMILL_SYMBOL), 'PAD_ESCAPE_SYMBOL' => $c->getSymbol(\NumberFormatter::PAD_ESCAPE_SYMBOL), 'INFINITY_SYMBOL' => $c->getSymbol(\NumberFormatter::INFINITY_SYMBOL), 'NAN_SYMBOL' => $c->getSymbol(\NumberFormatter::NAN_SYMBOL), 'SIGNIFICANT_DIGIT_SYMBOL' => $c->getSymbol(\NumberFormatter::SIGNIFICANT_DIGIT_SYMBOL), 'MONETARY_GROUPING_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL)])];
        return self::castError($c, $a);
    }
    public static function castIntlTimeZone(\IntlTimeZone $c, array $a, Stub $stub, $isNested)
    {
        $a += [Caster::PREFIX_VIRTUAL . 'display_name' => $c->getDisplayName(), Caster::PREFIX_VIRTUAL . 'id' => $c->getID(), Caster::PREFIX_VIRTUAL . 'raw_offset' => $c->getRawOffset()];
        if ($c->useDaylightTime()) {
            $a += [Caster::PREFIX_VIRTUAL . 'dst_savings' => $c->getDSTSavings()];
        }
        return self::castError($c, $a);
    }
    public static function castIntlCalendar(\IntlCalendar $c, array $a, Stub $stub, $isNested, $filter = 0)
    {
        $a += [Caster::PREFIX_VIRTUAL . 'type' => $c->getType(), Caster::PREFIX_VIRTUAL . 'first_day_of_week' => $c->getFirstDayOfWeek(), Caster::PREFIX_VIRTUAL . 'minimal_days_in_first_week' => $c->getMinimalDaysInFirstWeek(), Caster::PREFIX_VIRTUAL . 'repeated_wall_time_option' => $c->getRepeatedWallTimeOption(), Caster::PREFIX_VIRTUAL . 'skipped_wall_time_option' => $c->getSkippedWallTimeOption(), Caster::PREFIX_VIRTUAL . 'time' => $c->getTime(), Caster::PREFIX_VIRTUAL . 'in_daylight_time' => $c->inDaylightTime(), Caster::PREFIX_VIRTUAL . 'is_lenient' => $c->isLenient(), Caster::PREFIX_VIRTUAL . 'time_zone' => $filter & Caster::EXCLUDE_VERBOSE ? new CutStub($c->getTimeZone()) : $c->getTimeZone()];
        return self::castError($c, $a);
    }
    public static function castIntlDateFormatter(\IntlDateFormatter $c, array $a, Stub $stub, $isNested, $filter = 0)
    {
        $a += [Caster::PREFIX_VIRTUAL . 'locale' => $c->getLocale(), Caster::PREFIX_VIRTUAL . 'pattern' => $c->getPattern(), Caster::PREFIX_VIRTUAL . 'calendar' => $c->getCalendar(), Caster::PREFIX_VIRTUAL . 'time_zone_id' => $c->getTimeZoneId(), Caster::PREFIX_VIRTUAL . 'time_type' => $c->getTimeType(), Caster::PREFIX_VIRTUAL . 'date_type' => $c->getDateType(), Caster::PREFIX_VIRTUAL . 'calendar_object' => $filter & Caster::EXCLUDE_VERBOSE ? new CutStub($c->getCalendarObject()) : $c->getCalendarObject(), Caster::PREFIX_VIRTUAL . 'time_zone' => $filter & Caster::EXCLUDE_VERBOSE ? new CutStub($c->getTimeZone()) : $c->getTimeZone()];
        return self::castError($c, $a);
    }
    private static function castError($c, array $a) : array
    {
        if ($errorCode = $c->getErrorCode()) {
            $a += [Caster::PREFIX_VIRTUAL . 'error_code' => $errorCode, Caster::PREFIX_VIRTUAL . 'error_message' => $c->getErrorMessage()];
        }
        return $a;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * Casts Redis class from ext-redis to array representation.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @final since Symfony 4.4
 */
class RedisCaster
{
    private const SERIALIZERS = [\Redis::SERIALIZER_NONE => 'NONE', \Redis::SERIALIZER_PHP => 'PHP', 2 => 'IGBINARY'];
    private const MODES = [\Redis::ATOMIC => 'ATOMIC', \Redis::MULTI => 'MULTI', \Redis::PIPELINE => 'PIPELINE'];
    private const COMPRESSION_MODES = [
        0 => 'NONE',
        // Redis::COMPRESSION_NONE
        1 => 'LZF',
    ];
    private const FAILOVER_OPTIONS = [\RedisCluster::FAILOVER_NONE => 'NONE', \RedisCluster::FAILOVER_ERROR => 'ERROR', \RedisCluster::FAILOVER_DISTRIBUTE => 'DISTRIBUTE', \RedisCluster::FAILOVER_DISTRIBUTE_SLAVES => 'DISTRIBUTE_SLAVES'];
    public static function castRedis(\Redis $c, array $a, Stub $stub, $isNested)
    {
        $prefix = Caster::PREFIX_VIRTUAL;
        if (!($connected = $c->isConnected())) {
            return $a + [$prefix . 'isConnected' => $connected];
        }
        $mode = $c->getMode();
        return $a + [$prefix . 'isConnected' => $connected, $prefix . 'host' => $c->getHost(), $prefix . 'port' => $c->getPort(), $prefix . 'auth' => $c->getAuth(), $prefix . 'mode' => isset(self::MODES[$mode]) ? new ConstStub(self::MODES[$mode], $mode) : $mode, $prefix . 'dbNum' => $c->getDbNum(), $prefix . 'timeout' => $c->getTimeout(), $prefix . 'lastError' => $c->getLastError(), $prefix . 'persistentId' => $c->getPersistentID(), $prefix . 'options' => self::getRedisOptions($c)];
    }
    public static function castRedisArray(\RedisArray $c, array $a, Stub $stub, $isNested)
    {
        $prefix = Caster::PREFIX_VIRTUAL;
        return $a + [$prefix . 'hosts' => $c->_hosts(), $prefix . 'function' => ClassStub::wrapCallable($c->_function()), $prefix . 'lastError' => $c->getLastError(), $prefix . 'options' => self::getRedisOptions($c)];
    }
    public static function castRedisCluster(\RedisCluster $c, array $a, Stub $stub, $isNested)
    {
        $prefix = Caster::PREFIX_VIRTUAL;
        $failover = $c->getOption(\RedisCluster::OPT_SLAVE_FAILOVER);
        $a += [$prefix . '_masters' => $c->_masters(), $prefix . '_redir' => $c->_redir(), $prefix . 'mode' => new ConstStub($c->getMode() ? 'MULTI' : 'ATOMIC', $c->getMode()), $prefix . 'lastError' => $c->getLastError(), $prefix . 'options' => self::getRedisOptions($c, ['SLAVE_FAILOVER' => isset(self::FAILOVER_OPTIONS[$failover]) ? new ConstStub(self::FAILOVER_OPTIONS[$failover], $failover) : $failover])];
        return $a;
    }
    /**
     * @param \Redis|\RedisArray|\RedisCluster $redis
     */
    private static function getRedisOptions($redis, array $options = []) : EnumStub
    {
        $serializer = $redis->getOption(\Redis::OPT_SERIALIZER);
        if (\is_array($serializer)) {
            foreach ($serializer as &$v) {
                if (isset(self::SERIALIZERS[$v])) {
                    $v = new ConstStub(self::SERIALIZERS[$v], $v);
                }
            }
        } elseif (isset(self::SERIALIZERS[$serializer])) {
            $serializer = new ConstStub(self::SERIALIZERS[$serializer], $serializer);
        }
        $compression = \defined('Redis::OPT_COMPRESSION') ? $redis->getOption(\Redis::OPT_COMPRESSION) : 0;
        if (\is_array($compression)) {
            foreach ($compression as &$v) {
                if (isset(self::COMPRESSION_MODES[$v])) {
                    $v = new ConstStub(self::COMPRESSION_MODES[$v], $v);
                }
            }
        } elseif (isset(self::COMPRESSION_MODES[$compression])) {
            $compression = new ConstStub(self::COMPRESSION_MODES[$compression], $compression);
        }
        $retry = \defined('Redis::OPT_SCAN') ? $redis->getOption(\Redis::OPT_SCAN) : 0;
        if (\is_array($retry)) {
            foreach ($retry as &$v) {
                $v = new ConstStub($v ? 'RETRY' : 'NORETRY', $v);
            }
        } else {
            $retry = new ConstStub($retry ? 'RETRY' : 'NORETRY', $retry);
        }
        $options += ['TCP_KEEPALIVE' => \defined('Redis::OPT_TCP_KEEPALIVE') ? $redis->getOption(\Redis::OPT_TCP_KEEPALIVE) : 0, 'READ_TIMEOUT' => $redis->getOption(\Redis::OPT_READ_TIMEOUT), 'COMPRESSION' => $compression, 'SERIALIZER' => $serializer, 'PREFIX' => $redis->getOption(\Redis::OPT_PREFIX), 'SCAN' => $retry];
        return new EnumStub($options);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Symfony\Component\ErrorHandler\Exception\SilencedErrorContext;
use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
use CivixPhar\Symfony\Component\VarDumper\Exception\ThrowingCasterException;
/**
 * Casts common Exception classes to array representation.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @final since Symfony 4.4
 */
class ExceptionCaster
{
    public static $srcContext = 1;
    public static $traceArgs = \true;
    public static $errorTypes = [\E_DEPRECATED => 'E_DEPRECATED', \E_USER_DEPRECATED => 'E_USER_DEPRECATED', \E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR', \E_ERROR => 'E_ERROR', \E_WARNING => 'E_WARNING', \E_PARSE => 'E_PARSE', \E_NOTICE => 'E_NOTICE', \E_CORE_ERROR => 'E_CORE_ERROR', \E_CORE_WARNING => 'E_CORE_WARNING', \E_COMPILE_ERROR => 'E_COMPILE_ERROR', \E_COMPILE_WARNING => 'E_COMPILE_WARNING', \E_USER_ERROR => 'E_USER_ERROR', \E_USER_WARNING => 'E_USER_WARNING', \E_USER_NOTICE => 'E_USER_NOTICE', \E_STRICT => 'E_STRICT'];
    private static $framesCache = [];
    public static function castError(\Error $e, array $a, Stub $stub, $isNested, $filter = 0)
    {
        return self::filterExceptionArray($stub->class, $a, "\x00Error\x00", $filter);
    }
    public static function castException(\Exception $e, array $a, Stub $stub, $isNested, $filter = 0)
    {
        return self::filterExceptionArray($stub->class, $a, "\x00Exception\x00", $filter);
    }
    public static function castErrorException(\ErrorException $e, array $a, Stub $stub, $isNested)
    {
        if (isset($a[$s = Caster::PREFIX_PROTECTED . 'severity'], self::$errorTypes[$a[$s]])) {
            $a[$s] = new ConstStub(self::$errorTypes[$a[$s]], $a[$s]);
        }
        return $a;
    }
    public static function castThrowingCasterException(ThrowingCasterException $e, array $a, Stub $stub, $isNested)
    {
        $trace = Caster::PREFIX_VIRTUAL . 'trace';
        $prefix = Caster::PREFIX_PROTECTED;
        $xPrefix = "\x00Exception\x00";
        if (isset($a[$xPrefix . 'previous'], $a[$trace]) && $a[$xPrefix . 'previous'] instanceof \Exception) {
            $b = (array) $a[$xPrefix . 'previous'];
            $class = \get_debug_type($a[$xPrefix . 'previous']);
            self::traceUnshift($b[$xPrefix . 'trace'], $class, $b[$prefix . 'file'], $b[$prefix . 'line']);
            $a[$trace] = new TraceStub($b[$xPrefix . 'trace'], \false, 0, -\count($a[$trace]->value));
        }
        unset($a[$xPrefix . 'previous'], $a[$prefix . 'code'], $a[$prefix . 'file'], $a[$prefix . 'line']);
        return $a;
    }
    public static function castSilencedErrorContext(SilencedErrorContext $e, array $a, Stub $stub, $isNested)
    {
        $sPrefix = "\x00" . SilencedErrorContext::class . "\x00";
        if (!isset($a[$s = $sPrefix . 'severity'])) {
            return $a;
        }
        if (isset(self::$errorTypes[$a[$s]])) {
            $a[$s] = new ConstStub(self::$errorTypes[$a[$s]], $a[$s]);
        }
        $trace = [['file' => $a[$sPrefix . 'file'], 'line' => $a[$sPrefix . 'line']]];
        if (isset($a[$sPrefix . 'trace'])) {
            $trace = \array_merge($trace, $a[$sPrefix . 'trace']);
        }
        unset($a[$sPrefix . 'file'], $a[$sPrefix . 'line'], $a[$sPrefix . 'trace']);
        $a[Caster::PREFIX_VIRTUAL . 'trace'] = new TraceStub($trace, self::$traceArgs);
        return $a;
    }
    public static function castTraceStub(TraceStub $trace, array $a, Stub $stub, $isNested)
    {
        if (!$isNested) {
            return $a;
        }
        $stub->class = '';
        $stub->handle = 0;
        $frames = $trace->value;
        $prefix = Caster::PREFIX_VIRTUAL;
        $a = [];
        $j = \count($frames);
        if (0 > ($i = $trace->sliceOffset)) {
            $i = \max(0, $j + $i);
        }
        if (!isset($trace->value[$i])) {
            return [];
        }
        $lastCall = isset($frames[$i]['function']) ? (isset($frames[$i]['class']) ? $frames[0]['class'] . $frames[$i]['type'] : '') . $frames[$i]['function'] . '()' : '';
        $frames[] = ['function' => ''];
        $collapse = \false;
        for ($j += $trace->numberingOffset - $i++; isset($frames[$i]); ++$i, --$j) {
            $f = $frames[$i];
            $call = isset($f['function']) ? (isset($f['class']) ? $f['class'] . $f['type'] : '') . $f['function'] : '???';
            $frame = new FrameStub(['object' => $f['object'] ?? null, 'class' => $f['class'] ?? null, 'type' => $f['type'] ?? null, 'function' => $f['function'] ?? null] + $frames[$i - 1], \false, \true);
            $f = self::castFrameStub($frame, [], $frame, \true);
            if (isset($f[$prefix . 'src'])) {
                foreach ($f[$prefix . 'src']->value as $label => $frame) {
                    if (\str_starts_with($label, "\x00~collapse=0")) {
                        if ($collapse) {
                            $label = \substr_replace($label, '1', 11, 1);
                        } else {
                            $collapse = \true;
                        }
                    }
                    $label = \substr_replace($label, "title=Stack level {$j}.&", 2, 0);
                }
                $f = $frames[$i - 1];
                if ($trace->keepArgs && !empty($f['args']) && $frame instanceof EnumStub) {
                    $frame->value['arguments'] = new ArgsStub($f['args'], $f['function'] ?? null, $f['class'] ?? null);
                }
            } elseif ('???' !== $lastCall) {
                $label = new ClassStub($lastCall);
                if (isset($label->attr['ellipsis'])) {
                    $label->attr['ellipsis'] += 2;
                    $label = \substr_replace($prefix, "ellipsis-type=class&ellipsis={$label->attr['ellipsis']}&ellipsis-tail=1&title=Stack level {$j}.", 2, 0) . $label->value . '()';
                } else {
                    $label = \substr_replace($prefix, "title=Stack level {$j}.", 2, 0) . $label->value . '()';
                }
            } else {
                $label = \substr_replace($prefix, "title=Stack level {$j}.", 2, 0) . $lastCall;
            }
            $a[\substr_replace($label, \sprintf('separator=%s&', $frame instanceof EnumStub ? ' ' : ':'), 2, 0)] = $frame;
            $lastCall = $call;
        }
        if (null !== $trace->sliceLength) {
            $a = \array_slice($a, 0, $trace->sliceLength, \true);
        }
        return $a;
    }
    public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, $isNested)
    {
        if (!$isNested) {
            return $a;
        }
        $f = $frame->value;
        $prefix = Caster::PREFIX_VIRTUAL;
        if (isset($f['file'], $f['line'])) {
            $cacheKey = $f;
            unset($cacheKey['object'], $cacheKey['args']);
            $cacheKey[] = self::$srcContext;
            $cacheKey = \implode('-', $cacheKey);
            if (isset(self::$framesCache[$cacheKey])) {
                $a[$prefix . 'src'] = self::$framesCache[$cacheKey];
            } else {
                if (\preg_match('/\\((\\d+)\\)(?:\\([\\da-f]{32}\\))? : (?:eval\\(\\)\'d code|runtime-created function)$/', $f['file'], $match)) {
                    $f['file'] = \substr($f['file'], 0, -\strlen($match[0]));
                    $f['line'] = (int) $match[1];
                }
                $src = $f['line'];
                $srcKey = $f['file'];
                $ellipsis = new LinkStub($srcKey, 0);
                $srcAttr = 'collapse=' . (int) $ellipsis->inVendor;
                $ellipsisTail = $ellipsis->attr['ellipsis-tail'] ?? 0;
                $ellipsis = $ellipsis->attr['ellipsis'] ?? 0;
                if (\file_exists($f['file']) && 0 <= self::$srcContext) {
                    if (!empty($f['class']) && (\is_subclass_of($f['class'], 'CivixPhar\\Twig\\Template') || \is_subclass_of($f['class'], 'CivixPhar\\Twig_Template')) && \method_exists($f['class'], 'getDebugInfo')) {
                        $template = null;
                        if (isset($f['object'])) {
                            $template = $f['object'];
                        } elseif ((new \ReflectionClass($f['class']))->isInstantiable()) {
                            $template = \unserialize(\sprintf('O:%d:"%s":0:{}', \strlen($f['class']), $f['class']));
                        }
                        if (null !== $template) {
                            $ellipsis = 0;
                            $templateSrc = \method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getCode() : (\method_exists($template, 'getSource') ? $template->getSource() : '');
                            $templateInfo = $template->getDebugInfo();
                            if (isset($templateInfo[$f['line']])) {
                                if (!\method_exists($template, 'getSourceContext') || !\file_exists($templatePath = $template->getSourceContext()->getPath())) {
                                    $templatePath = null;
                                }
                                if ($templateSrc) {
                                    $src = self::extractSource($templateSrc, $templateInfo[$f['line']], self::$srcContext, 'twig', $templatePath, $f);
                                    $srcKey = ($templatePath ?: $template->getTemplateName()) . ':' . $templateInfo[$f['line']];
                                }
                            }
                        }
                    }
                    if ($srcKey == $f['file']) {
                        $src = self::extractSource(\file_get_contents($f['file']), $f['line'], self::$srcContext, 'php', $f['file'], $f);
                        $srcKey .= ':' . $f['line'];
                        if ($ellipsis) {
                            $ellipsis += 1 + \strlen($f['line']);
                        }
                    }
                    $srcAttr .= \sprintf('&separator= &file=%s&line=%d', \rawurlencode($f['file']), $f['line']);
                } else {
                    $srcAttr .= '&separator=:';
                }
                $srcAttr .= $ellipsis ? '&ellipsis-type=path&ellipsis=' . $ellipsis . '&ellipsis-tail=' . $ellipsisTail : '';
                self::$framesCache[$cacheKey] = $a[$prefix . 'src'] = new EnumStub(["\x00~{$srcAttr}\x00{$srcKey}" => $src]);
            }
        }
        unset($a[$prefix . 'args'], $a[$prefix . 'line'], $a[$prefix . 'file']);
        if ($frame->inTraceStub) {
            unset($a[$prefix . 'class'], $a[$prefix . 'type'], $a[$prefix . 'function']);
        }
        foreach ($a as $k => $v) {
            if (!$v) {
                unset($a[$k]);
            }
        }
        if ($frame->keepArgs && !empty($f['args'])) {
            $a[$prefix . 'arguments'] = new ArgsStub($f['args'], $f['function'], $f['class']);
        }
        return $a;
    }
    private static function filterExceptionArray(string $xClass, array $a, string $xPrefix, int $filter) : array
    {
        if (isset($a[$xPrefix . 'trace'])) {
            $trace = $a[$xPrefix . 'trace'];
            unset($a[$xPrefix . 'trace']);
            // Ensures the trace is always last
        } else {
            $trace = [];
        }
        if (!($filter & Caster::EXCLUDE_VERBOSE) && $trace) {
            if (isset($a[Caster::PREFIX_PROTECTED . 'file'], $a[Caster::PREFIX_PROTECTED . 'line'])) {
                self::traceUnshift($trace, $xClass, $a[Caster::PREFIX_PROTECTED . 'file'], $a[Caster::PREFIX_PROTECTED . 'line']);
            }
            $a[Caster::PREFIX_VIRTUAL . 'trace'] = new TraceStub($trace, self::$traceArgs);
        }
        if (empty($a[$xPrefix . 'previous'])) {
            unset($a[$xPrefix . 'previous']);
        }
        unset($a[$xPrefix . 'string'], $a[Caster::PREFIX_DYNAMIC . 'xdebug_message'], $a[Caster::PREFIX_DYNAMIC . '__destructorException']);
        if (isset($a[Caster::PREFIX_PROTECTED . 'message']) && \str_contains($a[Caster::PREFIX_PROTECTED . 'message'], "@anonymous\x00")) {
            $a[Caster::PREFIX_PROTECTED . 'message'] = \preg_replace_callback('/[a-zA-Z_\\x7f-\\xff][\\\\a-zA-Z0-9_\\x7f-\\xff]*+@anonymous\\x00.*?\\.php(?:0x?|:[0-9]++\\$)[0-9a-fA-F]++/', function ($m) {
                return \class_exists($m[0], \false) ? ((\get_parent_class($m[0]) ?: \key(\class_implements($m[0]))) ?: 'class') . '@anonymous' : $m[0];
            }, $a[Caster::PREFIX_PROTECTED . 'message']);
        }
        if (isset($a[Caster::PREFIX_PROTECTED . 'file'], $a[Caster::PREFIX_PROTECTED . 'line'])) {
            $a[Caster::PREFIX_PROTECTED . 'file'] = new LinkStub($a[Caster::PREFIX_PROTECTED . 'file'], $a[Caster::PREFIX_PROTECTED . 'line']);
        }
        return $a;
    }
    private static function traceUnshift(array &$trace, ?string $class, string $file, int $line) : void
    {
        if (isset($trace[0]['file'], $trace[0]['line']) && $trace[0]['file'] === $file && $trace[0]['line'] === $line) {
            return;
        }
        \array_unshift($trace, ['function' => $class ? 'new ' . $class : null, 'file' => $file, 'line' => $line]);
    }
    private static function extractSource(string $srcLines, int $line, int $srcContext, string $lang, ?string $file, array $frame) : EnumStub
    {
        $srcLines = \explode("\n", $srcLines);
        $src = [];
        for ($i = $line - 1 - $srcContext; $i <= $line - 1 + $srcContext; ++$i) {
            $src[] = ($srcLines[$i] ?? '') . "\n";
        }
        if ($frame['function'] ?? \false) {
            $stub = new CutStub(new \stdClass());
            $stub->class = (isset($frame['class']) ? $frame['class'] . $frame['type'] : '') . $frame['function'];
            $stub->type = Stub::TYPE_OBJECT;
            $stub->attr['cut_hash'] = \true;
            $stub->attr['file'] = $frame['file'];
            $stub->attr['line'] = $frame['line'];
            try {
                $caller = isset($frame['class']) ? new \ReflectionMethod($frame['class'], $frame['function']) : new \ReflectionFunction($frame['function']);
                $stub->class .= ReflectionCaster::getSignature(ReflectionCaster::castFunctionAbstract($caller, [], $stub, \true, Caster::EXCLUDE_VERBOSE));
                if ($f = $caller->getFileName()) {
                    $stub->attr['file'] = $f;
                    $stub->attr['line'] = $caller->getStartLine();
                }
            } catch (\ReflectionException $e) {
                // ignore fake class/function
            }
            $srcLines = ["\x00~separator=\x00" => $stub];
        } else {
            $stub = null;
            $srcLines = [];
        }
        $ltrim = 0;
        do {
            $pad = null;
            for ($i = $srcContext << 1; $i >= 0; --$i) {
                if (isset($src[$i][$ltrim]) && "\r" !== ($c = $src[$i][$ltrim]) && "\n" !== $c) {
                    if (null === $pad) {
                        $pad = $c;
                    }
                    if (' ' !== $c && "\t" !== $c || $pad !== $c) {
                        break;
                    }
                }
            }
            ++$ltrim;
        } while (0 > $i && null !== $pad);
        --$ltrim;
        foreach ($src as $i => $c) {
            if ($ltrim) {
                $c = isset($c[$ltrim]) && "\r" !== $c[$ltrim] ? \substr($c, $ltrim) : \ltrim($c, " \t");
            }
            $c = \substr($c, 0, -1);
            if ($i !== $srcContext) {
                $c = new ConstStub('default', $c);
            } else {
                $c = new ConstStub($c, $stub ? 'in ' . $stub->class : '');
                if (null !== $file) {
                    $c->attr['file'] = $file;
                    $c->attr['line'] = $line;
                }
            }
            $c->attr['lang'] = $lang;
            $srcLines[\sprintf("\x00~separator=â€º &%d\x00", $i + $line - $srcContext)] = $c;
        }
        return new EnumStub($srcLines);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * Casts PDO related classes to array representation.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @final since Symfony 4.4
 */
class PdoCaster
{
    private const PDO_ATTRIBUTES = ['CASE' => [\PDO::CASE_LOWER => 'LOWER', \PDO::CASE_NATURAL => 'NATURAL', \PDO::CASE_UPPER => 'UPPER'], 'ERRMODE' => [\PDO::ERRMODE_SILENT => 'SILENT', \PDO::ERRMODE_WARNING => 'WARNING', \PDO::ERRMODE_EXCEPTION => 'EXCEPTION'], 'TIMEOUT', 'PREFETCH', 'AUTOCOMMIT', 'PERSISTENT', 'DRIVER_NAME', 'SERVER_INFO', 'ORACLE_NULLS' => [\PDO::NULL_NATURAL => 'NATURAL', \PDO::NULL_EMPTY_STRING => 'EMPTY_STRING', \PDO::NULL_TO_STRING => 'TO_STRING'], 'CLIENT_VERSION', 'SERVER_VERSION', 'STATEMENT_CLASS', 'EMULATE_PREPARES', 'CONNECTION_STATUS', 'STRINGIFY_FETCHES', 'DEFAULT_FETCH_MODE' => [\PDO::FETCH_ASSOC => 'ASSOC', \PDO::FETCH_BOTH => 'BOTH', \PDO::FETCH_LAZY => 'LAZY', \PDO::FETCH_NUM => 'NUM', \PDO::FETCH_OBJ => 'OBJ']];
    public static function castPdo(\PDO $c, array $a, Stub $stub, $isNested)
    {
        $attr = [];
        $errmode = $c->getAttribute(\PDO::ATTR_ERRMODE);
        $c->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
        foreach (self::PDO_ATTRIBUTES as $k => $v) {
            if (!isset($k[0])) {
                $k = $v;
                $v = [];
            }
            try {
                $attr[$k] = 'ERRMODE' === $k ? $errmode : $c->getAttribute(\constant('PDO::ATTR_' . $k));
                if ($v && isset($v[$attr[$k]])) {
                    $attr[$k] = new ConstStub($v[$attr[$k]], $attr[$k]);
                }
            } catch (\Exception $e) {
            }
        }
        if (isset($attr[$k = 'STATEMENT_CLASS'][1])) {
            if ($attr[$k][1]) {
                $attr[$k][1] = new ArgsStub($attr[$k][1], '__construct', $attr[$k][0]);
            }
            $attr[$k][0] = new ClassStub($attr[$k][0]);
        }
        $prefix = Caster::PREFIX_VIRTUAL;
        $a += [$prefix . 'inTransaction' => \method_exists($c, 'inTransaction'), $prefix . 'errorInfo' => $c->errorInfo(), $prefix . 'attributes' => new EnumStub($attr)];
        if ($a[$prefix . 'inTransaction']) {
            $a[$prefix . 'inTransaction'] = $c->inTransaction();
        } else {
            unset($a[$prefix . 'inTransaction']);
        }
        if (!isset($a[$prefix . 'errorInfo'][1], $a[$prefix . 'errorInfo'][2])) {
            unset($a[$prefix . 'errorInfo']);
        }
        $c->setAttribute(\PDO::ATTR_ERRMODE, $errmode);
        return $a;
    }
    public static function castPdoStatement(\PDOStatement $c, array $a, Stub $stub, $isNested)
    {
        $prefix = Caster::PREFIX_VIRTUAL;
        $a[$prefix . 'errorInfo'] = $c->errorInfo();
        if (!isset($a[$prefix . 'errorInfo'][1], $a[$prefix . 'errorInfo'][2])) {
            unset($a[$prefix . 'errorInfo']);
        }
        return $a;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

/**
 * Represents a file or a URL.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
class LinkStub extends ConstStub
{
    public $inVendor = \false;
    private static $vendorRoots;
    private static $composerRoots;
    public function __construct(string $label, int $line = 0, string $href = null)
    {
        $this->value = $label;
        if (null === $href) {
            $href = $label;
        }
        if (!\is_string($href)) {
            return;
        }
        if (\str_starts_with($href, 'file://')) {
            if ($href === $label) {
                $label = \substr($label, 7);
            }
            $href = \substr($href, 7);
        } elseif (\str_contains($href, '://')) {
            $this->attr['href'] = $href;
            return;
        }
        if (!\file_exists($href)) {
            return;
        }
        if ($line) {
            $this->attr['line'] = $line;
        }
        if ($label !== ($this->attr['file'] = \realpath($href) ?: $href)) {
            return;
        }
        if ($composerRoot = $this->getComposerRoot($href, $this->inVendor)) {
            $this->attr['ellipsis'] = \strlen($href) - \strlen($composerRoot) + 1;
            $this->attr['ellipsis-type'] = 'path';
            $this->attr['ellipsis-tail'] = 1 + ($this->inVendor ? 2 + \strlen(\implode('', \array_slice(\explode(\DIRECTORY_SEPARATOR, \substr($href, 1 - $this->attr['ellipsis'])), 0, 2))) : 0);
        } elseif (3 < \count($ellipsis = \explode(\DIRECTORY_SEPARATOR, $href))) {
            $this->attr['ellipsis'] = 2 + \strlen(\implode('', \array_slice($ellipsis, -2)));
            $this->attr['ellipsis-type'] = 'path';
            $this->attr['ellipsis-tail'] = 1;
        }
    }
    private function getComposerRoot(string $file, bool &$inVendor)
    {
        if (null === self::$vendorRoots) {
            self::$vendorRoots = [];
            foreach (\get_declared_classes() as $class) {
                if ('C' === $class[0] && \str_starts_with($class, 'ComposerAutoloaderInit')) {
                    $r = new \ReflectionClass($class);
                    $v = \dirname($r->getFileName(), 2);
                    if (\file_exists($v . '/composer/installed.json')) {
                        self::$vendorRoots[] = $v . \DIRECTORY_SEPARATOR;
                    }
                }
            }
        }
        $inVendor = \false;
        if (isset(self::$composerRoots[$dir = \dirname($file)])) {
            return self::$composerRoots[$dir];
        }
        foreach (self::$vendorRoots as $root) {
            if ($inVendor = \str_starts_with($file, $root)) {
                return $root;
            }
        }
        $parent = $dir;
        while (!@\file_exists($parent . '/composer.json')) {
            if (!@\file_exists($parent)) {
                // open_basedir restriction in effect
                break;
            }
            if ($parent === \dirname($parent)) {
                return self::$composerRoots[$dir] = \false;
            }
            $parent = \dirname($parent);
        }
        return self::$composerRoots[$dir] = $parent . \DIRECTORY_SEPARATOR;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * Represents a backtrace as returned by debug_backtrace() or Exception->getTrace().
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
class TraceStub extends Stub
{
    public $keepArgs;
    public $sliceOffset;
    public $sliceLength;
    public $numberingOffset;
    public function __construct(array $trace, bool $keepArgs = \true, int $sliceOffset = 0, int $sliceLength = null, int $numberingOffset = 0)
    {
        $this->value = $trace;
        $this->keepArgs = $keepArgs;
        $this->sliceOffset = $sliceOffset;
        $this->sliceLength = $sliceLength;
        $this->numberingOffset = $numberingOffset;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * Casts DateTimeInterface related classes to array representation.
 *
 * @author Dany Maillard <danymaillard93b@gmail.com>
 *
 * @final since Symfony 4.4
 */
class DateCaster
{
    private const PERIOD_LIMIT = 3;
    public static function castDateTime(\DateTimeInterface $d, array $a, Stub $stub, $isNested, $filter)
    {
        $prefix = Caster::PREFIX_VIRTUAL;
        $location = $d->getTimezone()->getLocation();
        $fromNow = (new \DateTime())->diff($d);
        $title = $d->format('l, F j, Y') . "\n" . self::formatInterval($fromNow) . ' from now' . ($location ? $d->format('I') ? "\nDST On" : "\nDST Off" : '');
        unset($a[Caster::PREFIX_DYNAMIC . 'date'], $a[Caster::PREFIX_DYNAMIC . 'timezone'], $a[Caster::PREFIX_DYNAMIC . 'timezone_type']);
        $a[$prefix . 'date'] = new ConstStub(self::formatDateTime($d, $location ? ' e (P)' : ' P'), $title);
        $stub->class .= $d->format(' @U');
        return $a;
    }
    public static function castInterval(\DateInterval $interval, array $a, Stub $stub, $isNested, $filter)
    {
        $now = new \DateTimeImmutable('@0', new \DateTimeZone('UTC'));
        $numberOfSeconds = $now->add($interval)->getTimestamp() - $now->getTimestamp();
        $title = \number_format($numberOfSeconds, 0, '.', ' ') . 's';
        $i = [Caster::PREFIX_VIRTUAL . 'interval' => new ConstStub(self::formatInterval($interval), $title)];
        return $filter & Caster::EXCLUDE_VERBOSE ? $i : $i + $a;
    }
    private static function formatInterval(\DateInterval $i) : string
    {
        $format = '%R ';
        if (0 === $i->y && 0 === $i->m && ($i->h >= 24 || $i->i >= 60 || $i->s >= 60)) {
            $d = new \DateTimeImmutable('@0', new \DateTimeZone('UTC'));
            $i = $d->diff($d->add($i));
            // recalculate carry over points
            $format .= 0 < $i->days ? '%ad ' : '';
        } else {
            $format .= ($i->y ? '%yy ' : '') . ($i->m ? '%mm ' : '') . ($i->d ? '%dd ' : '');
        }
        $format .= $i->h || $i->i || $i->s || $i->f ? '%H:%I:' . self::formatSeconds($i->s, \substr($i->f, 2)) : '';
        $format = '%R ' === $format ? '0s' : $format;
        return $i->format(\rtrim($format));
    }
    public static function castTimeZone(\DateTimeZone $timeZone, array $a, Stub $stub, $isNested, $filter)
    {
        $location = $timeZone->getLocation();
        $formatted = (new \DateTime('now', $timeZone))->format($location ? 'e (P)' : 'P');
        $title = $location && \extension_loaded('intl') ? \Locale::getDisplayRegion('-' . $location['country_code']) : '';
        $z = [Caster::PREFIX_VIRTUAL . 'timezone' => new ConstStub($formatted, $title)];
        return $filter & Caster::EXCLUDE_VERBOSE ? $z : $z + $a;
    }
    public static function castPeriod(\DatePeriod $p, array $a, Stub $stub, $isNested, $filter)
    {
        $dates = [];
        if (\PHP_VERSION_ID >= 70107) {
            // see https://bugs.php.net/74639
            foreach (clone $p as $i => $d) {
                if (self::PERIOD_LIMIT === $i) {
                    $now = new \DateTimeImmutable('now', new \DateTimeZone('UTC'));
                    $dates[] = \sprintf('%s more', ($end = $p->getEndDate()) ? \ceil(($end->format('U.u') - $d->format('U.u')) / ((int) $now->add($p->getDateInterval())->format('U.u') - (int) $now->format('U.u'))) : $p->recurrences - $i);
                    break;
                }
                $dates[] = \sprintf('%s) %s', $i + 1, self::formatDateTime($d));
            }
        }
        $period = \sprintf('every %s, from %s (%s) %s', self::formatInterval($p->getDateInterval()), self::formatDateTime($p->getStartDate()), $p->include_start_date ? 'included' : 'excluded', ($end = $p->getEndDate()) ? 'to ' . self::formatDateTime($end) : 'recurring ' . $p->recurrences . ' time/s');
        $p = [Caster::PREFIX_VIRTUAL . 'period' => new ConstStub($period, \implode("\n", $dates))];
        return $filter & Caster::EXCLUDE_VERBOSE ? $p : $p + $a;
    }
    private static function formatDateTime(\DateTimeInterface $d, string $extra = '') : string
    {
        return $d->format('Y-m-d H:i:' . self::formatSeconds($d->format('s'), $d->format('u')) . $extra);
    }
    private static function formatSeconds(string $s, string $us) : string
    {
        return \sprintf('%02d.%s', $s, 0 === ($len = \strlen($t = \rtrim($us, '0'))) ? '0' : ($len <= 3 ? \str_pad($t, 3, '0') : $us));
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * Casts Amqp related classes to array representation.
 *
 * @author GrÃ©goire Pineau <lyrixx@lyrixx.info>
 *
 * @final since Symfony 4.4
 */
class AmqpCaster
{
    private const FLAGS = [\AMQP_DURABLE => 'AMQP_DURABLE', \AMQP_PASSIVE => 'AMQP_PASSIVE', \AMQP_EXCLUSIVE => 'AMQP_EXCLUSIVE', \AMQP_AUTODELETE => 'AMQP_AUTODELETE', \AMQP_INTERNAL => 'AMQP_INTERNAL', \AMQP_NOLOCAL => 'AMQP_NOLOCAL', \AMQP_AUTOACK => 'AMQP_AUTOACK', \AMQP_IFEMPTY => 'AMQP_IFEMPTY', \AMQP_IFUNUSED => 'AMQP_IFUNUSED', \AMQP_MANDATORY => 'AMQP_MANDATORY', \AMQP_IMMEDIATE => 'AMQP_IMMEDIATE', \AMQP_MULTIPLE => 'AMQP_MULTIPLE', \AMQP_NOWAIT => 'AMQP_NOWAIT', \AMQP_REQUEUE => 'AMQP_REQUEUE'];
    private const EXCHANGE_TYPES = [\AMQP_EX_TYPE_DIRECT => 'AMQP_EX_TYPE_DIRECT', \AMQP_EX_TYPE_FANOUT => 'AMQP_EX_TYPE_FANOUT', \AMQP_EX_TYPE_TOPIC => 'AMQP_EX_TYPE_TOPIC', \AMQP_EX_TYPE_HEADERS => 'AMQP_EX_TYPE_HEADERS'];
    public static function castConnection(\AMQPConnection $c, array $a, Stub $stub, $isNested)
    {
        $prefix = Caster::PREFIX_VIRTUAL;
        $a += [$prefix . 'is_connected' => $c->isConnected()];
        // Recent version of the extension already expose private properties
        if (isset($a["\x00AMQPConnection\x00login"])) {
            return $a;
        }
        // BC layer in the amqp lib
        if (\method_exists($c, 'getReadTimeout')) {
            $timeout = $c->getReadTimeout();
        } else {
            $timeout = $c->getTimeout();
        }
        $a += [$prefix . 'is_connected' => $c->isConnected(), $prefix . 'login' => $c->getLogin(), $prefix . 'password' => $c->getPassword(), $prefix . 'host' => $c->getHost(), $prefix . 'vhost' => $c->getVhost(), $prefix . 'port' => $c->getPort(), $prefix . 'read_timeout' => $timeout];
        return $a;
    }
    public static function castChannel(\AMQPChannel $c, array $a, Stub $stub, $isNested)
    {
        $prefix = Caster::PREFIX_VIRTUAL;
        $a += [$prefix . 'is_connected' => $c->isConnected(), $prefix . 'channel_id' => $c->getChannelId()];
        // Recent version of the extension already expose private properties
        if (isset($a["\x00AMQPChannel\x00connection"])) {
            return $a;
        }
        $a += [$prefix . 'connection' => $c->getConnection(), $prefix . 'prefetch_size' => $c->getPrefetchSize(), $prefix . 'prefetch_count' => $c->getPrefetchCount()];
        return $a;
    }
    public static function castQueue(\AMQPQueue $c, array $a, Stub $stub, $isNested)
    {
        $prefix = Caster::PREFIX_VIRTUAL;
        $a += [$prefix . 'flags' => self::extractFlags($c->getFlags())];
        // Recent version of the extension already expose private properties
        if (isset($a["\x00AMQPQueue\x00name"])) {
            return $a;
        }
        $a += [$prefix . 'connection' => $c->getConnection(), $prefix . 'channel' => $c->getChannel(), $prefix . 'name' => $c->getName(), $prefix . 'arguments' => $c->getArguments()];
        return $a;
    }
    public static function castExchange(\AMQPExchange $c, array $a, Stub $stub, $isNested)
    {
        $prefix = Caster::PREFIX_VIRTUAL;
        $a += [$prefix . 'flags' => self::extractFlags($c->getFlags())];
        $type = isset(self::EXCHANGE_TYPES[$c->getType()]) ? new ConstStub(self::EXCHANGE_TYPES[$c->getType()], $c->getType()) : $c->getType();
        // Recent version of the extension already expose private properties
        if (isset($a["\x00AMQPExchange\x00name"])) {
            $a["\x00AMQPExchange\x00type"] = $type;
            return $a;
        }
        $a += [$prefix . 'connection' => $c->getConnection(), $prefix . 'channel' => $c->getChannel(), $prefix . 'name' => $c->getName(), $prefix . 'type' => $type, $prefix . 'arguments' => $c->getArguments()];
        return $a;
    }
    public static function castEnvelope(\AMQPEnvelope $c, array $a, Stub $stub, $isNested, $filter = 0)
    {
        $prefix = Caster::PREFIX_VIRTUAL;
        $deliveryMode = new ConstStub($c->getDeliveryMode() . (2 === $c->getDeliveryMode() ? ' (persistent)' : ' (non-persistent)'), $c->getDeliveryMode());
        // Recent version of the extension already expose private properties
        if (isset($a["\x00AMQPEnvelope\x00body"])) {
            $a["\x00AMQPEnvelope\x00delivery_mode"] = $deliveryMode;
            return $a;
        }
        if (!($filter & Caster::EXCLUDE_VERBOSE)) {
            $a += [$prefix . 'body' => $c->getBody()];
        }
        $a += [$prefix . 'delivery_tag' => $c->getDeliveryTag(), $prefix . 'is_redelivery' => $c->isRedelivery(), $prefix . 'exchange_name' => $c->getExchangeName(), $prefix . 'routing_key' => $c->getRoutingKey(), $prefix . 'content_type' => $c->getContentType(), $prefix . 'content_encoding' => $c->getContentEncoding(), $prefix . 'headers' => $c->getHeaders(), $prefix . 'delivery_mode' => $deliveryMode, $prefix . 'priority' => $c->getPriority(), $prefix . 'correlation_id' => $c->getCorrelationId(), $prefix . 'reply_to' => $c->getReplyTo(), $prefix . 'expiration' => $c->getExpiration(), $prefix . 'message_id' => $c->getMessageId(), $prefix . 'timestamp' => $c->getTimeStamp(), $prefix . 'type' => $c->getType(), $prefix . 'user_id' => $c->getUserId(), $prefix . 'app_id' => $c->getAppId()];
        return $a;
    }
    private static function extractFlags(int $flags) : ConstStub
    {
        $flagsArray = [];
        foreach (self::FLAGS as $value => $name) {
            if ($flags & $value) {
                $flagsArray[] = $name;
            }
        }
        if (!$flagsArray) {
            $flagsArray = ['AMQP_NOPARAM'];
        }
        return new ConstStub(\implode('|', $flagsArray), $flags);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * Casts XmlReader class to array representation.
 *
 * @author Baptiste ClaviÃ© <clavie.b@gmail.com>
 *
 * @final since Symfony 4.4
 */
class XmlReaderCaster
{
    private const NODE_TYPES = [\XMLReader::NONE => 'NONE', \XMLReader::ELEMENT => 'ELEMENT', \XMLReader::ATTRIBUTE => 'ATTRIBUTE', \XMLReader::TEXT => 'TEXT', \XMLReader::CDATA => 'CDATA', \XMLReader::ENTITY_REF => 'ENTITY_REF', \XMLReader::ENTITY => 'ENTITY', \XMLReader::PI => 'PI (Processing Instruction)', \XMLReader::COMMENT => 'COMMENT', \XMLReader::DOC => 'DOC', \XMLReader::DOC_TYPE => 'DOC_TYPE', \XMLReader::DOC_FRAGMENT => 'DOC_FRAGMENT', \XMLReader::NOTATION => 'NOTATION', \XMLReader::WHITESPACE => 'WHITESPACE', \XMLReader::SIGNIFICANT_WHITESPACE => 'SIGNIFICANT_WHITESPACE', \XMLReader::END_ELEMENT => 'END_ELEMENT', \XMLReader::END_ENTITY => 'END_ENTITY', \XMLReader::XML_DECLARATION => 'XML_DECLARATION'];
    public static function castXmlReader(\XMLReader $reader, array $a, Stub $stub, $isNested)
    {
        try {
            $properties = ['LOADDTD' => @$reader->getParserProperty(\XMLReader::LOADDTD), 'DEFAULTATTRS' => @$reader->getParserProperty(\XMLReader::DEFAULTATTRS), 'VALIDATE' => @$reader->getParserProperty(\XMLReader::VALIDATE), 'SUBST_ENTITIES' => @$reader->getParserProperty(\XMLReader::SUBST_ENTITIES)];
        } catch (\Error $e) {
            $properties = ['LOADDTD' => \false, 'DEFAULTATTRS' => \false, 'VALIDATE' => \false, 'SUBST_ENTITIES' => \false];
        }
        $props = Caster::PREFIX_VIRTUAL . 'parserProperties';
        $info = ['localName' => $reader->localName, 'prefix' => $reader->prefix, 'nodeType' => new ConstStub(self::NODE_TYPES[$reader->nodeType], $reader->nodeType), 'depth' => $reader->depth, 'isDefault' => $reader->isDefault, 'isEmptyElement' => \XMLReader::NONE === $reader->nodeType ? null : $reader->isEmptyElement, 'xmlLang' => $reader->xmlLang, 'attributeCount' => $reader->attributeCount, 'value' => $reader->value, 'namespaceURI' => $reader->namespaceURI, 'baseURI' => $reader->baseURI ? new LinkStub($reader->baseURI) : $reader->baseURI, $props => $properties];
        if ($info[$props] = Caster::filter($info[$props], Caster::EXCLUDE_EMPTY, [], $count)) {
            $info[$props] = new EnumStub($info[$props]);
            $info[$props]->cut = $count;
        }
        $info = Caster::filter($info, Caster::EXCLUDE_EMPTY, [], $count);
        // +2 because hasValue and hasAttributes are always filtered
        $stub->cut += $count + 2;
        return $a + $info;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * Casts common resource types to array representation.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @final since Symfony 4.4
 */
class ResourceCaster
{
    /**
     * @param \CurlHandle|resource $h
     *
     * @return array
     */
    public static function castCurl($h, array $a, Stub $stub, $isNested)
    {
        return \curl_getinfo($h);
    }
    public static function castDba($dba, array $a, Stub $stub, $isNested)
    {
        $list = \dba_list();
        $a['file'] = $list[(int) $dba];
        return $a;
    }
    public static function castProcess($process, array $a, Stub $stub, $isNested)
    {
        return \proc_get_status($process);
    }
    public static function castStream($stream, array $a, Stub $stub, $isNested)
    {
        $a = \stream_get_meta_data($stream) + static::castStreamContext($stream, $a, $stub, $isNested);
        if ($a['uri'] ?? \false) {
            $a['uri'] = new LinkStub($a['uri']);
        }
        return $a;
    }
    public static function castStreamContext($stream, array $a, Stub $stub, $isNested)
    {
        return @\stream_context_get_params($stream) ?: $a;
    }
    public static function castGd($gd, array $a, Stub $stub, $isNested)
    {
        $a['size'] = \imagesx($gd) . 'x' . \imagesy($gd);
        $a['trueColor'] = \imageistruecolor($gd);
        return $a;
    }
    public static function castMysqlLink($h, array $a, Stub $stub, $isNested)
    {
        $a['host'] = \mysql_get_host_info($h);
        $a['protocol'] = \mysql_get_proto_info($h);
        $a['server'] = \mysql_get_server_info($h);
        return $a;
    }
    public static function castOpensslX509($h, array $a, Stub $stub, $isNested)
    {
        $stub->cut = -1;
        $info = \openssl_x509_parse($h, \false);
        $pin = \openssl_pkey_get_public($h);
        $pin = \openssl_pkey_get_details($pin)['key'];
        $pin = \array_slice(\explode("\n", $pin), 1, -2);
        $pin = \base64_decode(\implode('', $pin));
        $pin = \base64_encode(\hash('sha256', $pin, \true));
        $a += ['subject' => new EnumStub(\array_intersect_key($info['subject'], ['organizationName' => \true, 'commonName' => \true])), 'issuer' => new EnumStub(\array_intersect_key($info['issuer'], ['organizationName' => \true, 'commonName' => \true])), 'expiry' => new ConstStub(\date(\DateTime::ISO8601, $info['validTo_time_t']), $info['validTo_time_t']), 'fingerprint' => new EnumStub(['md5' => new ConstStub(\wordwrap(\strtoupper(\openssl_x509_fingerprint($h, 'md5')), 2, ':', \true)), 'sha1' => new ConstStub(\wordwrap(\strtoupper(\openssl_x509_fingerprint($h, 'sha1')), 2, ':', \true)), 'sha256' => new ConstStub(\wordwrap(\strtoupper(\openssl_x509_fingerprint($h, 'sha256')), 2, ':', \true)), 'pin-sha256' => new ConstStub($pin)])];
        return $a;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

/**
 * Represents a single backtrace frame as returned by debug_backtrace() or Exception->getTrace().
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
class FrameStub extends EnumStub
{
    public $keepArgs;
    public $inTraceStub;
    public function __construct(array $frame, bool $keepArgs = \true, bool $inTraceStub = \false)
    {
        $this->value = $frame;
        $this->keepArgs = $keepArgs;
        $this->inTraceStub = $inTraceStub;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use Ds\Collection;
use Ds\Map;
use Ds\Pair;
use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * Casts Ds extension classes to array representation.
 *
 * @author JÃ¡chym TouÅ¡ek <enumag@gmail.com>
 *
 * @final since Symfony 4.4
 */
class DsCaster
{
    public static function castCollection(Collection $c, array $a, Stub $stub, bool $isNested) : array
    {
        $a[Caster::PREFIX_VIRTUAL . 'count'] = $c->count();
        $a[Caster::PREFIX_VIRTUAL . 'capacity'] = $c->capacity();
        if (!$c instanceof Map) {
            $a += $c->toArray();
        }
        return $a;
    }
    public static function castMap(Map $c, array $a, Stub $stub, bool $isNested) : array
    {
        foreach ($c as $k => $v) {
            $a[] = new DsPairStub($k, $v);
        }
        return $a;
    }
    public static function castPair(Pair $c, array $a, Stub $stub, bool $isNested) : array
    {
        foreach ($c->toArray() as $k => $v) {
            $a[Caster::PREFIX_VIRTUAL . $k] = $v;
        }
        return $a;
    }
    public static function castPairStub(DsPairStub $c, array $a, Stub $stub, bool $isNested) : array
    {
        if ($isNested) {
            $stub->class = Pair::class;
            $stub->value = null;
            $stub->handle = 0;
            $a = $c->value;
        }
        return $a;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * @author Jan SchÃ¤dlich <jan.schaedlich@sensiolabs.de>
 *
 * @final since Symfony 4.4
 */
class MemcachedCaster
{
    private static $optionConstants;
    private static $defaultOptions;
    public static function castMemcached(\Memcached $c, array $a, Stub $stub, $isNested)
    {
        $a += [Caster::PREFIX_VIRTUAL . 'servers' => $c->getServerList(), Caster::PREFIX_VIRTUAL . 'options' => new EnumStub(self::getNonDefaultOptions($c))];
        return $a;
    }
    private static function getNonDefaultOptions(\Memcached $c) : array
    {
        self::$defaultOptions = self::$defaultOptions ?? self::discoverDefaultOptions();
        self::$optionConstants = self::$optionConstants ?? self::getOptionConstants();
        $nonDefaultOptions = [];
        foreach (self::$optionConstants as $constantKey => $value) {
            if (self::$defaultOptions[$constantKey] !== ($option = $c->getOption($value))) {
                $nonDefaultOptions[$constantKey] = $option;
            }
        }
        return $nonDefaultOptions;
    }
    private static function discoverDefaultOptions() : array
    {
        $defaultMemcached = new \Memcached();
        $defaultMemcached->addServer('127.0.0.1', 11211);
        $defaultOptions = [];
        self::$optionConstants = self::$optionConstants ?? self::getOptionConstants();
        foreach (self::$optionConstants as $constantKey => $value) {
            $defaultOptions[$constantKey] = $defaultMemcached->getOption($value);
        }
        return $defaultOptions;
    }
    private static function getOptionConstants() : array
    {
        $reflectedMemcached = new \ReflectionClass(\Memcached::class);
        $optionConstants = [];
        foreach ($reflectedMemcached->getConstants() as $constantKey => $value) {
            if (\str_starts_with($constantKey, 'OPT_')) {
                $optionConstants[$constantKey] = $value;
            }
        }
        return $optionConstants;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * Represents a list of function arguments.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
class ArgsStub extends EnumStub
{
    private static $parameters = [];
    public function __construct(array $args, string $function, ?string $class)
    {
        [$variadic, $params] = self::getParameters($function, $class);
        $values = [];
        foreach ($args as $k => $v) {
            $values[$k] = !\is_scalar($v) && !$v instanceof Stub ? new CutStub($v) : $v;
        }
        if (null === $params) {
            parent::__construct($values, \false);
            return;
        }
        if (\count($values) < \count($params)) {
            $params = \array_slice($params, 0, \count($values));
        } elseif (\count($values) > \count($params)) {
            $values[] = new EnumStub(\array_splice($values, \count($params)), \false);
            $params[] = $variadic;
        }
        if (['...'] === $params) {
            $this->dumpKeys = \false;
            $this->value = $values[0]->value;
        } else {
            $this->value = \array_combine($params, $values);
        }
    }
    private static function getParameters(string $function, ?string $class) : array
    {
        if (isset(self::$parameters[$k = $class . '::' . $function])) {
            return self::$parameters[$k];
        }
        try {
            $r = null !== $class ? new \ReflectionMethod($class, $function) : new \ReflectionFunction($function);
        } catch (\ReflectionException $e) {
            return [null, null];
        }
        $variadic = '...';
        $params = [];
        foreach ($r->getParameters() as $v) {
            $k = '$' . $v->name;
            if ($v->isPassedByReference()) {
                $k = '&' . $k;
            }
            if ($v->isVariadic()) {
                $variadic .= $k;
            } else {
                $params[] = $k;
            }
        }
        return self::$parameters[$k] = [$variadic, $params];
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * Helper for filtering out properties in casters.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @final
 */
class Caster
{
    public const EXCLUDE_VERBOSE = 1;
    public const EXCLUDE_VIRTUAL = 2;
    public const EXCLUDE_DYNAMIC = 4;
    public const EXCLUDE_PUBLIC = 8;
    public const EXCLUDE_PROTECTED = 16;
    public const EXCLUDE_PRIVATE = 32;
    public const EXCLUDE_NULL = 64;
    public const EXCLUDE_EMPTY = 128;
    public const EXCLUDE_NOT_IMPORTANT = 256;
    public const EXCLUDE_STRICT = 512;
    public const PREFIX_VIRTUAL = "\x00~\x00";
    public const PREFIX_DYNAMIC = "\x00+\x00";
    public const PREFIX_PROTECTED = "\x00*\x00";
    /**
     * Casts objects to arrays and adds the dynamic property prefix.
     *
     * @param object $obj          The object to cast
     * @param bool   $hasDebugInfo Whether the __debugInfo method exists on $obj or not
     *
     * @return array The array-cast of the object, with prefixed dynamic properties
     */
    public static function castObject($obj, string $class, bool $hasDebugInfo = \false, string $debugClass = null) : array
    {
        if ($hasDebugInfo) {
            try {
                $debugInfo = $obj->__debugInfo();
            } catch (\Exception $e) {
                // ignore failing __debugInfo()
                $hasDebugInfo = \false;
            }
        }
        $a = $obj instanceof \Closure ? [] : (array) $obj;
        if ($obj instanceof \__PHP_Incomplete_Class) {
            return $a;
        }
        if ($a) {
            static $publicProperties = [];
            $debugClass = $debugClass ?? \get_debug_type($obj);
            $i = 0;
            $prefixedKeys = [];
            foreach ($a as $k => $v) {
                if (isset($k[0]) ? "\x00" !== $k[0] : \PHP_VERSION_ID >= 70200) {
                    if (!isset($publicProperties[$class])) {
                        foreach ((new \ReflectionClass($class))->getProperties(\ReflectionProperty::IS_PUBLIC) as $prop) {
                            $publicProperties[$class][$prop->name] = \true;
                        }
                    }
                    if (!isset($publicProperties[$class][$k])) {
                        $prefixedKeys[$i] = self::PREFIX_DYNAMIC . $k;
                    }
                } elseif ($debugClass !== $class && 1 === \strpos($k, $class)) {
                    $prefixedKeys[$i] = "\x00" . $debugClass . \strrchr($k, "\x00");
                }
                ++$i;
            }
            if ($prefixedKeys) {
                $keys = \array_keys($a);
                foreach ($prefixedKeys as $i => $k) {
                    $keys[$i] = $k;
                }
                $a = \array_combine($keys, $a);
            }
        }
        if ($hasDebugInfo && \is_array($debugInfo)) {
            foreach ($debugInfo as $k => $v) {
                if (!isset($k[0]) || "\x00" !== $k[0]) {
                    if (\array_key_exists(self::PREFIX_DYNAMIC . $k, $a)) {
                        continue;
                    }
                    $k = self::PREFIX_VIRTUAL . $k;
                }
                unset($a[$k]);
                $a[$k] = $v;
            }
        }
        return $a;
    }
    /**
     * Filters out the specified properties.
     *
     * By default, a single match in the $filter bit field filters properties out, following an "or" logic.
     * When EXCLUDE_STRICT is set, an "and" logic is applied: all bits must match for a property to be removed.
     *
     * @param array    $a                The array containing the properties to filter
     * @param int      $filter           A bit field of Caster::EXCLUDE_* constants specifying which properties to filter out
     * @param string[] $listedProperties List of properties to exclude when Caster::EXCLUDE_VERBOSE is set, and to preserve when Caster::EXCLUDE_NOT_IMPORTANT is set
     * @param int      &$count           Set to the number of removed properties
     *
     * @return array The filtered array
     */
    public static function filter(array $a, int $filter, array $listedProperties = [], ?int &$count = 0) : array
    {
        $count = 0;
        foreach ($a as $k => $v) {
            $type = self::EXCLUDE_STRICT & $filter;
            if (null === $v) {
                $type |= self::EXCLUDE_NULL & $filter;
                $type |= self::EXCLUDE_EMPTY & $filter;
            } elseif (\false === $v || '' === $v || '0' === $v || 0 === $v || 0.0 === $v || [] === $v) {
                $type |= self::EXCLUDE_EMPTY & $filter;
            }
            if (self::EXCLUDE_NOT_IMPORTANT & $filter && !\in_array($k, $listedProperties, \true)) {
                $type |= self::EXCLUDE_NOT_IMPORTANT;
            }
            if (self::EXCLUDE_VERBOSE & $filter && \in_array($k, $listedProperties, \true)) {
                $type |= self::EXCLUDE_VERBOSE;
            }
            if (!isset($k[1]) || "\x00" !== $k[0]) {
                $type |= self::EXCLUDE_PUBLIC & $filter;
            } elseif ('~' === $k[1]) {
                $type |= self::EXCLUDE_VIRTUAL & $filter;
            } elseif ('+' === $k[1]) {
                $type |= self::EXCLUDE_DYNAMIC & $filter;
            } elseif ('*' === $k[1]) {
                $type |= self::EXCLUDE_PROTECTED & $filter;
            } else {
                $type |= self::EXCLUDE_PRIVATE & $filter;
            }
            if (self::EXCLUDE_STRICT & $filter ? $type === $filter : $type) {
                unset($a[$k]);
                ++$count;
            }
        }
        return $a;
    }
    public static function castPhpIncompleteClass(\__PHP_Incomplete_Class $c, array $a, Stub $stub, bool $isNested) : array
    {
        if (isset($a['__PHP_Incomplete_Class_Name'])) {
            $stub->class .= '(' . $a['__PHP_Incomplete_Class_Name'] . ')';
            unset($a['__PHP_Incomplete_Class_Name']);
        }
        return $a;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Caster;

/**
 * @author GrÃ©goire Pineau <lyrixx@lyrixx.info>
 */
class ImgStub extends ConstStub
{
    public function __construct(string $data, string $contentType, string $size)
    {
        $this->value = '';
        $this->attr['img-data'] = $data;
        $this->attr['img-size'] = $size;
        $this->attr['content-type'] = $contentType;
    }
}
<?php

namespace CivixPhar;

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
use CivixPhar\Symfony\Component\VarDumper\VarDumper;
if (!\function_exists('CivixPhar\\dump')) {
    /**
     * @author Nicolas Grekas <p@tchwork.com>
     */
    function dump($var, ...$moreVars)
    {
        VarDumper::dump($var);
        foreach ($moreVars as $v) {
            VarDumper::dump($v);
        }
        if (1 < \func_num_args()) {
            return \func_get_args();
        }
        return $var;
    }
}
if (!\function_exists('CivixPhar\\dd')) {
    function dd(...$vars)
    {
        foreach ($vars as $v) {
            VarDumper::dump($v);
        }
        exit(1);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Exception;

/**
 * @author Nicolas Grekas <p@tchwork.com>
 */
class ThrowingCasterException extends \Exception
{
    /**
     * @param \Throwable $prev The exception thrown from the caster
     */
    public function __construct(\Throwable $prev)
    {
        parent::__construct('Unexpected ' . \get_class($prev) . ' thrown from a caster: ' . $prev->getMessage(), 0, $prev);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Cloner;

/**
 * Represents the main properties of a PHP variable.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
class Stub
{
    public const TYPE_REF = 1;
    public const TYPE_STRING = 2;
    public const TYPE_ARRAY = 3;
    public const TYPE_OBJECT = 4;
    public const TYPE_RESOURCE = 5;
    public const STRING_BINARY = 1;
    public const STRING_UTF8 = 2;
    public const ARRAY_ASSOC = 1;
    public const ARRAY_INDEXED = 2;
    public $type = self::TYPE_REF;
    public $class = '';
    public $value;
    public $cut = 0;
    public $handle = 0;
    public $refCount = 0;
    public $position = 0;
    public $attr = [];
    private static $defaultProperties = [];
    /**
     * @internal
     */
    public function __sleep() : array
    {
        $properties = [];
        if (!isset(self::$defaultProperties[$c = static::class])) {
            self::$defaultProperties[$c] = \get_class_vars($c);
            foreach ((new \ReflectionClass($c))->getStaticProperties() as $k => $v) {
                unset(self::$defaultProperties[$c][$k]);
            }
        }
        foreach (self::$defaultProperties[$c] as $k => $v) {
            if ($this->{$k} !== $v) {
                $properties[] = $k;
            }
        }
        return $properties;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Cloner;

/**
 * Represents the current state of a dumper while dumping.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
class Cursor
{
    public const HASH_INDEXED = Stub::ARRAY_INDEXED;
    public const HASH_ASSOC = Stub::ARRAY_ASSOC;
    public const HASH_OBJECT = Stub::TYPE_OBJECT;
    public const HASH_RESOURCE = Stub::TYPE_RESOURCE;
    public $depth = 0;
    public $refIndex = 0;
    public $softRefTo = 0;
    public $softRefCount = 0;
    public $softRefHandle = 0;
    public $hardRefTo = 0;
    public $hardRefCount = 0;
    public $hardRefHandle = 0;
    public $hashType;
    public $hashKey;
    public $hashKeyIsBinary;
    public $hashIndex = 0;
    public $hashLength = 0;
    public $hashCut = 0;
    public $stop = \false;
    public $attr = [];
    public $skipChildren = \false;
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Cloner;

/**
 * @author Nicolas Grekas <p@tchwork.com>
 */
interface ClonerInterface
{
    /**
     * Clones a PHP variable.
     *
     * @param mixed $var Any PHP variable
     *
     * @return Data The cloned variable represented by a Data object
     */
    public function cloneVar($var);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Cloner;

use CivixPhar\Symfony\Component\VarDumper\Caster\Caster;
use CivixPhar\Symfony\Component\VarDumper\Exception\ThrowingCasterException;
/**
 * AbstractCloner implements a generic caster mechanism for objects and resources.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
abstract class AbstractCloner implements ClonerInterface
{
    public static $defaultCasters = ['__PHP_Incomplete_Class' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\Caster', 'castPhpIncompleteClass'], 'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\CutStub' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\StubCaster', 'castStub'], 'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\CutArrayStub' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\StubCaster', 'castCutArray'], 'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ConstStub' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\StubCaster', 'castStub'], 'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\EnumStub' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\StubCaster', 'castEnum'], 'Closure' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ReflectionCaster', 'castClosure'], 'Generator' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ReflectionCaster', 'castGenerator'], 'ReflectionType' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ReflectionCaster', 'castType'], 'ReflectionGenerator' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ReflectionCaster', 'castReflectionGenerator'], 'ReflectionClass' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ReflectionCaster', 'castClass'], 'ReflectionFunctionAbstract' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ReflectionCaster', 'castFunctionAbstract'], 'ReflectionMethod' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ReflectionCaster', 'castMethod'], 'ReflectionParameter' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ReflectionCaster', 'castParameter'], 'ReflectionProperty' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ReflectionCaster', 'castProperty'], 'ReflectionReference' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ReflectionCaster', 'castReference'], 'ReflectionExtension' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ReflectionCaster', 'castExtension'], 'ReflectionZendExtension' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ReflectionCaster', 'castZendExtension'], 'CivixPhar\\Doctrine\\Common\\Persistence\\ObjectManager' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\StubCaster', 'cutInternals'], 'CivixPhar\\Doctrine\\Common\\Proxy\\Proxy' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DoctrineCaster', 'castCommonProxy'], 'CivixPhar\\Doctrine\\ORM\\Proxy\\Proxy' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DoctrineCaster', 'castOrmProxy'], 'CivixPhar\\Doctrine\\ORM\\PersistentCollection' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DoctrineCaster', 'castPersistentCollection'], 'CivixPhar\\Doctrine\\Persistence\\ObjectManager' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\StubCaster', 'cutInternals'], 'DOMException' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DOMCaster', 'castException'], 'DOMStringList' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DOMCaster', 'castLength'], 'DOMNameList' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DOMCaster', 'castLength'], 'DOMImplementation' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DOMCaster', 'castImplementation'], 'DOMImplementationList' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DOMCaster', 'castLength'], 'DOMNode' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DOMCaster', 'castNode'], 'DOMNameSpaceNode' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DOMCaster', 'castNameSpaceNode'], 'DOMDocument' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DOMCaster', 'castDocument'], 'DOMNodeList' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DOMCaster', 'castLength'], 'DOMNamedNodeMap' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DOMCaster', 'castLength'], 'DOMCharacterData' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DOMCaster', 'castCharacterData'], 'DOMAttr' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DOMCaster', 'castAttr'], 'DOMElement' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DOMCaster', 'castElement'], 'DOMText' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DOMCaster', 'castText'], 'DOMTypeinfo' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DOMCaster', 'castTypeinfo'], 'DOMDomError' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DOMCaster', 'castDomError'], 'DOMLocator' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DOMCaster', 'castLocator'], 'DOMDocumentType' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DOMCaster', 'castDocumentType'], 'DOMNotation' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DOMCaster', 'castNotation'], 'DOMEntity' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DOMCaster', 'castEntity'], 'DOMProcessingInstruction' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DOMCaster', 'castProcessingInstruction'], 'DOMXPath' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DOMCaster', 'castXPath'], 'XMLReader' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\XmlReaderCaster', 'castXmlReader'], 'ErrorException' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ExceptionCaster', 'castErrorException'], 'Exception' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ExceptionCaster', 'castException'], 'Error' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ExceptionCaster', 'castError'], 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\StubCaster', 'cutInternals'], 'CivixPhar\\Symfony\\Component\\EventDispatcher\\EventDispatcherInterface' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\StubCaster', 'cutInternals'], 'CivixPhar\\Symfony\\Component\\HttpClient\\CurlHttpClient' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\SymfonyCaster', 'castHttpClient'], 'CivixPhar\\Symfony\\Component\\HttpClient\\NativeHttpClient' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\SymfonyCaster', 'castHttpClient'], 'CivixPhar\\Symfony\\Component\\HttpClient\\Response\\CurlResponse' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\SymfonyCaster', 'castHttpClientResponse'], 'CivixPhar\\Symfony\\Component\\HttpClient\\Response\\NativeResponse' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\SymfonyCaster', 'castHttpClientResponse'], 'Symfony\\Component\\HttpFoundation\\Request' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\SymfonyCaster', 'castRequest'], 'CivixPhar\\Symfony\\Component\\VarDumper\\Exception\\ThrowingCasterException' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ExceptionCaster', 'castThrowingCasterException'], 'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\TraceStub' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ExceptionCaster', 'castTraceStub'], 'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\FrameStub' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ExceptionCaster', 'castFrameStub'], 'CivixPhar\\Symfony\\Component\\VarDumper\\Cloner\\AbstractCloner' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\StubCaster', 'cutInternals'], 'CivixPhar\\Symfony\\Component\\ErrorHandler\\Exception\\SilencedErrorContext' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ExceptionCaster', 'castSilencedErrorContext'], 'CivixPhar\\Imagine\\Image\\ImageInterface' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ImagineCaster', 'castImage'], 'CivixPhar\\Ramsey\\Uuid\\UuidInterface' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\UuidCaster', 'castRamseyUuid'], 'CivixPhar\\ProxyManager\\Proxy\\ProxyInterface' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ProxyManagerCaster', 'castProxy'], 'PHPUnit_Framework_MockObject_MockObject' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\StubCaster', 'cutInternals'], 'CivixPhar\\PHPUnit\\Framework\\MockObject\\MockObject' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\StubCaster', 'cutInternals'], 'CivixPhar\\PHPUnit\\Framework\\MockObject\\Stub' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\StubCaster', 'cutInternals'], 'CivixPhar\\Prophecy\\Prophecy\\ProphecySubjectInterface' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\StubCaster', 'cutInternals'], 'CivixPhar\\Mockery\\MockInterface' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\StubCaster', 'cutInternals'], 'PDO' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\PdoCaster', 'castPdo'], 'PDOStatement' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\PdoCaster', 'castPdoStatement'], 'AMQPConnection' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\AmqpCaster', 'castConnection'], 'AMQPChannel' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\AmqpCaster', 'castChannel'], 'AMQPQueue' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\AmqpCaster', 'castQueue'], 'AMQPExchange' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\AmqpCaster', 'castExchange'], 'AMQPEnvelope' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\AmqpCaster', 'castEnvelope'], 'ArrayObject' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\SplCaster', 'castArrayObject'], 'ArrayIterator' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\SplCaster', 'castArrayIterator'], 'SplDoublyLinkedList' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\SplCaster', 'castDoublyLinkedList'], 'SplFileInfo' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\SplCaster', 'castFileInfo'], 'SplFileObject' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\SplCaster', 'castFileObject'], 'SplHeap' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\SplCaster', 'castHeap'], 'SplObjectStorage' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\SplCaster', 'castObjectStorage'], 'SplPriorityQueue' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\SplCaster', 'castHeap'], 'OuterIterator' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\SplCaster', 'castOuterIterator'], 'WeakReference' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\SplCaster', 'castWeakReference'], 'Redis' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\RedisCaster', 'castRedis'], 'RedisArray' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\RedisCaster', 'castRedisArray'], 'RedisCluster' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\RedisCaster', 'castRedisCluster'], 'DateTimeInterface' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DateCaster', 'castDateTime'], 'DateInterval' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DateCaster', 'castInterval'], 'DateTimeZone' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DateCaster', 'castTimeZone'], 'DatePeriod' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DateCaster', 'castPeriod'], 'GMP' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\GmpCaster', 'castGmp'], 'MessageFormatter' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\IntlCaster', 'castMessageFormatter'], 'NumberFormatter' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\IntlCaster', 'castNumberFormatter'], 'IntlTimeZone' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\IntlCaster', 'castIntlTimeZone'], 'IntlCalendar' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\IntlCaster', 'castIntlCalendar'], 'IntlDateFormatter' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\IntlCaster', 'castIntlDateFormatter'], 'Memcached' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\MemcachedCaster', 'castMemcached'], 'CivixPhar\\Ds\\Collection' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DsCaster', 'castCollection'], 'CivixPhar\\Ds\\Map' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DsCaster', 'castMap'], 'CivixPhar\\Ds\\Pair' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DsCaster', 'castPair'], 'CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DsPairStub' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\DsCaster', 'castPairStub'], 'CurlHandle' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ResourceCaster', 'castCurl'], ':curl' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ResourceCaster', 'castCurl'], ':dba' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ResourceCaster', 'castDba'], ':dba persistent' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ResourceCaster', 'castDba'], 'GdImage' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ResourceCaster', 'castGd'], ':gd' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ResourceCaster', 'castGd'], ':mysql link' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ResourceCaster', 'castMysqlLink'], ':pgsql large object' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\PgSqlCaster', 'castLargeObject'], ':pgsql link' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\PgSqlCaster', 'castLink'], ':pgsql link persistent' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\PgSqlCaster', 'castLink'], ':pgsql result' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\PgSqlCaster', 'castResult'], ':process' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ResourceCaster', 'castProcess'], ':stream' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ResourceCaster', 'castStream'], 'OpenSSLCertificate' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ResourceCaster', 'castOpensslX509'], ':OpenSSL X.509' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ResourceCaster', 'castOpensslX509'], ':persistent stream' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ResourceCaster', 'castStream'], ':stream-context' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\ResourceCaster', 'castStreamContext'], 'XmlParser' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\XmlResourceCaster', 'castXml'], ':xml' => ['CivixPhar\\Symfony\\Component\\VarDumper\\Caster\\XmlResourceCaster', 'castXml']];
    protected $maxItems = 2500;
    protected $maxString = -1;
    protected $minDepth = 1;
    private $casters = [];
    private $prevErrorHandler;
    private $classInfo = [];
    private $filter = 0;
    /**
     * @param callable[]|null $casters A map of casters
     *
     * @see addCasters
     */
    public function __construct(array $casters = null)
    {
        if (null === $casters) {
            $casters = static::$defaultCasters;
        }
        $this->addCasters($casters);
    }
    /**
     * Adds casters for resources and objects.
     *
     * Maps resources or objects types to a callback.
     * Types are in the key, with a callable caster for value.
     * Resource types are to be prefixed with a `:`,
     * see e.g. static::$defaultCasters.
     *
     * @param callable[] $casters A map of casters
     */
    public function addCasters(array $casters)
    {
        foreach ($casters as $type => $callback) {
            $this->casters[$type][] = $callback;
        }
    }
    /**
     * Sets the maximum number of items to clone past the minimum depth in nested structures.
     *
     * @param int $maxItems
     */
    public function setMaxItems($maxItems)
    {
        $this->maxItems = (int) $maxItems;
    }
    /**
     * Sets the maximum cloned length for strings.
     *
     * @param int $maxString
     */
    public function setMaxString($maxString)
    {
        $this->maxString = (int) $maxString;
    }
    /**
     * Sets the minimum tree depth where we are guaranteed to clone all the items.  After this
     * depth is reached, only setMaxItems items will be cloned.
     *
     * @param int $minDepth
     */
    public function setMinDepth($minDepth)
    {
        $this->minDepth = (int) $minDepth;
    }
    /**
     * Clones a PHP variable.
     *
     * @param mixed $var    Any PHP variable
     * @param int   $filter A bit field of Caster::EXCLUDE_* constants
     *
     * @return Data The cloned variable represented by a Data object
     */
    public function cloneVar($var, $filter = 0)
    {
        $this->prevErrorHandler = \set_error_handler(function ($type, $msg, $file, $line, $context = []) {
            if (\E_RECOVERABLE_ERROR === $type || \E_USER_ERROR === $type) {
                // Cloner never dies
                throw new \ErrorException($msg, 0, $type, $file, $line);
            }
            if ($this->prevErrorHandler) {
                return ($this->prevErrorHandler)($type, $msg, $file, $line, $context);
            }
            return \false;
        });
        $this->filter = $filter;
        if ($gc = \gc_enabled()) {
            \gc_disable();
        }
        try {
            return new Data($this->doClone($var));
        } finally {
            if ($gc) {
                \gc_enable();
            }
            \restore_error_handler();
            $this->prevErrorHandler = null;
        }
    }
    /**
     * Effectively clones the PHP variable.
     *
     * @param mixed $var Any PHP variable
     *
     * @return array The cloned variable represented in an array
     */
    protected abstract function doClone($var);
    /**
     * Casts an object to an array representation.
     *
     * @param bool $isNested True if the object is nested in the dumped structure
     *
     * @return array The object casted as array
     */
    protected function castObject(Stub $stub, $isNested)
    {
        $obj = $stub->value;
        $class = $stub->class;
        if (\PHP_VERSION_ID < 80000 ? "\x00" === ($class[15] ?? null) : \str_contains($class, "@anonymous\x00")) {
            $stub->class = \get_debug_type($obj);
        }
        if (isset($this->classInfo[$class])) {
            [$i, $parents, $hasDebugInfo, $fileInfo] = $this->classInfo[$class];
        } else {
            $i = 2;
            $parents = [$class];
            $hasDebugInfo = \method_exists($class, '__debugInfo');
            foreach (\class_parents($class) as $p) {
                $parents[] = $p;
                ++$i;
            }
            foreach (\class_implements($class) as $p) {
                $parents[] = $p;
                ++$i;
            }
            $parents[] = '*';
            $r = new \ReflectionClass($class);
            $fileInfo = $r->isInternal() || $r->isSubclassOf(Stub::class) ? [] : ['file' => $r->getFileName(), 'line' => $r->getStartLine()];
            $this->classInfo[$class] = [$i, $parents, $hasDebugInfo, $fileInfo];
        }
        $stub->attr += $fileInfo;
        $a = Caster::castObject($obj, $class, $hasDebugInfo, $stub->class);
        try {
            while ($i--) {
                if (!empty($this->casters[$p = $parents[$i]])) {
                    foreach ($this->casters[$p] as $callback) {
                        $a = $callback($obj, $a, $stub, $isNested, $this->filter);
                    }
                }
            }
        } catch (\Exception $e) {
            $a = [(Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '') . 'âš ' => new ThrowingCasterException($e)] + $a;
        }
        return $a;
    }
    /**
     * Casts a resource to an array representation.
     *
     * @param bool $isNested True if the object is nested in the dumped structure
     *
     * @return array The resource casted as array
     */
    protected function castResource(Stub $stub, $isNested)
    {
        $a = [];
        $res = $stub->value;
        $type = $stub->class;
        try {
            if (!empty($this->casters[':' . $type])) {
                foreach ($this->casters[':' . $type] as $callback) {
                    $a = $callback($res, $a, $stub, $isNested, $this->filter);
                }
            }
        } catch (\Exception $e) {
            $a = [(Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '') . 'âš ' => new ThrowingCasterException($e)] + $a;
        }
        return $a;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Cloner;

/**
 * DumperInterface used by Data objects.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
interface DumperInterface
{
    /**
     * Dumps a scalar value.
     *
     * @param string                $type  The PHP type of the value being dumped
     * @param string|int|float|bool $value The scalar value being dumped
     */
    public function dumpScalar(Cursor $cursor, $type, $value);
    /**
     * Dumps a string.
     *
     * @param string $str The string being dumped
     * @param bool   $bin Whether $str is UTF-8 or binary encoded
     * @param int    $cut The number of characters $str has been cut by
     */
    public function dumpString(Cursor $cursor, $str, $bin, $cut);
    /**
     * Dumps while entering an hash.
     *
     * @param int        $type     A Cursor::HASH_* const for the type of hash
     * @param string|int $class    The object class, resource type or array count
     * @param bool       $hasChild When the dump of the hash has child item
     */
    public function enterHash(Cursor $cursor, $type, $class, $hasChild);
    /**
     * Dumps while leaving an hash.
     *
     * @param int        $type     A Cursor::HASH_* const for the type of hash
     * @param string|int $class    The object class, resource type or array count
     * @param bool       $hasChild When the dump of the hash has child item
     * @param int        $cut      The number of items the hash has been cut by
     */
    public function leaveHash(Cursor $cursor, $type, $class, $hasChild, $cut);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Cloner;

/**
 * @author Nicolas Grekas <p@tchwork.com>
 */
class VarCloner extends AbstractCloner
{
    private static $gid;
    private static $arrayCache = [];
    /**
     * {@inheritdoc}
     */
    protected function doClone($var)
    {
        $len = 1;
        // Length of $queue
        $pos = 0;
        // Number of cloned items past the minimum depth
        $refsCounter = 0;
        // Hard references counter
        $queue = [[$var]];
        // This breadth-first queue is the return value
        $indexedArrays = [];
        // Map of queue indexes that hold numerically indexed arrays
        $hardRefs = [];
        // Map of original zval ids to stub objects
        $objRefs = [];
        // Map of original object handles to their stub object counterpart
        $objects = [];
        // Keep a ref to objects to ensure their handle cannot be reused while cloning
        $resRefs = [];
        // Map of original resource handles to their stub object counterpart
        $values = [];
        // Map of stub objects' ids to original values
        $maxItems = $this->maxItems;
        $maxString = $this->maxString;
        $minDepth = $this->minDepth;
        $currentDepth = 0;
        // Current tree depth
        $currentDepthFinalIndex = 0;
        // Final $queue index for current tree depth
        $minimumDepthReached = 0 === $minDepth;
        // Becomes true when minimum tree depth has been reached
        $cookie = (object) [];
        // Unique object used to detect hard references
        $a = null;
        // Array cast for nested structures
        $stub = null;
        // Stub capturing the main properties of an original item value
        // or null if the original value is used directly
        if (!($gid = self::$gid)) {
            $gid = self::$gid = \md5(\random_bytes(6));
            // Unique string used to detect the special $GLOBALS variable
        }
        $arrayStub = new Stub();
        $arrayStub->type = Stub::TYPE_ARRAY;
        $fromObjCast = \false;
        for ($i = 0; $i < $len; ++$i) {
            // Detect when we move on to the next tree depth
            if ($i > $currentDepthFinalIndex) {
                ++$currentDepth;
                $currentDepthFinalIndex = $len - 1;
                if ($currentDepth >= $minDepth) {
                    $minimumDepthReached = \true;
                }
            }
            $refs = $vals = $queue[$i];
            if (\PHP_VERSION_ID < 70200 && empty($indexedArrays[$i])) {
                // see https://wiki.php.net/rfc/convert_numeric_keys_in_object_array_casts
                foreach ($vals as $k => $v) {
                    if (\is_int($k)) {
                        continue;
                    }
                    foreach ([$k => \true] as $gk => $gv) {
                    }
                    if ($gk !== $k) {
                        $fromObjCast = \true;
                        $refs = $vals = \array_values($queue[$i]);
                        break;
                    }
                }
            }
            foreach ($vals as $k => $v) {
                // $v is the original value or a stub object in case of hard references
                if (\PHP_VERSION_ID >= 70400) {
                    $zvalRef = ($r = \ReflectionReference::fromArrayElement($vals, $k)) ? $r->getId() : null;
                } else {
                    $refs[$k] = $cookie;
                    $zvalRef = $vals[$k] === $cookie;
                }
                if ($zvalRef) {
                    $vals[$k] =& $stub;
                    // Break hard references to make $queue completely
                    unset($stub);
                    // independent from the original structure
                    if (\PHP_VERSION_ID >= 70400 ? null !== ($vals[$k] = $hardRefs[$zvalRef] ?? null) : $v instanceof Stub && isset($hardRefs[\spl_object_id($v)])) {
                        if (\PHP_VERSION_ID >= 70400) {
                            $v = $vals[$k];
                        } else {
                            $refs[$k] = $vals[$k] = $v;
                        }
                        if ($v->value instanceof Stub && (Stub::TYPE_OBJECT === $v->value->type || Stub::TYPE_RESOURCE === $v->value->type)) {
                            ++$v->value->refCount;
                        }
                        ++$v->refCount;
                        continue;
                    }
                    $vals[$k] = new Stub();
                    $vals[$k]->value = $v;
                    $vals[$k]->handle = ++$refsCounter;
                    if (\PHP_VERSION_ID >= 70400) {
                        $hardRefs[$zvalRef] = $vals[$k];
                    } else {
                        $refs[$k] = $vals[$k];
                        $h = \spl_object_id($refs[$k]);
                        $hardRefs[$h] =& $refs[$k];
                        $values[$h] = $v;
                    }
                }
                // Create $stub when the original value $v can not be used directly
                // If $v is a nested structure, put that structure in array $a
                switch (\true) {
                    case null === $v:
                    case \is_bool($v):
                    case \is_int($v):
                    case \is_float($v):
                        continue 2;
                    case \is_string($v):
                        if ('' === $v) {
                            continue 2;
                        }
                        if (!\preg_match('//u', $v)) {
                            $stub = new Stub();
                            $stub->type = Stub::TYPE_STRING;
                            $stub->class = Stub::STRING_BINARY;
                            if (0 <= $maxString && 0 < ($cut = \strlen($v) - $maxString)) {
                                $stub->cut = $cut;
                                $stub->value = \substr($v, 0, -$cut);
                            } else {
                                $stub->value = $v;
                            }
                        } elseif (0 <= $maxString && isset($v[1 + ($maxString >> 2)]) && 0 < ($cut = \mb_strlen($v, 'UTF-8') - $maxString)) {
                            $stub = new Stub();
                            $stub->type = Stub::TYPE_STRING;
                            $stub->class = Stub::STRING_UTF8;
                            $stub->cut = $cut;
                            $stub->value = \mb_substr($v, 0, $maxString, 'UTF-8');
                        } else {
                            continue 2;
                        }
                        $a = null;
                        break;
                    case \is_array($v):
                        if (!$v) {
                            continue 2;
                        }
                        $stub = $arrayStub;
                        $stub->class = Stub::ARRAY_INDEXED;
                        $j = -1;
                        foreach ($v as $gk => $gv) {
                            if ($gk !== ++$j) {
                                $stub->class = Stub::ARRAY_ASSOC;
                                break;
                            }
                        }
                        $a = $v;
                        if (Stub::ARRAY_ASSOC === $stub->class) {
                            // Copies of $GLOBALS have very strange behavior,
                            // let's detect them with some black magic
                            if (\PHP_VERSION_ID < 80100 && ($a[$gid] = \true) && isset($v[$gid])) {
                                unset($v[$gid]);
                                $a = [];
                                foreach ($v as $gk => &$gv) {
                                    if ($v === $gv && (\PHP_VERSION_ID < 70400 || !isset($hardRefs[\ReflectionReference::fromArrayElement($v, $gk)->getId()]))) {
                                        unset($v);
                                        $v = new Stub();
                                        $v->value = [$v->cut = \count($gv), Stub::TYPE_ARRAY => 0];
                                        $v->handle = -1;
                                        if (\PHP_VERSION_ID >= 70400) {
                                            $gv =& $a[$gk];
                                            $hardRefs[\ReflectionReference::fromArrayElement($a, $gk)->getId()] =& $gv;
                                        } else {
                                            $gv =& $hardRefs[\spl_object_id($v)];
                                        }
                                        $gv = $v;
                                    }
                                    $a[$gk] =& $gv;
                                }
                                unset($gv);
                            } else {
                                $a = $v;
                            }
                        } elseif (\PHP_VERSION_ID < 70200) {
                            $indexedArrays[$len] = \true;
                        }
                        break;
                    case \is_object($v):
                    case $v instanceof \__PHP_Incomplete_Class:
                        if (empty($objRefs[$h = \spl_object_id($v)])) {
                            $stub = new Stub();
                            $stub->type = Stub::TYPE_OBJECT;
                            $stub->class = \get_class($v);
                            $stub->value = $v;
                            $stub->handle = $h;
                            $a = $this->castObject($stub, 0 < $i);
                            if ($v !== $stub->value) {
                                if (Stub::TYPE_OBJECT !== $stub->type || null === $stub->value) {
                                    break;
                                }
                                $stub->handle = $h = \spl_object_id($stub->value);
                            }
                            $stub->value = null;
                            if (0 <= $maxItems && $maxItems <= $pos && $minimumDepthReached) {
                                $stub->cut = \count($a);
                                $a = null;
                            }
                        }
                        if (empty($objRefs[$h])) {
                            $objRefs[$h] = $stub;
                            $objects[] = $v;
                        } else {
                            $stub = $objRefs[$h];
                            ++$stub->refCount;
                            $a = null;
                        }
                        break;
                    default:
                        // resource
                        if (empty($resRefs[$h = (int) $v])) {
                            $stub = new Stub();
                            $stub->type = Stub::TYPE_RESOURCE;
                            if ('Unknown' === ($stub->class = @\get_resource_type($v))) {
                                $stub->class = 'Closed';
                            }
                            $stub->value = $v;
                            $stub->handle = $h;
                            $a = $this->castResource($stub, 0 < $i);
                            $stub->value = null;
                            if (0 <= $maxItems && $maxItems <= $pos && $minimumDepthReached) {
                                $stub->cut = \count($a);
                                $a = null;
                            }
                        }
                        if (empty($resRefs[$h])) {
                            $resRefs[$h] = $stub;
                        } else {
                            $stub = $resRefs[$h];
                            ++$stub->refCount;
                            $a = null;
                        }
                        break;
                }
                if ($a) {
                    if (!$minimumDepthReached || 0 > $maxItems) {
                        $queue[$len] = $a;
                        $stub->position = $len++;
                    } elseif ($pos < $maxItems) {
                        if ($maxItems < ($pos += \count($a))) {
                            $a = \array_slice($a, 0, $maxItems - $pos, \true);
                            if ($stub->cut >= 0) {
                                $stub->cut += $pos - $maxItems;
                            }
                        }
                        $queue[$len] = $a;
                        $stub->position = $len++;
                    } elseif ($stub->cut >= 0) {
                        $stub->cut += \count($a);
                        $stub->position = 0;
                    }
                }
                if ($arrayStub === $stub) {
                    if ($arrayStub->cut) {
                        $stub = [$arrayStub->cut, $arrayStub->class => $arrayStub->position];
                        $arrayStub->cut = 0;
                    } elseif (isset(self::$arrayCache[$arrayStub->class][$arrayStub->position])) {
                        $stub = self::$arrayCache[$arrayStub->class][$arrayStub->position];
                    } else {
                        self::$arrayCache[$arrayStub->class][$arrayStub->position] = $stub = [$arrayStub->class => $arrayStub->position];
                    }
                }
                if (!$zvalRef) {
                    $vals[$k] = $stub;
                } elseif (\PHP_VERSION_ID >= 70400) {
                    $hardRefs[$zvalRef]->value = $stub;
                } else {
                    $refs[$k]->value = $stub;
                }
            }
            if ($fromObjCast) {
                $fromObjCast = \false;
                $refs = $vals;
                $vals = [];
                $j = -1;
                foreach ($queue[$i] as $k => $v) {
                    foreach ([$k => \true] as $gk => $gv) {
                    }
                    if ($gk !== $k) {
                        $vals = (object) $vals;
                        $vals->{$k} = $refs[++$j];
                        $vals = (array) $vals;
                    } else {
                        $vals[$k] = $refs[++$j];
                    }
                }
            }
            $queue[$i] = $vals;
        }
        foreach ($values as $h => $v) {
            $hardRefs[$h] = $v;
        }
        return $queue;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Cloner;

use CivixPhar\Symfony\Component\VarDumper\Caster\Caster;
use CivixPhar\Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider;
/**
 * @author Nicolas Grekas <p@tchwork.com>
 */
class Data implements \ArrayAccess, \Countable, \IteratorAggregate
{
    private $data;
    private $position = 0;
    private $key = 0;
    private $maxDepth = 20;
    private $maxItemsPerDepth = -1;
    private $useRefHandles = -1;
    private $context = [];
    /**
     * @param array $data An array as returned by ClonerInterface::cloneVar()
     */
    public function __construct(array $data)
    {
        $this->data = $data;
    }
    /**
     * @return string|null The type of the value
     */
    public function getType()
    {
        $item = $this->data[$this->position][$this->key];
        if ($item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) {
            $item = $item->value;
        }
        if (!$item instanceof Stub) {
            return \gettype($item);
        }
        if (Stub::TYPE_STRING === $item->type) {
            return 'string';
        }
        if (Stub::TYPE_ARRAY === $item->type) {
            return 'array';
        }
        if (Stub::TYPE_OBJECT === $item->type) {
            return $item->class;
        }
        if (Stub::TYPE_RESOURCE === $item->type) {
            return $item->class . ' resource';
        }
        return null;
    }
    /**
     * @param array|bool $recursive Whether values should be resolved recursively or not
     *
     * @return string|int|float|bool|array|Data[]|null A native representation of the original value
     */
    public function getValue($recursive = \false)
    {
        $item = $this->data[$this->position][$this->key];
        if ($item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) {
            $item = $item->value;
        }
        if (!($item = $this->getStub($item)) instanceof Stub) {
            return $item;
        }
        if (Stub::TYPE_STRING === $item->type) {
            return $item->value;
        }
        $children = $item->position ? $this->data[$item->position] : [];
        foreach ($children as $k => $v) {
            if ($recursive && !($v = $this->getStub($v)) instanceof Stub) {
                continue;
            }
            $children[$k] = clone $this;
            $children[$k]->key = $k;
            $children[$k]->position = $item->position;
            if ($recursive) {
                if (Stub::TYPE_REF === $v->type && ($v = $this->getStub($v->value)) instanceof Stub) {
                    $recursive = (array) $recursive;
                    if (isset($recursive[$v->position])) {
                        continue;
                    }
                    $recursive[$v->position] = \true;
                }
                $children[$k] = $children[$k]->getValue($recursive);
            }
        }
        return $children;
    }
    /**
     * @return int
     */
    #[\ReturnTypeWillChange]
    public function count()
    {
        return \count($this->getValue());
    }
    /**
     * @return \Traversable
     */
    #[\ReturnTypeWillChange]
    public function getIterator()
    {
        if (!\is_array($value = $this->getValue())) {
            throw new \LogicException(\sprintf('"%s" object holds non-iterable type "%s".', self::class, \gettype($value)));
        }
        yield from $value;
    }
    public function __get($key)
    {
        if (null !== ($data = $this->seek($key))) {
            $item = $this->getStub($data->data[$data->position][$data->key]);
            return $item instanceof Stub || [] === $item ? $data : $item;
        }
        return null;
    }
    /**
     * @return bool
     */
    public function __isset($key)
    {
        return null !== $this->seek($key);
    }
    /**
     * @return bool
     */
    #[\ReturnTypeWillChange]
    public function offsetExists($key)
    {
        return $this->__isset($key);
    }
    /**
     * @return mixed
     */
    #[\ReturnTypeWillChange]
    public function offsetGet($key)
    {
        return $this->__get($key);
    }
    /**
     * @return void
     */
    #[\ReturnTypeWillChange]
    public function offsetSet($key, $value)
    {
        throw new \BadMethodCallException(self::class . ' objects are immutable.');
    }
    /**
     * @return void
     */
    #[\ReturnTypeWillChange]
    public function offsetUnset($key)
    {
        throw new \BadMethodCallException(self::class . ' objects are immutable.');
    }
    /**
     * @return string
     */
    public function __toString()
    {
        $value = $this->getValue();
        if (!\is_array($value)) {
            return (string) $value;
        }
        return \sprintf('%s (count=%d)', $this->getType(), \count($value));
    }
    /**
     * Returns a depth limited clone of $this.
     *
     * @param int $maxDepth The max dumped depth level
     *
     * @return static
     */
    public function withMaxDepth($maxDepth)
    {
        $data = clone $this;
        $data->maxDepth = (int) $maxDepth;
        return $data;
    }
    /**
     * Limits the number of elements per depth level.
     *
     * @param int $maxItemsPerDepth The max number of items dumped per depth level
     *
     * @return static
     */
    public function withMaxItemsPerDepth($maxItemsPerDepth)
    {
        $data = clone $this;
        $data->maxItemsPerDepth = (int) $maxItemsPerDepth;
        return $data;
    }
    /**
     * Enables/disables objects' identifiers tracking.
     *
     * @param bool $useRefHandles False to hide global ref. handles
     *
     * @return static
     */
    public function withRefHandles($useRefHandles)
    {
        $data = clone $this;
        $data->useRefHandles = $useRefHandles ? -1 : 0;
        return $data;
    }
    /**
     * @return static
     */
    public function withContext(array $context)
    {
        $data = clone $this;
        $data->context = $context;
        return $data;
    }
    /**
     * Seeks to a specific key in nested data structures.
     *
     * @param string|int $key The key to seek to
     *
     * @return static|null Null if the key is not set
     */
    public function seek($key)
    {
        $item = $this->data[$this->position][$this->key];
        if ($item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) {
            $item = $item->value;
        }
        if (!($item = $this->getStub($item)) instanceof Stub || !$item->position) {
            return null;
        }
        $keys = [$key];
        switch ($item->type) {
            case Stub::TYPE_OBJECT:
                $keys[] = Caster::PREFIX_DYNAMIC . $key;
                $keys[] = Caster::PREFIX_PROTECTED . $key;
                $keys[] = Caster::PREFIX_VIRTUAL . $key;
                $keys[] = "\x00{$item->class}\x00{$key}";
            // no break
            case Stub::TYPE_ARRAY:
            case Stub::TYPE_RESOURCE:
                break;
            default:
                return null;
        }
        $data = null;
        $children = $this->data[$item->position];
        foreach ($keys as $key) {
            if (isset($children[$key]) || \array_key_exists($key, $children)) {
                $data = clone $this;
                $data->key = $key;
                $data->position = $item->position;
                break;
            }
        }
        return $data;
    }
    /**
     * Dumps data with a DumperInterface dumper.
     */
    public function dump(DumperInterface $dumper)
    {
        $refs = [0];
        $cursor = new Cursor();
        if ($cursor->attr = $this->context[SourceContextProvider::class] ?? []) {
            $cursor->attr['if_links'] = \true;
            $cursor->hashType = -1;
            $dumper->dumpScalar($cursor, 'default', '^');
            $cursor->attr = ['if_links' => \true];
            $dumper->dumpScalar($cursor, 'default', ' ');
            $cursor->hashType = 0;
        }
        $this->dumpItem($dumper, $cursor, $refs, $this->data[$this->position][$this->key]);
    }
    /**
     * Depth-first dumping of items.
     *
     * @param mixed $item A Stub object or the original value being dumped
     */
    private function dumpItem(DumperInterface $dumper, Cursor $cursor, array &$refs, $item)
    {
        $cursor->refIndex = 0;
        $cursor->softRefTo = $cursor->softRefHandle = $cursor->softRefCount = 0;
        $cursor->hardRefTo = $cursor->hardRefHandle = $cursor->hardRefCount = 0;
        $firstSeen = \true;
        if (!$item instanceof Stub) {
            $cursor->attr = [];
            $type = \gettype($item);
            if ($item && 'array' === $type) {
                $item = $this->getStub($item);
            }
        } elseif (Stub::TYPE_REF === $item->type) {
            if ($item->handle) {
                if (!isset($refs[$r = $item->handle - (\PHP_INT_MAX >> 1)])) {
                    $cursor->refIndex = $refs[$r] = $cursor->refIndex ?: ++$refs[0];
                } else {
                    $firstSeen = \false;
                }
                $cursor->hardRefTo = $refs[$r];
                $cursor->hardRefHandle = $this->useRefHandles & $item->handle;
                $cursor->hardRefCount = 0 < $item->handle ? $item->refCount : 0;
            }
            $cursor->attr = $item->attr;
            $type = $item->class ?: \gettype($item->value);
            $item = $this->getStub($item->value);
        }
        if ($item instanceof Stub) {
            if ($item->refCount) {
                if (!isset($refs[$r = $item->handle])) {
                    $cursor->refIndex = $refs[$r] = $cursor->refIndex ?: ++$refs[0];
                } else {
                    $firstSeen = \false;
                }
                $cursor->softRefTo = $refs[$r];
            }
            $cursor->softRefHandle = $this->useRefHandles & $item->handle;
            $cursor->softRefCount = $item->refCount;
            $cursor->attr = $item->attr;
            $cut = $item->cut;
            if ($item->position && $firstSeen) {
                $children = $this->data[$item->position];
                if ($cursor->stop) {
                    if ($cut >= 0) {
                        $cut += \count($children);
                    }
                    $children = [];
                }
            } else {
                $children = [];
            }
            switch ($item->type) {
                case Stub::TYPE_STRING:
                    $dumper->dumpString($cursor, $item->value, Stub::STRING_BINARY === $item->class, $cut);
                    break;
                case Stub::TYPE_ARRAY:
                    $item = clone $item;
                    $item->type = $item->class;
                    $item->class = $item->value;
                // no break
                case Stub::TYPE_OBJECT:
                case Stub::TYPE_RESOURCE:
                    $withChildren = $children && $cursor->depth !== $this->maxDepth && $this->maxItemsPerDepth;
                    $dumper->enterHash($cursor, $item->type, $item->class, $withChildren);
                    if ($withChildren) {
                        if ($cursor->skipChildren) {
                            $withChildren = \false;
                            $cut = -1;
                        } else {
                            $cut = $this->dumpChildren($dumper, $cursor, $refs, $children, $cut, $item->type, null !== $item->class);
                        }
                    } elseif ($children && 0 <= $cut) {
                        $cut += \count($children);
                    }
                    $cursor->skipChildren = \false;
                    $dumper->leaveHash($cursor, $item->type, $item->class, $withChildren, $cut);
                    break;
                default:
                    throw new \RuntimeException(\sprintf('Unexpected Stub type: "%s".', $item->type));
            }
        } elseif ('array' === $type) {
            $dumper->enterHash($cursor, Cursor::HASH_INDEXED, 0, \false);
            $dumper->leaveHash($cursor, Cursor::HASH_INDEXED, 0, \false, 0);
        } elseif ('string' === $type) {
            $dumper->dumpString($cursor, $item, \false, 0);
        } else {
            $dumper->dumpScalar($cursor, $type, $item);
        }
    }
    /**
     * Dumps children of hash structures.
     *
     * @return int The final number of removed items
     */
    private function dumpChildren(DumperInterface $dumper, Cursor $parentCursor, array &$refs, array $children, int $hashCut, int $hashType, bool $dumpKeys) : int
    {
        $cursor = clone $parentCursor;
        ++$cursor->depth;
        $cursor->hashType = $hashType;
        $cursor->hashIndex = 0;
        $cursor->hashLength = \count($children);
        $cursor->hashCut = $hashCut;
        foreach ($children as $key => $child) {
            $cursor->hashKeyIsBinary = isset($key[0]) && !\preg_match('//u', $key);
            $cursor->hashKey = $dumpKeys ? $key : null;
            $this->dumpItem($dumper, $cursor, $refs, $child);
            if (++$cursor->hashIndex === $this->maxItemsPerDepth || $cursor->stop) {
                $parentCursor->stop = \true;
                return $hashCut >= 0 ? $hashCut + $cursor->hashLength - $cursor->hashIndex : $hashCut;
            }
        }
        return $hashCut;
    }
    private function getStub($item)
    {
        if (!$item || !\is_array($item)) {
            return $item;
        }
        $stub = new Stub();
        $stub->type = Stub::TYPE_ARRAY;
        foreach ($item as $stub->class => $stub->position) {
        }
        if (isset($item[0])) {
            $stub->cut = $item[0];
        }
        $stub->value = $stub->cut + ($stub->position ? \count($this->data[$stub->position]) : 0);
        return $stub;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Command\Descriptor;

use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CivixPhar\Symfony\Component\VarDumper\Cloner\Data;
use CivixPhar\Symfony\Component\VarDumper\Dumper\HtmlDumper;
/**
 * Describe collected data clones for html output.
 *
 * @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
 *
 * @final
 */
class HtmlDescriptor implements DumpDescriptorInterface
{
    private $dumper;
    private $initialized = \false;
    public function __construct(HtmlDumper $dumper)
    {
        $this->dumper = $dumper;
    }
    public function describe(OutputInterface $output, Data $data, array $context, int $clientId) : void
    {
        if (!$this->initialized) {
            $styles = \file_get_contents(__DIR__ . '/../../Resources/css/htmlDescriptor.css');
            $scripts = \file_get_contents(__DIR__ . '/../../Resources/js/htmlDescriptor.js');
            $output->writeln("<style>{$styles}</style><script>{$scripts}</script>");
            $this->initialized = \true;
        }
        $title = '-';
        if (isset($context['request'])) {
            $request = $context['request'];
            $controller = "<span class='dumped-tag'>{$this->dumper->dump($request['controller'], \true, ['maxDepth' => 0])}</span>";
            $title = \sprintf('<code>%s</code> <a href="%s">%s</a>', $request['method'], $uri = $request['uri'], $uri);
            $dedupIdentifier = $request['identifier'];
        } elseif (isset($context['cli'])) {
            $title = '<code>$ </code>' . $context['cli']['command_line'];
            $dedupIdentifier = $context['cli']['identifier'];
        } else {
            $dedupIdentifier = \uniqid('', \true);
        }
        $sourceDescription = '';
        if (isset($context['source'])) {
            $source = $context['source'];
            $projectDir = $source['project_dir'] ?? null;
            $sourceDescription = \sprintf('%s on line %d', $source['name'], $source['line']);
            if (isset($source['file_link'])) {
                $sourceDescription = \sprintf('<a href="%s">%s</a>', $source['file_link'], $sourceDescription);
            }
        }
        $isoDate = $this->extractDate($context, 'c');
        $tags = \array_filter(['controller' => $controller ?? null, 'project dir' => $projectDir ?? null]);
        $output->writeln(<<<HTML
<article data-dedup-id="{$dedupIdentifier}">
    <header>
        <div class="row">
            <h2 class="col">{$title}</h2>
            <time class="col text-small" title="{$isoDate}" datetime="{$isoDate}">
                {$this->extractDate($context)}
            </time>
        </div>
        {$this->renderTags($tags)}
    </header>
    <section class="body">
        <p class="text-small">
            {$sourceDescription}
        </p>
        {$this->dumper->dump($data, \true)}
    </section>
</article>
HTML
);
    }
    private function extractDate(array $context, string $format = 'r') : string
    {
        return \date($format, (int) $context['timestamp']);
    }
    private function renderTags(array $tags) : string
    {
        if (!$tags) {
            return '';
        }
        $renderedTags = '';
        foreach ($tags as $key => $value) {
            $renderedTags .= \sprintf('<li><span class="badge">%s</span>%s</li>', $key, $value);
        }
        return <<<HTML
<div class="row">
    <ul class="tags">
        {$renderedTags}
    </ul>
</div>
HTML;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Command\Descriptor;

use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CivixPhar\Symfony\Component\VarDumper\Cloner\Data;
/**
 * @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
 */
interface DumpDescriptorInterface
{
    public function describe(OutputInterface $output, Data $data, array $context, int $clientId) : void;
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Command\Descriptor;

use CivixPhar\Symfony\Component\Console\Formatter\OutputFormatterStyle;
use CivixPhar\Symfony\Component\Console\Input\ArrayInput;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CivixPhar\Symfony\Component\Console\Style\SymfonyStyle;
use CivixPhar\Symfony\Component\VarDumper\Cloner\Data;
use CivixPhar\Symfony\Component\VarDumper\Dumper\CliDumper;
/**
 * Describe collected data clones for cli output.
 *
 * @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
 *
 * @final
 */
class CliDescriptor implements DumpDescriptorInterface
{
    private $dumper;
    private $lastIdentifier;
    private $supportsHref;
    public function __construct(CliDumper $dumper)
    {
        $this->dumper = $dumper;
        $this->supportsHref = \method_exists(OutputFormatterStyle::class, 'setHref');
    }
    public function describe(OutputInterface $output, Data $data, array $context, int $clientId) : void
    {
        $io = $output instanceof SymfonyStyle ? $output : new SymfonyStyle(new ArrayInput([]), $output);
        $this->dumper->setColors($output->isDecorated());
        $rows = [['date', \date('r', (int) $context['timestamp'])]];
        $lastIdentifier = $this->lastIdentifier;
        $this->lastIdentifier = $clientId;
        $section = "Received from client #{$clientId}";
        if (isset($context['request'])) {
            $request = $context['request'];
            $this->lastIdentifier = $request['identifier'];
            $section = \sprintf('%s %s', $request['method'], $request['uri']);
            if ($controller = $request['controller']) {
                $rows[] = ['controller', \rtrim($this->dumper->dump($controller, \true), "\n")];
            }
        } elseif (isset($context['cli'])) {
            $this->lastIdentifier = $context['cli']['identifier'];
            $section = '$ ' . $context['cli']['command_line'];
        }
        if ($this->lastIdentifier !== $lastIdentifier) {
            $io->section($section);
        }
        if (isset($context['source'])) {
            $source = $context['source'];
            $sourceInfo = \sprintf('%s on line %d', $source['name'], $source['line']);
            $fileLink = $source['file_link'] ?? null;
            if ($this->supportsHref && $fileLink) {
                $sourceInfo = \sprintf('<href=%s>%s</>', $fileLink, $sourceInfo);
            }
            $rows[] = ['source', $sourceInfo];
            $file = $source['file_relative'] ?? $source['file'];
            $rows[] = ['file', $file];
        }
        $io->table([], $rows);
        if (!$this->supportsHref && isset($fileLink)) {
            $io->writeln(['<info>Open source in your IDE/browser:</info>', $fileLink]);
            $io->newLine();
        }
        $this->dumper->dump($data);
        $io->newLine();
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Command;

use CivixPhar\Symfony\Component\Console\Command\Command;
use CivixPhar\Symfony\Component\Console\Exception\InvalidArgumentException;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CivixPhar\Symfony\Component\Console\Style\SymfonyStyle;
use CivixPhar\Symfony\Component\VarDumper\Cloner\Data;
use CivixPhar\Symfony\Component\VarDumper\Command\Descriptor\CliDescriptor;
use CivixPhar\Symfony\Component\VarDumper\Command\Descriptor\DumpDescriptorInterface;
use CivixPhar\Symfony\Component\VarDumper\Command\Descriptor\HtmlDescriptor;
use CivixPhar\Symfony\Component\VarDumper\Dumper\CliDumper;
use CivixPhar\Symfony\Component\VarDumper\Dumper\HtmlDumper;
use CivixPhar\Symfony\Component\VarDumper\Server\DumpServer;
/**
 * Starts a dump server to collect and output dumps on a single place with multiple formats support.
 *
 * @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
 *
 * @final
 */
class ServerDumpCommand extends Command
{
    protected static $defaultName = 'server:dump';
    private $server;
    /** @var DumpDescriptorInterface[] */
    private $descriptors;
    public function __construct(DumpServer $server, array $descriptors = [])
    {
        $this->server = $server;
        $this->descriptors = $descriptors + ['cli' => new CliDescriptor(new CliDumper()), 'html' => new HtmlDescriptor(new HtmlDumper())];
        parent::__construct();
    }
    protected function configure()
    {
        $availableFormats = \implode(', ', \array_keys($this->descriptors));
        $this->addOption('format', null, InputOption::VALUE_REQUIRED, \sprintf('The output format (%s)', $availableFormats), 'cli')->setDescription('Start a dump server that collects and displays dumps in a single place')->setHelp(<<<'EOF'
<info>%command.name%</info> starts a dump server that collects and displays
dumps in a single place for debugging you application:

  <info>php %command.full_name%</info>

You can consult dumped data in HTML format in your browser by providing the <comment>--format=html</comment> option
and redirecting the output to a file:

  <info>php %command.full_name% --format="html" > dump.html</info>

EOF
);
    }
    protected function execute(InputInterface $input, OutputInterface $output) : int
    {
        $io = new SymfonyStyle($input, $output);
        $format = $input->getOption('format');
        if (!($descriptor = $this->descriptors[$format] ?? null)) {
            throw new InvalidArgumentException(\sprintf('Unsupported format "%s".', $format));
        }
        $errorIo = $io->getErrorStyle();
        $errorIo->title('Symfony Var Dumper Server');
        $this->server->start();
        $errorIo->success(\sprintf('Server listening on %s', $this->server->getHost()));
        $errorIo->comment('Quit the server with CONTROL-C.');
        $this->server->listen(function (Data $data, array $context, int $clientId) use($descriptor, $io) {
            $descriptor->describe($io, $data, $context, $clientId);
        });
        return 0;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Server;

use CivixPhar\Psr\Log\LoggerInterface;
use CivixPhar\Symfony\Component\VarDumper\Cloner\Data;
use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * A server collecting Data clones sent by a ServerDumper.
 *
 * @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
 *
 * @final
 */
class DumpServer
{
    private $host;
    private $socket;
    private $logger;
    public function __construct(string $host, LoggerInterface $logger = null)
    {
        if (!\str_contains($host, '://')) {
            $host = 'tcp://' . $host;
        }
        $this->host = $host;
        $this->logger = $logger;
    }
    public function start() : void
    {
        if (!($this->socket = \stream_socket_server($this->host, $errno, $errstr))) {
            throw new \RuntimeException(\sprintf('Server start failed on "%s": ', $this->host) . $errstr . ' ' . $errno);
        }
    }
    public function listen(callable $callback) : void
    {
        if (null === $this->socket) {
            $this->start();
        }
        foreach ($this->getMessages() as $clientId => $message) {
            $payload = @\unserialize(\base64_decode($message), ['allowed_classes' => [Data::class, Stub::class]]);
            // Impossible to decode the message, give up.
            if (\false === $payload) {
                if ($this->logger) {
                    $this->logger->warning('Unable to decode a message from {clientId} client.', ['clientId' => $clientId]);
                }
                continue;
            }
            if (!\is_array($payload) || \count($payload) < 2 || !$payload[0] instanceof Data || !\is_array($payload[1])) {
                if ($this->logger) {
                    $this->logger->warning('Invalid payload from {clientId} client. Expected an array of two elements (Data $data, array $context)', ['clientId' => $clientId]);
                }
                continue;
            }
            [$data, $context] = $payload;
            $callback($data, $context, $clientId);
        }
    }
    public function getHost() : string
    {
        return $this->host;
    }
    private function getMessages() : iterable
    {
        $sockets = [(int) $this->socket => $this->socket];
        $write = [];
        while (\true) {
            $read = $sockets;
            \stream_select($read, $write, $write, null);
            foreach ($read as $stream) {
                if ($this->socket === $stream) {
                    $stream = \stream_socket_accept($this->socket);
                    $sockets[(int) $stream] = $stream;
                } elseif (\feof($stream)) {
                    unset($sockets[(int) $stream]);
                    \fclose($stream);
                } else {
                    (yield (int) $stream => \fgets($stream));
                }
            }
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Server;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Data;
use CivixPhar\Symfony\Component\VarDumper\Dumper\ContextProvider\ContextProviderInterface;
/**
 * Forwards serialized Data clones to a server.
 *
 * @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
 */
class Connection
{
    private $host;
    private $contextProviders;
    private $socket;
    /**
     * @param string                     $host             The server host
     * @param ContextProviderInterface[] $contextProviders Context providers indexed by context name
     */
    public function __construct(string $host, array $contextProviders = [])
    {
        if (!\str_contains($host, '://')) {
            $host = 'tcp://' . $host;
        }
        $this->host = $host;
        $this->contextProviders = $contextProviders;
    }
    public function getContextProviders() : array
    {
        return $this->contextProviders;
    }
    public function write(Data $data) : bool
    {
        $socketIsFresh = !$this->socket;
        if (!($this->socket = $this->socket ?: $this->createSocket())) {
            return \false;
        }
        $context = ['timestamp' => \microtime(\true)];
        foreach ($this->contextProviders as $name => $provider) {
            $context[$name] = $provider->getContext();
        }
        $context = \array_filter($context);
        $encodedPayload = \base64_encode(\serialize([$data, $context])) . "\n";
        \set_error_handler([self::class, 'nullErrorHandler']);
        try {
            if (-1 !== \stream_socket_sendto($this->socket, $encodedPayload)) {
                return \true;
            }
            if (!$socketIsFresh) {
                \stream_socket_shutdown($this->socket, \STREAM_SHUT_RDWR);
                \fclose($this->socket);
                $this->socket = $this->createSocket();
            }
            if (-1 !== \stream_socket_sendto($this->socket, $encodedPayload)) {
                return \true;
            }
        } finally {
            \restore_error_handler();
        }
        return \false;
    }
    private static function nullErrorHandler(int $t, string $m)
    {
        // no-op
    }
    private function createSocket()
    {
        \set_error_handler([self::class, 'nullErrorHandler']);
        try {
            return \stream_socket_client($this->host, $errno, $errstr, 3, \STREAM_CLIENT_CONNECT | \STREAM_CLIENT_ASYNC_CONNECT);
        } finally {
            \restore_error_handler();
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Dumper;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Cursor;
use CivixPhar\Symfony\Component\VarDumper\Cloner\Data;
/**
 * HtmlDumper dumps variables as HTML.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
class HtmlDumper extends CliDumper
{
    public static $defaultOutput = 'php://output';
    protected static $themes = ['dark' => ['default' => 'background-color:#18171B; color:#FF8400; line-height:1.2em; font:12px Menlo, Monaco, Consolas, monospace; word-wrap: break-word; white-space: pre-wrap; position:relative; z-index:99999; word-break: break-all', 'num' => 'font-weight:bold; color:#1299DA', 'const' => 'font-weight:bold', 'str' => 'font-weight:bold; color:#56DB3A', 'note' => 'color:#1299DA', 'ref' => 'color:#A0A0A0', 'public' => 'color:#FFFFFF', 'protected' => 'color:#FFFFFF', 'private' => 'color:#FFFFFF', 'meta' => 'color:#B729D9', 'key' => 'color:#56DB3A', 'index' => 'color:#1299DA', 'ellipsis' => 'color:#FF8400', 'ns' => 'user-select:none;'], 'light' => ['default' => 'background:none; color:#CC7832; line-height:1.2em; font:12px Menlo, Monaco, Consolas, monospace; word-wrap: break-word; white-space: pre-wrap; position:relative; z-index:99999; word-break: break-all', 'num' => 'font-weight:bold; color:#1299DA', 'const' => 'font-weight:bold', 'str' => 'font-weight:bold; color:#629755;', 'note' => 'color:#6897BB', 'ref' => 'color:#6E6E6E', 'public' => 'color:#262626', 'protected' => 'color:#262626', 'private' => 'color:#262626', 'meta' => 'color:#B729D9', 'key' => 'color:#789339', 'index' => 'color:#1299DA', 'ellipsis' => 'color:#CC7832', 'ns' => 'user-select:none;']];
    protected $dumpHeader;
    protected $dumpPrefix = '<pre class=sf-dump id=%s data-indent-pad="%s">';
    protected $dumpSuffix = '</pre><script>Sfdump(%s)</script>';
    protected $dumpId = 'sf-dump';
    protected $colors = \true;
    protected $headerIsDumped = \false;
    protected $lastDepth = -1;
    protected $styles;
    private $displayOptions = ['maxDepth' => 1, 'maxStringLength' => 160, 'fileLinkFormat' => null];
    private $extraDisplayOptions = [];
    /**
     * {@inheritdoc}
     */
    public function __construct($output = null, string $charset = null, int $flags = 0)
    {
        AbstractDumper::__construct($output, $charset, $flags);
        $this->dumpId = 'sf-dump-' . \mt_rand();
        $this->displayOptions['fileLinkFormat'] = \ini_get('xdebug.file_link_format') ?: \get_cfg_var('xdebug.file_link_format');
        $this->styles = static::$themes['dark'] ?? self::$themes['dark'];
    }
    /**
     * {@inheritdoc}
     */
    public function setStyles(array $styles)
    {
        $this->headerIsDumped = \false;
        $this->styles = $styles + $this->styles;
    }
    public function setTheme(string $themeName)
    {
        if (!isset(static::$themes[$themeName])) {
            throw new \InvalidArgumentException(\sprintf('Theme "%s" does not exist in class "%s".', $themeName, static::class));
        }
        $this->setStyles(static::$themes[$themeName]);
    }
    /**
     * Configures display options.
     *
     * @param array $displayOptions A map of display options to customize the behavior
     */
    public function setDisplayOptions(array $displayOptions)
    {
        $this->headerIsDumped = \false;
        $this->displayOptions = $displayOptions + $this->displayOptions;
    }
    /**
     * Sets an HTML header that will be dumped once in the output stream.
     *
     * @param string $header An HTML string
     */
    public function setDumpHeader($header)
    {
        $this->dumpHeader = $header;
    }
    /**
     * Sets an HTML prefix and suffix that will encapse every single dump.
     *
     * @param string $prefix The prepended HTML string
     * @param string $suffix The appended HTML string
     */
    public function setDumpBoundaries($prefix, $suffix)
    {
        $this->dumpPrefix = $prefix;
        $this->dumpSuffix = $suffix;
    }
    /**
     * {@inheritdoc}
     */
    public function dump(Data $data, $output = null, array $extraDisplayOptions = [])
    {
        $this->extraDisplayOptions = $extraDisplayOptions;
        $result = parent::dump($data, $output);
        $this->dumpId = 'sf-dump-' . \mt_rand();
        return $result;
    }
    /**
     * Dumps the HTML header.
     */
    protected function getDumpHeader()
    {
        $this->headerIsDumped = $this->outputStream ?? $this->lineDumper;
        if (null !== $this->dumpHeader) {
            return $this->dumpHeader;
        }
        $line = \str_replace('{$options}', \json_encode($this->displayOptions, \JSON_FORCE_OBJECT), <<<'EOHTML'
<script>
Sfdump = window.Sfdump || (function (doc) {

var refStyle = doc.createElement('style'),
    rxEsc = /([.*+?^${}()|\[\]\/\\])/g,
    idRx = /\bsf-dump-\d+-ref[012]\w+\b/,
    keyHint = 0 <= navigator.platform.toUpperCase().indexOf('MAC') ? 'Cmd' : 'Ctrl',
    addEventListener = function (e, n, cb) {
        e.addEventListener(n, cb, false);
    };

(doc.documentElement.firstElementChild || doc.documentElement.children[0]).appendChild(refStyle);

if (!doc.addEventListener) {
    addEventListener = function (element, eventName, callback) {
        element.attachEvent('on' + eventName, function (e) {
            e.preventDefault = function () {e.returnValue = false;};
            e.target = e.srcElement;
            callback(e);
        });
    };
}

function toggle(a, recursive) {
    var s = a.nextSibling || {}, oldClass = s.className, arrow, newClass;

    if (/\bsf-dump-compact\b/.test(oldClass)) {
        arrow = 'â–¼';
        newClass = 'sf-dump-expanded';
    } else if (/\bsf-dump-expanded\b/.test(oldClass)) {
        arrow = 'â–¶';
        newClass = 'sf-dump-compact';
    } else {
        return false;
    }

    if (doc.createEvent && s.dispatchEvent) {
        var event = doc.createEvent('Event');
        event.initEvent('sf-dump-expanded' === newClass ? 'sfbeforedumpexpand' : 'sfbeforedumpcollapse', true, false);

        s.dispatchEvent(event);
    }

    a.lastChild.innerHTML = arrow;
    s.className = s.className.replace(/\bsf-dump-(compact|expanded)\b/, newClass);

    if (recursive) {
        try {
            a = s.querySelectorAll('.'+oldClass);
            for (s = 0; s < a.length; ++s) {
                if (-1 == a[s].className.indexOf(newClass)) {
                    a[s].className = newClass;
                    a[s].previousSibling.lastChild.innerHTML = arrow;
                }
            }
        } catch (e) {
        }
    }

    return true;
};

function collapse(a, recursive) {
    var s = a.nextSibling || {}, oldClass = s.className;

    if (/\bsf-dump-expanded\b/.test(oldClass)) {
        toggle(a, recursive);

        return true;
    }

    return false;
};

function expand(a, recursive) {
    var s = a.nextSibling || {}, oldClass = s.className;

    if (/\bsf-dump-compact\b/.test(oldClass)) {
        toggle(a, recursive);

        return true;
    }

    return false;
};

function collapseAll(root) {
    var a = root.querySelector('a.sf-dump-toggle');
    if (a) {
        collapse(a, true);
        expand(a);

        return true;
    }

    return false;
}

function reveal(node) {
    var previous, parents = [];

    while ((node = node.parentNode || {}) && (previous = node.previousSibling) && 'A' === previous.tagName) {
        parents.push(previous);
    }

    if (0 !== parents.length) {
        parents.forEach(function (parent) {
            expand(parent);
        });

        return true;
    }

    return false;
}

function highlight(root, activeNode, nodes) {
    resetHighlightedNodes(root);

    Array.from(nodes||[]).forEach(function (node) {
        if (!/\bsf-dump-highlight\b/.test(node.className)) {
            node.className = node.className + ' sf-dump-highlight';
        }
    });

    if (!/\bsf-dump-highlight-active\b/.test(activeNode.className)) {
        activeNode.className = activeNode.className + ' sf-dump-highlight-active';
    }
}

function resetHighlightedNodes(root) {
    Array.from(root.querySelectorAll('.sf-dump-str, .sf-dump-key, .sf-dump-public, .sf-dump-protected, .sf-dump-private')).forEach(function (strNode) {
        strNode.className = strNode.className.replace(/\bsf-dump-highlight\b/, '');
        strNode.className = strNode.className.replace(/\bsf-dump-highlight-active\b/, '');
    });
}

return function (root, x) {
    root = doc.getElementById(root);

    var indentRx = new RegExp('^('+(root.getAttribute('data-indent-pad') || '  ').replace(rxEsc, '\\$1')+')+', 'm'),
        options = {$options},
        elt = root.getElementsByTagName('A'),
        len = elt.length,
        i = 0, s, h,
        t = [];

    while (i < len) t.push(elt[i++]);

    for (i in x) {
        options[i] = x[i];
    }

    function a(e, f) {
        addEventListener(root, e, function (e, n) {
            if ('A' == e.target.tagName) {
                f(e.target, e);
            } else if ('A' == e.target.parentNode.tagName) {
                f(e.target.parentNode, e);
            } else {
                n = /\bsf-dump-ellipsis\b/.test(e.target.className) ? e.target.parentNode : e.target;

                if ((n = n.nextElementSibling) && 'A' == n.tagName) {
                    if (!/\bsf-dump-toggle\b/.test(n.className)) {
                        n = n.nextElementSibling || n;
                    }

                    f(n, e, true);
                }
            }
        });
    };
    function isCtrlKey(e) {
        return e.ctrlKey || e.metaKey;
    }
    function xpathString(str) {
        var parts = str.match(/[^'"]+|['"]/g).map(function (part) {
            if ("'" == part)  {
                return '"\'"';
            }
            if ('"' == part) {
                return "'\"'";
            }

            return "'" + part + "'";
        });

        return "concat(" + parts.join(",") + ", '')";
    }
    function xpathHasClass(className) {
        return "contains(concat(' ', normalize-space(@class), ' '), ' " + className +" ')";
    }
    addEventListener(root, 'mouseover', function (e) {
        if ('' != refStyle.innerHTML) {
            refStyle.innerHTML = '';
        }
    });
    a('mouseover', function (a, e, c) {
        if (c) {
            e.target.style.cursor = "pointer";
        } else if (a = idRx.exec(a.className)) {
            try {
                refStyle.innerHTML = 'pre.sf-dump .'+a[0]+'{background-color: #B729D9; color: #FFF !important; border-radius: 2px}';
            } catch (e) {
            }
        }
    });
    a('click', function (a, e, c) {
        if (/\bsf-dump-toggle\b/.test(a.className)) {
            e.preventDefault();
            if (!toggle(a, isCtrlKey(e))) {
                var r = doc.getElementById(a.getAttribute('href').substr(1)),
                    s = r.previousSibling,
                    f = r.parentNode,
                    t = a.parentNode;
                t.replaceChild(r, a);
                f.replaceChild(a, s);
                t.insertBefore(s, r);
                f = f.firstChild.nodeValue.match(indentRx);
                t = t.firstChild.nodeValue.match(indentRx);
                if (f && t && f[0] !== t[0]) {
                    r.innerHTML = r.innerHTML.replace(new RegExp('^'+f[0].replace(rxEsc, '\\$1'), 'mg'), t[0]);
                }
                if (/\bsf-dump-compact\b/.test(r.className)) {
                    toggle(s, isCtrlKey(e));
                }
            }

            if (c) {
            } else if (doc.getSelection) {
                try {
                    doc.getSelection().removeAllRanges();
                } catch (e) {
                    doc.getSelection().empty();
                }
            } else {
                doc.selection.empty();
            }
        } else if (/\bsf-dump-str-toggle\b/.test(a.className)) {
            e.preventDefault();
            e = a.parentNode.parentNode;
            e.className = e.className.replace(/\bsf-dump-str-(expand|collapse)\b/, a.parentNode.className);
        }
    });

    elt = root.getElementsByTagName('SAMP');
    len = elt.length;
    i = 0;

    while (i < len) t.push(elt[i++]);
    len = t.length;

    for (i = 0; i < len; ++i) {
        elt = t[i];
        if ('SAMP' == elt.tagName) {
            a = elt.previousSibling || {};
            if ('A' != a.tagName) {
                a = doc.createElement('A');
                a.className = 'sf-dump-ref';
                elt.parentNode.insertBefore(a, elt);
            } else {
                a.innerHTML += ' ';
            }
            a.title = (a.title ? a.title+'\n[' : '[')+keyHint+'+click] Expand all children';
            a.innerHTML += '<span>â–¼</span>';
            a.className += ' sf-dump-toggle';

            x = 1;
            if ('sf-dump' != elt.parentNode.className) {
                x += elt.parentNode.getAttribute('data-depth')/1;
            }
            elt.setAttribute('data-depth', x);
            var className = elt.className;
            elt.className = 'sf-dump-expanded';
            if (className ? 'sf-dump-expanded' !== className : (x > options.maxDepth)) {
                toggle(a);
            }
        } else if (/\bsf-dump-ref\b/.test(elt.className) && (a = elt.getAttribute('href'))) {
            a = a.substr(1);
            elt.className += ' '+a;

            if (/[\[{]$/.test(elt.previousSibling.nodeValue)) {
                a = a != elt.nextSibling.id && doc.getElementById(a);
                try {
                    s = a.nextSibling;
                    elt.appendChild(a);
                    s.parentNode.insertBefore(a, s);
                    if (/^[@#]/.test(elt.innerHTML)) {
                        elt.innerHTML += ' <span>â–¶</span>';
                    } else {
                        elt.innerHTML = '<span>â–¶</span>';
                        elt.className = 'sf-dump-ref';
                    }
                    elt.className += ' sf-dump-toggle';
                } catch (e) {
                    if ('&' == elt.innerHTML.charAt(0)) {
                        elt.innerHTML = 'â€¦';
                        elt.className = 'sf-dump-ref';
                    }
                }
            }
        }
    }

    if (doc.evaluate && Array.from && root.children.length > 1) {
        root.setAttribute('tabindex', 0);

        SearchState = function () {
            this.nodes = [];
            this.idx = 0;
        };
        SearchState.prototype = {
            next: function () {
                if (this.isEmpty()) {
                    return this.current();
                }
                this.idx = this.idx < (this.nodes.length - 1) ? this.idx + 1 : 0;

                return this.current();
            },
            previous: function () {
                if (this.isEmpty()) {
                    return this.current();
                }
                this.idx = this.idx > 0 ? this.idx - 1 : (this.nodes.length - 1);

                return this.current();
            },
            isEmpty: function () {
                return 0 === this.count();
            },
            current: function () {
                if (this.isEmpty()) {
                    return null;
                }
                return this.nodes[this.idx];
            },
            reset: function () {
                this.nodes = [];
                this.idx = 0;
            },
            count: function () {
                return this.nodes.length;
            },
        };

        function showCurrent(state)
        {
            var currentNode = state.current(), currentRect, searchRect;
            if (currentNode) {
                reveal(currentNode);
                highlight(root, currentNode, state.nodes);
                if ('scrollIntoView' in currentNode) {
                    currentNode.scrollIntoView(true);
                    currentRect = currentNode.getBoundingClientRect();
                    searchRect = search.getBoundingClientRect();
                    if (currentRect.top < (searchRect.top + searchRect.height)) {
                        window.scrollBy(0, -(searchRect.top + searchRect.height + 5));
                    }
                }
            }
            counter.textContent = (state.isEmpty() ? 0 : state.idx + 1) + ' of ' + state.count();
        }

        var search = doc.createElement('div');
        search.className = 'sf-dump-search-wrapper sf-dump-search-hidden';
        search.innerHTML = '
            <input type="text" class="sf-dump-search-input">
            <span class="sf-dump-search-count">0 of 0<\/span>
            <button type="button" class="sf-dump-search-input-previous" tabindex="-1">
                <svg viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1683 1331l-166 165q-19 19-45 19t-45-19L896 965l-531 531q-19 19-45 19t-45-19l-166-165q-19-19-19-45.5t19-45.5l742-741q19-19 45-19t45 19l742 741q19 19 19 45.5t-19 45.5z"\/><\/svg>
            <\/button>
            <button type="button" class="sf-dump-search-input-next" tabindex="-1">
                <svg viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1683 808l-742 741q-19 19-45 19t-45-19L109 808q-19-19-19-45.5t19-45.5l166-165q19-19 45-19t45 19l531 531 531-531q19-19 45-19t45 19l166 165q19 19 19 45.5t-19 45.5z"\/><\/svg>
            <\/button>
        ';
        root.insertBefore(search, root.firstChild);

        var state = new SearchState();
        var searchInput = search.querySelector('.sf-dump-search-input');
        var counter = search.querySelector('.sf-dump-search-count');
        var searchInputTimer = 0;
        var previousSearchQuery = '';

        addEventListener(searchInput, 'keyup', function (e) {
            var searchQuery = e.target.value;
            /* Don't perform anything if the pressed key didn't change the query */
            if (searchQuery === previousSearchQuery) {
                return;
            }
            previousSearchQuery = searchQuery;
            clearTimeout(searchInputTimer);
            searchInputTimer = setTimeout(function () {
                state.reset();
                collapseAll(root);
                resetHighlightedNodes(root);
                if ('' === searchQuery) {
                    counter.textContent = '0 of 0';

                    return;
                }

                var classMatches = [
                    "sf-dump-str",
                    "sf-dump-key",
                    "sf-dump-public",
                    "sf-dump-protected",
                    "sf-dump-private",
                ].map(xpathHasClass).join(' or ');

                var xpathResult = doc.evaluate('.//span[' + classMatches + '][contains(translate(child::text(), ' + xpathString(searchQuery.toUpperCase()) + ', ' + xpathString(searchQuery.toLowerCase()) + '), ' + xpathString(searchQuery.toLowerCase()) + ')]', root, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);

                while (node = xpathResult.iterateNext()) state.nodes.push(node);

                showCurrent(state);
            }, 400);
        });

        Array.from(search.querySelectorAll('.sf-dump-search-input-next, .sf-dump-search-input-previous')).forEach(function (btn) {
            addEventListener(btn, 'click', function (e) {
                e.preventDefault();
                -1 !== e.target.className.indexOf('next') ? state.next() : state.previous();
                searchInput.focus();
                collapseAll(root);
                showCurrent(state);
            })
        });

        addEventListener(root, 'keydown', function (e) {
            var isSearchActive = !/\bsf-dump-search-hidden\b/.test(search.className);
            if ((114 === e.keyCode && !isSearchActive) || (isCtrlKey(e) && 70 === e.keyCode)) {
                /* F3 or CMD/CTRL + F */
                if (70 === e.keyCode && document.activeElement === searchInput) {
                   /*
                    * If CMD/CTRL + F is hit while having focus on search input,
                    * the user probably meant to trigger browser search instead.
                    * Let the browser execute its behavior:
                    */
                    return;
                }

                e.preventDefault();
                search.className = search.className.replace(/\bsf-dump-search-hidden\b/, '');
                searchInput.focus();
            } else if (isSearchActive) {
                if (27 === e.keyCode) {
                    /* ESC key */
                    search.className += ' sf-dump-search-hidden';
                    e.preventDefault();
                    resetHighlightedNodes(root);
                    searchInput.value = '';
                } else if (
                    (isCtrlKey(e) && 71 === e.keyCode) /* CMD/CTRL + G */
                    || 13 === e.keyCode /* Enter */
                    || 114 === e.keyCode /* F3 */
                ) {
                    e.preventDefault();
                    e.shiftKey ? state.previous() : state.next();
                    collapseAll(root);
                    showCurrent(state);
                }
            }
        });
    }

    if (0 >= options.maxStringLength) {
        return;
    }
    try {
        elt = root.querySelectorAll('.sf-dump-str');
        len = elt.length;
        i = 0;
        t = [];

        while (i < len) t.push(elt[i++]);
        len = t.length;

        for (i = 0; i < len; ++i) {
            elt = t[i];
            s = elt.innerText || elt.textContent;
            x = s.length - options.maxStringLength;
            if (0 < x) {
                h = elt.innerHTML;
                elt[elt.innerText ? 'innerText' : 'textContent'] = s.substring(0, options.maxStringLength);
                elt.className += ' sf-dump-str-collapse';
                elt.innerHTML = '<span class=sf-dump-str-collapse>'+h+'<a class="sf-dump-ref sf-dump-str-toggle" title="Collapse"> â—€</a></span>'+
                    '<span class=sf-dump-str-expand>'+elt.innerHTML+'<a class="sf-dump-ref sf-dump-str-toggle" title="'+x+' remaining characters"> â–¶</a></span>';
            }
        }
    } catch (e) {
    }
};

})(document);
</script><style>
pre.sf-dump {
    display: block;
    white-space: pre;
    padding: 5px;
    overflow: initial !important;
}
pre.sf-dump:after {
   content: "";
   visibility: hidden;
   display: block;
   height: 0;
   clear: both;
}
pre.sf-dump span {
    display: inline;
}
pre.sf-dump .sf-dump-compact {
    display: none;
}
pre.sf-dump a {
    text-decoration: none;
    cursor: pointer;
    border: 0;
    outline: none;
    color: inherit;
}
pre.sf-dump img {
    max-width: 50em;
    max-height: 50em;
    margin: .5em 0 0 0;
    padding: 0;
    background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAAHUlEQVQY02O8zAABilCaiQEN0EeA8QuUcX9g3QEAAjcC5piyhyEAAAAASUVORK5CYII=) #D3D3D3;
}
pre.sf-dump .sf-dump-ellipsis {
    display: inline-block;
    overflow: visible;
    text-overflow: ellipsis;
    max-width: 5em;
    white-space: nowrap;
    overflow: hidden;
    vertical-align: top;
}
pre.sf-dump .sf-dump-ellipsis+.sf-dump-ellipsis {
    max-width: none;
}
pre.sf-dump code {
    display:inline;
    padding:0;
    background:none;
}
.sf-dump-str-collapse .sf-dump-str-collapse {
    display: none;
}
.sf-dump-str-expand .sf-dump-str-expand {
    display: none;
}
.sf-dump-public.sf-dump-highlight,
.sf-dump-protected.sf-dump-highlight,
.sf-dump-private.sf-dump-highlight,
.sf-dump-str.sf-dump-highlight,
.sf-dump-key.sf-dump-highlight {
    background: rgba(111, 172, 204, 0.3);
    border: 1px solid #7DA0B1;
    border-radius: 3px;
}
.sf-dump-public.sf-dump-highlight-active,
.sf-dump-protected.sf-dump-highlight-active,
.sf-dump-private.sf-dump-highlight-active,
.sf-dump-str.sf-dump-highlight-active,
.sf-dump-key.sf-dump-highlight-active {
    background: rgba(253, 175, 0, 0.4);
    border: 1px solid #ffa500;
    border-radius: 3px;
}
pre.sf-dump .sf-dump-search-hidden {
    display: none !important;
}
pre.sf-dump .sf-dump-search-wrapper {
    font-size: 0;
    white-space: nowrap;
    margin-bottom: 5px;
    display: flex;
    position: -webkit-sticky;
    position: sticky;
    top: 5px;
}
pre.sf-dump .sf-dump-search-wrapper > * {
    vertical-align: top;
    box-sizing: border-box;
    height: 21px;
    font-weight: normal;
    border-radius: 0;
    background: #FFF;
    color: #757575;
    border: 1px solid #BBB;
}
pre.sf-dump .sf-dump-search-wrapper > input.sf-dump-search-input {
    padding: 3px;
    height: 21px;
    font-size: 12px;
    border-right: none;
    border-top-left-radius: 3px;
    border-bottom-left-radius: 3px;
    color: #000;
    min-width: 15px;
    width: 100%;
}
pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-next,
pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-previous {
    background: #F2F2F2;
    outline: none;
    border-left: none;
    font-size: 0;
    line-height: 0;
}
pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-next {
    border-top-right-radius: 3px;
    border-bottom-right-radius: 3px;
}
pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-next > svg,
pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-previous > svg {
    pointer-events: none;
    width: 12px;
    height: 12px;
}
pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-count {
    display: inline-block;
    padding: 0 5px;
    margin: 0;
    border-left: none;
    line-height: 21px;
    font-size: 12px;
}
EOHTML
);
        foreach ($this->styles as $class => $style) {
            $line .= 'pre.sf-dump' . ('default' === $class ? ', pre.sf-dump' : '') . ' .sf-dump-' . $class . '{' . $style . '}';
        }
        $line .= 'pre.sf-dump .sf-dump-ellipsis-note{' . $this->styles['note'] . '}';
        return $this->dumpHeader = \preg_replace('/\\s+/', ' ', $line) . '</style>' . $this->dumpHeader;
    }
    /**
     * {@inheritdoc}
     */
    public function dumpString(Cursor $cursor, $str, $bin, $cut)
    {
        if ('' === $str && isset($cursor->attr['img-data'], $cursor->attr['content-type'])) {
            $this->dumpKey($cursor);
            $this->line .= $this->style('default', $cursor->attr['img-size'] ?? '', []) . ' <samp>';
            $this->endValue($cursor);
            $this->line .= $this->indentPad;
            $this->line .= \sprintf('<img src="data:%s;base64,%s" /></samp>', $cursor->attr['content-type'], \base64_encode($cursor->attr['img-data']));
            $this->endValue($cursor);
        } else {
            parent::dumpString($cursor, $str, $bin, $cut);
        }
    }
    /**
     * {@inheritdoc}
     */
    public function enterHash(Cursor $cursor, $type, $class, $hasChild)
    {
        if (Cursor::HASH_OBJECT === $type) {
            $cursor->attr['depth'] = $cursor->depth;
        }
        parent::enterHash($cursor, $type, $class, \false);
        if ($cursor->skipChildren) {
            $cursor->skipChildren = \false;
            $eol = ' class=sf-dump-compact>';
        } elseif ($this->expandNextHash) {
            $this->expandNextHash = \false;
            $eol = ' class=sf-dump-expanded>';
        } else {
            $eol = '>';
        }
        if ($hasChild) {
            $this->line .= '<samp';
            if ($cursor->refIndex) {
                $r = Cursor::HASH_OBJECT !== $type ? 1 - (Cursor::HASH_RESOURCE !== $type) : 2;
                $r .= $r && 0 < $cursor->softRefHandle ? $cursor->softRefHandle : $cursor->refIndex;
                $this->line .= \sprintf(' id=%s-ref%s', $this->dumpId, $r);
            }
            $this->line .= $eol;
            $this->dumpLine($cursor->depth);
        }
    }
    /**
     * {@inheritdoc}
     */
    public function leaveHash(Cursor $cursor, $type, $class, $hasChild, $cut)
    {
        $this->dumpEllipsis($cursor, $hasChild, $cut);
        if ($hasChild) {
            $this->line .= '</samp>';
        }
        parent::leaveHash($cursor, $type, $class, $hasChild, 0);
    }
    /**
     * {@inheritdoc}
     */
    protected function style($style, $value, $attr = [])
    {
        if ('' === $value) {
            return '';
        }
        $v = esc($value);
        if ('ref' === $style) {
            if (empty($attr['count'])) {
                return \sprintf('<a class=sf-dump-ref>%s</a>', $v);
            }
            $r = ('#' !== $v[0] ? 1 - ('@' !== $v[0]) : 2) . \substr($value, 1);
            return \sprintf('<a class=sf-dump-ref href=#%s-ref%s title="%d occurrences">%s</a>', $this->dumpId, $r, 1 + $attr['count'], $v);
        }
        if ('const' === $style && isset($attr['value'])) {
            $style .= \sprintf(' title="%s"', esc(\is_scalar($attr['value']) ? $attr['value'] : \json_encode($attr['value'])));
        } elseif ('public' === $style) {
            $style .= \sprintf(' title="%s"', empty($attr['dynamic']) ? 'Public property' : 'Runtime added dynamic property');
        } elseif ('str' === $style && 1 < $attr['length']) {
            $style .= \sprintf(' title="%d%s characters"', $attr['length'], $attr['binary'] ? ' binary or non-UTF-8' : '');
        } elseif ('note' === $style && 0 < ($attr['depth'] ?? 0) && \false !== ($c = \strrpos($value, '\\'))) {
            $style .= ' title=""';
            $attr += ['ellipsis' => \strlen($value) - $c, 'ellipsis-type' => 'note', 'ellipsis-tail' => 1];
        } elseif ('protected' === $style) {
            $style .= ' title="Protected property"';
        } elseif ('meta' === $style && isset($attr['title'])) {
            $style .= \sprintf(' title="%s"', esc($this->utf8Encode($attr['title'])));
        } elseif ('private' === $style) {
            $style .= \sprintf(' title="Private property defined in class:&#10;`%s`"', esc($this->utf8Encode($attr['class'])));
        }
        $map = static::$controlCharsMap;
        if (isset($attr['ellipsis'])) {
            $class = 'sf-dump-ellipsis';
            if (isset($attr['ellipsis-type'])) {
                $class = \sprintf('"%s sf-dump-ellipsis-%s"', $class, $attr['ellipsis-type']);
            }
            $label = esc(\substr($value, -$attr['ellipsis']));
            $style = \str_replace(' title="', " title=\"{$v}\n", $style);
            $v = \sprintf('<span class=%s>%s</span>', $class, \substr($v, 0, -\strlen($label)));
            if (!empty($attr['ellipsis-tail'])) {
                $tail = \strlen(esc(\substr($value, -$attr['ellipsis'], $attr['ellipsis-tail'])));
                $v .= \sprintf('<span class=%s>%s</span>%s', $class, \substr($label, 0, $tail), \substr($label, $tail));
            } else {
                $v .= $label;
            }
        }
        $v = "<span class=sf-dump-{$style}>" . \preg_replace_callback(static::$controlCharsRx, function ($c) use($map) {
            $s = $b = '<span class="sf-dump-default';
            $c = $c[$i = 0];
            if ($ns = "\r" === $c[$i] || "\n" === $c[$i]) {
                $s .= ' sf-dump-ns';
            }
            $s .= '">';
            do {
                if (("\r" === $c[$i] || "\n" === $c[$i]) !== $ns) {
                    $s .= '</span>' . $b;
                    if ($ns = !$ns) {
                        $s .= ' sf-dump-ns';
                    }
                    $s .= '">';
                }
                $s .= $map[$c[$i]] ?? \sprintf('\\x%02X', \ord($c[$i]));
            } while (isset($c[++$i]));
            return $s . '</span>';
        }, $v) . '</span>';
        if (isset($attr['file']) && ($href = $this->getSourceLink($attr['file'], $attr['line'] ?? 0))) {
            $attr['href'] = $href;
        }
        if (isset($attr['href'])) {
            $target = isset($attr['file']) ? '' : ' target="_blank"';
            $v = \sprintf('<a href="%s"%s rel="noopener noreferrer">%s</a>', esc($this->utf8Encode($attr['href'])), $target, $v);
        }
        if (isset($attr['lang'])) {
            $v = \sprintf('<code class="%s">%s</code>', esc($attr['lang']), $v);
        }
        return $v;
    }
    /**
     * {@inheritdoc}
     */
    protected function dumpLine($depth, $endOfValue = \false)
    {
        if (-1 === $this->lastDepth) {
            $this->line = \sprintf($this->dumpPrefix, $this->dumpId, $this->indentPad) . $this->line;
        }
        if ($this->headerIsDumped !== ($this->outputStream ?? $this->lineDumper)) {
            $this->line = $this->getDumpHeader() . $this->line;
        }
        if (-1 === $depth) {
            $args = ['"' . $this->dumpId . '"'];
            if ($this->extraDisplayOptions) {
                $args[] = \json_encode($this->extraDisplayOptions, \JSON_FORCE_OBJECT);
            }
            // Replace is for BC
            $this->line .= \sprintf(\str_replace('"%s"', '%s', $this->dumpSuffix), \implode(', ', $args));
        }
        $this->lastDepth = $depth;
        $this->line = \mb_convert_encoding($this->line, 'HTML-ENTITIES', 'UTF-8');
        if (-1 === $depth) {
            AbstractDumper::dumpLine(0);
        }
        AbstractDumper::dumpLine($depth);
    }
    private function getSourceLink(string $file, int $line)
    {
        $options = $this->extraDisplayOptions + $this->displayOptions;
        if ($fmt = $options['fileLinkFormat']) {
            return \is_string($fmt) ? \strtr($fmt, ['%f' => $file, '%l' => $line]) : $fmt->format($file, $line);
        }
        return \false;
    }
}
function esc(string $str)
{
    return \htmlspecialchars($str, \ENT_QUOTES, 'UTF-8');
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Dumper;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Data;
use CivixPhar\Symfony\Component\VarDumper\Cloner\DumperInterface;
/**
 * Abstract mechanism for dumping a Data object.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
abstract class AbstractDumper implements DataDumperInterface, DumperInterface
{
    public const DUMP_LIGHT_ARRAY = 1;
    public const DUMP_STRING_LENGTH = 2;
    public const DUMP_COMMA_SEPARATOR = 4;
    public const DUMP_TRAILING_COMMA = 8;
    public static $defaultOutput = 'php://output';
    protected $line = '';
    protected $lineDumper;
    protected $outputStream;
    protected $decimalPoint;
    // This is locale dependent
    protected $indentPad = '  ';
    protected $flags;
    private $charset = '';
    /**
     * @param callable|resource|string|null $output  A line dumper callable, an opened stream or an output path, defaults to static::$defaultOutput
     * @param string|null                   $charset The default character encoding to use for non-UTF8 strings
     * @param int                           $flags   A bit field of static::DUMP_* constants to fine tune dumps representation
     */
    public function __construct($output = null, string $charset = null, int $flags = 0)
    {
        $this->flags = $flags;
        $this->setCharset((($charset ?: \ini_get('php.output_encoding')) ?: \ini_get('default_charset')) ?: 'UTF-8');
        $this->decimalPoint = \localeconv();
        $this->decimalPoint = $this->decimalPoint['decimal_point'];
        $this->setOutput($output ?: static::$defaultOutput);
        if (!$output && \is_string(static::$defaultOutput)) {
            static::$defaultOutput = $this->outputStream;
        }
    }
    /**
     * Sets the output destination of the dumps.
     *
     * @param callable|resource|string $output A line dumper callable, an opened stream or an output path
     *
     * @return callable|resource|string The previous output destination
     */
    public function setOutput($output)
    {
        $prev = $this->outputStream ?? $this->lineDumper;
        if (\is_callable($output)) {
            $this->outputStream = null;
            $this->lineDumper = $output;
        } else {
            if (\is_string($output)) {
                $output = \fopen($output, 'w');
            }
            $this->outputStream = $output;
            $this->lineDumper = [$this, 'echoLine'];
        }
        return $prev;
    }
    /**
     * Sets the default character encoding to use for non-UTF8 strings.
     *
     * @param string $charset The default character encoding to use for non-UTF8 strings
     *
     * @return string The previous charset
     */
    public function setCharset($charset)
    {
        $prev = $this->charset;
        $charset = \strtoupper($charset);
        $charset = null === $charset || 'UTF-8' === $charset || 'UTF8' === $charset ? 'CP1252' : $charset;
        $this->charset = $charset;
        return $prev;
    }
    /**
     * Sets the indentation pad string.
     *
     * @param string $pad A string that will be prepended to dumped lines, repeated by nesting level
     *
     * @return string The previous indent pad
     */
    public function setIndentPad($pad)
    {
        $prev = $this->indentPad;
        $this->indentPad = $pad;
        return $prev;
    }
    /**
     * Dumps a Data object.
     *
     * @param callable|resource|string|true|null $output A line dumper callable, an opened stream, an output path or true to return the dump
     *
     * @return string|null The dump as string when $output is true
     */
    public function dump(Data $data, $output = null)
    {
        $this->decimalPoint = \localeconv();
        $this->decimalPoint = $this->decimalPoint['decimal_point'];
        if ($locale = $this->flags & (self::DUMP_COMMA_SEPARATOR | self::DUMP_TRAILING_COMMA) ? \setlocale(\LC_NUMERIC, 0) : null) {
            \setlocale(\LC_NUMERIC, 'C');
        }
        if ($returnDump = \true === $output) {
            $output = \fopen('php://memory', 'r+');
        }
        if ($output) {
            $prevOutput = $this->setOutput($output);
        }
        try {
            $data->dump($this);
            $this->dumpLine(-1);
            if ($returnDump) {
                $result = \stream_get_contents($output, -1, 0);
                \fclose($output);
                return $result;
            }
        } finally {
            if ($output) {
                $this->setOutput($prevOutput);
            }
            if ($locale) {
                \setlocale(\LC_NUMERIC, $locale);
            }
        }
        return null;
    }
    /**
     * Dumps the current line.
     *
     * @param int $depth The recursive depth in the dumped structure for the line being dumped,
     *                   or -1 to signal the end-of-dump to the line dumper callable
     */
    protected function dumpLine($depth)
    {
        ($this->lineDumper)($this->line, $depth, $this->indentPad);
        $this->line = '';
    }
    /**
     * Generic line dumper callback.
     *
     * @param string $line      The line to write
     * @param int    $depth     The recursive depth in the dumped structure
     * @param string $indentPad The line indent pad
     */
    protected function echoLine($line, $depth, $indentPad)
    {
        if (-1 !== $depth) {
            \fwrite($this->outputStream, \str_repeat($indentPad, $depth) . $line . "\n");
        }
    }
    /**
     * Converts a non-UTF-8 string to UTF-8.
     *
     * @param string|null $s The non-UTF-8 string to convert
     *
     * @return string|null The string converted to UTF-8
     */
    protected function utf8Encode($s)
    {
        if (null === $s || \preg_match('//u', $s)) {
            return $s;
        }
        if (!\function_exists('iconv')) {
            throw new \RuntimeException('Unable to convert a non-UTF-8 string to UTF-8: required function iconv() does not exist. You should install ext-iconv or symfony/polyfill-iconv.');
        }
        if (\false !== ($c = @\iconv($this->charset, 'UTF-8', $s))) {
            return $c;
        }
        if ('CP1252' !== $this->charset && \false !== ($c = @\iconv('CP1252', 'UTF-8', $s))) {
            return $c;
        }
        return \iconv('CP850', 'UTF-8', $s);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Dumper;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Data;
use CivixPhar\Symfony\Component\VarDumper\Dumper\ContextProvider\ContextProviderInterface;
use CivixPhar\Symfony\Component\VarDumper\Server\Connection;
/**
 * ServerDumper forwards serialized Data clones to a server.
 *
 * @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
 */
class ServerDumper implements DataDumperInterface
{
    private $connection;
    private $wrappedDumper;
    /**
     * @param string                     $host             The server host
     * @param DataDumperInterface|null   $wrappedDumper    A wrapped instance used whenever we failed contacting the server
     * @param ContextProviderInterface[] $contextProviders Context providers indexed by context name
     */
    public function __construct(string $host, DataDumperInterface $wrappedDumper = null, array $contextProviders = [])
    {
        $this->connection = new Connection($host, $contextProviders);
        $this->wrappedDumper = $wrappedDumper;
    }
    public function getContextProviders() : array
    {
        return $this->connection->getContextProviders();
    }
    /**
     * {@inheritdoc}
     */
    public function dump(Data $data)
    {
        if (!$this->connection->write($data) && $this->wrappedDumper) {
            $this->wrappedDumper->dump($data);
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Dumper;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Data;
/**
 * DataDumperInterface for dumping Data objects.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
interface DataDumperInterface
{
    public function dump(Data $data);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Dumper;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Cursor;
use CivixPhar\Symfony\Component\VarDumper\Cloner\Stub;
/**
 * CliDumper dumps variables for command line output.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
class CliDumper extends AbstractDumper
{
    public static $defaultColors;
    public static $defaultOutput = 'php://stdout';
    protected $colors;
    protected $maxStringWidth = 0;
    protected $styles = [
        // See http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
        'default' => '0;38;5;208',
        'num' => '1;38;5;38',
        'const' => '1;38;5;208',
        'str' => '1;38;5;113',
        'note' => '38;5;38',
        'ref' => '38;5;247',
        'public' => '',
        'protected' => '',
        'private' => '',
        'meta' => '38;5;170',
        'key' => '38;5;113',
        'index' => '38;5;38',
    ];
    protected static $controlCharsRx = '/[\\x00-\\x1F\\x7F]+/';
    protected static $controlCharsMap = ["\t" => '\\t', "\n" => '\\n', "\v" => '\\v', "\f" => '\\f', "\r" => '\\r', "\x1b" => '\\e'];
    protected $collapseNextHash = \false;
    protected $expandNextHash = \false;
    private $displayOptions = ['fileLinkFormat' => null];
    private $handlesHrefGracefully;
    /**
     * {@inheritdoc}
     */
    public function __construct($output = null, string $charset = null, int $flags = 0)
    {
        parent::__construct($output, $charset, $flags);
        if ('\\' === \DIRECTORY_SEPARATOR && !$this->isWindowsTrueColor()) {
            // Use only the base 16 xterm colors when using ANSICON or standard Windows 10 CLI
            $this->setStyles(['default' => '31', 'num' => '1;34', 'const' => '1;31', 'str' => '1;32', 'note' => '34', 'ref' => '1;30', 'meta' => '35', 'key' => '32', 'index' => '34']);
        }
        $this->displayOptions['fileLinkFormat'] = (\ini_get('xdebug.file_link_format') ?: \get_cfg_var('xdebug.file_link_format')) ?: 'file://%f#L%l';
    }
    /**
     * Enables/disables colored output.
     *
     * @param bool $colors
     */
    public function setColors($colors)
    {
        $this->colors = (bool) $colors;
    }
    /**
     * Sets the maximum number of characters per line for dumped strings.
     *
     * @param int $maxStringWidth
     */
    public function setMaxStringWidth($maxStringWidth)
    {
        $this->maxStringWidth = (int) $maxStringWidth;
    }
    /**
     * Configures styles.
     *
     * @param array $styles A map of style names to style definitions
     */
    public function setStyles(array $styles)
    {
        $this->styles = $styles + $this->styles;
    }
    /**
     * Configures display options.
     *
     * @param array $displayOptions A map of display options to customize the behavior
     */
    public function setDisplayOptions(array $displayOptions)
    {
        $this->displayOptions = $displayOptions + $this->displayOptions;
    }
    /**
     * {@inheritdoc}
     */
    public function dumpScalar(Cursor $cursor, $type, $value)
    {
        $this->dumpKey($cursor);
        $style = 'const';
        $attr = $cursor->attr;
        switch ($type) {
            case 'default':
                $style = 'default';
                break;
            case 'integer':
                $style = 'num';
                break;
            case 'double':
                $style = 'num';
                switch (\true) {
                    case \INF === $value:
                        $value = 'INF';
                        break;
                    case -\INF === $value:
                        $value = '-INF';
                        break;
                    case \is_nan($value):
                        $value = 'NAN';
                        break;
                    default:
                        $value = (string) $value;
                        if (!\str_contains($value, $this->decimalPoint)) {
                            $value .= $this->decimalPoint . '0';
                        }
                        break;
                }
                break;
            case 'NULL':
                $value = 'null';
                break;
            case 'boolean':
                $value = $value ? 'true' : 'false';
                break;
            default:
                $attr += ['value' => $this->utf8Encode($value)];
                $value = $this->utf8Encode($type);
                break;
        }
        $this->line .= $this->style($style, $value, $attr);
        $this->endValue($cursor);
    }
    /**
     * {@inheritdoc}
     */
    public function dumpString(Cursor $cursor, $str, $bin, $cut)
    {
        $this->dumpKey($cursor);
        $attr = $cursor->attr;
        if ($bin) {
            $str = $this->utf8Encode($str);
        }
        if ('' === $str) {
            $this->line .= '""';
            $this->endValue($cursor);
        } else {
            $attr += ['length' => 0 <= $cut ? \mb_strlen($str, 'UTF-8') + $cut : 0, 'binary' => $bin];
            $str = \explode("\n", $str);
            if (isset($str[1]) && !isset($str[2]) && !isset($str[1][0])) {
                unset($str[1]);
                $str[0] .= "\n";
            }
            $m = \count($str) - 1;
            $i = $lineCut = 0;
            if (self::DUMP_STRING_LENGTH & $this->flags) {
                $this->line .= '(' . $attr['length'] . ') ';
            }
            if ($bin) {
                $this->line .= 'b';
            }
            if ($m) {
                $this->line .= '"""';
                $this->dumpLine($cursor->depth);
            } else {
                $this->line .= '"';
            }
            foreach ($str as $str) {
                if ($i < $m) {
                    $str .= "\n";
                }
                if (0 < $this->maxStringWidth && $this->maxStringWidth < ($len = \mb_strlen($str, 'UTF-8'))) {
                    $str = \mb_substr($str, 0, $this->maxStringWidth, 'UTF-8');
                    $lineCut = $len - $this->maxStringWidth;
                }
                if ($m && 0 < $cursor->depth) {
                    $this->line .= $this->indentPad;
                }
                if ('' !== $str) {
                    $this->line .= $this->style('str', $str, $attr);
                }
                if ($i++ == $m) {
                    if ($m) {
                        if ('' !== $str) {
                            $this->dumpLine($cursor->depth);
                            if (0 < $cursor->depth) {
                                $this->line .= $this->indentPad;
                            }
                        }
                        $this->line .= '"""';
                    } else {
                        $this->line .= '"';
                    }
                    if ($cut < 0) {
                        $this->line .= 'â€¦';
                        $lineCut = 0;
                    } elseif ($cut) {
                        $lineCut += $cut;
                    }
                }
                if ($lineCut) {
                    $this->line .= 'â€¦' . $lineCut;
                    $lineCut = 0;
                }
                if ($i > $m) {
                    $this->endValue($cursor);
                } else {
                    $this->dumpLine($cursor->depth);
                }
            }
        }
    }
    /**
     * {@inheritdoc}
     */
    public function enterHash(Cursor $cursor, $type, $class, $hasChild)
    {
        if (null === $this->colors) {
            $this->colors = $this->supportsColors();
        }
        $this->dumpKey($cursor);
        $attr = $cursor->attr;
        if ($this->collapseNextHash) {
            $cursor->skipChildren = \true;
            $this->collapseNextHash = $hasChild = \false;
        }
        $class = $this->utf8Encode($class);
        if (Cursor::HASH_OBJECT === $type) {
            $prefix = $class && 'stdClass' !== $class ? $this->style('note', $class, $attr) . (empty($attr['cut_hash']) ? ' {' : '') : '{';
        } elseif (Cursor::HASH_RESOURCE === $type) {
            $prefix = $this->style('note', $class . ' resource', $attr) . ($hasChild ? ' {' : ' ');
        } else {
            $prefix = $class && !(self::DUMP_LIGHT_ARRAY & $this->flags) ? $this->style('note', 'array:' . $class) . ' [' : '[';
        }
        if (($cursor->softRefCount || 0 < $cursor->softRefHandle) && empty($attr['cut_hash'])) {
            $prefix .= $this->style('ref', (Cursor::HASH_RESOURCE === $type ? '@' : '#') . (0 < $cursor->softRefHandle ? $cursor->softRefHandle : $cursor->softRefTo), ['count' => $cursor->softRefCount]);
        } elseif ($cursor->hardRefTo && !$cursor->refIndex && $class) {
            $prefix .= $this->style('ref', '&' . $cursor->hardRefTo, ['count' => $cursor->hardRefCount]);
        } elseif (!$hasChild && Cursor::HASH_RESOURCE === $type) {
            $prefix = \substr($prefix, 0, -1);
        }
        $this->line .= $prefix;
        if ($hasChild) {
            $this->dumpLine($cursor->depth);
        }
    }
    /**
     * {@inheritdoc}
     */
    public function leaveHash(Cursor $cursor, $type, $class, $hasChild, $cut)
    {
        if (empty($cursor->attr['cut_hash'])) {
            $this->dumpEllipsis($cursor, $hasChild, $cut);
            $this->line .= Cursor::HASH_OBJECT === $type ? '}' : (Cursor::HASH_RESOURCE !== $type ? ']' : ($hasChild ? '}' : ''));
        }
        $this->endValue($cursor);
    }
    /**
     * Dumps an ellipsis for cut children.
     *
     * @param bool $hasChild When the dump of the hash has child item
     * @param int  $cut      The number of items the hash has been cut by
     */
    protected function dumpEllipsis(Cursor $cursor, $hasChild, $cut)
    {
        if ($cut) {
            $this->line .= ' â€¦';
            if (0 < $cut) {
                $this->line .= $cut;
            }
            if ($hasChild) {
                $this->dumpLine($cursor->depth + 1);
            }
        }
    }
    /**
     * Dumps a key in a hash structure.
     */
    protected function dumpKey(Cursor $cursor)
    {
        if (null !== ($key = $cursor->hashKey)) {
            if ($cursor->hashKeyIsBinary) {
                $key = $this->utf8Encode($key);
            }
            $attr = ['binary' => $cursor->hashKeyIsBinary];
            $bin = $cursor->hashKeyIsBinary ? 'b' : '';
            $style = 'key';
            switch ($cursor->hashType) {
                default:
                case Cursor::HASH_INDEXED:
                    if (self::DUMP_LIGHT_ARRAY & $this->flags) {
                        break;
                    }
                    $style = 'index';
                // no break
                case Cursor::HASH_ASSOC:
                    if (\is_int($key)) {
                        $this->line .= $this->style($style, $key) . ' => ';
                    } else {
                        $this->line .= $bin . '"' . $this->style($style, $key) . '" => ';
                    }
                    break;
                case Cursor::HASH_RESOURCE:
                    $key = "\x00~\x00" . $key;
                // no break
                case Cursor::HASH_OBJECT:
                    if (!isset($key[0]) || "\x00" !== $key[0]) {
                        $this->line .= '+' . $bin . $this->style('public', $key) . ': ';
                    } elseif (0 < \strpos($key, "\x00", 1)) {
                        $key = \explode("\x00", \substr($key, 1), 2);
                        switch ($key[0][0]) {
                            case '+':
                                // User inserted keys
                                $attr['dynamic'] = \true;
                                $this->line .= '+' . $bin . '"' . $this->style('public', $key[1], $attr) . '": ';
                                break 2;
                            case '~':
                                $style = 'meta';
                                if (isset($key[0][1])) {
                                    \parse_str(\substr($key[0], 1), $attr);
                                    $attr += ['binary' => $cursor->hashKeyIsBinary];
                                }
                                break;
                            case '*':
                                $style = 'protected';
                                $bin = '#' . $bin;
                                break;
                            default:
                                $attr['class'] = $key[0];
                                $style = 'private';
                                $bin = '-' . $bin;
                                break;
                        }
                        if (isset($attr['collapse'])) {
                            if ($attr['collapse']) {
                                $this->collapseNextHash = \true;
                            } else {
                                $this->expandNextHash = \true;
                            }
                        }
                        $this->line .= $bin . $this->style($style, $key[1], $attr) . ($attr['separator'] ?? ': ');
                    } else {
                        // This case should not happen
                        $this->line .= '-' . $bin . '"' . $this->style('private', $key, ['class' => '']) . '": ';
                    }
                    break;
            }
            if ($cursor->hardRefTo) {
                $this->line .= $this->style('ref', '&' . ($cursor->hardRefCount ? $cursor->hardRefTo : ''), ['count' => $cursor->hardRefCount]) . ' ';
            }
        }
    }
    /**
     * Decorates a value with some style.
     *
     * @param string $style The type of style being applied
     * @param string $value The value being styled
     * @param array  $attr  Optional context information
     *
     * @return string The value with style decoration
     */
    protected function style($style, $value, $attr = [])
    {
        if (null === $this->colors) {
            $this->colors = $this->supportsColors();
        }
        if (null === $this->handlesHrefGracefully) {
            $this->handlesHrefGracefully = 'JetBrains-JediTerm' !== \getenv('TERMINAL_EMULATOR') && (!\getenv('KONSOLE_VERSION') || (int) \getenv('KONSOLE_VERSION') > 201100);
        }
        if (isset($attr['ellipsis'], $attr['ellipsis-type'])) {
            $prefix = \substr($value, 0, -$attr['ellipsis']);
            if ('cli' === \PHP_SAPI && 'path' === $attr['ellipsis-type'] && isset($_SERVER[$pwd = '\\' === \DIRECTORY_SEPARATOR ? 'CD' : 'PWD']) && \str_starts_with($prefix, $_SERVER[$pwd])) {
                $prefix = '.' . \substr($prefix, \strlen($_SERVER[$pwd]));
            }
            if (!empty($attr['ellipsis-tail'])) {
                $prefix .= \substr($value, -$attr['ellipsis'], $attr['ellipsis-tail']);
                $value = \substr($value, -$attr['ellipsis'] + $attr['ellipsis-tail']);
            } else {
                $value = \substr($value, -$attr['ellipsis']);
            }
            $value = $this->style('default', $prefix) . $this->style($style, $value);
            goto href;
        }
        $map = static::$controlCharsMap;
        $startCchr = $this->colors ? "\x1b[m\x1b[{$this->styles['default']}m" : '';
        $endCchr = $this->colors ? "\x1b[m\x1b[{$this->styles[$style]}m" : '';
        $value = \preg_replace_callback(static::$controlCharsRx, function ($c) use($map, $startCchr, $endCchr) {
            $s = $startCchr;
            $c = $c[$i = 0];
            do {
                $s .= $map[$c[$i]] ?? \sprintf('\\x%02X', \ord($c[$i]));
            } while (isset($c[++$i]));
            return $s . $endCchr;
        }, $value, -1, $cchrCount);
        if ($this->colors) {
            if ($cchrCount && "\x1b" === $value[0]) {
                $value = \substr($value, \strlen($startCchr));
            } else {
                $value = "\x1b[{$this->styles[$style]}m" . $value;
            }
            if ($cchrCount && \str_ends_with($value, $endCchr)) {
                $value = \substr($value, 0, -\strlen($endCchr));
            } else {
                $value .= "\x1b[{$this->styles['default']}m";
            }
        }
        href:
        if ($this->colors && $this->handlesHrefGracefully) {
            if (isset($attr['file']) && ($href = $this->getSourceLink($attr['file'], $attr['line'] ?? 0))) {
                if ('note' === $style) {
                    $value .= "\x1b]8;;{$href}\x1b\\^\x1b]8;;\x1b\\";
                } else {
                    $attr['href'] = $href;
                }
            }
            if (isset($attr['href'])) {
                $value = "\x1b]8;;{$attr['href']}\x1b\\{$value}\x1b]8;;\x1b\\";
            }
        } elseif ($attr['if_links'] ?? \false) {
            return '';
        }
        return $value;
    }
    /**
     * @return bool Tells if the current output stream supports ANSI colors or not
     */
    protected function supportsColors()
    {
        if ($this->outputStream !== static::$defaultOutput) {
            return $this->hasColorSupport($this->outputStream);
        }
        if (null !== static::$defaultColors) {
            return static::$defaultColors;
        }
        if (isset($_SERVER['argv'][1])) {
            $colors = $_SERVER['argv'];
            $i = \count($colors);
            while (--$i > 0) {
                if (isset($colors[$i][5])) {
                    switch ($colors[$i]) {
                        case '--ansi':
                        case '--color':
                        case '--color=yes':
                        case '--color=force':
                        case '--color=always':
                            return static::$defaultColors = \true;
                        case '--no-ansi':
                        case '--color=no':
                        case '--color=none':
                        case '--color=never':
                            return static::$defaultColors = \false;
                    }
                }
            }
        }
        $h = \stream_get_meta_data($this->outputStream) + ['wrapper_type' => null];
        $h = 'Output' === $h['stream_type'] && 'PHP' === $h['wrapper_type'] ? \fopen('php://stdout', 'w') : $this->outputStream;
        return static::$defaultColors = $this->hasColorSupport($h);
    }
    /**
     * {@inheritdoc}
     */
    protected function dumpLine($depth, $endOfValue = \false)
    {
        if ($this->colors) {
            $this->line = \sprintf("\x1b[%sm%s\x1b[m", $this->styles['default'], $this->line);
        }
        parent::dumpLine($depth);
    }
    protected function endValue(Cursor $cursor)
    {
        if (-1 === $cursor->hashType) {
            return;
        }
        if (Stub::ARRAY_INDEXED === $cursor->hashType || Stub::ARRAY_ASSOC === $cursor->hashType) {
            if (self::DUMP_TRAILING_COMMA & $this->flags && 0 < $cursor->depth) {
                $this->line .= ',';
            } elseif (self::DUMP_COMMA_SEPARATOR & $this->flags && 1 < $cursor->hashLength - $cursor->hashIndex) {
                $this->line .= ',';
            }
        }
        $this->dumpLine($cursor->depth, \true);
    }
    /**
     * Returns true if the stream supports colorization.
     *
     * Reference: Composer\XdebugHandler\Process::supportsColor
     * https://github.com/composer/xdebug-handler
     *
     * @param mixed $stream A CLI output stream
     */
    private function hasColorSupport($stream) : bool
    {
        if (!\is_resource($stream) || 'stream' !== \get_resource_type($stream)) {
            return \false;
        }
        // Follow https://no-color.org/
        if (isset($_SERVER['NO_COLOR']) || \false !== \getenv('NO_COLOR')) {
            return \false;
        }
        if ('Hyper' === \getenv('TERM_PROGRAM')) {
            return \true;
        }
        if (\DIRECTORY_SEPARATOR === '\\') {
            return \function_exists('sapi_windows_vt100_support') && @\sapi_windows_vt100_support($stream) || \false !== \getenv('ANSICON') || 'ON' === \getenv('ConEmuANSI') || 'xterm' === \getenv('TERM');
        }
        if (\function_exists('stream_isatty')) {
            return @\stream_isatty($stream);
        }
        if (\function_exists('posix_isatty')) {
            return @\posix_isatty($stream);
        }
        $stat = @\fstat($stream);
        // Check if formatted mode is S_IFCHR
        return $stat ? 020000 === ($stat['mode'] & 0170000) : \false;
    }
    /**
     * Returns true if the Windows terminal supports true color.
     *
     * Note that this does not check an output stream, but relies on environment
     * variables from known implementations, or a PHP and Windows version that
     * supports true color.
     */
    private function isWindowsTrueColor() : bool
    {
        $result = 183 <= \getenv('ANSICON_VER') || 'ON' === \getenv('ConEmuANSI') || 'xterm' === \getenv('TERM') || 'Hyper' === \getenv('TERM_PROGRAM');
        if (!$result && \PHP_VERSION_ID >= 70200) {
            $version = \sprintf('%s.%s.%s', \PHP_WINDOWS_VERSION_MAJOR, \PHP_WINDOWS_VERSION_MINOR, \PHP_WINDOWS_VERSION_BUILD);
            $result = $version >= '10.0.15063';
        }
        return $result;
    }
    private function getSourceLink(string $file, int $line)
    {
        if ($fmt = $this->displayOptions['fileLinkFormat']) {
            return \is_string($fmt) ? \strtr($fmt, ['%f' => $file, '%l' => $line]) : ($fmt->format($file, $line) ?: 'file://' . $file . '#L' . $line);
        }
        return \false;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Dumper\ContextProvider;

use CivixPhar\Symfony\Component\HttpKernel\Debug\FileLinkFormatter;
use CivixPhar\Symfony\Component\VarDumper\Cloner\VarCloner;
use CivixPhar\Symfony\Component\VarDumper\Dumper\HtmlDumper;
use CivixPhar\Symfony\Component\VarDumper\VarDumper;
use CivixPhar\Twig\Template;
/**
 * Tries to provide context from sources (class name, file, line, code excerpt, ...).
 *
 * @author Nicolas Grekas <p@tchwork.com>
 * @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
 */
final class SourceContextProvider implements ContextProviderInterface
{
    private $limit;
    private $charset;
    private $projectDir;
    private $fileLinkFormatter;
    public function __construct(string $charset = null, string $projectDir = null, FileLinkFormatter $fileLinkFormatter = null, int $limit = 9)
    {
        $this->charset = $charset;
        $this->projectDir = $projectDir;
        $this->fileLinkFormatter = $fileLinkFormatter;
        $this->limit = $limit;
    }
    public function getContext() : ?array
    {
        $trace = \debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT | \DEBUG_BACKTRACE_IGNORE_ARGS, $this->limit);
        $file = $trace[1]['file'];
        $line = $trace[1]['line'];
        $name = \false;
        $fileExcerpt = \false;
        for ($i = 2; $i < $this->limit; ++$i) {
            if (isset($trace[$i]['class'], $trace[$i]['function']) && 'dump' === $trace[$i]['function'] && VarDumper::class === $trace[$i]['class']) {
                $file = $trace[$i]['file'] ?? $file;
                $line = $trace[$i]['line'] ?? $line;
                while (++$i < $this->limit) {
                    if (isset($trace[$i]['function'], $trace[$i]['file']) && empty($trace[$i]['class']) && !\str_starts_with($trace[$i]['function'], 'call_user_func')) {
                        $file = $trace[$i]['file'];
                        $line = $trace[$i]['line'];
                        break;
                    } elseif (isset($trace[$i]['object']) && $trace[$i]['object'] instanceof Template) {
                        $template = $trace[$i]['object'];
                        $name = $template->getTemplateName();
                        $src = \method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getCode() : (\method_exists($template, 'getSource') ? $template->getSource() : \false);
                        $info = $template->getDebugInfo();
                        if (isset($info[$trace[$i - 1]['line']])) {
                            $line = $info[$trace[$i - 1]['line']];
                            $file = \method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getPath() : null;
                            if ($src) {
                                $src = \explode("\n", $src);
                                $fileExcerpt = [];
                                for ($i = \max($line - 3, 1), $max = \min($line + 3, \count($src)); $i <= $max; ++$i) {
                                    $fileExcerpt[] = '<li' . ($i === $line ? ' class="selected"' : '') . '><code>' . $this->htmlEncode($src[$i - 1]) . '</code></li>';
                                }
                                $fileExcerpt = '<ol start="' . \max($line - 3, 1) . '">' . \implode("\n", $fileExcerpt) . '</ol>';
                            }
                        }
                        break;
                    }
                }
                break;
            }
        }
        if (\false === $name) {
            $name = \str_replace('\\', '/', $file);
            $name = \substr($name, \strrpos($name, '/') + 1);
        }
        $context = ['name' => $name, 'file' => $file, 'line' => $line];
        $context['file_excerpt'] = $fileExcerpt;
        if (null !== $this->projectDir) {
            $context['project_dir'] = $this->projectDir;
            if (\str_starts_with($file, $this->projectDir)) {
                $context['file_relative'] = \ltrim(\substr($file, \strlen($this->projectDir)), \DIRECTORY_SEPARATOR);
            }
        }
        if ($this->fileLinkFormatter && ($fileLink = $this->fileLinkFormatter->format($context['file'], $context['line']))) {
            $context['file_link'] = $fileLink;
        }
        return $context;
    }
    private function htmlEncode(string $s) : string
    {
        $html = '';
        $dumper = new HtmlDumper(function ($line) use(&$html) {
            $html .= $line;
        }, $this->charset);
        $dumper->setDumpHeader('');
        $dumper->setDumpBoundaries('', '');
        $cloner = new VarCloner();
        $dumper->dump($cloner->cloneVar($s));
        return \substr(\strip_tags($html), 1, -1);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Dumper\ContextProvider;

/**
 * Tries to provide context on CLI.
 *
 * @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
 */
final class CliContextProvider implements ContextProviderInterface
{
    public function getContext() : ?array
    {
        if ('cli' !== \PHP_SAPI) {
            return null;
        }
        return ['command_line' => $commandLine = \implode(' ', $_SERVER['argv'] ?? []), 'identifier' => \hash('crc32b', $commandLine . $_SERVER['REQUEST_TIME_FLOAT'])];
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Dumper\ContextProvider;

use Symfony\Component\HttpFoundation\RequestStack;
use CivixPhar\Symfony\Component\VarDumper\Caster\ReflectionCaster;
use CivixPhar\Symfony\Component\VarDumper\Cloner\VarCloner;
/**
 * Tries to provide context from a request.
 *
 * @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
 */
final class RequestContextProvider implements ContextProviderInterface
{
    private $requestStack;
    private $cloner;
    public function __construct(RequestStack $requestStack)
    {
        $this->requestStack = $requestStack;
        $this->cloner = new VarCloner();
        $this->cloner->setMaxItems(0);
        $this->cloner->addCasters(ReflectionCaster::UNSET_CLOSURE_FILE_INFO);
    }
    public function getContext() : ?array
    {
        if (null === ($request = $this->requestStack->getCurrentRequest())) {
            return null;
        }
        $controller = $request->attributes->get('_controller');
        return ['uri' => $request->getUri(), 'method' => $request->getMethod(), 'controller' => $controller ? $this->cloner->cloneVar($controller) : $controller, 'identifier' => \spl_object_hash($request)];
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Dumper\ContextProvider;

/**
 * Interface to provide contextual data about dump data clones sent to a server.
 *
 * @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
 */
interface ContextProviderInterface
{
    /**
     * @return array|null Context data or null if unable to provide any context
     */
    public function getContext() : ?array;
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarDumper\Dumper;

use CivixPhar\Symfony\Component\VarDumper\Cloner\Data;
use CivixPhar\Symfony\Component\VarDumper\Dumper\ContextProvider\ContextProviderInterface;
/**
 * @author KÃ©vin ThÃ©rage <therage.kevin@gmail.com>
 */
class ContextualizedDumper implements DataDumperInterface
{
    private $wrappedDumper;
    private $contextProviders;
    /**
     * @param ContextProviderInterface[] $contextProviders
     */
    public function __construct(DataDumperInterface $wrappedDumper, array $contextProviders)
    {
        $this->wrappedDumper = $wrappedDumper;
        $this->contextProviders = $contextProviders;
    }
    public function dump(Data $data)
    {
        $context = [];
        foreach ($this->contextProviders as $contextProvider) {
            $context[\get_class($contextProvider)] = $contextProvider->getContext();
        }
        $this->wrappedDumper->dump($data->withContext($context));
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Filesystem\Exception;

/**
 * @author Christian Flothmann <christian.flothmann@sensiolabs.de>
 */
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Filesystem\Exception;

/**
 * IOException interface for file and input/output stream related exceptions thrown by the component.
 *
 * @author Christian GÃ¤rtner <christiangaertner.film@googlemail.com>
 */
interface IOExceptionInterface extends ExceptionInterface
{
    /**
     * Returns the associated path for the exception.
     *
     * @return string|null The path
     */
    public function getPath();
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Filesystem\Exception;

/**
 * Exception interface for all exceptions thrown by the component.
 *
 * @author Romain Neutron <imprec@gmail.com>
 */
interface ExceptionInterface extends \Throwable
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Filesystem\Exception;

/**
 * Exception class thrown when a file couldn't be found.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Christian GÃ¤rtner <christiangaertner.film@googlemail.com>
 */
class FileNotFoundException extends IOException
{
    public function __construct(string $message = null, int $code = 0, \Throwable $previous = null, string $path = null)
    {
        if (null === $message) {
            if (null === $path) {
                $message = 'File could not be found.';
            } else {
                $message = \sprintf('File "%s" could not be found.', $path);
            }
        }
        parent::__construct($message, $code, $previous, $path);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Filesystem\Exception;

/**
 * Exception class thrown when a filesystem operation failure happens.
 *
 * @author Romain Neutron <imprec@gmail.com>
 * @author Christian GÃ¤rtner <christiangaertner.film@googlemail.com>
 * @author Fabien Potencier <fabien@symfony.com>
 */
class IOException extends \RuntimeException implements IOExceptionInterface
{
    private $path;
    public function __construct(string $message, int $code = 0, \Throwable $previous = null, string $path = null)
    {
        $this->path = $path;
        parent::__construct($message, $code, $previous);
    }
    /**
     * {@inheritdoc}
     */
    public function getPath()
    {
        return $this->path;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Filesystem;

use CivixPhar\Symfony\Component\Filesystem\Exception\FileNotFoundException;
use CivixPhar\Symfony\Component\Filesystem\Exception\InvalidArgumentException;
use CivixPhar\Symfony\Component\Filesystem\Exception\IOException;
/**
 * Provides basic utility to manipulate the file system.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class Filesystem
{
    private static $lastError;
    /**
     * Copies a file.
     *
     * If the target file is older than the origin file, it's always overwritten.
     * If the target file is newer, it is overwritten only when the
     * $overwriteNewerFiles option is set to true.
     *
     * @param string $originFile          The original filename
     * @param string $targetFile          The target filename
     * @param bool   $overwriteNewerFiles If true, target files newer than origin files are overwritten
     *
     * @throws FileNotFoundException When originFile doesn't exist
     * @throws IOException           When copy fails
     */
    public function copy($originFile, $targetFile, $overwriteNewerFiles = \false)
    {
        $originIsLocal = \stream_is_local($originFile) || 0 === \stripos($originFile, 'file://');
        if ($originIsLocal && !\is_file($originFile)) {
            throw new FileNotFoundException(\sprintf('Failed to copy "%s" because file does not exist.', $originFile), 0, null, $originFile);
        }
        $this->mkdir(\dirname($targetFile));
        $doCopy = \true;
        if (!$overwriteNewerFiles && null === \parse_url($originFile, \PHP_URL_HOST) && \is_file($targetFile)) {
            $doCopy = \filemtime($originFile) > \filemtime($targetFile);
        }
        if ($doCopy) {
            // https://bugs.php.net/64634
            if (\false === ($source = @\fopen($originFile, 'r'))) {
                throw new IOException(\sprintf('Failed to copy "%s" to "%s" because source file could not be opened for reading.', $originFile, $targetFile), 0, null, $originFile);
            }
            // Stream context created to allow files overwrite when using FTP stream wrapper - disabled by default
            if (\false === ($target = @\fopen($targetFile, 'w', \false, \stream_context_create(['ftp' => ['overwrite' => \true]])))) {
                throw new IOException(\sprintf('Failed to copy "%s" to "%s" because target file could not be opened for writing.', $originFile, $targetFile), 0, null, $originFile);
            }
            $bytesCopied = \stream_copy_to_stream($source, $target);
            \fclose($source);
            \fclose($target);
            unset($source, $target);
            if (!\is_file($targetFile)) {
                throw new IOException(\sprintf('Failed to copy "%s" to "%s".', $originFile, $targetFile), 0, null, $originFile);
            }
            if ($originIsLocal) {
                // Like `cp`, preserve executable permission bits
                @\chmod($targetFile, \fileperms($targetFile) | \fileperms($originFile) & 0111);
                if ($bytesCopied !== ($bytesOrigin = \filesize($originFile))) {
                    throw new IOException(\sprintf('Failed to copy the whole content of "%s" to "%s" (%g of %g bytes copied).', $originFile, $targetFile, $bytesCopied, $bytesOrigin), 0, null, $originFile);
                }
            }
        }
    }
    /**
     * Creates a directory recursively.
     *
     * @param string|iterable $dirs The directory path
     * @param int             $mode The directory mode
     *
     * @throws IOException On any directory creation failure
     */
    public function mkdir($dirs, $mode = 0777)
    {
        foreach ($this->toIterable($dirs) as $dir) {
            if (\is_dir($dir)) {
                continue;
            }
            if (!self::box('mkdir', $dir, $mode, \true)) {
                if (!\is_dir($dir)) {
                    // The directory was not created by a concurrent process. Let's throw an exception with a developer friendly error message if we have one
                    if (self::$lastError) {
                        throw new IOException(\sprintf('Failed to create "%s": ', $dir) . self::$lastError, 0, null, $dir);
                    }
                    throw new IOException(\sprintf('Failed to create "%s".', $dir), 0, null, $dir);
                }
            }
        }
    }
    /**
     * Checks the existence of files or directories.
     *
     * @param string|iterable $files A filename, an array of files, or a \Traversable instance to check
     *
     * @return bool true if the file exists, false otherwise
     */
    public function exists($files)
    {
        $maxPathLength = \PHP_MAXPATHLEN - 2;
        foreach ($this->toIterable($files) as $file) {
            if (\strlen($file) > $maxPathLength) {
                throw new IOException(\sprintf('Could not check if file exist because path length exceeds %d characters.', $maxPathLength), 0, null, $file);
            }
            if (!\file_exists($file)) {
                return \false;
            }
        }
        return \true;
    }
    /**
     * Sets access and modification time of file.
     *
     * @param string|iterable $files A filename, an array of files, or a \Traversable instance to create
     * @param int|null        $time  The touch time as a Unix timestamp, if not supplied the current system time is used
     * @param int|null        $atime The access time as a Unix timestamp, if not supplied the current system time is used
     *
     * @throws IOException When touch fails
     */
    public function touch($files, $time = null, $atime = null)
    {
        foreach ($this->toIterable($files) as $file) {
            $touch = $time ? @\touch($file, $time, $atime) : @\touch($file);
            if (\true !== $touch) {
                throw new IOException(\sprintf('Failed to touch "%s".', $file), 0, null, $file);
            }
        }
    }
    /**
     * Removes files or directories.
     *
     * @param string|iterable $files A filename, an array of files, or a \Traversable instance to remove
     *
     * @throws IOException When removal fails
     */
    public function remove($files)
    {
        if ($files instanceof \Traversable) {
            $files = \iterator_to_array($files, \false);
        } elseif (!\is_array($files)) {
            $files = [$files];
        }
        $files = \array_reverse($files);
        foreach ($files as $file) {
            if (\is_link($file)) {
                // See https://bugs.php.net/52176
                if (!(self::box('unlink', $file) || '\\' !== \DIRECTORY_SEPARATOR || self::box('rmdir', $file)) && \file_exists($file)) {
                    throw new IOException(\sprintf('Failed to remove symlink "%s": ', $file) . self::$lastError);
                }
            } elseif (\is_dir($file)) {
                $this->remove(new \FilesystemIterator($file, \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS));
                if (!self::box('rmdir', $file) && \file_exists($file)) {
                    throw new IOException(\sprintf('Failed to remove directory "%s": ', $file) . self::$lastError);
                }
            } elseif (!self::box('unlink', $file) && (\str_contains(self::$lastError, 'Permission denied') || \file_exists($file))) {
                throw new IOException(\sprintf('Failed to remove file "%s": ', $file) . self::$lastError);
            }
        }
    }
    /**
     * Change mode for an array of files or directories.
     *
     * @param string|iterable $files     A filename, an array of files, or a \Traversable instance to change mode
     * @param int             $mode      The new mode (octal)
     * @param int             $umask     The mode mask (octal)
     * @param bool            $recursive Whether change the mod recursively or not
     *
     * @throws IOException When the change fails
     */
    public function chmod($files, $mode, $umask = 00, $recursive = \false)
    {
        foreach ($this->toIterable($files) as $file) {
            if ((\PHP_VERSION_ID < 80000 || \is_int($mode)) && \true !== @\chmod($file, $mode & ~$umask)) {
                throw new IOException(\sprintf('Failed to chmod file "%s".', $file), 0, null, $file);
            }
            if ($recursive && \is_dir($file) && !\is_link($file)) {
                $this->chmod(new \FilesystemIterator($file), $mode, $umask, \true);
            }
        }
    }
    /**
     * Change the owner of an array of files or directories.
     *
     * @param string|iterable $files     A filename, an array of files, or a \Traversable instance to change owner
     * @param string|int      $user      A user name or number
     * @param bool            $recursive Whether change the owner recursively or not
     *
     * @throws IOException When the change fails
     */
    public function chown($files, $user, $recursive = \false)
    {
        foreach ($this->toIterable($files) as $file) {
            if ($recursive && \is_dir($file) && !\is_link($file)) {
                $this->chown(new \FilesystemIterator($file), $user, \true);
            }
            if (\is_link($file) && \function_exists('lchown')) {
                if (\true !== @\lchown($file, $user)) {
                    throw new IOException(\sprintf('Failed to chown file "%s".', $file), 0, null, $file);
                }
            } else {
                if (\true !== @\chown($file, $user)) {
                    throw new IOException(\sprintf('Failed to chown file "%s".', $file), 0, null, $file);
                }
            }
        }
    }
    /**
     * Change the group of an array of files or directories.
     *
     * @param string|iterable $files     A filename, an array of files, or a \Traversable instance to change group
     * @param string|int      $group     A group name or number
     * @param bool            $recursive Whether change the group recursively or not
     *
     * @throws IOException When the change fails
     */
    public function chgrp($files, $group, $recursive = \false)
    {
        foreach ($this->toIterable($files) as $file) {
            if ($recursive && \is_dir($file) && !\is_link($file)) {
                $this->chgrp(new \FilesystemIterator($file), $group, \true);
            }
            if (\is_link($file) && \function_exists('lchgrp')) {
                if (\true !== @\lchgrp($file, $group)) {
                    throw new IOException(\sprintf('Failed to chgrp file "%s".', $file), 0, null, $file);
                }
            } else {
                if (\true !== @\chgrp($file, $group)) {
                    throw new IOException(\sprintf('Failed to chgrp file "%s".', $file), 0, null, $file);
                }
            }
        }
    }
    /**
     * Renames a file or a directory.
     *
     * @param string $origin    The origin filename or directory
     * @param string $target    The new filename or directory
     * @param bool   $overwrite Whether to overwrite the target if it already exists
     *
     * @throws IOException When target file or directory already exists
     * @throws IOException When origin cannot be renamed
     */
    public function rename($origin, $target, $overwrite = \false)
    {
        // we check that target does not exist
        if (!$overwrite && $this->isReadable($target)) {
            throw new IOException(\sprintf('Cannot rename because the target "%s" already exists.', $target), 0, null, $target);
        }
        if (\true !== @\rename($origin, $target)) {
            if (\is_dir($origin)) {
                // See https://bugs.php.net/54097 & https://php.net/rename#113943
                $this->mirror($origin, $target, null, ['override' => $overwrite, 'delete' => $overwrite]);
                $this->remove($origin);
                return;
            }
            throw new IOException(\sprintf('Cannot rename "%s" to "%s".', $origin, $target), 0, null, $target);
        }
    }
    /**
     * Tells whether a file exists and is readable.
     *
     * @throws IOException When windows path is longer than 258 characters
     */
    private function isReadable(string $filename) : bool
    {
        $maxPathLength = \PHP_MAXPATHLEN - 2;
        if (\strlen($filename) > $maxPathLength) {
            throw new IOException(\sprintf('Could not check if file is readable because path length exceeds %d characters.', $maxPathLength), 0, null, $filename);
        }
        return \is_readable($filename);
    }
    /**
     * Creates a symbolic link or copy a directory.
     *
     * @param string $originDir     The origin directory path
     * @param string $targetDir     The symbolic link name
     * @param bool   $copyOnWindows Whether to copy files if on Windows
     *
     * @throws IOException When symlink fails
     */
    public function symlink($originDir, $targetDir, $copyOnWindows = \false)
    {
        if ('\\' === \DIRECTORY_SEPARATOR) {
            $originDir = \strtr($originDir, '/', '\\');
            $targetDir = \strtr($targetDir, '/', '\\');
            if ($copyOnWindows) {
                $this->mirror($originDir, $targetDir);
                return;
            }
        }
        $this->mkdir(\dirname($targetDir));
        if (\is_link($targetDir)) {
            if (\readlink($targetDir) === $originDir) {
                return;
            }
            $this->remove($targetDir);
        }
        if (!self::box('symlink', $originDir, $targetDir)) {
            $this->linkException($originDir, $targetDir, 'symbolic');
        }
    }
    /**
     * Creates a hard link, or several hard links to a file.
     *
     * @param string          $originFile  The original file
     * @param string|string[] $targetFiles The target file(s)
     *
     * @throws FileNotFoundException When original file is missing or not a file
     * @throws IOException           When link fails, including if link already exists
     */
    public function hardlink($originFile, $targetFiles)
    {
        if (!$this->exists($originFile)) {
            throw new FileNotFoundException(null, 0, null, $originFile);
        }
        if (!\is_file($originFile)) {
            throw new FileNotFoundException(\sprintf('Origin file "%s" is not a file.', $originFile));
        }
        foreach ($this->toIterable($targetFiles) as $targetFile) {
            if (\is_file($targetFile)) {
                if (\fileinode($originFile) === \fileinode($targetFile)) {
                    continue;
                }
                $this->remove($targetFile);
            }
            if (!self::box('link', $originFile, $targetFile)) {
                $this->linkException($originFile, $targetFile, 'hard');
            }
        }
    }
    /**
     * @param string $linkType Name of the link type, typically 'symbolic' or 'hard'
     */
    private function linkException(string $origin, string $target, string $linkType)
    {
        if (self::$lastError) {
            if ('\\' === \DIRECTORY_SEPARATOR && \str_contains(self::$lastError, 'error code(1314)')) {
                throw new IOException(\sprintf('Unable to create "%s" link due to error code 1314: \'A required privilege is not held by the client\'. Do you have the required Administrator-rights?', $linkType), 0, null, $target);
            }
        }
        throw new IOException(\sprintf('Failed to create "%s" link from "%s" to "%s".', $linkType, $origin, $target), 0, null, $target);
    }
    /**
     * Resolves links in paths.
     *
     * With $canonicalize = false (default)
     *      - if $path does not exist or is not a link, returns null
     *      - if $path is a link, returns the next direct target of the link without considering the existence of the target
     *
     * With $canonicalize = true
     *      - if $path does not exist, returns null
     *      - if $path exists, returns its absolute fully resolved final version
     *
     * @param string $path         A filesystem path
     * @param bool   $canonicalize Whether or not to return a canonicalized path
     *
     * @return string|null
     */
    public function readlink($path, $canonicalize = \false)
    {
        if (!$canonicalize && !\is_link($path)) {
            return null;
        }
        if ($canonicalize) {
            if (!$this->exists($path)) {
                return null;
            }
            if ('\\' === \DIRECTORY_SEPARATOR && \PHP_VERSION_ID < 70410) {
                $path = \readlink($path);
            }
            return \realpath($path);
        }
        if ('\\' === \DIRECTORY_SEPARATOR && \PHP_VERSION_ID < 70400) {
            return \realpath($path);
        }
        return \readlink($path);
    }
    /**
     * Given an existing path, convert it to a path relative to a given starting path.
     *
     * @param string $endPath   Absolute path of target
     * @param string $startPath Absolute path where traversal begins
     *
     * @return string Path of target relative to starting path
     */
    public function makePathRelative($endPath, $startPath)
    {
        if (!$this->isAbsolutePath($startPath)) {
            throw new InvalidArgumentException(\sprintf('The start path "%s" is not absolute.', $startPath));
        }
        if (!$this->isAbsolutePath($endPath)) {
            throw new InvalidArgumentException(\sprintf('The end path "%s" is not absolute.', $endPath));
        }
        // Normalize separators on Windows
        if ('\\' === \DIRECTORY_SEPARATOR) {
            $endPath = \str_replace('\\', '/', $endPath);
            $startPath = \str_replace('\\', '/', $startPath);
        }
        $splitDriveLetter = function ($path) {
            return \strlen($path) > 2 && ':' === $path[1] && '/' === $path[2] && \ctype_alpha($path[0]) ? [\substr($path, 2), \strtoupper($path[0])] : [$path, null];
        };
        $splitPath = function ($path) {
            $result = [];
            foreach (\explode('/', \trim($path, '/')) as $segment) {
                if ('..' === $segment) {
                    \array_pop($result);
                } elseif ('.' !== $segment && '' !== $segment) {
                    $result[] = $segment;
                }
            }
            return $result;
        };
        [$endPath, $endDriveLetter] = $splitDriveLetter($endPath);
        [$startPath, $startDriveLetter] = $splitDriveLetter($startPath);
        $startPathArr = $splitPath($startPath);
        $endPathArr = $splitPath($endPath);
        if ($endDriveLetter && $startDriveLetter && $endDriveLetter != $startDriveLetter) {
            // End path is on another drive, so no relative path exists
            return $endDriveLetter . ':/' . ($endPathArr ? \implode('/', $endPathArr) . '/' : '');
        }
        // Find for which directory the common path stops
        $index = 0;
        while (isset($startPathArr[$index]) && isset($endPathArr[$index]) && $startPathArr[$index] === $endPathArr[$index]) {
            ++$index;
        }
        // Determine how deep the start path is relative to the common path (ie, "web/bundles" = 2 levels)
        if (1 === \count($startPathArr) && '' === $startPathArr[0]) {
            $depth = 0;
        } else {
            $depth = \count($startPathArr) - $index;
        }
        // Repeated "../" for each level need to reach the common path
        $traverser = \str_repeat('../', $depth);
        $endPathRemainder = \implode('/', \array_slice($endPathArr, $index));
        // Construct $endPath from traversing to the common path, then to the remaining $endPath
        $relativePath = $traverser . ('' !== $endPathRemainder ? $endPathRemainder . '/' : '');
        return '' === $relativePath ? './' : $relativePath;
    }
    /**
     * Mirrors a directory to another.
     *
     * Copies files and directories from the origin directory into the target directory. By default:
     *
     *  - existing files in the target directory will be overwritten, except if they are newer (see the `override` option)
     *  - files in the target directory that do not exist in the source directory will not be deleted (see the `delete` option)
     *
     * @param string            $originDir The origin directory
     * @param string            $targetDir The target directory
     * @param \Traversable|null $iterator  Iterator that filters which files and directories to copy, if null a recursive iterator is created
     * @param array             $options   An array of boolean options
     *                                     Valid options are:
     *                                     - $options['override'] If true, target files newer than origin files are overwritten (see copy(), defaults to false)
     *                                     - $options['copy_on_windows'] Whether to copy files instead of links on Windows (see symlink(), defaults to false)
     *                                     - $options['delete'] Whether to delete files that are not in the source directory (defaults to false)
     *
     * @throws IOException When file type is unknown
     */
    public function mirror($originDir, $targetDir, \Traversable $iterator = null, $options = [])
    {
        $targetDir = \rtrim($targetDir, '/\\');
        $originDir = \rtrim($originDir, '/\\');
        $originDirLen = \strlen($originDir);
        if (!$this->exists($originDir)) {
            throw new IOException(\sprintf('The origin directory specified "%s" was not found.', $originDir), 0, null, $originDir);
        }
        // Iterate in destination folder to remove obsolete entries
        if ($this->exists($targetDir) && isset($options['delete']) && $options['delete']) {
            $deleteIterator = $iterator;
            if (null === $deleteIterator) {
                $flags = \FilesystemIterator::SKIP_DOTS;
                $deleteIterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($targetDir, $flags), \RecursiveIteratorIterator::CHILD_FIRST);
            }
            $targetDirLen = \strlen($targetDir);
            foreach ($deleteIterator as $file) {
                $origin = $originDir . \substr($file->getPathname(), $targetDirLen);
                if (!$this->exists($origin)) {
                    $this->remove($file);
                }
            }
        }
        $copyOnWindows = $options['copy_on_windows'] ?? \false;
        if (null === $iterator) {
            $flags = $copyOnWindows ? \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS : \FilesystemIterator::SKIP_DOTS;
            $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($originDir, $flags), \RecursiveIteratorIterator::SELF_FIRST);
        }
        $this->mkdir($targetDir);
        $filesCreatedWhileMirroring = [];
        foreach ($iterator as $file) {
            if ($file->getPathname() === $targetDir || $file->getRealPath() === $targetDir || isset($filesCreatedWhileMirroring[$file->getRealPath()])) {
                continue;
            }
            $target = $targetDir . \substr($file->getPathname(), $originDirLen);
            $filesCreatedWhileMirroring[$target] = \true;
            if (!$copyOnWindows && \is_link($file)) {
                $this->symlink($file->getLinkTarget(), $target);
            } elseif (\is_dir($file)) {
                $this->mkdir($target);
            } elseif (\is_file($file)) {
                $this->copy($file, $target, $options['override'] ?? \false);
            } else {
                throw new IOException(\sprintf('Unable to guess "%s" file type.', $file), 0, null, $file);
            }
        }
    }
    /**
     * Returns whether the file path is an absolute path.
     *
     * @param string $file A file path
     *
     * @return bool
     */
    public function isAbsolutePath($file)
    {
        if (null === $file) {
            @\trigger_error(\sprintf('Calling "%s()" with a null in the $file argument is deprecated since Symfony 4.4.', __METHOD__), \E_USER_DEPRECATED);
        }
        return '' !== (string) $file && (\strspn($file, '/\\', 0, 1) || \strlen($file) > 3 && \ctype_alpha($file[0]) && ':' === $file[1] && \strspn($file, '/\\', 2, 1) || null !== \parse_url($file, \PHP_URL_SCHEME));
    }
    /**
     * Creates a temporary file with support for custom stream wrappers.
     *
     * @param string $dir    The directory where the temporary filename will be created
     * @param string $prefix The prefix of the generated temporary filename
     *                       Note: Windows uses only the first three characters of prefix
     *
     * @return string The new temporary filename (with path), or throw an exception on failure
     */
    public function tempnam($dir, $prefix)
    {
        [$scheme, $hierarchy] = $this->getSchemeAndHierarchy($dir);
        // If no scheme or scheme is "file" or "gs" (Google Cloud) create temp file in local filesystem
        if (null === $scheme || 'file' === $scheme || 'gs' === $scheme) {
            $tmpFile = @\tempnam($hierarchy, $prefix);
            // If tempnam failed or no scheme return the filename otherwise prepend the scheme
            if (\false !== $tmpFile) {
                if (null !== $scheme && 'gs' !== $scheme) {
                    return $scheme . '://' . $tmpFile;
                }
                return $tmpFile;
            }
            throw new IOException('A temporary file could not be created.');
        }
        // Loop until we create a valid temp file or have reached 10 attempts
        for ($i = 0; $i < 10; ++$i) {
            // Create a unique filename
            $tmpFile = $dir . '/' . $prefix . \uniqid(\mt_rand(), \true);
            // Use fopen instead of file_exists as some streams do not support stat
            // Use mode 'x+' to atomically check existence and create to avoid a TOCTOU vulnerability
            $handle = @\fopen($tmpFile, 'x+');
            // If unsuccessful restart the loop
            if (\false === $handle) {
                continue;
            }
            // Close the file if it was successfully opened
            @\fclose($handle);
            return $tmpFile;
        }
        throw new IOException('A temporary file could not be created.');
    }
    /**
     * Atomically dumps content into a file.
     *
     * @param string          $filename The file to be written to
     * @param string|resource $content  The data to write into the file
     *
     * @throws IOException if the file cannot be written to
     */
    public function dumpFile($filename, $content)
    {
        if (\is_array($content)) {
            @\trigger_error(\sprintf('Calling "%s()" with an array in the $content argument is deprecated since Symfony 4.3.', __METHOD__), \E_USER_DEPRECATED);
        }
        $dir = \dirname($filename);
        if (!\is_dir($dir)) {
            $this->mkdir($dir);
        }
        // Will create a temp file with 0600 access rights
        // when the filesystem supports chmod.
        $tmpFile = $this->tempnam($dir, \basename($filename));
        try {
            if (\false === @\file_put_contents($tmpFile, $content)) {
                throw new IOException(\sprintf('Failed to write file "%s".', $filename), 0, null, $filename);
            }
            @\chmod($tmpFile, \file_exists($filename) ? \fileperms($filename) : 0666 & ~\umask());
            $this->rename($tmpFile, $filename, \true);
        } finally {
            if (\file_exists($tmpFile)) {
                @\unlink($tmpFile);
            }
        }
    }
    /**
     * Appends content to an existing file.
     *
     * @param string          $filename The file to which to append content
     * @param string|resource $content  The content to append
     *
     * @throws IOException If the file is not writable
     */
    public function appendToFile($filename, $content)
    {
        if (\is_array($content)) {
            @\trigger_error(\sprintf('Calling "%s()" with an array in the $content argument is deprecated since Symfony 4.3.', __METHOD__), \E_USER_DEPRECATED);
        }
        $dir = \dirname($filename);
        if (!\is_dir($dir)) {
            $this->mkdir($dir);
        }
        if (\false === @\file_put_contents($filename, $content, \FILE_APPEND)) {
            throw new IOException(\sprintf('Failed to write file "%s".', $filename), 0, null, $filename);
        }
    }
    private function toIterable($files) : iterable
    {
        return \is_iterable($files) ? $files : [$files];
    }
    /**
     * Gets a 2-tuple of scheme (may be null) and hierarchical part of a filename (e.g. file:///tmp -> [file, tmp]).
     */
    private function getSchemeAndHierarchy(string $filename) : array
    {
        $components = \explode('://', $filename, 2);
        return 2 === \count($components) ? [$components[0], $components[1]] : [null, $components[0]];
    }
    /**
     * @param mixed ...$args
     *
     * @return mixed
     */
    private static function box(callable $func, ...$args)
    {
        self::$lastError = null;
        \set_error_handler(__CLASS__ . '::handleError');
        try {
            $result = $func(...$args);
            \restore_error_handler();
            return $result;
        } catch (\Throwable $e) {
        }
        \restore_error_handler();
        throw $e;
    }
    /**
     * @internal
     */
    public static function handleError(int $type, string $msg)
    {
        self::$lastError = $msg;
    }
}
<?php

namespace CivixPhar;

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
class JsonException extends \Exception
{
}
/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
\class_alias('CivixPhar\\JsonException', 'JsonException', \false);
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Polyfill\Php73;

/**
 * @author Gabriel Caruso <carusogabriel34@gmail.com>
 * @author Ion Bazan <ion.bazan@gmail.com>
 *
 * @internal
 */
final class Php73
{
    public static $startAt = 1533462603;
    /**
     * @param bool $asNum
     *
     * @return array|float|int
     */
    public static function hrtime($asNum = \false)
    {
        $ns = \microtime(\false);
        $s = \substr($ns, 11) - self::$startAt;
        $ns = 1000000000.0 * (float) $ns;
        if ($asNum) {
            $ns += $s * 1000000000.0;
            return \PHP_INT_SIZE === 4 ? $ns : (int) $ns;
        }
        return [$s, (int) $ns];
    }
}
<?php

namespace CivixPhar;

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
use CivixPhar\Symfony\Polyfill\Php73 as p;
if (\PHP_VERSION_ID >= 70300) {
    return;
}
if (!\function_exists('is_countable')) {
    function is_countable($value)
    {
        return \is_array($value) || $value instanceof \Countable || $value instanceof \ResourceBundle || $value instanceof \SimpleXmlElement;
    }
}
if (!\function_exists('hrtime')) {
    require_once __DIR__ . '/Php73.php';
    p\Php73::$startAt = (int) \microtime(\true);
    function hrtime($as_number = \false)
    {
        return p\Php73::hrtime($as_number);
    }
}
if (!\function_exists('array_key_first')) {
    function array_key_first(array $array)
    {
        foreach ($array as $key => $value) {
            return $key;
        }
    }
}
if (!\function_exists('array_key_last')) {
    function array_key_last(array $array)
    {
        return \key(\array_slice($array, -1, 1, \true));
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarExporter;

use CivixPhar\Symfony\Component\VarExporter\Exception\ExceptionInterface;
use CivixPhar\Symfony\Component\VarExporter\Exception\NotInstantiableTypeException;
use CivixPhar\Symfony\Component\VarExporter\Internal\Hydrator;
use CivixPhar\Symfony\Component\VarExporter\Internal\Registry;
/**
 * A utility class to create objects without calling their constructor.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
final class Instantiator
{
    /**
     * Creates an object and sets its properties without calling its constructor nor any other methods.
     *
     * For example:
     *
     *     // creates an empty instance of Foo
     *     Instantiator::instantiate(Foo::class);
     *
     *     // creates a Foo instance and sets one of its properties
     *     Instantiator::instantiate(Foo::class, ['propertyName' => $propertyValue]);
     *
     *     // creates a Foo instance and sets a private property defined on its parent Bar class
     *     Instantiator::instantiate(Foo::class, [], [
     *         Bar::class => ['privateBarProperty' => $propertyValue],
     *     ]);
     *
     * Instances of ArrayObject, ArrayIterator and SplObjectHash can be created
     * by using the special "\0" property name to define their internal value:
     *
     *     // creates an SplObjectHash where $info1 is attached to $obj1, etc.
     *     Instantiator::instantiate(SplObjectStorage::class, ["\0" => [$obj1, $info1, $obj2, $info2...]]);
     *
     *     // creates an ArrayObject populated with $inputArray
     *     Instantiator::instantiate(ArrayObject::class, ["\0" => [$inputArray]]);
     *
     * @param string $class             The class of the instance to create
     * @param array  $properties        The properties to set on the instance
     * @param array  $privateProperties The private properties to set on the instance,
     *                                  keyed by their declaring class
     *
     * @return object The created instance
     *
     * @throws ExceptionInterface When the instance cannot be created
     */
    public static function instantiate(string $class, array $properties = [], array $privateProperties = [])
    {
        $reflector = Registry::$reflectors[$class] ?? Registry::getClassReflector($class);
        if (Registry::$cloneable[$class]) {
            $wrappedInstance = [clone Registry::$prototypes[$class]];
        } elseif (Registry::$instantiableWithoutConstructor[$class]) {
            $wrappedInstance = [$reflector->newInstanceWithoutConstructor()];
        } elseif (null === Registry::$prototypes[$class]) {
            throw new NotInstantiableTypeException($class);
        } elseif ($reflector->implementsInterface('Serializable') && (\PHP_VERSION_ID < 70400 || !\method_exists($class, '__unserialize'))) {
            $wrappedInstance = [\unserialize('C:' . \strlen($class) . ':"' . $class . '":0:{}')];
        } else {
            $wrappedInstance = [\unserialize('O:' . \strlen($class) . ':"' . $class . '":0:{}')];
        }
        if ($properties) {
            $privateProperties[$class] = isset($privateProperties[$class]) ? $properties + $privateProperties[$class] : $properties;
        }
        foreach ($privateProperties as $class => $properties) {
            if (!$properties) {
                continue;
            }
            foreach ($properties as $name => $value) {
                // because they're also used for "unserialization", hydrators
                // deal with array of instances, so we need to wrap values
                $properties[$name] = [$value];
            }
            (Hydrator::$hydrators[$class] ?? Hydrator::getHydrator($class))($properties, $wrappedInstance);
        }
        return $wrappedInstance[0];
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarExporter;

use CivixPhar\Symfony\Component\VarExporter\Exception\ExceptionInterface;
use CivixPhar\Symfony\Component\VarExporter\Internal\Exporter;
use CivixPhar\Symfony\Component\VarExporter\Internal\Hydrator;
use CivixPhar\Symfony\Component\VarExporter\Internal\Registry;
use CivixPhar\Symfony\Component\VarExporter\Internal\Values;
/**
 * Exports serializable PHP values to PHP code.
 *
 * VarExporter allows serializing PHP data structures to plain PHP code (like var_export())
 * while preserving all the semantics associated with serialize() (unlike var_export()).
 *
 * By leveraging OPcache, the generated PHP code is faster than doing the same with unserialize().
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
final class VarExporter
{
    /**
     * Exports a serializable PHP value to PHP code.
     *
     * @param mixed $value          The value to export
     * @param bool  &$isStaticValue Set to true after execution if the provided value is static, false otherwise
     *
     * @return string The value exported as PHP code
     *
     * @throws ExceptionInterface When the provided value cannot be serialized
     */
    public static function export($value, bool &$isStaticValue = null) : string
    {
        $isStaticValue = \true;
        if (!\is_object($value) && !(\is_array($value) && $value) && !$value instanceof \__PHP_Incomplete_Class && !\is_resource($value) || $value instanceof \UnitEnum) {
            return Exporter::export($value);
        }
        $objectsPool = new \SplObjectStorage();
        $refsPool = [];
        $objectsCount = 0;
        try {
            $value = Exporter::prepare([$value], $objectsPool, $refsPool, $objectsCount, $isStaticValue)[0];
        } finally {
            $references = [];
            foreach ($refsPool as $i => $v) {
                if ($v[0]->count) {
                    $references[1 + $i] = $v[2];
                }
                $v[0] = $v[1];
            }
        }
        if ($isStaticValue) {
            return Exporter::export($value);
        }
        $classes = [];
        $values = [];
        $states = [];
        foreach ($objectsPool as $i => $v) {
            [, $classes[], $values[], $wakeup] = $objectsPool[$v];
            if (0 < $wakeup) {
                $states[$wakeup] = $i;
            } elseif (0 > $wakeup) {
                $states[-$wakeup] = [$i, \array_pop($values)];
                $values[] = [];
            }
        }
        \ksort($states);
        $wakeups = [null];
        foreach ($states as $k => $v) {
            if (\is_array($v)) {
                $wakeups[-$v[0]] = $v[1];
            } else {
                $wakeups[] = $v;
            }
        }
        if (null === $wakeups[0]) {
            unset($wakeups[0]);
        }
        $properties = [];
        foreach ($values as $i => $vars) {
            foreach ($vars as $class => $values) {
                foreach ($values as $name => $v) {
                    $properties[$class][$name][$i] = $v;
                }
            }
        }
        if ($classes || $references) {
            $value = new Hydrator(new Registry($classes), $references ? new Values($references) : null, $properties, $value, $wakeups);
        } else {
            $isStaticValue = \true;
        }
        return Exporter::export($value);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarExporter\Exception;

class ClassNotFoundException extends \Exception implements ExceptionInterface
{
    public function __construct(string $class, \Throwable $previous = null)
    {
        parent::__construct(\sprintf('Class "%s" not found.', $class), 0, $previous);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarExporter\Exception;

interface ExceptionInterface extends \Throwable
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarExporter\Exception;

class NotInstantiableTypeException extends \Exception implements ExceptionInterface
{
    public function __construct(string $type, \Throwable $previous = null)
    {
        parent::__construct(\sprintf('Type "%s" is not instantiable.', $type), 0, $previous);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarExporter\Internal;

use CivixPhar\Symfony\Component\VarExporter\Exception\NotInstantiableTypeException;
/**
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @internal
 */
class Exporter
{
    /**
     * Prepares an array of values for VarExporter.
     *
     * For performance this method is public and has no type-hints.
     *
     * @param array             &$values
     * @param \SplObjectStorage $objectsPool
     * @param array             &$refsPool
     * @param int               &$objectsCount
     * @param bool              &$valuesAreStatic
     *
     * @return array
     *
     * @throws NotInstantiableTypeException When a value cannot be serialized
     */
    public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount, &$valuesAreStatic)
    {
        $refs = $values;
        foreach ($values as $k => $value) {
            if (\is_resource($value)) {
                throw new NotInstantiableTypeException(\get_resource_type($value) . ' resource');
            }
            $refs[$k] = $objectsPool;
            if ($isRef = !($valueIsStatic = $values[$k] !== $objectsPool)) {
                $values[$k] =& $value;
                // Break hard references to make $values completely
                unset($value);
                // independent from the original structure
                $refs[$k] = $value = $values[$k];
                if ($value instanceof Reference && 0 > $value->id) {
                    $valuesAreStatic = \false;
                    ++$value->count;
                    continue;
                }
                $refsPool[] = [&$refs[$k], $value, &$value];
                $refs[$k] = $values[$k] = new Reference(-\count($refsPool), $value);
            }
            if (\is_array($value)) {
                if ($value) {
                    $value = self::prepare($value, $objectsPool, $refsPool, $objectsCount, $valueIsStatic);
                }
                goto handle_value;
            } elseif (!\is_object($value) && !$value instanceof \__PHP_Incomplete_Class || $value instanceof \UnitEnum) {
                goto handle_value;
            }
            $valueIsStatic = \false;
            if (isset($objectsPool[$value])) {
                ++$objectsCount;
                $value = new Reference($objectsPool[$value][0]);
                goto handle_value;
            }
            $class = \get_class($value);
            $reflector = Registry::$reflectors[$class] ?? Registry::getClassReflector($class);
            if ($reflector->hasMethod('__serialize')) {
                if (!$reflector->getMethod('__serialize')->isPublic()) {
                    throw new \Error(\sprintf('Call to %s method "%s::__serialize()".', $reflector->getMethod('__serialize')->isProtected() ? 'protected' : 'private', $class));
                }
                if (!\is_array($properties = $value->__serialize())) {
                    throw new \TypeError($class . '::__serialize() must return an array');
                }
                goto prepare_value;
            }
            $properties = [];
            $sleep = null;
            $arrayValue = (array) $value;
            $proto = Registry::$prototypes[$class];
            if (($value instanceof \ArrayIterator || $value instanceof \ArrayObject) && null !== $proto) {
                // ArrayIterator and ArrayObject need special care because their "flags"
                // option changes the behavior of the (array) casting operator.
                $properties = self::getArrayObjectProperties($value, $arrayValue, $proto);
                // populates Registry::$prototypes[$class] with a new instance
                Registry::getClassReflector($class, Registry::$instantiableWithoutConstructor[$class], Registry::$cloneable[$class]);
            } elseif ($value instanceof \SplObjectStorage && Registry::$cloneable[$class] && null !== $proto) {
                // By implementing Serializable, SplObjectStorage breaks
                // internal references; let's deal with it on our own.
                foreach (clone $value as $v) {
                    $properties[] = $v;
                    $properties[] = $value[$v];
                }
                $properties = ['SplObjectStorage' => ["\x00" => $properties]];
            } elseif ($value instanceof \Serializable || $value instanceof \__PHP_Incomplete_Class) {
                ++$objectsCount;
                $objectsPool[$value] = [$id = \count($objectsPool), \serialize($value), [], 0];
                $value = new Reference($id);
                goto handle_value;
            }
            if (\method_exists($class, '__sleep')) {
                if (!\is_array($sleep = $value->__sleep())) {
                    \trigger_error('serialize(): __sleep should return an array only containing the names of instance-variables to serialize', \E_USER_NOTICE);
                    $value = null;
                    goto handle_value;
                }
                foreach ($sleep as $name) {
                    if (\property_exists($value, $name) && !$reflector->hasProperty($name)) {
                        $arrayValue[$name] = $value->{$name};
                    }
                }
                $sleep = \array_flip($sleep);
            }
            $proto = (array) $proto;
            foreach ($arrayValue as $name => $v) {
                $i = 0;
                $n = (string) $name;
                if ('' === $n || "\x00" !== $n[0]) {
                    $c = 'stdClass';
                } elseif ('*' === $n[1]) {
                    $n = \substr($n, 3);
                    $c = $reflector->getProperty($n)->class;
                    if ('Error' === $c) {
                        $c = 'TypeError';
                    } elseif ('Exception' === $c) {
                        $c = 'ErrorException';
                    }
                } else {
                    $i = \strpos($n, "\x00", 2);
                    $c = \substr($n, 1, $i - 1);
                    $n = \substr($n, 1 + $i);
                }
                if (null !== $sleep) {
                    if (!isset($sleep[$n]) || $i && $c !== $class) {
                        continue;
                    }
                    $sleep[$n] = \false;
                }
                if (!\array_key_exists($name, $proto) || $proto[$name] !== $v || "\x00Error\x00trace" === $name || "\x00Exception\x00trace" === $name) {
                    $properties[$c][$n] = $v;
                }
            }
            if ($sleep) {
                foreach ($sleep as $n => $v) {
                    if (\false !== $v) {
                        \trigger_error(\sprintf('serialize(): "%s" returned as member variable from __sleep() but does not exist', $n), \E_USER_NOTICE);
                    }
                }
            }
            prepare_value:
            $objectsPool[$value] = [$id = \count($objectsPool)];
            $properties = self::prepare($properties, $objectsPool, $refsPool, $objectsCount, $valueIsStatic);
            ++$objectsCount;
            $objectsPool[$value] = [$id, $class, $properties, \method_exists($class, '__unserialize') ? -$objectsCount : (\method_exists($class, '__wakeup') ? $objectsCount : 0)];
            $value = new Reference($id);
            handle_value:
            if ($isRef) {
                unset($value);
                // Break the hard reference created above
            } elseif (!$valueIsStatic) {
                $values[$k] = $value;
            }
            $valuesAreStatic = $valueIsStatic && $valuesAreStatic;
        }
        return $values;
    }
    public static function export($value, $indent = '')
    {
        switch (\true) {
            case \is_int($value) || \is_float($value) || $value instanceof \UnitEnum:
                return \var_export($value, \true);
            case [] === $value:
                return '[]';
            case \false === $value:
                return 'false';
            case \true === $value:
                return 'true';
            case null === $value:
                return 'null';
            case '' === $value:
                return "''";
        }
        if ($value instanceof Reference) {
            if (0 <= $value->id) {
                return '$o[' . $value->id . ']';
            }
            if (!$value->count) {
                return self::export($value->value, $indent);
            }
            $value = -$value->id;
            return '&$r[' . $value . ']';
        }
        $subIndent = $indent . '    ';
        if (\is_string($value)) {
            $code = \sprintf("'%s'", \addcslashes($value, "'\\"));
            $code = \preg_replace_callback('/([\\0\\r\\n]++)(.)/', function ($m) use($subIndent) {
                $m[1] = \sprintf('\'."%s".\'', \str_replace(["\x00", "\r", "\n", '\\n\\'], ['\\0', '\\r', '\\n', '\\n"' . "\n" . $subIndent . '."\\'], $m[1]));
                if ("'" === $m[2]) {
                    return \substr($m[1], 0, -2);
                }
                if ('n".\'' === \substr($m[1], -4)) {
                    return \substr_replace($m[1], "\n" . $subIndent . ".'" . $m[2], -2);
                }
                return $m[1] . $m[2];
            }, $code, -1, $count);
            if ($count && 0 === \strpos($code, "''.")) {
                $code = \substr($code, 3);
            }
            return $code;
        }
        if (\is_array($value)) {
            $j = -1;
            $code = '';
            foreach ($value as $k => $v) {
                $code .= $subIndent;
                if (!\is_int($k) || 1 !== $k - $j) {
                    $code .= self::export($k, $subIndent) . ' => ';
                }
                if (\is_int($k) && $k > $j) {
                    $j = $k;
                }
                $code .= self::export($v, $subIndent) . ",\n";
            }
            return "[\n" . $code . $indent . ']';
        }
        if ($value instanceof Values) {
            $code = $subIndent . "\$r = [],\n";
            foreach ($value->values as $k => $v) {
                $code .= $subIndent . '$r[' . $k . '] = ' . self::export($v, $subIndent) . ",\n";
            }
            return "[\n" . $code . $indent . ']';
        }
        if ($value instanceof Registry) {
            return self::exportRegistry($value, $indent, $subIndent);
        }
        if ($value instanceof Hydrator) {
            return self::exportHydrator($value, $indent, $subIndent);
        }
        throw new \UnexpectedValueException(\sprintf('Cannot export value of type "%s".', \is_object($value) ? \get_class($value) : \gettype($value)));
    }
    private static function exportRegistry(Registry $value, string $indent, string $subIndent) : string
    {
        $code = '';
        $serializables = [];
        $seen = [];
        $prototypesAccess = 0;
        $factoriesAccess = 0;
        $r = '\\' . Registry::class;
        $j = -1;
        foreach ($value as $k => $class) {
            if (':' === ($class[1] ?? null)) {
                $serializables[$k] = $class;
                continue;
            }
            if (!Registry::$instantiableWithoutConstructor[$class]) {
                if (\is_subclass_of($class, 'Serializable') && !\method_exists($class, '__unserialize')) {
                    $serializables[$k] = 'C:' . \strlen($class) . ':"' . $class . '":0:{}';
                } else {
                    $serializables[$k] = 'O:' . \strlen($class) . ':"' . $class . '":0:{}';
                }
                if (\is_subclass_of($class, 'Throwable')) {
                    $eol = \is_subclass_of($class, 'Error') ? "\x00Error\x00" : "\x00Exception\x00";
                    $serializables[$k] = \substr_replace($serializables[$k], '1:{s:' . (5 + \strlen($eol)) . ':"' . $eol . 'trace";a:0:{}}', -4);
                }
                continue;
            }
            $code .= $subIndent . (1 !== $k - $j ? $k . ' => ' : '');
            $j = $k;
            $eol = ",\n";
            $c = '[' . self::export($class) . ']';
            if ($seen[$class] ?? \false) {
                if (Registry::$cloneable[$class]) {
                    ++$prototypesAccess;
                    $code .= 'clone $p' . $c;
                } else {
                    ++$factoriesAccess;
                    $code .= '$f' . $c . '()';
                }
            } else {
                $seen[$class] = \true;
                if (Registry::$cloneable[$class]) {
                    $code .= 'clone (' . ($prototypesAccess++ ? '$p' : '($p = &' . $r . '::$prototypes)') . $c . ' ?? ' . $r . '::p';
                } else {
                    $code .= '(' . ($factoriesAccess++ ? '$f' : '($f = &' . $r . '::$factories)') . $c . ' ?? ' . $r . '::f';
                    $eol = '()' . $eol;
                }
                $code .= '(' . \substr($c, 1, -1) . '))';
            }
            $code .= $eol;
        }
        if (1 === $prototypesAccess) {
            $code = \str_replace('($p = &' . $r . '::$prototypes)', $r . '::$prototypes', $code);
        }
        if (1 === $factoriesAccess) {
            $code = \str_replace('($f = &' . $r . '::$factories)', $r . '::$factories', $code);
        }
        if ('' !== $code) {
            $code = "\n" . $code . $indent;
        }
        if ($serializables) {
            $code = $r . '::unserialize([' . $code . '], ' . self::export($serializables, $indent) . ')';
        } else {
            $code = '[' . $code . ']';
        }
        return '$o = ' . $code;
    }
    private static function exportHydrator(Hydrator $value, string $indent, string $subIndent) : string
    {
        $code = '';
        foreach ($value->properties as $class => $properties) {
            $code .= $subIndent . '    ' . self::export($class) . ' => ' . self::export($properties, $subIndent . '    ') . ",\n";
        }
        $code = [self::export($value->registry, $subIndent), self::export($value->values, $subIndent), '' !== $code ? "[\n" . $code . $subIndent . ']' : '[]', self::export($value->value, $subIndent), self::export($value->wakeups, $subIndent)];
        return '\\' . \get_class($value) . "::hydrate(\n" . $subIndent . \implode(",\n" . $subIndent, $code) . "\n" . $indent . ')';
    }
    /**
     * @param \ArrayIterator|\ArrayObject $value
     * @param \ArrayIterator|\ArrayObject $proto
     */
    private static function getArrayObjectProperties($value, array &$arrayValue, $proto) : array
    {
        $reflector = $value instanceof \ArrayIterator ? 'ArrayIterator' : 'ArrayObject';
        $reflector = Registry::$reflectors[$reflector] ?? Registry::getClassReflector($reflector);
        $properties = [$arrayValue, $reflector->getMethod('getFlags')->invoke($value), $value instanceof \ArrayObject ? $reflector->getMethod('getIteratorClass')->invoke($value) : 'ArrayIterator'];
        $reflector = $reflector->getMethod('setFlags');
        $reflector->invoke($proto, \ArrayObject::STD_PROP_LIST);
        if ($properties[1] & \ArrayObject::STD_PROP_LIST) {
            $reflector->invoke($value, 0);
            $properties[0] = (array) $value;
        } else {
            $reflector->invoke($value, \ArrayObject::STD_PROP_LIST);
            $arrayValue = (array) $value;
        }
        $reflector->invoke($value, $properties[1]);
        if ([[], 0, 'ArrayIterator'] === $properties) {
            $properties = [];
        } else {
            if ('ArrayIterator' === $properties[2]) {
                unset($properties[2]);
            }
            $properties = [$reflector->class => ["\x00" => $properties]];
        }
        return $properties;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarExporter\Internal;

/**
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @internal
 */
class Values
{
    public $values;
    public function __construct(array $values)
    {
        $this->values = $values;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarExporter\Internal;

use CivixPhar\Symfony\Component\VarExporter\Exception\ClassNotFoundException;
use CivixPhar\Symfony\Component\VarExporter\Exception\NotInstantiableTypeException;
/**
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @internal
 */
class Registry
{
    public static $reflectors = [];
    public static $prototypes = [];
    public static $factories = [];
    public static $cloneable = [];
    public static $instantiableWithoutConstructor = [];
    public function __construct(array $classes)
    {
        foreach ($classes as $i => $class) {
            $this->{$i} = $class;
        }
    }
    public static function unserialize($objects, $serializables)
    {
        $unserializeCallback = \ini_set('unserialize_callback_func', __CLASS__ . '::getClassReflector');
        try {
            foreach ($serializables as $k => $v) {
                $objects[$k] = \unserialize($v);
            }
        } finally {
            \ini_set('unserialize_callback_func', $unserializeCallback);
        }
        return $objects;
    }
    public static function p($class)
    {
        self::getClassReflector($class, \true, \true);
        return self::$prototypes[$class];
    }
    public static function f($class)
    {
        $reflector = self::$reflectors[$class] ?? self::getClassReflector($class, \true, \false);
        return self::$factories[$class] = \Closure::fromCallable([$reflector, 'newInstanceWithoutConstructor']);
    }
    public static function getClassReflector($class, $instantiableWithoutConstructor = \false, $cloneable = null)
    {
        if (!($isClass = \class_exists($class)) && !\interface_exists($class, \false) && !\trait_exists($class, \false)) {
            throw new ClassNotFoundException($class);
        }
        $reflector = new \ReflectionClass($class);
        if ($instantiableWithoutConstructor) {
            $proto = $reflector->newInstanceWithoutConstructor();
        } elseif (!$isClass || $reflector->isAbstract()) {
            throw new NotInstantiableTypeException($class);
        } elseif ($reflector->name !== $class) {
            $reflector = self::$reflectors[$name = $reflector->name] ?? self::getClassReflector($name, \false, $cloneable);
            self::$cloneable[$class] = self::$cloneable[$name];
            self::$instantiableWithoutConstructor[$class] = self::$instantiableWithoutConstructor[$name];
            self::$prototypes[$class] = self::$prototypes[$name];
            return self::$reflectors[$class] = $reflector;
        } else {
            try {
                $proto = $reflector->newInstanceWithoutConstructor();
                $instantiableWithoutConstructor = \true;
            } catch (\ReflectionException $e) {
                $proto = $reflector->implementsInterface('Serializable') && !\method_exists($class, '__unserialize') ? 'C:' : 'O:';
                if ('C:' === $proto && !$reflector->getMethod('unserialize')->isInternal()) {
                    $proto = null;
                } else {
                    try {
                        $proto = @\unserialize($proto . \strlen($class) . ':"' . $class . '":0:{}');
                    } catch (\Exception $e) {
                        if (__FILE__ !== $e->getFile()) {
                            throw $e;
                        }
                        throw new NotInstantiableTypeException($class, $e);
                    }
                    if (\false === $proto) {
                        throw new NotInstantiableTypeException($class);
                    }
                }
            }
            if (null !== $proto && !$proto instanceof \Throwable && !$proto instanceof \Serializable && !\method_exists($class, '__sleep') && (\PHP_VERSION_ID < 70400 || !\method_exists($class, '__serialize'))) {
                try {
                    \serialize($proto);
                } catch (\Exception $e) {
                    throw new NotInstantiableTypeException($class, $e);
                }
            }
        }
        if (null === $cloneable) {
            if (($proto instanceof \Reflector || $proto instanceof \ReflectionGenerator || $proto instanceof \ReflectionType || $proto instanceof \IteratorIterator || $proto instanceof \RecursiveIteratorIterator) && (!$proto instanceof \Serializable && !\method_exists($proto, '__wakeup') && (\PHP_VERSION_ID < 70400 || !\method_exists($class, '__unserialize')))) {
                throw new NotInstantiableTypeException($class);
            }
            $cloneable = $reflector->isCloneable() && !$reflector->hasMethod('__clone');
        }
        self::$cloneable[$class] = $cloneable;
        self::$instantiableWithoutConstructor[$class] = $instantiableWithoutConstructor;
        self::$prototypes[$class] = $proto;
        if ($proto instanceof \Throwable) {
            static $setTrace;
            if (null === $setTrace) {
                $setTrace = [new \ReflectionProperty(\Error::class, 'trace'), new \ReflectionProperty(\Exception::class, 'trace')];
                $setTrace[0]->setAccessible(\true);
                $setTrace[1]->setAccessible(\true);
                $setTrace[0] = \Closure::fromCallable([$setTrace[0], 'setValue']);
                $setTrace[1] = \Closure::fromCallable([$setTrace[1], 'setValue']);
            }
            $setTrace[$proto instanceof \Exception]($proto, []);
        }
        return self::$reflectors[$class] = $reflector;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarExporter\Internal;

/**
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @internal
 */
class Reference
{
    public $id;
    public $value;
    public $count = 0;
    public function __construct(int $id, $value = null)
    {
        $this->id = $id;
        $this->value = $value;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\VarExporter\Internal;

use CivixPhar\Symfony\Component\VarExporter\Exception\ClassNotFoundException;
/**
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @internal
 */
class Hydrator
{
    public static $hydrators = [];
    public $registry;
    public $values;
    public $properties;
    public $value;
    public $wakeups;
    public function __construct(?Registry $registry, ?Values $values, array $properties, $value, array $wakeups)
    {
        $this->registry = $registry;
        $this->values = $values;
        $this->properties = $properties;
        $this->value = $value;
        $this->wakeups = $wakeups;
    }
    public static function hydrate($objects, $values, $properties, $value, $wakeups)
    {
        foreach ($properties as $class => $vars) {
            (self::$hydrators[$class] ?? self::getHydrator($class))($vars, $objects);
        }
        foreach ($wakeups as $k => $v) {
            if (\is_array($v)) {
                $objects[-$k]->__unserialize($v);
            } else {
                $objects[$v]->__wakeup();
            }
        }
        return $value;
    }
    public static function getHydrator($class)
    {
        if ('stdClass' === $class) {
            return self::$hydrators[$class] = static function ($properties, $objects) {
                foreach ($properties as $name => $values) {
                    foreach ($values as $i => $v) {
                        $objects[$i]->{$name} = $v;
                    }
                }
            };
        }
        if (!\class_exists($class) && !\interface_exists($class, \false) && !\trait_exists($class, \false)) {
            throw new ClassNotFoundException($class);
        }
        $classReflector = new \ReflectionClass($class);
        if (!$classReflector->isInternal()) {
            return self::$hydrators[$class] = (self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'))->bindTo(null, $class);
        }
        if ($classReflector->name !== $class) {
            return self::$hydrators[$classReflector->name] ?? self::getHydrator($classReflector->name);
        }
        switch ($class) {
            case 'ArrayIterator':
            case 'ArrayObject':
                $constructor = \Closure::fromCallable([$classReflector->getConstructor(), 'invokeArgs']);
                return self::$hydrators[$class] = static function ($properties, $objects) use($constructor) {
                    foreach ($properties as $name => $values) {
                        if ("\x00" !== $name) {
                            foreach ($values as $i => $v) {
                                $objects[$i]->{$name} = $v;
                            }
                        }
                    }
                    foreach ($properties["\x00"] ?? [] as $i => $v) {
                        $constructor($objects[$i], $v);
                    }
                };
            case 'ErrorException':
                return self::$hydrators[$class] = (self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'))->bindTo(null, new class extends \ErrorException
                {
                });
            case 'TypeError':
                return self::$hydrators[$class] = (self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'))->bindTo(null, new class extends \Error
                {
                });
            case 'SplObjectStorage':
                return self::$hydrators[$class] = static function ($properties, $objects) {
                    foreach ($properties as $name => $values) {
                        if ("\x00" === $name) {
                            foreach ($values as $i => $v) {
                                for ($j = 0; $j < \count($v); ++$j) {
                                    $objects[$i]->attach($v[$j], $v[++$j]);
                                }
                            }
                            continue;
                        }
                        foreach ($values as $i => $v) {
                            $objects[$i]->{$name} = $v;
                        }
                    }
                };
        }
        $propertySetters = [];
        foreach ($classReflector->getProperties() as $propertyReflector) {
            if (!$propertyReflector->isStatic()) {
                $propertyReflector->setAccessible(\true);
                $propertySetters[$propertyReflector->name] = \Closure::fromCallable([$propertyReflector, 'setValue']);
            }
        }
        if (!$propertySetters) {
            return self::$hydrators[$class] = self::$hydrators['stdClass'] ?? self::getHydrator('stdClass');
        }
        return self::$hydrators[$class] = static function ($properties, $objects) use($propertySetters) {
            foreach ($properties as $name => $values) {
                if ($setValue = $propertySetters[$name] ?? null) {
                    foreach ($values as $i => $v) {
                        $setValue($objects[$i], $v);
                    }
                    continue;
                }
                foreach ($values as $i => $v) {
                    $objects[$i]->{$name} = $v;
                }
            }
        };
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Process;

use CivixPhar\Symfony\Component\Process\Exception\LogicException;
use CivixPhar\Symfony\Component\Process\Exception\RuntimeException;
/**
 * PhpProcess runs a PHP script in an independent process.
 *
 *     $p = new PhpProcess('<?php echo "foo"; ?>');
 *     $p->run();
 *     print $p->getOutput()."\n";
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class PhpProcess extends Process
{
    /**
     * @param string      $script  The PHP script to run (as a string)
     * @param string|null $cwd     The working directory or null to use the working dir of the current PHP process
     * @param array|null  $env     The environment variables or null to use the same environment as the current PHP process
     * @param int         $timeout The timeout in seconds
     * @param array|null  $php     Path to the PHP binary to use with any additional arguments
     */
    public function __construct(string $script, string $cwd = null, array $env = null, int $timeout = 60, array $php = null)
    {
        if (null === $php) {
            $executableFinder = new PhpExecutableFinder();
            $php = $executableFinder->find(\false);
            $php = \false === $php ? null : \array_merge([$php], $executableFinder->findArguments());
        }
        if ('phpdbg' === \PHP_SAPI) {
            $file = \tempnam(\sys_get_temp_dir(), 'dbg');
            \file_put_contents($file, $script);
            \register_shutdown_function('unlink', $file);
            $php[] = $file;
            $script = null;
        }
        parent::__construct($php, $cwd, $env, $script, $timeout);
    }
    /**
     * {@inheritdoc}
     */
    public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60)
    {
        throw new LogicException(\sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class));
    }
    /**
     * Sets the path to the PHP binary to use.
     *
     * @deprecated since Symfony 4.2, use the $php argument of the constructor instead.
     */
    public function setPhpBinary($php)
    {
        @\trigger_error(\sprintf('The "%s()" method is deprecated since Symfony 4.2, use the $php argument of the constructor instead.', __METHOD__), \E_USER_DEPRECATED);
        $this->setCommandLine($php);
    }
    /**
     * {@inheritdoc}
     */
    public function start(callable $callback = null, array $env = [])
    {
        if (null === $this->getCommandLine()) {
            throw new RuntimeException('Unable to find the PHP executable.');
        }
        parent::start($callback, $env);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Process;

use CivixPhar\Symfony\Component\Process\Exception\RuntimeException;
/**
 * Provides a way to continuously write to the input of a Process until the InputStream is closed.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
class InputStream implements \IteratorAggregate
{
    /** @var callable|null */
    private $onEmpty = null;
    private $input = [];
    private $open = \true;
    /**
     * Sets a callback that is called when the write buffer becomes empty.
     */
    public function onEmpty(callable $onEmpty = null)
    {
        $this->onEmpty = $onEmpty;
    }
    /**
     * Appends an input to the write buffer.
     *
     * @param resource|string|int|float|bool|\Traversable|null $input The input to append as scalar,
     *                                                                stream resource or \Traversable
     */
    public function write($input)
    {
        if (null === $input) {
            return;
        }
        if ($this->isClosed()) {
            throw new RuntimeException(\sprintf('"%s" is closed.', static::class));
        }
        $this->input[] = ProcessUtils::validateInput(__METHOD__, $input);
    }
    /**
     * Closes the write buffer.
     */
    public function close()
    {
        $this->open = \false;
    }
    /**
     * Tells whether the write buffer is closed or not.
     */
    public function isClosed()
    {
        return !$this->open;
    }
    /**
     * @return \Traversable
     */
    #[\ReturnTypeWillChange]
    public function getIterator()
    {
        $this->open = \true;
        while ($this->open || $this->input) {
            if (!$this->input) {
                (yield '');
                continue;
            }
            $current = \array_shift($this->input);
            if ($current instanceof \Iterator) {
                yield from $current;
            } else {
                (yield $current);
            }
            if (!$this->input && $this->open && null !== ($onEmpty = $this->onEmpty)) {
                $this->write($onEmpty($this));
            }
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Process\Pipes;

use CivixPhar\Symfony\Component\Process\Exception\RuntimeException;
use CivixPhar\Symfony\Component\Process\Process;
/**
 * WindowsPipes implementation uses temporary files as handles.
 *
 * @see https://bugs.php.net/51800
 * @see https://bugs.php.net/65650
 *
 * @author Romain Neutron <imprec@gmail.com>
 *
 * @internal
 */
class WindowsPipes extends AbstractPipes
{
    private $files = [];
    private $fileHandles = [];
    private $lockHandles = [];
    private $readBytes = [Process::STDOUT => 0, Process::STDERR => 0];
    private $haveReadSupport;
    public function __construct($input, bool $haveReadSupport)
    {
        $this->haveReadSupport = $haveReadSupport;
        if ($this->haveReadSupport) {
            // Fix for PHP bug #51800: reading from STDOUT pipe hangs forever on Windows if the output is too big.
            // Workaround for this problem is to use temporary files instead of pipes on Windows platform.
            //
            // @see https://bugs.php.net/51800
            $pipes = [Process::STDOUT => Process::OUT, Process::STDERR => Process::ERR];
            $tmpDir = \sys_get_temp_dir();
            $lastError = 'unknown reason';
            \set_error_handler(function ($type, $msg) use(&$lastError) {
                $lastError = $msg;
            });
            for ($i = 0;; ++$i) {
                foreach ($pipes as $pipe => $name) {
                    $file = \sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name);
                    if (!($h = \fopen($file . '.lock', 'w'))) {
                        if (\file_exists($file . '.lock')) {
                            continue 2;
                        }
                        \restore_error_handler();
                        throw new RuntimeException('A temporary file could not be opened to write the process output: ' . $lastError);
                    }
                    if (!\flock($h, \LOCK_EX | \LOCK_NB)) {
                        continue 2;
                    }
                    if (isset($this->lockHandles[$pipe])) {
                        \flock($this->lockHandles[$pipe], \LOCK_UN);
                        \fclose($this->lockHandles[$pipe]);
                    }
                    $this->lockHandles[$pipe] = $h;
                    if (!($h = \fopen($file, 'w')) || !\fclose($h) || !($h = \fopen($file, 'r'))) {
                        \flock($this->lockHandles[$pipe], \LOCK_UN);
                        \fclose($this->lockHandles[$pipe]);
                        unset($this->lockHandles[$pipe]);
                        continue 2;
                    }
                    $this->fileHandles[$pipe] = $h;
                    $this->files[$pipe] = $file;
                }
                break;
            }
            \restore_error_handler();
        }
        parent::__construct($input);
    }
    /**
     * @return array
     */
    public function __sleep()
    {
        throw new \BadMethodCallException('Cannot serialize ' . __CLASS__);
    }
    public function __wakeup()
    {
        throw new \BadMethodCallException('Cannot unserialize ' . __CLASS__);
    }
    public function __destruct()
    {
        $this->close();
    }
    /**
     * {@inheritdoc}
     */
    public function getDescriptors() : array
    {
        if (!$this->haveReadSupport) {
            $nullstream = \fopen('NUL', 'c');
            return [['pipe', 'r'], $nullstream, $nullstream];
        }
        // We're not using pipe on Windows platform as it hangs (https://bugs.php.net/51800)
        // We're not using file handles as it can produce corrupted output https://bugs.php.net/65650
        // So we redirect output within the commandline and pass the nul device to the process
        return [['pipe', 'r'], ['file', 'NUL', 'w'], ['file', 'NUL', 'w']];
    }
    /**
     * {@inheritdoc}
     */
    public function getFiles() : array
    {
        return $this->files;
    }
    /**
     * {@inheritdoc}
     */
    public function readAndWrite(bool $blocking, bool $close = \false) : array
    {
        $this->unblock();
        $w = $this->write();
        $read = $r = $e = [];
        if ($blocking) {
            if ($w) {
                @\stream_select($r, $w, $e, 0, Process::TIMEOUT_PRECISION * 1000000.0);
            } elseif ($this->fileHandles) {
                \usleep(Process::TIMEOUT_PRECISION * 1000000.0);
            }
        }
        foreach ($this->fileHandles as $type => $fileHandle) {
            $data = \stream_get_contents($fileHandle, -1, $this->readBytes[$type]);
            if (isset($data[0])) {
                $this->readBytes[$type] += \strlen($data);
                $read[$type] = $data;
            }
            if ($close) {
                \ftruncate($fileHandle, 0);
                \fclose($fileHandle);
                \flock($this->lockHandles[$type], \LOCK_UN);
                \fclose($this->lockHandles[$type]);
                unset($this->fileHandles[$type], $this->lockHandles[$type]);
            }
        }
        return $read;
    }
    /**
     * {@inheritdoc}
     */
    public function haveReadSupport() : bool
    {
        return $this->haveReadSupport;
    }
    /**
     * {@inheritdoc}
     */
    public function areOpen() : bool
    {
        return $this->pipes && $this->fileHandles;
    }
    /**
     * {@inheritdoc}
     */
    public function close()
    {
        parent::close();
        foreach ($this->fileHandles as $type => $handle) {
            \ftruncate($handle, 0);
            \fclose($handle);
            \flock($this->lockHandles[$type], \LOCK_UN);
            \fclose($this->lockHandles[$type]);
        }
        $this->fileHandles = $this->lockHandles = [];
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Process\Pipes;

use CivixPhar\Symfony\Component\Process\Process;
/**
 * UnixPipes implementation uses unix pipes as handles.
 *
 * @author Romain Neutron <imprec@gmail.com>
 *
 * @internal
 */
class UnixPipes extends AbstractPipes
{
    private $ttyMode;
    private $ptyMode;
    private $haveReadSupport;
    public function __construct(?bool $ttyMode, bool $ptyMode, $input, bool $haveReadSupport)
    {
        $this->ttyMode = $ttyMode;
        $this->ptyMode = $ptyMode;
        $this->haveReadSupport = $haveReadSupport;
        parent::__construct($input);
    }
    /**
     * @return array
     */
    public function __sleep()
    {
        throw new \BadMethodCallException('Cannot serialize ' . __CLASS__);
    }
    public function __wakeup()
    {
        throw new \BadMethodCallException('Cannot unserialize ' . __CLASS__);
    }
    public function __destruct()
    {
        $this->close();
    }
    /**
     * {@inheritdoc}
     */
    public function getDescriptors() : array
    {
        if (!$this->haveReadSupport) {
            $nullstream = \fopen('/dev/null', 'c');
            return [['pipe', 'r'], $nullstream, $nullstream];
        }
        if ($this->ttyMode) {
            return [['file', '/dev/tty', 'r'], ['file', '/dev/tty', 'w'], ['file', '/dev/tty', 'w']];
        }
        if ($this->ptyMode && Process::isPtySupported()) {
            return [['pty'], ['pty'], ['pty']];
        }
        return [
            ['pipe', 'r'],
            ['pipe', 'w'],
            // stdout
            ['pipe', 'w'],
        ];
    }
    /**
     * {@inheritdoc}
     */
    public function getFiles() : array
    {
        return [];
    }
    /**
     * {@inheritdoc}
     */
    public function readAndWrite(bool $blocking, bool $close = \false) : array
    {
        $this->unblock();
        $w = $this->write();
        $read = $e = [];
        $r = $this->pipes;
        unset($r[0]);
        // let's have a look if something changed in streams
        \set_error_handler([$this, 'handleError']);
        if (($r || $w) && \false === \stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1000000.0 : 0)) {
            \restore_error_handler();
            // if a system call has been interrupted, forget about it, let's try again
            // otherwise, an error occurred, let's reset pipes
            if (!$this->hasSystemCallBeenInterrupted()) {
                $this->pipes = [];
            }
            return $read;
        }
        \restore_error_handler();
        foreach ($r as $pipe) {
            // prior PHP 5.4 the array passed to stream_select is modified and
            // lose key association, we have to find back the key
            $read[$type = \array_search($pipe, $this->pipes, \true)] = '';
            do {
                $data = @\fread($pipe, self::CHUNK_SIZE);
                $read[$type] .= $data;
            } while (isset($data[0]) && ($close || isset($data[self::CHUNK_SIZE - 1])));
            if (!isset($read[$type][0])) {
                unset($read[$type]);
            }
            if ($close && \feof($pipe)) {
                \fclose($pipe);
                unset($this->pipes[$type]);
            }
        }
        return $read;
    }
    /**
     * {@inheritdoc}
     */
    public function haveReadSupport() : bool
    {
        return $this->haveReadSupport;
    }
    /**
     * {@inheritdoc}
     */
    public function areOpen() : bool
    {
        return (bool) $this->pipes;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Process\Pipes;

use CivixPhar\Symfony\Component\Process\Exception\InvalidArgumentException;
/**
 * @author Romain Neutron <imprec@gmail.com>
 *
 * @internal
 */
abstract class AbstractPipes implements PipesInterface
{
    public $pipes = [];
    private $inputBuffer = '';
    private $input;
    private $blocked = \true;
    private $lastError;
    /**
     * @param resource|string|int|float|bool|\Iterator|null $input
     */
    public function __construct($input)
    {
        if (\is_resource($input) || $input instanceof \Iterator) {
            $this->input = $input;
        } elseif (\is_string($input)) {
            $this->inputBuffer = $input;
        } else {
            $this->inputBuffer = (string) $input;
        }
    }
    /**
     * {@inheritdoc}
     */
    public function close()
    {
        foreach ($this->pipes as $pipe) {
            \fclose($pipe);
        }
        $this->pipes = [];
    }
    /**
     * Returns true if a system call has been interrupted.
     */
    protected function hasSystemCallBeenInterrupted() : bool
    {
        $lastError = $this->lastError;
        $this->lastError = null;
        // stream_select returns false when the `select` system call is interrupted by an incoming signal
        return null !== $lastError && \false !== \stripos($lastError, 'interrupted system call');
    }
    /**
     * Unblocks streams.
     */
    protected function unblock()
    {
        if (!$this->blocked) {
            return;
        }
        foreach ($this->pipes as $pipe) {
            \stream_set_blocking($pipe, 0);
        }
        if (\is_resource($this->input)) {
            \stream_set_blocking($this->input, 0);
        }
        $this->blocked = \false;
    }
    /**
     * Writes input to stdin.
     *
     * @throws InvalidArgumentException When an input iterator yields a non supported value
     */
    protected function write() : ?array
    {
        if (!isset($this->pipes[0])) {
            return null;
        }
        $input = $this->input;
        if ($input instanceof \Iterator) {
            if (!$input->valid()) {
                $input = null;
            } elseif (\is_resource($input = $input->current())) {
                \stream_set_blocking($input, 0);
            } elseif (!isset($this->inputBuffer[0])) {
                if (!\is_string($input)) {
                    if (!\is_scalar($input)) {
                        throw new InvalidArgumentException(\sprintf('"%s" yielded a value of type "%s", but only scalars and stream resources are supported.', \get_class($this->input), \gettype($input)));
                    }
                    $input = (string) $input;
                }
                $this->inputBuffer = $input;
                $this->input->next();
                $input = null;
            } else {
                $input = null;
            }
        }
        $r = $e = [];
        $w = [$this->pipes[0]];
        // let's have a look if something changed in streams
        if (\false === @\stream_select($r, $w, $e, 0, 0)) {
            return null;
        }
        foreach ($w as $stdin) {
            if (isset($this->inputBuffer[0])) {
                $written = \fwrite($stdin, $this->inputBuffer);
                $this->inputBuffer = \substr($this->inputBuffer, $written);
                if (isset($this->inputBuffer[0])) {
                    return [$this->pipes[0]];
                }
            }
            if ($input) {
                for (;;) {
                    $data = \fread($input, self::CHUNK_SIZE);
                    if (!isset($data[0])) {
                        break;
                    }
                    $written = \fwrite($stdin, $data);
                    $data = \substr($data, $written);
                    if (isset($data[0])) {
                        $this->inputBuffer = $data;
                        return [$this->pipes[0]];
                    }
                }
                if (\feof($input)) {
                    if ($this->input instanceof \Iterator) {
                        $this->input->next();
                    } else {
                        $this->input = null;
                    }
                }
            }
        }
        // no input to read on resource, buffer is empty
        if (!isset($this->inputBuffer[0]) && !($this->input instanceof \Iterator ? $this->input->valid() : $this->input)) {
            $this->input = null;
            \fclose($this->pipes[0]);
            unset($this->pipes[0]);
        } elseif (!$w) {
            return [$this->pipes[0]];
        }
        return null;
    }
    /**
     * @internal
     */
    public function handleError(int $type, string $msg)
    {
        $this->lastError = $msg;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Process\Pipes;

/**
 * PipesInterface manages descriptors and pipes for the use of proc_open.
 *
 * @author Romain Neutron <imprec@gmail.com>
 *
 * @internal
 */
interface PipesInterface
{
    public const CHUNK_SIZE = 16384;
    /**
     * Returns an array of descriptors for the use of proc_open.
     */
    public function getDescriptors() : array;
    /**
     * Returns an array of filenames indexed by their related stream in case these pipes use temporary files.
     *
     * @return string[]
     */
    public function getFiles() : array;
    /**
     * Reads data in file handles and pipes.
     *
     * @param bool $blocking Whether to use blocking calls or not
     * @param bool $close    Whether to close pipes if they've reached EOF
     *
     * @return string[] An array of read data indexed by their fd
     */
    public function readAndWrite(bool $blocking, bool $close = \false) : array;
    /**
     * Returns if the current state has open file handles or pipes.
     */
    public function areOpen() : bool;
    /**
     * Returns if pipes are able to read output.
     */
    public function haveReadSupport() : bool;
    /**
     * Closes file handles and pipes.
     */
    public function close();
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Process;

/**
 * An executable finder specifically designed for the PHP executable.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class PhpExecutableFinder
{
    private $executableFinder;
    public function __construct()
    {
        $this->executableFinder = new ExecutableFinder();
    }
    /**
     * Finds The PHP executable.
     *
     * @param bool $includeArgs Whether or not include command arguments
     *
     * @return string|false The PHP executable path or false if it cannot be found
     */
    public function find($includeArgs = \true)
    {
        if ($php = \getenv('PHP_BINARY')) {
            if (!\is_executable($php)) {
                $command = '\\' === \DIRECTORY_SEPARATOR ? 'where' : 'command -v';
                if ($php = \strtok(\exec($command . ' ' . \escapeshellarg($php)), \PHP_EOL)) {
                    if (!\is_executable($php)) {
                        return \false;
                    }
                } else {
                    return \false;
                }
            }
            return $php;
        }
        $args = $this->findArguments();
        $args = $includeArgs && $args ? ' ' . \implode(' ', $args) : '';
        // PHP_BINARY return the current sapi executable
        if (\PHP_BINARY && \in_array(\PHP_SAPI, ['cgi-fcgi', 'cli', 'cli-server', 'phpdbg'], \true)) {
            return \PHP_BINARY . $args;
        }
        if ($php = \getenv('PHP_PATH')) {
            if (!@\is_executable($php)) {
                return \false;
            }
            return $php;
        }
        if ($php = \getenv('PHP_PEAR_PHP_BIN')) {
            if (@\is_executable($php)) {
                return $php;
            }
        }
        if (@\is_executable($php = \PHP_BINDIR . ('\\' === \DIRECTORY_SEPARATOR ? '\\php.exe' : '/php'))) {
            return $php;
        }
        $dirs = [\PHP_BINDIR];
        if ('\\' === \DIRECTORY_SEPARATOR) {
            $dirs[] = 'C:\\xampp\\php\\';
        }
        return $this->executableFinder->find('php', \false, $dirs);
    }
    /**
     * Finds the PHP executable arguments.
     *
     * @return array The PHP executable arguments
     */
    public function findArguments()
    {
        $arguments = [];
        if ('phpdbg' === \PHP_SAPI) {
            $arguments[] = '-qrr';
        }
        return $arguments;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Process;

/**
 * Generic executable finder.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ExecutableFinder
{
    private $suffixes = ['.exe', '.bat', '.cmd', '.com'];
    /**
     * Replaces default suffixes of executable.
     */
    public function setSuffixes(array $suffixes)
    {
        $this->suffixes = $suffixes;
    }
    /**
     * Adds new possible suffix to check for executable.
     *
     * @param string $suffix
     */
    public function addSuffix($suffix)
    {
        $this->suffixes[] = $suffix;
    }
    /**
     * Finds an executable by name.
     *
     * @param string      $name      The executable name (without the extension)
     * @param string|null $default   The default to return if no executable is found
     * @param array       $extraDirs Additional dirs to check into
     *
     * @return string|null The executable path or default value
     */
    public function find($name, $default = null, array $extraDirs = [])
    {
        if (\ini_get('open_basedir')) {
            $searchPath = \array_merge(\explode(\PATH_SEPARATOR, \ini_get('open_basedir')), $extraDirs);
            $dirs = [];
            foreach ($searchPath as $path) {
                // Silencing against https://bugs.php.net/69240
                if (@\is_dir($path)) {
                    $dirs[] = $path;
                } else {
                    if (\basename($path) == $name && @\is_executable($path)) {
                        return $path;
                    }
                }
            }
        } else {
            $dirs = \array_merge(\explode(\PATH_SEPARATOR, \getenv('PATH') ?: \getenv('Path')), $extraDirs);
        }
        $suffixes = [''];
        if ('\\' === \DIRECTORY_SEPARATOR) {
            $pathExt = \getenv('PATHEXT');
            $suffixes = \array_merge($pathExt ? \explode(\PATH_SEPARATOR, $pathExt) : $this->suffixes, $suffixes);
        }
        foreach ($suffixes as $suffix) {
            foreach ($dirs as $dir) {
                if (@\is_file($file = $dir . \DIRECTORY_SEPARATOR . $name . $suffix) && ('\\' === \DIRECTORY_SEPARATOR || @\is_executable($file))) {
                    return $file;
                }
            }
        }
        return $default;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Process;

use CivixPhar\Symfony\Component\Process\Exception\InvalidArgumentException;
/**
 * ProcessUtils is a bunch of utility methods.
 *
 * This class contains static methods only and is not meant to be instantiated.
 *
 * @author Martin HasoÅˆ <martin.hason@gmail.com>
 */
class ProcessUtils
{
    /**
     * This class should not be instantiated.
     */
    private function __construct()
    {
    }
    /**
     * Validates and normalizes a Process input.
     *
     * @param string $caller The name of method call that validates the input
     * @param mixed  $input  The input to validate
     *
     * @return mixed The validated input
     *
     * @throws InvalidArgumentException In case the input is not valid
     */
    public static function validateInput($caller, $input)
    {
        if (null !== $input) {
            if (\is_resource($input)) {
                return $input;
            }
            if (\is_string($input)) {
                return $input;
            }
            if (\is_scalar($input)) {
                return (string) $input;
            }
            if ($input instanceof Process) {
                return $input->getIterator($input::ITER_SKIP_ERR);
            }
            if ($input instanceof \Iterator) {
                return $input;
            }
            if ($input instanceof \Traversable) {
                return new \IteratorIterator($input);
            }
            throw new InvalidArgumentException(\sprintf('"%s" only accepts strings, Traversable objects or stream resources.', $caller));
        }
        return $input;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Process\Exception;

/**
 * LogicException for the Process Component.
 *
 * @author Romain Neutron <imprec@gmail.com>
 */
class LogicException extends \LogicException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Process\Exception;

/**
 * InvalidArgumentException for the Process Component.
 *
 * @author Romain Neutron <imprec@gmail.com>
 */
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Process\Exception;

use CivixPhar\Symfony\Component\Process\Process;
/**
 * Exception for failed processes.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ProcessFailedException extends RuntimeException
{
    private $process;
    public function __construct(Process $process)
    {
        if ($process->isSuccessful()) {
            throw new InvalidArgumentException('Expected a failed process, but the given process was successful.');
        }
        $error = \sprintf('The command "%s" failed.' . "\n\nExit Code: %s(%s)\n\nWorking directory: %s", $process->getCommandLine(), $process->getExitCode(), $process->getExitCodeText(), $process->getWorkingDirectory());
        if (!$process->isOutputDisabled()) {
            $error .= \sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s", $process->getOutput(), $process->getErrorOutput());
        }
        parent::__construct($error);
        $this->process = $process;
    }
    public function getProcess()
    {
        return $this->process;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Process\Exception;

use CivixPhar\Symfony\Component\Process\Process;
/**
 * Exception that is thrown when a process has been signaled.
 *
 * @author Sullivan Senechal <soullivaneuh@gmail.com>
 */
final class ProcessSignaledException extends RuntimeException
{
    private $process;
    public function __construct(Process $process)
    {
        $this->process = $process;
        parent::__construct(\sprintf('The process has been signaled with signal "%s".', $process->getTermSignal()));
    }
    public function getProcess() : Process
    {
        return $this->process;
    }
    public function getSignal() : int
    {
        return $this->getProcess()->getTermSignal();
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Process\Exception;

use CivixPhar\Symfony\Component\Process\Process;
/**
 * Exception that is thrown when a process times out.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ProcessTimedOutException extends RuntimeException
{
    public const TYPE_GENERAL = 1;
    public const TYPE_IDLE = 2;
    private $process;
    private $timeoutType;
    public function __construct(Process $process, int $timeoutType)
    {
        $this->process = $process;
        $this->timeoutType = $timeoutType;
        parent::__construct(\sprintf('The process "%s" exceeded the timeout of %s seconds.', $process->getCommandLine(), $this->getExceededTimeout()));
    }
    public function getProcess()
    {
        return $this->process;
    }
    public function isGeneralTimeout()
    {
        return self::TYPE_GENERAL === $this->timeoutType;
    }
    public function isIdleTimeout()
    {
        return self::TYPE_IDLE === $this->timeoutType;
    }
    public function getExceededTimeout()
    {
        switch ($this->timeoutType) {
            case self::TYPE_GENERAL:
                return $this->process->getTimeout();
            case self::TYPE_IDLE:
                return $this->process->getIdleTimeout();
            default:
                throw new \LogicException(\sprintf('Unknown timeout type "%d".', $this->timeoutType));
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Process\Exception;

/**
 * RuntimeException for the Process Component.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Process\Exception;

/**
 * Marker Interface for the Process Component.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
interface ExceptionInterface extends \Throwable
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace CivixPhar\Symfony\Component\Process;

use CivixPhar\Symfony\Component\Process\Exception\InvalidArgumentException;
use CivixPhar\Symfony\Component\Process\Exception\LogicException;
use CivixPhar\Symfony\Component\Process\Exception\ProcessFailedException;
use CivixPhar\Symfony\Component\Process\Exception\ProcessSignaledException;
use CivixPhar\Symfony\Component\Process\Exception\ProcessTimedOutException;
use CivixPhar\Symfony\Component\Process\Exception\RuntimeException;
use CivixPhar\Symfony\Component\Process\Pipes\PipesInterface;
use CivixPhar\Symfony\Component\Process\Pipes\UnixPipes;
use CivixPhar\Symfony\Component\Process\Pipes\WindowsPipes;
/**
 * Process is a thin wrapper around proc_* functions to easily
 * start independent PHP processes.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Romain Neutron <imprec@gmail.com>
 */
class Process implements \IteratorAggregate
{
    public const ERR = 'err';
    public const OUT = 'out';
    public const STATUS_READY = 'ready';
    public const STATUS_STARTED = 'started';
    public const STATUS_TERMINATED = 'terminated';
    public const STDIN = 0;
    public const STDOUT = 1;
    public const STDERR = 2;
    // Timeout Precision in seconds.
    public const TIMEOUT_PRECISION = 0.2;
    public const ITER_NON_BLOCKING = 1;
    // By default, iterating over outputs is a blocking call, use this flag to make it non-blocking
    public const ITER_KEEP_OUTPUT = 2;
    // By default, outputs are cleared while iterating, use this flag to keep them in memory
    public const ITER_SKIP_OUT = 4;
    // Use this flag to skip STDOUT while iterating
    public const ITER_SKIP_ERR = 8;
    // Use this flag to skip STDERR while iterating
    private $callback;
    private $hasCallback = \false;
    private $commandline;
    private $cwd;
    private $env;
    private $input;
    private $starttime;
    private $lastOutputTime;
    private $timeout;
    private $idleTimeout;
    private $exitcode;
    private $fallbackStatus = [];
    private $processInformation;
    private $outputDisabled = \false;
    private $stdout;
    private $stderr;
    private $process;
    private $status = self::STATUS_READY;
    private $incrementalOutputOffset = 0;
    private $incrementalErrorOutputOffset = 0;
    private $tty = \false;
    private $pty;
    private $useFileHandles = \false;
    /** @var PipesInterface */
    private $processPipes;
    private $latestSignal;
    private static $sigchild;
    /**
     * Exit codes translation table.
     *
     * User-defined errors must use exit codes in the 64-113 range.
     */
    public static $exitCodes = [
        0 => 'OK',
        1 => 'General error',
        2 => 'Misuse of shell builtins',
        126 => 'Invoked command cannot execute',
        127 => 'Command not found',
        128 => 'Invalid exit argument',
        // signals
        129 => 'Hangup',
        130 => 'Interrupt',
        131 => 'Quit and dump core',
        132 => 'Illegal instruction',
        133 => 'Trace/breakpoint trap',
        134 => 'Process aborted',
        135 => 'Bus error: "access to undefined portion of memory object"',
        136 => 'Floating point exception: "erroneous arithmetic operation"',
        137 => 'Kill (terminate immediately)',
        138 => 'User-defined 1',
        139 => 'Segmentation violation',
        140 => 'User-defined 2',
        141 => 'Write to pipe with no one reading',
        142 => 'Signal raised by alarm',
        143 => 'Termination (request to terminate)',
        // 144 - not defined
        145 => 'Child process terminated, stopped (or continued*)',
        146 => 'Continue if stopped',
        147 => 'Stop executing temporarily',
        148 => 'Terminal stop signal',
        149 => 'Background process attempting to read from tty ("in")',
        150 => 'Background process attempting to write to tty ("out")',
        151 => 'Urgent data available on socket',
        152 => 'CPU time limit exceeded',
        153 => 'File size limit exceeded',
        154 => 'Signal raised by timer counting virtual time: "virtual timer expired"',
        155 => 'Profiling timer expired',
        // 156 - not defined
        157 => 'Pollable event',
        // 158 - not defined
        159 => 'Bad syscall',
    ];
    /**
     * @param array          $command The command to run and its arguments listed as separate entries
     * @param string|null    $cwd     The working directory or null to use the working dir of the current PHP process
     * @param array|null     $env     The environment variables or null to use the same environment as the current PHP process
     * @param mixed          $input   The input as stream resource, scalar or \Traversable, or null for no input
     * @param int|float|null $timeout The timeout in seconds or null to disable
     *
     * @throws LogicException When proc_open is not installed
     */
    public function __construct($command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60)
    {
        if (!\function_exists('proc_open')) {
            throw new LogicException('The Process class relies on proc_open, which is not available on your PHP installation.');
        }
        if (!\is_array($command)) {
            @\trigger_error(\sprintf('Passing a command as string when creating a "%s" instance is deprecated since Symfony 4.2, pass it as an array of its arguments instead, or use the "Process::fromShellCommandline()" constructor if you need features provided by the shell.', __CLASS__), \E_USER_DEPRECATED);
        }
        $this->commandline = $command;
        $this->cwd = $cwd;
        // on Windows, if the cwd changed via chdir(), proc_open defaults to the dir where PHP was started
        // on Gnu/Linux, PHP builds with --enable-maintainer-zts are also affected
        // @see : https://bugs.php.net/51800
        // @see : https://bugs.php.net/50524
        if (null === $this->cwd && (\defined('ZEND_THREAD_SAFE') || '\\' === \DIRECTORY_SEPARATOR)) {
            $this->cwd = \getcwd();
        }
        if (null !== $env) {
            $this->setEnv($env);
        }
        $this->setInput($input);
        $this->setTimeout($timeout);
        $this->useFileHandles = '\\' === \DIRECTORY_SEPARATOR;
        $this->pty = \false;
    }
    /**
     * Creates a Process instance as a command-line to be run in a shell wrapper.
     *
     * Command-lines are parsed by the shell of your OS (/bin/sh on Unix-like, cmd.exe on Windows.)
     * This allows using e.g. pipes or conditional execution. In this mode, signals are sent to the
     * shell wrapper and not to your commands.
     *
     * In order to inject dynamic values into command-lines, we strongly recommend using placeholders.
     * This will save escaping values, which is not portable nor secure anyway:
     *
     *   $process = Process::fromShellCommandline('my_command "$MY_VAR"');
     *   $process->run(null, ['MY_VAR' => $theValue]);
     *
     * @param string         $command The command line to pass to the shell of the OS
     * @param string|null    $cwd     The working directory or null to use the working dir of the current PHP process
     * @param array|null     $env     The environment variables or null to use the same environment as the current PHP process
     * @param mixed          $input   The input as stream resource, scalar or \Traversable, or null for no input
     * @param int|float|null $timeout The timeout in seconds or null to disable
     *
     * @return static
     *
     * @throws LogicException When proc_open is not installed
     */
    public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60)
    {
        $process = new static([], $cwd, $env, $input, $timeout);
        $process->commandline = $command;
        return $process;
    }
    /**
     * @return array
     */
    public function __sleep()
    {
        throw new \BadMethodCallException('Cannot serialize ' . __CLASS__);
    }
    public function __wakeup()
    {
        throw new \BadMethodCallException('Cannot unserialize ' . __CLASS__);
    }
    public function __destruct()
    {
        $this->stop(0);
    }
    public function __clone()
    {
        $this->resetProcessData();
    }
    /**
     * Runs the process.
     *
     * The callback receives the type of output (out or err) and
     * some bytes from the output in real-time. It allows to have feedback
     * from the independent process during execution.
     *
     * The STDOUT and STDERR are also available after the process is finished
     * via the getOutput() and getErrorOutput() methods.
     *
     * @param callable|null $callback A PHP callback to run whenever there is some
     *                                output available on STDOUT or STDERR
     *
     * @return int The exit status code
     *
     * @throws RuntimeException         When process can't be launched
     * @throws RuntimeException         When process is already running
     * @throws ProcessTimedOutException When process timed out
     * @throws ProcessSignaledException When process stopped after receiving signal
     * @throws LogicException           In case a callback is provided and output has been disabled
     *
     * @final
     */
    public function run(callable $callback = null, array $env = []) : int
    {
        $this->start($callback, $env);
        return $this->wait();
    }
    /**
     * Runs the process.
     *
     * This is identical to run() except that an exception is thrown if the process
     * exits with a non-zero exit code.
     *
     * @return $this
     *
     * @throws ProcessFailedException if the process didn't terminate successfully
     *
     * @final
     */
    public function mustRun(callable $callback = null, array $env = []) : self
    {
        if (0 !== $this->run($callback, $env)) {
            throw new ProcessFailedException($this);
        }
        return $this;
    }
    /**
     * Starts the process and returns after writing the input to STDIN.
     *
     * This method blocks until all STDIN data is sent to the process then it
     * returns while the process runs in the background.
     *
     * The termination of the process can be awaited with wait().
     *
     * The callback receives the type of output (out or err) and some bytes from
     * the output in real-time while writing the standard input to the process.
     * It allows to have feedback from the independent process during execution.
     *
     * @param callable|null $callback A PHP callback to run whenever there is some
     *                                output available on STDOUT or STDERR
     *
     * @throws RuntimeException When process can't be launched
     * @throws RuntimeException When process is already running
     * @throws LogicException   In case a callback is provided and output has been disabled
     */
    public function start(callable $callback = null, array $env = [])
    {
        if ($this->isRunning()) {
            throw new RuntimeException('Process is already running.');
        }
        $this->resetProcessData();
        $this->starttime = $this->lastOutputTime = \microtime(\true);
        $this->callback = $this->buildCallback($callback);
        $this->hasCallback = null !== $callback;
        $descriptors = $this->getDescriptors();
        if ($this->env) {
            $env += $this->env;
        }
        $env += $this->getDefaultEnv();
        if (\is_array($commandline = $this->commandline)) {
            $commandline = \implode(' ', \array_map([$this, 'escapeArgument'], $commandline));
            if ('\\' !== \DIRECTORY_SEPARATOR) {
                // exec is mandatory to deal with sending a signal to the process
                $commandline = 'exec ' . $commandline;
            }
        } else {
            $commandline = $this->replacePlaceholders($commandline, $env);
        }
        $options = ['suppress_errors' => \true];
        if ('\\' === \DIRECTORY_SEPARATOR) {
            $options['bypass_shell'] = \true;
            $commandline = $this->prepareWindowsCommandLine($commandline, $env);
        } elseif (!$this->useFileHandles && $this->isSigchildEnabled()) {
            // last exit code is output on the fourth pipe and caught to work around --enable-sigchild
            $descriptors[3] = ['pipe', 'w'];
            // See https://unix.stackexchange.com/questions/71205/background-process-pipe-input
            $commandline = '{ (' . $commandline . ') <&3 3<&- 3>/dev/null & } 3<&0;';
            $commandline .= 'pid=$!; echo $pid >&3; wait $pid; code=$?; echo $code >&3; exit $code';
            // Workaround for the bug, when PTS functionality is enabled.
            // @see : https://bugs.php.net/69442
            $ptsWorkaround = \fopen(__FILE__, 'r');
        }
        $envPairs = [];
        foreach ($env as $k => $v) {
            if (\false !== $v && 'argc' !== $k && 'argv' !== $k) {
                $envPairs[] = $k . '=' . $v;
            }
        }
        if (!\is_dir($this->cwd)) {
            throw new RuntimeException(\sprintf('The provided cwd "%s" does not exist.', $this->cwd));
        }
        $this->process = @\proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $options);
        if (!\is_resource($this->process)) {
            throw new RuntimeException('Unable to launch a new process.');
        }
        $this->status = self::STATUS_STARTED;
        if (isset($descriptors[3])) {
            $this->fallbackStatus['pid'] = (int) \fgets($this->processPipes->pipes[3]);
        }
        if ($this->tty) {
            return;
        }
        $this->updateStatus(\false);
        $this->checkTimeout();
    }
    /**
     * Restarts the process.
     *
     * Be warned that the process is cloned before being started.
     *
     * @param callable|null $callback A PHP callback to run whenever there is some
     *                                output available on STDOUT or STDERR
     *
     * @return static
     *
     * @throws RuntimeException When process can't be launched
     * @throws RuntimeException When process is already running
     *
     * @see start()
     *
     * @final
     */
    public function restart(callable $callback = null, array $env = []) : self
    {
        if ($this->isRunning()) {
            throw new RuntimeException('Process is already running.');
        }
        $process = clone $this;
        $process->start($callback, $env);
        return $process;
    }
    /**
     * Waits for the process to terminate.
     *
     * The callback receives the type of output (out or err) and some bytes
     * from the output in real-time while writing the standard input to the process.
     * It allows to have feedback from the independent process during execution.
     *
     * @param callable|null $callback A valid PHP callback
     *
     * @return int The exitcode of the process
     *
     * @throws ProcessTimedOutException When process timed out
     * @throws ProcessSignaledException When process stopped after receiving signal
     * @throws LogicException           When process is not yet started
     */
    public function wait(callable $callback = null)
    {
        $this->requireProcessIsStarted(__FUNCTION__);
        $this->updateStatus(\false);
        if (null !== $callback) {
            if (!$this->processPipes->haveReadSupport()) {
                $this->stop(0);
                throw new LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::wait".');
            }
            $this->callback = $this->buildCallback($callback);
        }
        do {
            $this->checkTimeout();
            $running = '\\' === \DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen();
            $this->readPipes($running, '\\' !== \DIRECTORY_SEPARATOR || !$running);
        } while ($running);
        while ($this->isRunning()) {
            $this->checkTimeout();
            \usleep(1000);
        }
        if ($this->processInformation['signaled'] && $this->processInformation['termsig'] !== $this->latestSignal) {
            throw new ProcessSignaledException($this);
        }
        return $this->exitcode;
    }
    /**
     * Waits until the callback returns true.
     *
     * The callback receives the type of output (out or err) and some bytes
     * from the output in real-time while writing the standard input to the process.
     * It allows to have feedback from the independent process during execution.
     *
     * @throws RuntimeException         When process timed out
     * @throws LogicException           When process is not yet started
     * @throws ProcessTimedOutException In case the timeout was reached
     */
    public function waitUntil(callable $callback) : bool
    {
        $this->requireProcessIsStarted(__FUNCTION__);
        $this->updateStatus(\false);
        if (!$this->processPipes->haveReadSupport()) {
            $this->stop(0);
            throw new LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::waitUntil".');
        }
        $callback = $this->buildCallback($callback);
        $ready = \false;
        while (\true) {
            $this->checkTimeout();
            $running = '\\' === \DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen();
            $output = $this->processPipes->readAndWrite($running, '\\' !== \DIRECTORY_SEPARATOR || !$running);
            foreach ($output as $type => $data) {
                if (3 !== $type) {
                    $ready = $callback(self::STDOUT === $type ? self::OUT : self::ERR, $data) || $ready;
                } elseif (!isset($this->fallbackStatus['signaled'])) {
                    $this->fallbackStatus['exitcode'] = (int) $data;
                }
            }
            if ($ready) {
                return \true;
            }
            if (!$running) {
                return \false;
            }
            \usleep(1000);
        }
    }
    /**
     * Returns the Pid (process identifier), if applicable.
     *
     * @return int|null The process id if running, null otherwise
     */
    public function getPid()
    {
        return $this->isRunning() ? $this->processInformation['pid'] : null;
    }
    /**
     * Sends a POSIX signal to the process.
     *
     * @param int $signal A valid POSIX signal (see https://php.net/pcntl.constants)
     *
     * @return $this
     *
     * @throws LogicException   In case the process is not running
     * @throws RuntimeException In case --enable-sigchild is activated and the process can't be killed
     * @throws RuntimeException In case of failure
     */
    public function signal($signal)
    {
        $this->doSignal($signal, \true);
        return $this;
    }
    /**
     * Disables fetching output and error output from the underlying process.
     *
     * @return $this
     *
     * @throws RuntimeException In case the process is already running
     * @throws LogicException   if an idle timeout is set
     */
    public function disableOutput()
    {
        if ($this->isRunning()) {
            throw new RuntimeException('Disabling output while the process is running is not possible.');
        }
        if (null !== $this->idleTimeout) {
            throw new LogicException('Output can not be disabled while an idle timeout is set.');
        }
        $this->outputDisabled = \true;
        return $this;
    }
    /**
     * Enables fetching output and error output from the underlying process.
     *
     * @return $this
     *
     * @throws RuntimeException In case the process is already running
     */
    public function enableOutput()
    {
        if ($this->isRunning()) {
            throw new RuntimeException('Enabling output while the process is running is not possible.');
        }
        $this->outputDisabled = \false;
        return $this;
    }
    /**
     * Returns true in case the output is disabled, false otherwise.
     *
     * @return bool
     */
    public function isOutputDisabled()
    {
        return $this->outputDisabled;
    }
    /**
     * Returns the current output of the process (STDOUT).
     *
     * @return string The process output
     *
     * @throws LogicException in case the output has been disabled
     * @throws LogicException In case the process is not started
     */
    public function getOutput()
    {
        $this->readPipesForOutput(__FUNCTION__);
        if (\false === ($ret = \stream_get_contents($this->stdout, -1, 0))) {
            return '';
        }
        return $ret;
    }
    /**
     * Returns the output incrementally.
     *
     * In comparison with the getOutput method which always return the whole
     * output, this one returns the new output since the last call.
     *
     * @return string The process output since the last call
     *
     * @throws LogicException in case the output has been disabled
     * @throws LogicException In case the process is not started
     */
    public function getIncrementalOutput()
    {
        $this->readPipesForOutput(__FUNCTION__);
        $latest = \stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset);
        $this->incrementalOutputOffset = \ftell($this->stdout);
        if (\false === $latest) {
            return '';
        }
        return $latest;
    }
    /**
     * Returns an iterator to the output of the process, with the output type as keys (Process::OUT/ERR).
     *
     * @param int $flags A bit field of Process::ITER_* flags
     *
     * @throws LogicException in case the output has been disabled
     * @throws LogicException In case the process is not started
     *
     * @return \Generator
     */
    #[\ReturnTypeWillChange]
    public function getIterator($flags = 0)
    {
        $this->readPipesForOutput(__FUNCTION__, \false);
        $clearOutput = !(self::ITER_KEEP_OUTPUT & $flags);
        $blocking = !(self::ITER_NON_BLOCKING & $flags);
        $yieldOut = !(self::ITER_SKIP_OUT & $flags);
        $yieldErr = !(self::ITER_SKIP_ERR & $flags);
        while (null !== $this->callback || $yieldOut && !\feof($this->stdout) || $yieldErr && !\feof($this->stderr)) {
            if ($yieldOut) {
                $out = \stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset);
                if (isset($out[0])) {
                    if ($clearOutput) {
                        $this->clearOutput();
                    } else {
                        $this->incrementalOutputOffset = \ftell($this->stdout);
                    }
                    (yield self::OUT => $out);
                }
            }
            if ($yieldErr) {
                $err = \stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset);
                if (isset($err[0])) {
                    if ($clearOutput) {
                        $this->clearErrorOutput();
                    } else {
                        $this->incrementalErrorOutputOffset = \ftell($this->stderr);
                    }
                    (yield self::ERR => $err);
                }
            }
            if (!$blocking && !isset($out[0]) && !isset($err[0])) {
                (yield self::OUT => '');
            }
            $this->checkTimeout();
            $this->readPipesForOutput(__FUNCTION__, $blocking);
        }
    }
    /**
     * Clears the process output.
     *
     * @return $this
     */
    public function clearOutput()
    {
        \ftruncate($this->stdout, 0);
        \fseek($this->stdout, 0);
        $this->incrementalOutputOffset = 0;
        return $this;
    }
    /**
     * Returns the current error output of the process (STDERR).
     *
     * @return string The process error output
     *
     * @throws LogicException in case the output has been disabled
     * @throws LogicException In case the process is not started
     */
    public function getErrorOutput()
    {
        $this->readPipesForOutput(__FUNCTION__);
        if (\false === ($ret = \stream_get_contents($this->stderr, -1, 0))) {
            return '';
        }
        return $ret;
    }
    /**
     * Returns the errorOutput incrementally.
     *
     * In comparison with the getErrorOutput method which always return the
     * whole error output, this one returns the new error output since the last
     * call.
     *
     * @return string The process error output since the last call
     *
     * @throws LogicException in case the output has been disabled
     * @throws LogicException In case the process is not started
     */
    public function getIncrementalErrorOutput()
    {
        $this->readPipesForOutput(__FUNCTION__);
        $latest = \stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset);
        $this->incrementalErrorOutputOffset = \ftell($this->stderr);
        if (\false === $latest) {
            return '';
        }
        return $latest;
    }
    /**
     * Clears the process output.
     *
     * @return $this
     */
    public function clearErrorOutput()
    {
        \ftruncate($this->stderr, 0);
        \fseek($this->stderr, 0);
        $this->incrementalErrorOutputOffset = 0;
        return $this;
    }
    /**
     * Returns the exit code returned by the process.
     *
     * @return int|null The exit status code, null if the Process is not terminated
     */
    public function getExitCode()
    {
        $this->updateStatus(\false);
        return $this->exitcode;
    }
    /**
     * Returns a string representation for the exit code returned by the process.
     *
     * This method relies on the Unix exit code status standardization
     * and might not be relevant for other operating systems.
     *
     * @return string|null A string representation for the exit status code, null if the Process is not terminated
     *
     * @see http://tldp.org/LDP/abs/html/exitcodes.html
     * @see http://en.wikipedia.org/wiki/Unix_signal
     */
    public function getExitCodeText()
    {
        if (null === ($exitcode = $this->getExitCode())) {
            return null;
        }
        return self::$exitCodes[$exitcode] ?? 'Unknown error';
    }
    /**
     * Checks if the process ended successfully.
     *
     * @return bool true if the process ended successfully, false otherwise
     */
    public function isSuccessful()
    {
        return 0 === $this->getExitCode();
    }
    /**
     * Returns true if the child process has been terminated by an uncaught signal.
     *
     * It always returns false on Windows.
     *
     * @return bool
     *
     * @throws LogicException In case the process is not terminated
     */
    public function hasBeenSignaled()
    {
        $this->requireProcessIsTerminated(__FUNCTION__);
        return $this->processInformation['signaled'];
    }
    /**
     * Returns the number of the signal that caused the child process to terminate its execution.
     *
     * It is only meaningful if hasBeenSignaled() returns true.
     *
     * @return int
     *
     * @throws RuntimeException In case --enable-sigchild is activated
     * @throws LogicException   In case the process is not terminated
     */
    public function getTermSignal()
    {
        $this->requireProcessIsTerminated(__FUNCTION__);
        if ($this->isSigchildEnabled() && -1 === $this->processInformation['termsig']) {
            throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.');
        }
        return $this->processInformation['termsig'];
    }
    /**
     * Returns true if the child process has been stopped by a signal.
     *
     * It always returns false on Windows.
     *
     * @return bool
     *
     * @throws LogicException In case the process is not terminated
     */
    public function hasBeenStopped()
    {
        $this->requireProcessIsTerminated(__FUNCTION__);
        return $this->processInformation['stopped'];
    }
    /**
     * Returns the number of the signal that caused the child process to stop its execution.
     *
     * It is only meaningful if hasBeenStopped() returns true.
     *
     * @return int
     *
     * @throws LogicException In case the process is not terminated
     */
    public function getStopSignal()
    {
        $this->requireProcessIsTerminated(__FUNCTION__);
        return $this->processInformation['stopsig'];
    }
    /**
     * Checks if the process is currently running.
     *
     * @return bool true if the process is currently running, false otherwise
     */
    public function isRunning()
    {
        if (self::STATUS_STARTED !== $this->status) {
            return \false;
        }
        $this->updateStatus(\false);
        return $this->processInformation['running'];
    }
    /**
     * Checks if the process has been started with no regard to the current state.
     *
     * @return bool true if status is ready, false otherwise
     */
    public function isStarted()
    {
        return self::STATUS_READY != $this->status;
    }
    /**
     * Checks if the process is terminated.
     *
     * @return bool true if process is terminated, false otherwise
     */
    public function isTerminated()
    {
        $this->updateStatus(\false);
        return self::STATUS_TERMINATED == $this->status;
    }
    /**
     * Gets the process status.
     *
     * The status is one of: ready, started, terminated.
     *
     * @return string The current process status
     */
    public function getStatus()
    {
        $this->updateStatus(\false);
        return $this->status;
    }
    /**
     * Stops the process.
     *
     * @param int|float $timeout The timeout in seconds
     * @param int       $signal  A POSIX signal to send in case the process has not stop at timeout, default is SIGKILL (9)
     *
     * @return int|null The exit-code of the process or null if it's not running
     */
    public function stop($timeout = 10, $signal = null)
    {
        $timeoutMicro = \microtime(\true) + $timeout;
        if ($this->isRunning()) {
            // given SIGTERM may not be defined and that "proc_terminate" uses the constant value and not the constant itself, we use the same here
            $this->doSignal(15, \false);
            do {
                \usleep(1000);
            } while ($this->isRunning() && \microtime(\true) < $timeoutMicro);
            if ($this->isRunning()) {
                // Avoid exception here: process is supposed to be running, but it might have stopped just
                // after this line. In any case, let's silently discard the error, we cannot do anything.
                $this->doSignal($signal ?: 9, \false);
            }
        }
        if ($this->isRunning()) {
            if (isset($this->fallbackStatus['pid'])) {
                unset($this->fallbackStatus['pid']);
                return $this->stop(0, $signal);
            }
            $this->close();
        }
        return $this->exitcode;
    }
    /**
     * Adds a line to the STDOUT stream.
     *
     * @internal
     */
    public function addOutput(string $line)
    {
        $this->lastOutputTime = \microtime(\true);
        \fseek($this->stdout, 0, \SEEK_END);
        \fwrite($this->stdout, $line);
        \fseek($this->stdout, $this->incrementalOutputOffset);
    }
    /**
     * Adds a line to the STDERR stream.
     *
     * @internal
     */
    public function addErrorOutput(string $line)
    {
        $this->lastOutputTime = \microtime(\true);
        \fseek($this->stderr, 0, \SEEK_END);
        \fwrite($this->stderr, $line);
        \fseek($this->stderr, $this->incrementalErrorOutputOffset);
    }
    /**
     * Gets the last output time in seconds.
     *
     * @return float|null The last output time in seconds or null if it isn't started
     */
    public function getLastOutputTime() : ?float
    {
        return $this->lastOutputTime;
    }
    /**
     * Gets the command line to be executed.
     *
     * @return string The command to execute
     */
    public function getCommandLine()
    {
        return \is_array($this->commandline) ? \implode(' ', \array_map([$this, 'escapeArgument'], $this->commandline)) : $this->commandline;
    }
    /**
     * Sets the command line to be executed.
     *
     * @param string|array $commandline The command to execute
     *
     * @return $this
     *
     * @deprecated since Symfony 4.2.
     */
    public function setCommandLine($commandline)
    {
        @\trigger_error(\sprintf('The "%s()" method is deprecated since Symfony 4.2.', __METHOD__), \E_USER_DEPRECATED);
        $this->commandline = $commandline;
        return $this;
    }
    /**
     * Gets the process timeout (max. runtime).
     *
     * @return float|null The timeout in seconds or null if it's disabled
     */
    public function getTimeout()
    {
        return $this->timeout;
    }
    /**
     * Gets the process idle timeout (max. time since last output).
     *
     * @return float|null The timeout in seconds or null if it's disabled
     */
    public function getIdleTimeout()
    {
        return $this->idleTimeout;
    }
    /**
     * Sets the process timeout (max. runtime) in seconds.
     *
     * To disable the timeout, set this value to null.
     *
     * @param int|float|null $timeout The timeout in seconds
     *
     * @return $this
     *
     * @throws InvalidArgumentException if the timeout is negative
     */
    public function setTimeout($timeout)
    {
        $this->timeout = $this->validateTimeout($timeout);
        return $this;
    }
    /**
     * Sets the process idle timeout (max. time since last output).
     *
     * To disable the timeout, set this value to null.
     *
     * @param int|float|null $timeout The timeout in seconds
     *
     * @return $this
     *
     * @throws LogicException           if the output is disabled
     * @throws InvalidArgumentException if the timeout is negative
     */
    public function setIdleTimeout($timeout)
    {
        if (null !== $timeout && $this->outputDisabled) {
            throw new LogicException('Idle timeout can not be set while the output is disabled.');
        }
        $this->idleTimeout = $this->validateTimeout($timeout);
        return $this;
    }
    /**
     * Enables or disables the TTY mode.
     *
     * @param bool $tty True to enabled and false to disable
     *
     * @return $this
     *
     * @throws RuntimeException In case the TTY mode is not supported
     */
    public function setTty($tty)
    {
        if ('\\' === \DIRECTORY_SEPARATOR && $tty) {
            throw new RuntimeException('TTY mode is not supported on Windows platform.');
        }
        if ($tty && !self::isTtySupported()) {
            throw new RuntimeException('TTY mode requires /dev/tty to be read/writable.');
        }
        $this->tty = (bool) $tty;
        return $this;
    }
    /**
     * Checks if the TTY mode is enabled.
     *
     * @return bool true if the TTY mode is enabled, false otherwise
     */
    public function isTty()
    {
        return $this->tty;
    }
    /**
     * Sets PTY mode.
     *
     * @param bool $bool
     *
     * @return $this
     */
    public function setPty($bool)
    {
        $this->pty = (bool) $bool;
        return $this;
    }
    /**
     * Returns PTY state.
     *
     * @return bool
     */
    public function isPty()
    {
        return $this->pty;
    }
    /**
     * Gets the working directory.
     *
     * @return string|null The current working directory or null on failure
     */
    public function getWorkingDirectory()
    {
        if (null === $this->cwd) {
            // getcwd() will return false if any one of the parent directories does not have
            // the readable or search mode set, even if the current directory does
            return \getcwd() ?: null;
        }
        return $this->cwd;
    }
    /**
     * Sets the current working directory.
     *
     * @param string $cwd The new working directory
     *
     * @return $this
     */
    public function setWorkingDirectory($cwd)
    {
        $this->cwd = $cwd;
        return $this;
    }
    /**
     * Gets the environment variables.
     *
     * @return array The current environment variables
     */
    public function getEnv()
    {
        return $this->env;
    }
    /**
     * Sets the environment variables.
     *
     * @param array<string|\Stringable> $env The new environment variables
     *
     * @return $this
     */
    public function setEnv(array $env)
    {
        $this->env = $env;
        return $this;
    }
    /**
     * Gets the Process input.
     *
     * @return resource|string|\Iterator|null The Process input
     */
    public function getInput()
    {
        return $this->input;
    }
    /**
     * Sets the input.
     *
     * This content will be passed to the underlying process standard input.
     *
     * @param string|int|float|bool|resource|\Traversable|null $input The content
     *
     * @return $this
     *
     * @throws LogicException In case the process is running
     */
    public function setInput($input)
    {
        if ($this->isRunning()) {
            throw new LogicException('Input can not be set while the process is running.');
        }
        $this->input = ProcessUtils::validateInput(__METHOD__, $input);
        return $this;
    }
    /**
     * Sets whether environment variables will be inherited or not.
     *
     * @param bool $inheritEnv
     *
     * @return $this
     *
     * @deprecated since Symfony 4.4, env variables are always inherited
     */
    public function inheritEnvironmentVariables($inheritEnv = \true)
    {
        @\trigger_error(\sprintf('The "%s()" method is deprecated since Symfony 4.4, env variables are always inherited.', __METHOD__), \E_USER_DEPRECATED);
        if (!$inheritEnv) {
            throw new InvalidArgumentException('Not inheriting environment variables is not supported.');
        }
        return $this;
    }
    /**
     * Performs a check between the timeout definition and the time the process started.
     *
     * In case you run a background process (with the start method), you should
     * trigger this method regularly to ensure the process timeout
     *
     * @throws ProcessTimedOutException In case the timeout was reached
     */
    public function checkTimeout()
    {
        if (self::STATUS_STARTED !== $this->status) {
            return;
        }
        if (null !== $this->timeout && $this->timeout < \microtime(\true) - $this->starttime) {
            $this->stop(0);
            throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_GENERAL);
        }
        if (null !== $this->idleTimeout && $this->idleTimeout < \microtime(\true) - $this->lastOutputTime) {
            $this->stop(0);
            throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_IDLE);
        }
    }
    /**
     * Returns whether TTY is supported on the current operating system.
     */
    public static function isTtySupported() : bool
    {
        static $isTtySupported;
        if (null === $isTtySupported) {
            $isTtySupported = (bool) @\proc_open('echo 1 >/dev/null', [['file', '/dev/tty', 'r'], ['file', '/dev/tty', 'w'], ['file', '/dev/tty', 'w']], $pipes);
        }
        return $isTtySupported;
    }
    /**
     * Returns whether PTY is supported on the current operating system.
     *
     * @return bool
     */
    public static function isPtySupported()
    {
        static $result;
        if (null !== $result) {
            return $result;
        }
        if ('\\' === \DIRECTORY_SEPARATOR) {
            return $result = \false;
        }
        return $result = (bool) @\proc_open('echo 1 >/dev/null', [['pty'], ['pty'], ['pty']], $pipes);
    }
    /**
     * Creates the descriptors needed by the proc_open.
     */
    private function getDescriptors() : array
    {
        if ($this->input instanceof \Iterator) {
            $this->input->rewind();
        }
        if ('\\' === \DIRECTORY_SEPARATOR) {
            $this->processPipes = new WindowsPipes($this->input, !$this->outputDisabled || $this->hasCallback);
        } else {
            $this->processPipes = new UnixPipes($this->isTty(), $this->isPty(), $this->input, !$this->outputDisabled || $this->hasCallback);
        }
        return $this->processPipes->getDescriptors();
    }
    /**
     * Builds up the callback used by wait().
     *
     * The callbacks adds all occurred output to the specific buffer and calls
     * the user callback (if present) with the received output.
     *
     * @param callable|null $callback The user defined PHP callback
     *
     * @return \Closure A PHP closure
     */
    protected function buildCallback(callable $callback = null)
    {
        if ($this->outputDisabled) {
            return function ($type, $data) use($callback) : bool {
                return null !== $callback && $callback($type, $data);
            };
        }
        $out = self::OUT;
        return function ($type, $data) use($callback, $out) : bool {
            if ($out == $type) {
                $this->addOutput($data);
            } else {
                $this->addErrorOutput($data);
            }
            return null !== $callback && $callback($type, $data);
        };
    }
    /**
     * Updates the status of the process, reads pipes.
     *
     * @param bool $blocking Whether to use a blocking read call
     */
    protected function updateStatus($blocking)
    {
        if (self::STATUS_STARTED !== $this->status) {
            return;
        }
        $this->processInformation = \proc_get_status($this->process);
        $running = $this->processInformation['running'];
        $this->readPipes($running && $blocking, '\\' !== \DIRECTORY_SEPARATOR || !$running);
        if ($this->fallbackStatus && $this->isSigchildEnabled()) {
            $this->processInformation = $this->fallbackStatus + $this->processInformation;
        }
        if (!$running) {
            $this->close();
        }
    }
    /**
     * Returns whether PHP has been compiled with the '--enable-sigchild' option or not.
     *
     * @return bool
     */
    protected function isSigchildEnabled()
    {
        if (null !== self::$sigchild) {
            return self::$sigchild;
        }
        if (!\function_exists('phpinfo')) {
            return self::$sigchild = \false;
        }
        \ob_start();
        \phpinfo(\INFO_GENERAL);
        return self::$sigchild = \str_contains(\ob_get_clean(), '--enable-sigchild');
    }
    /**
     * Reads pipes for the freshest output.
     *
     * @param string $caller   The name of the method that needs fresh outputs
     * @param bool   $blocking Whether to use blocking calls or not
     *
     * @throws LogicException in case output has been disabled or process is not started
     */
    private function readPipesForOutput(string $caller, bool $blocking = \false)
    {
        if ($this->outputDisabled) {
            throw new LogicException('Output has been disabled.');
        }
        $this->requireProcessIsStarted($caller);
        $this->updateStatus($blocking);
    }
    /**
     * Validates and returns the filtered timeout.
     *
     * @throws InvalidArgumentException if the given timeout is a negative number
     */
    private function validateTimeout(?float $timeout) : ?float
    {
        $timeout = (float) $timeout;
        if (0.0 === $timeout) {
            $timeout = null;
        } elseif ($timeout < 0) {
            throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.');
        }
        return $timeout;
    }
    /**
     * Reads pipes, executes callback.
     *
     * @param bool $blocking Whether to use blocking calls or not
     * @param bool $close    Whether to close file handles or not
     */
    private function readPipes(bool $blocking, bool $close)
    {
        $result = $this->processPipes->readAndWrite($blocking, $close);
        $callback = $this->callback;
        foreach ($result as $type => $data) {
            if (3 !== $type) {
                $callback(self::STDOUT === $type ? self::OUT : self::ERR, $data);
            } elseif (!isset($this->fallbackStatus['signaled'])) {
                $this->fallbackStatus['exitcode'] = (int) $data;
            }
        }
    }
    /**
     * Closes process resource, closes file handles, sets the exitcode.
     *
     * @return int The exitcode
     */
    private function close() : int
    {
        $this->processPipes->close();
        if (\is_resource($this->process)) {
            \proc_close($this->process);
        }
        $this->exitcode = $this->processInformation['exitcode'];
        $this->status = self::STATUS_TERMINATED;
        if (-1 === $this->exitcode) {
            if ($this->processInformation['signaled'] && 0 < $this->processInformation['termsig']) {
                // if process has been signaled, no exitcode but a valid termsig, apply Unix convention
                $this->exitcode = 128 + $this->processInformation['termsig'];
            } elseif ($this->isSigchildEnabled()) {
                $this->processInformation['signaled'] = \true;
                $this->processInformation['termsig'] = -1;
            }
        }
        // Free memory from self-reference callback created by buildCallback
        // Doing so in other contexts like __destruct or by garbage collector is ineffective
        // Now pipes are closed, so the callback is no longer necessary
        $this->callback = null;
        return $this->exitcode;
    }
    /**
     * Resets data related to the latest run of the process.
     */
    private function resetProcessData()
    {
        $this->starttime = null;
        $this->callback = null;
        $this->exitcode = null;
        $this->fallbackStatus = [];
        $this->processInformation = null;
        $this->stdout = \fopen('php://temp/maxmemory:' . 1024 * 1024, 'w+');
        $this->stderr = \fopen('php://temp/maxmemory:' . 1024 * 1024, 'w+');
        $this->process = null;
        $this->latestSignal = null;
        $this->status = self::STATUS_READY;
        $this->incrementalOutputOffset = 0;
        $this->incrementalErrorOutputOffset = 0;
    }
    /**
     * Sends a POSIX signal to the process.
     *
     * @param int  $signal         A valid POSIX signal (see https://php.net/pcntl.constants)
     * @param bool $throwException Whether to throw exception in case signal failed
     *
     * @return bool True if the signal was sent successfully, false otherwise
     *
     * @throws LogicException   In case the process is not running
     * @throws RuntimeException In case --enable-sigchild is activated and the process can't be killed
     * @throws RuntimeException In case of failure
     */
    private function doSignal(int $signal, bool $throwException) : bool
    {
        if (null === ($pid = $this->getPid())) {
            if ($throwException) {
                throw new LogicException('Can not send signal on a non running process.');
            }
            return \false;
        }
        if ('\\' === \DIRECTORY_SEPARATOR) {
            \exec(\sprintf('taskkill /F /T /PID %d 2>&1', $pid), $output, $exitCode);
            if ($exitCode && $this->isRunning()) {
                if ($throwException) {
                    throw new RuntimeException(\sprintf('Unable to kill the process (%s).', \implode(' ', $output)));
                }
                return \false;
            }
        } else {
            if (!$this->isSigchildEnabled()) {
                $ok = @\proc_terminate($this->process, $signal);
            } elseif (\function_exists('posix_kill')) {
                $ok = @\posix_kill($pid, $signal);
            } elseif ($ok = \proc_open(\sprintf('kill -%d %d', $signal, $pid), [2 => ['pipe', 'w']], $pipes)) {
                $ok = \false === \fgets($pipes[2]);
            }
            if (!$ok) {
                if ($throwException) {
                    throw new RuntimeException(\sprintf('Error while sending signal "%s".', $signal));
                }
                return \false;
            }
        }
        $this->latestSignal = $signal;
        $this->fallbackStatus['signaled'] = \true;
        $this->fallbackStatus['exitcode'] = -1;
        $this->fallbackStatus['termsig'] = $this->latestSignal;
        return \true;
    }
    private function prepareWindowsCommandLine(string $cmd, array &$env) : string
    {
        $uid = \uniqid('', \true);
        $varCount = 0;
        $varCache = [];
        $cmd = \preg_replace_callback('/"(?:(
                [^"%!^]*+
                (?:
                    (?: !LF! | "(?:\\^[%!^])?+" )
                    [^"%!^]*+
                )++
            ) | [^"]*+ )"/x', function ($m) use(&$env, &$varCache, &$varCount, $uid) {
            if (!isset($m[1])) {
                return $m[0];
            }
            if (isset($varCache[$m[0]])) {
                return $varCache[$m[0]];
            }
            if (\str_contains($value = $m[1], "\x00")) {
                $value = \str_replace("\x00", '?', $value);
            }
            if (\false === \strpbrk($value, "\"%!\n")) {
                return '"' . $value . '"';
            }
            $value = \str_replace(['!LF!', '"^!"', '"^%"', '"^^"', '""'], ["\n", '!', '%', '^', '"'], $value);
            $value = '"' . \preg_replace('/(\\\\*)"/', '$1$1\\"', $value) . '"';
            $var = $uid . ++$varCount;
            $env[$var] = $value;
            return $varCache[$m[0]] = '!' . $var . '!';
        }, $cmd);
        $cmd = 'cmd /V:ON /E:ON /D /C (' . \str_replace("\n", ' ', $cmd) . ')';
        foreach ($this->processPipes->getFiles() as $offset => $filename) {
            $cmd .= ' ' . $offset . '>"' . $filename . '"';
        }
        return $cmd;
    }
    /**
     * Ensures the process is running or terminated, throws a LogicException if the process has a not started.
     *
     * @throws LogicException if the process has not run
     */
    private function requireProcessIsStarted(string $functionName)
    {
        if (!$this->isStarted()) {
            throw new LogicException(\sprintf('Process must be started before calling "%s()".', $functionName));
        }
    }
    /**
     * Ensures the process is terminated, throws a LogicException if the process has a status different than "terminated".
     *
     * @throws LogicException if the process is not yet terminated
     */
    private function requireProcessIsTerminated(string $functionName)
    {
        if (!$this->isTerminated()) {
            throw new LogicException(\sprintf('Process must be terminated before calling "%s()".', $functionName));
        }
    }
    /**
     * Escapes a string to be used as a shell argument.
     */
    private function escapeArgument(?string $argument) : string
    {
        if ('' === $argument || null === $argument) {
            return '""';
        }
        if ('\\' !== \DIRECTORY_SEPARATOR) {
            return "'" . \str_replace("'", "'\\''", $argument) . "'";
        }
        if (\str_contains($argument, "\x00")) {
            $argument = \str_replace("\x00", '?', $argument);
        }
        if (!\preg_match('/[\\/()%!^"<>&|\\s]/', $argument)) {
            return $argument;
        }
        $argument = \preg_replace('/(\\\\+)$/', '$1$1', $argument);
        return '"' . \str_replace(['"', '^', '%', '!', "\n"], ['""', '"^^"', '"^%"', '"^!"', '!LF!'], $argument) . '"';
    }
    private function replacePlaceholders(string $commandline, array $env)
    {
        return \preg_replace_callback('/"\\$\\{:([_a-zA-Z]++[_a-zA-Z0-9]*+)\\}"/', function ($matches) use($commandline, $env) {
            if (!isset($env[$matches[1]]) || \false === $env[$matches[1]]) {
                throw new InvalidArgumentException(\sprintf('Command line is missing a value for parameter "%s": ', $matches[1]) . $commandline);
            }
            return $this->escapeArgument($env[$matches[1]]);
        }, $commandline);
    }
    private function getDefaultEnv() : array
    {
        $env = \getenv();
        $env = \array_intersect_key($env, $_SERVER) ?: $env;
        return $_ENV + $env;
    }
}
<?php

/*
 * This file is part of Composer Extra Files Plugin.
 *
 * (c) 2017 Last Call Media, Rob Bayliss <rob@lastcallmedia.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */
namespace CivixPhar\LastCall\DownloadsPlugin;

use CivixPhar\Composer\Composer;
use CivixPhar\Composer\EventDispatcher\EventSubscriberInterface;
use CivixPhar\Composer\Installer\PackageEvent;
use CivixPhar\Composer\Installer\PackageEvents;
use CivixPhar\Composer\IO\IOInterface;
use CivixPhar\Composer\Package\Package;
use CivixPhar\Composer\Package\PackageInterface;
use CivixPhar\Composer\Plugin\PluginInterface;
use CivixPhar\Composer\Script\Event;
use CivixPhar\Composer\Script\ScriptEvents;
use CivixPhar\LastCall\DownloadsPlugin\Handler\BaseHandler;
class Plugin implements PluginInterface, EventSubscriberInterface
{
    /** @var Composer */
    private $composer;
    /** @var IOInterface */
    private $io;
    private $parser;
    public function __construct()
    {
        $this->parser = new DownloadsParser();
    }
    public static function getSubscribedEvents()
    {
        return [PackageEvents::POST_PACKAGE_INSTALL => ['installDownloads', 10], PackageEvents::POST_PACKAGE_UPDATE => ['updateDownloads', 10], ScriptEvents::POST_INSTALL_CMD => ['installDownloadsRoot', 10], ScriptEvents::POST_UPDATE_CMD => ['installDownloadsRoot', 10]];
    }
    public function installDownloadsRoot(Event $event)
    {
        $rootPackage = $this->composer->getPackage();
        $this->installUpdateDownloads(\getcwd(), $rootPackage);
        // Ensure that any other packages are properly reconciled.
        $localRepo = $this->composer->getRepositoryManager()->getLocalRepository();
        $installationManager = $this->composer->getInstallationManager();
        foreach ($localRepo->getCanonicalPackages() as $package) {
            /** @var \Composer\Package\PackageInterface $package */
            if (!empty($package->getExtra()['downloads'])) {
                $this->installUpdateDownloads($installationManager->getInstallPath($package), $package);
            }
        }
    }
    public function installDownloads(PackageEvent $event)
    {
        /** @var \Composer\Package\PackageInterface $package */
        $package = $event->getOperation()->getPackage();
        $installationManager = $event->getComposer()->getInstallationManager();
        $this->installUpdateDownloads($installationManager->getInstallPath($package), $package);
    }
    public function updateDownloads(PackageEvent $event)
    {
        /** @var \Composer\Package\PackageInterface $package */
        $package = $event->getOperation()->getTargetPackage();
        $installationManager = $event->getComposer()->getInstallationManager();
        $this->installUpdateDownloads($installationManager->getInstallPath($package), $package);
    }
    public function activate(Composer $composer, IOInterface $io)
    {
        $this->composer = $composer;
        $this->io = $io;
    }
    public function deactivate(Composer $composer, IOInterface $io)
    {
        // @todo determine if any operation required.
    }
    public function uninstall(Composer $composer, IOInterface $io)
    {
        // @todo determine if any operation required.
    }
    /**
     * @param string $basePath
     * @param PackageInterface $package
     */
    protected function installUpdateDownloads($basePath, $package)
    {
        $first = \TRUE;
        foreach ($this->parser->parse($package, $basePath) as $extraFileHandler) {
            /** @var BaseHandler $extraFileHandler */
            $extraFilePkg = $extraFileHandler->getSubpackage();
            $targetPath = $extraFileHandler->getTargetPath();
            $trackingFile = $extraFileHandler->getTrackingFile();
            if (\file_exists($targetPath) && !\file_exists($trackingFile)) {
                $this->io->write(\sprintf("<info>Extra file <comment>%s</comment> has been locally overriden in <comment>%s</comment>. To reset it, delete and reinstall.</info>", $extraFilePkg->getName(), $extraFilePkg->getTargetDir()), \TRUE);
                continue;
            }
            if (\file_exists($targetPath) && \file_exists($trackingFile)) {
                $meta = @\json_decode(\file_get_contents($trackingFile), 1);
                if (isset($meta['checksum']) && $meta['checksum'] === $extraFileHandler->getChecksum()) {
                    $this->io->write(\sprintf("<info>Skip extra file <comment>%s</comment></info>", $extraFilePkg->getName()), \TRUE, IOInterface::VERY_VERBOSE);
                    continue;
                }
            }
            if ($first) {
                $this->io->write(\sprintf("<info>Download extra files for <comment>%s</comment></info>", $package->getName()));
                $first = \FALSE;
            }
            $this->io->write(\sprintf("<info>Download extra file <comment>%s</comment></info>", $extraFilePkg->getName()), \TRUE, IOInterface::VERBOSE);
            $extraFileHandler->download($this->composer, $this->io);
            if (!\file_exists(\dirname($trackingFile))) {
                \mkdir(\dirname($trackingFile), 0777, \TRUE);
            }
            \file_put_contents($trackingFile, \json_encode($extraFileHandler->createTrackingData(), \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES));
        }
    }
}
<?php

/**
 * Created by PhpStorm.
 * User: totten
 * Date: 8/21/19
 * Time: 6:31 PM
 */
namespace CivixPhar\LastCall\DownloadsPlugin\Handler;

use CivixPhar\Composer\Composer;
use CivixPhar\Composer\IO\IOInterface;
use CivixPhar\Composer\Package\PackageInterface;
use CivixPhar\Composer\Package\RootPackageInterface;
use CivixPhar\Composer\Package\Version\VersionParser;
use CivixPhar\LastCall\DownloadsPlugin\Subpackage;
abstract class BaseHandler
{
    const FAKE_VERSION = 'dev-master';
    const DOT_DIR = '.composer-downloads';
    /**
     * @var array
     *   File specification from composer.json, with defaults/substitutions applied.
     */
    protected $extraFile;
    /**
     * @var PackageInterface
     */
    protected $parent;
    /**
     * @var string
     *   Path to the parent package.
     */
    protected $parentPath;
    /**
     * @var Subpackage
     */
    protected $subpackage;
    /**
     * BaseHandler constructor.
     * @param PackageInterface $parent
     * @param string $parentPath
     * @param array $extraFile
     */
    public function __construct(PackageInterface $parent, $parentPath, $extraFile)
    {
        $this->parent = $parent;
        $this->parentPath = $parentPath;
        $this->extraFile = $extraFile;
    }
    public function getSubpackage()
    {
        if ($this->subpackage === NULL) {
            $this->subpackage = $this->createSubpackage();
        }
        return $this->subpackage;
    }
    /**
     * @return Subpackage
     */
    public function createSubpackage()
    {
        $versionParser = new VersionParser();
        $extraFile = $this->extraFile;
        $parent = $this->parent;
        if (isset($extraFile['version'])) {
            // $version = $versionParser->normalize($extraFile['version']);
            $version = $versionParser->normalize(self::FAKE_VERSION);
            $prettyVersion = $extraFile['version'];
        } elseif ($parent instanceof RootPackageInterface) {
            $version = $versionParser->normalize(self::FAKE_VERSION);
            $prettyVersion = self::FAKE_VERSION;
        } else {
            $version = $parent->getVersion();
            $prettyVersion = $parent->getPrettyVersion();
        }
        $package = new Subpackage($parent, $extraFile['id'], $extraFile['url'], NULL, $extraFile['path'], $version, $prettyVersion);
        return $package;
    }
    public function createTrackingData()
    {
        return ['name' => $this->getSubpackage()->getName(), 'url' => $this->getSubpackage()->getDistUrl(), 'checksum' => $this->getChecksum()];
    }
    /**
     * @return string
     *   A unique identifier for this configuration of this asset.
     *   If the identifier changes, that implies that the asset should be
     *   replaced/redownloaded.
     */
    public function getChecksum()
    {
        $extraFile = $this->extraFile;
        return \hash('sha256', \serialize([\get_class($this), $extraFile['id'], $extraFile['url'], $extraFile['path']]));
    }
    /**
     * @return string
     */
    public function getTargetPath()
    {
        return $this->parentPath . '/' . $this->extraFile['path'];
    }
    /**
     * @param Composer $composer
     * @param IOInterface $io
     */
    public abstract function download(Composer $composer, IOInterface $io);
    /**
     * @return string
     */
    public abstract function getTrackingFile();
}
<?php

namespace CivixPhar\LastCall\DownloadsPlugin\Handler;

use CivixPhar\Composer\Composer;
use CivixPhar\Composer\IO\IOInterface;
use CivixPhar\Composer\Util\Filesystem;
use CivixPhar\React\Promise\PromiseInterface;
class FileHandler extends BaseHandler
{
    const TMP_PREFIX = '.composer-extra-tmp-';
    public function createSubpackage()
    {
        $pkg = parent::createSubpackage();
        $pkg->setDistType('file');
        return $pkg;
    }
    public function getTrackingFile()
    {
        $file = \basename($this->extraFile['id']) . '-' . \md5($this->extraFile['id']) . '.json';
        return \dirname($this->getTargetPath()) . \DIRECTORY_SEPARATOR . self::DOT_DIR . \DIRECTORY_SEPARATOR . $file;
    }
    /**
     * @param Composer $composer
     * @param IOInterface $io
     */
    public function download(Composer $composer, IOInterface $io)
    {
        // We want to take advantage of the cache in composer's downloader, but it
        // doesn't put the file the spot we want, so we shuffle a bit.
        $cfs = new Filesystem();
        $target = $this->getTargetPath();
        $tmpDir = \dirname($target) . \DIRECTORY_SEPARATOR . self::TMP_PREFIX . \basename($target);
        if (\file_exists($tmpDir)) {
            $cfs->remove($tmpDir);
        }
        if (\file_exists($target)) {
            $cfs->remove($target);
        }
        $pkg = clone $this->getSubpackage();
        $pkg->setTargetDir($tmpDir);
        $downloadManager = $composer->getDownloadManager();
        // composer:v2
        $version = \method_exists(Composer::class, 'getVersion') ? Composer::getVersion() : Composer::VERSION;
        if (\version_compare($version, '2.0.0') >= 0) {
            $file = '';
            $promise = $downloadManager->download($pkg, $tmpDir);
            $promise->then(static function ($res) use(&$file) {
                $file = $res;
            });
            $composer->getLoop()->wait([$promise]);
            $cfs->rename($file, $target);
            $cfs->remove($tmpDir);
        } else {
            $downloadManager->download($pkg, $tmpDir);
            foreach ((array) \glob("{$tmpDir}/*") as $file) {
                if (\is_file($file)) {
                    $cfs->rename($file, $target);
                    $cfs->remove($tmpDir);
                    break;
                }
            }
        }
    }
}
<?php

namespace CivixPhar\LastCall\DownloadsPlugin\Handler;

use CivixPhar\Composer\Composer;
use CivixPhar\Composer\IO\IOInterface;
use CivixPhar\Composer\Util\Platform;
class PharHandler extends FileHandler
{
    /**
     * @param Composer $composer
     * @param IOInterface $io
     */
    public function download(Composer $composer, IOInterface $io)
    {
        parent::download($composer, $io);
        if (Platform::isWindows()) {
            // TODO make .bat or .cmd
        } else {
            \chmod($this->getTargetPath(), 0777 ^ \umask());
        }
    }
}
<?php

namespace CivixPhar\LastCall\DownloadsPlugin\Handler;

use CivixPhar\Composer\Composer;
use CivixPhar\Composer\IO\IOInterface;
use CivixPhar\LastCall\DownloadsPlugin\GlobCleaner;
class ArchiveHandler extends BaseHandler
{
    public function createSubpackage()
    {
        $pkg = parent::createSubpackage();
        $pkg->setDistType($this->parseDistType($this->extraFile['url']));
        return $pkg;
    }
    protected function parseDistType($url)
    {
        $parts = \parse_url($url);
        $filename = \pathinfo($parts['path'], \PATHINFO_BASENAME);
        if (\preg_match('/\\.zip$/', $filename)) {
            return 'zip';
        } elseif (\preg_match('/\\.(tar\\.gz|tgz)$/', $filename)) {
            return 'tar';
        } else {
            throw new \RuntimeException("Failed to determine archive type for {$filename}");
        }
    }
    public function getTrackingFile()
    {
        $file = \basename($this->extraFile['id']) . '-' . \md5($this->extraFile['id']) . '.json';
        return $this->getTargetPath() . \DIRECTORY_SEPARATOR . self::DOT_DIR . \DIRECTORY_SEPARATOR . $file;
    }
    public function createTrackingData()
    {
        $meta = parent::createTrackingData();
        $meta['ignore'] = $this->findIgnores();
        return $meta;
    }
    public function getChecksum()
    {
        $ignore = empty($this->extraFile['ignore']) ? [] : \array_values($this->extraFile['ignore']);
        \sort($ignore);
        return \hash('sha256', parent::getChecksum() . \serialize($ignore));
    }
    /**
     * @return string[]|NULL
     *   List of files to exclude. Use '**' to match subdirectories.
     *   Ex: ['.gitignore', '*.md']
     */
    public function findIgnores()
    {
        return isset($this->extraFile['ignore']) ? $this->extraFile['ignore'] : NULL;
    }
    /**
     * @param Composer $composer
     * @param IOInterface $io
     */
    public function download(Composer $composer, IOInterface $io)
    {
        $targetPath = $this->getTargetPath();
        $downloadManager = $composer->getDownloadManager();
        // In composer:v2, download and extract were separated.
        $version = \method_exists(Composer::class, 'getVersion') ? Composer::getVersion() : Composer::VERSION;
        if (\version_compare($version, '2.0.0') >= 0) {
            $promise = $downloadManager->download($this->getSubpackage(), $targetPath);
            $composer->getLoop()->wait([$promise]);
            $promise = $downloadManager->install($this->getSubpackage(), $targetPath);
            $composer->getLoop()->wait([$promise]);
        } else {
            $downloadManager->download($this->getSubpackage(), $targetPath);
        }
        GlobCleaner::clean($io, $targetPath, $this->findIgnores());
    }
}
<?php

/*
 * This file is part of Composer Extra Files Plugin.
 *
 * (c) 2017 Last Call Media, Rob Bayliss <rob@lastcallmedia.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */
namespace CivixPhar\LastCall\DownloadsPlugin;

use CivixPhar\Composer\Package\PackageInterface;
use CivixPhar\LastCall\DownloadsPlugin\Handler\ArchiveHandler;
use CivixPhar\LastCall\DownloadsPlugin\Handler\BaseHandler;
use CivixPhar\LastCall\DownloadsPlugin\Handler\FileHandler;
use CivixPhar\LastCall\DownloadsPlugin\Handler\PharHandler;
class DownloadsParser
{
    /**
     * @param \Composer\Package\PackageInterface $package
     *
     * @return BaseHandler[]
     *   Each item is a specification of an extra file, with defaults and variables evaluated.
     */
    public function parse(PackageInterface $package, $basePath)
    {
        $extraFiles = [];
        $extra = $package->getExtra();
        $defaults = isset($extra['downloads']['*']) ? $extra['downloads']['*'] : [];
        if (!empty($extra['downloads'])) {
            foreach ((array) $extra['downloads'] as $id => $extraFile) {
                if ($id === '*') {
                    continue;
                }
                $extraFile = \array_merge($defaults, $extraFile);
                $extraFile['id'] = $id;
                foreach (['url', 'path'] as $prop) {
                    if (isset($extraFile[$prop])) {
                        $extraFile[$prop] = \strtr($extraFile[$prop], ['{$id}' => $extraFile['id'], '{$version}' => isset($extraFile['version']) ? $extraFile['version'] : '']);
                    }
                }
                $class = $this->pickClass($extraFile);
                $extraFiles[] = new $class($package, $basePath, $extraFile);
            }
        }
        return $extraFiles;
    }
    public function pickClass($extraFile)
    {
        $types = ['archive' => ArchiveHandler::CLASS, 'file' => FileHandler::CLASS, 'phar' => PharHandler::CLASS];
        if (isset($extraFile['type'], $types[$extraFile['type']])) {
            return $types[$extraFile['type']];
        }
        $parts = \parse_url($extraFile['url']);
        $filename = \pathinfo($parts['path'], \PATHINFO_BASENAME);
        if (\preg_match('/\\.(zip|tar\\.gz|tgz)$/', $filename)) {
            return $types['archive'];
        }
        return $types['file'];
    }
}
<?php

namespace CivixPhar\LastCall\DownloadsPlugin;

use CivixPhar\Composer\IO\IOInterface;
class GlobCleaner
{
    /**
     * @param IOInterface $io
     * @param string $baseDir
     * @param string[] $ignores
     * @return \Generator|void
     */
    public static function clean(IOInterface $io, $baseDir, $ignores)
    {
        if (empty($ignores)) {
            return;
        }
        $dirs = [];
        $finder = new \CivixPhar\TOGoS_GitIgnore_FileFinder(array('ruleset' => \CivixPhar\TOGoS_GitIgnore_Ruleset::loadFromStrings($ignores), 'invertRulesetResult' => \false, 'defaultResult' => \false, 'includeDirectories' => \false, 'callback' => function ($file, $match) use($baseDir, &$dirs) {
            if ($match) {
                \unlink("{$baseDir}/{$file}");
                $dir = \dirname($file);
                if ($dir !== '.') {
                    $dirs[\dirname($file)] = 1;
                }
            }
        }));
        $finder->findFiles($baseDir);
        // Cleanup any empy directories
        $dirNames = \array_keys($dirs);
        $byLength = function ($a, $b) {
            return \strlen($b) - \strlen($a);
        };
        \usort($dirNames, $byLength);
        while ($dirName = \array_shift($dirNames)) {
            if (!\glob("{$baseDir}/{$dirName}/*")) {
                @\rmdir("{$baseDir}/{$dirName}");
                $dirNames[] = \dirname($dirName);
                \usort($dirNames, $byLength);
            }
        }
    }
}
<?php

/*
 * This file is part of Composer Extra Files Plugin.
 *
 * (c) 2017 Last Call Media, Rob Bayliss <rob@lastcallmedia.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */
namespace CivixPhar\LastCall\DownloadsPlugin;

use CivixPhar\Composer\IO\IOInterface;
use CivixPhar\Composer\Package\Package;
use CivixPhar\Composer\Package\PackageInterface;
use CivixPhar\Composer\Package\RootPackageInterface;
/**
 * Class Subpackage
 * @package LastCall\DownloadsPlugin
 *
 * A subpackage is simulated package which lives beneath some parent package.
 */
class Subpackage extends Package
{
    /**
     * @var PackageInterface
     */
    private $parent;
    public function __construct(PackageInterface $parent, $id, $url, $type, $path, $version = NULL, $prettyVersion = NULL)
    {
        parent::__construct(\sprintf('%s:%s', $parent->getName(), $id), $version ? $version : $parent->getVersion(), $prettyVersion ? $prettyVersion : $parent->getPrettyVersion());
        $this->parent = $parent;
        $this->id = $id;
        $this->setDistUrl($url);
        $this->setDistType($type);
        $this->setTargetDir($path);
        $this->setInstallationSource('dist');
    }
}
<?php

namespace Civi\Cv;

/**
 * This is all so evil. It shouldn't exist. God save ye wretched souls who
 * seek to reconcile all the error-handlers of all the platforms.
 */
class ErrorHandler
{
    private static $hasShutdown = \FALSE;
    private static $count = 0;
    private static $renderer = NULL;
    public static function pushHandler()
    {
        static::$count++;
        if (!static::$hasShutdown) {
            static::$hasShutdown = \TRUE;
            \register_shutdown_function([static::class, 'onShutdown']);
        }
        // set_error_handler([static::class, 'onError']);
        \set_error_handler([static::class, 'onError']);
        \set_exception_handler([static::class, 'onException']);
    }
    public static function popHandler()
    {
        static::$count--;
        \restore_error_handler();
        \restore_exception_handler();
    }
    public static function onShutdown()
    {
        if (static::$count > 0) {
            $error = \error_get_last();
            if (isset($error['type']) && $error['type'] & (\E_ERROR | \E_PARSE | \E_CORE_ERROR | \E_COMPILE_ERROR | \E_USER_ERROR | \E_RECOVERABLE_ERROR)) {
                // Something - like a bad eval() - interrupted normal execution.
                // Make sure the status code reflects that.
                exit(255);
            }
        }
    }
    public static function onError($errorLevel, $message, $filename, $line)
    {
        if ($errorLevel & \error_reporting()) {
            $errorType = static::getErrorTypes()[$errorLevel] ?: "Unknown[{$errorLevel}]";
            \fprintf(\STDERR, "[%s] %s at %s:%d\n", $errorType, $message, $filename, $line);
            return \TRUE;
        } else {
            return \FALSE;
        }
    }
    /**
     * @param \Throwable $exception
     */
    public static function onException($exception)
    {
        if (isset(static::$renderer)) {
            \call_user_func(static::$renderer, $exception);
        } else {
            \fprintf(\STDERR, "Exception: %s (%s)\n%s", $exception->getMessage(), \get_class($exception), $exception->getTraceAsString());
        }
        exit(255);
    }
    /**
     * @param callable|null $renderer
     */
    public static function setRenderer(?callable $renderer) : void
    {
        self::$renderer = $renderer;
    }
    protected static function getErrorTypes() : array
    {
        return [\E_ERROR => 'PHP Error', \E_WARNING => 'PHP Warning', \E_PARSE => 'PHP Parse Error', \E_NOTICE => 'PHP Notice', \E_CORE_ERROR => 'PHP Core Error', \E_CORE_WARNING => 'PHP Core Warning', \E_COMPILE_ERROR => 'PHP Compile Error', \E_COMPILE_WARNING => 'PHP Compile Warning', \E_USER_ERROR => 'PHP User Error', \E_USER_WARNING => 'PHP User Warning', \E_USER_NOTICE => 'PHP User Notice', \E_STRICT => 'PHP Strict Warning', \E_RECOVERABLE_ERROR => 'PHP Recoverable Fatal Error', \E_DEPRECATED => 'PHP Deprecation', \E_USER_DEPRECATED => 'PHP User Deprecation'];
    }
}
<?php

namespace Civi\Cv;

use Civi\Cv\Util\Filesystem;
class BuildkitReader
{
    /**
     * Given a civicrm.settings.php file, find the matching buildkit .sh config file.
     *
     * @param string $settingsFile
     * @return null|string
     */
    public static function findShFile($settingsFile)
    {
        $fs = new Filesystem();
        $settingsFile = $fs->toAbsolutePath($settingsFile);
        $parts = \explode('/', \str_replace('\\', '/', $settingsFile));
        while (!empty($parts)) {
            $last = \array_pop($parts);
            $basePath = \implode('/', $parts);
            $shFile = "{$basePath}/{$last}.sh";
            if (\is_dir("{$basePath}/{$last}") && \file_exists($shFile)) {
                // Does it look vaguely like a buildkit config file?
                if (\preg_match('/ADMIN_USER=/', \file_get_contents($shFile))) {
                    return $shFile;
                }
            }
        }
        return NULL;
    }
    /**
     * Parse the key-value paris in buildkit .sh config file.
     *
     * @param string $shFile
     * @return array
     */
    public static function readShFile($shFile)
    {
        $lines = \explode("\n", \file_get_contents($shFile));
        $result = array();
        foreach ($lines as $line) {
            if (empty($line) || $line[0] == '#') {
                continue;
            }
            if (\preg_match('/^([A-Z0-9_]+)=\\"(.*)\\"$/', $line, $matches)) {
                $result[$matches[1]] = \stripcslashes($matches[2]);
            } else {
                throw new \RuntimeException("Malformed line [{$line}]");
            }
        }
        return $result;
    }
}
<?php

namespace Civi\Cv;

/**
 * Bootstrap the CMS runtime.
 *
 * @code
 * // Use default bootstrap
 * require_once '/path/to/CmsBootstrap.php';
 * Civi\Cv\CmsBootstrap::singleton()->bootCms()->bootCivi();
 *
 * // Use custom bootstrap
 * require_once '/path/to/CmsBootstrap.php';
 * Civi\Cv\CmsBootstrap::singleton()
 *   ->addOptions(array(...))
 *   ->bootCms()
 *   ->bootCivi();
 * @endcode
 *
 * This class is intended to be run *before* the classloader is available. Therefore, it
 * must be self-sufficient - do not rely on other classes, even in the same package.
 *
 * By default, bootstrap will scan PWD and every ancestor directory to see if it
 * contains a supported CMS. If you have performance considerations, or if the
 * directory structure is not amenable to scanning, then set the environment
 * variable CIVICRM_BOOT (in bashrc and/or httpd vhost).
 *
 * The bootstrapper accepts a few options (either via the constructor or addOptions()). They are:
 *   - env: string|NULL. The environment variable which may contain boot options
 *     Ex: 'Drupal://var/www' or 'WordPress://admin@var/www'. Set NULL to disable.
 *     (Default: CIVICRM_BOOT)
 *   - search: bool|string. Attempt to determine root+settings by searching
 *     the file system and checking against common Civi directory structures.
 *     Boolean TRUE means it should use a default (PWD).
 *     (Default: TRUE aka PWD)
 *   - user: string|NULL. The name of a CMS user to authenticate as.
 *   - httpHost: string|NULL. For multisite, the HTTP hostname.
 *   - log: \Psr\Log\LoggerInterface|\Civi\Cv\Log\InternalLogger (If given, send log messages here)
 *   - output: Symfony OutputInterface. (Fallback for handling logs - in absence of 'log')
 *
 * @package Civi
 */
class CmsBootstrap
{
    protected static $singleton = NULL;
    protected $options = array();
    /**
     * @var \Psr\Log\LoggerInterface|\Civi\Cv\Log\InternalLogger
     */
    protected $log = NULL;
    /**
     * @var array|null
     */
    protected $bootedCms = NULL;
    /**
     * Holds the requested user to login as for Standalone.
     * Normally the user is loaded in bootCms but since Civi is our CMS,
     * we have to wait for bootCivi().
     *
     * @var string|null
     */
    protected $deferredUserToLogin = NULL;
    /**
     * @param string $text
     * @param int $level
     * @deprecated
     */
    public function writeln($text, $level = 32)
    {
        $this->log->info($text);
    }
    /**
     * @return CmsBootstrap
     */
    public static function singleton()
    {
        if (self::$singleton === NULL) {
            self::$singleton = new \Civi\Cv\CmsBootstrap(array('env' => 'CIVICRM_BOOT', 'search' => \TRUE, 'httpHost' => \array_key_exists('HTTP_HOST', $_SERVER) ? $_SERVER['HTTP_HOST'] : 'localhost', 'user' => NULL));
        }
        return self::$singleton;
    }
    /**
     * @param array $options
     *   See options in class doc.
     */
    public function __construct($options = array())
    {
        $this->addOptions($options);
    }
    /**
     * Export bootstrap logic.
     *
     * @param array $actions
     *   List of bootstrap actions to include.
     *   Ex: ['bootCms', 'bootCivi']
     * @return string
     *   PHP code to `CmsBootstrap` in a new process
     */
    public function generate(array $actions = []) : string
    {
        $instanceExpr = '\\' . \get_class($this) . '::singleton()';
        $code = '';
        $code .= \sprintf("require_once %s;\n", \var_export(CV_AUTOLOAD, \TRUE));
        $code .= \sprintf("%s->addOptions(%s);\n", $instanceExpr, \var_export($this->getOptions(), \TRUE));
        foreach ($actions as $action) {
            $code .= \sprintf("%s->%s()->bootCivi();\n", $instanceExpr, $action);
        }
        return $code;
    }
    /**
     * Bootstrap the CiviCRM runtime.
     *
     * @return CmsBootstrap
     * @throws \Exception
     */
    public function bootCms()
    {
        $this->log->debug("Options: " . \json_encode($this->options, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES));
        if ($this->options['env'] && \getenv($this->options['env'])) {
            $cmsExpr = \getenv($this->options['env']);
            $this->log->debug("Parse CMS options ({$cmsExpr})");
            $cms = array('type' => \parse_url($cmsExpr, \PHP_URL_SCHEME), 'path' => '/' . \parse_url($cmsExpr, \PHP_URL_HOST) . \parse_url($cmsExpr, \PHP_URL_PATH));
            $cms['path'] = \preg_replace(';^//+;', '/', $cms['path']);
            if ($cms['type'] === 'Auto') {
                $isAutoPath = \trim($cms['path'], '/') === '.';
                $cms = $this->findCmsRoot($isAutoPath ? $this->getSearchDir() : $cms['path']);
            }
            if (!isset($this->options['user']) && \parse_url($cmsExpr, \PHP_URL_USER)) {
                $this->options['user'] = \parse_url($cmsExpr, \PHP_URL_USER);
            }
            if (\parse_url($cmsExpr, \PHP_URL_QUERY)) {
                \parse_str(\parse_url($cmsExpr, \PHP_URL_QUERY), $query);
                if (!empty($query['host'])) {
                    $this->options['httpHost'] = $query['host'];
                }
            }
        } else {
            $this->log->debug("Find CMS...");
            $cms = $this->findCmsRoot($this->getSearchDir());
        }
        $this->log->debug("CMS: " . \json_encode($cms, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES));
        if (empty($cms['path']) || empty($cms['type']) || !\file_exists($cms['path'])) {
            $cmsJson = \json_encode($cms, \JSON_UNESCAPED_SLASHES);
            throw new \Exception("Failed to parse or find a CMS {$cmsJson}");
        }
        if (\PHP_SAPI === "cli") {
            $this->log->debug("Simulate web environment in CLI");
            $this->simulateWebEnv($this->options['httpHost'], $cms['path'] . '/index.php');
        }
        $func = 'boot' . $cms['type'];
        if (!\is_callable([$this, $func])) {
            throw new \Exception("Failed to locate boot function ({$func})");
        }
        \call_user_func([$this, $func], $cms['path'], $this->options['user'], $this->options['httpHost']);
        if (\PHP_SAPI === "cli") {
            \error_reporting(1);
        }
        $this->log->debug("Finished");
        $this->bootedCms = $cms;
        return $this;
    }
    /**
     * Determine what, if any, CMS has been bootstrapped.
     *
     * @return string|NULL
     *   Ex: 'Backdrop', 'Drupal', 'Drupal8', 'Joomla', 'WordPress'.
     */
    public function getBootedCmsType()
    {
        return isset($this->bootedCms['type']) ? $this->bootedCms['type'] : NULL;
    }
    /**
     * Determine what, if any, CMS has been bootstrapped.
     *
     * @return string|NULL
     *   Ex: '/var/www'.
     */
    public function getBootedCmsPath()
    {
        return isset($this->bootedCms['path']) ? $this->bootedCms['path'] : NULL;
    }
    /**
     * @return $this
     * @throws \Exception
     */
    public function bootCivi()
    {
        // PRE-CONDITIONS: CMS has already been booted, and Civi is already installed.
        if (\function_exists('civicrm_initialize')) {
            \civicrm_initialize();
        } elseif (\class_exists('Drupal')) {
            //Drupal 8 / 9
            \Drupal::service('civicrm')->initialize();
        } elseif ($this->bootedCms['type'] === 'Standalone') {
            $this->log->debug("Hello there Standalone, come join us!");
            \Civi\Cv\Bootstrap::singleton()->boot();
            $this->loginStandaloneUser();
        } else {
            throw new \Exception("This system does not appear to have CiviCRM");
        }
        if (!empty($this->options['user'])) {
            $this->ensureUserContact();
        }
        // Some UF integrations/versions don't seem to do this... work-around...
        if (\is_callable([\CRM_Core_Config::singleton()->userSystem, 'setMySQLTimeZone'])) {
            \CRM_Core_Config::singleton()->userSystem->setMySQLTimeZone();
        }
        $GLOBALS['_CV'] = $this->buildCv();
        return $this;
    }
    protected function buildCv() : array
    {
        $settings = \constant('CIVICRM_SETTINGS_PATH');
        if ($settings && \class_exists('Civi\\Cv\\SiteConfigReader')) {
            $this->log->debug("Load supplemental configuration for \"{$settings}\"");
            $reader = new \Civi\Cv\SiteConfigReader($settings);
            return $reader->compile(array('buildkit', 'home'));
        } else {
            $this->log->debug("Warning: Not loading supplemental configuration for \"{$settings}\". SiteConfigReader is missing.");
            return [];
        }
    }
    /**
     */
    protected function loginStandaloneUser()
    {
        if (!empty($this->deferredUserToLogin)) {
            global $loggedInUserId;
            if (\class_exists(\Civi\Api4\User::class)) {
                $userID = \Civi\Api4\User::get(\FALSE)->addWhere('username', '=', $this->deferredUserToLogin)->addWhere('is_active', '=', 1)->execute()->single();
                \CRM_Core_Session::singleton()->set('ufId', $userID);
                $loggedInUserId = $userID['contact_id'];
            }
            if (empty($loggedInUserId)) {
                throw new \RuntimeException("Unable to login as '{$this->deferredUserToLogin}'");
            }
        }
    }
    public function bootBackdrop($cmsPath, $cmsUser)
    {
        if (!\file_exists("{$cmsPath}/core/includes/bootstrap.inc")) {
            throw new \Exception('Sorry, could not locate Backdrop\'s bootstrap.inc');
        }
        \chdir($cmsPath);
        \define('BACKDROP_ROOT', $cmsPath);
        require_once "{$cmsPath}/core/includes/bootstrap.inc";
        require_once "{$cmsPath}/core/includes/config.inc";
        \backdrop_bootstrap(BACKDROP_BOOTSTRAP_FULL);
        if (!\function_exists('module_exists')) {
            throw new \Exception('Sorry, could not bootstrap Backdrop.');
        }
        if ($cmsUser) {
            global $user;
            $user = \user_load(array('name' => $cmsUser));
        }
        return $this;
    }
    public function bootDrupal($cmsPath, $cmsUser)
    {
        if (!\file_exists("{$cmsPath}/includes/bootstrap.inc")) {
            // Sanity check.
            throw new \Exception('Sorry, could not locate Drupal\'s bootstrap.inc');
        }
        \chdir($cmsPath);
        \define('DRUPAL_ROOT', $cmsPath);
        require_once 'includes/bootstrap.inc';
        \drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
        if (!\function_exists('module_exists')) {
            throw new \Exception('Sorry, could not bootstrap Drupal.');
        }
        if ($cmsUser) {
            global $user;
            $user = \user_load_by_name($cmsUser);
        }
        return $this;
    }
    public function bootDrupal8($cmsRootPath, $cmsUser)
    {
        if (!\file_exists("{$cmsRootPath}/core/core.services.yml")) {
            // Sanity check.
            throw new \Exception('Sorry, could not locate Drupal8\'s core.services.yml');
        }
        \chdir($cmsRootPath);
        \define('DRUPAL_DIR', $cmsRootPath);
        $autoloader = (require_once DRUPAL_DIR . '/autoload.php');
        $request = \Symfony\Component\HttpFoundation\Request::createFromGlobals();
        $kernel = \Drupal\Core\DrupalKernel::createFromRequest($request, $autoloader, 'prod');
        $kernel->boot();
        $kernel->preHandle($request);
        $container = $kernel->rebuildContainer();
        // Add our request to the stack and route context.
        $request->attributes->set(\Drupal\Core\Routing\RouteObjectInterface::ROUTE_OBJECT, new \Symfony\Component\Routing\Route('<none>'));
        $request->attributes->set(\Drupal\Core\Routing\RouteObjectInterface::ROUTE_NAME, '<none>');
        $container->get('request_stack')->push($request);
        $container->get('router.request_context')->fromRequest($request);
        if (!\function_exists('t')) {
            throw new \Exception('Sorry, could not bootstrap Drupal8.');
        }
        if ($cmsUser) {
            // Drupal 8
            if (\method_exists('Drupal', 'entityManager')) {
                $entity_manager = \Drupal::entityManager();
                $users = $entity_manager->getStorage($entity_manager->getEntityTypeFromClass('Drupal\\user\\Entity\\User'))->loadByProperties(array('name' => $cmsUser));
            } else {
                // Drupal 9
                $entity_manager = \Drupal::entityTypeManager();
                $users = $entity_manager->getStorage(\Drupal::service('entity_type.repository')->getEntityTypeFromClass('Drupal\\user\\Entity\\User'))->loadByProperties(['name' => $cmsUser]);
            }
            if (\count($users) == 1) {
                foreach ($users as $uid => $user) {
                    \user_login_finalize($user);
                }
            } elseif (empty($users)) {
                throw new \Exception(\sprintf("Failed to find Drupal8 user (%s)", $cmsUser));
            } else {
                throw new \Exception(\sprintf("Found too many Drupal8 users (%d)", \count($users)));
            }
        }
        return $this;
    }
    // TODO public function bootJoomla($cmsRootPath, $cmsUser) { }
    /**
     * @param string $cmsRootPath
     * @param string $cmsUser
     * @return $this
     */
    public function bootWordPress($cmsRootPath, $cmsUser)
    {
        if (!\file_exists($cmsRootPath . \DIRECTORY_SEPARATOR . 'wp-load.php')) {
            throw new \Exception('Sorry, could not locate WordPress\'s wp-load.php.');
        }
        \chdir($cmsRootPath);
        require_once $cmsRootPath . \DIRECTORY_SEPARATOR . 'wp-load.php';
        if (!\function_exists('wp_set_current_user')) {
            throw new \Exception('Sorry, could not bootstrap WordPress.');
        }
        if ($cmsUser) {
            \wp_set_current_user(NULL, $cmsUser);
        }
        return $this;
    }
    /**
     * @param string $cmsPath
     * @param string $cmsUser
     * @return $this
     */
    public function bootStandalone($cmsPath, $cmsUser)
    {
        /* @todo clarify: assumes $cmsPath is to the project root, not the webroot */
        $candidates = [$cmsPath . '/vendor/autoload.php', $cmsPath . '/web/core/vendor/autoload.php', \dirname($cmsPath) . '/vendor/autoload.php'];
        $autoloader = NULL;
        foreach ($candidates as $candidate) {
            if (\file_exists($candidate)) {
                $autoloader = $candidate;
                break;
            }
        }
        if (!$autoloader) {
            throw new \RuntimeException("Failed to find autoloader. Possibilities: " . \implode(', ', $candidates));
        }
        require_once $autoloader;
        $this->deferredUserToLogin = $cmsUser ?? NULL;
        return $this;
    }
    /**
     * @return array
     *   See options in class doc.
     */
    public function getOptions()
    {
        return $this->options;
    }
    /**
     * @param array $options
     *   See options in class doc.
     * @return CmsBootstrap
     */
    public function addOptions($options)
    {
        $this->options = \array_merge($this->options, $options);
        $this->log = \Civi\Cv\Log\Logger::resolve($options, 'CmsBootstrap');
        return $this;
    }
    /**
     * @param string $searchDir
     *   The directory from which to begin the upward search.
     * @return array|NULL
     *   Ex: ['path' => '/var/www', 'type' => 'WordPress]
     */
    protected function findCmsRoot($searchDir)
    {
        // A list of file patterns; if one of the patterns matches a give
        // directory, then we can assume that this directory is the
        // CMS root.
        $cmsPatterns = array('WordPress' => array(
            // 'wp-includes/version.php',
            'wp-load.php',
        ), 'Joomla' => array('administrator/components/com_users/users.php'), 'Drupal' => array('modules/system/system.module'), 'Drupal8' => array('core/core.services.yml'), 'Backdrop' => array('core/modules/layout/layout.module'), 'Standalone' => array('civicrm.config.php.standalone'));
        $parts = \explode('/', \str_replace('\\', '/', $searchDir));
        while (!empty($parts)) {
            $basePath = \implode('/', $parts);
            foreach ($cmsPatterns as $cmsType => $relPaths) {
                if (!empty($this->options['cmsType']) && $this->options['cmsType'] != $cmsType) {
                    continue;
                }
                foreach ($relPaths as $relPath) {
                    $matches = \glob("{$basePath}/{$relPath}");
                    if (!empty($matches)) {
                        return array('path' => $basePath, 'type' => $cmsType);
                    }
                    $matches = \glob("{$basePath}/web/{$relPath}");
                    if (!empty($matches)) {
                        return array('path' => "{$basePath}/web", 'type' => $cmsType);
                    }
                    if ($cmsType === 'Standalone') {
                        $matches = \glob("{$basePath}/srv/{$relPath}");
                        if (!empty($matches)) {
                            return array('path' => "{$basePath}/srv", 'type' => $cmsType);
                        }
                    }
                }
            }
            \array_pop($parts);
        }
        return NULL;
    }
    /**
     * @return string
     */
    protected function getSearchDir()
    {
        if ($this->options['search'] === \TRUE) {
            // exec(pwd) works better with symlinked source trees, but it's
            // probably not portable to Windows.
            if (\strtoupper(\substr(\PHP_OS, 0, 3)) === 'WIN') {
                return \getcwd();
            } else {
                \exec('pwd', $output);
                return \trim(\implode("\n", $output));
            }
        } else {
            return $this->options['search'];
        }
    }
    /**
     * @param $scriptFile
     * @param $host
     */
    protected function simulateWebEnv($host, $scriptFile)
    {
        $_SERVER['SCRIPT_FILENAME'] = $scriptFile;
        $_SERVER['REMOTE_ADDR'] = "127.0.0.1";
        $_SERVER['SERVER_SOFTWARE'] = NULL;
        $_SERVER['REQUEST_METHOD'] = 'GET';
        $_SERVER['SERVER_NAME'] = $host;
        $_SERVER['HTTP_HOST'] = $host;
        if (\ord($_SERVER['SCRIPT_NAME']) != 47) {
            $_SERVER['SCRIPT_NAME'] = '/' . $_SERVER['SCRIPT_NAME'];
        }
    }
    protected function ensureUserContact()
    {
        if ($cid = \CRM_Core_Session::getLoggedInContactID()) {
            return $cid;
        }
        // Ugh, this codepath.
        switch (CIVICRM_UF) {
            case 'Drupal':
            case 'Drupal6':
            case 'Backdrop':
                \CRM_Core_BAO_UFMatch::synchronize($GLOBALS['user'], \TRUE, CIVICRM_UF, 'Individual');
                break;
            case 'Drupal8':
                $user = \Drupal\user\Entity\User::load(\Drupal::currentUser()->id());
                \CRM_Core_BAO_UFMatch::synchronize($user, \TRUE, CIVICRM_UF, 'Individual');
                break;
            case 'Joomla':
                \CRM_Core_BAO_UFMatch::synchronize(\JFactory::getUser(), \TRUE, CIVICRM_UF, 'Individual');
                break;
            case 'WordPress':
                \CRM_Core_BAO_UFMatch::synchronize($GLOBALS['current_user'], \TRUE, CIVICRM_UF, 'Individual');
                break;
            default:
                $this->log->error("Unrecognized UF: " . CIVICRM_UF);
        }
        return \CRM_Core_Session::getLoggedInContactID();
    }
}
<?php

namespace Civi\Cv\Log;

/**
 * This is a work-a-like for PSR Log.
 *
 * In the wild, there are too many major versions of `psr/log` floating around,
 * and we have to execute without knowing what's needed.
 *
 * Downstream consumers may know more about which flavor is in play. If they want
 * to convert between contracts, it should be fairly easy:
 *
 *   // Take the $internalLog and present as a $psrLog.
 *   $psrLog = new class extends \Psr\Log\AbstractLogger {
 *      public function log(...) { $internalLog->log(...); }
 *   };
 *
 *   // Take the $psrLog and present as an $internalLog.
 *   $internalLog = new class extends \Civi\Cv\Log\InternalLogger {
 *     public function log(...) { $psrLog->log(...); }
 *   };
 */
abstract class InternalLogger
{
    protected $topic;
    public function __construct(string $topic)
    {
        $this->topic = $topic;
    }
    protected function interpolate(string $message, array $context) : string
    {
        if (\strpos($message, '{') === \FALSE) {
            return $message;
        }
        $replacements = [];
        foreach ($context as $key => $val) {
            if (NULL === $val || \is_scalar($val) || \is_object($val) && \method_exists($val, '__toString')) {
                $replacements["{{$key}}"] = $val;
            } elseif ($val instanceof \DateTimeInterface) {
                $replacements["{{$key}}"] = $val->format(\DateTime::RFC3339);
            } elseif (\is_object($val)) {
                $replacements["{{$key}}"] = '[object ' . \get_class($val) . ']';
            } else {
                $replacements["{{$key}}"] = '[' . \gettype($val) . ']';
            }
            $replacements["{{$key}}"] = $this->decorateInterpolatedValue($replacements["{{$key}}"]);
        }
        return \strtr($message, $replacements);
    }
    protected function decorateInterpolatedValue(string $value) : string
    {
        return $value;
    }
    /**
     * @param $level
     * @return bool
     */
    protected function isAnomolous($level) : bool
    {
        return \in_array($level, ['warning', 'error', 'emergency', 'critical']);
    }
    /**
     * Logs with an arbitrary level.
     *
     * @param mixed $level
     * @param string $message
     * @param mixed[] $context
     *
     * @return void
     *
     * @throws \Psr\Log\InvalidArgumentException
     */
    public abstract function log($level, $message, array $context = array());
    /**
     * System is unusable.
     *
     * @param string $message
     * @param mixed[] $context
     *
     * @return void
     */
    public function emergency($message, array $context = array())
    {
        $this->log('emergency', $message, $context);
    }
    /**
     * Action must be taken immediately.
     *
     * Example: Entire website down, database unavailable, etc. This should
     * trigger the SMS alerts and wake you up.
     *
     * @param string $message
     * @param mixed[] $context
     *
     * @return void
     */
    public function alert($message, array $context = array())
    {
        $this->log('alert', $message, $context);
    }
    /**
     * Critical conditions.
     *
     * Example: Application component unavailable, unexpected exception.
     *
     * @param string $message
     * @param mixed[] $context
     *
     * @return void
     */
    public function critical($message, array $context = array())
    {
        $this->log('critical', $message, $context);
    }
    /**
     * Runtime errors that do not require immediate action but should typically
     * be logged and monitored.
     *
     * @param string $message
     * @param mixed[] $context
     *
     * @return void
     */
    public function error($message, array $context = array())
    {
        $this->log('error', $message, $context);
    }
    /**
     * Exceptional occurrences that are not errors.
     *
     * Example: Use of deprecated APIs, poor use of an API, undesirable things
     * that are not necessarily wrong.
     *
     * @param string $message
     * @param mixed[] $context
     *
     * @return void
     */
    public function warning($message, array $context = array())
    {
        $this->log('warning', $message, $context);
    }
    /**
     * Normal but significant events.
     *
     * @param string $message
     * @param mixed[] $context
     *
     * @return void
     */
    public function notice($message, array $context = array())
    {
        $this->log('notice', $message, $context);
    }
    /**
     * Interesting events.
     *
     * Example: User logs in, SQL logs.
     *
     * @param string $message
     * @param mixed[] $context
     *
     * @return void
     */
    public function info($message, array $context = array())
    {
        $this->log('info', $message, $context);
    }
    /**
     * Detailed debug information.
     *
     * @param string $message
     * @param mixed[] $context
     *
     * @return void
     */
    public function debug($message, array $context = array())
    {
        $this->log('debug', $message, $context);
    }
}
<?php

namespace Civi\Cv\Log;

use CivixPhar\Symfony\Component\Console\Output\ConsoleOutputInterface;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
/**
 * Send log messages to the console with Symfony formatting codes.
 */
class SymfonyConsoleLogger extends \Civi\Cv\Log\InternalLogger
{
    private $verbosityLevelMap;
    /**
     * @var \Symfony\Component\Console\Output\OutputInterface
     */
    protected $output;
    /**
     * @param string $topic
     * @param \Symfony\Component\Console\Output\OutputInterface $output
     */
    public function __construct(string $topic, $output)
    {
        parent::__construct($topic);
        $this->output = $output;
        $this->verbosityLevelMap = ['emergency' => OutputInterface::VERBOSITY_NORMAL, 'alert' => OutputInterface::VERBOSITY_NORMAL, 'critical' => OutputInterface::VERBOSITY_NORMAL, 'error' => OutputInterface::VERBOSITY_NORMAL, 'warning' => OutputInterface::VERBOSITY_NORMAL, 'notice' => OutputInterface::VERBOSITY_VERBOSE, 'info' => OutputInterface::VERBOSITY_VERY_VERBOSE, 'debug' => OutputInterface::VERBOSITY_DEBUG];
    }
    public function log($level, $message, array $context = [])
    {
        $output = $this->output;
        if ($output instanceof ConsoleOutputInterface) {
            $output = $output->getErrorOutput();
        }
        if ($this->isAnomolous($level)) {
            $template = '<error>[%s:%s]</error> %s';
        } else {
            $template = '<info>[%s:%s]</info> %s';
        }
        if ($output->getVerbosity() >= $this->verbosityLevelMap[$level]) {
            $output->writeln(\sprintf($template, $this->topic, $level, $this->interpolate($message, $context)), $this->verbosityLevelMap[$level]);
        }
    }
    protected function decorateInterpolatedValue(string $value) : string
    {
        return "<comment>{$value}</comment>";
    }
}
<?php

namespace Civi\Cv\Log;

class Logger
{
    /**
     * Determine which logger to use.
     *
     * @param array $options
     *   Some mix of the following:
     *   - log: \Psr\Log\LoggerInterface|\Civi\Cv\Log\InternalLogger (If given, send log messages here)
     *   - output: Symfony OutputInterface. (Fallback for handling logs - in absence of 'log')
     * @param string $topic
     * @return \Psr\Log\LoggerInterface|\Civi\Cv\Log\InternalLogger
     */
    public static function resolve(array $options, string $topic)
    {
        if (!empty($options['log'])) {
            return $options['log'];
        } elseif (!empty($options['output'])) {
            return new \Civi\Cv\Log\SymfonyConsoleLogger($topic, $options['output']);
        } else {
            return new \Civi\Cv\Log\StderrLogger($topic);
        }
    }
}
<?php

namespace Civi\Cv\Log;

/**
 * Send anomolous logs (errors, warnings, etc) to STDERR.
 *
 * Informational logs will be discarded (unless you enable the $verbose flag).
 */
class StderrLogger extends \Civi\Cv\Log\InternalLogger
{
    protected $verbose;
    public function __construct(string $topic, bool $verbose = \FALSE)
    {
        parent::__construct($topic);
        $this->verbose = $verbose;
    }
    public function log($level, $message, array $context = [])
    {
        if ($this->isAnomolous($level) || $this->verbose) {
            $template = "[%s:%s] %s\n";
            \fprintf(\STDERR, $template, $this->topic, $level, $this->interpolate($message, $context));
        }
    }
}
<?php

namespace Civi\Cv\Util;

/**
 * A few selected excerpts from "symfony/filesystem".
 *
 * @see \Symfony\Component\Filesystem\Filesystem
 * @author Fabien Potencier <fabien@symfony.com>
 * @license MIT
 */
trait FilesystemTrait
{
    /**
     * @var string|null
     */
    private static $lastError;
    /**
     * Returns whether the file path is an absolute path.
     *
     * @param string $file A file path
     * @return bool
     */
    public function isAbsolutePath($file)
    {
        return '' !== (string) $file && (\strspn($file, '/\\', 0, 1) || \strlen($file) > 3 && \ctype_alpha($file[0]) && ':' === $file[1] && \strspn($file, '/\\', 2, 1) || NULL !== \parse_url($file, \PHP_URL_SCHEME));
    }
    /**
     * Removes files or directories.
     *
     * @param string|iterable $files A filename, an array of files, or a \Traversable instance to remove
     *
     * @throws \RuntimeException When removal fails
     */
    public function remove($files)
    {
        if ($files instanceof \Traversable) {
            $files = \iterator_to_array($files, \FALSE);
        } elseif (!\is_array($files)) {
            $files = [$files];
        }
        $files = \array_reverse($files);
        foreach ($files as $file) {
            if (\is_link($file)) {
                // See https://bugs.php.net/52176
                if (!(self::box('unlink', $file) || '\\' !== \DIRECTORY_SEPARATOR || self::box('rmdir', $file)) && \file_exists($file)) {
                    throw new \RuntimeException(\sprintf('Failed to remove symlink "%s": ', $file) . self::$lastError);
                }
            } elseif (\is_dir($file)) {
                $this->remove(new \FilesystemIterator($file, \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS));
                if (!self::box('rmdir', $file) && \file_exists($file)) {
                    throw new \RuntimeException(\sprintf('Failed to remove directory "%s": ', $file) . self::$lastError);
                }
            } elseif (!self::box('unlink', $file) && (\str_contains(self::$lastError, 'Permission denied') || \file_exists($file))) {
                throw new \RuntimeException(\sprintf('Failed to remove file "%s": ', $file) . self::$lastError);
            }
        }
    }
    /**
     * @param callable $func
     *   File I/O function from PHP stdlib
     * @param mixed ...$args
     * @return mixed
     */
    private static function box(callable $func, ...$args)
    {
        self::$lastError = NULL;
        \set_error_handler(__CLASS__ . '::handleError');
        try {
            $result = $func(...$args);
            \restore_error_handler();
            return $result;
        } catch (\Throwable $e) {
        }
        \restore_error_handler();
        throw $e;
    }
    /**
     * @internal
     */
    public static function handleError(int $type, string $msg)
    {
        self::$lastError = $msg;
    }
}
<?php

namespace Civi\Cv\Util;

use Civi\Cv\ErrorHandler;
use Civi\Cv\Log\InternalLogger;
use Civi\Cv\Log\SymfonyConsoleLogger;
use Civi\Cv\PharOut\PharOut;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
/**
 * This trait can be mixed into a Symfony `Command` to provide Civi/CMS-bootstrap options.
 *
 * It first boots Civi and then boots the CMS.
 */
trait BootTrait
{
    public function configureBootOptions($defaultLevel = 'full|cms-full')
    {
        $this->addOption('level', NULL, InputOption::VALUE_REQUIRED, 'Bootstrap level (none,classloader,settings,full,cms-only,cms-full)', $defaultLevel);
        $this->addOption('hostname', NULL, InputOption::VALUE_REQUIRED, 'Hostname (for a multisite system)');
        $this->addOption('test', 't', InputOption::VALUE_NONE, 'Bootstrap the test database (CIVICRM_UF=UnitTests)');
        $this->addOption('user', 'U', InputOption::VALUE_REQUIRED, 'CMS user');
    }
    public function boot(InputInterface $input, OutputInterface $output)
    {
        $logger = $this->bootLogger($output);
        $logger->debug('Start');
        $this->setupErrorHandling($output);
        if ($input->hasOption('test') && $input->getOption('test')) {
            $logger->debug('Use test mode');
            \putenv('CIVICRM_UF=UnitTests');
            $_ENV['CIVICRM_UF'] = 'UnitTests';
        }
        if ($input->getOption('level') === 'full|cms-full') {
            if (\getenv('CIVICRM_UF') === 'UnitTests') {
                $input->setOption('level', 'full');
            } elseif (\getenv('CIVICRM_BOOT')) {
                $input->setOption('level', 'cms-full');
            } elseif (\getenv('CIVICRM_SETTINGS')) {
                $input->setOption('level', 'full');
            } else {
                $input->setOption('level', 'full');
                // TODO (when tests pass, for v0.4): $input->setOption('level', 'cms-full');
            }
        }
        if (\getenv('CIVICRM_UF') === 'UnitTests' && \preg_match('/^cms-/', $input->getOption('level'))) {
            throw new \Exception("UnitTest bootstrapping is not compatible with CMS bootstrapping");
        }
        $func = '_boot_' . \strtr($input->getOption('level'), '-', '_');
        if (\is_callable([$this, $func])) {
            \call_user_func([$this, $func], $input, $output);
        } else {
            throw new \Exception("Unrecognized bootstrap level");
        }
        // CMS may have installed wonky error-handling. Add our own.
        ErrorHandler::pushHandler();
        $logger->debug('Finished');
    }
    /**
     * Do not do anything for bootstrap. Just use the given environment.
     *
     * @param \Symfony\Component\Console\Input\InputInterface $input
     * @param \Symfony\Component\Console\Output\OutputInterface $output
     */
    public function _boot_none(InputInterface $input, OutputInterface $output)
    {
        $this->bootLogger($output)->debug('Skip');
    }
    /**
     * Setup the CiviCRM classloader.
     *
     * @param \Symfony\Component\Console\Input\InputInterface $input
     * @param \Symfony\Component\Console\Output\OutputInterface $output
     */
    public function _boot_classloader(InputInterface $input, OutputInterface $output)
    {
        $this->bootLogger($output)->debug('Call basic cv bootstrap (' . $input->getOption('level') . ')');
        \Civi\Cv\Bootstrap::singleton()->boot($this->createBootParams($input, $output) + array('prefetch' => \FALSE));
    }
    /**
     * Get the CiviCRM classloader and settings file.
     *
     * @param \Symfony\Component\Console\Input\InputInterface $input
     * @param \Symfony\Component\Console\Output\OutputInterface $output
     */
    public function _boot_settings(InputInterface $input, OutputInterface $output)
    {
        $this->bootLogger($output)->debug('Call basic cv bootstrap (' . $input->getOption('level') . ')');
        \Civi\Cv\Bootstrap::singleton()->boot($this->createBootParams($input, $output) + array('prefetch' => \FALSE));
    }
    /**
     * Boot CiviCRM, then boot the corresponding CMS.
     *
     * @param \Symfony\Component\Console\Input\InputInterface $input
     * @param \Symfony\Component\Console\Output\OutputInterface $output
     * @throws \Exception
     */
    public function _boot_full(InputInterface $input, OutputInterface $output)
    {
        PharOut::prepare();
        $logger = $this->bootLogger($output);
        $logger->debug('Call standard cv bootstrap');
        \Civi\Cv\Bootstrap::singleton()->boot($this->createBootParams($input, $output));
        $logger->debug('Call core bootstrap');
        \CRM_Core_Config::singleton();
        $logger->debug('Call CMS bootstrap');
        \CRM_Utils_System::loadBootStrap(array(), \FALSE);
        if ($input->getOption('user')) {
            $logger->debug('Set system user');
            if (\is_callable(array(\CRM_Core_Config::singleton()->userSystem, 'loadUser'))) {
                if (!\CRM_Core_Config::singleton()->userSystem->loadUser($input->getOption('user')) || !$this->ensureUserContact($output)) {
                    throw new \Exception("Failed to determine contactID for user=" . $input->getOption('user'));
                }
            } else {
                $output->getErrorOutput()->writeln("<error>Failed to set user. Feature not supported by UF (" . CIVICRM_UF . ")</error>");
            }
        }
        if (\is_callable([\CRM_Core_Config::singleton()->userSystem, 'setMySQLTimeZone'])) {
            $logger->debug('Set active MySQL timezone');
            \CRM_Core_Config::singleton()->userSystem->setMySQLTimeZone();
        }
        if (CIVICRM_UF === 'Joomla') {
            PharOut::reset();
        }
    }
    /**
     * Boot only the CMS.
     *
     * @param \Symfony\Component\Console\Input\InputInterface $input
     * @param \Symfony\Component\Console\Output\OutputInterface $output
     * @return \Civi\Cv\CmsBootstrap
     */
    public function _boot_cms_only(InputInterface $input, OutputInterface $output)
    {
        $bootstrap = $this->createCmsBootstrap($input, $output);
        $this->bootLogger($output)->debug('Call CMS bootstrap');
        $bootstrap->bootCms();
        return $bootstrap;
    }
    /**
     * Boot the CMS, then boot CiviCRM.
     *
     * @param \Symfony\Component\Console\Input\InputInterface $input
     * @param \Symfony\Component\Console\Output\OutputInterface $output
     * @return \Civi\Cv\CmsBootstrap
     */
    public function _boot_cms_full(InputInterface $input, OutputInterface $output)
    {
        $bootstrap = $this->_boot_cms_only($input, $output);
        $this->bootLogger($output)->debug('Call Civi bootstrap');
        $bootstrap->bootCivi();
        return $bootstrap;
    }
    /**
     * @param \Symfony\Component\Console\Input\InputInterface $input
     * @param \Symfony\Component\Console\Output\OutputInterface $output
     * @return \Civi\Cv\CmsBootstrap
     */
    protected function createCmsBootstrap(InputInterface $input, OutputInterface $output)
    {
        if ($output->isDebug()) {
            // add the output object to allow the bootstrapper to output debug messages
            // and track verboisty
            $boot_params = array('output' => $output);
        } else {
            $boot_params = array();
        }
        if ($input->getOption('user')) {
            $boot_params['user'] = $input->getOption('user');
        }
        if ($input->getOption('hostname')) {
            $boot_params['httpHost'] = $input->getOption('hostname');
        }
        return \Civi\Cv\CmsBootstrap::singleton()->addOptions($boot_params);
    }
    /**
     * Ensure that the current user has a contact record.
     *
     * @param \Symfony\Component\Console\Output\OutputInterface $output
     * @return int|NULL
     *   The user's contact ID, or NULL
     */
    public function ensureUserContact(OutputInterface $output)
    {
        if ($cid = \CRM_Core_Session::getLoggedInContactID()) {
            return $cid;
        }
        // Ugh, this codepath is ridiculous.
        switch (CIVICRM_UF) {
            case 'Drupal':
            case 'Drupal6':
            case 'Backdrop':
                \CRM_Core_BAO_UFMatch::synchronize($GLOBALS['user'], \TRUE, CIVICRM_UF, 'Individual');
                break;
            case 'Drupal8':
                $user = \Drupal\user\Entity\User::load(\Drupal::currentUser()->id());
                \CRM_Core_BAO_UFMatch::synchronize($user, \TRUE, CIVICRM_UF, 'Individual');
                break;
            case 'Joomla':
                \CRM_Core_BAO_UFMatch::synchronize(\JFactory::getUser(), \TRUE, CIVICRM_UF, 'Individual');
                break;
            case 'Standalone':
                // At time of writing, support for 'loggedInUser' is in a PR. Once the functionality is merged, we can update/simplify this.
                if (empty($GLOBALS['loggedInUser'])) {
                    $this->bootLogger($output)->error('Failed to sync user/contact. You may be running a pre-release of civicrm-standalone.');
                } else {
                    \CRM_Core_BAO_UFMatch::synchronize($GLOBALS['loggedInUser'], \TRUE, CIVICRM_UF, 'Individual');
                }
                break;
            case 'WordPress':
                \CRM_Core_BAO_UFMatch::synchronize($GLOBALS['current_user'], \TRUE, CIVICRM_UF, 'Individual');
                break;
            default:
                $this->bootLogger($output)->error("Unrecognized UF: " . CIVICRM_UF);
        }
        return \CRM_Core_Session::getLoggedInContactID();
    }
    protected function setupErrorHandling(OutputInterface $output)
    {
        $this->bootLogger($output)->debug('Attempting to set verbose error reporting');
        // standard php debug chat settings
        \error_reporting(\E_ALL | \E_STRICT);
        \ini_set('display_errors', 'stderr');
        \ini_set('display_startup_errors', \TRUE);
    }
    /**
     * @param \Symfony\Component\Console\Input\InputInterface $input
     * @param \Symfony\Component\Console\Output\OutputInterface $output
     * @return array
     */
    protected function createBootParams(InputInterface $input, OutputInterface $output)
    {
        $boot_params = [];
        if ($output->isDebug()) {
            $boot_params['output'] = $output;
        }
        if ($input->getOption('hostname')) {
            $boot_params['httpHost'] = $input->getOption('hostname');
        }
        return $boot_params;
    }
    private function bootLogger(OutputInterface $output) : InternalLogger
    {
        return new SymfonyConsoleLogger('BootTrait', $output);
    }
}
<?php

namespace Civi\Cv\Util;

class Filesystem
{
    use \Civi\Cv\Util\FilesystemTrait;
    public static function exists(?string $path) : bool
    {
        return $path !== NULL && \file_exists($path);
    }
    /**
     * @return false|string
     */
    public function pwd()
    {
        // exec(pwd) works better with symlinked source trees, but it's
        // probably not portable to Windows.
        if (\strtoupper(\substr(\PHP_OS, 0, 3)) === 'WIN') {
            return \getcwd();
        } else {
            \exec('pwd', $output);
            return \trim(\implode("\n", $output));
        }
    }
    /**
     * @param string $path
     * @return string updated $path
     */
    public function toAbsolutePath($path)
    {
        if (empty($path)) {
            $res = $this->pwd();
        } elseif ($this->isAbsolutePath($path)) {
            $res = $path;
        } else {
            $res = $this->pwd() . \DIRECTORY_SEPARATOR . $path;
        }
        if (\is_dir($res)) {
            return \realpath($res);
        } else {
            return $res;
        }
    }
    /**
     * @param array $paths of string
     * @return array updated paths
     */
    public function toAbsolutePaths($paths)
    {
        $result = array();
        foreach ($paths as $path) {
            $result[] = $this->toAbsolutePath($path);
        }
        return $result;
    }
    public function isDescendent($child, $parent)
    {
        $parent = \rtrim($parent, \DIRECTORY_SEPARATOR) . \DIRECTORY_SEPARATOR;
        $child = \rtrim($child, \DIRECTORY_SEPARATOR) . \DIRECTORY_SEPARATOR;
        if (\strlen($parent) >= \strlen($child)) {
            return \FALSE;
        }
        return $parent == \substr($child, 0, \strlen($parent));
    }
    /**
     * Atomically read, filter, and write a file.
     *
     * @param string $file
     * @param callable $filter
     *   A function which accepts full file content as input,
     *   and returns new content as output.
     * @param int|float $maxWait
     * @return bool
     * @throws \RuntimeException
     */
    public function update($file, $filter, $maxWait = 5.0)
    {
        $mode = \file_exists($file) ? 'r+' : 'w+';
        if (!($fh = \fopen($file, $mode))) {
            throw new \RuntimeException("Failed to open");
        }
        $start = \microtime(\TRUE);
        do {
            $locked = \flock($fh, \LOCK_EX | \LOCK_NB);
            if (!$locked && \microtime(\TRUE) - $start > $maxWait) {
                throw new \RuntimeException("Failed to lock");
            }
            if (!$locked) {
                \usleep(\rand(20, 100) * 1000);
            }
        } while (!$locked);
        // TODO throw an error $maxSize exceeded.
        $buf = '';
        while (!\feof($fh)) {
            $buf .= \fread($fh, 1024 * 1024);
        }
        $rawOut = \call_user_func($filter, $buf);
        if (!\rewind($fh)) {
            throw new \RuntimeException('Bad rewind');
        }
        if (!\ftruncate($fh, 0)) {
            throw new \RuntimeException('Bad truncate');
        }
        if (!\fwrite($fh, $rawOut)) {
            throw new \RuntimeException('Bad write');
        }
        \flock($fh, \LOCK_UN);
        return \fclose($fh);
    }
}
<?php

namespace Civi\Cv\PharOut;

use TYPO3\PharStreamWrapper\Helper;
use TYPO3\PharStreamWrapper\Exception;
/**
 * Accept PHP from PHAR files if either (a) they have the '.phar' extension or
 * (b) it is the top-level/main file.
 *
 * @see \TYPO3\PharStreamWrapper\Interceptor\PharExtensionInterceptor
 */
trait PharPolicyTrait
{
    /**
     * The initial/top-level/main script.
     *
     * @var string|null
     */
    private $mainFile;
    /**
     * Determines whether the base file name has a ".phar" suffix.
     *
     * @param string $path
     * @param string $command
     * @return bool
     * @throws Exception
     */
    public function assert($path, $command) : bool
    {
        if ($this->mainFile === NULL) {
            $this->mainFile = $this->findMainFile();
        }
        $baseFile = Helper::determineBaseFile($path);
        if ($baseFile === NULL) {
            throw new Exception(\sprintf('Failed to identify origin of "%s"', $path), 1535198703);
        }
        if ($baseFile === $this->mainFile || \strtolower(\pathinfo($baseFile, \PATHINFO_EXTENSION)) === 'phar') {
            return \TRUE;
        }
        throw new Exception(\sprintf('File "%s" does not resolve to approved PHAR location.', $path), 1535198703);
    }
    /**
     * Determine the 'main' script that started this process.
     *
     * @return string|null
     */
    private function findMainFile()
    {
        if (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'])) {
            return NULL;
        }
        $backtrace = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS);
        do {
            $caller = \array_pop($backtrace);
        } while (empty($caller['file']) && !empty($backtrace));
        return isset($caller['file']) ? Helper::determineBaseFile($caller['file']) : NULL;
    }
}
<?php

namespace Civi\Cv\PharOut;

/**
 * This is a work-around for a little piece of hell that is known only to Joomla-related console apps.
 *
 * The problem:
 *
 * - PHARs are archive-files. The usually include PHP code.
 * - There exists a general class of code-execution vulnerabilities involving PHARs
 *   (eg when you have an innocent-looking statement like `file_exists($userString)` and when
 *   you receive a specially-crafted upload, eg JPG with embedded PHAR - you might be
 *   tricked into executing arbitrary code).
 * - A general mitigation is to limit which PHARs you load.
 * - The library `TYPO3\PharStreamWrapper` defines a framework for limiting which PHARs you load.
 * - The library has gone through a few revisions which include BC breaks (v1, v2, v3).
 * - The library is widely used by different projects (Drupal, Joomla, etc).
 * - The library includes a basic/example policy ("only load files with .phar extension").
 * - The basic/example policy sucks for CLI tools. It's much more convenient to name CLI commands
 *   like `bin/phpunit`, `bin/composer`, `bin/cv`, rather than `bin/phpunit.phar`, `bin/composer.phar`, `bin/cv.phar`.
 * - Drupal implements a fairly sensible policy ("allow PHAR data from the main/entry-file or from *.phar files").
 *   This works well for `bin/drush`, `bin/phpunit`, `bin/cv`, etc.
 * - Joomla uses the basic/example policy.
 * - If you launch a CLI-PHAR command (eg `cv`) and then boot Joomla, it shoots your foot and breaks class-loading.
 * - When `cv` starts, we don't yet know which CMS will load -- or which (if any) version
 *   of `TYPO3\PharStreamWrapper` will be required by it. We won't know much until after they setup
 *   a policy (at which point, we may not be able to load additional resources to tune that policy).
 *
 * The "Pharout" class is work-around to fix Joomla's PHAR loading policy from outside.
 */
class PharOut
{
    /**
     * Load any resources from selfsame PHAR that may be needed for PharStreamWrapper.
     * But do not actually do anything with PharStreamWrapper yet (because it's not available yet).
     */
    public static function prepare()
    {
        require_once __DIR__ . '/PharPolicyTrait.php';
    }
    /**
     * Remove and re-initialize the PharStreamWrapper policy.
     */
    public static function reset()
    {
        if (!\class_exists('\\TYPO3\\PharStreamWrapper\\Manager')) {
            // It wasn't setup, so we don't need to reset it.
            return;
        }
        \TYPO3\PharStreamWrapper\Manager::destroy();
        \TYPO3\PharStreamWrapper\Manager::initialize((new \TYPO3\PharStreamWrapper\Behavior())->withAssertion(new class implements \TYPO3\PharStreamWrapper\Assertable
        {
            use \Civi\Cv\PharOut\PharPolicyTrait;
        }));
        if (\in_array('phar', \stream_get_wrappers())) {
            \stream_wrapper_unregister('phar');
            \stream_wrapper_register('phar', \TYPO3\PharStreamWrapper\PharStreamWrapper::class);
        }
    }
}
<?php

namespace Civi\Cv;

/**
 * Bootstrap the CiviCRM runtime.
 *
 * @code
 * // Use default bootstrap
 * require_once '/path/to/Civi/Bootstrap.php';
 * Civi\Bootstrap::singleton()->boot();
 *
 * // Use custom bootstrap
 * require_once '/path/to/Civi/Bootstrap.php';
 * Civi\Bootstrap::singleton()->boot(array(
 *   'settingsFile' => '/path/to/civicrm.settings.php',
 * ));
 * @endcode
 *
 * This class is intended to be run *before* the classloader is available. Therefore, it
 * must be self-sufficient - do not rely on other classes, even in the same package.
 *
 * A key issue is locating the civicrm.settings.php file -- this is complicated because
 * each CMS has a different structure, because some CMS's have multisite features, and
 * because we don't know who's calling us.
 *
 * By default, bootstrap will search as follows:
 *   - Check ../settings_location.php for define(CIVICRM_CONFDIR)
 *   - Check ENV['CIVICRM_SETTINGS']
 *   - Check $options['settingsFile']
 *   - Scan PWD and every ancestor directory to see if it
 *     contains civicrm.settings.php in one of the
 *     standard subdirectories.
 *
 * Recommendations:
 *   - Administrators with an unusual directory structure should either:
 *     - Set env var CIVICRM_SETTINGS in their httpd vhost and bashrc, or
 *     - Create settings_location.php
 *   - Primary CMS-integration modules should preemptively configure the
 *     defaults so that other code may bootstrap without specifying options.
 *       require_once $cividir/Civi/Bootstrap.php
 *       Civi\Bootstrap::singleton()->setOptions(
 *         'settingsFile' => ...,
 *         'search' => FALSE,
 *       ));
 *   - External scripts should call:
 *       require_once $cividir/Civi/Bootstrap.php;
 *       Civi\Bootstrap::singleton()->boot();
 *   - Administrators who are concerned about bootstrap time for external
 *     scripts should use CIVICRM_SETTINGS or settings_location.php.
 *   - Pre-installation programs (code-generators, installers, etc) should not
 *     use Civi\Bootstrap. Instead, they should use CRM_Core_ClassLoader.
 *
 * The bootstrapper accepts a few options (either via setOptions() or boot()). They are:
 *   - dynamicSettingsFile: string|NULL. The location of a PHP file which dynamically
 *     determines the location of civicrm.settings.php. This is provided for backward
 *     compatibility.
 *     (Default: $civiRoot/settings_location.php)
 *   - cmsType: string|NULL. Give a hint to the search algorithm about which
 *     type of CMS is being used.
 *     (Default: NULL)
 *   - env: string|NULL. The environment variable which may contain the path to
 *     civicrm.settings.php (or the token "Auto"). Set NULL to disable environment-checking.
 *     (Default: CIVICRM_SETTINGS)
 *   - httpHost: string|NULL. For multisite, the HTTP hostname.
 *   - log: \Psr\Log\LoggerInterface|\Civi\Cv\Log\InternalLogger (If given, send log messages here)
 *   - output: Symfony OutputInterface. (Fallback for handling logs - in absence of 'log')
 *   - prefetch: bool. Whether to load various caches.
 *     (Default: TRUE)
 *   - settingsFile: string|NULL. The full path to the civicrm.settings.php
 *     (Default: NULL)
 *   - search: bool|string. Attempt to determine root+settings by searching
 *     the file system and checking against common Civi directory structures.
 *     Boolean TRUE means it should use a default (PWD).
 *     (Default: TRUE aka PWD)
 *
 * TODO: Consider adding flags for CMS bootstrap.
 *
 * @package Civi
 */
class Bootstrap
{
    const PHP_RECOMMENDED_MIN = '7.0.0';
    protected static $singleton = NULL;
    protected $options = array();
    /**
     * @var \Psr\Log\LoggerInterface|\Civi\Cv\Log\InternalLogger
     */
    protected $log = NULL;
    /**
     * @param string $text
     * @param int $level
     * @deprecated
     */
    public function writeln($text, $level = 32)
    {
        $this->log->info($text);
    }
    /**
     * @return Bootstrap
     */
    public static function singleton()
    {
        if (self::$singleton === NULL) {
            self::$singleton = new \Civi\Cv\Bootstrap(array('dynamicSettingsFile' => \dirname(__DIR__) . '/settings_location.php', 'env' => 'CIVICRM_SETTINGS', 'prefetch' => \TRUE, 'settingsFile' => NULL, 'search' => \TRUE, 'cmsType' => NULL, 'httpHost' => \array_key_exists('HTTP_HOST', $_SERVER) ? $_SERVER['HTTP_HOST'] : ''));
        }
        return self::$singleton;
    }
    /**
     * @param array $options
     *   See options in class doc.
     */
    public function __construct($options = array())
    {
        $this->options = $options;
    }
    /**
     * Bootstrap the CiviCRM runtime.
     *
     * @param array $options
     *   See options in class doc.
     * @throws \Exception
     */
    public function boot($options = array())
    {
        $this->log = \Civi\Cv\Log\Logger::resolve($options, 'Bootstrap');
        $isBooting = \TRUE;
        \register_shutdown_function(function () use(&$isBooting) {
            if (!$isBooting) {
                // Someone will probably handle it
                return;
            }
            $last_error = \error_get_last();
            switch ($last_error['type'] ?? NULL) {
                case \E_ERROR:
                case \E_PARSE:
                case \E_COMPILE_ERROR:
                    $errMsg = \sprintf("PHP Error: %s\nat line %s in %s", $last_error['message'], $last_error['line'], $last_error['file']);
                    // We only warn about PHP version if there's actually a fatal; for older versions of civicrm-core, it would be incorrect for
                    // cv to start outputting PHP version errors.
                    if (!\version_compare(\PHP_VERSION, self::PHP_RECOMMENDED_MIN, '>=')) {
                        $errMsg .= \sprintf("\n\nWARNING: cv recommends PHP %s+ for use with current CiviCRM versions. This command is running PHP %s.", self::PHP_RECOMMENDED_MIN, \PHP_VERSION);
                    }
                    if ($this->log) {
                        $this->log->error($errMsg);
                    } else {
                        \fwrite(\STDERR, "{$errMsg}\n");
                    }
                    break;
            }
        });
        if (!\defined('CIVICRM_SETTINGS_PATH')) {
            $this->options = $options = \array_merge($this->options, $options);
            $this->log->debug("Options: " . \json_encode($options, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES));
            $this->log->debug("Find settings file");
            $settings = $this->getCivicrmSettingsPhp($options);
            if (empty($settings) || !\file_exists($settings)) {
                throw new \Exception("Failed to locate civicrm.settings.php." . " By default, this tool searches the parent directories for a standard CMS (Drupal, WordPress, etal) and standard civicrm.settings.php." . " Symlinks and multisite configurations may interfere." . " To customize, set variable CIVICRM_SETTINGS to point to the preferred civicrm.settings.php.");
            }
            if (\class_exists('Civi\\Cv\\SiteConfigReader')) {
                $this->log->debug("Load supplemental configuration for \"{$settings}\"");
                $reader = new \Civi\Cv\SiteConfigReader($settings);
                $GLOBALS['_CV'] = $reader->compile(array('buildkit', 'home'));
            } else {
                $this->log->debug("Warning: Not loading supplemental configuration for \"{$settings}\". SiteConfigReader is missing.");
                $GLOBALS['_CV'] = [];
            }
            $this->log->notice("Find CMS root for \"" . $this->getSearchDir() . "\"");
            list($cmsType, $cmsBasePath) = $this->findCmsRoot($this->getSearchDir());
            $this->log->notice("Found \"{$cmsType}\" in \"{$cmsBasePath}\"");
            if (\PHP_SAPI === "cli") {
                $this->log->notice("Simulate web environment in CLI");
                $_SERVER['SCRIPT_FILENAME'] = $cmsBasePath . '/index.php';
                $_SERVER['REMOTE_ADDR'] = "127.0.0.1";
                $_SERVER['SERVER_SOFTWARE'] = NULL;
                $_SERVER['REQUEST_METHOD'] = 'GET';
                if (!empty($options['httpHost'])) {
                    // Hint for D7 multisite
                    $_SERVER['HTTP_HOST'] = $options['httpHost'];
                }
                if (\ord($_SERVER['SCRIPT_NAME']) != 47) {
                    $_SERVER['SCRIPT_NAME'] = '/' . $_SERVER['SCRIPT_NAME'];
                }
            }
            $this->log->debug("Load settings file \"" . $settings . "\"");
            \define('CIVICRM_SETTINGS_PATH', $settings);
            $error = @(include_once $settings);
            if ($error == \FALSE) {
                $this->log->notice("Failed to load settings file");
                throw new \Exception("Could not load the CiviCRM settings file: {$settings}");
            }
        }
        // Backward compatibility - New civicrm.settings.php files include
        // the classloader, but old ones don't.
        $this->log->notice("Initialize class loader");
        global $civicrm_root;
        require_once $civicrm_root . '/CRM/Core/ClassLoader.php';
        \CRM_Core_ClassLoader::singleton()->register();
        if (!empty($options['prefetch'])) {
            $this->log->notice("Call core bootstrap");
            // I'm not sure why this is called explicitly during bootstrap
            // rather than lazily. However, it seems to be done by all
            // the existing bootstrap code. Perhaps initializing Config
            // has a side-effect of initializing other things?
            \CRM_Core_Config::singleton();
        }
        $this->log->debug("Finished");
        $isBooting = \FALSE;
    }
    /**
     * Generate bootstrap logic.
     *
     * NOTE: Assumes boot() has already run.
     *
     * @return string
     *   PHP code.
     */
    public function generate()
    {
        $code = array();
        $code[] = 'if (PHP_SAPI === "cli") {';
        $srvVars = array('SCRIPT_FILENAME', 'REMOTE_ADDR', 'SERVER_SOFTWARE', 'REQUEST_METHOD', 'SCRIPT_NAME');
        foreach ($srvVars as $srvVar) {
            $code[] = \sprintf('$_SERVER["%s"] = %s;', $srvVar, \var_export($_SERVER[$srvVar], 1));
        }
        foreach (array('CIVICRM_UF') as $envVar) {
            if (\getenv($envVar)) {
                $code[] = \sprintf('putenv("%s=" . %s);', $envVar, \var_export(\getenv($envVar), 1));
                $code[] = \sprintf('$_ENV["%s"] = %s;', $envVar, \var_export(\getenv($envVar), 1));
            }
        }
        $code[] = '}';
        $code[] = \sprintf('$GLOBALS[\'_CV\'] = %s;', \var_export($GLOBALS['_CV'], 1));
        $code[] = \sprintf('define("CIVICRM_SETTINGS_PATH", %s);', \var_export(CIVICRM_SETTINGS_PATH, 1));
        $code[] = '$error = @include_once CIVICRM_SETTINGS_PATH;';
        $code[] = 'if ($error == FALSE) {';
        $code[] = '  throw new \\Exception("Could not load the CiviCRM settings file: {$settings}");';
        $code[] = '}';
        $code[] = 'require_once $GLOBALS["civicrm_root"] . "/CRM/Core/ClassLoader.php";';
        $code[] = '\\CRM_Core_ClassLoader::singleton()->register();';
        return \implode("\n", $code);
    }
    /**
     * @return array
     *   See options in class doc.
     */
    public function getOptions()
    {
        return $this->options;
    }
    /**
     * @param array $options
     *   See options in class doc.
     */
    public function setOptions($options)
    {
        $this->options = $options;
    }
    /**
     * @param array $options
     * @return string
     * @throws \Exception
     */
    public function getCivicrmSettingsPhp($options)
    {
        if (!empty($options['dynamicSettingsFile']) && \file_exists($options['dynamicSettingsFile'])) {
            include $options['dynamicSettingsFile'];
        }
        /**
         * @var string
         *   Path to the settings file.
         */
        $settings = NULL;
        if (\defined('CIVICRM_CONFDIR') && \file_exists(CIVICRM_CONFDIR . '/civicrm.settings.php')) {
            $settings = CIVICRM_CONFDIR . '/civicrm.settings.php';
        } elseif (!empty($options['env']) && \getenv($options['env']) && \getenv($options['env']) !== 'Auto' && \file_exists(\getenv($options['env']))) {
            $settings = \getenv($options['env']);
        } elseif (!empty($options['settingsFile']) && \file_exists($options['settingsFile'])) {
            $settings = $options['settingsFile'];
        } elseif (!empty($options['search'])) {
            list(, , $settings) = $this->findCivicrmSettingsPhp($this->getSearchDir());
        }
        return $settings;
    }
    /**
     * Locate a civicrm.settings.php using normal directory structures.
     *
     * @param string $searchDir
     *   The directory from which to begin the upward search.
     * @return array
     *   Array(string $cmsType, string $cmsRoot, string $settingsFile).
     */
    protected function findCivicrmSettingsPhp($searchDir)
    {
        list($cmsType, $cmsRoot) = $this->findCmsRoot($searchDir);
        $settings = NULL;
        switch ($cmsType) {
            case 'backdrop':
                $settings = $this->findFirstFile(\array_merge($this->findDrupalDirs($cmsRoot, $searchDir), array($cmsRoot)), 'civicrm.settings.php');
                break;
            case 'drupal':
                $settings = $this->findFirstFile($this->findDrupalDirs($cmsRoot, $searchDir), 'civicrm.settings.php');
                break;
            case 'joomla':
                // Note: Joomla technically has two copies of civicrm.settings.php with
                // slightly different values of CIVICRM_UF_BASEURL. It appears that Joomla
                // always used the admin copy for CLI/bin/extern scripts, so we do the
                // same. However, the arrangement seems gratuitous considering that WP
                // has the same frontend/backend split and does not need two copies of
                // civicrm.settings.php.
                $settings = $cmsRoot . '/administrator/components/com_civicrm/civicrm.settings.php';
                // $result =  $cmsRoot . 'components/com_civicrm/civicrm.settings.php';
                break;
            case 'wp':
                $wpDirs = array($cmsRoot . '/*/uploads/civicrm', $cmsRoot . '/*/plugins/civicrm', $cmsRoot . '/*/uploads/sites/*/civicrm', $cmsRoot . '/*/blogs.dir/*/files/civicrm');
                $settings = $this->findFirstFile($wpDirs, 'civicrm.settings.php');
                break;
            case 'standalone':
                $settings = $cmsRoot . '/data/civicrm.settings.php';
                // $result =  $cmsRoot . 'components/com_civicrm/civicrm.settings.php';
                break;
        }
        return array($cmsType, $cmsRoot, $settings);
    }
    /**
     * Get an ordered list of multisite dirs that might apply to this request.
     *
     * @param string $cmsRoot
     *   The root of the Drupal installation.
     * @param string $searchDir
     *   The location from which we're searching. Usually PWD.
     * @return array
     */
    protected function findDrupalDirs($cmsRoot, $searchDir)
    {
        // If there's no explicit host and we start the search from "web/sites/FOO/...", then infer subsite path.
        $sitesRoot = "{$cmsRoot}/sites";
        $sitesRootQt = \preg_quote($sitesRoot, ';');
        if (empty($this->options['httpHost']) && \preg_match(";^({$sitesRootQt}/[^/]+);", $searchDir, $m)) {
            if (\basename($m[1]) !== 'all') {
                return [$m[1]];
            }
        }
        $sites = array();
        if (\file_exists("{$cmsRoot}/sites/sites.php")) {
            include "{$cmsRoot}/sites/sites.php";
        }
        $dirs = array();
        $server = \explode('.', \implode('.', \array_reverse(\explode(':', \rtrim($this->options['httpHost'], '.')))));
        for ($j = \count($server); $j > 0; $j--) {
            $s = \implode('.', \array_slice($server, -$j));
            if (isset($sites[$s]) && \file_exists("{$cmsRoot}/sites/" . $sites[$s])) {
                $s = $sites[$s];
            }
            $dirs[] = "{$cmsRoot}/sites/{$s}";
        }
        $dirs[] = "{$cmsRoot}/sites/default";
        return $dirs;
    }
    /**
     * @param string $searchDir
     *   The directory from which to begin the upward search.
     * @return array
     *   Array(string $cmsType, string $cmsRoot, string $civiRoot)
     */
    protected function findCmsRoot($searchDir)
    {
        // A list of file patterns; if one of the patterns matches a give
        // directory, then we can assume that this directory is the
        // CMS root.
        $cmsPatterns = array('wp' => array('wp-includes/version.php'), 'joomla' => array('administrator/components/com_civicrm/civicrm/civicrm-version.php', 'administrator/components/com_users/users.php'), 'drupal' => array(
            // D7
            'modules/system/system.module',
            // D8
            'core/core.services.yml',
        ), 'backdrop' => array('core/modules/layout/layout.module'), 'standalone' => array('civicrm.config.php.standalone'));
        $parts = \explode('/', \str_replace('\\', '/', $searchDir));
        while (!empty($parts)) {
            $basePath = \implode('/', $parts);
            foreach ($cmsPatterns as $cmsType => $relPaths) {
                if (!empty($this->options['cmsType']) && $this->options['cmsType'] != $cmsType) {
                    continue;
                }
                foreach ($relPaths as $relPath) {
                    $matches = \glob("{$basePath}/{$relPath}");
                    if (!empty($matches)) {
                        return array($cmsType, $basePath);
                    }
                    $matches = \glob("{$basePath}/web/{$relPath}");
                    if (!empty($matches)) {
                        return array($cmsType, "{$basePath}/web");
                    }
                    if ($cmsType === 'standalone') {
                        $matches = \glob("{$basePath}/srv/{$relPath}");
                        if (!empty($matches)) {
                            return array($cmsType, "{$basePath}/srv");
                        }
                    }
                }
            }
            \array_pop($parts);
        }
        return array(NULL, NULL);
    }
    /**
     * @param string|array $dirs
     *   List of directories to check.
     * @param string|array $items
     *   List of globs to check in each directory.
     * @return null|string
     */
    protected function findFirstFile($dirs, $items)
    {
        $dirs = (array) $dirs;
        $items = (array) $items;
        foreach ($dirs as $dir) {
            foreach ($items as $item) {
                $matches = (array) \glob("{$dir}/{$item}");
                if (isset($matches[0])) {
                    return $matches[0];
                }
            }
        }
        return NULL;
    }
    /**
     * @return string
     */
    protected function getSearchDir()
    {
        if ($this->options['search'] === \TRUE) {
            // exec(pwd) works better with symlinked source trees, but it's
            // probably not portable to Windows.
            if (\strtoupper(\substr(\PHP_OS, 0, 3)) === 'WIN') {
                return \getcwd();
            } else {
                \exec('pwd', $output);
                return \trim(\implode("\n", $output));
            }
        } else {
            return $this->options['search'];
        }
    }
}
<?php

namespace Civi\Cv;

class SiteConfigReader
{
    protected $settingsFile;
    protected $cache = array();
    /**
     * SiteConfigReader constructor.
     * @param string $settingsFile
     *   The identifier for the site we want to read.
     */
    public function __construct($settingsFile)
    {
        $this->settingsFile = $settingsFile;
    }
    /**
     * @param array $parts
     *   Any of 'buildkit', 'home', 'active'.
     * @return array
     */
    public function compile($parts)
    {
        $data = array();
        foreach ($parts as $part) {
            switch ($part) {
                case 'buildkit':
                    $data = \array_merge($data, $this->readBuildkitConfig());
                    break;
                case 'home':
                    $data = \array_merge($data, $this->readHomeConfig());
                    break;
                case 'active':
                    $data = \array_merge($data, $this->readActiveConfig());
                    break;
            }
        }
        return $this->clean($data);
    }
    /**
     * Read the config vars from buildkit's .sh file.
     *
     * @return array
     */
    public function readBuildkitConfig()
    {
        if (!isset($this->cache['buildkit'])) {
            $shFile = \Civi\Cv\BuildkitReader::findShFile($this->settingsFile);
            $this->cache['buildkit'] = $shFile ? \Civi\Cv\BuildkitReader::readShFile($shFile) : array();
        }
        return $this->cache['buildkit'];
    }
    /**
     * Read the config vars from ~/.cv.json.
     *
     * @return array
     */
    public function readHomeConfig()
    {
        if (!isset($this->cache['home'])) {
            $config = \Civi\Cv\Config::read();
            $this->cache['home'] = isset($config['sites'][$this->settingsFile]) ? $config['sites'][$this->settingsFile] : array();
        }
        return $this->cache['home'];
    }
    /**
     * @return array
     */
    public function readActiveConfig()
    {
        if (!\defined('CIVICRM_SETTINGS_PATH') || CIVICRM_SETTINGS_PATH !== $this->settingsFile) {
            return array();
        }
        $paths = \is_callable(array('Civi', 'paths')) ? \Civi::paths() : NULL;
        $data = array('CMS_DB_DSN' => CIVICRM_UF_DSN, 'CMS_VERSION' => \CRM_Core_Config::singleton()->userSystem->getVersion(), 'CIVI_DB_DSN' => CIVICRM_DSN, 'CIVI_SITE_KEY' => CIVICRM_SITE_KEY, 'CIVI_VERSION' => \CRM_Utils_System::version(), 'CIVI_SETTINGS' => CIVICRM_SETTINGS_PATH, 'CIVI_TEMPLATEC' => \CRM_Core_Config::singleton()->templateCompileDir, 'CIVI_LOG' => \CRM_Core_Error::createDebugLogger()->_filename, 'CIVI_UF' => \CRM_Core_Config::singleton()->userFramework, 'IS_INSTALLED' => '1', 'SITE_TYPE' => 'cv-auto');
        if (\is_callable(array('Civi', 'paths'))) {
            $data += [
                'CMS_URL' => \Civi::paths()->getUrl('[cms.root]/', 'absolute'),
                'CMS_ROOT' => \Civi::paths()->getPath('[cms.root]/.'),
                'CIVI_CORE' => \Civi::paths()->getPath('[civicrm.root]/.'),
                // NOTE: not in buildkit:
                'CIVI_URL' => \Civi::paths()->getUrl('[civicrm.root]/', 'absolute'),
                'CIVI_FILES' => \Civi::paths()->getPath('[civicrm.files]/.'),
            ];
        } else {
            $data += [
                'CMS_URL' => \CRM_Utils_System::languageNegotiationURL(\CRM_Utils_System::baseCMSURL(), \FALSE, \TRUE),
                'CMS_ROOT' => \CRM_Core_Config::singleton()->userSystem->cmsRootPath(),
                'CIVI_CORE' => $GLOBALS['civicrm_root'],
                // NOTE: not in buildkit:
                'CIVI_URL' => '',
                // NOTE: This was ill-defined in older versions:
                'CIVI_FILES' => \dirname(\CRM_Core_Config::singleton()->templateCompileDir),
            ];
        }
        return $data;
    }
    /**
     * @parm array $data
     * @return array
     */
    public function clean($data)
    {
        $this->cleanPaths($data);
        $this->cleanUrls($data);
        $this->cleanDbs($data);
        \ksort($data);
        return $data;
    }
    /**
     * @param $data
     */
    protected function cleanPaths(&$data)
    {
        $paths = array('CIVI_CORE', 'CIVI_FILES', 'CIVI_TEMPLATEC', 'CMS_ROOT');
        foreach ($paths as $path) {
            if (!empty($data[$path])) {
                $data[$path] = \rtrim($data[$path], \DIRECTORY_SEPARATOR) . \DIRECTORY_SEPARATOR;
            }
        }
    }
    /**
     * @param $data
     */
    protected function cleanUrls(&$data)
    {
        $urls = array('CMS_URL', 'CIVI_URL');
        foreach ($urls as $url) {
            if (isset($data[$url])) {
                $data[$url] = \rtrim($data[$url], '/') . '/';
            }
        }
    }
    /**
     * @param $data
     */
    protected function cleanDbs(&$data)
    {
        foreach (array('CIVI', 'CMS', 'TEST') as $prefix) {
            if (isset($data["{$prefix}_DB_DSN"])) {
                $data = \array_merge($data, $this->parseDsn($prefix, $data["{$prefix}_DB_DSN"]));
            }
        }
    }
    protected function parseDsn($prefix, $dsn)
    {
        $url = \parse_url($dsn);
        // Ex: CMS_DB_ARGS="-h 127.0.0.1 -u username -ptopsecret -P 3307 dbname"
        $parts = array();
        if (!empty($url['host'])) {
            $parts[] = '-h';
            $parts[] = $url['host'];
        }
        if (!empty($url['user'])) {
            $parts[] = '-u';
            $parts[] = $url['user'];
        }
        if (!empty($url['pass'])) {
            $parts[] = '-p' . $url['user'];
        }
        if (!empty($url['port'])) {
            $parts[] = '-P';
            $parts[] = $url['port'];
        }
        if (!empty($url['path'])) {
            $parts[] = \trim($url['path'], '/');
        }
        foreach ($parts as $part) {
            if (!\preg_match('/^[a-zA-Z0-9\\._+\\-]*$/', $part)) {
                throw new \InvalidArgumentException("Cannot format DB CLI arguments ({$dsn})");
            }
        }
        return array("{$prefix}_DB_USER" => empty($url['user']) ? '' : $url['user'], "{$prefix}_DB_PASS" => empty($url['pass']) ? '' : $url['pass'], "{$prefix}_DB_HOST" => empty($url['host']) ? '' : $url['host'], "{$prefix}_DB_PORT" => empty($url['port']) ? '' : $url['port'], "{$prefix}_DB_NAME" => empty($url['path']) ? '' : \trim($url['path'], '/'), "{$prefix}_DB_ARGS" => \implode(' ', $parts));
    }
}
<?php

namespace Civi\Cv;

use Civi\Cv\Util\Filesystem;
class Config
{
    public static function read()
    {
        $file = self::getFileName();
        if ($file && \file_exists($file)) {
            $buf = \file_get_contents($file);
            $config = \json_decode($buf, \TRUE);
            if (!empty($buf) && $config === NULL) {
                throw new \RuntimeException("Config file ({$file}) contains malformed JSON.");
            }
            return $config;
        } else {
            return array();
        }
    }
    /**
     * Update a section of the config
     *
     * @param callable $filter
     *   A filter function which accepts the old config and returns the new config.
     *   Ex: function($data) { $data['x']=123; return $data; }
     * @return bool
     * @throws \RuntimeException
     */
    public static function update($filter)
    {
        $fs = new Filesystem();
        return $fs->update(self::getFileName(), function ($rawIn) use($filter) {
            $data = empty($rawIn) ? array() : \json_decode($rawIn, \TRUE);
            $data = \call_user_func($filter, $data);
            return \Civi\Cv\Encoder::encode($data, 'json-pretty');
        });
    }
    /**
     * @return string
     */
    public static function getFileName()
    {
        if (\getenv('CV_CONFIG')) {
            return \getenv('CV_CONFIG');
        } elseif (\getenv('HOME')) {
            return \getenv('HOME') . '/.cv.json';
        } else {
            throw new \RuntimeException("Failed to determine file path for 'cv.json'.");
        }
    }
}
<?php

// @generated by Humbug Box

// Backup the autoloaded Composer files
if (isset($GLOBALS['__composer_autoload_files'])) {
    $existingComposerAutoloadFiles = $GLOBALS['__composer_autoload_files'];
}

// autoload.php @generated by Composer

if (PHP_VERSION_ID < 50600) {
    echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
    exit(1);
}

require_once __DIR__ . '/composer/autoload_real.php';

$loader = ComposerAutoloaderInit3099b3329d998f64461a08224d3887b9::getLoader();

// Ensure InstalledVersions is available
$installedVersionsPath = __DIR__.'/composer/InstalledVersions.php';
if (file_exists($installedVersionsPath)) require_once $installedVersionsPath;

// Restore the backup
if (isset($existingComposerAutoloadFiles)) {
    $GLOBALS['__composer_autoload_files'] = $existingComposerAutoloadFiles;
} else {
    unset($GLOBALS['__composer_autoload_files']);
}

// Class aliases. For more information see:
// https://github.com/humbug/php-scoper/blob/master/docs/further-reading.md#class-aliases
if (!function_exists('humbug_phpscoper_expose_class')) {
    function humbug_phpscoper_expose_class(string $exposed, string $prefixed): void {
        if (!class_exists($exposed, false) && !interface_exists($exposed, false) && !trait_exists($exposed, false)) {
            spl_autoload_call($prefixed);
        }
    }
}
humbug_phpscoper_expose_class('ComposerAutoloaderInit3099b3329d998f64461a08224d3887b9', 'CivixPhar\ComposerAutoloaderInit3099b3329d998f64461a08224d3887b9');
humbug_phpscoper_expose_class('JsonException', 'CivixPhar\JsonException');
humbug_phpscoper_expose_class('TOGoS_GitIgnore_Util', 'CivixPhar\TOGoS_GitIgnore_Util');
humbug_phpscoper_expose_class('TOGoS_GitIgnore_FileFinder', 'CivixPhar\TOGoS_GitIgnore_FileFinder');
humbug_phpscoper_expose_class('TOGoS_GitIgnore_Pattern', 'CivixPhar\TOGoS_GitIgnore_Pattern');
humbug_phpscoper_expose_class('TOGoS_GitIgnore_Rule', 'CivixPhar\TOGoS_GitIgnore_Rule');
humbug_phpscoper_expose_class('TOGoS_GitIgnore_Ruleset', 'CivixPhar\TOGoS_GitIgnore_Ruleset');

// Function aliases. For more information see:
// https://github.com/humbug/php-scoper/blob/master/docs/further-reading.md#function-aliases
if (!function_exists('array_key_first')) { function array_key_first() { return \CivixPhar\array_key_first(...func_get_args()); } }
if (!function_exists('array_key_last')) { function array_key_last() { return \CivixPhar\array_key_last(...func_get_args()); } }
if (!function_exists('ctype_alnum')) { function ctype_alnum() { return \CivixPhar\ctype_alnum(...func_get_args()); } }
if (!function_exists('ctype_alpha')) { function ctype_alpha() { return \CivixPhar\ctype_alpha(...func_get_args()); } }
if (!function_exists('ctype_cntrl')) { function ctype_cntrl() { return \CivixPhar\ctype_cntrl(...func_get_args()); } }
if (!function_exists('ctype_digit')) { function ctype_digit() { return \CivixPhar\ctype_digit(...func_get_args()); } }
if (!function_exists('ctype_graph')) { function ctype_graph() { return \CivixPhar\ctype_graph(...func_get_args()); } }
if (!function_exists('ctype_lower')) { function ctype_lower() { return \CivixPhar\ctype_lower(...func_get_args()); } }
if (!function_exists('ctype_print')) { function ctype_print() { return \CivixPhar\ctype_print(...func_get_args()); } }
if (!function_exists('ctype_punct')) { function ctype_punct() { return \CivixPhar\ctype_punct(...func_get_args()); } }
if (!function_exists('ctype_space')) { function ctype_space() { return \CivixPhar\ctype_space(...func_get_args()); } }
if (!function_exists('ctype_upper')) { function ctype_upper() { return \CivixPhar\ctype_upper(...func_get_args()); } }
if (!function_exists('ctype_xdigit')) { function ctype_xdigit() { return \CivixPhar\ctype_xdigit(...func_get_args()); } }
if (!function_exists('fdiv')) { function fdiv() { return \CivixPhar\fdiv(...func_get_args()); } }
if (!function_exists('get_debug_type')) { function get_debug_type() { return \CivixPhar\get_debug_type(...func_get_args()); } }
if (!function_exists('get_resource_id')) { function get_resource_id() { return \CivixPhar\get_resource_id(...func_get_args()); } }
if (!function_exists('hrtime')) { function hrtime() { return \CivixPhar\hrtime(...func_get_args()); } }
if (!function_exists('is_countable')) { function is_countable() { return \CivixPhar\is_countable(...func_get_args()); } }
if (!function_exists('mb_check_encoding')) { function mb_check_encoding() { return \CivixPhar\mb_check_encoding(...func_get_args()); } }
if (!function_exists('mb_chr')) { function mb_chr() { return \CivixPhar\mb_chr(...func_get_args()); } }
if (!function_exists('mb_convert_case')) { function mb_convert_case() { return \CivixPhar\mb_convert_case(...func_get_args()); } }
if (!function_exists('mb_convert_encoding')) { function mb_convert_encoding() { return \CivixPhar\mb_convert_encoding(...func_get_args()); } }
if (!function_exists('mb_convert_variables')) { function mb_convert_variables() { return \CivixPhar\mb_convert_variables(...func_get_args()); } }
if (!function_exists('mb_decode_mimeheader')) { function mb_decode_mimeheader() { return \CivixPhar\mb_decode_mimeheader(...func_get_args()); } }
if (!function_exists('mb_decode_numericentity')) { function mb_decode_numericentity() { return \CivixPhar\mb_decode_numericentity(...func_get_args()); } }
if (!function_exists('mb_detect_encoding')) { function mb_detect_encoding() { return \CivixPhar\mb_detect_encoding(...func_get_args()); } }
if (!function_exists('mb_detect_order')) { function mb_detect_order() { return \CivixPhar\mb_detect_order(...func_get_args()); } }
if (!function_exists('mb_encode_mimeheader')) { function mb_encode_mimeheader() { return \CivixPhar\mb_encode_mimeheader(...func_get_args()); } }
if (!function_exists('mb_encode_numericentity')) { function mb_encode_numericentity() { return \CivixPhar\mb_encode_numericentity(...func_get_args()); } }
if (!function_exists('mb_encoding_aliases')) { function mb_encoding_aliases() { return \CivixPhar\mb_encoding_aliases(...func_get_args()); } }
if (!function_exists('mb_get_info')) { function mb_get_info() { return \CivixPhar\mb_get_info(...func_get_args()); } }
if (!function_exists('mb_http_input')) { function mb_http_input() { return \CivixPhar\mb_http_input(...func_get_args()); } }
if (!function_exists('mb_http_output')) { function mb_http_output() { return \CivixPhar\mb_http_output(...func_get_args()); } }
if (!function_exists('mb_internal_encoding')) { function mb_internal_encoding() { return \CivixPhar\mb_internal_encoding(...func_get_args()); } }
if (!function_exists('mb_language')) { function mb_language() { return \CivixPhar\mb_language(...func_get_args()); } }
if (!function_exists('mb_list_encodings')) { function mb_list_encodings() { return \CivixPhar\mb_list_encodings(...func_get_args()); } }
if (!function_exists('mb_ord')) { function mb_ord() { return \CivixPhar\mb_ord(...func_get_args()); } }
if (!function_exists('mb_output_handler')) { function mb_output_handler() { return \CivixPhar\mb_output_handler(...func_get_args()); } }
if (!function_exists('mb_parse_str')) { function mb_parse_str() { return \CivixPhar\mb_parse_str(...func_get_args()); } }
if (!function_exists('mb_scrub')) { function mb_scrub() { return \CivixPhar\mb_scrub(...func_get_args()); } }
if (!function_exists('mb_str_split')) { function mb_str_split() { return \CivixPhar\mb_str_split(...func_get_args()); } }
if (!function_exists('mb_stripos')) { function mb_stripos() { return \CivixPhar\mb_stripos(...func_get_args()); } }
if (!function_exists('mb_stristr')) { function mb_stristr() { return \CivixPhar\mb_stristr(...func_get_args()); } }
if (!function_exists('mb_strlen')) { function mb_strlen() { return \CivixPhar\mb_strlen(...func_get_args()); } }
if (!function_exists('mb_strpos')) { function mb_strpos() { return \CivixPhar\mb_strpos(...func_get_args()); } }
if (!function_exists('mb_strrchr')) { function mb_strrchr() { return \CivixPhar\mb_strrchr(...func_get_args()); } }
if (!function_exists('mb_strrichr')) { function mb_strrichr() { return \CivixPhar\mb_strrichr(...func_get_args()); } }
if (!function_exists('mb_strripos')) { function mb_strripos() { return \CivixPhar\mb_strripos(...func_get_args()); } }
if (!function_exists('mb_strrpos')) { function mb_strrpos() { return \CivixPhar\mb_strrpos(...func_get_args()); } }
if (!function_exists('mb_strstr')) { function mb_strstr() { return \CivixPhar\mb_strstr(...func_get_args()); } }
if (!function_exists('mb_strtolower')) { function mb_strtolower() { return \CivixPhar\mb_strtolower(...func_get_args()); } }
if (!function_exists('mb_strtoupper')) { function mb_strtoupper() { return \CivixPhar\mb_strtoupper(...func_get_args()); } }
if (!function_exists('mb_strwidth')) { function mb_strwidth() { return \CivixPhar\mb_strwidth(...func_get_args()); } }
if (!function_exists('mb_substitute_character')) { function mb_substitute_character() { return \CivixPhar\mb_substitute_character(...func_get_args()); } }
if (!function_exists('mb_substr')) { function mb_substr() { return \CivixPhar\mb_substr(...func_get_args()); } }
if (!function_exists('mb_substr_count')) { function mb_substr_count() { return \CivixPhar\mb_substr_count(...func_get_args()); } }
if (!function_exists('preg_last_error_msg')) { function preg_last_error_msg() { return \CivixPhar\preg_last_error_msg(...func_get_args()); } }
if (!function_exists('sapi_windows_vt100_support')) { function sapi_windows_vt100_support() { return \CivixPhar\sapi_windows_vt100_support(...func_get_args()); } }
if (!function_exists('spl_object_id')) { function spl_object_id() { return \CivixPhar\spl_object_id(...func_get_args()); } }
if (!function_exists('str_contains')) { function str_contains() { return \CivixPhar\str_contains(...func_get_args()); } }
if (!function_exists('str_ends_with')) { function str_ends_with() { return \CivixPhar\str_ends_with(...func_get_args()); } }
if (!function_exists('str_starts_with')) { function str_starts_with() { return \CivixPhar\str_starts_with(...func_get_args()); } }
if (!function_exists('stream_isatty')) { function stream_isatty() { return \CivixPhar\stream_isatty(...func_get_args()); } }
if (!function_exists('utf8_decode')) { function utf8_decode() { return \CivixPhar\utf8_decode(...func_get_args()); } }
if (!function_exists('utf8_encode')) { function utf8_encode() { return \CivixPhar\utf8_encode(...func_get_args()); } }

return $loader;
<?php

namespace CivixPhar\Lurker;

use CivixPhar\Lurker\Event\FilesystemEvent;
use CivixPhar\Lurker\Exception\InvalidArgumentException;
use CivixPhar\Lurker\Resource\DirectoryResource;
use CivixPhar\Lurker\Resource\FileResource;
use CivixPhar\Lurker\Resource\ResourceInterface;
use CivixPhar\Lurker\Resource\TrackedResource;
use CivixPhar\Lurker\Tracker\InotifyTracker;
use CivixPhar\Lurker\Tracker\RecursiveIteratorTracker;
use CivixPhar\Lurker\Tracker\TrackerInterface;
use CivixPhar\Lurker\EventDispatcher\EventDispatcher;
use CivixPhar\Lurker\EventDispatcher\EventDispatcherInterface;
/**
 * Resource changes watcher.
 *
 * @author Konstantin Kudryashov <ever.zet@gmail.com>
 */
class ResourceWatcher
{
    private $tracker;
    /**
     * @var EventDispatcherInterface|null
     */
    private $eventDispatcher;
    private $watching = \false;
    /**
     * Initializes path watcher.
     *
     * @param TrackerInterface         $tracker
     * @param EventDispatcherInterface $eventDispatcher
     */
    public function __construct(TrackerInterface $tracker = null, $eventDispatcher = null)
    {
        if (null === $tracker) {
            // TODO: Re-enable InotifyTracker when it's passing its tests.
            $tracker = new RecursiveIteratorTracker();
            //if (function_exists('inotify_init')) {
            //    $tracker = new InotifyTracker();
            //} else {
            //    $tracker = new RecursiveIteratorTracker();
            //}
        }
        if ($eventDispatcher instanceof \CivixPhar\Symfony\Component\EventDispatcher\EventDispatcherInterface) {
            \trigger_error('In lurkerlite, the ResourceWatcher does not support Symfony EventDispatcher.' . ' See CHANGELOG for upgrade guidance.', \E_USER_DEPRECATED);
            $eventDispatcher = new EventDispatcher();
        }
        if (null === $eventDispatcher) {
            $eventDispatcher = new EventDispatcher();
        }
        $this->tracker = $tracker;
        $this->eventDispatcher = $eventDispatcher;
    }
    /**
     * Returns current tracker instance.
     *
     * @return TrackerInterface
     */
    public function getTracker()
    {
        return $this->tracker;
    }
    /**
     * Returns event dispatcher mapped to this tracker.
     *
     * @return EventDispatcherInterface
     */
    public function getEventDispatcher()
    {
        return $this->eventDispatcher;
    }
    /**
     * Track resource with watcher.
     *
     * @param string                   $trackingId id to this track (used for events naming)
     * @param ResourceInterface|string $resource   resource to track
     * @param integer                  $eventsMask event types bitmask
     *
     * @throws InvalidArgumentException If 'all' is used as a tracking id
     */
    public function track($trackingId, $resource, $eventsMask = FilesystemEvent::ALL)
    {
        if ('all' === $trackingId) {
            throw new InvalidArgumentException('"all" is a reserved keyword and can not be used as tracking id');
        }
        if (!$resource instanceof ResourceInterface) {
            if (\is_file($resource)) {
                $resource = new FileResource($resource);
            } elseif (\is_dir($resource)) {
                $resource = new DirectoryResource($resource);
            } else {
                throw new InvalidArgumentException(\sprintf('Second argument to track() should be either file or directory resource, ' . 'but got "%s"', $resource));
            }
        }
        $trackedResource = new TrackedResource($trackingId, $resource);
        $this->getTracker()->track($trackedResource, $eventsMask);
    }
    /**
     * Adds callback as specific tracking listener.
     *
     * @param string   $trackingId id to this track (used for events naming)
     * @param callable $callback   callback to call on change
     *
     * @throws InvalidArgumentException If $callback argument isn't callable
     */
    public function addListener($trackingId, $callback)
    {
        if (!\is_callable($callback)) {
            throw new InvalidArgumentException(\sprintf('Second argument to listen() should be callable, but got %s', \gettype($callback)));
        }
        $this->getEventDispatcher()->addListener('resource_watcher.' . $trackingId, $callback);
    }
    /**
     * Tracks specific resource change by provided callback.
     *
     * @param ResourceInterface|string $resource   resource to track
     * @param callable                 $callback   callback to call on change
     * @param integer                  $eventsMask event types bitmask
     */
    public function trackByListener($resource, $callback, $eventsMask = FilesystemEvent::ALL)
    {
        $this->track($trackingId = \md5((string) $resource . $eventsMask), $resource, $eventsMask);
        $this->addListener($trackingId, $callback);
    }
    /**
     * Returns true if watcher is currently watching on tracked resources (started).
     *
     * @return Boolean
     */
    public function isWatching()
    {
        return $this->watching;
    }
    /**
     * Starts watching on tracked resources.
     *
     * @param integer $checkInterval check interval in microseconds
     * @param integer $timeLimit     maximum watching time limit in microseconds
     */
    public function start($checkInterval = 1000000, $timeLimit = null)
    {
        $totalTime = 0;
        $this->watching = \true;
        while ($this->watching) {
            \usleep($checkInterval);
            $totalTime += $checkInterval;
            if (null !== $timeLimit && $totalTime > $timeLimit) {
                break;
            }
            foreach ($this->getTracker()->getEvents() as $event) {
                $trackedResource = $event->getTrackedResource();
                // fire global event
                $this->getEventDispatcher()->dispatch('resource_watcher.all', $event);
                // fire specific trackingId event
                $this->getEventDispatcher()->dispatch(\sprintf('resource_watcher.%s', $trackedResource->getTrackingId()), $event);
            }
        }
        $this->watching = \false;
    }
    /**
     * Stop watching on tracked resources.
     */
    public function stop()
    {
        $this->watching = \false;
    }
}
<?php

namespace CivixPhar\Lurker\Tracker;

use CivixPhar\Lurker\Resource\DirectoryResource;
use CivixPhar\Lurker\Event\FilesystemEvent;
use CivixPhar\Lurker\Resource\TrackedResource;
use CivixPhar\Lurker\StateChecker\DirectoryStateChecker;
use CivixPhar\Lurker\StateChecker\FileStateChecker;
/**
 * Recursive iterator resources tracker.
 *
 * @author Konstantin Kudryashov <ever.zet@gmail.com>
 */
class RecursiveIteratorTracker implements TrackerInterface
{
    private $checkers = array();
    /**
     * {@inheritdoc}
     */
    public function track(TrackedResource $resource, $eventsMask = FilesystemEvent::ALL)
    {
        $trackingId = $resource->getTrackingId();
        $checker = $resource->getOriginalResource() instanceof DirectoryResource ? new DirectoryStateChecker($resource->getOriginalResource(), $eventsMask) : new FileStateChecker($resource->getOriginalResource(), $eventsMask);
        $this->checkers[$trackingId] = array('tracked' => $resource, 'checker' => $checker);
    }
    /**
     * {@inheritdoc}
     */
    public function getEvents()
    {
        $events = array();
        foreach ($this->checkers as $trackingId => $meta) {
            $tracked = $meta['tracked'];
            $checker = $meta['checker'];
            foreach ($checker->getChangeset() as $change) {
                $events[] = new FilesystemEvent($tracked, $change['resource'], $change['event']);
            }
        }
        return $events;
    }
}
<?php

namespace CivixPhar\Lurker\Tracker;

use CivixPhar\Lurker\Resource\TrackedResource;
use CivixPhar\Lurker\Event\FilesystemEvent;
/**
 * Resources tracker interface.
 *
 * @author Konstantin Kudryashov <ever.zet@gmail.com>
 */
interface TrackerInterface
{
    /**
     * Starts to track provided resource for changes.
     *
     * @param TrackedResource $resource
     * @param integer         $eventsMask event types bitmask
     */
    public function track(TrackedResource $resource, $eventsMask = FilesystemEvent::ALL);
    /**
     * Checks tracked resources for change events.
     *
     * @return array change events array
     */
    public function getEvents();
}
<?php

namespace CivixPhar\Lurker\Tracker;

use CivixPhar\Lurker\Resource\DirectoryResource;
use CivixPhar\Lurker\Resource\TrackedResource;
use CivixPhar\Lurker\Event\FilesystemEvent;
use CivixPhar\Lurker\StateChecker\Inotify\TopDirectoryStateChecker;
use CivixPhar\Lurker\StateChecker\Inotify\FileStateChecker;
use CivixPhar\Lurker\Exception\RuntimeException;
use CivixPhar\Lurker\StateChecker\Inotify\CheckerBag;
/**
 * Inotify tracker. To use this tracker you must install inotify extension.
 *
 * @link http://pecl.php.net/package/inotify Inotify PECL extension
 * @author Yaroslav Kiliba <om.dattaya@gmail.com>
 */
class InotifyTracker implements TrackerInterface
{
    /**
     * @var array
     */
    protected $checkers = array();
    /**
     * @var CheckerBag
     */
    protected $bag;
    /**
     * @var resource Inotify resource.
     */
    private $inotify;
    /**
     * Initializes tracker. Creates inotify resource used to track file and directory changes.
     *
     * @throws RuntimeException If inotify extension unavailable
     */
    public function __construct()
    {
        if (!\function_exists('inotify_init')) {
            throw new RuntimeException('You must install inotify to be able to use this tracker.');
        }
        $this->inotify = \inotify_init();
        \stream_set_blocking($this->inotify, 0);
        $this->bag = new CheckerBag($this->inotify);
    }
    /**
     * {@inheritdoc}
     */
    public function track(TrackedResource $resource, $eventsMask = FilesystemEvent::ALL)
    {
        $trackingId = $resource->getTrackingId();
        $checker = $resource->getOriginalResource() instanceof DirectoryResource ? new TopDirectoryStateChecker($this->bag, $resource->getOriginalResource(), $eventsMask) : new FileStateChecker($this->bag, $resource->getOriginalResource(), $eventsMask);
        $this->checkers[$trackingId] = array('tracked' => $resource, 'checker' => $checker);
    }
    /**
     * {@inheritdoc}
     *
     * @throws RuntimeException If event queue overflowed
     */
    public function getEvents()
    {
        $inotifyEvents = $this->readEvents();
        $inotifyEvents = \is_array($inotifyEvents) ? $inotifyEvents : array();
        $last = \end($inotifyEvents);
        if (\IN_Q_OVERFLOW === $last['mask']) {
            throw new RuntimeException('Event queue overflowed. Either read events more frequently or increase the limit for queues. The limit can be changed in /proc/sys/fs/inotify/max_queued_events');
        }
        foreach ($inotifyEvents as $event) {
            foreach ($this->bag->get($event['wd']) as $watched) {
                $watched->setEvent($event['mask'], $event['name']);
            }
        }
        $events = array();
        foreach ($this->checkers as $meta) {
            $tracked = $meta['tracked'];
            $watched = $meta['checker'];
            foreach ($watched->getChangeset() as $change) {
                $events[] = new FilesystemEvent($tracked, $change['resource'], $change['event']);
            }
        }
        return $events;
    }
    /**
     * Closes the inotify resource.
     */
    public function __destruct()
    {
        \fclose($this->inotify);
    }
    /**
     * Returns all events happened since last event readout
     *
     * @return array
     */
    protected function readEvents()
    {
        return \inotify_read($this->inotify);
    }
}
<?php

namespace CivixPhar\Lurker\Event;

use CivixPhar\Lurker\Resource\TrackedResource;
use CivixPhar\Lurker\Exception\InvalidArgumentException;
use CivixPhar\Lurker\Resource\ResourceInterface;
use CivixPhar\Lurker\Resource\FileResource;
use CivixPhar\Lurker\Resource\DirectoryResource;
trait FilesystemEventTrait
{
    private $tracked;
    private $resource;
    private $type;
    protected static $types = array(1 => 'create', 2 => 'modify', 4 => 'delete');
    /**
     * Initializes resource event.
     *
     * @param TrackedResource   $tracked  resource, that being tracked
     * @param ResourceInterface $resource resource instance
     * @param integer           $type     event type bit
     */
    public function __construct(TrackedResource $tracked, ResourceInterface $resource, $type)
    {
        if (!isset(self::$types[$type])) {
            throw new InvalidArgumentException('Wrong event type providen');
        }
        $this->tracked = $tracked;
        $this->resource = $resource;
        $this->type = $type;
    }
    /**
     * Returns resource, that being tracked while event occured.
     *
     * @return int
     */
    public function getTrackedResource()
    {
        return $this->tracked;
    }
    /**
     * Returns changed resource.
     *
     * @return ResourceInterface
     */
    public function getResource()
    {
        return $this->resource;
    }
    /**
     * Returns true is resource, that fired event is file.
     *
     * @return Boolean
     */
    public function isFileChange()
    {
        return $this->resource instanceof FileResource;
    }
    /**
     * Returns true is resource, that fired event is directory.
     *
     * @return Boolean
     */
    public function isDirectoryChange()
    {
        return $this->resource instanceof DirectoryResource;
    }
    /**
     * Returns event type.
     *
     * @return integer
     */
    public function getType()
    {
        return $this->type;
    }
    /**
     * Returns event type string representation.
     *
     * @return string
     */
    public function getTypeString()
    {
        return self::$types[$this->getType()];
    }
}
<?php

namespace CivixPhar\Lurker\Event;

/**
 * Resource change event.
 *
 * @author Konstantin Kudryashov <ever.zet@gmail.com>
 */
class FilesystemEvent
{
    const CREATE = 1;
    const MODIFY = 2;
    const DELETE = 4;
    const ALL = 7;
    use FilesystemEventTrait;
}
<?php

namespace CivixPhar\Lurker\Resource;

use CivixPhar\Lurker\Exception\InvalidArgumentException;
/**
 * @package Lurker
 */
class FileResource implements ResourceInterface
{
    /**
     * @var string
     */
    private $resource;
    /**
     * @param string $resource
     */
    public function __construct($resource)
    {
        $this->resource = \realpath($resource);
        if (\false === $this->resource && \file_exists($resource)) {
            $this->resource = $resource;
        }
        if (\false === $this->resource) {
            throw new InvalidArgumentException(\sprintf('The file "%s" does not exist.', $resource));
        }
    }
    /**
     * @return string
     */
    public function getResource()
    {
        return $this->resource;
    }
    /**
     * @return string
     */
    public function __toString()
    {
        return $this->resource;
    }
    public function getModificationTime()
    {
        if (!$this->exists()) {
            return -1;
        }
        \clearstatcache(\true, $this->getResource());
        if (\false === ($mtime = @\filemtime($this->getResource()))) {
            return -1;
        }
        return $mtime;
    }
    public function getId()
    {
        return \md5('f' . $this);
    }
    public function isFresh($timestamp)
    {
        if (!$this->exists()) {
            return \false;
        }
        return $this->getModificationTime() < $timestamp;
    }
    public function exists()
    {
        \clearstatcache(\true, $this->getResource());
        return \is_file($this);
    }
}
<?php

namespace CivixPhar\Lurker\Resource;

use CivixPhar\Lurker\Exception\InvalidArgumentException;
/**
 * Wraps usual resource with tracker information.
 *
 * @author Konstantin Kudryashov <ever.zet@gmail.com>
 */
class TrackedResource
{
    private $trackingId;
    private $resource;
    /**
     * Initializes tracked resource.
     *
     * @param string            $trackingId id of the tracked resource
     * @param ResourceInterface $resource   resource
     */
    public function __construct($trackingId, ResourceInterface $resource)
    {
        if (!$resource->exists()) {
            throw new InvalidArgumentException(\sprintf('Unable to track a non-existent resource (%s)', $resource));
        }
        $this->trackingId = $trackingId;
        $this->resource = $resource;
    }
    /**
     * Returns tracking ID of the resource.
     *
     * @return string
     */
    public function getTrackingId()
    {
        return $this->trackingId;
    }
    /**
     * Returns original resource instance.
     *
     * @return ResourceInterface
     */
    public function getOriginalResource()
    {
        return $this->resource;
    }
}
<?php

namespace CivixPhar\Lurker\Resource;

/**
 * @package Lurker
 */
interface ResourceInterface
{
    /**
     * @return boolean
     */
    public function exists();
    /**
     * @return integer
     */
    public function getModificationTime();
    /**
     * @return string
     */
    public function getId();
}
<?php

namespace CivixPhar\Lurker\Resource;

use CivixPhar\Lurker\Exception\InvalidArgumentException;
/**
 * @package Lurker
 */
class DirectoryResource implements ResourceInterface
{
    /**
     * @var string
     */
    private $resource;
    /**
     * @var string|null
     */
    private $pattern;
    /**
     * @param string $resource
     * @param string|null $pattern
     */
    public function __construct($resource, $pattern = null)
    {
        $this->resource = \realpath($resource);
        $this->pattern = $pattern;
        if (\false === $this->resource || !\is_dir($this->resource)) {
            throw new InvalidArgumentException(\sprintf('The directory "%s" does not exist.', $resource));
        }
    }
    /**
     * @return string
     */
    public function getResource()
    {
        return $this->resource;
    }
    /**
     * @return string
     */
    public function getPattern()
    {
        return $this->pattern;
    }
    /**
     * @return string
     */
    public function __toString()
    {
        return \md5(\serialize(array($this->resource, $this->pattern)));
    }
    public function exists()
    {
        \clearstatcache(\true, $resource = $this->getResource());
        return \is_dir($resource);
    }
    public function getModificationTime()
    {
        if (!$this->exists()) {
            return -1;
        }
        \clearstatcache(\true, $this->getResource());
        if (\false === ($mtime = @\filemtime($this->getResource()))) {
            return -1;
        }
        return $mtime;
    }
    public function isFresh($timestamp)
    {
        if (!$this->exists()) {
            return \false;
        }
        return $this->getModificationTime() < $timestamp;
    }
    public function getId()
    {
        return \md5('d' . $this . $this->getPattern());
    }
    public function hasFile($file)
    {
        if (!$file instanceof \SplFileInfo) {
            $file = new \SplFileInfo($file);
        }
        if (0 !== \strpos($file->getRealPath(), \realpath($this->getResource()))) {
            return \false;
        }
        if ($this->getPattern()) {
            return (bool) \preg_match($this->getPattern(), $file->getBasename());
        }
        return \true;
    }
    public function getFilteredResources()
    {
        if (!$this->exists()) {
            return array();
        }
        // race conditions
        try {
            $iterator = new \DirectoryIterator($this->getResource());
        } catch (\UnexpectedValueException $e) {
            return array();
        }
        $resources = array();
        foreach ($iterator as $file) {
            // if regex filtering is enabled only return matching files
            if ($file->isFile() && !$this->hasFile($file)) {
                continue;
            }
            // always monitor directories for changes, except the .. entries
            // (otherwise deleted files wouldn't get detected)
            if ($file->isDir() && '/..' === \substr($file, -3)) {
                continue;
            }
            // if file is dot - continue
            if ($file->isDot()) {
                continue;
            }
            if ($file->isFile()) {
                $resources[] = new FileResource($file->getRealPath());
            } elseif ($file->isDir()) {
                $resources[] = new DirectoryResource($file->getRealPath());
            }
        }
        return $resources;
    }
}
<?php

namespace CivixPhar\Lurker\StateChecker;

use CivixPhar\Lurker\Event\FilesystemEvent;
use CivixPhar\Lurker\Resource\DirectoryResource;
/**
 * Recursive directory state checker.
 *
 * @author Konstantin Kudryashov <ever.zet@gmail.com>
 */
class DirectoryStateChecker extends NewDirectoryStateChecker
{
    /**
     * {@inheritdoc}
     */
    public function __construct(DirectoryResource $resource, $eventsMask = FilesystemEvent::ALL)
    {
        parent::__construct($resource, $eventsMask);
        foreach ($this->createDirectoryChildCheckers($resource) as $checker) {
            $this->childs[$checker->getResource()->getId()] = $checker;
        }
    }
}
<?php

namespace CivixPhar\Lurker\StateChecker;

use CivixPhar\Lurker\Resource\FileResource;
use CivixPhar\Lurker\Event\FilesystemEvent;
/**
 * File state checker.
 *
 * @author Konstantin Kudryashov <ever.zet@gmail.com>
 */
class FileStateChecker extends ResourceStateChecker
{
    /**
     * Initializes checker.
     *
     * @param FileResource $resource
     * @param integer      $eventsMask event types bitmask
     */
    public function __construct(FileResource $resource, $eventsMask = FilesystemEvent::ALL)
    {
        parent::__construct($resource, $eventsMask);
    }
}
<?php

namespace CivixPhar\Lurker\StateChecker;

use CivixPhar\Lurker\Resource\ResourceInterface;
/**
 * Resource state checker interface.
 *
 * @author Konstantin Kudryashov <ever.zet@gmail.com>
 */
interface StateCheckerInterface
{
    /**
     * Returns tracked resource.
     *
     * @return ResourceInterface
     */
    public function getResource();
    /**
     * Check tracked resource for changes.
     *
     * @return array
     */
    public function getChangeset();
}
<?php

namespace CivixPhar\Lurker\StateChecker\Inotify;

/**
 * Topmost directory state checker. Top directory - folder that was provided to InotifyTracker::track method.
 *
 * @author Yaroslav Kiliba <om.dattaya@gmail.com>
 */
class TopDirectoryStateChecker extends DirectoryStateChecker
{
    /**
     * {@inheritdoc}
     */
    protected function handleItself()
    {
        if ($this->getResource()->exists()) {
            if ($this->isMoved($this->event)) {
                if ($this->id !== ($id = $this->addWatch())) {
                    $this->unwatch($this->id);
                    $this->reindexChildCheckers();
                    if ($this->getBag()->has($id)) {
                        $this->unwatch($id);
                    }
                }
                return;
            }
            if ($this->isIgnored($this->event) || !$this->id) {
                $this->event = $this->id ? null : \IN_CREATE;
                $this->reindexChildCheckers();
            }
        } elseif ($this->id) {
            $this->event = \IN_DELETE;
            $this->unwatch($this->id);
        }
    }
}
<?php

namespace CivixPhar\Lurker\StateChecker\Inotify;

use CivixPhar\Lurker\Resource\DirectoryResource;
use CivixPhar\Lurker\Resource\FileResource;
use CivixPhar\Lurker\Event\FilesystemEvent;
/**
 * Directory state checker.
 *
 * @author Yaroslav Kiliba <om.dattaya@gmail.com>
 */
class DirectoryStateChecker extends ResourceStateChecker
{
    /**
     * @var DirectoryStateChecker[]
     */
    protected $directories = array();
    /**
     * @var FileResource[]
     */
    protected $files = array();
    /**
     * @var array File inotify events
     */
    protected $fileEvents = array();
    /**
     * @var array Dir inotify events
     */
    protected $dirEvents = array();
    /**
     * @var array It is used to track resource moving
     * @see DirectoryStateChecker::trackMoveEvent()
     */
    protected $movedResources = array();
    /**
     * @var string Key in the $movedResources array where to put name of the resource from next following move event.
     * @see DirectoryStateChecker::trackMoveEvent()
     */
    protected $lastMove;
    /**
     * @var bool
     */
    protected $isNew = \false;
    /**
     * Initializes checker.
     *
     * @param CheckerBag        $bag
     * @param DirectoryResource $resource
     * @param int               $eventsMask
     */
    public function __construct(CheckerBag $bag, DirectoryResource $resource, $eventsMask = FilesystemEvent::ALL)
    {
        parent::__construct($bag, $resource, $eventsMask);
        $this->createChildCheckers();
    }
    /**
     * {@inheritdoc}
     */
    public function setEvent($mask, $name = '')
    {
        if ($this->isDir($mask)) {
            if (0 !== (\IN_ATTRIB & $mask)) {
                return;
            }
            $this->dirEvents[$name] = $mask;
        } else {
            $this->fileEvents[$name] = $mask;
        }
        $this->trackMoveEvent($mask, $name);
    }
    /**
     * {@inheritdoc}
     */
    public function getChangeset()
    {
        $this->event = isset($this->fileEvents['']) ? $this->fileEvents[''] : null;
        unset($this->fileEvents['']);
        $this->handleItself();
        $changeset = array();
        if ($this->event) {
            if ($event = $this->fromInotifyMask($this->event)) {
                $changeset[] = array('resource' => $this->getResource(), 'event' => $event);
            }
            if ($this->isDeleted($this->event)) {
                $this->fileEvents = \array_fill_keys(\array_keys($this->files), \IN_DELETE);
                $this->dirEvents = \array_fill_keys(\array_keys($this->directories), \IN_DELETE);
                $this->getBag()->remove($this);
                $this->id = null;
            }
        }
        $deleted = array();
        foreach ($this->movedResources as $key => $value) {
            if ($key === $value) {
                unset($this->dirEvents[$key]);
                unset($this->fileEvents[$key]);
            }
        }
        foreach ($this->dirEvents as $name => $event) {
            $normalized = $this->normalizeEvent($event);
            if (isset($this->directories[$name])) {
                $this->directories[$name]->setEvent($normalized);
                if ($this->isDeleted($normalized)) {
                    $deleted[] = $this->directories[$name];
                    unset($this->directories[$name]);
                }
            } elseif (!$this->isDeleted($normalized)) {
                $this->createNewDirectoryChecker($name);
            }
        }
        foreach ($this->fileEvents as $name => $event) {
            $normalized = $this->normalizeFileEvent($event, $name);
            if (($event = $this->fromInotifyMask($normalized)) && $this->files[$name] instanceof FileResource) {
                $changeset[] = array('resource' => $this->files[$name], 'event' => $event);
            }
            if ($this->isDeleted($normalized)) {
                unset($this->files[$name]);
            }
        }
        $funct = function ($checker) use(&$changeset) {
            foreach ($checker->getChangeset() as $change) {
                $changeset[] = $change;
            }
        };
        \array_walk($this->directories, $funct);
        \array_walk($deleted, $funct);
        $this->dirEvents = $this->fileEvents = $this->movedResources = array();
        $this->event = null;
        return $changeset;
    }
    /**
     * Tracks move event. It is for situation when resource was roundtripped, e.g.
     * rename('dir', 'dir_new'); rename('dir_new', 'dir'). As a result no events should be returned.
     * This function just keeps track of the move events, and they're analyzed in the getChangeset method.
     *
     * @param int    $mask
     * @param string $name
     */
    protected function trackMoveEvent($mask, $name)
    {
        if ($this->isMovedFrom($mask)) {
            if ($key = \array_search($name, $this->movedResources)) {
                $this->lastMove = $key;
            } else {
                $this->lastMove = $name;
            }
        } elseif ($this->isMovedTo($mask)) {
            $this->movedResources[$this->lastMove] = $name;
        } elseif ($key = \array_search($name, $this->movedResources)) {
            unset($this->movedResources[$key]);
        }
    }
    /**
     * Handles event related to itself.
     */
    protected function handleItself()
    {
        if (!$this->isNew && $this->isCreated($this->event)) {
            $this->unwatch($this->id);
            $this->reindexChildCheckers();
            $this->event = null;
        }
        $this->isNew = \false;
    }
    /**
     * Reads files and subdirectories and transforms them to resources.
     */
    protected function createChildCheckers()
    {
        foreach ($this->getResource()->getFilteredResources() as $resource) {
            $resource instanceof DirectoryResource ? $this->directories[\basename((string) $resource)] = new DirectoryStateChecker($this->getBag(), $resource, $this->getEventsMask()) : ($this->files[\basename((string) $resource)] = $resource);
        }
    }
    /**
     * Used in case the folder was deleted and than created again or situations like this.
     * It rescans the folder, files that was before get IN_MODIFY event, folders - IN_CREATE - to make them to rescan itself
     */
    protected function reindexChildCheckers()
    {
        $this->fileEvents = \array_fill_keys(\array_keys($this->files), \IN_DELETE);
        $this->dirEvents = \array_fill_keys(\array_keys($this->directories), \IN_DELETE);
        foreach ($this->getResource()->getFilteredResources() as $resource) {
            $basename = \basename((string) $resource);
            if ($resource instanceof FileResource) {
                if (isset($this->files[$basename])) {
                    $this->fileEvents[$basename] = \IN_MODIFY;
                } else {
                    $this->files[$basename] = $resource;
                    $this->fileEvents[$basename] = 'new';
                }
            } else {
                isset($this->directories[$basename]) ? $this->dirEvents[$basename] = \IN_CREATE : $this->createNewDirectoryChecker($basename, $resource);
            }
        }
        $this->watch();
    }
    /**
     * Normalizes file event
     *
     * @param int    $event
     * @param string $name
     *
     * @return null|int
     */
    protected function normalizeFileEvent($event, $name)
    {
        if ('new' === $event) {
            return \IN_CREATE;
        }
        $event = $this->normalizeEvent($event);
        if (isset($this->files[$name])) {
            return $this->isCreated($event) ? \IN_MODIFY : $event;
        }
        if (!$this->isDeleted($event)) {
            $this->createFileResource($name);
            return \IN_CREATE;
        }
        return null;
    }
    /**
     * Normalizes event
     *
     * @param int $event
     *
     * @return int
     */
    protected function normalizeEvent($event)
    {
        $event &= ~\IN_ISDIR;
        if (0 !== ($event & \IN_MOVED_FROM)) {
            return \IN_DELETE;
        } elseif (0 !== ($event & \IN_MOVED_TO)) {
            return \IN_CREATE;
        }
        return $event;
    }
    /**
     * Creates new DirectoryStateChecker
     *
     * @param string                 $name
     * @param null|DirectoryResource $resource
     */
    protected function createNewDirectoryChecker($name, DirectoryResource $resource = null)
    {
        $resource = $resource ?: new DirectoryResource($this->getResource()->getResource() . '/' . $name);
        $this->directories[$name] = new NewDirectoryStateChecker($this->getBag(), $resource, $this->getEventsMask());
    }
    /**
     * Creates new FileResource
     *
     * @param string $name
     */
    protected function createFileResource($name)
    {
        if ($this->getResource()->getPattern() && !\preg_match($this->getResource()->getPattern(), $name)) {
            $this->files[$name] = 'skip';
        } else {
            $this->files[$name] = new FileResource($this->getResource()->getResource() . '/' . $name);
        }
    }
}
<?php

namespace CivixPhar\Lurker\StateChecker\Inotify;

use CivixPhar\Lurker\Resource\FileResource;
use CivixPhar\Lurker\Event\FilesystemEvent;
/**
 * File state checker.
 *
 * @author Yaroslav Kiliba <om.dattaya@gmail.com>
 */
class FileStateChecker extends ResourceStateChecker
{
    /**
     * Initializes checker.
     *
     * @param CheckerBag   $bag
     * @param FileResource $resource
     * @param int          $eventsMask
     */
    public function __construct(CheckerBag $bag, FileResource $resource, $eventsMask = FilesystemEvent::ALL)
    {
        parent::__construct($bag, $resource, $eventsMask);
    }
    /**
     * {@inheritdoc}
     */
    public function setEvent($mask, $name = '')
    {
        $this->event = $mask;
    }
    /**
     * {@inheritdoc}
     */
    public function getChangeset()
    {
        $changeset = array();
        $this->handleItself();
        if ($this->fromInotifyMask($this->event)) {
            $changeset[] = array('resource' => $this->getResource(), 'event' => $this->fromInotifyMask($this->event));
        }
        $this->setEvent(\false);
        return $changeset;
    }
    /**
     * Handles event related to itself.
     */
    protected function handleItself()
    {
        if ($this->isMoved($this->event)) {
            if ($this->getResource()->exists() && $this->addWatch() === $this->id) {
                return;
            }
            $this->unwatch($this->id);
        }
        if ($this->getResource()->exists()) {
            if ($this->isIgnored($this->event) || $this->isMoved($this->event) || !$this->id) {
                $this->setEvent($this->id ? \IN_MODIFY : \IN_CREATE);
                $this->watch();
            }
        } elseif ($this->id) {
            $this->event = \IN_DELETE;
            $this->getBag()->remove($this);
            $this->unwatch($this->id);
            $this->id = null;
        }
    }
}
<?php

namespace CivixPhar\Lurker\StateChecker\Inotify;

/**
 * Bag for the inotify resource state checkers.
 *
 * @author Yaroslav Kiliba <om.dattaya@gmail.com>
 */
class CheckerBag
{
    /**
     * @var \SplObjectStorage[]
     */
    protected $watched = array();
    /**
     * @var resource Inotify resource.
     */
    private $inotify;
    /**
     * Initializes bag.
     *
     * @param resource $inotify Inotify resource
     */
    public function __construct($inotify)
    {
        $this->inotify = $inotify;
    }
    /**
     * Adds state checker to the bag.
     *
     * @param ResourceStateChecker $watched
     */
    public function add(ResourceStateChecker $watched)
    {
        $id = $watched->getId();
        if (!isset($this->watched[$id])) {
            $this->watched[$id] = new \SplObjectStorage();
        }
        $this->watched[$id]->attach($watched);
    }
    /**
     * Returns state checker from the bag
     *
     * @param int $id Watch descriptor
     *
     * @return \SplObjectStorage|array
     */
    public function get($id)
    {
        return isset($this->watched[$id]) ? $this->watched[$id] : array();
    }
    /**
     * Checks whether at least one state checker with id $id exists.
     *
     * @param int $id Watch descriptor
     *
     * @return bool
     */
    public function has($id)
    {
        return isset($this->watched[$id]) && 0 !== $this->watched[$id]->count();
    }
    /**
     * @return resource Inotify resource
     */
    public function getInotify()
    {
        return $this->inotify;
    }
    /**
     * Removes state checker from the bag
     *
     * @param ResourceStateChecker $watched
     */
    public function remove(ResourceStateChecker $watched)
    {
        $this->watched[$watched->getId()]->detach($watched);
    }
}
<?php

namespace CivixPhar\Lurker\StateChecker\Inotify;

use CivixPhar\Lurker\Event\FilesystemEvent;
use CivixPhar\Lurker\Resource\ResourceInterface;
use CivixPhar\Lurker\StateChecker\StateCheckerInterface;
/**
 * Abstract resource state checker.
 *
 * @author Yaroslav Kiliba <om.dattaya@gmail.com>
 */
abstract class ResourceStateChecker implements StateCheckerInterface
{
    /**
     * @var int Watch descriptor
     */
    protected $id;
    /**
     * @var int Inotify event
     */
    protected $event;
    /**
     * @var CheckerBag
     */
    private $bag;
    /**
     * @var int
     */
    private $eventsMask;
    /**
     * @var ResourceInterface
     */
    private $resource;
    /**
     * Initializes checker.
     *
     * @param CheckerBag        $bag
     * @param ResourceInterface $resource
     * @param int               $eventsMask
     */
    public function __construct(CheckerBag $bag, ResourceInterface $resource, $eventsMask = FilesystemEvent::ALL)
    {
        $this->resource = $resource;
        $this->eventsMask = $eventsMask;
        $this->bag = $bag;
        $this->watch();
    }
    /**
     * Returns tracked resource.
     *
     * @return ResourceInterface
     */
    public function getResource()
    {
        return $this->resource;
    }
    /**
     * Returns watch descriptor
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }
    /**
     * Allows to set event for resource itself or for child resources.
     *
     * @param int    $mask
     * @param string $name
     */
    public abstract function setEvent($mask, $name = '');
    /**
     * Returns events mask for checker.
     *
     * @return int
     */
    protected function getEventsMask()
    {
        return $this->eventsMask;
    }
    /**
     * @return CheckerBag
     */
    protected function getBag()
    {
        return $this->bag;
    }
    /**
     * Starts to track current resource
     */
    protected function watch()
    {
        if ($this->id) {
            $this->bag->remove($this);
        }
        $this->id = $this->addWatch();
        $this->bag->add($this);
    }
    /**
     * Watch resource
     *
     * @return int
     */
    protected function addWatch()
    {
        return \inotify_add_watch($this->getBag()->getInotify(), $this->getResource()->getResource(), $this->getInotifyEventMask());
    }
    /**
     * Unwatch resource
     *
     * @param int $id Watch descriptor
     */
    protected function unwatch($id)
    {
        @\inotify_rm_watch($this->bag->getInotify(), $id);
    }
    /**
     * Transforms inotify event to FilesystemEvent event
     *
     * @param int $mask
     *
     * @return bool|int Returns event only if the checker supports it.
     */
    protected function fromInotifyMask($mask)
    {
        $mask &= ~\IN_ISDIR;
        $event = 0;
        switch ($mask) {
            case \IN_MODIFY:
            case \IN_ATTRIB:
                $event = FilesystemEvent::MODIFY;
                break;
            case \IN_CREATE:
                $event = FilesystemEvent::CREATE;
                break;
            case \IN_DELETE:
            case \IN_IGNORED:
                $event = FilesystemEvent::DELETE;
        }
        return $this->supportsEvent($event) ? $event : \false;
    }
    /**
     * Checks whether checker supports provided resource event.
     *
     * @param int $event
     *
     * @return bool
     */
    protected function supportsEvent($event)
    {
        return 0 !== ($this->eventsMask & $event);
    }
    /**
     * Inotify event mask for inotify_add_watch
     *
     * @return int
     */
    protected function getInotifyEventMask()
    {
        return \IN_MODIFY | \IN_ATTRIB | \IN_DELETE | \IN_CREATE | \IN_MOVE | \IN_MOVE_SELF;
    }
    /**
     * Returns true if it is a directory mask
     *
     * @param int $mask
     *
     * @return bool
     */
    protected function isDir($mask)
    {
        return 0 !== ($mask & \IN_ISDIR);
    }
    /**
     * Returns true if it is a mask with a IN_DELETE bit active
     *
     * @param int $mask
     *
     * @return bool
     */
    protected function isDeleted($mask)
    {
        return 0 !== ($mask & \IN_DELETE);
    }
    /**
     * Returns true if it is a IN_IGNORED mask
     *
     * @param int $mask
     *
     * @return bool
     */
    protected function isIgnored($mask)
    {
        return \IN_IGNORED === $mask;
    }
    /**
     * Returns true if it is a IN_MOVE_SELF mask
     *
     * @param int $mask
     *
     * @return bool
     */
    protected function isMoved($mask)
    {
        return \IN_MOVE_SELF === $mask;
    }
    /**
     * Returns true if it is a mask with a IN_CREATE bit active
     *
     * @param int $mask
     *
     * @return bool
     */
    protected function isCreated($mask)
    {
        return 0 !== ($mask & \IN_CREATE);
    }
    /**
     * Returns true if it is a mask with a IN_MOVED_FROM bit active
     *
     * @param int $mask
     *
     * @return bool
     */
    protected function isMovedFrom($mask)
    {
        return 0 !== ($mask & \IN_MOVED_FROM);
    }
    /**
     * Returns true if it is a mask with a IN_MOVED_TO bit active
     *
     * @param int $mask
     *
     * @return bool
     */
    protected function isMovedTo($mask)
    {
        return 0 !== ($mask & \IN_MOVED_TO);
    }
}
<?php

namespace CivixPhar\Lurker\StateChecker\Inotify;

use CivixPhar\Lurker\Resource\DirectoryResource;
use CivixPhar\Lurker\Event\FilesystemEvent;
/**
 * Directory state checker. Sets for itself and children a flag that indicates newness.
 *
 * @author Yaroslav Kiliba <om.dattaya@gmail.com>
 */
class NewDirectoryStateChecker extends DirectoryStateChecker
{
    /**
     * @var bool|null
     */
    protected $isNew = \true;
    /**
     * Initializes checker.
     *
     * @param CheckerBag        $bag
     * @param DirectoryResource $resource
     * @param int               $eventsMask
     */
    public function __construct(CheckerBag $bag, DirectoryResource $resource, $eventsMask = FilesystemEvent::ALL)
    {
        $this->setEvent(\IN_CREATE);
        parent::__construct($bag, $resource, $eventsMask);
    }
    /**
     * {@inheritdoc}
     */
    protected function createChildCheckers()
    {
        foreach ($this->getResource()->getFilteredResources() as $resource) {
            $basename = \basename((string) $resource);
            if ($resource instanceof DirectoryResource) {
                $this->createNewDirectoryChecker($basename, $resource);
            } else {
                $this->files[$basename] = $resource;
                $this->fileEvents[$basename] = 'new';
            }
        }
    }
}
<?php

namespace CivixPhar\Lurker\StateChecker;

use CivixPhar\Lurker\Event\FilesystemEvent;
use CivixPhar\Lurker\Resource\ResourceInterface;
/**
 * Abstract resource state checker class.
 *
 * @author Konstantin Kudryashov <ever.zet@gmail.com>
 */
abstract class ResourceStateChecker implements StateCheckerInterface
{
    private $resource;
    private $timestamp;
    private $eventsMask;
    private $deleted = \false;
    /**
     * Initializes checker.
     *
     * @param ResourceInterface $resource   resource
     * @param integer           $eventsMask event types bitmask
     */
    public function __construct(ResourceInterface $resource, $eventsMask = FilesystemEvent::ALL)
    {
        $this->resource = $resource;
        $this->timestamp = $resource->getModificationTime() + 1;
        $this->eventsMask = $eventsMask;
        $this->deleted = !$resource->exists();
    }
    /**
     * {@inheritdoc}
     */
    public function getResource()
    {
        return $this->resource;
    }
    /**
     * Returns events mask for checker.
     *
     * @return integer
     */
    public function getEventsMask()
    {
        return $this->eventsMask;
    }
    /**
     * {@inheritdoc}
     */
    public function getChangeset()
    {
        $changeset = array();
        if ($this->deleted) {
            if ($this->resource->exists()) {
                $this->timestamp = $this->resource->getModificationTime() + 1;
                $this->deleted = \false;
                if ($this->supportsEvent($event = FilesystemEvent::CREATE)) {
                    $changeset[] = array('event' => $event, 'resource' => $this->resource);
                }
            }
        } elseif (!$this->resource->exists()) {
            $this->deleted = \true;
            if ($this->supportsEvent($event = FilesystemEvent::DELETE)) {
                $changeset[] = array('event' => $event, 'resource' => $this->resource);
            }
        } elseif (!$this->resource->isFresh($this->timestamp)) {
            $this->timestamp = $this->resource->getModificationTime() + 1;
            if ($this->supportsEvent($event = FilesystemEvent::MODIFY)) {
                $changeset[] = array('event' => $event, 'resource' => $this->resource);
            }
        }
        return $changeset;
    }
    /**
     * Checks whether checker supports provided resource event.
     *
     * @param integer $event
     *
     * @return Boolean
     */
    protected function supportsEvent($event)
    {
        return 0 !== ($this->eventsMask & $event);
    }
    /**
     * Checks whether resource have been previously deleted.
     *
     * @return Boolean
     */
    protected function isDeleted()
    {
        return $this->deleted;
    }
}
<?php

namespace CivixPhar\Lurker\StateChecker;

use CivixPhar\Lurker\Event\FilesystemEvent;
use CivixPhar\Lurker\Resource\DirectoryResource;
/**
 * Recursive directory state checker.
 *
 * @author Konstantin Kudryashov <ever.zet@gmail.com>
 */
class NewDirectoryStateChecker extends ResourceStateChecker
{
    protected $childs = array();
    /**
     * Initializes checker.
     *
     * @param DirectoryResource $resource
     * @param integer           $eventsMask event types bitmask
     */
    public function __construct(DirectoryResource $resource, $eventsMask = FilesystemEvent::ALL)
    {
        parent::__construct($resource, $eventsMask);
    }
    /**
     * {@inheritdoc}
     */
    public function getChangeset()
    {
        $changeset = parent::getChangeset();
        // remove directory modification from changeset
        if (isset($changeset[0]) && FilesystemEvent::MODIFY === $changeset[0]['event']) {
            $changeset = array();
        }
        // check for changes in already added subfolders/files
        foreach ($this->childs as $id => $checker) {
            foreach ($checker->getChangeset() as $change) {
                if ($this->supportsEvent($change['event'])) {
                    $changeset[] = $change;
                }
            }
            // remove checkers for removed resources
            if (!$checker->getResource()->exists()) {
                unset($this->childs[$id]);
            }
        }
        // check for new subfolders/files
        if ($this->getResource()->exists()) {
            foreach ($this->createNewDirectoryChildCheckers($this->getResource()) as $checker) {
                $resource = $checker->getResource();
                $resourceId = $resource->getId();
                if (!isset($this->childs[$resourceId])) {
                    $this->childs[$resourceId] = $checker;
                    if ($this->supportsEvent($event = FilesystemEvent::CREATE)) {
                        $changeset[] = array('event' => $event, 'resource' => $resource);
                    }
                    // check for new directory changes
                    if ($checker instanceof NewDirectoryStateChecker) {
                        foreach ($checker->getChangeset() as $change) {
                            if ($this->supportsEvent($change['event'])) {
                                $changeset[] = $change;
                            }
                        }
                    }
                }
            }
        }
        return $changeset;
    }
    /**
     * Reads files and subdirectories on provided resource path and transform them to resources.
     *
     * @param DirectoryResource $resource
     *
     * @return array
     */
    protected function createDirectoryChildCheckers(DirectoryResource $resource)
    {
        $checkers = array();
        foreach ($resource->getFilteredResources() as $resource) {
            if ($resource instanceof DirectoryResource) {
                $checkers[] = new DirectoryStateChecker($resource, $this->getEventsMask());
            } else {
                $checkers[] = new FileStateChecker($resource, $this->getEventsMask());
            }
        }
        return $checkers;
    }
    /**
     * Reads files and subdirectories on provided resource path and transform them to resources.
     *
     * @param DirectoryResource $resource
     *
     * @return array
     */
    protected function createNewDirectoryChildCheckers(DirectoryResource $resource)
    {
        $checkers = array();
        foreach ($resource->getFilteredResources() as $resource) {
            if ($resource instanceof DirectoryResource) {
                $checkers[] = new NewDirectoryStateChecker($resource, $this->getEventsMask());
            } else {
                $checkers[] = new FileStateChecker($resource, $this->getEventsMask());
            }
        }
        return $checkers;
    }
}
<?php

namespace CivixPhar\Lurker\Exception;

use InvalidArgumentException as BaseInvalidArgumentException;
/**
 * InvalidArgumentException
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class InvalidArgumentException extends BaseInvalidArgumentException implements ExceptionInterface
{
}
<?php

namespace CivixPhar\Lurker\Exception;

use RuntimeException as BaseRuntimeException;
/**
 * RuntimeException
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class RuntimeException extends BaseRuntimeException implements ExceptionInterface
{
}
<?php

namespace CivixPhar\Lurker\Exception;

/**
 * Exception interface for all exceptions thrown by the component.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
interface ExceptionInterface
{
}
<?php

namespace CivixPhar\Lurker\EventDispatcher;

/**
 * Interface EventDispatcherInterface
 * @package Lurker
 *
 * This is a strict subset of Symfony 2/3 "EventDispatcherInterface".
 */
interface EventDispatcherInterface
{
    public function dispatch($eventName, $event = null);
    public function addListener($eventName, $listener);
}
<?php

namespace CivixPhar\Lurker\EventDispatcher;

/**
 * Class EventDispatcher
 * @package Lurker
 *
 * This EventDispatcher supports a strict subset of the contract in
 * Symfony (v2/3) EventDispatcher.
 */
class EventDispatcher implements EventDispatcherInterface
{
    /**
     * @var array
     *
     * $listeners['event-name'][$int] = $callable;
     */
    protected $listeners = [];
    public function addListener($eventName, $listener)
    {
        $this->listeners[$eventName][] = $listener;
    }
    public function dispatch($eventName, $event = null)
    {
        $listeners = isset($this->listeners[$eventName]) ? $this->listeners[$eventName] : [];
        foreach ($listeners as $listener) {
            \call_user_func($listener, $event, $eventName, $this);
        }
    }
}
<?php

namespace CivixPhar\ProcessHelper;

class ProcessErrorException extends \RuntimeException
{
    /**
     * @var \Symfony\Component\Process\Process
     */
    private $process;
    public function __construct(\CivixPhar\Symfony\Component\Process\Process $process, $message = "", $code = 0, Exception $previous = NULL)
    {
        $this->process = $process;
        if (empty($message)) {
            $message = $this->createReport($process);
        }
        parent::__construct($message, $code, $previous);
    }
    /**
     * @param \Symfony\Component\Process\Process $process
     */
    public function setProcess($process)
    {
        $this->process = $process;
    }
    /**
     * @return \Symfony\Component\Process\Process
     */
    public function getProcess()
    {
        return $this->process;
    }
    public function createReport($process)
    {
        return "Process failed:\n" . ProcessHelper::createReport($process);
    }
}
<?php

namespace CivixPhar\ProcessHelper;

use CivixPhar\Symfony\Component\Process\Process;
class ProcessHelper
{
    /**
     * Run a command synchronously.
     *
     * @param \Symfony\Component\Process\Process|string|array $process
     *   Ex: 'echo "Hello world"'
     *   Ex: ['echo @MSG', 'MSG' => 'Hello world']
     * @return \Symfony\Component\Process\Process
     * @throws \RuntimeException
     * @see interpolate
     */
    public static function run($process)
    {
        $process = self::castToProcess($process);
        if (\getenv('DEBUG') > 0) {
            \printf("RUN: %s\n    (in %s)\n", $process->getCommandLine(), $process->getWorkingDirectory());
            // ob_flush();
        }
        $process->run(function ($type, $buffer) {
            if (\getenv('DEBUG') > 1) {
                if (\CivixPhar\Symfony\Component\Process\Process::ERR === $type) {
                    echo 'STDERR > ' . $buffer;
                } else {
                    echo 'STDOUT > ' . $buffer;
                }
                // ob_flush();
            }
        });
        return $process;
    }
    /**
     * Run a command synchronously. Assert successful execution.
     *
     * @param \Symfony\Component\Process\Process|string|array $process
     *   Ex: 'echo "Hello world"'
     *   Ex: ['echo @MSG', 'MSG' => 'Hello world']
     * @return \Symfony\Component\Process\Process
     * @throws \RuntimeException
     * @see self::interpolate()
     */
    public static function runOk($process)
    {
        $process = self::castToProcess($process);
        self::run($process);
        if (!$process->isSuccessful()) {
            throw new ProcessErrorException($process);
        }
        return $process;
    }
    /**
     * Print information about a command to screen.
     *
     * @param \Symfony\Component\Process\Process|string|array $process
     */
    public static function dump($process)
    {
        $process = self::castToProcess($process);
        echo self::createReport($process);
    }
    /**
     * Format a detailed summary about the process.
     *
     * @param \Symfony\Component\Process\Process|string|array $process
     * @return string
     */
    public static function createReport($process)
    {
        $process = self::castToProcess($process);
        return "[[ COMMAND: {$process->getCommandLine()} ]]\n[[ CWD: {$process->getWorkingDirectory()} ]]\n[[ EXIT CODE: {$process->getExitCode()} ]]\n[[ STDOUT ]]\n{$process->getOutput()}\n[[ STDERR ]]\n{$process->getErrorOutput()}\n\n";
    }
    /**
     * Evaluate a string, replacing variables with shell-escaped values.
     *
     * @param string $expr
     *   Ex: "ls @DIR | head -n #CNT !FINALE"
     *   Note: "@" indicates a value should be shell-escaped
     *   Note: "#" indicates a value should be numeric
     *   Note: "!" indicates a value should NOT be escaped or validated
     * @param array $args
     *   Ex: ['DIR' => '/home/foo/My Special Data', 'CNT' => 5, 'FINALE' => '>/dev/null']
     */
    public static function interpolate($expr, $args)
    {
        if ($args === NULL) {
            return $expr;
        } else {
            return \preg_replace_callback('/([#!@])([a-zA-Z0-9_]+)/', function ($m) use($args) {
                if (isset($args[$m[2]])) {
                    $values = $args[$m[2]];
                } else {
                    // Unrecognized variables are ignored. Mitigate risk of accidents.
                    return $m[0];
                }
                $values = \is_array($values) ? $values : array($values);
                switch ($m[1]) {
                    case '@':
                        return \implode(', ', \array_map('escapeshellarg', $values));
                    case '!':
                        return \implode(', ', $values);
                    case '#':
                        foreach ($values as $valueKey => $value) {
                            if ($value === NULL) {
                                $values[$valueKey] = 'NULL';
                            } elseif (!\is_numeric($value)) {
                                //throw new API_Exception("Failed encoding non-numeric value" . var_export(array($m[0] => $values), TRUE));
                                throw new \RuntimeException("Failed encoding non-numeric value (" . $m[0] . ")");
                            }
                        }
                        return \implode(', ', $values);
                    default:
                        throw new \RuntimeException("Unrecognized prefix");
                }
            }, $expr);
        }
    }
    /**
     * Convert from various formats to a Process object.
     *
     * @param string|array|Process $process
     * @return \Symfony\Component\Process\Process
     */
    public static function castToProcess($process)
    {
        if ($process instanceof Process) {
            return $process;
        }
        if (\is_string($process)) {
            return new Process($process, NULL, NULL, NULL, NULL);
        }
        if (\is_array($process)) {
            $cmd = $process[0];
            unset($process[0]);
            return new Process(self::interpolate($cmd, $process), NULL, NULL, NULL, NULL);
        }
        throw new \RuntimeException("Cannot cast item to process");
    }
}
<?php

/**
 * "license-data package"
 * Copyright (c) 2013, Tim Otten
 * License: BSD-2-Clause
 */
namespace CivixPhar\LicenseData;

class License
{
    private $name;
    private $title;
    private $txtPath;
    private $url;
    public function __construct($name, $title, $txtPath, $url = NULL)
    {
        $this->name = $name;
        $this->title = $title;
        $this->txtPath = $txtPath;
        $this->url = $url;
    }
    /**
     * @return string a code name (eg "GPL-2.0+")
     */
    function getName()
    {
        return $this->name;
    }
    /**
     * @return string descriptive title
     */
    function getTitle()
    {
        return $this->title;
    }
    /**
     * @return string the full license text
     */
    function getText()
    {
        return \file_get_contents($this->txtPath);
    }
    /**
     * @return string public web URL for the license
     */
    function getUrl()
    {
        return $this->url;
    }
}
<?php

/**
 * "license-data package"
 * Copyright (c) 2013, Tim Otten
 * License: BSD-2-Clause
 */
namespace CivixPhar\LicenseData;

class Repository
{
    private $basedir;
    private $index;
    /**
     * @param string $basedir The source tree for the dataset
     */
    public function __construct($basedir = NULL)
    {
        if ($basedir === NULL) {
            $basedir = \dirname(\dirname(__DIR__));
        }
        $this->basedir = $basedir;
        $this->flush();
    }
    /**
     * Reset any cached data
     *
     * @void
     */
    public function flush()
    {
        $this->index = NULL;
    }
    /**
     * @return string path to the index file
     */
    public function getIndexFile()
    {
        return $this->basedir . \DIRECTORY_SEPARATOR . 'index.csv';
    }
    /**
     * Read the index file
     *
     * @param string $file path to the index file
     * @void
     */
    protected function load($file)
    {
        $this->index = array();
        if ($fh = \fopen($file, 'r')) {
            while ($row = \fgetcsv($fh)) {
                $this->index[$row[0]] = new License($row[0], $row[1], $this->basedir . \DIRECTORY_SEPARATOR . $row[2], $row[3]);
            }
            \fclose($fh);
        } else {
            throw new Exception("Failed to open index.csv");
        }
    }
    /**
     * @return array of License
     */
    public function getAll()
    {
        if ($this->index === NULL) {
            $this->load($this->getIndexFile());
        }
        return $this->index;
    }
    /**
     * @param string $name a code name (eg "GPL-2.0+")
     * @return License|NULL
     */
    public function get($name)
    {
        $all = $this->getAll();
        return isset($all[$name]) ? $all[$name] : NULL;
    }
}
AGPL-3.0,GNU Affero General Public License v3.0,licenses/AGPL-3.0.txt,http://www.gnu.org/licenses/agpl-3.0.html
Apache-2.0,Apache License 2.0,licenses/Apache-2.0.txt,http://www.apache.org/licenses/LICENSE-2.0.html
BSD-2-Clause,BSD 2-clause "Simplified" License,licenses/BSD-2-Clause.txt,http://opensource.org/licenses/BSD-2-Clause
GPL-2.0,GNU General Public License v2.0 only,licenses/GPL-2.0.txt,http://www.gnu.org/licenses/gpl-2.0.html
GPL-2.0+,GNU General Public License v2.0 or later,licenses/GPL-2.0+.txt,http://www.gnu.org/licenses/gpl-2.0.html
GPL-3.0,GNU General Public License v3.0 only,licenses/GPL-3.0.txt,http://www.gnu.org/licenses/gpl-3.0.html
GPL-3.0+,GNU General Public License v3.0 or later,licenses/GPL-3.0+.txt,http://www.gnu.org/licenses/gpl-3.0.html
LGPL-2.1,GNU Lesser General Public License v2.1 only,licenses/LGPL-2.1.txt,http://www.gnu.org/licenses/lgpl-2.1.html
LGPL-2.1+,GNU Lesser General Public License v2.1 or later,licenses/LGPL-2.1+.txt,http://www.gnu.org/licenses/lgpl-2.1.html
LGPL-3.0,GNU Lesser General Public License v3.0 only,licenses/LGPL-3.0.txt,http://www.gnu.org/licenses/lgpl-3.0.html
LGPL-3.0+,GNU Lesser General Public License v3.0 or later,licenses/LGPL-3.0+.txt,http://www.gnu.org/licenses/lgpl-3.0.html
MIT,MIT License,licenses/MIT.txt,http://opensource.org/licenses/MIT
WTFPL,WTF Public License,licenses/WTFPL.txt,http://www.wtfpl.net/about/
<TITLE>
Copyright (C) <YEAR>, <OWNER>
Licensed under GNU Lesser General Public License v3.0 only (below).

-------------------------------------------------------------------------------

                   GNU LESSER GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.


  This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.

  0. Additional Definitions.

  As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.

  "The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.

  An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.

  A "Combined Work" is a work produced by combining or linking an
Application with the Library.  The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".

  The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.

  The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.

  1. Exception to Section 3 of the GNU GPL.

  You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.

  2. Conveying Modified Versions.

  If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:

   a) under this License, provided that you make a good faith effort to
   ensure that, in the event an Application does not supply the
   function or data, the facility still operates, and performs
   whatever part of its purpose remains meaningful, or

   b) under the GNU GPL, with none of the additional permissions of
   this License applicable to that copy.

  3. Object Code Incorporating Material from Library Header Files.

  The object code form of an Application may incorporate material from
a header file that is part of the Library.  You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:

   a) Give prominent notice with each copy of the object code that the
   Library is used in it and that the Library and its use are
   covered by this License.

   b) Accompany the object code with a copy of the GNU GPL and this license
   document.

  4. Combined Works.

  You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:

   a) Give prominent notice with each copy of the Combined Work that
   the Library is used in it and that the Library and its use are
   covered by this License.

   b) Accompany the Combined Work with a copy of the GNU GPL and this license
   document.

   c) For a Combined Work that displays copyright notices during
   execution, include the copyright notice for the Library among
   these notices, as well as a reference directing the user to the
   copies of the GNU GPL and this license document.

   d) Do one of the following:

       0) Convey the Minimal Corresponding Source under the terms of this
       License, and the Corresponding Application Code in a form
       suitable for, and under terms that permit, the user to
       recombine or relink the Application with a modified version of
       the Linked Version to produce a modified Combined Work, in the
       manner specified by section 6 of the GNU GPL for conveying
       Corresponding Source.

       1) Use a suitable shared library mechanism for linking with the
       Library.  A suitable mechanism is one that (a) uses at run time
       a copy of the Library already present on the user's computer
       system, and (b) will operate properly with a modified version
       of the Library that is interface-compatible with the Linked
       Version.

   e) Provide Installation Information, but only if you would otherwise
   be required to provide such information under section 6 of the
   GNU GPL, and only to the extent that such information is
   necessary to install and execute a modified version of the
   Combined Work produced by recombining or relinking the
   Application with a modified version of the Linked Version. (If
   you use option 4d0, the Installation Information must accompany
   the Minimal Corresponding Source and Corresponding Application
   Code. If you use option 4d1, you must provide the Installation
   Information in the manner specified by section 6 of the GNU GPL
   for conveying Corresponding Source.)

  5. Combined Libraries.

  You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:

   a) Accompany the combined library with a copy of the same work based
   on the Library, uncombined with any other library facilities,
   conveyed under the terms of this License.

   b) Give prominent notice with the combined library that part of it
   is a work based on the Library, and explaining where to find the
   accompanying uncombined form of the same work.

  6. Revised Versions of the GNU Lesser General Public License.

  The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.

  Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.

  If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
<TITLE>
Copyright (c) <YEAR>, <OWNER>
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1) Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

2) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
<TITLE>
Copyright (C) <YEAR>, <OWNER>
Licensed under GNU Lesser General Public License v2.1 or later (below).

-------------------------------------------------------------------------------

                  GNU LESSER GENERAL PUBLIC LICENSE
                       Version 2.1, February 1999

 Copyright (C) 1991, 1999 Free Software Foundation, Inc.
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

[This is the first released version of the Lesser GPL.  It also counts
 as the successor of the GNU Library Public License, version 2, hence
 the version number 2.1.]

                            Preamble

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.

  This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it.  You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.

  When we speak of free software, we are referring to freedom of use,
not price.  Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.

  To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights.  These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.

  For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you.  You must make sure that they, too, receive or can get the source
code.  If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it.  And you must show them these terms so they know their rights.

  We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.

  To protect each distributor, we want to make it very clear that
there is no warranty for the free library.  Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.

  Finally, software patents pose a constant threat to the existence of
any free program.  We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder.  Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.

  Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License.  This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License.  We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.

  When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library.  The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom.  The Lesser General
Public License permits more lax criteria for linking other code with
the library.

  We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License.  It also provides other free software developers Less
of an advantage over competing non-free programs.  These disadvantages
are the reason we use the ordinary General Public License for many
libraries.  However, the Lesser license provides advantages in certain
special circumstances.

  For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard.  To achieve this, non-free programs must be
allowed to use the library.  A more frequent case is that a free
library does the same job as widely used non-free libraries.  In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.

  In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software.  For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.

  Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.

  The precise terms and conditions for copying, distribution and
modification follow.  Pay close attention to the difference between a
"work based on the library" and a "work that uses the library".  The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.

                  GNU LESSER GENERAL PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".

  A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.

  The "Library", below, refers to any such software library or work
which has been distributed under these terms.  A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language.  (Hereinafter, translation is
included without limitation in the term "modification".)

  "Source code" for a work means the preferred form of the work for
making modifications to it.  For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.

  Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it).  Whether that is true depends on what the Library does
and what the program that uses the Library does.

  1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.

  You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.

  2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

    a) The modified work must itself be a software library.

    b) You must cause the files modified to carry prominent notices
    stating that you changed the files and the date of any change.

    c) You must cause the whole of the work to be licensed at no
    charge to all third parties under the terms of this License.

    d) If a facility in the modified Library refers to a function or a
    table of data to be supplied by an application program that uses
    the facility, other than as an argument passed when the facility
    is invoked, then you must make a good faith effort to ensure that,
    in the event an application does not supply such function or
    table, the facility still operates, and performs whatever part of
    its purpose remains meaningful.

    (For example, a function in a library to compute square roots has
    a purpose that is entirely well-defined independent of the
    application.  Therefore, Subsection 2d requires that any
    application-supplied function or table used by this function must
    be optional: if the application does not supply it, the square
    root function must still compute square roots.)

These requirements apply to the modified work as a whole.  If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works.  But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.

In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

  3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library.  To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License.  (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.)  Do not make any other change in
these notices.

  Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.

  This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.

  4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.

  If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.

  5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library".  Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.

  However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library".  The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.

  When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library.  The
threshold for this to be true is not precisely defined by law.

  If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work.  (Executables containing this object code plus portions of the
Library will still fall under Section 6.)

  Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.

  6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.

  You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License.  You must supply a copy of this License.  If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License.  Also, you must do one
of these things:

    a) Accompany the work with the complete corresponding
    machine-readable source code for the Library including whatever
    changes were used in the work (which must be distributed under
    Sections 1 and 2 above); and, if the work is an executable linked
    with the Library, with the complete machine-readable "work that
    uses the Library", as object code and/or source code, so that the
    user can modify the Library and then relink to produce a modified
    executable containing the modified Library.  (It is understood
    that the user who changes the contents of definitions files in the
    Library will not necessarily be able to recompile the application
    to use the modified definitions.)

    b) Use a suitable shared library mechanism for linking with the
    Library.  A suitable mechanism is one that (1) uses at run time a
    copy of the library already present on the user's computer system,
    rather than copying library functions into the executable, and (2)
    will operate properly with a modified version of the library, if
    the user installs one, as long as the modified version is
    interface-compatible with the version that the work was made with.

    c) Accompany the work with a written offer, valid for at
    least three years, to give the same user the materials
    specified in Subsection 6a, above, for a charge no more
    than the cost of performing this distribution.

    d) If distribution of the work is made by offering access to copy
    from a designated place, offer equivalent access to copy the above
    specified materials from the same place.

    e) Verify that the user has already received a copy of these
    materials or that you have already sent this user a copy.

  For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it.  However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.

  It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system.  Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.

  7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:

    a) Accompany the combined library with a copy of the same work
    based on the Library, uncombined with any other library
    facilities.  This must be distributed under the terms of the
    Sections above.

    b) Give prominent notice with the combined library of the fact
    that part of it is a work based on the Library, and explaining
    where to find the accompanying uncombined form of the same work.

  8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License.  Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License.  However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.

  9. You are not required to accept this License, since you have not
signed it.  However, nothing else grants you permission to modify or
distribute the Library or its derivative works.  These actions are
prohibited by law if you do not accept this License.  Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.

  10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions.  You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.

  11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all.  For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.

If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices.  Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.

  12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded.  In such case, this License incorporates the limitation as if
written in the body of this License.

  13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.

Each version is given a distinguishing version number.  If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation.  If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.

  14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission.  For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this.  Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.

                            NO WARRANTY

  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.

                     END OF TERMS AND CONDITIONS

           How to Apply These Terms to Your New Libraries

  If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change.  You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).

  To apply these terms, attach the following notices to the library.  It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.

    <one line to give the library's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

Also add information on how to contact you by electronic and paper mail.

You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary.  Here is a sample; alter the names:

  Yoyodyne, Inc., hereby disclaims all copyright interest in the
  library `Frob' (a library for tweaking knobs) written by James Random Hacker.

  <signature of Ty Coon>, 1 April 1990
  Ty Coon, President of Vice

That's all there is to it!
<TITLE>
Copyright (C) <YEAR>, <OWNER>
Licensed under GNU General Public License v2.0 only (below).

-------------------------------------------------------------------------------

                    GNU GENERAL PUBLIC LICENSE
                       Version 2, June 1991

 Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users.  This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it.  (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.)  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.

  To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have.  You must make sure that they, too, receive or can get the
source code.  And you must show them these terms so they know their
rights.

  We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.

  Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software.  If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.

  Finally, any free program is threatened constantly by software
patents.  We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary.  To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.

  The precise terms and conditions for copying, distribution and
modification follow.

                    GNU GENERAL PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License.  The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language.  (Hereinafter, translation is included without limitation in
the term "modification".)  Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.

  1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.

You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.

  2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

    a) You must cause the modified files to carry prominent notices
    stating that you changed the files and the date of any change.

    b) You must cause any work that you distribute or publish, that in
    whole or in part contains or is derived from the Program or any
    part thereof, to be licensed as a whole at no charge to all third
    parties under the terms of this License.

    c) If the modified program normally reads commands interactively
    when run, you must cause it, when started running for such
    interactive use in the most ordinary way, to print or display an
    announcement including an appropriate copyright notice and a
    notice that there is no warranty (or else, saying that you provide
    a warranty) and that users may redistribute the program under
    these conditions, and telling the user how to view a copy of this
    License.  (Exception: if the Program itself is interactive but
    does not normally print such an announcement, your work based on
    the Program is not required to print an announcement.)

These requirements apply to the modified work as a whole.  If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works.  But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.

In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

  3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:

    a) Accompany it with the complete corresponding machine-readable
    source code, which must be distributed under the terms of Sections
    1 and 2 above on a medium customarily used for software interchange; or,

    b) Accompany it with a written offer, valid for at least three
    years, to give any third party, for a charge no more than your
    cost of physically performing source distribution, a complete
    machine-readable copy of the corresponding source code, to be
    distributed under the terms of Sections 1 and 2 above on a medium
    customarily used for software interchange; or,

    c) Accompany it with the information you received as to the offer
    to distribute corresponding source code.  (This alternative is
    allowed only for noncommercial distribution and only if you
    received the program in object code or executable form with such
    an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for
making modifications to it.  For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable.  However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.

If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.

  4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License.  Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.

  5. You are not required to accept this License, since you have not
signed it.  However, nothing else grants you permission to modify or
distribute the Program or its derivative works.  These actions are
prohibited by law if you do not accept this License.  Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.

  6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions.  You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.

  7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all.  For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices.  Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.

  8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded.  In such case, this License incorporates
the limitation as if written in the body of this License.

  9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

Each version is given a distinguishing version number.  If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation.  If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.

  10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission.  For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this.  Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.

                            NO WARRANTY

  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.

  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

Also add information on how to contact you by electronic and paper mail.

If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:

    Gnomovision version 69, Copyright (C) year name of author
    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.

You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary.  Here is a sample; alter the names:

  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
  `Gnomovision' (which makes passes at compilers) written by James Hacker.

  <signature of Ty Coon>, 1 April 1989
  Ty Coon, President of Vice

This General Public License does not permit incorporating your program into
proprietary programs.  If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
<TITLE>
Copyright (C) <YEAR>, <OWNER>
Licensed under GNU General Public License v3.0 only (below).

-------------------------------------------------------------------------------

                    GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU General Public License is a free, copyleft license for
software and other kinds of works.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.  We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors.  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights.  Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received.  You must make sure that they, too, receive
or can get the source code.  And you must show them these terms so they
know their rights.

  Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.

  For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software.  For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.

  Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so.  This is fundamentally incompatible with the aim of
protecting users' freedom to change the software.  The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable.  Therefore, we
have designed this version of the GPL to prohibit the practice for those
products.  If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.

  Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary.  To prevent this, the GPL assures that
patents cannot be used to render the program non-free.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Use with the GNU Affero General Public License.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

  If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:

    <program>  Copyright (C) <year>  <name of author>
    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.

  The GNU General Public License does not permit incorporating your program
into proprietary programs.  If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.  But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
<TITLE>
Copyright (C) <YEAR>, <OWNER>
Licensed under the GNU Affero Public License 3.0 (below).

-------------------------------------------------------------------------------

                    GNU AFFERO GENERAL PUBLIC LICENSE
                       Version 3, 19 November 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.

  A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate.  Many developers of free software are heartened and
encouraged by the resulting cooperation.  However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.

  The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community.  It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server.  Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.

  An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals.  This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU Affero General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Remote Network Interaction; Use with the GNU General Public License.

  Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software.  This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time.  Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

  If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source.  For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code.  There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<http://www.gnu.org/licenses/>.
<TITLE>
Copyright (c) <YEAR> <OWNER>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
<TITLE>
Copyright (C) <YEAR>, <OWNER>
Licensed under GNU Lesser General Public License v2.1 only (below).

-------------------------------------------------------------------------------

                  GNU LESSER GENERAL PUBLIC LICENSE
                       Version 2.1, February 1999

 Copyright (C) 1991, 1999 Free Software Foundation, Inc.
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

[This is the first released version of the Lesser GPL.  It also counts
 as the successor of the GNU Library Public License, version 2, hence
 the version number 2.1.]

                            Preamble

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.

  This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it.  You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.

  When we speak of free software, we are referring to freedom of use,
not price.  Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.

  To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights.  These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.

  For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you.  You must make sure that they, too, receive or can get the source
code.  If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it.  And you must show them these terms so they know their rights.

  We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.

  To protect each distributor, we want to make it very clear that
there is no warranty for the free library.  Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.

  Finally, software patents pose a constant threat to the existence of
any free program.  We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder.  Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.

  Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License.  This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License.  We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.

  When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library.  The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom.  The Lesser General
Public License permits more lax criteria for linking other code with
the library.

  We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License.  It also provides other free software developers Less
of an advantage over competing non-free programs.  These disadvantages
are the reason we use the ordinary General Public License for many
libraries.  However, the Lesser license provides advantages in certain
special circumstances.

  For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard.  To achieve this, non-free programs must be
allowed to use the library.  A more frequent case is that a free
library does the same job as widely used non-free libraries.  In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.

  In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software.  For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.

  Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.

  The precise terms and conditions for copying, distribution and
modification follow.  Pay close attention to the difference between a
"work based on the library" and a "work that uses the library".  The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.

                  GNU LESSER GENERAL PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".

  A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.

  The "Library", below, refers to any such software library or work
which has been distributed under these terms.  A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language.  (Hereinafter, translation is
included without limitation in the term "modification".)

  "Source code" for a work means the preferred form of the work for
making modifications to it.  For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.

  Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it).  Whether that is true depends on what the Library does
and what the program that uses the Library does.

  1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.

  You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.

  2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

    a) The modified work must itself be a software library.

    b) You must cause the files modified to carry prominent notices
    stating that you changed the files and the date of any change.

    c) You must cause the whole of the work to be licensed at no
    charge to all third parties under the terms of this License.

    d) If a facility in the modified Library refers to a function or a
    table of data to be supplied by an application program that uses
    the facility, other than as an argument passed when the facility
    is invoked, then you must make a good faith effort to ensure that,
    in the event an application does not supply such function or
    table, the facility still operates, and performs whatever part of
    its purpose remains meaningful.

    (For example, a function in a library to compute square roots has
    a purpose that is entirely well-defined independent of the
    application.  Therefore, Subsection 2d requires that any
    application-supplied function or table used by this function must
    be optional: if the application does not supply it, the square
    root function must still compute square roots.)

These requirements apply to the modified work as a whole.  If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works.  But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.

In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

  3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library.  To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License.  (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.)  Do not make any other change in
these notices.

  Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.

  This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.

  4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.

  If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.

  5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library".  Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.

  However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library".  The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.

  When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library.  The
threshold for this to be true is not precisely defined by law.

  If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work.  (Executables containing this object code plus portions of the
Library will still fall under Section 6.)

  Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.

  6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.

  You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License.  You must supply a copy of this License.  If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License.  Also, you must do one
of these things:

    a) Accompany the work with the complete corresponding
    machine-readable source code for the Library including whatever
    changes were used in the work (which must be distributed under
    Sections 1 and 2 above); and, if the work is an executable linked
    with the Library, with the complete machine-readable "work that
    uses the Library", as object code and/or source code, so that the
    user can modify the Library and then relink to produce a modified
    executable containing the modified Library.  (It is understood
    that the user who changes the contents of definitions files in the
    Library will not necessarily be able to recompile the application
    to use the modified definitions.)

    b) Use a suitable shared library mechanism for linking with the
    Library.  A suitable mechanism is one that (1) uses at run time a
    copy of the library already present on the user's computer system,
    rather than copying library functions into the executable, and (2)
    will operate properly with a modified version of the library, if
    the user installs one, as long as the modified version is
    interface-compatible with the version that the work was made with.

    c) Accompany the work with a written offer, valid for at
    least three years, to give the same user the materials
    specified in Subsection 6a, above, for a charge no more
    than the cost of performing this distribution.

    d) If distribution of the work is made by offering access to copy
    from a designated place, offer equivalent access to copy the above
    specified materials from the same place.

    e) Verify that the user has already received a copy of these
    materials or that you have already sent this user a copy.

  For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it.  However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.

  It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system.  Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.

  7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:

    a) Accompany the combined library with a copy of the same work
    based on the Library, uncombined with any other library
    facilities.  This must be distributed under the terms of the
    Sections above.

    b) Give prominent notice with the combined library of the fact
    that part of it is a work based on the Library, and explaining
    where to find the accompanying uncombined form of the same work.

  8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License.  Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License.  However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.

  9. You are not required to accept this License, since you have not
signed it.  However, nothing else grants you permission to modify or
distribute the Library or its derivative works.  These actions are
prohibited by law if you do not accept this License.  Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.

  10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions.  You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.

  11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all.  For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.

If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices.  Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.

  12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded.  In such case, this License incorporates the limitation as if
written in the body of this License.

  13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.

Each version is given a distinguishing version number.  If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation.  If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.

  14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission.  For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this.  Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.

                            NO WARRANTY

  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.

                     END OF TERMS AND CONDITIONS

           How to Apply These Terms to Your New Libraries

  If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change.  You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).

  To apply these terms, attach the following notices to the library.  It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.

    <one line to give the library's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

Also add information on how to contact you by electronic and paper mail.

You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary.  Here is a sample; alter the names:

  Yoyodyne, Inc., hereby disclaims all copyright interest in the
  library `Frob' (a library for tweaking knobs) written by James Random Hacker.

  <signature of Ty Coon>, 1 April 1990
  Ty Coon, President of Vice

That's all there is to it!
<TITLE>
Copyright (C) <YEAR>, <OWNER>
Licensed under GNU General Public License v2.0 or later (below).

-------------------------------------------------------------------------------

                    GNU GENERAL PUBLIC LICENSE
                       Version 2, June 1991

 Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users.  This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it.  (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.)  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.

  To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have.  You must make sure that they, too, receive or can get the
source code.  And you must show them these terms so they know their
rights.

  We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.

  Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software.  If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.

  Finally, any free program is threatened constantly by software
patents.  We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary.  To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.

  The precise terms and conditions for copying, distribution and
modification follow.

                    GNU GENERAL PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License.  The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language.  (Hereinafter, translation is included without limitation in
the term "modification".)  Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.

  1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.

You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.

  2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

    a) You must cause the modified files to carry prominent notices
    stating that you changed the files and the date of any change.

    b) You must cause any work that you distribute or publish, that in
    whole or in part contains or is derived from the Program or any
    part thereof, to be licensed as a whole at no charge to all third
    parties under the terms of this License.

    c) If the modified program normally reads commands interactively
    when run, you must cause it, when started running for such
    interactive use in the most ordinary way, to print or display an
    announcement including an appropriate copyright notice and a
    notice that there is no warranty (or else, saying that you provide
    a warranty) and that users may redistribute the program under
    these conditions, and telling the user how to view a copy of this
    License.  (Exception: if the Program itself is interactive but
    does not normally print such an announcement, your work based on
    the Program is not required to print an announcement.)

These requirements apply to the modified work as a whole.  If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works.  But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.

In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

  3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:

    a) Accompany it with the complete corresponding machine-readable
    source code, which must be distributed under the terms of Sections
    1 and 2 above on a medium customarily used for software interchange; or,

    b) Accompany it with a written offer, valid for at least three
    years, to give any third party, for a charge no more than your
    cost of physically performing source distribution, a complete
    machine-readable copy of the corresponding source code, to be
    distributed under the terms of Sections 1 and 2 above on a medium
    customarily used for software interchange; or,

    c) Accompany it with the information you received as to the offer
    to distribute corresponding source code.  (This alternative is
    allowed only for noncommercial distribution and only if you
    received the program in object code or executable form with such
    an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for
making modifications to it.  For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable.  However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.

If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.

  4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License.  Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.

  5. You are not required to accept this License, since you have not
signed it.  However, nothing else grants you permission to modify or
distribute the Program or its derivative works.  These actions are
prohibited by law if you do not accept this License.  Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.

  6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions.  You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.

  7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all.  For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices.  Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.

  8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded.  In such case, this License incorporates
the limitation as if written in the body of this License.

  9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

Each version is given a distinguishing version number.  If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation.  If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.

  10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission.  For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this.  Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.

                            NO WARRANTY

  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.

  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

Also add information on how to contact you by electronic and paper mail.

If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:

    Gnomovision version 69, Copyright (C) year name of author
    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.

You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary.  Here is a sample; alter the names:

  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
  `Gnomovision' (which makes passes at compilers) written by James Hacker.

  <signature of Ty Coon>, 1 April 1989
  Ty Coon, President of Vice

This General Public License does not permit incorporating your program into
proprietary programs.  If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
<TITLE>
Copyright (C) <YEAR>, <OWNER>
Licensed under GNU Lesser General Public License v3.0 or later (below).

-------------------------------------------------------------------------------

                   GNU LESSER GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.


  This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.

  0. Additional Definitions.

  As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.

  "The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.

  An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.

  A "Combined Work" is a work produced by combining or linking an
Application with the Library.  The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".

  The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.

  The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.

  1. Exception to Section 3 of the GNU GPL.

  You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.

  2. Conveying Modified Versions.

  If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:

   a) under this License, provided that you make a good faith effort to
   ensure that, in the event an Application does not supply the
   function or data, the facility still operates, and performs
   whatever part of its purpose remains meaningful, or

   b) under the GNU GPL, with none of the additional permissions of
   this License applicable to that copy.

  3. Object Code Incorporating Material from Library Header Files.

  The object code form of an Application may incorporate material from
a header file that is part of the Library.  You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:

   a) Give prominent notice with each copy of the object code that the
   Library is used in it and that the Library and its use are
   covered by this License.

   b) Accompany the object code with a copy of the GNU GPL and this license
   document.

  4. Combined Works.

  You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:

   a) Give prominent notice with each copy of the Combined Work that
   the Library is used in it and that the Library and its use are
   covered by this License.

   b) Accompany the Combined Work with a copy of the GNU GPL and this license
   document.

   c) For a Combined Work that displays copyright notices during
   execution, include the copyright notice for the Library among
   these notices, as well as a reference directing the user to the
   copies of the GNU GPL and this license document.

   d) Do one of the following:

       0) Convey the Minimal Corresponding Source under the terms of this
       License, and the Corresponding Application Code in a form
       suitable for, and under terms that permit, the user to
       recombine or relink the Application with a modified version of
       the Linked Version to produce a modified Combined Work, in the
       manner specified by section 6 of the GNU GPL for conveying
       Corresponding Source.

       1) Use a suitable shared library mechanism for linking with the
       Library.  A suitable mechanism is one that (a) uses at run time
       a copy of the Library already present on the user's computer
       system, and (b) will operate properly with a modified version
       of the Library that is interface-compatible with the Linked
       Version.

   e) Provide Installation Information, but only if you would otherwise
   be required to provide such information under section 6 of the
   GNU GPL, and only to the extent that such information is
   necessary to install and execute a modified version of the
   Combined Work produced by recombining or relinking the
   Application with a modified version of the Linked Version. (If
   you use option 4d0, the Installation Information must accompany
   the Minimal Corresponding Source and Corresponding Application
   Code. If you use option 4d1, you must provide the Installation
   Information in the manner specified by section 6 of the GNU GPL
   for conveying Corresponding Source.)

  5. Combined Libraries.

  You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:

   a) Accompany the combined library with a copy of the same work based
   on the Library, uncombined with any other library facilities,
   conveyed under the terms of this License.

   b) Give prominent notice with the combined library that part of it
   is a work based on the Library, and explaining where to find the
   accompanying uncombined form of the same work.

  6. Revised Versions of the GNU Lesser General Public License.

  The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.

  Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.

  If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
<TITLE>
Copyright (C) <YEAR>, <OWNER>
Licensed under Apache License 2.0 (below).

-------------------------------------------------------------------------------

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
<TITLE>
Copyright (C) <YEAR>, <OWNER>
Licensed under GNU General Public License v3.0 or later (below).

-------------------------------------------------------------------------------

                    GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU General Public License is a free, copyleft license for
software and other kinds of works.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.  We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors.  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights.  Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received.  You must make sure that they, too, receive
or can get the source code.  And you must show them these terms so they
know their rights.

  Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.

  For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software.  For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.

  Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so.  This is fundamentally incompatible with the aim of
protecting users' freedom to change the software.  The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable.  Therefore, we
have designed this version of the GPL to prohibit the practice for those
products.  If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.

  Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary.  To prevent this, the GPL assures that
patents cannot be used to render the program non-free.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Use with the GNU Affero General Public License.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

  If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:

    <program>  Copyright (C) <year>  <name of author>
    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.

  The GNU General Public License does not permit incorporating your program
into proprietary programs.  If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.  But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
<TITLE>
Copyright (C)  <YEAR>, <OWNER>
This work is free. You can redistribute it and/or modify it under the
terms of the Do What The Fuck You Want To Public License, Version 2,
as published by Sam Hocevar. See below for more details.

-------------------------------------------------------------------------------


        DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 
                    Version 2, December 2004 

 Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> 

 Everyone is permitted to copy and distribute verbatim or modified 
 copies of this license document, and changing it is allowed as long 
 as the name is changed. 

            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 

  0. You just DO WHAT THE FUCK YOU WANT TO.
<?php

namespace CivixPhar;

class TOGoS_GitIgnore_Util
{
    public static function aize($word)
    {
        if (\preg_match('/^[aeiou]/', $word)) {
            return "an {$word}";
        }
        return "a {$word}";
    }
    public static function describe($val)
    {
        if ($val === null) {
            return "null";
        }
        if (\is_float($val) or \is_int($val)) {
            return "the number {$val}";
        }
        if (\is_bool($val)) {
            return $val ? "true" : "false";
        }
        if (\is_object($val)) {
            return self::aize(\get_class($val));
        }
        return aize(\gettype($val));
    }
}
\class_alias('CivixPhar\\TOGoS_GitIgnore_Util', 'TOGoS_GitIgnore_Util', \false);
<?php

namespace CivixPhar;

class TOGoS_GitIgnore_FileFinder
{
    public function __construct(array $options)
    {
        // TODO: Validate options
        $this->ruleset = $options['ruleset'];
        $this->invertRulesetResult = $options['invertRulesetResult'];
        $this->defaultResult = $options['defaultResult'];
        $this->includeDirectories = $options['includeDirectories'];
        $this->callback = $options['callback'];
    }
    protected function match($rootDir, $f)
    {
        $result = $this->ruleset->match($f);
        if ($this->invertRulesetResult and $result !== null) {
            $result = !$result;
        }
        return $result === null ? $this->defaultResult : $result;
    }
    protected function _findFiles($rootDir, $f)
    {
        if (\preg_match('#/$#', $rootDir)) {
            throw new \Exception("Root directory argument to _findFiles should not end with a slash; given Â«{$rootDir}Â»");
        }
        if (\preg_match('#^/|/$#', $f)) {
            throw new \Exception("Relative path argument to _findFiles should not start or end with a slash; given Â«{$f}Â»");
        }
        //echo "_findFiles($rootDir, $f)\n";
        $fullPath = $f == '' ? $rootDir : $rootDir . '/' . $f;
        if ($this->includeDirectories or !\is_dir($fullPath)) {
            $result = $this->match($rootDir, $f);
            \call_user_func($this->callback, $f, $result);
        }
        if (\is_dir($fullPath)) {
            $dh = \opendir($fullPath);
            while (($fn = \readdir($dh)) !== \false) {
                if ($fn == '.' or $fn == '..') {
                    continue;
                }
                $this->_findFiles($rootDir, $f == '' ? $fn : $f . '/' . $fn);
            }
            \closedir($dh);
        }
    }
    public function findFiles($dir)
    {
        self::_findFiles($dir, '');
    }
}
\class_alias('CivixPhar\\TOGoS_GitIgnore_FileFinder', 'TOGoS_GitIgnore_FileFinder', \false);
<?php

namespace CivixPhar;

class TOGoS_GitIgnore_Pattern
{
    protected $patternString;
    protected $regex;
    protected function __construct($pattern, $regex)
    {
        $this->patternString = $pattern;
        $this->regex = $regex;
    }
    public function getPatternString()
    {
        return $this->patternString;
    }
    protected static function patternToRegex($pp)
    {
        \preg_match_all('/\\*|\\*\\*|\\?|[^\\*\\?]|\\[![^\\]+]|\\[[^\\]+]/', $pp, $bifs);
        $regex = '';
        foreach ($bifs[0] as $part) {
            if ($part == '**') {
                $regex .= ".*";
            } else {
                if ($part == '*') {
                    $regex .= "[^/]*";
                } else {
                    if ($part == '?') {
                        $regex .= '?';
                    } else {
                        if ($part[0] == '[') {
                            // Not exactly, but maybe close enough.
                            // Maybe fnmatch is the thing to use
                            if ($part[1] == '!') {
                                $part[1] = '^';
                            }
                            $regex .= $part;
                        } else {
                            $regex .= \preg_quote($part, '#');
                        }
                    }
                }
            }
        }
        return $regex;
    }
    public static function parse($pattern)
    {
        $r = self::patternToRegex($pattern);
        if (\strlen($pattern) == 0) {
            throw new \Exception("Zero-length pattern string passed to " . __METHOD__);
        }
        if ($pattern[0] == '/') {
            $r = '#^' . \substr($r, 1) . '(?:$|/)#';
        } else {
            $r = '#(?:^|/)' . $r . '(?:$|/)#';
        }
        return new self($pattern, $r);
    }
    public function match($path)
    {
        if (\strlen($path) > 0 and $path[0] == '/') {
            throw new \Exception("Paths passed to #match should not start with a slash; given: Â«" . $path . "Â»");
        }
        if (!\is_string($path)) {
            throw new \Exception(__METHOD__ . " expects a string; given " . TOGoS_GitIgnore_Util::describe($path));
        }
        return \preg_match($this->regex, $path);
    }
}
\class_alias('CivixPhar\\TOGoS_GitIgnore_Pattern', 'TOGoS_GitIgnore_Pattern', \false);
<?php

namespace CivixPhar;

class TOGoS_GitIgnore_Rule
{
    protected $isExclusion;
    protected $pattern;
    public function __construct(TOGoS_GitIgnore_Pattern $pattern, $isExclusion)
    {
        $this->pattern = $pattern;
        $this->isExclusion = $isExclusion;
    }
    /** @return true: include this file, false: exclude this file, null: rule does not apply to this file */
    public function match($path)
    {
        if (!\is_string($path)) {
            throw new \Exception(__METHOD__ . " expects a string; given " . TOGoS_GitIgnore_Util::describe($path));
        }
        if ($this->pattern->match($path)) {
            return $this->isExclusion ? \false : \true;
        }
        return null;
    }
    public static function parse($str)
    {
        $isExclusion = \false;
        if ($str[0] == '!') {
            $isExclusion = \true;
            $str = \substr($str, 1);
        }
        $pattern = TOGoS_GitIgnore_Pattern::parse($str);
        return new self($pattern, $isExclusion);
    }
}
\class_alias('CivixPhar\\TOGoS_GitIgnore_Rule', 'TOGoS_GitIgnore_Rule', \false);
<?php

namespace CivixPhar;

class TOGoS_GitIgnore_Ruleset
{
    protected $rules;
    public function addRule($rule)
    {
        if (\is_string($rule)) {
            $str = \trim($rule);
            if ($str == '') {
                return;
            }
            if ($str[0] == '#') {
                return;
            }
            if (\substr($str, 0, 2) == '\\#') {
                $str = \substr($str, 1);
            }
            $rule = TOGoS_GitIgnore_Rule::parse($str);
        }
        if (!$rule instanceof TOGoS_GitIgnore_Rule) {
            throw new \Exception("Argument to TOGoS_GitIgnore_Ruleset#addRule should be a string or TOGoS_GitIgnore_Rule; received " . TOGoS_GitIgnore_Util::describe($rule));
        }
        $this->rules[] = $rule;
    }
    public function match($path)
    {
        if (!\is_string($path)) {
            throw new \Exception(__METHOD__ . " expects a string; given " . TOGoS_GitIgnore_Util::describe($path));
        }
        $lastResult = null;
        foreach ($this->rules as $rule) {
            $result = $rule->match($path);
            if ($result !== null) {
                $lastResult = $result;
            }
        }
        return $lastResult;
    }
    public static function loadFromStrings($lines)
    {
        $rs = new self();
        foreach ($lines as $line) {
            $rs->addRule($line);
        }
        return $rs;
    }
    public static function loadFromString($str)
    {
        $lines = \explode("\n", $str);
        return self::loadFromStrings($lines);
    }
    public static function loadFromFile($filename)
    {
        $rs = new self();
        $fh = \fopen($filename);
        while ($line = \fgets($fh)) {
            $rs->addRule($line);
        }
        \fclose($fh);
        return $rs;
    }
}
\class_alias('CivixPhar\\TOGoS_GitIgnore_Ruleset', 'TOGoS_GitIgnore_Ruleset', \false);
‰PNG

   IHDR  »  Š   Í#V×  -ÆIDATxÚíÝMh�éy?`A ‹@ È¢P(²
�.
��B�@ �E tdº+�B!È"²Hf„lK2Ò‘d[È²%aëÙúÂÇ²%$Ûš™ÅÛÿïùóžœÑÈ¶lëHçãZ\Œt¬ÏGš£÷÷ÞÏsßCï¿ÿ~   ýdè¯ýkuïÞ½jmm­«ò:   ô²vGGG«ÕÕÕê£�>ªšÍf5;;[}ðÁ  €ž2>>^Š¹Cí~øá‡ÕÜÜ\µ··WWËËËÕµk×,   ]+ÅÚmS¼M–M1wèUixcc£T{=zTÝ¸qÃ"  Ð5Rœ]YY)7EÛoë]ÊC¯{çT{ççç«ýýýêùóçå|ïÕ«W-,   —"ÅØeSœM‘6ÅÚSÏìžÕäädõàÁƒêã�?®¶··«ééi  @Ç¥èšâkŠ°)Æ¦(›âìËÞ~èm>ÉÈÈHµ°°PVGGGÕââbyÌ   €ó”"kŠ­)º¦øš"ìYÞoè]?q£Ñh}âÍÍÍòº   o«½ÀyùM¬CçõÅ\¹r¥ZZZªž={VJÊwïÞ­†‡‡ý    ¸ð£³C�øsXxgg§|�9,|ýúu?8   >#çnïÜ¹ó©¦È)¦¾ëÇêä�Ä÷ïß¯^¼xQ=}úôµˆ  �w;tßDæÝ¼y³ÕzmmíÔÖÐ   ôw7³p37³q———Ë¬ÜN|®¡‹þæFGG«ÕÕÕò�=~ü¸š��mý   ÿ´çÀf³y!9pè²¾Ù|cí‰>ßx§=   Ÿù.s‡ïP7,B¾áõõõÖ^í,ˆj/  @ï9Ù»éöíÛ—Ò»i¨›%�&VY�ºWÊ/  @w›™™iMåÉø ËžÊ3Ô­511Ñš¯”ËÂù  è###ÕÒÒRuttTVwïÞ­†‡‡»âkêöÅËBeÁ²pYÀ,äyÌ\  àí4�jss³'óß¼Þm_ã�  à¬…Èƒƒƒž(Dõâ"gA»µT  ÐOrövcc£uÄôÆ�=ñuõúÂŸ<�³¾~!  Þ^š§‹rš§«rº+÷Zóà¡~ùadáÓ½9]œóIWçËho  Ð«ÆÆÆÊ<ÜŒ…m6›==v¨ß~8—=¸   ×2Ôììl	·ÉP«««ÕèèhÏ_CýüC»víZùAW{{{ÕÜÜ\ÏÞ•   8ï¼´¼¼ü©¼ÔO»c‡á‡Xß©xüøqùAöË�
  €7•S»»»¥Š›ÆSi@Õ�ßçÐ ý`³¥¹Þƒž­Î½¼  à,ê‰6éq´¿¿_&Úô{�£¡Aýaç›&V½Ü]  àU¦¦¦ªííí2½æáÃ‡ÕäääÀ|ïC~zwn  ÀI###ÕÂÂBuxxX•—óØ ­ƒ°Ûfxx¸”óSÖÏ/EÊü)÷[   Û¥jûàÁƒrd3ÕÜééé�^a÷%�Fµ¹¹Yª½ùEÉëÖ  èÆã™)Øå<î½{÷ÏvÏ¾`qq±Tz³`P·    Ý#�w×××?Õx×º»o-Û êÃÝÙ0H‡» €Ë•)2™…›™¸õHÕÌÊµ6Âî¹É¶€l¨ÛvgÛ@¿·í  .Çèèh	¶	¸�?®fgg�Ov;/�›³m ÈœíÖ  x×*n¶&×YcmmMÖv/G¶,//—»-ÙV�íª½  ÀÛî"}úô©]¤ÂnwÝ�É¶‚f³YîÀd»A¶X  àeÒhgg§ÕhbbÂº»Ýkll¬l7HèMø½uë–½õ  @qÚä—ááak#ìöŽl;È¶ælCxñâEÙî¬k  ¦F£Qmnn–*îÖÖVyÝº»=ïúõë¥‘Uª½Ù¦�WÖ  ú[*¶wïÞ-Ó\ž={V---UW®\±6Ânÿ²çð¹_v  PìBØí+“““ÕÃ‡Ë6†ííír8Ýº  @oc|òä‰cŒÂ.õõJÏáôú€z³6  Ðý2…EƒZa—×Hu7UÞT{SõMõ×º  @wI˜M¨­G�&ì=*ìr9Ç[•ÎùÞœó5T  .W¶%g{r¶)g»r¶-»NvyK9Ì¾»»[îå�{»[  ¸Økò4šrM.ìâ.  ôünËLOÉÈ z·e¦«Xaç   ç4�V�ÍÍM}t„].CBîêêj«óÛìì¬Îo  ð†R±­'¤U‹‹‹&¤»tƒz¦×ÞÞ^u||l¦  œÁÄÄDõàÁƒRÅÍ™ÜLG±.Â.]*‡åsh>ÕÞG�•ÃôÖ  þV(šŸŸ¯ž>}Z¦Ÿd
ÊÕ«W­�°K/ýO|çÎ�r˜ÞÿÄ  ºñññÒï¦.
Ý¼yÓ@a—^—CõÙž‘ÿ±sØÞö  AÂlúÚ<~ü¸÷K¿Í]…]úPÙ·¼ÏËÞ ÐoÒ¿&Á67}m4rv '[ªçuë @/ËÖälQÎŽÆõõõ²uÙº»(Ã² èeéK“þ4éS“ëÙ4ŸJÿk#ìBK:7§åzª½éèœÎÎÖ €n”>4õNÅô§IŸë‚°ËkïŽeVï‹/JKöÛ·o»; À¥«{Ð¤ÿLúÐèAƒ°Ë[É!þösiÕîÜ  -UÛ‡–*nª¹SSSÖa—ó‘íuG»f³©£  •�…é'“s¸9�›>3é7cmvéXµwnn®´p¯g•¥µ»µ à<¤oLúÇdgáîîné+c]v¹PÙÒœ–îy"ÊVçlyVí àmª¸uA%}cÒ?FAa—®xrJ‹÷4³Ê“´~O“+k ÀYŽÊ¥xâ¨Â.]ß< ­ßÓ< cŒÒÞº  Ð~,.;në&¨cccÖa—Þ0<<\ZÁ§%|ZÃ§¡€¶ð  ƒËxK„]úN£Ñ¨677Kµ7ÿÍëÖ `0¤ÁTvüåZ0�§Ò€Êº ìÒWÒ*>ÞzxZÉ§lm  ú÷ºïààÀuÂ.ƒcff¦u‡/g|'&&¬ €} ìÒ?g7Ò½¹>»‘®ÎÎn  ôŽTlS¹Õ«aNQwåË¼Þº+_æøZ €î”³·íS8²sÏº ìÂ+ÔóÖŽ��Ë`qóÖ  ºCvàe'^väeg^vèe§žµAØ…7¬ö&è>~ü¸ßàak p±²ã.;ï²/;ñ²#O1a<Á ôlá¡Ùl*< ìÂEo�¹ÿ¾­3  çèÚµkÕòòrëHÙÜÜœ¢»p‘N6EÈÀrë ðvr-U7ÝØØÐ,a.[Ýî>Ëëv÷dnm  ^-×Li2õüùój¿ºsçŽ*.Â.t£öAæ[[[™ œbzzºÚÞÞ.×LÙ)799i]v¡d�ùââb©ôfÀùÂÂB© [ `�¯�rM”k£úú(�Y„]pç  çäÚ§îs’k¢\Y„]è#éÚÜ~&%]��I úQ®qrþ6×<¹öÉ5�ž&»0 2§W·A  ßäš&×6¹ÆÉµŽi»0 2GneeÅ9  g}ðÁå&×2¹¦ÉµM®q¬Â.PþHÌÎÎVÍf³ü‘X]]­FGG­ Ðµr­’k–\»ä&×2¹¦±6»À©ÆÆÆªµµµ²ý'8²åÙ  [nÐ·ÇÊ5‹ãX ìÂÉvæl	zúôiõâÅ‹jyyÙ–  àRÔ�6sM’k�6AØ…sqýúõV³‡��Í €133S®=êŠ¹&±. ìÂ¹®îÞ½Ûjã¿´´¤�? p®FFFÊ5ÆÑÑQuxxX®=rbm@Ø…‘í›››­íSSSÖ xk�F£um±µµU^·. ìÂ¥Þ}]XXhÝ}ÍËyÌÚ  gÝ5vppP®%ìaºÒôôt©òÖçjRýµ. ÀIu?�\3èÂ.ôŒÜ‘MÇÄœëÍùÞÜ±Õ1 Ûi“ÒeÙÚ€°=)wjwwwK'çÜÁÕE ËØØX™‡›k�f³Yæäf^®µaúBfôænîä>yò¤ÜÙUí€þ”0;;;[ÂmBîêêj5::jm@Ø…Áùã—;½þø@ÿÝÜÞÛÛss„]L	¹íÛš‚mk Ç– aúBÝ°"w€ë†¹3lm  {¥!eFiH	Â.põ(‚Ü~ôè‘Q Ðe¦¦¦Z£777�axÓjï�;wÊ�âÜ1Î(#ã	 àrŒŒŒTÕááauttT^ÎcÖ„]àäŽñƒÊäÜIžžž¶. ào0 ì‚»Ê ÀÙwWÍÏÏWOŸ>µ»
„]Ày! èmãããÕúúz«oÆÍ›7­»Àe©;A>{ö¬Õ	rxxØÚ Àdä_Fÿe"Âññqµººj"»@·Içæ��3þ à52ë>Á6÷ñãÇfÝƒ°ô‚œ+Ê¬ÞÌìÍy£Û·o›û€*îÿ³Ùšœ-Ê¹1¼¶¶V¶.[v�ý£Þl6ýQ` o§ÉTšMå&pšO¹	Â.Ð‡Ûµ~m× ßeLPÝÌ1ãƒ4saèc¹“=77×jÄ±²²¢ }##ùËˆ¾ŒêË˜>�AØŒ ô‹Tm3Š/UÜTs�†uaPíý°œ_Ê9¦œgÊ¹¦œo²6 t³Tl3r/£÷2‚/£ø2’ÏÚ€°pê�ñœkÊ�ñŒ1Êy'ë@7Éh½ŒØËÎ¤ü­Êè=ë»À™ï–çœSÎ;åÜSî–ç”µà²v!¥çÄ“'OÊh½ŒØÓsv�w’sO[[[¥Ú›óPÎApQ2M £óRÅÍ4�[·n™& »ÀùÊ9¨TxSé=88(ç¤t¸à¼%Ì&Ô¶Ï‰Oèµ6€°t\ÎGåœT=»0ç§¬ ï"Í³=9Û”Ó41Û–³}ÙÚ Â.p)&éÞ\_˜¤«³ Þæjª¸i<å* ì]µå,sz3¯÷øø¸l9Ë_kÀ«ŽÆddPF9»@×Ë¹ªÕÕÕz÷ööªÙÙYÍD (4=„] /ª½	º	¼	¾	ÀŒ ž“ãì�³„] ?dKs=:"[�³åYµ ¿MLL”&†©âæLîôô´u„] ?¥yUšX¥™UšZ¥¹Uš\Y Ïó Â.ÐÒm³ýŽÿÌÌŒu°ƒ@Øúç,Wºp”³\éÎ™.�Ö »Õ½?~¬7 ì¼Jºr¦;gª½éÖ©K'@÷¹víZµ²²Òêº?77§Š» g‘.�©ð¦Ò›î�éâiþ"Àåªç©g«òúúºyê€°ð.Ò½3gzSíÍßÉÉIëpAÒ\*M¦ž?^íïï—æSiBem a \éòé‚ ³7···K×�F@Ø¸ 9f+@gŽ�äØHû’<fm aà‚uk“”TžS�x�Ó¸ìç¬Tm>|XŽ‹¤š;55åo ìtKµ7ã/šÍfWŒ¿xñâE©>¼Nž/.ãy*Ç@2ö-çpºsLÄØ7@ØèbÙÒ¼¶¶V¶8'üæbò¢«½Â.Ð­a÷úõëÕÆÆFyŽÜÝÝ­nÜ¸áo ìô’T-nß¾]¶çbryy¹4¹v�A»y>Ì1�÷Èî—<æˆ¿€°ÐãêJFÎ£å|\§+Â.Ða7Ç9r¬#7;]rÜ£ú » çlxx¸uFíÙ³gÕÒÒRGÎ¨	»Àe…Ýºc}Âm¶*çXÇØØ˜¿€°0(Ò}tss³Õ}´Ñh»@Ï†ÝÓ¸ÿ~ùx9¾‘cf‘Â.À ëÄ\Ia¸¨°›c9ž‘w9®‘cžÛa€O™žž.UÞ\4>xð T…] ÛÂnŽ_äFnÒ”ã9¦áyv-Àk·fædfOæ|ï�;wÞh; °t"ìæ¸E}ü"ÿ=Ïã Â.À€ÉÁG�•F/gÝ"(ìçvëÆz©à¦’Û©Æz Â.À€ÊLÊÌ¦Ì�ÌªÌÌÊ—U{…]à]Ãnn¬å8E=2mffÆs1€°Ð9ë‘Y•õX�Ì°Ì,Kax×°›hé¢œnÊy<Ý•s¬Âs/€°p¡r3Ã2¡7á÷Ö­[%»À›„ÝñññÖsIŽMäñ<—xžv.Uª1ÙÖüäÉ“rášm‡.â�³øä“OÊñˆÓv‰  ìt�œ³v�³J5÷Mº½ ì\Û˜�NÎÙ@Øva@Ø@Ø„] a av„] a@Øv„]@Ø@Øva@Ø@Ø„] a av„] a@Øv„]@Ø@Øva@Øµ Â. ì» »€° ì».âa@Øva a@Ø„] „] av„] „]@Øvva@Øv„] a@Ø„] „] av„] „]@Øvva@Øv„] a@Ø„] „] av„] „]@Øvva@Øv„] a@Ø„] „] avv„]@Øvva@Øv…]@Øv„]@Ø@Øva a@Ø„] a av„] „]@Øv„] a@Øva a@Ø„] a av„] „]@Øv„] a@Øvy¥ßýîwÕw¾ó�ê«_ýjõw÷wå¿ßýîwËãƒ´###e~ùË_žûÇþË_þâwMØvv/Ê/~ñ‹jhh¨úüç?_}ãß¨Þ{ï½òßÏ}îsåñŸÿüç³þóŸË÷œÀ{ž7kzÞa@Øvy‰?ü°„Ü¿ÿû¿ÿLåñOúS©ò&ôæea÷íuâc"ì» Â./ñ_ÿõ_%ˆ¥º{Ú¿ÿçþgù÷÷ßÿ¥á0^·58N>~íÚµò¾ùï«Þzzº¼ÝY·çmâ_÷ñNûºO†Ýñññ3}�ù|y»ÉÉIaWØvv/Û¯ýëÄr>÷´OÈûßÿýßO…Õ„ÅŸüä'Õ—¾ô¥ò¾ñå/¹ú�ÿø�ÖÛüë¿þk‘·«ß¦Ô©ÿó?ÿsëñø§ú§ÏT�óy~ô£U_øÂZo÷•¯|¥ðö·«?WÏ×Q¿í×¾öµê÷¿ÿý§>ÞøÃO}¼|?ýéO?v¿ýíoWßÿþ÷KÕ;¯§ºý/ÿò/%üž\¿ø‡h}¼¼}BmŽûÛß–êxþ-Ÿ7/ç1¿{Â.€° ìºˆï T"ÓŒ*aìÿñKc¦×mYNÌÛ'`&ìýêW¿*g|óX^ÎÛ|ó›ß,Á3/o÷­o}«4»Ju6�ñ‹_¬~ö³Ÿ• �œÇ¢½z›ÀYñÿùŸÿ);¡8�µ7�ÊçÊÇËçJ¸þïÿþïêÇ?þq	¨Ùž��›·«ƒwo>o¾ö|]y¬êuØÍû&Äæñ|Þúíò½×Ÿ7Ÿ'�åí´ó1Îó¾YÓ¬m*¾ùõúæåWU�v„] a—sìœÀØ^iMðLØ¬Ãk{å3a.áïd8a3�® í!²ö½ï}¯<þ›ßüæ3Ý óxþ½®ˆ¶¿Þ^�MÅ6ÙzËpý¹N~­	Éy¼®îæíR>öóx‚w{ØMxnßºœÏ›÷Mxn=ëtr‹vz�Üúm³° ì ì^’„ÂléÍãö­¾©¦ÖÛwSQÍc©jžšOÐ“Û~S	=íó'ÄÖa4Ò¼ÿi£�"Ûs>W¶¿ìíRqm¯'@ç}ëŠïigv³eùä¿µž:œ§J|Zµ<oWaWØvv»D‚`¶ùÖÛ“ðƒ”Çÿíßþ­¼þ‡?üá•ï_‡ÝÓ5½NÞ.ÁðuoWW�ó¹röäçª·×a7A¶ý|m}Bmšt�¥sû÷T7özÙ<Þ|=í_“°+ì» »(Ûws¾õeÿžÊl¶Çy…Ý¯ýë%ˆ¾L{ØÍyÞ—½]}¶ø¬a·ñ9ÿ›Šl*Éuð­ƒ¨°+ì ì»} nøôª±>	§9Ãš—>_¶�9Á¹® ¿,ì&4¿ls¶Q×_G>ÎË¶1çmþøÇ?~jËôY+»y¿“³„ë]õ(¤³„Ý|­'V�ÜÆœµv…] a a÷´w
>m–l]Á¬Ï°¾ªAU‚ìÉU'?^Ý4êd3©TŠóqë÷Ï™ÚºãóÉíÕy›üÛ›Vvóõ¥š{ò¬î{ï½÷Æa7Ò¬*g�OvW®Ï
·�4v…] a a÷‚Ïæ&ÈÖˆÈ²U9[›ëªo]B`ý>Ù\Ñ„ÖâTVë`ù²°[�ÊyÙ|Ž¼}¶§1UÞ¿}mÝP*a4Ÿ§}ôP{Eõ¬a·Þ‚]¼z;s{¨~“°›�Q�7Êçª?^ûè¡úmóý&l§ñ–9»Â.€°€°{A�7ãrÚ›7ÕœR‰=m‹sª—	oõÛæ}ÓÐªþ÷„ÇÓh(8
ë÷OXn?[[]	¨íŸ'/§bÚ^�Íçjï|Ü^•Î×P‡Ë¼Ofí¶¼|�	¨u×è|¯yŸÓº,Ÿö=%àækoÿxéö|²Jžíßu‡ëzÌÂ.€° ìrAR�L}ÕÞ“•Ú“sfß$dçs�¶}ú´ÏsÖ¯é,²õ¸½Zý®ê-Ð~‡„] a av„] a@Øv„]@Ø@Øva a@Ø„] a av„] „]@Øv„]@Ø@Øva a@Ø„] a av„] „]@Øv„] a@Øva a@Ø„] a av„] „]@Øv„] a@Øva a@Ø„] a av„] „]@Øv„] a@Øva a@Ø„] „] av„] „]@Øvva@Øva×ó&€° ìÂ. Â.€°» Â. Â. ì» »€° ì» Â.€° ìÂ. Â.€°» Â. Â. ì» »€° ì» Â.€° ìÂ. Â.€°» Â®E va@Ø@Ø„] a@Øu» Â.€°» » Ýéƒ>¨>úè#ñÀ™äùbxxØó'€°Ð�®^½ZÝ¿¿Ti>ùäñÀ™äù"�wcc£º~ýºçS a ;ÌÌÌT;;;ÕÇ\=xð \¬ÚÆ¼É6æÜ,[^^./?}ú´º}ûvõá‡zŽv.ÖÈÈHµ´´TU‡‡‡ÕÝ»w?µQØÞæÌnŽAä±f³Yª½kkkÕøø¸ç] a ³�Fµ¹¹Yª¸ùo^× 
èDƒªÑÑÑjuuµ:>>.áwvv¶„aÏÅ Â.À¹HÅ6•ÛƒƒƒRÉME÷Ê•+º1Ò�9Û™çææª½½½|WVVªk×®y~vÞNÎÞ¦aLª¸9“{ãÆ�3¿¯°tbôP¶4¯¯¯—-Î�=*ïïù@Øx­TPÒ&brš†1ió¦GØ:9g7ÏUóóóå¹êùóçÕ½{÷Þê¹
@Øèsccc¥Lª%9—Ðw9'ì�»í&''K'øzÊôô´çu@Ød	³iøRw=M#˜4„9��-ìvÛû,,,”ñu�tŽ÷|» "�]êy–iø’Æ/ç=ÏRØ.:ìžì¿µµõÚÎñ Â.@Hƒ©ÝÝÝRÅMã©4 êÔçv�Ë»µtŽ¯g‚§£üÉ™à Â.@�ª/ôÒÀe¿\è�wWØº5ì¶›™™)gzSíÍßNÞðv:djjªÚÞÞnmáK—‹üüÂ.Ðma·–®ÍéÞœÏ›nÎéê|7„]€·”F,íÍYòòe5gv�n»íMúòù3¯7Ç;Ò‘>s|ý=„]€.Ñ>v#ÕÜn»q||\.^'gi/û9+�èÓ‘>Ï]iÜ—Nõï2~@ØxKÙr—­wÙ‚—ó¸Ù’—­yÖàÝª½	º	¼	¾ç9’@Øx…l±[__/Õ�l½Ë<ëÐ™çÛlmNè­ŸoU{a Ã•†ÌÊµ6 »“&ç‹í¤„] gÈ úJÆÕ=2Æ(óË­ ìœ±Š«;(@w.sËÓ\+Ýï3Ï<sÍ­ ìœPÏ}L³)szG£Ñ(óÌSíÝÚÚ*¯[@Ø^Æe\P.’²5.c„¬@ïÉ\óTxSéÍ¼óÌ:OØÚ Â.0PD‹‹‹.ˆ ÜÈv�Þ—‹�z«[.‚lupD@ØzRÝÄd¿\ìhb0˜Ú›nllh>»@oÊxŠ\Ìä¢Æx
 j™“¾²²Ò+777§Ú»@wËÅJ.Zž<yR½xñ¢Z^^.5Ö€“2j.óÓ›Íf	¾™«žùêÖv�®‘‹“\¤¤Š›‹–\¼ä"ÆÚ pÙÒœ¹êõß‘lyöwv�K»#ëÖ­rQ’‹“\¤¸#ÀyìJ3«z‡Pš\Y@Ø:.¹øÈEH.Fœµ ô~ „]àBä"#”‹�\„X :MW@ØÎ].&rQñìÙ³r‘‘‹�\tX .ÃÉyíSSSÖv�³k4ÕÖÖV¹˜ÈEE^·. t‹‘‘‘jaa¡:::ªËËyÌÚ Â.ðÒmb¹hÈÅC*º. èvÓÓÓ¥Ê›´<(Õ_ëÂ.@511Q.r‘�3¹¹h°. ôâÑ›{÷î•s½9zsçÎAØMþøÏÏÏ·F;äâÀh úEš*îîî–NÎš*‚°€ñññ27ü=zTÝ¼y³ÌËµ6 ô£k×®µÆå=yòÄ¸<v�~’0;;;[=~ü¸:>>®VWW«ÑÑQkÀÀý-l6›å†onüú[Â.ÐÃw³WVVJÀÝÛÛ+w³Uqt	¹õ.§„ß„`AØzäœR¶(×ç”²uÙº À§e;snç†p¶9g»sn[v�.’æRí(Ó|Ê™$ 8›4°ÊâÜ(Nc«Ü8¶. ì—ÈlA 8ßjoFåÆqn ›V Â.p�FFFª………êðð°ÈËyÌÚ ÀùÉäz}n,›CÂ.ÐÁ?º>ôG .é&óÑÑ‘›Ì ì�ÚNuåÊk —`jjªu|hssÓñ!v�7•Êu£ŒtVÖ( ºGn</--UÏž=+7¤ïÞ½[[v�—Uqë™�k t¿Ü�ÞÙÙi�üKggëÂ.ð×ÿ?Ü~uuµ\Ãí 7¥ksnTgfïÓ§O«Û·oÂ.ž„Ù›7o–-Ê¹¼¶¶V¶.[ è�¿ñ¹�ío<»0Pw}ïß¿ßºë;??ï®/ Ø½»Ð›fffÊyžtoÌÌ>çy `pœìË±²²¢/»Ð»2ƒ/�3“/³ùtj ²¥y}}½5q![žU{AØ…žÐh4Êì½z_^·. ÀÉjoŽ3åXÓóçÏ«{÷î•ãNÖ„]è*©Ø¦r{ppP*¹©èfŸµ ^grr²sÊ�ò{šžž¶. ìÂåÊÙÛÌÔ«ÿ8eÖžu ÞöæùÂÂB9þTß<Ï±(kÂ.\Ø¶£ÌÎË¶£tUÎL=ÛŽ €ó>µµµåX»ÐyccceV^Jd|€† @§åXTÝð2Ç¥4¼aÎEÂlfâÕƒá3+/3ó¬ pÑNŽ2œ˜˜°. ìÂ›Éì»lOÎ6åÌÄËl¼l_¶6 ÀeËñ©toÎuJŽU¥«³ëvá•Ò`jww·TqÓx*¨¬ Ð­;Ðr¬*ózsí’ãV™ãkmv�O�…ÉŒ»ýýýrÆÝQ  —ä˜UŽ[—]i9†¥·Â.¨©©©j{{»Õå03î¬ ÐëÕÞÝÞ_ýFva@dV]ûüº¼l~ Ð�²¥9[›z³ÕÙ$	„]èC©Ú¦kaª¸©æNOO[ ` äxVšX¥™UšZÝ¿¿4¹²6»ÐOì9�›®…žØ€A–æ›u cŒÒœÓº ìBmÙY__/]	ë-;Ö ào†‡‡KSÎƒƒƒr´+Í:Ó´ÓÚ ìB—9­CfåZ €Wk4¥Ygª½[[[åuë‚°—,�V›} €w—¦�©ð¦Ò›fžiä™
°µAØ…¬â  Ð9iæY�hÌ_#v¡ƒÒ\*M¦Òl*M§Ò|*M¨¬ @ç¯¿ö÷÷]!ì‚;‹  ý¥}gÝÆÆ†�u»ð¶gF� è2é™²²²Òê™277§Ú‹°¯“ªmÝ0Õ\Ý  ºS=£Ùl¶¦aŒŽŽZ„]¨åN`æ¼åHÎƒ˜ó Ð[²¥9MC³Å9á7[žMÈ@Øe`]¿~½œ÷È“âÎÎNuãÆë ÐãEŒlkN3Ñ/^TËËËeÛ³µAØe`ž Ÿ<yâ	 @a„]z[ÎoäG½µ%ç;lm èi2êÈÂ.}×´àÖ­[%Ü&äæ‡¦  ƒëd3Ò©©)ë‚°KïÈðñlOÎ6åœ×ÐŽ €v3™Ñ’íc&ó˜µAØ¥+åFÎcäN]Îgäœ†u àU¦§§K•7×�<(Õ_ë‚°Ë¥Ëy‹œ»È]¹œÃÈyŒœË°6  ¼éuå½{÷Ê¹ÞúºÒî@„].\£Ñ¨¶¶¶Ê¸œ»ÈëÖ €óÚ1¸»»[ú¾Ø1ˆ°KÇÕ�ôr®"•ÜTt�­   S2¢²î“Ñ•zÁ ìr®&&&Êù‰Tqs&7ç*¬  %S>2ºÒ”„]ÞYî˜ÍÏÏ—nÊ¹“–óé²lm  ¸L	¹	»	½	¿	Á	ÃÖa—Wo=y<zô¨ºyó¦'  º²8“mÍ{{{¥8“íÎÙölm„]Á©ÛBŽ��«ÕÕUÛB  èi`•FVuÁ&®¬‹°Ë€ø_YY)7wÄrgL €^®öÞ¹s§Œ.Ê#Gñ„]LîtåŽWÝÊ=[—­  ýdrr²Õdu{{[“Ua—~•;ZíCºÓ|JÛv  ú]Fe.,,´Ægæeã3…]ú@î`åNVîhåÎVîpY  ÑÔÔTëÚxssÓµ±°K/ß½
w¯  ào®\¹R---UÏž=+»ïÞ½[[aç   ?¤ŸÍÎÎN¹†N?›tv¶.Â.]à´Žs¹Sem  àìÒã&³z3³÷éÓ§ÕíÛ·õ¸v¹é l–  œ¯Œâ¼yófÕl6ËµöÚÚšé%Â.QÅÍ,ÜÌÄÍlÜÜyÊ¬\k  çott´Z]]-×Þ	¿³³³%[aÿ“ @ß�VVV�„]ÞuûD¶(Û>  Ýsœp}}½uœ0×ì
QÂ.g<Ÿ&SõÁøùùyã  «½¹VÏ5{Ý(6×òÖFØå„™™™VËóŒÒò  zCûÐ\Ó*ì¼‘‘‘2Ìúèè¨:<<4Ì  zX®åÊµ}®ñs­Ÿk~k#ìŒF£Qmnn–;?ùo^·.  Ð_×ü[[[®ù…ÝÁ¸Ë“ÊíÁÁAë.Ï•+W¬  ô±\ó×»9“ìævûFÎÞnll´öïß¸qÃº  À :Ù§gbbÂº»½¥žÃ•Îléª¼¼¼¬3  P˜À"ìöœ±±±273·šÍ¦™[  ÀK%+$3d^o2D²DæøZa·k~AgggK¸Í/èêêj5::jm  €3K†H–8>>®öööJÆP8v/Åµk×Êöäl=È/c¶-Ûz   œG1-#ÁW1MØ½0i0µ»»[ª¸i<•TÖ  8oÙÒœ­Í	½Ùêì˜¤°{îêváÏŸ?¯ö÷÷K»pU\  à"${¤‰UÝ ÷þýûà
»ï&ƒŸ···[ƒ '''­  pi²³4c‹Œ6vßØÈÈHµ°°P–ÁÏy9�Y   [—§%·d'jv¤
»~9>#UÛúIª¹ÓÓÓÖ  è‰©Ù‰š,³µµU^ví}oí}ÏyÜv¶÷  èÕ]ª‹‹‹¥Ò›�ªÙ¥š
°°;@ÒÕl}}½tT®»šùŸ  èÙ©Z÷ÊÖAé?4�a÷´yU™•ë   _eçjv°Ö“e²³µŸ'ËTØM M°MÀMÐMà5›
  4ÙÑš�­Ùáº±±Qv¼
»=XÅmÿAfs?þ   Þ¦ ¸²²Ò*ÎÍÍõMµ·oÃn{‰>M§ú½D  ð®G=›Ífë¨çèè¨°ëð5  @+;b³36á7;e{ñøg_„]mµ  ÎWvÆf[svÊ¾xñ¢Z^^î©Æ¾=vSµ­&§š;È“  :åúõë¥‘Uª½;;;Õ�7„ÝNÜ]¸{÷ni•�ó¸KKKÕ•+Wü  tXvÐöJë™°Û‹w   úÕÉ�¶SSSÂî›îòäIOî  èwé¡”¾IéŸT÷PÊcÂî)Òâ:­®ëî_i�Ý‹Ý¿   I7MÇéš°›0{ëÖ­nrÓêº×ç:  ¢œã½wï^9×›ó½9ç›�»v¯^½Z¶'g›rZZgÛòE/   �‘~K»»»¥¨™>LéÇÔ×a7ßpM¥¼}‘ß0   /ý—êBgú2uºÐy¡a7¥ì´¦>::j•²ÓºÚ  `0äkú2uúë…„ÝF£Qmmm•*nZSçu?d  €ÁÖÉæÄ»õ°á´žN%7Ýnh?  @w©ÇÎîíí�ÛØÙs»¥Åtª¸9“›ÖÓ~x   œEú9¥¯Sª½�=*ýž.-ì&…ÏÏÏ—nÊIái1�.Ë~P   ¼mÎ¼sçNé÷”Foš3ß)ìŽ��—ÃÄuâ¾yóæ¹í¯  €˜œœlí ÞÞÞ>Óâ7»í�³Ž��ËaâNtÎ  €véµ°°Ðê•—_ÖêÌa7‡ƒWVVJÀÍ¡áVÅ  à2dÊOª¼õÔŸTß(ìæ0p¶(g«r	gë²…   \¹r¥LÿyöìY9ß›©@™tjØÍ¡ßþÍ!à¼qšOåp°…   [¥X›©@©ö~*ìæ�o]Îáß“e`   èv)àµð�Wð  €^0”ÑAgmÝ   =vÿýßÿý   è'ÿN||6¦ Ú|    IEND®B`‚<?php

/**
 * Auto-register "*.theme.php" files.
 *
 * @mixinName theme-php
 * @mixinVersion 1.0.0
 *
 * @param CRM_Extension_MixInfo $mixInfo
 *   On newer deployments, this will be an instance of MixInfo. On older deployments, Civix may polyfill with a work-a-like.
 * @param \CRM_Extension_BootCache $bootCache
 *   On newer deployments, this will be an instance of MixInfo. On older deployments, Civix may polyfill with a work-a-like.
 */
return function ($mixInfo, $bootCache) {

  /**
   * @param \Civi\Core\Event\GenericHookEvent $e
   * @see CRM_Utils_Hook::themes()
   */
  Civi::dispatcher()->addListener('hook_civicrm_themes', function ($e) use ($mixInfo) {
    // When deactivating on a polyfill/pre-mixin system, listeners may not cleanup automatically.
    if (!$mixInfo->isActive()) {
      return;
    }
    $files = (array) glob($mixInfo->getPath('*.theme.php'));
    foreach ($files as $file) {
      $themeMeta = include $file;
      if (empty($themeMeta['name'])) {
        $themeMeta['name'] = preg_replace(':\.theme\.php$:', '', basename($file));
      }
      if (empty($themeMeta['ext'])) {
        $themeMeta['ext'] = $mixInfo->longName;
      }
      $e->themes[$themeMeta['name']] = $themeMeta;
    }
  });

};
<?php

/**
 * When deploying on systems that lack mixin support, fake it.
 *
 * @mixinFile polyfill.php
 *
 * This polyfill does some (persnickity) deduplication, but it doesn't allow upgrades or shipping replacements in core.
 *
 * Note: The polyfill.php is designed to be copied into extensions for interoperability. Consequently, this file is
 * not used 'live' by `civicrm-core`. However, the file does need a canonical home, and it's convenient to keep it
 * adjacent to the actual mixin files.
 *
 * @param string $longName
 * @param string $shortName
 * @param string $basePath
 */
return function ($longName, $shortName, $basePath) {
  // Construct imitations of the mixin services. These cannot work as well (e.g. with respect to
  // number of file-reads, deduping, upgrading)... but they should be OK for a few months while
  // the mixin services become available.

  // List of active mixins; deduped by version
  $mixinVers = [];
  foreach ((array) glob($basePath . '/mixin/*.mixin.php') as $f) {
    [$name, $ver] = explode('@', substr(basename($f), 0, -10));
    if (!isset($mixinVers[$name]) || version_compare($ver, $mixinVers[$name], '>')) {
      $mixinVers[$name] = $ver;
    }
  }
  $mixins = [];
  foreach ($mixinVers as $name => $ver) {
    $mixins[] = "$name@$ver";
  }

  // Imitate CRM_Extension_MixInfo.
  $mixInfo = new class() {

    /**
     * @var string
     */
    public $longName;

    /**
     * @var string
     */
    public $shortName;

    public $_basePath;

    public function getPath($file = NULL) {
      return $this->_basePath . ($file === NULL ? '' : (DIRECTORY_SEPARATOR . $file));
    }

    public function isActive() {
      return \CRM_Extension_System::singleton()->getMapper()->isActiveModule($this->shortName);
    }

  };
  $mixInfo->longName = $longName;
  $mixInfo->shortName = $shortName;
  $mixInfo->_basePath = $basePath;

  // Imitate CRM_Extension_BootCache.
  $bootCache = new class() {

    public function define($name, $callback) {
      $envId = \CRM_Core_Config_Runtime::getId();
      $oldExtCachePath = \Civi::paths()->getPath("[civicrm.compile]/CachedExtLoader.{$envId}.php");
      $stat = stat($oldExtCachePath);
      $file = Civi::paths()->getPath('[civicrm.compile]/CachedMixin.' . md5($name . ($stat['mtime'] ?? 0)) . '.php');
      if (file_exists($file)) {
        return include $file;
      }
      else {
        $data = $callback();
        file_put_contents($file, '<' . "?php\nreturn " . var_export($data, 1) . ';');
        return $data;
      }
    }

  };

  // Imitate CRM_Extension_MixinLoader::run()
  // Parse all live mixins before trying to scan any classes.
  global $_CIVIX_MIXIN_POLYFILL;
  foreach ($mixins as $mixin) {
    // If the exact same mixin is defined by multiple exts, just use the first one.
    if (!isset($_CIVIX_MIXIN_POLYFILL[$mixin])) {
      $_CIVIX_MIXIN_POLYFILL[$mixin] = include_once $basePath . '/mixin/' . $mixin . '.mixin.php';
    }
  }
  foreach ($mixins as $mixin) {
    // If there's trickery about installs/uninstalls/resets, then we may need to register a second time.
    if (!isset(\Civi::$statics[$longName][$mixin])) {
      \Civi::$statics[$longName][$mixin] = 1;
      $func = $_CIVIX_MIXIN_POLYFILL[$mixin];
      $func($mixInfo, $bootCache);
    }
  }
};
<?php

/**
 * Auto-register entity declarations from `xml/schema/...*.entityType.php`.
 *
 * @mixinName entity-types-php
 * @mixinVersion 1.0.0
 * @since 5.57
 *
 * @param CRM_Extension_MixInfo $mixInfo
 *   On newer deployments, this will be an instance of MixInfo. On older deployments, Civix may polyfill with a work-a-like.
 * @param \CRM_Extension_BootCache $bootCache
 *   On newer deployments, this will be an instance of MixInfo. On older deployments, Civix may polyfill with a work-a-like.
 */
return function ($mixInfo, $bootCache) {

  /**
   * @param \Civi\Core\Event\GenericHookEvent $e
   * @see CRM_Utils_Hook::entityTypes()
   */
  Civi::dispatcher()->addListener('hook_civicrm_entityTypes', function ($e) use ($mixInfo) {
    // When deactivating on a polyfill/pre-mixin system, listeners may not cleanup automatically.
    if (!$mixInfo->isActive() || !is_dir($mixInfo->getPath('xml/schema/CRM'))) {
      return;
    }

    $files = (array) glob($mixInfo->getPath('xml/schema/CRM/*/*.entityType.php'));
    foreach ($files as $file) {
      $entities = include $file;
      foreach ($entities as $entity) {
        $e->entityTypes[$entity['class']] = $entity;
      }
    }
  });

};
<?php

/**
 * Auto-register "ang/*.ang.php" files.
 *
 * @mixinName ang-php
 * @mixinVersion 1.0.0
 *
 * @param CRM_Extension_MixInfo $mixInfo
 *   On newer deployments, this will be an instance of MixInfo. On older deployments, Civix may polyfill with a work-a-like.
 * @param \CRM_Extension_BootCache $bootCache
 *   On newer deployments, this will be an instance of MixInfo. On older deployments, Civix may polyfill with a work-a-like.
 */
return function ($mixInfo, $bootCache) {

  /**
   * @param \Civi\Core\Event\GenericHookEvent $e
   * @see CRM_Utils_Hook::angularModules()
   */
  Civi::dispatcher()->addListener('hook_civicrm_angularModules', function ($e) use ($mixInfo) {
    // When deactivating on a polyfill/pre-mixin system, listeners may not cleanup automatically.
    if (!$mixInfo->isActive() || !is_dir($mixInfo->getPath('ang'))) {
      return;
    }

    $files = (array) glob($mixInfo->getPath('ang/*.ang.php'));
    foreach ($files as $file) {
      $name = preg_replace(':\.ang\.php$:', '', basename($file));
      $module = include $file;
      if (empty($module['ext'])) {
        $module['ext'] = $mixInfo->longName;
      }
      $e->angularModules[$name] = $module;
    }
  });

};
<?php

/**
 * Auto-register "**.mgd.php" files.
 *
 * @mixinName mgd-php
 * @mixinVersion 1.0.0
 *
 * @param CRM_Extension_MixInfo $mixInfo
 *   On newer deployments, this will be an instance of MixInfo. On older deployments, Civix may polyfill with a work-a-like.
 * @param \CRM_Extension_BootCache $bootCache
 *   On newer deployments, this will be an instance of MixInfo. On older deployments, Civix may polyfill with a work-a-like.
 */
return function ($mixInfo, $bootCache) {

  /**
   * @param \Civi\Core\Event\GenericHookEvent $e
   * @see CRM_Utils_Hook::managed()
   */
  Civi::dispatcher()->addListener('hook_civicrm_managed', function ($event) use ($mixInfo) {
    // When deactivating on a polyfill/pre-mixin system, listeners may not cleanup automatically.
    if (!$mixInfo->isActive()) {
      return;
    }

    $mgdFiles = CRM_Utils_File::findFiles($mixInfo->getPath(), '*.mgd.php');
    sort($mgdFiles);
    foreach ($mgdFiles as $file) {
      $es = include $file;
      foreach ($es as $e) {
        if (empty($e['module'])) {
          $e['module'] = $mixInfo->longName;
        }
        if (empty($e['params']['version'])) {
          $e['params']['version'] = '3';
        }
        $event->entities[] = $e;
      }
    }
  });

};
<?php

/**
 * Auto-register "**.mgd.php" files.
 *
 * @mixinName mgd-php
 * @mixinVersion 1.0.0
 *
 * @param CRM_Extension_MixInfo $mixInfo
 *   On newer deployments, this will be an instance of MixInfo. On older deployments, Civix may polyfill with a work-a-like.
 * @param \CRM_Extension_BootCache $bootCache
 *   On newer deployments, this will be an instance of MixInfo. On older deployments, Civix may polyfill with a work-a-like.
 */
return function ($mixInfo, $bootCache) {

  /**
   * @param \Civi\Core\Event\GenericHookEvent $e
   * @see CRM_Utils_Hook::managed()
   */
  Civi::dispatcher()->addListener('hook_civicrm_managed', function ($event) use ($mixInfo) {
    // When deactivating on a polyfill/pre-mixin system, listeners may not cleanup automatically.
    if (!$mixInfo->isActive()) {
      return;
    }

    $mgdFiles = CRM_Utils_File::findFiles($mixInfo->getPath(), '*.mgd.php');
    sort($mgdFiles);
    foreach ($mgdFiles as $file) {
      $es = include $file;
      foreach ($es as $e) {
        if (empty($e['module'])) {
          $e['module'] = $mixInfo->longName;
        }
        if (empty($e['params']['version'])) {
          $e['params']['version'] = '3';
        }
        $event->entities[] = $e;
      }
    }
  });

};
<?php

/**
 * Auto-register "templates/" folder.
 *
 * @mixinName smarty-v2
 * @mixinVersion 1.0.1
 * @since 5.59
 *
 * @param CRM_Extension_MixInfo $mixInfo
 *   On newer deployments, this will be an instance of MixInfo. On older deployments, Civix may polyfill with a work-a-like.
 * @param \CRM_Extension_BootCache $bootCache
 *   On newer deployments, this will be an instance of MixInfo. On older deployments, Civix may polyfill with a work-a-like.
 */
return function ($mixInfo, $bootCache) {
  $dir = $mixInfo->getPath('templates');
  if (!file_exists($dir)) {
    return;
  }

  $register = function() use ($dir) {
    // This implementation has a theoretical edge-case bug on older versions of CiviCRM where a template could
    // be registered more than once.
    CRM_Core_Smarty::singleton()->addTemplateDir($dir);
  };

  // Let's figure out what environment we're in -- so that we know the best way to call $register().

  if (!empty($GLOBALS['_CIVIX_MIXIN_POLYFILL'])) {
    // Polyfill Loader (v<=5.45): We're already in the middle of firing `hook_config`.
    if ($mixInfo->isActive()) {
      $register();
    }
    return;
  }

  if (CRM_Extension_System::singleton()->getManager()->extensionIsBeingInstalledOrEnabled($mixInfo->longName)) {
    // New Install, Standard Loader: The extension has just been enabled, and we're now setting it up.
    // System has already booted. New templates may be needed for upcoming installation steps.
    $register();
    return;
  }

  // Typical Pageview, Standard Loader: Defer the actual registration for a moment -- to ensure that Smarty is online.
  \Civi::dispatcher()->addListener('hook_civicrm_config', function() use ($mixInfo, $register) {
    if ($mixInfo->isActive()) {
      $register();
    }
  });

};
<?php

/**
 * Auto-register "xml/case/*.xml" files.
 *
 * @mixinName case-xml
 * @mixinVersion 1.0.0
 *
 * @param CRM_Extension_MixInfo $mixInfo
 *   On newer deployments, this will be an instance of MixInfo. On older deployments, Civix may polyfill with a work-a-like.
 * @param \CRM_Extension_BootCache $bootCache
 *   On newer deployments, this will be an instance of MixInfo. On older deployments, Civix may polyfill with a work-a-like.
 */
return function ($mixInfo, $bootCache) {

  /**
   * @param \Civi\Core\Event\GenericHookEvent $e
   * @see CRM_Utils_Hook::caseTypes()
   */
  Civi::dispatcher()->addListener('hook_civicrm_caseTypes', function ($e) use ($mixInfo) {
    // When deactivating on a polyfill/pre-mixin system, listeners may not cleanup automatically.

    if (!$mixInfo->isActive() || !is_dir($mixInfo->getPath('xml/case'))) {
      return;
    }

    foreach ((array) glob($mixInfo->getPath('xml/case/*.xml')) as $file) {
      $name = preg_replace('/\.xml$/', '', basename($file));
      if ($name != CRM_Case_XMLProcessor::mungeCaseType($name)) {
        $errorMessage = sprintf("Case-type file name is malformed (%s vs %s)", $name, CRM_Case_XMLProcessor::mungeCaseType($name));
        throw new CRM_Core_Exception($errorMessage);
      }
      $e->caseTypes[$name] = [
        'module' => $mixInfo->longName,
        'name' => $name,
        'file' => $file,
      ];
    }
  });

};
<?php

/**
 * Auto-register "xml/Menu/*.xml" files.
 *
 * @mixinName menu-xml
 * @mixinVersion 1.0.0
 *
 * @param CRM_Extension_MixInfo $mixInfo
 *   On newer deployments, this will be an instance of MixInfo. On older deployments, Civix may polyfill with a work-a-like.
 * @param \CRM_Extension_BootCache $bootCache
 *   On newer deployments, this will be an instance of MixInfo. On older deployments, Civix may polyfill with a work-a-like.
 */
return function ($mixInfo, $bootCache) {

  /**
   * @param \Civi\Core\Event\GenericHookEvent $e
   * @see CRM_Utils_Hook::xmlMenu()
   */
  Civi::dispatcher()->addListener('hook_civicrm_xmlMenu', function ($e) use ($mixInfo) {
    if (!$mixInfo->isActive()) {
      return;
    }

    $files = (array) glob($mixInfo->getPath('xml/Menu/*.xml'));
    foreach ($files as $file) {
      $e->files[] = $file;
    }
  });

};
<?php

/**
 * Auto-register "afformEntities/*.php" files.
 *
 * @mixinName afform-entity-php
 * @mixinVersion 1.0.0
 * @since 5.50
 *
 * @param CRM_Extension_MixInfo $mixInfo
 *   On newer deployments, this will be an instance of MixInfo. On older deployments, Civix may polyfill with a work-a-like.
 * @param \CRM_Extension_BootCache $bootCache
 *   On newer deployments, this will be an instance of MixInfo. On older deployments, Civix may polyfill with a work-a-like.
 */
return function ($mixInfo, $bootCache) {

  /**
   * @param \Civi\Core\Event\GenericHookEvent $e
   */
  Civi::dispatcher()->addListener('civi.afform_admin.metadata', function ($e) use ($mixInfo) {
    // When deactivating on a polyfill/pre-mixin system, listeners may not cleanup automatically.
    if (!$mixInfo->isActive() || !is_dir($mixInfo->getPath('afformEntities'))) {
      return;
    }

    $files = (array) glob($mixInfo->getPath('afformEntities/*.php'));
    foreach ($files as $file) {
      $entityInfo = include $file;
      $entityName = basename($file, '.php');
      $apiInfo = \Civi\AfformAdmin\AfformAdminMeta::getApiEntity($entityInfo['entity'] ?? $entityName);
      // Skip disabled contact types & entities from disabled components/extensions
      if (!$apiInfo) {
        continue;
      }
      $entityInfo += $apiInfo;
      $e->entities[$entityName] = $entityInfo;
    }
  });

};
<?php

/**
 * Auto-register "settings/*.setting.php" files.
 *
 * @mixinName setting-php
 * @mixinVersion 1.0.0
 *
 * @param CRM_Extension_MixInfo $mixInfo
 *   On newer deployments, this will be an instance of MixInfo. On older deployments, Civix may polyfill with a work-a-like.
 * @param \CRM_Extension_BootCache $bootCache
 *   On newer deployments, this will be an instance of MixInfo. On older deployments, Civix may polyfill with a work-a-like.
 */
return function ($mixInfo, $bootCache) {

  /**
   * @param \Civi\Core\Event\GenericHookEvent $e
   * @see CRM_Utils_Hook::alterSettingsFolders()
   */
  Civi::dispatcher()->addListener('hook_civicrm_alterSettingsFolders', function ($e) use ($mixInfo) {
    // When deactivating on a polyfill/pre-mixin system, listeners may not cleanup automatically.
    if (!$mixInfo->isActive()) {
      return;
    }

    $settingsDir = $mixInfo->getPath('settings');
    if (!in_array($settingsDir, $e->settingsFolders) && is_dir($settingsDir)) {
      $e->settingsFolders[] = $settingsDir;
    }
  });

};
<?php

/**
 * Scan for files which implement common Civi-PHP interfaces.
 *
 * Specifically, this listens to `hook_scanClasses` and reports any classes with Civi-related
 * interfaces (eg `CRM_Foo_BarInterface` or `Civi\Foo\BarInterface`). For example:
 *
 *   - \Civi\Core\HookInterface
 *   - \Civi\Test\ExampleDataInterface
 *   - \Civi\WorkflowMessage\WorkflowMessageInterface
 *
 * If you are adding this to an existing extension, take care that you meet these assumptions:
 *
 *   - Classes live in 'CRM_' ('./CRM/**.php') or 'Civi\' ('./Civi/**.php').
 *   - Class files only begin with uppercase letters.
 *   - Class files only contain alphanumerics.
 *   - Class files never have multiple dots in the name. ("CRM/Foo.php" is a class; "CRM/Foo.bar.php" is not).
 *   - The ONLY files which match these patterns are STRICTLY class files.
 *   - The ONLY classes which match these patterns are SAFE/INTENDED for use with `hook_scanClasses`.
 *
 * To minimize unintended activations, this only loads Civi interfaces. It skips other interfaces.
 *
 * @mixinName scan-classes
 * @mixinVersion 1.0.0
 * @since 5.52
 *
 * @param CRM_Extension_MixInfo $mixInfo
 *   On newer deployments, this will be an instance of MixInfo. On older deployments, Civix may polyfill with a work-a-like.
 * @param \CRM_Extension_BootCache $bootCache
 *   On newer deployments, this will be an instance of MixInfo. On older deployments, Civix may polyfill with a work-a-like.
 */

/**
 * @param \CRM_Extension_MixInfo $mixInfo
 * @param \CRM_Extension_BootCache $bootCache
 */
return function ($mixInfo, $bootCache) {
  /**
   * @param \Civi\Core\Event\GenericHookEvent $event
   */
  Civi::dispatcher()->addListener('hook_civicrm_scanClasses', function ($event) use ($mixInfo) {
    if (!$mixInfo->isActive()) {
      return;
    }

    $cache = \Civi\Core\ClassScanner::cache('structure');
    $cacheKey = $mixInfo->longName;
    $all = $cache->get($cacheKey);
    if ($all === NULL) {
      $baseDir = CRM_Utils_File::addTrailingSlash($mixInfo->getPath());
      $all = [];

      \Civi\Core\ClassScanner::scanFolders($all, $baseDir, 'CRM', '_');
      \Civi\Core\ClassScanner::scanFolders($all, $baseDir, 'Civi', '\\');
      if (defined('CIVICRM_TEST')) {
        \Civi\Core\ClassScanner::scanFolders($all, "$baseDir/tests/phpunit", 'CRM', '_');
        \Civi\Core\ClassScanner::scanFolders($all, "$baseDir/tests/phpunit", 'Civi', '\\');
      }
      $cache->set($cacheKey, $all, \Civi\Core\ClassScanner::TTL);
    }

    $event->classes = array_merge($event->classes, $all);
  });

};
<?php

/**
 * The Mixlib class is a utility for downloading/listing available mixins.
 * It is used by some test-infra and by civix.
 */
class Mixlib {

  /**
   * Local path to the mixlib folder.
   *
   * @var string|null
   */
  private $mixlibDir;

  /**
   * Public URL of the mixlib folder.
   *
   * @var string|null
   */
  private $mixlibUrl;

  private $cache = [];

  /**
   * Mixlib constructor.
   *
   * @param string|NULL $mixlibDir
   *   Ex: Civi::paths()->getPath('[civicrm.root]/mixin')
   * @param string|NULL $mixlibUrl
   *   Ex: "https://raw.githubusercontent.com/civicrm/civicrm-core/5.45/mixin"
   *   Ex: "https://raw.githubusercontent.com/totten/civicrm-core/master-mix-dec/mixin"
   */
  public function __construct(?string $mixlibDir = NULL, ?string $mixlibUrl = NULL) {
    $this->mixlibDir = $mixlibDir ?: dirname(__DIR__, 3) . '/mixin';
    $this->mixlibUrl = $mixlibUrl;
  }

  public function getList(): array {
    if ($this->mixlibDir === NULL || !file_exists($this->mixlibDir)) {
      throw new \RuntimeException("Cannot get list of available mixins");
    }

    if (isset($this->cache['getList'])) {
      return $this->cache['getList'];
    }

    $dirs = (array) glob($this->mixlibDir . '/*@*');
    $mixinNames = [];
    foreach ($dirs as $dir) {
      if (is_dir($dir)) {
        $mixinNames[] = basename($dir);
      }
    }
    sort($mixinNames);
    $this->cache['getList'] = $mixinNames;
    return $mixinNames;
  }

  /**
   * @param string $mixin
   *
   * @return array
   *   Item with keys:
   *   - mixinName: string, eg 'mgd-php'
   *   - mixinVersion: string, eg '1.0.2'
   *   - mixinConstraint: string, eg 'mgd-php@1.0.2'
   *   - mixinFile: string, eg 'mgd-php@1.0.2.mixin.php'
   *   - src: string, unevaluated PHP source
   */
  public function get(string $mixin) {
    if (isset($this->cache["parsed:$mixin"])) {
      return $this->cache["parsed:$mixin"];
    }

    $phpCode = $this->getSourceCode($mixin);
    $mixinSpec = $this->parseString($phpCode);
    $mixinSpec['mixinName'] = $mixinSpec['mixinName'] ?? preg_replace(';@.*$;', '', $mixin);

    $parts = explode('@', $mixin);
    $effectiveVersion = !empty($mixinSpec['mixinVersion']) ? $mixinSpec['mixinVersion'] : ($parts[1] ?? '');
    if ($effectiveVersion) {
      $mixinSpec = array_merge([
        'mixinConstraint' => $mixinSpec['mixinName'] . '@' . $effectiveVersion,
        'mixinFile' => $mixinSpec['mixinName'] . '@' . $effectiveVersion . '.mixin.php',
      ], $mixinSpec);
    }
    else {
      $mixinSpec = array_merge([
        'mixinFile' => $mixinSpec['mixinName'] . '.mixin.php',
      ], $mixinSpec);
    }
    $mixinSpec['src'] = $phpCode;
    $this->cache["parsed:$mixin"] = $mixinSpec;

    return $this->cache["parsed:$mixin"];
  }

  /**
   * Consolidate and retrieve the listed mixins.
   *
   * @param array $mixinConstraints
   *   Ex: ['foo@1.0', 'bar@1.2', 'bar@1.3']
   * @return array
   *   Ex: ['foo@1.0' => array, 'bar@1.3' => array]
   */
  public function consolidate(array $mixinConstraints): array {
    // Find and remove duplicate constraints. Pick tightest constraint.
    // array(string $mixinName => string $mixinVersion)
    $preferredVersions = [];
    foreach ($mixinConstraints as $mixinName) {
      [$name, $version] = explode('@', $mixinName);
      if (!isset($preferredVersions[$name])) {
        $preferredVersions[$name] = $version;
      }
      elseif (version_compare($version, $preferredVersions[$name], '>=')) {
        $preferredVersions[$name] = $version;
      }
    }

    // Resolve current versions matching constraint.
    $result = [];
    foreach ($preferredVersions as $mixinName => $mixinVersion) {
      $result[] = $mixinName . '@' . $mixinVersion;
    }
    sort($result);
    return $result;
  }

  /**
   * Consolidate and retrieve the listed mixins.
   *
   * @param array $mixinConstraints
   *   Ex: ['foo@1.0', 'bar@1.2', 'bar@1.3']
   * @return array
   *   Ex: ['foo@1.0' => array, 'bar@1.3' => array]
   */
  public function resolve(array $mixinConstraints): array {
    $mixinConstraints = $this->consolidate($mixinConstraints);

    $result = [];
    foreach ($mixinConstraints as $mixinConstraint) {
      [$expectName, $expectVersion] = explode('@', $mixinConstraint);
      $mixin = $this->get($mixinConstraint);
      $this->assertValid($mixin);
      if (!version_compare($mixin['mixinVersion'], $expectVersion, '>=') || $mixin['mixinName'] !== $expectName) {
        throw new \RuntimeException(sprintf("Received incompatible version (expected=\"%s@%s\", actual=\"%s@%s\")", $expectName, $expectVersion, $mixin['mixinName'], $mixin['mixinVersion']));
      }
      $result[$mixin['mixinConstraint']] = $mixin;
    }
    return $result;
  }

  /**
   * @param string $mixin
   *  Ex: 'foo@1.2.3', 'foo-bar@4.5.6', 'polyfill',
   * @return string
   */
  protected function getSourceCode(string $mixin): string {
    if ($mixin === 'polyfill') {
      $file = 'polyfill.php';
    }
    elseif (preg_match(';^([-\w]+)@(\d+)([\.\d]+)?;', $mixin, $m)) {
      // Get the last revision within the major series.
      $file = sprintf('%s@%s/mixin.php', $m[1], $m[2]);
    }
    else {
      throw new \RuntimeException("Failed to parse mixin name ($mixin)");
    }

    if ($this->mixlibDir && file_exists($this->mixlibDir . '/' . $file)) {
      return file_get_contents($this->mixlibDir . '/' . $file);
    }

    if ($this->mixlibUrl) {
      $url = $this->mixlibUrl . '/' . $file;
      $download = file_get_contents($url);
      if (!empty($download)) {
        $this->cache["src:$mixin"] = $download;
        return $download;
      }
    }

    throw new \RuntimeException("Failed to locate $file (mixlibDir={$this->mixlibDir}, mixlibUrl={$this->mixlibUrl})");
  }

  public function assertValid(array $mixin): array {
    if (empty($mixin['mixinVersion'])) {
      throw new \RuntimeException("Invalid {$mixin["file"]}. There is no @mixinVersion annotation.");
    }
    if (empty($mixin['mixinVersion'])) {
      throw new \RuntimeException("Invalid {$mixin["file"]}. There is no @mixinName annotation.");
    }
    return $mixin;
  }

  /**
   * @param string $phpCode
   * @return array
   */
  protected function parseString(string $phpCode): array {
    $commmentTokens = [T_DOC_COMMENT, T_COMMENT, T_FUNC_C, T_METHOD_C, T_TRAIT_C, T_CLASS_C];
    $mixinSpec = [];
    foreach (token_get_all($phpCode) as $token) {
      if (is_array($token) && in_array($token[0], $commmentTokens)) {
        $mixinSpec = $this->parseComment($token[1]);
        break;
      }
    }
    return $mixinSpec;
  }

  protected function parseComment(string $comment): array {
    $info = [];
    $param = NULL;
    foreach (preg_split("/((\r?\n)|(\r\n?))/", $comment) as $num => $line) {
      if (!$num || strpos($line, '*/') !== FALSE) {
        continue;
      }
      $line = ltrim(trim($line), '*');
      if (strlen($line) && $line[0] === ' ') {
        $line = substr($line, 1);
      }
      if (strpos(ltrim($line), '@') === 0) {
        $words = explode(' ', ltrim($line, ' @'));
        $key = array_shift($words);
        $param = NULL;
        if ($key == 'var') {
          $info['type'] = explode('|', $words[0]);
        }
        elseif ($key == 'return') {
          $info['return'] = explode('|', $words[0]);
        }
        elseif ($key == 'options' || $key == 'ui_join_filters') {
          $val = str_replace(', ', ',', implode(' ', $words));
          $info[$key] = explode(',', $val);
        }
        elseif ($key == 'throws' || $key == 'see') {
          $info[$key][] = implode(' ', $words);
        }
        elseif ($key == 'param' && $words) {
          $type = $words[0][0] !== '$' ? explode('|', array_shift($words)) : NULL;
          $param = rtrim(array_shift($words), '-:()/');
          $info['params'][$param] = [
            'type' => $type,
            'description' => $words ? ltrim(implode(' ', $words), '-: ') : '',
            'comment' => '',
          ];
        }
        else {
          // Unrecognized annotation, but we'll duly add it to the info array
          $val = implode(' ', $words);
          $info[$key] = strlen($val) ? $val : TRUE;
        }
      }
      elseif ($param) {
        $info['params'][$param]['comment'] .= $line . "\n";
      }
      elseif ($num == 1) {
        $info['description'] = ucfirst($line);
      }
      elseif (!$line) {
        if (isset($info['comment'])) {
          $info['comment'] .= "\n";
        }
        else {
          $info['comment'] = NULL;
        }
      }
      // For multi-line description.
      elseif (count($info) === 1 && isset($info['description']) && substr($info['description'], -1) !== '.') {
        $info['description'] .= ' ' . $line;
      }
      else {
        $info['comment'] = isset($info['comment']) ? "{$info['comment']}\n$line" : $line;
      }
    }
    if (isset($info['comment'])) {
      $info['comment'] = rtrim($info['comment']);
    }
    return $info;
  }

}
<?php

namespace CRM\CivixBundle;

/**
 * Use this trait if you want to delegate to an open-ended list of methods.
 *
 * For example, suppose you want a method "checkRequirements()" which is built on running
 * methods "checkRequirements_foo()","checkRequirements_bar()", etc.
 *
 * You could implement as:
 *
 *   use RunMethodsTrait;
 *   public function checkRequirements() {
 *     $this->runMethods('/^checkRequirements_/');
 *   }
 *   protected function checkRequirements_foo() { ... }
 *   protected function checkRequirements_bar() { ... }
 */
trait RunMethodsTrait
{
    /**
     *
     * Ex: [$results] = $this->runMethods(';foo.*;');
     * Ex: [$results, $skipped] = $this->runMethods(';foo.*;', ['val1', 'val2']);
     *
     * @param string $methodRegex
     * @param array $params
     *   A list of parameters to pass down to each method.
     * @return array
     *   Results of calling the methods.
     *   Some methods have opted-out of execution.
     *   Formally, the results are a tuple of `[$executed, $skipped]`.
     * @throws \ReflectionException
     */
    protected function runMethods(string $methodRegex, array $params = []) : array
    {
        $executed = [];
        $skipped = [];
        $class = new \ReflectionClass($this);
        foreach ($class->getMethods() as $method) {
            /** @var \ReflectionMethod $method */
            if (\preg_match($methodRegex, $method->getName())) {
                try {
                    $result = $method->invoke($this, ...$params);
                    $executed[$method->getName()] = $result;
                } catch (\CRM\CivixBundle\SkippedMethodException $e) {
                    $skipped[$method->getName()] = $method->getName();
                }
            }
        }
        return [$executed, $skipped];
    }
    /**
     * Assert that the current method is (or is not) applicable.
     *
     * @param bool $bool
     *   If TRUE, then proceed with normal execution.
     *
     *   If FALSE, raise an exception that will propagate back to the main `testSnapshot()` method.
     *   The next check will run.
     */
    protected function runsIf(bool $bool)
    {
        if (!$bool) {
            throw new \CRM\CivixBundle\SkippedMethodException();
        }
    }
}
<?php
echo "<?php\n";
$_namespace = preg_replace(':/:', '_', $namespace);
?>
use <?php echo $_namespace ?>_ExtensionUtil as E;

class <?php echo $reportClassName ?> extends CRM_Report_Form {

  protected $_addressField = FALSE;

  protected $_emailField = FALSE;

  protected $_summary = NULL;

  protected $_customGroupExtends = array('Membership');
  protected $_customGroupGroupBy = FALSE; function __construct() {
    $this->_columns = array(
      'civicrm_contact' => array(
        'dao' => 'CRM_Contact_DAO_Contact',
        'fields' => array(
          'sort_name' => array(
            'title' => E::ts('Contact Name'),
            'required' => TRUE,
            'default' => TRUE,
            'no_repeat' => TRUE,
          ),
          'id' => array(
            'no_display' => TRUE,
            'required' => TRUE,
          ),
          'first_name' => array(
            'title' => E::ts('First Name'),
            'no_repeat' => TRUE,
          ),
          'id' => array(
            'no_display' => TRUE,
            'required' => TRUE,
          ),
          'last_name' => array(
            'title' => E::ts('Last Name'),
            'no_repeat' => TRUE,
          ),
          'id' => array(
            'no_display' => TRUE,
            'required' => TRUE,
          ),
        ),
        'filters' => array(
          'sort_name' => array(
            'title' => E::ts('Contact Name'),
            'operator' => 'like',
          ),
          'id' => array(
            'no_display' => TRUE,
          ),
        ),
        'grouping' => 'contact-fields',
      ),
      'civicrm_membership' => array(
        'dao' => 'CRM_Member_DAO_Membership',
        'fields' => array(
          'membership_type_id' => array(
            'title' => 'Membership Type',
            'required' => TRUE,
            'no_repeat' => TRUE,
          ),
          'join_date' => array(
            'title' => E::ts('Join Date'),
            'default' => TRUE,
          ),
          'source' => array('title' => 'Source'),
        ),
        'filters' => array(
          'join_date' => array(
            'operatorType' => CRM_Report_Form::OP_DATE,
          ),
          'owner_membership_id' => array(
            'title' => E::ts('Membership Owner ID'),
            'operatorType' => CRM_Report_Form::OP_INT,
          ),
          'tid' => array(
            'name' => 'membership_type_id',
            'title' => E::ts('Membership Types'),
            'type' => CRM_Utils_Type::T_INT,
            'operatorType' => CRM_Report_Form::OP_MULTISELECT,
            'options' => CRM_Member_PseudoConstant::membershipType(),
          ),
        ),
        'grouping' => 'member-fields',
      ),
      'civicrm_membership_status' => array(
        'dao' => 'CRM_Member_DAO_MembershipStatus',
        'alias' => 'mem_status',
        'fields' => array(
          'name' => array(
            'title' => E::ts('Status'),
            'default' => TRUE,
          ),
        ),
        'filters' => array(
          'sid' => array(
            'name' => 'id',
            'title' => E::ts('Status'),
            'type' => CRM_Utils_Type::T_INT,
            'operatorType' => CRM_Report_Form::OP_MULTISELECT,
            'options' => CRM_Member_PseudoConstant::membershipStatus(NULL, NULL, 'label'),
          ),
        ),
        'grouping' => 'member-fields',
      ),
      'civicrm_address' => array(
        'dao' => 'CRM_Core_DAO_Address',
        'fields' => array(
          'street_address' => NULL,
          'city' => NULL,
          'postal_code' => NULL,
          'state_province_id' => array('title' => E::ts('State/Province')),
          'country_id' => array('title' => E::ts('Country')),
        ),
        'grouping' => 'contact-fields',
      ),
      'civicrm_email' => array(
        'dao' => 'CRM_Core_DAO_Email',
        'fields' => array('email' => NULL),
        'grouping' => 'contact-fields',
      ),
    );
    $this->_groupFilter = TRUE;
    $this->_tagFilter = TRUE;
    parent::__construct();
  }

  function preProcess() {
    $this->assign('reportTitle', E::ts('Membership Detail Report'));
    parent::preProcess();
  }

  function from() {
    $this->_from = NULL;

    $this->_from = "
         FROM  civicrm_contact {$this->_aliases['civicrm_contact']} {$this->_aclFrom}
               INNER JOIN civicrm_membership {$this->_aliases['civicrm_membership']}
                          ON {$this->_aliases['civicrm_contact']}.id =
                             {$this->_aliases['civicrm_membership']}.contact_id AND {$this->_aliases['civicrm_membership']}.is_test = 0
               LEFT  JOIN civicrm_membership_status {$this->_aliases['civicrm_membership_status']}
                          ON {$this->_aliases['civicrm_membership_status']}.id =
                             {$this->_aliases['civicrm_membership']}.status_id ";


    $this->joinAddressFromContact();
    $this->joinEmailFromContact();
  }

  /**
   * Add field specific select alterations.
   *
   * @param string $tableName
   * @param string $tableKey
   * @param string $fieldName
   * @param array $field
   *
   * @return string
   */
  function selectClause(&$tableName, $tableKey, &$fieldName, &$field) {
    return parent::selectClause($tableName, $tableKey, $fieldName, $field);
  }

  /**
   * Add field specific where alterations.
   *
   * This can be overridden in reports for special treatment of a field
   *
   * @param array $field Field specifications
   * @param string $op Query operator (not an exact match to sql)
   * @param mixed $value
   * @param float $min
   * @param float $max
   *
   * @return null|string
   */
  public function whereClause(&$field, $op, $value, $min, $max) {
    return parent::whereClause($field, $op, $value, $min, $max);
  }

  function alterDisplay(&$rows) {
    // custom code to alter rows
    $entryFound = FALSE;
    $checkList = array();
    foreach ($rows as $rowNum => $row) {

      if (!empty($this->_noRepeats) && $this->_outputMode != 'csv') {
        // not repeat contact display names if it matches with the one
        // in previous row
        $repeatFound = FALSE;
        foreach ($row as $colName => $colVal) {
          if ($checkList[$colName] ?? NULL) &&
            is_array($checkList[$colName]) &&
            in_array($colVal, $checkList[$colName])
          ) {
            $rows[$rowNum][$colName] = "";
            $repeatFound = TRUE;
          }
          if (in_array($colName, $this->_noRepeats)) {
            $checkList[$colName][] = $colVal;
          }
        }
      }

      if (array_key_exists('civicrm_membership_membership_type_id', $row)) {
        if ($value = $row['civicrm_membership_membership_type_id']) {
          $rows[$rowNum]['civicrm_membership_membership_type_id'] = CRM_Member_PseudoConstant::membershipType($value, FALSE);
        }
        $entryFound = TRUE;
      }

      if (array_key_exists('civicrm_address_state_province_id', $row)) {
        if ($value = $row['civicrm_address_state_province_id']) {
          $rows[$rowNum]['civicrm_address_state_province_id'] = CRM_Core_PseudoConstant::stateProvince($value, FALSE);
        }
        $entryFound = TRUE;
      }

      if (array_key_exists('civicrm_address_country_id', $row)) {
        if ($value = $row['civicrm_address_country_id']) {
          $rows[$rowNum]['civicrm_address_country_id'] = CRM_Core_PseudoConstant::country($value, FALSE);
        }
        $entryFound = TRUE;
      }

      if (array_key_exists('civicrm_contact_sort_name', $row) &&
        $rows[$rowNum]['civicrm_contact_sort_name'] &&
        array_key_exists('civicrm_contact_id', $row)
      ) {
        $url = CRM_Utils_System::url("civicrm/contact/view",
          'reset=1&cid=' . $row['civicrm_contact_id'],
          $this->_absoluteUrl
        );
        $rows[$rowNum]['civicrm_contact_sort_name_link'] = $url;
        $rows[$rowNum]['civicrm_contact_sort_name_hover'] = E::ts("View Contact Summary for this Contact.");
        $entryFound = TRUE;
      }

      if (!$entryFound) {
        break;
      }
    }
  }

}
<?php
echo "<?php\n";
$_namespace = preg_replace(':/:', '_', $namespace);
?>
// phpcs:disable
use <?php echo $_namespace ?>_ExtensionUtil as E;
// phpcs:enable

class <?php echo $baoClassName ?> extends <?php echo $daoClassName ?> {

}
<?php
echo "<?php\n";

if ($testNamespace) {
  echo "namespace $testNamespace;\n";
}
$_namespace = preg_replace(':/:', '_', $namespace);
?>

use <?php echo $_namespace ?>_ExtensionUtil as E;
use Civi\Test\EndToEndInterface;

/**
 * FIXME - Add test description.
 *
 * Tips:
 *  - The global variable $_CV has some properties which may be useful, such as:
 *    CMS_URL, ADMIN_USER, ADMIN_PASS, ADMIN_EMAIL, DEMO_USER, DEMO_PASS, DEMO_EMAIL.
 *  - To spawn a new CiviCRM thread and execute an API call or PHP code, use cv(), e.g.
 *      cv('api system.flush');
 *      $data = cv('eval "return Civi::settings()->get(\'foobar\')"');
 *      $dashboardUrl = cv('url civicrm/dashboard');
 *  - This template uses the most generic base-class, but you may want to use a more
 *    powerful base class, such as \PHPUnit_Extensions_SeleniumTestCase or
 *    \PHPUnit_Extensions_Selenium2TestCase.
 *    See also: https://phpunit.de/manual/4.8/en/selenium.html
 *
 * @group e2e
 * @see cv
 */
class <?php echo $testClass ?> extends \PHPUnit\Framework\TestCase implements EndToEndInterface {

  public static function setUpBeforeClass(): void {
    // See: https://docs.civicrm.org/dev/en/latest/testing/phpunit/#civitest

    // Example: Install this extension. Don't care about anything else.
    \Civi\Test::e2e()->installMe(__DIR__)->apply();

    // Example: Uninstall all extensions except this one.
    // \Civi\Test::e2e()->uninstall('*')->installMe(__DIR__)->apply();

    // Example: Install only core civicrm extensions.
    // \Civi\Test::e2e()->uninstall('*')->install('org.civicrm.*')->apply();
  }

  public function setUp(): void {
    parent::setUp();
  }

  public function tearDown(): void {
    parent::tearDown();
  }

  /**
   * Example: Test that a version is returned.
   */
  public function testWellFormedVersion(): void {
    $this->assertNotEmpty(E::SHORT_NAME);
    $this->assertRegExp('/^([0-9\.]|alpha|beta)*$/', \CRM_Utils_System::version());
  }

  /**
   * Example: Test that we're using a real CMS (Drupal, WordPress, etc).
   */
  public function testWellFormedUF(): void {
    $this->assertRegExp('/^(Drupal|Backdrop|WordPress|Joomla)/', CIVICRM_UF);
  }

}
<?php
echo "<?php\n";
$_namespace = preg_replace(':/:', '_', $namespace);
$_compatibility = isset($compatibilityVerMin) ? $compatibilityVerMin : '5.0';
$_invokePolyfill = version_compare($_compatibility, '5.45.beta1', '<')
  ? sprintf("  _%s_civix_mixin_polyfill();\n", $mainFile)
  : "  // Based on <compatibility>, this does not currently require mixin/polyfill.php.\n";
?>

// AUTO-GENERATED FILE -- Civix may overwrite any changes made to this file

/**
 * The ExtensionUtil class provides small stubs for accessing resources of this
 * extension.
 */
class <?php echo $_namespace ?>_ExtensionUtil {
  const SHORT_NAME = '<?php echo $mainFile; ?>';
  const LONG_NAME = '<?php echo $fullName; ?>';
  const CLASS_PREFIX = '<?php echo $_namespace; ?>';

  /**
   * Translate a string using the extension's domain.
   *
   * If the extension doesn't have a specific translation
   * for the string, fallback to the default translations.
   *
   * @param string $text
   *   Canonical message text (generally en_US).
   * @param array $params
   * @return string
   *   Translated text.
   * @see ts
   */
  public static function ts($text, $params = []): string {
    if (!array_key_exists('domain', $params)) {
      $params['domain'] = [self::LONG_NAME, NULL];
    }
    return ts($text, $params);
  }

  /**
   * Get the URL of a resource file (in this extension).
   *
   * @param string|NULL $file
   *   Ex: NULL.
   *   Ex: 'css/foo.css'.
   * @return string
   *   Ex: 'http://example.org/sites/default/ext/org.example.foo'.
   *   Ex: 'http://example.org/sites/default/ext/org.example.foo/css/foo.css'.
   */
  public static function url($file = NULL): string {
    if ($file === NULL) {
      return rtrim(CRM_Core_Resources::singleton()->getUrl(self::LONG_NAME), '/');
    }
    return CRM_Core_Resources::singleton()->getUrl(self::LONG_NAME, $file);
  }

  /**
   * Get the path of a resource file (in this extension).
   *
   * @param string|NULL $file
   *   Ex: NULL.
   *   Ex: 'css/foo.css'.
   * @return string
   *   Ex: '/var/www/example.org/sites/default/ext/org.example.foo'.
   *   Ex: '/var/www/example.org/sites/default/ext/org.example.foo/css/foo.css'.
   */
  public static function path($file = NULL) {
    // return CRM_Core_Resources::singleton()->getPath(self::LONG_NAME, $file);
    return __DIR__ . ($file === NULL ? '' : (DIRECTORY_SEPARATOR . $file));
  }

  /**
   * Get the name of a class within this extension.
   *
   * @param string $suffix
   *   Ex: 'Page_HelloWorld' or 'Page\\HelloWorld'.
   * @return string
   *   Ex: 'CRM_Foo_Page_HelloWorld'.
   */
  public static function findClass($suffix) {
    return self::CLASS_PREFIX . '_' . str_replace('\\', '_', $suffix);
  }

}

use <?php echo $_namespace ?>_ExtensionUtil as E;

<?php if (version_compare($_compatibility, '5.45.beta1', '<')) { ?>
function _<?php echo $mainFile ?>_civix_mixin_polyfill() {
  if (!class_exists('CRM_Extension_MixInfo')) {
    $polyfill = __DIR__ . '/mixin/polyfill.php';
    (require $polyfill)(E::LONG_NAME, E::SHORT_NAME, E::path());
  }
}

<?php } ?>
/**
 * (Delegated) Implements hook_civicrm_config().
 *
 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_config
 */
function _<?php echo $mainFile ?>_civix_civicrm_config($config = NULL) {
  static $configured = FALSE;
  if ($configured) {
    return;
  }
  $configured = TRUE;

  $extRoot = __DIR__ . DIRECTORY_SEPARATOR;
  $include_path = $extRoot . PATH_SEPARATOR . get_include_path();
  set_include_path($include_path);
<?php echo $_invokePolyfill; ?>
}

/**
 * Implements hook_civicrm_install().
 *
 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_install
 */
function _<?php echo $mainFile ?>_civix_civicrm_install() {
  _<?php echo $mainFile ?>_civix_civicrm_config();
<?php echo $_invokePolyfill; ?>
}

/**
 * (Delegated) Implements hook_civicrm_enable().
 *
 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_enable
 */
function _<?php echo $mainFile ?>_civix_civicrm_enable(): void {
  _<?php echo $mainFile ?>_civix_civicrm_config();
<?php echo $_invokePolyfill; ?>
}

/**
 * Inserts a navigation menu item at a given place in the hierarchy.
 *
 * @param array $menu - menu hierarchy
 * @param string $path - path to parent of this item, e.g. 'my_extension/submenu'
 *    'Mailing', or 'Administer/System Settings'
 * @param array $item - the item to insert (parent/child attributes will be
 *    filled for you)
 *
 * @return bool
 */
function _<?php echo $mainFile ?>_civix_insert_navigation_menu(&$menu, $path, $item) {
  // If we are done going down the path, insert menu
  if (empty($path)) {
    $menu[] = [
      'attributes' => array_merge([
        'label' => $item['name'] ?? NULL,
        'active' => 1,
      ], $item),
    ];
    return TRUE;
  }
  else {
    // Find an recurse into the next level down
    $found = FALSE;
    $path = explode('/', $path);
    $first = array_shift($path);
    foreach ($menu as $key => &$entry) {
      if ($entry['attributes']['name'] == $first) {
        if (!isset($entry['child'])) {
          $entry['child'] = [];
        }
        $found = _<?php echo $mainFile ?>_civix_insert_navigation_menu($entry['child'], implode('/', $path), $item);
      }
    }
    return $found;
  }
}

/**
 * (Delegated) Implements hook_civicrm_navigationMenu().
 */
function _<?php echo $mainFile ?>_civix_navigationMenu(&$nodes) {
  if (!is_callable(['CRM_Core_BAO_Navigation', 'fixNavigationMenu'])) {
    _<?php echo $mainFile ?>_civix_fixNavigationMenu($nodes);
  }
}

/**
 * Given a navigation menu, generate navIDs for any items which are
 * missing them.
 */
function _<?php echo $mainFile ?>_civix_fixNavigationMenu(&$nodes) {
  $maxNavID = 1;
  array_walk_recursive($nodes, function($item, $key) use (&$maxNavID) {
    if ($key === 'navID') {
      $maxNavID = max($maxNavID, $item);
    }
  });
  _<?php echo $mainFile ?>_civix_fixNavigationMenuItems($nodes, $maxNavID, NULL);
}

function _<?php echo $mainFile ?>_civix_fixNavigationMenuItems(&$nodes, &$maxNavID, $parentID) {
  $origKeys = array_keys($nodes);
  foreach ($origKeys as $origKey) {
    if (!isset($nodes[$origKey]['attributes']['parentID']) && $parentID !== NULL) {
      $nodes[$origKey]['attributes']['parentID'] = $parentID;
    }
    // If no navID, then assign navID and fix key.
    if (!isset($nodes[$origKey]['attributes']['navID'])) {
      $newKey = ++$maxNavID;
      $nodes[$origKey]['attributes']['navID'] = $newKey;
      $nodes[$newKey] = $nodes[$origKey];
      unset($nodes[$origKey]);
      $origKey = $newKey;
    }
    if (isset($nodes[$origKey]['child']) && is_array($nodes[$origKey]['child'])) {
      _<?php echo $mainFile ?>_civix_fixNavigationMenuItems($nodes[$origKey]['child'], $maxNavID, $nodes[$origKey]['attributes']['navID']);
    }
  }
}
(function(angular, $, _) {

  angular.module('<?php echo $angularModuleName ?>').config(function($routeProvider) {
      $routeProvider.when('/<?php echo $ctrlRelPath ?>', {
        controller: '<?php echo $ctrlName ?>',
        controllerAs: '$ctrl',
        templateUrl: '<?php echo $htmlName ?>',

        // If you need to look up data when opening the page, list it out
        // under "resolve".
        resolve: {
          myContact: function(crmApi) {
            return crmApi('Contact', 'getsingle', {
              id: 'user_contact_id',
              return: ['first_name', 'last_name']
            });
          }
        }
      });
    }
  );

  // The controller uses *injection*. This default injects a few things:
  //   $scope -- This is the set of variables shared between JS and HTML.
  //   crmApi, crmStatus, crmUiHelp -- These are services provided by civicrm-core.
  //   myContact -- The current contact, defined above in config().
  angular.module('<?php echo $angularModuleName ?>').controller('<?php echo $ctrlName ?>', function($scope, crmApi, crmStatus, crmUiHelp, myContact) {
    // The ts() and hs() functions help load strings for this module.
    var ts = $scope.ts = CRM.ts('<?php echo $tsDomain ?>');
    var hs = $scope.hs = crmUiHelp({file: '<?php echo $hlpName ?>'}); // See: templates/<?php echo $hlpName ?>.hlp
    // Local variable for this controller (needed when inside a callback fn where `this` is not available).
    var ctrl = this;

    // We have myContact available in JS. We also want to reference it in HTML.
    this.myContact = myContact;

    this.save = function() {
      return crmStatus(
        // Status messages. For defaults, just use "{}"
        {start: ts('Saving...'), success: ts('Saved')},
        // The save action. Note that crmApi() returns a promise.
        crmApi('Contact', 'create', {
          id: ctrl.myContact.id,
          first_name: ctrl.myContact.first_name,
          last_name: ctrl.myContact.last_name
        })
      );
    };
  });

})(angular, CRM.$, CRM._);
<?php
echo "<?php\n";

if ($testNamespace) {
  echo "namespace $testNamespace;\n";
}
$_namespace = preg_replace(':/:', '_', $namespace);
?>

use <?php echo $_namespace ?>_ExtensionUtil as E;
use Civi\Test\CiviEnvBuilder;
use Civi\Test\HeadlessInterface;
use Civi\Test\HookInterface;
use Civi\Test\TransactionalInterface;

/**
 * FIXME - Add test description.
 *
 * Tips:
 *  - With HookInterface, you may implement CiviCRM hooks directly in the test class.
 *    Simply create corresponding functions (e.g. "hook_civicrm_post(...)" or similar).
 *  - With TransactionalInterface, any data changes made by setUp() or test****() functions will
 *    rollback automatically -- as long as you don't manipulate schema or truncate tables.
 *    If this test needs to manipulate schema or truncate tables, then either:
 *       a. Do all that using setupHeadless() and Civi\Test.
 *       b. Disable TransactionalInterface, and handle all setup/teardown yourself.
 *
 * @group headless
 */
class <?php echo $testClass ?> extends \PHPUnit\Framework\TestCase implements HeadlessInterface, HookInterface, TransactionalInterface {

  /**
   * Setup used when HeadlessInterface is implemented.
   *
   * Civi\Test has many helpers, like install(), uninstall(), sql(), and sqlFile().
   *
   * @link https://github.com/civicrm/org.civicrm.testapalooza/blob/master/civi-test.md
   *
   * @return \Civi\Test\CiviEnvBuilder
   *
   * @throws \CRM_Extension_Exception_ParseException
   */
  public function setUpHeadless(): CiviEnvBuilder {
    return \Civi\Test::headless()
      ->installMe(__DIR__)
      ->apply();
  }

  public function setUp():void {
    parent::setUp();
  }

  public function tearDown():void {
    parent::tearDown();
  }

  /**
   * Example: Test that a version is returned.
   */
  public function testWellFormedVersion():void {
    $this->assertNotEmpty(E::SHORT_NAME);
    $this->assertRegExp('/^([0-9\.]|alpha|beta)*$/', \CRM_Utils_System::version());
  }

  /**
   * Example: Test that we're using a fake CMS.
   */
  public function testWellFormedUF():void {
    $this->assertEquals('UnitTests', CIVICRM_UF);
  }

}
<div class="crm-container">
  <div crm-ui-debug="$ctrl.myContact"></div>

  <h1 crm-page-title>{{ts('About %1', {1: $ctrl.myContact.first_name + ' ' + $ctrl.myContact.last_name})}}</h1>

  <form name="myForm" crm-ui-id-scope>

    <div class="help">
      <p>{{ts('This is an auto-generated skeletal page.')}}</p>

      <p>{{ts('To view more debugging information, edit the URL and include "?angularDebug=1".')}}</p>
    </div>

    <div crm-ui-accordion="{title: ts('Greeting')}">
      <p ng-show="$ctrl.myContact.first_name">{{ ts('Hello, %1.', {1: $ctrl.myContact.first_name}) }}</p>

      <p ng-show="!$ctrl.myContact.first_name">{{ ts('Hello, stranger.') }}</p>
    </div>

    <div crm-ui-accordion="{title: ts('About Me')}">
      <div class="crm-block">
        <div class="crm-group">
          <div crm-ui-field="{name: 'myForm.first_name', title: ts('Name'), help: hs('full_name')}">
            <input
              crm-ui-id="myForm.first_name"
              name="first_name"
              ng-model="$ctrl.myContact.first_name"
              class="crm-form-text"
              placeholder="{{ts('First')}}"
              />
            <input
              crm-ui-id="myForm.last_name"
              name="last_name"
              ng-model="$ctrl.myContact.last_name"
              class="crm-form-text"
              placeholder="{{ts('Last')}}"
              />
          </div>
        </div>
      </div>

      <div>
        <button ng-click="$ctrl.save()">{{ts('Save')}}</button>
      </div>
    </div>

  </form>

</div>
<?php
echo "<?php\n";
$_namespace = preg_replace(':/:', '_', $namespace);
?>
// phpcs:disable
use <?php echo $_namespace ?>_ExtensionUtil as E;
// phpcs:enable

/**
 * Collection of upgrade steps.
 */
class <?php echo $_namespace ?>_Upgrader extends <?php echo $baseUpgrader ?> {

  // By convention, functions that look like "function upgrade_NNNN()" are
  // upgrade tasks. They are executed in order (like Drupal's hook_update_N).

  /**
   * Example: Run an external SQL script when the module is installed.
   *
   * Note that if a file is present sql\auto_install that will run regardless of this hook.
   */
  // public function install(): void {
  //   $this->executeSqlFile('sql/my_install.sql');
  // }

  /**
   * Example: Work with entities usually not available during the install step.
   *
   * This method can be used for any post-install tasks. For example, if a step
   * of your installation depends on accessing an entity that is itself
   * created during the installation (e.g., a setting or a managed entity), do
   * so here to avoid order of operation problems.
   */
  // public function postInstall(): void {
  //  $customFieldId = civicrm_api3('CustomField', 'getvalue', array(
  //    'return' => array("id"),
  //    'name' => "customFieldCreatedViaManagedHook",
  //  ));
  //  civicrm_api3('Setting', 'create', array(
  //    'myWeirdFieldSetting' => array('id' => $customFieldId, 'weirdness' => 1),
  //  ));
  // }

  /**
   * Example: Run an external SQL script when the module is uninstalled.
   *
   * Note that if a file is present sql\auto_uninstall that will run regardless of this hook.
   */
  // public function uninstall(): void {
  //   $this->executeSqlFile('sql/my_uninstall.sql');
  // }

  /**
   * Example: Run a simple query when a module is enabled.
   */
  // public function enable(): void {
  //  CRM_Core_DAO::executeQuery('UPDATE foo SET is_active = 1 WHERE bar = "whiz"');
  // }

  /**
   * Example: Run a simple query when a module is disabled.
   */
  // public function disable(): void {
  //   CRM_Core_DAO::executeQuery('UPDATE foo SET is_active = 0 WHERE bar = "whiz"');
  // }

  /**
   * Example: Run a couple simple queries.
   *
   * @return TRUE on success
   * @throws CRM_Core_Exception
   */
  // public function upgrade_4200(): bool {
  //   $this->ctx->log->info('Applying update 4200');
  //   CRM_Core_DAO::executeQuery('UPDATE foo SET bar = "whiz"');
  //   CRM_Core_DAO::executeQuery('DELETE FROM bang WHERE willy = wonka(2)');
  //   return TRUE;
  // }

  /**
   * Example: Run an external SQL script.
   *
   * @return TRUE on success
   * @throws CRM_Core_Exception
   */
  // public function upgrade_4201(): bool {
  //   $this->ctx->log->info('Applying update 4201');
  //   // this path is relative to the extension base dir
  //   $this->executeSqlFile('sql/upgrade_4201.sql');
  //   return TRUE;
  // }

  /**
   * Example: Run a slow upgrade process by breaking it up into smaller chunk.
   *
   * @return TRUE on success
   * @throws CRM_Core_Exception
   */
  // public function upgrade_4202(): bool {
  //   $this->ctx->log->info('Planning update 4202'); // PEAR Log interface

  //   $this->addTask(E::ts('Process first step'), 'processPart1', $arg1, $arg2);
  //   $this->addTask(E::ts('Process second step'), 'processPart2', $arg3, $arg4);
  //   $this->addTask(E::ts('Process second step'), 'processPart3', $arg5);
  //   return TRUE;
  // }
  // public function processPart1($arg1, $arg2) { sleep(10); return TRUE; }
  // public function processPart2($arg3, $arg4) { sleep(10); return TRUE; }
  // public function processPart3($arg5) { sleep(10); return TRUE; }

  /**
   * Example: Run an upgrade with a query that touches many (potentially
   * millions) of records by breaking it up into smaller chunks.
   *
   * @return TRUE on success
   * @throws CRM_Core_Exception
   */
  // public function upgrade_4203(): bool {
  //   $this->ctx->log->info('Planning update 4203'); // PEAR Log interface

  //   $minId = CRM_Core_DAO::singleValueQuery('SELECT coalesce(min(id),0) FROM civicrm_contribution');
  //   $maxId = CRM_Core_DAO::singleValueQuery('SELECT coalesce(max(id),0) FROM civicrm_contribution');
  //   for ($startId = $minId; $startId <= $maxId; $startId += self::BATCH_SIZE) {
  //     $endId = $startId + self::BATCH_SIZE - 1;
  //     $title = E::ts('Upgrade Batch (%1 => %2)', array(
  //       1 => $startId,
  //       2 => $endId,
  //     ));
  //     $sql = '
  //       UPDATE civicrm_contribution SET foobar = apple(banana()+durian)
  //       WHERE id BETWEEN %1 and %2
  //     ';
  //     $params = array(
  //       1 => array($startId, 'Integer'),
  //       2 => array($endId, 'Integer'),
  //     );
  //     $this->addTask($title, 'executeSql', $sql, $params);
  //   }
  //   return TRUE;
  // }

}
{* HEADER *}

<div class="crm-submit-buttons">
{include file="CRM/common/formButtons.tpl" location="top"}
</div>

{* FIELD EXAMPLE: OPTION 1 (AUTOMATIC LAYOUT) *}

{foreach from=$elementNames item=elementName}
  <div class="crm-section">
    <div class="label">{$form.$elementName.label}</div>
    <div class="content">{$form.$elementName.html}</div>
    <div class="clear"></div>
  </div>
{/foreach}

{* FIELD EXAMPLE: OPTION 2 (MANUAL LAYOUT)

  <div>
    <span>{$form.favorite_color.label}</span>
    <span>{$form.favorite_color.html}</span>
  </div>

{* FOOTER *}
<div class="crm-submit-buttons">
{include file="CRM/common/formButtons.tpl" location="bottom"}
</div>
<h3>This new page is generated by <?php echo $namespace ?>/Page/<?php echo $shortClassName ?>.php</h3>

{* Example: Display a variable directly *}
<p>The current time is {$currentTime}</p>

{* Example: Display a translated string -- which happens to include a variable *}
<p>{ts 1=$currentTime}(In your native language) The current time is %1.{/ts}</p>
<?php
echo "<?php\n";
$_namespace = preg_replace(':/:', '_', $namespace);
?>
use <?php echo $_namespace ?>_ExtensionUtil as E;

class <?php echo preg_replace(':/:', '_', $fullClassName) ?> extends CRM_Core_Page {

  public function run() {
    // Example: Set the page-title dynamically; alternatively, declare a static title in xml/Menu/*.xml
    CRM_Utils_System::setTitle(E::ts('<?php echo $shortClassName ?>'));

    // Example: Assign a variable for use in a template
    $this->assign('currentTime', date('Y-m-d H:i:s'));

    parent::run();
  }

}
<?php
echo "<?php\n";
$_namespace = preg_replace(':/:', '_', $namespace);
?>
use <?php echo $_namespace ?>_ExtensionUtil as E;

/**
 * <?php echo $entityNameCamel ?>.create API specification (optional).
 * This is used for documentation and validation.
 *
 * @param array $spec description of fields supported by this API call
 *
 * @see https://docs.civicrm.org/dev/en/latest/framework/api-architecture/
 */
function _<?php echo $apiFunctionPrefix ?>create_spec(&$spec) {
  // $spec['some_parameter']['api.required'] = 1;
}

/**
 * <?php echo $entityNameCamel ?>.create API.
 *
 * @param array $params
 *
 * @return array
 *   API result descriptor
 *
 * @throws API_Exception
 */
function <?php echo $apiFunctionPrefix ?>create($params) {
  return _civicrm_api3_basic_create(_civicrm_api3_get_BAO(__FUNCTION__), $params, <?php var_export($entityNameCamel); ?>);
}

/**
 * <?php echo $entityNameCamel ?>.delete API.
 *
 * @param array $params
 *
 * @return array
 *   API result descriptor
 *
 * @throws API_Exception
 */
function <?php echo $apiFunctionPrefix ?>delete($params) {
  return _civicrm_api3_basic_delete(_civicrm_api3_get_BAO(__FUNCTION__), $params);
}

/**
 * <?php echo $entityNameCamel ?>.get API.
 *
 * @param array $params
 *
 * @return array
 *   API result descriptor
 *
 * @throws API_Exception
 */
function <?php echo $apiFunctionPrefix ?>get($params) {
  return _civicrm_api3_basic_get(_civicrm_api3_get_BAO(__FUNCTION__), $params, TRUE, <?php var_export($entityNameCamel); ?>);
}
<?php
echo "<?php\n";

if ($testNamespace) {
  echo "namespace $testNamespace;\n";
}
$_namespace = preg_replace(':/:', '_', $namespace);
?>

use <?php echo $_namespace ?>_ExtensionUtil as E;
use Civi\Test\HeadlessInterface;
use Civi\Test\HookInterface;
use Civi\Test\TransactionalInterface;
use Civi\Test\CiviEnvBuilder;

/**
 * FIXME - Add test description.
 *
 * Tips:
 *  - With HookInterface, you may implement CiviCRM hooks directly in the test class.
 *    Simply create corresponding functions (e.g. "hook_civicrm_post(...)" or similar).
 *  - With TransactionalInterface, any data changes made by setUp() or test****() functions will
 *    rollback automatically -- as long as you don't manipulate schema or truncate tables.
 *    If this test needs to manipulate schema or truncate tables, then either:
 *       a. Do all that using setupHeadless() and Civi\Test.
 *       b. Disable TransactionalInterface, and handle all setup/teardown yourself.
 *
 * @group headless
 */
class <?php echo $testClass ?> extends \PHPUnit\Framework\TestCase implements HeadlessInterface, HookInterface, TransactionalInterface {

  /**
   * Setup used when HeadlessInterface is implemented.
   *
   * Civi\Test has many helpers, like install(), uninstall(), sql(), and sqlFile().
   * 
   * @link https://github.com/civicrm/org.civicrm.testapalooza/blob/master/civi-test.md
   *
   * @return \Civi\Test\CiviEnvBuilder
   *
   * @throws \CRM_Extension_Exception_ParseException
   */
  public function setUpHeadless(): CiviEnvBuilder {
    return \Civi\Test::headless()
      ->installMe(__DIR__)
      ->apply();
  }

  public function setUp():void {
    parent::setUp();
  }

  public function tearDown():void {
    parent::tearDown();
  }

  /**
   * Example: Test that a version is returned.
   */
  public function testWellFormedVersion():void {
    $this->assertNotEmpty(E::SHORT_NAME);
    $this->assertRegExp('/^([0-9\.]|alpha|beta)*$/', \CRM_Utils_System::version());
  }

  /**
   * Example: Test that we're using a fake CMS.
   */
  public function testWellFormedUF():void {
    $this->assertEquals('UnitTests', CIVICRM_UF);
  }

}
<?php
echo "<?php\n";
$_namespace = preg_replace(':/:', '_', $namespace);
?>
use <?php echo $_namespace ?>_ExtensionUtil as E;

/**
 * <?php echo $entityNameCamel ?>.create API specification (optional).
 * This is used for documentation and validation.
 *
 * @param array $spec description of fields supported by this API call
 *
 * @see https://docs.civicrm.org/dev/en/latest/framework/api-architecture/
 */
function _<?php echo $apiFunctionPrefix ?>create_spec(&$spec) {
  // $spec['some_parameter']['api.required'] = 1;
}

/**
 * <?php echo $entityNameCamel ?>.create API.
 *
 * @param array $params
 *
 * @return array
 *   API result descriptor
 *
 * @throws API_Exception
 */
function <?php echo $apiFunctionPrefix ?>create($params) {
  return _civicrm_api3_basic_create(_civicrm_api3_get_BAO(__FUNCTION__), $params, <?php var_export($entityNameCamel); ?>);
}

/**
 * <?php echo $entityNameCamel ?>.delete API.
 *
 * @param array $params
 *
 * @return array
 *   API result descriptor
 *
 * @throws API_Exception
 */
function <?php echo $apiFunctionPrefix ?>delete($params) {
  return _civicrm_api3_basic_delete(_civicrm_api3_get_BAO(__FUNCTION__), $params);
}

/**
 * <?php echo $entityNameCamel ?>.get API.
 *
 * @param array $params
 *
 * @return array
 *   API result descriptor
 *
 * @throws API_Exception
 */
function <?php echo $apiFunctionPrefix ?>get($params) {
  return _civicrm_api3_basic_get(_civicrm_api3_get_BAO(__FUNCTION__), $params, FALSE, <?php var_export($entityNameCamel); ?>);
}
<?php
echo "<?php\n";
?>

/**
 * This is a generic test class for the extension (implemented with PHPUnit).
 */
class <?php echo $testClass ?> extends \PHPUnit\Framework\TestCase {

  /**
   * The setup() method is executed before the test is executed (optional).
   */
  public function setUp():void {
    parent::setUp();
  }

  /**
   * The tearDown() method is executed after the test was executed (optional).
   *
   * This can be used for cleanup.
   */
  public function tearDown():void {
    parent::tearDown();
  }

  /**
   * Simple example test case.
   *
   * Note how the function name begins with the word "test".
   */
  public function testExample():void {
    self::assertTrue(TRUE, "The argument must be true to pass the test");
  }

}
{htxt id="full_name"}
{ts}The contact name  should be divided in two parts, the first name and last name.{/ts}
{/htxt}
/**
 * This is a placeholder for bootstrap.css in the '<?php echo $themeName; ?>' theme.
 * Here are a few ideas on what to do about it:
 *   - Make a real CSS file (e.g. by hand-coding or setting up a SASS/SCSS build process).
 *   - Inherit the stock Greenwich file:
 *       - Edit the file '<?php echo $themeName; ?>.theme.php'
 *         and add 'greenwich' to the 'search_order'
 *       - Delete this copy of 'bootstrap.css'
 *   - Disable this file completely:
 *       - Edit the file '<?php echo $themeName; ?>.theme.php'
 *         and add 'css/bootstrap.css' to the 'excludes' list
 *       - Delete this copy of 'bootstrap.css'
 */
<?php
echo '<?xml version="1.0" encoding="iso-8859-1" ?>'."\n";
?>

<table>
  <base><?php echo $namespace ?></base>
  <class><?php echo $entityNameCamel ?></class>
  <name><?php echo $tableName ?></name>
  <comment>FIXME</comment>
  <log>true</log>

  <field>
    <name>id</name>
    <type>int unsigned</type>
    <required>true</required>
    <comment>Unique <?php echo $entityNameCamel ?> ID</comment>
    <html>
      <type>Number</type>
    </html>
  </field>
  <primaryKey>
    <name>id</name>
    <autoincrement>true</autoincrement>
  </primaryKey>

  <field>
    <name>contact_id</name>
    <type>int unsigned</type>
    <comment>FK to Contact</comment>
  </field>
  <foreignKey>
    <name>contact_id</name>
    <table>civicrm_contact</table>
    <key>id</key>
    <onDelete>CASCADE</onDelete>
  </foreignKey>

</table>
<?php
echo "<?php\n";
$_namespace = preg_replace(':/:', '_', $namespace);
?>

use <?php echo $_namespace ?>_ExtensionUtil as E;

/**
 * Form controller class
 *
 * @see https://docs.civicrm.org/dev/en/latest/framework/quickform/
 */
class <?php echo preg_replace(':/:', '_', $fullClassName) ?> extends CRM_Core_Form {
  public function buildQuickForm() {

    // add form elements
    $this->add(
      'select', // field type
      'favorite_color', // field name
      'Favorite Color', // field label
      $this->getColorOptions(), // list of options
      TRUE // is required
    );
    $this->addButtons(array(
      array(
        'type' => 'submit',
        'name' => E::ts('Submit'),
        'isDefault' => TRUE,
      ),
    ));

    // export form elements
    $this->assign('elementNames', $this->getRenderableElementNames());
    parent::buildQuickForm();
  }

  public function postProcess() {
    $values = $this->exportValues();
    $options = $this->getColorOptions();
    CRM_Core_Session::setStatus(E::ts('You picked color "%1"', array(
      1 => $options[$values['favorite_color']],
    )));
    parent::postProcess();
  }

  public function getColorOptions() {
    $options = array(
      '' => E::ts('- select -'),
      '#f00' => E::ts('Red'),
      '#0f0' => E::ts('Green'),
      '#00f' => E::ts('Blue'),
      '#f0f' => E::ts('Purple'),
    );
    foreach (array('1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e') as $f) {
      $options["#{$f}{$f}{$f}"] = E::ts('Grey (%1)', array(1 => $f));
    }
    return $options;
  }

  /**
   * Get the fields/elements defined in this form.
   *
   * @return array (string)
   */
  public function getRenderableElementNames() {
    // The _elements list includes some items which should not be
    // auto-rendered in the loop -- such as "qfKey" and "buttons".  These
    // items don't have labels.  We'll identify renderable by filtering on
    // the 'label'.
    $elementNames = array();
    foreach ($this->_elements as $element) {
      /** @var HTML_QuickForm_Element $element */
      $label = $element->getLabel();
      if (!empty($label)) {
        $elementNames[] = $element->getName();
      }
    }
    return $elementNames;
  }

}
<?php
echo "<?php\n";
$_namespace = preg_replace(':/:', '_', $namespace);
?>
use <?php echo $_namespace ?>_ExtensionUtil as E;

/**
 * A custom contact search
 */
class <?php echo $searchClassName ?> extends CRM_Contact_Form_Search_Custom_Base implements CRM_Contact_Form_Search_Interface {
  function __construct(&$formValues) {
    parent::__construct($formValues);
  }

  /**
   * Prepare a set of search fields
   *
   * @param CRM_Core_Form $form modifiable
   * @return void
   */
  function buildForm(&$form) {
    CRM_Utils_System::setTitle(E::ts('My Search Title'));

    $form->add('text',
      'household_name',
      E::ts('Household Name'),
      TRUE
    );

    $stateProvince = array('' => E::ts('- any state/province -')) + CRM_Core_PseudoConstant::stateProvince();
    $form->addElement('select', 'state_province_id', E::ts('State/Province'), $stateProvince);

    // Optionally define default search values
    $form->setDefaults(array(
      'household_name' => '',
      'state_province_id' => NULL,
    ));

    /**
     * if you are using the standard template, this array tells the template what elements
     * are part of the search criteria
     */
    $form->assign('elements', array('household_name', 'state_province_id'));
  }

  /**
   * Get a list of summary data points
   *
   * @return mixed; NULL or array with keys:
   *  - summary: string
   *  - total: numeric
   */
  function summary() {
    return NULL;
    // return array(
    //   'summary' => 'This is a summary',
    //   'total' => 50.0,
    // );
  }

  /**
   * Get a list of displayable columns
   *
   * @return array, keys are printable column headers and values are SQL column names
   */
  function &columns() {
    // return by reference
    $columns = array(
      E::ts('Contact Id') => 'contact_id',
      E::ts('Contact Type') => 'contact_type',
      E::ts('Name') => 'sort_name',
      E::ts('State') => 'state_province',
    );
    return $columns;
  }

  /**
   * Construct a full SQL query which returns one page worth of results
   *
   * @param int $offset
   * @param int $rowcount
   * @param null $sort
   * @param bool $includeContactIDs
   * @param bool $justIDs
   * @return string, sql
   */
  function all($offset = 0, $rowcount = 0, $sort = NULL, $includeContactIDs = FALSE, $justIDs = FALSE) {
    // delegate to $this->sql(), $this->select(), $this->from(), $this->where(), etc.
    return $this->sql($this->select(), $offset, $rowcount, $sort, $includeContactIDs, NULL);
  }

  /**
   * Construct a SQL SELECT clause
   *
   * @return string, sql fragment with SELECT arguments
   */
  function select() {
    return "
      contact_a.id           as contact_id  ,
      contact_a.contact_type as contact_type,
      contact_a.sort_name    as sort_name,
      state_province.name    as state_province
    ";
  }

  /**
   * Construct a SQL FROM clause
   *
   * @return string, sql fragment with FROM and JOIN clauses
   */
  function from() {
    return "
      FROM      civicrm_contact contact_a
      LEFT JOIN civicrm_address address ON ( address.contact_id       = contact_a.id AND
                                             address.is_primary       = 1 )
      LEFT JOIN civicrm_email           ON ( civicrm_email.contact_id = contact_a.id AND
                                             civicrm_email.is_primary = 1 )
      LEFT JOIN civicrm_state_province state_province ON state_province.id = address.state_province_id
    ";
  }

  /**
   * Construct a SQL WHERE clause
   *
   * @param bool $includeContactIDs
   * @return string, sql fragment with conditional expressions
   */
  function where($includeContactIDs = FALSE) {
    $params = array();
    $where = "contact_a.contact_type   = 'Household'";

    $count  = 1;
    $clause = array();
    $name = $this->_formValues['household_name'] ?? NULL;
    if ($name != NULL) {
      if (strpos($name, '%') === FALSE) {
        $name = "%{$name}%";
      }
      $params[$count] = array($name, 'String');
      $clause[] = "contact_a.household_name LIKE %{$count}";
      $count++;
    }

    $state = $this->_formValues['state_province_id'] ?? NULL;
    if (!$state &&
      $this->_stateID
    ) {
      $state = $this->_stateID;
    }

    if ($state) {
      $params[$count] = array($state, 'Integer');
      $clause[] = "state_province.id = %{$count}";
    }

    if (!empty($clause)) {
      $where .= ' AND ' . implode(' AND ', $clause);
    }

    return $this->whereClause($where, $params);
  }

  /**
   * Determine the Smarty template for the search screen
   *
   * @return string, template path (findable through Smarty template path)
   */
  function templateFile() {
    return 'CRM/Contact/Form/Search/Custom.tpl';
  }

  /**
   * Modify the content of each row
   *
   * @param array $row modifiable SQL result row
   * @return void
   */
  function alterRow(&$row) {
    $row['sort_name'] .= ' ( altered )';
  }
}
<?php
echo "<?php\n";
$_namespace = preg_replace(':/:', '_', $namespace);
?>

require_once '<?php echo $mainFile ?>.civix.php';
// phpcs:disable
use <?php echo $_namespace ?>_ExtensionUtil as E;
// phpcs:enable

/**
 * Implements hook_civicrm_config().
 *
 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_config/
 */
function <?php echo $mainFile ?>_civicrm_config(&$config): void {
  _<?php echo $mainFile ?>_civix_civicrm_config($config);
}

/**
 * Implements hook_civicrm_install().
 *
 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_install
 */
function <?php echo $mainFile ?>_civicrm_install(): void {
  _<?php echo $mainFile ?>_civix_civicrm_install();
}

/**
 * Implements hook_civicrm_enable().
 *
 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_enable
 */
function <?php echo $mainFile ?>_civicrm_enable(): void {
  _<?php echo $mainFile ?>_civix_civicrm_enable();
}
<?php echo "<?php\n"; ?>
namespace Civi\Api4;

/**
 * <?php echo $entityNameCamel ?> entity.
 *
 * Provided by the <?php echo $extensionName ?> extension.
 *
 * @package Civi\Api4
 */
class <?php echo $entityNameCamel ?> extends Generic\DAOEntity {

}
<?php
echo "<?php\n";
?>

ini_set('memory_limit', '2G');

// phpcs:disable
eval(cv('php:boot --level=classloader', 'phpcode'));
// phpcs:enable
// Allow autoloading of PHPUnit helper classes in this extension.
$loader = new \Composer\Autoload\ClassLoader();
$loader = new \Composer\Autoload\ClassLoader();
$loader->add('CRM_', [__DIR__ . '/../..', __DIR__]);
$loader->addPsr4('Civi\\', [__DIR__ . '/../../Civi', __DIR__ . '/Civi']);
$loader->add('api_', [__DIR__ . '/../..', __DIR__]);
$loader->addPsr4('api\\', [__DIR__ . '/../../api', __DIR__ . '/api']);

$loader->register();

/**
 * Call the "cv" command.
 *
 * @param string $cmd
 *   The rest of the command to send.
 * @param string $decode
 *   Ex: 'json' or 'phpcode'.
 * @return mixed
 *   Response output (if the command executed normally).
 *   For 'raw' or 'phpcode', this will be a string. For 'json', it could be any JSON value.
 * @throws \RuntimeException
 *   If the command terminates abnormally.
 */
function cv(string $cmd, string $decode = 'json') {
  $cmd = 'cv ' . $cmd;
  $descriptorSpec = [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => STDERR];
  $oldOutput = getenv('CV_OUTPUT');
  putenv('CV_OUTPUT=json');

  // Execute `cv` in the original folder. This is a work-around for
  // phpunit/codeception, which seem to manipulate PWD.
  $cmd = sprintf('cd %s; %s', escapeshellarg(getenv('PWD')), $cmd);

  $process = proc_open($cmd, $descriptorSpec, $pipes, __DIR__);
  putenv("CV_OUTPUT=$oldOutput");
  fclose($pipes[0]);
  $result = stream_get_contents($pipes[1]);
  fclose($pipes[1]);
  if (proc_close($process) !== 0) {
    throw new RuntimeException("Command failed ($cmd):\n$result");
  }
  switch ($decode) {
    case 'raw':
      return $result;

    case 'phpcode':
      // If the last output is /*PHPCODE*/, then we managed to complete execution.
      if (substr(trim($result), 0, 12) !== '/*BEGINPHP*/' || substr(trim($result), -10) !== '/*ENDPHP*/') {
        throw new \RuntimeException("Command failed ($cmd):\n$result");
      }
      return $result;

    case 'json':
      return json_decode($result, 1);

    default:
      throw new RuntimeException("Bad decoder format ($decode)");
  }
}
<?php
echo "<?php\n";
?>

use Civi\Test\CiviEnvBuilder;
use Civi\Test\HeadlessInterface;
use Civi\Test\HookInterface;
use Civi\Test\TransactionalInterface;

/**
 * <?php echo $entityNameCamel ?> API Test Case
 * @group headless
 */
class <?php echo $testApi3ClassName ?> extends \PHPUnit\Framework\TestCase implements HeadlessInterface, HookInterface, TransactionalInterface {
  use \Civi\Test\Api3TestTrait;

  /**
   * Set up for headless tests.
   *
   * Civi\Test has many helpers, like install(), uninstall(), sql(), and sqlFile().
   *
   * See: https://docs.civicrm.org/dev/en/latest/testing/phpunit/#civitest
   */
  public function setUpHeadless(): CiviEnvBuilder {
    return \Civi\Test::headless()
      ->installMe(__DIR__)
      ->apply();
  }

  /**
   * The setup() method is executed before the test is executed (optional).
   */
  public function setUp(): void {
    $table = CRM_Core_DAO_AllCoreTables::getTableForEntityName(<?php var_export($entityNameCamel); ?>);
    $this->assertTrue($table && CRM_Core_DAO::checkTableExists($table), 'There was a problem with extension installation. Table for ' . <?php var_export($entityNameCamel); ?> . ' not found.');
    parent::setUp();
  }

  /**
   * The tearDown() method is executed after the test was executed (optional)
   * This can be used for cleanup.
   */
  public function tearDown(): void {
    parent::tearDown();
  }

  /**
   * Simple example test case.
   *
   * Note how the function name begins with the word "test".
   */
  public function testCreateGetDelete(): void {
    // Boilerplate entity has one data field -- 'contact_id'.
    // Put some data in, read it back out, and delete it.

    $created = $this->callAPISuccess(<?php var_export($entityNameCamel); ?>, 'create', [
      'contact_id' => 1,
    ]);
    $this->assertTrue(is_numeric($created['id']));

    $get = $this->callAPISuccess(<?php var_export($entityNameCamel); ?>, 'get', []);
    $this->assertEquals(1, $get['count']);
    $this->assertEquals(1, $get['values'][$created['id']]['contact_id']);

    $this->callAPISuccess(<?php var_export($entityNameCamel); ?>, 'delete', [
      'id' => $created['id'],
    ]);
  }

}
/**
 * This is a placeholder for civicrm.css in the '<?php echo $themeName; ?>' theme.
 * Here are a few ideas on what to do about it:
 *   - Make a real CSS file (e.g. by hand-coding or setting up a SASS/SCSS build process).
 *   - Inherit the stock Greenwich file:
 *       - Edit the file '<?php echo $themeName; ?>.theme.php'
 *         and add 'greenwich' to the 'search_order'
 *       - Delete this copy of 'civicrm.css'
 *   - Disable this file completely:
 *       - Edit the file '<?php echo $themeName; ?>.theme.php'
 *         and add 'css/civicrm.css' to the 'excludes' list
 *       - Delete this copy of 'civicrm.css'
 */
(function(angular, $, _) {
  // "<?php echo $dirNameCamel ?>" is a basic skeletal directive.
  // Example usage: <div <?php echo $dirNameHyp ?>="{foo: 1, bar: 2}"></div>
  angular.module('<?php echo $angularModuleName ?>').directive('<?php echo $dirNameCamel ?>', function() {
    return {
      restrict: 'AE',
      templateUrl: '<?php echo $htmlName ?>',
      scope: {
        <?php echo $dirNameCamel ?>: '='
      },
      link: function($scope, $el, $attr) {
        var ts = $scope.ts = CRM.ts('<?php echo $tsDomain ?>');
        $scope.$watch('<?php echo $dirNameCamel ?>', function(newValue){
          $scope.myOptions = newValue;
        });
      }
    };
  });
})(angular, CRM.$, CRM._);
<?php
echo "<?php\n";
$_namespace = preg_replace(':/:', '_', $namespace);
?>
use <?php echo $_namespace ?>_ExtensionUtil as E;

/**
 * <?php echo $entityNameCamel ?>.<?php echo $actionNameCamel ?> API specification (optional)
 * This is used for documentation and validation.
 *
 * @param array $spec description of fields supported by this API call
 *
 * @see https://docs.civicrm.org/dev/en/latest/framework/api-architecture/
 */
function _<?php echo $apiFunction ?>_spec(&$spec) {
  $spec['magicword']['api.required'] = 1;
}

/**
 * <?php echo $entityNameCamel ?>.<?php echo $actionNameCamel ?> API
 *
 * @param array $params
 *
 * @return array
 *   API result descriptor
 *
 * @see civicrm_api3_create_success
 *
 * @throws API_Exception
 */
function <?php echo $apiFunction ?>($params) {
  if (array_key_exists('magicword', $params) && $params['magicword'] == 'sesame') {
    $returnValues = array(
      // OK, return several data rows
      12 => ['id' => 12, 'name' => 'Twelve'],
      34 => ['id' => 34, 'name' => 'Thirty four'],
      56 => ['id' => 56, 'name' => 'Fifty six'],
    );
    // ALTERNATIVE: $returnValues = []; // OK, success
    // ALTERNATIVE: $returnValues = ["Some value"]; // OK, return a single value

    // Spec: civicrm_api3_create_success($values = 1, $params = [], $entity = NULL, $action = NULL)
    return civicrm_api3_create_success($returnValues, $params, '<?php echo $entityNameCamel; ?>', '<?php echo $actionNameCamel; ?>');
  }
  else {
    throw new API_Exception(/*error_message*/ 'Everyone knows that the magicword is "sesame"', /*error_code*/ 'magicword_incorrect');
  }
}
<?php echo '<?xml version="1.0" encoding="iso-8859-1" ?>'; ?>
<CaseType>
  <name><?php echo $caseTypeLabel?></name>
  <description><?php echo $caseTypeLabel?></description>

  <ActivityTypes>

    <!-- Standard case-management activities -->
    <ActivityType>
      <name>Open Case</name>
      <max_instances>1</max_instances>
    </ActivityType>
    <ActivityType>
      <name>Follow up</name>
    </ActivityType>
    <ActivityType>
      <name>Change Case Type</name>
    </ActivityType>
    <ActivityType>
      <name>Change Case Status</name>
    </ActivityType>
    <ActivityType>
      <name>Change Case Start Date</name>
    </ActivityType>
    <ActivityType>
      <name>Link Cases</name>
    </ActivityType>

    <!-- Configurable activities -->
    <ActivityType>
      <name>Email</name>
    </ActivityType>
    <ActivityType>
      <name>Meeting</name>
    </ActivityType>
    <ActivityType>
      <name>Phone Call</name>
    </ActivityType>

  </ActivityTypes>

  <ActivitySets>
    <ActivitySet>
      <name>standard_timeline</name>
      <label>Standard Timeline</label>
      <timeline>true</timeline>
      <ActivityTypes>
        <ActivityType>
          <name>Open Case</name>
          <status>Completed</status>
        </ActivityType>
        <ActivityType>
          <name>Phone Call</name>
          <reference_offset>1</reference_offset>
          <reference_select>newest</reference_select>
        </ActivityType>
        <ActivityType>
          <name>Follow up</name>
          <reference_offset>7</reference_offset>
          <reference_select>newest</reference_select>
        </ActivityType>
      </ActivityTypes>
    </ActivitySet>
  </ActivitySets>

  <CaseRoles>
    <RelationshipType>
      <name>Case Coordinator</name>
      <creator>1</creator>
      <manager>1</manager>
    </RelationshipType>
  </CaseRoles>

</CaseType>
<?php
echo "<?php\n";
?>

use Civi\Test\CiviEnvBuilder;
use Civi\Test\HeadlessInterface;
use Civi\Test\HookInterface;
use Civi\Test\TransactionalInterface;

/**
 * <?php echo $entityNameCamel ?>.<?php echo $actionNameCamel ?> API Test Case
 * This is a generic test class implemented with PHPUnit.
 * @group headless
 */
class <?php echo $testClassName ?> extends \PHPUnit\Framework\TestCase implements HeadlessInterface, HookInterface, TransactionalInterface {
  use \Civi\Test\Api3TestTrait;

  /**
   * Set up for headless tests.
   *
   * Civi\Test has many helpers, like install(), uninstall(), sql(), and sqlFile().
   *
   * See: https://docs.civicrm.org/dev/en/latest/testing/phpunit/#civitest
   */
  public function setUpHeadless(): CiviEnvBuilder {
    return \Civi\Test::headless()
      ->installMe(__DIR__)
      ->apply();
  }

  /**
   * The setup() method is executed before the test is executed (optional).
   */
  public function setUp(): void {
    parent::setUp();
  }

  /**
   * The tearDown() method is executed after the test was executed (optional)
   * This can be used for cleanup.
   */
  public function tearDown(): void {
    parent::tearDown();
  }

  /**
   * Simple example test case.
   *
   * Note how the function name begins with the word "test".
   */
  public function testApiExample() {
    $result = civicrm_api3('<?php echo $entityNameCamel ?>', '<?php echo $actionNameLower ?>', array('magicword' => 'sesame'));
    $this->assertEquals('Twelve', $result['values'][12]['name']);
  }

}
<?php
echo "<?php\n";
?>

ini_set('memory_limit', '2G');

// phpcs:disable
eval(cv('php:boot --level=classloader', 'phpcode'));
// phpcs:enable
// Allow autoloading of PHPUnit helper classes in this extension.
$loader = new \Composer\Autoload\ClassLoader();
$loader->add('CRM_', [__DIR__ . '/../..', __DIR__]);
$loader->addPsr4('Civi\\', [__DIR__ . '/../../Civi', __DIR__ . '/Civi']);
$loader->add('api_', [__DIR__ . '/../..', __DIR__]);
$loader->addPsr4('api\\', [__DIR__ . '/../../api', __DIR__ . '/api']);

$loader->register();

/**
 * Call the "cv" command.
 *
 * @param string $cmd
 *   The rest of the command to send.
 * @param string $decode
 *   Ex: 'json' or 'phpcode'.
 * @return mixed
 *   Response output (if the command executed normally).
 *   For 'raw' or 'phpcode', this will be a string. For 'json', it could be any JSON value.
 * @throws \RuntimeException
 *   If the command terminates abnormally.
 */
function cv(string $cmd, string $decode = 'json') {
  $cmd = 'cv ' . $cmd;
  $descriptorSpec = [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => STDERR];
  $oldOutput = getenv('CV_OUTPUT');
  putenv('CV_OUTPUT=json');

  // Execute `cv` in the original folder. This is a work-around for
  // phpunit/codeception, which seem to manipulate PWD.
  $cmd = sprintf('cd %s; %s', escapeshellarg(getenv('PWD')), $cmd);

  $process = proc_open($cmd, $descriptorSpec, $pipes, __DIR__);
  putenv("CV_OUTPUT=$oldOutput");
  fclose($pipes[0]);
  $result = stream_get_contents($pipes[1]);
  fclose($pipes[1]);
  if (proc_close($process) !== 0) {
    throw new RuntimeException("Command failed ($cmd):\n$result");
  }
  switch ($decode) {
    case 'raw':
      return $result;

    case 'phpcode':
      // If the last output is /*PHPCODE*/, then we managed to complete execution.
      if (substr(trim($result), 0, 12) !== '/*BEGINPHP*/' || substr(trim($result), -10) !== '/*ENDPHP*/') {
        throw new \RuntimeException("Command failed ($cmd):\n$result");
      }
      return $result;

    case 'json':
      return json_decode($result, 1);

    default:
      throw new RuntimeException("Bad decoder format ($decode)");
  }
}
# <?php echo $fullName; ?>


![Screenshot](/images/screenshot.png)

(*FIXME: In one or two paragraphs, describe what the extension does and why one would download it. *)

The extension is licensed under [<?php echo $license ?>](LICENSE.txt).

## Requirements

* PHP v7.2+
* CiviCRM (*FIXME: Version number*)

## Installation

Learn more about installing CiviCRM extensions in the [CiviCRM Sysadmin Guide](https://docs.civicrm.org/sysadmin/en/latest/customize/extensions/).

## Installation (CLI, Zip)

Sysadmins and developers may download the `.zip` file for this extension and
install it with the command-line tool [cv](https://github.com/civicrm/cv).

```bash
cd <extension-dir>
cv dl <?php echo $fullName; ?>@https://github.com/FIXME/<?php echo $fullName; ?>/archive/master.zip
```

## Installation (CLI, Git)

Sysadmins and developers may clone the [Git](https://en.wikipedia.org/wiki/Git) repo for this extension and
install it with the command-line tool [cv](https://github.com/civicrm/cv).

```bash
git clone https://github.com/FIXME/<?php echo $fullName; ?>.git
cv en <?php echo $mainFile . "\n"; ?>
```

## Getting Started

(* FIXME: Where would a new user navigate to get started? What changes would they see? *)

## Known Issues

(* FIXME *)
<?php
echo "<?php\n";

if ($testNamespace) {
  echo "namespace $testNamespace;\n";
}
$_namespace = preg_replace(':/:', '_', $namespace);
?>

use <?php echo $_namespace ?>_ExtensionUtil as E;
use Civi\Test\HeadlessInterface;

/**
 * FIXME - Add test description.
 *
 * Note: Legacy test cases are based on CiviUnitTestCase. These should work about
 * as well (or as poorly) as before. This generator is provided primarily as a way
 * test backward compatibility.
 *
 * @group headless
 * @group legacy
 */
class <?php echo $testClass ?> extends \CiviUnitTestCase implements HeadlessInterface {

  /**
   * Setup for when Headless interface is implemented.
   *
   * `CiviTestListener`+`HeadlessInterface` has some clever tricks for
   * bootstrapping which make it easier to use phpunit CLI.
   * However, there's not much point in using setupHeadless() with CiviUnitTestCase
   * because CiviUnitTestCase performs its own special setup/teardown logic.
   */
  public function setUpHeadless(): void {}

  /**
   * Setup any fixtures required for the tests in this class.
   */
  public function setUp(): void {
    parent::setUp();
  }

  /**
   * Return the database to the original state..
   */
  public function tearDown(): void {
    parent::tearDown();
  }

  /**
   * Example: Test that a version is returned.
   */
  public function testWellFormedVersion(): void {
    $this->assertNotEmpty(E::SHORT_NAME);
    $this->assertRegExp('/^([0-9\.]|alpha|beta)*$/', \CRM_Utils_System::version());
  }

  /**
   * Example: Test that we're using a fake CMS.
   */
  public function testWellFormedUF(): void {
    $this->assertEquals('UnitTests', CIVICRM_UF);
  }

}
{* Use the default layout *}
{include file="CRM/Report/Form.tpl"}
<?php
echo "<?php\n";
$_namespace = preg_replace(':/:', '_', $namespace);
?>

// AUTO-GENERATED FILE -- Civix may overwrite any changes made to this file
use <?php echo $_namespace ?>_ExtensionUtil as E;

/**
 * Base class which provides helpers to execute upgrade logic
 */
class <?php echo $_namespace ?>_Upgrader_Base {

  /**
   * @var <?php echo $_namespace ?>_Upgrader_Base
   */
  public static $instance;

  /**
   * @var CRM_Queue_TaskContext
   */
  protected $ctx;

  /**
   * @var string
   *   eg 'com.example.myextension'
   */
  protected $extensionName;

  /**
   * @var string
   *   full path to the extension's source tree
   */
  protected $extensionDir;

  /**
   * @var array
   *   sorted numerically
   */
  private $revisions;

  /**
   * @var bool
   *   Flag to clean up extension revision data in civicrm_setting
   */
  private $revisionStorageIsDeprecated = FALSE;

  /**
   * Obtain a reference to the active upgrade handler.
   */
  public static function instance() {
    if (!self::$instance) {
      self::$instance = new <?php echo $_namespace ?>_Upgrader(
        '<?php echo $fullName ?>',
        E::path()
      );
    }
    return self::$instance;
  }

  /**
   * Adapter that lets you add normal (non-static) member functions to the queue.
   *
   * Note: Each upgrader instance should only be associated with one
   * task-context; otherwise, this will be non-reentrant.
   *
   * ```
   * <?php echo $_namespace ?>_Upgrader_Base::_queueAdapter($ctx, 'methodName', 'arg1', 'arg2');
   * ```
   */
  public static function _queueAdapter() {
    $instance = self::instance();
    $args = func_get_args();
    $instance->ctx = array_shift($args);
    $instance->queue = $instance->ctx->queue;
    $method = array_shift($args);
    return call_user_func_array([$instance, $method], $args);
  }

  /**
   * <?php echo $_namespace ?>_Upgrader_Base constructor.
   *
   * @param $extensionName
   * @param $extensionDir
   */
  public function __construct($extensionName, $extensionDir) {
    $this->extensionName = $extensionName;
    $this->extensionDir = $extensionDir;
  }

  // ******** Task helpers ********

  /**
   * Run a CustomData file.
   *
   * @param string $relativePath
   *   the CustomData XML file path (relative to this extension's dir)
   * @return bool
   */
  public function executeCustomDataFile($relativePath): bool {
    $xml_file = $this->extensionDir . '/' . $relativePath;
    return $this->executeCustomDataFileByAbsPath($xml_file);
  }

  /**
   * Run a CustomData file
   *
   * @param string $xml_file
   *   the CustomData XML file path (absolute path)
   *
   * @return bool
   */
  protected function executeCustomDataFileByAbsPath($xml_file) {
    $import = new CRM_Utils_Migrate_Import();
    $import->run($xml_file);
    return TRUE;
  }

  /**
   * Run a SQL file.
   *
   * @param string $relativePath
   *   the SQL file path (relative to this extension's dir)
   *
   * @return bool
   */
  public function executeSqlFile($relativePath) {
    CRM_Utils_File::sourceSQLFile(
      CIVICRM_DSN,
      $this->extensionDir . DIRECTORY_SEPARATOR . $relativePath
    );
    return TRUE;
  }

  /**
   * Run the sql commands in the specified file.
   *
   * @param string $tplFile
   *   The SQL file path (relative to this extension's dir).
   *   Ex: "sql/mydata.mysql.tpl".
   *
   * @return bool
   * @throws \CRM_Core_Exception
   */
  public function executeSqlTemplate($tplFile) {
    // Assign multilingual variable to Smarty.
    $upgrade = new CRM_Upgrade_Form();

    $tplFile = CRM_Utils_File::isAbsolute($tplFile) ? $tplFile : $this->extensionDir . DIRECTORY_SEPARATOR . $tplFile;
    $smarty = CRM_Core_Smarty::singleton();
    $smarty->assign('domainID', CRM_Core_Config::domainID());
    CRM_Utils_File::sourceSQLFile(
      CIVICRM_DSN, $smarty->fetch($tplFile), NULL, TRUE
    );
    return TRUE;
  }

  /**
   * Run one SQL query.
   *
   * This is just a wrapper for CRM_Core_DAO::executeSql, but it
   * provides syntactic sugar for queueing several tasks that
   * run different queries
   *
   * @return bool
   */
  public function executeSql($query, $params = []) {
    // FIXME verify that we raise an exception on error
    CRM_Core_DAO::executeQuery($query, $params);
    return TRUE;
  }

  /**
   * Syntactic sugar for enqueuing a task which calls a function in this class.
   *
   * The task is weighted so that it is processed
   * as part of the currently-pending revision.
   *
   * After passing the $funcName, you can also pass parameters that will go to
   * the function. Note that all params must be serializable.
   */
  public function addTask($title) {
    $args = func_get_args();
    $title = array_shift($args);
    $task = new CRM_Queue_Task(
      [get_class($this), '_queueAdapter'],
      $args,
      $title
    );
    return $this->queue->createItem($task, ['weight' => -1]);
  }

  // ******** Revision-tracking helpers ********

  /**
   * Determine if there are any pending revisions.
   *
   * @return bool
   */
  public function hasPendingRevisions() {
    $revisions = $this->getRevisions();
    $currentRevision = $this->getCurrentRevision();

    if (empty($revisions)) {
      return FALSE;
    }
    if (empty($currentRevision)) {
      return TRUE;
    }

    return ($currentRevision < max($revisions));
  }

  /**
   * Add any pending revisions to the queue.
   *
   * @param CRM_Queue_Queue $queue
   */
  public function enqueuePendingRevisions(CRM_Queue_Queue $queue) {
    $this->queue = $queue;

    $currentRevision = $this->getCurrentRevision();
    foreach ($this->getRevisions() as $revision) {
      if ($revision > $currentRevision) {
        $title = E::ts('Upgrade %1 to revision %2', [
          1 => $this->extensionName,
          2 => $revision,
        ]);

        // note: don't use addTask() because it sets weight=-1

        $task = new CRM_Queue_Task(
          [get_class($this), '_queueAdapter'],
          ['upgrade_' . $revision],
          $title
        );
        $this->queue->createItem($task);

        $task = new CRM_Queue_Task(
          [get_class($this), '_queueAdapter'],
          ['setCurrentRevision', $revision],
          $title
        );
        $this->queue->createItem($task);
      }
    }
  }

  /**
   * Get a list of revisions.
   *
   * @return array
   *   revisionNumbers sorted numerically
   */
  public function getRevisions() {
    if (!is_array($this->revisions)) {
      $this->revisions = [];

      $clazz = new ReflectionClass(get_class($this));
      $methods = $clazz->getMethods();
      foreach ($methods as $method) {
        if (preg_match('/^upgrade_(.*)/', $method->name, $matches)) {
          $this->revisions[] = $matches[1];
        }
      }
      sort($this->revisions, SORT_NUMERIC);
    }

    return $this->revisions;
  }

  public function getCurrentRevision() {
    $revision = CRM_Core_BAO_Extension::getSchemaVersion($this->extensionName);
    if (!$revision) {
      $revision = $this->getCurrentRevisionDeprecated();
    }
    return $revision;
  }

  private function getCurrentRevisionDeprecated() {
    $key = $this->extensionName . ':version';
    if ($revision = \Civi::settings()->get($key)) {
      $this->revisionStorageIsDeprecated = TRUE;
    }
    return $revision;
  }

  public function setCurrentRevision($revision) {
    CRM_Core_BAO_Extension::setSchemaVersion($this->extensionName, $revision);
    // clean up legacy schema version store (CRM-19252)
    $this->deleteDeprecatedRevision();
    return TRUE;
  }

  private function deleteDeprecatedRevision() {
    if ($this->revisionStorageIsDeprecated) {
      $setting = new CRM_Core_BAO_Setting();
      $setting->name = $this->extensionName . ':version';
      $setting->delete();
      CRM_Core_Error::debug_log_message("Migrated extension schema revision ID for {$this->extensionName} from civicrm_setting (deprecated) to civicrm_extension.\n");
    }
  }

  // ******** Hook delegates ********

  /**
   * @see https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_install
   */
  public function onInstall() {
    $files = glob($this->extensionDir . '/sql/*_install.sql');
    if (is_array($files)) {
      foreach ($files as $file) {
        CRM_Utils_File::sourceSQLFile(CIVICRM_DSN, $file);
      }
    }
    $files = glob($this->extensionDir . '/sql/*_install.mysql.tpl');
    if (is_array($files)) {
      foreach ($files as $file) {
        $this->executeSqlTemplate($file);
      }
    }
    $files = glob($this->extensionDir . '/xml/*_install.xml');
    if (is_array($files)) {
      foreach ($files as $file) {
        $this->executeCustomDataFileByAbsPath($file);
      }
    }
    if (is_callable([$this, 'install'])) {
      $this->install();
    }
  }

  /**
   * @see https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_postInstall
   */
  public function onPostInstall() {
    $revisions = $this->getRevisions();
    if (!empty($revisions)) {
      $this->setCurrentRevision(max($revisions));
    }
    if (is_callable([$this, 'postInstall'])) {
      $this->postInstall();
    }
  }

  /**
   * @see https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_uninstall
   */
  public function onUninstall() {
    $files = glob($this->extensionDir . '/sql/*_uninstall.mysql.tpl');
    if (is_array($files)) {
      foreach ($files as $file) {
        $this->executeSqlTemplate($file);
      }
    }
    if (is_callable([$this, 'uninstall'])) {
      $this->uninstall();
    }
    $files = glob($this->extensionDir . '/sql/*_uninstall.sql');
    if (is_array($files)) {
      foreach ($files as $file) {
        CRM_Utils_File::sourceSQLFile(CIVICRM_DSN, $file);
      }
    }
  }

  /**
   * @see https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_enable
   */
  public function onEnable() {
    // stub for possible future use
    if (is_callable([$this, 'enable'])) {
      $this->enable();
    }
  }

  /**
   * @see https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_disable
   */
  public function onDisable() {
    // stub for possible future use
    if (is_callable([$this, 'disable'])) {
      $this->disable();
    }
  }

  public function onUpgrade($op, CRM_Queue_Queue $queue = NULL) {
    switch ($op) {
      case 'check':
        return [$this->hasPendingRevisions()];

      case 'enqueue':
        return $this->enqueuePendingRevisions($queue);

      default:
    }
  }

}
# <?php echo $fullName; ?>


![Screenshot](/images/screenshot.png)

(*FIXME: In one or two paragraphs, describe what the extension does and why one would download it. *)

The extension is licensed under [<?php echo $license ?>](LICENSE.txt).

## Requirements

* PHP v7.4+
* CiviCRM (*FIXME: Version number*)

## Installation (Web UI)

Learn more about installing CiviCRM extensions in the [CiviCRM Sysadmin Guide](https://docs.civicrm.org/sysadmin/en/latest/customize/extensions/).

## Installation (CLI, Zip)

Sysadmins and developers may download the `.zip` file for this extension and
install it with the command-line tool [cv](https://github.com/civicrm/cv).

```bash
cd <extension-dir>
cv dl <?php echo $fullName; ?>@https://github.com/FIXME/<?php echo $fullName; ?>/archive/master.zip
```
or
```bash
cd <extension-dir>
cv dl <?php echo $fullName; ?>@https://lab.civicrm.org/extensions/<?php echo $fullName; ?>/-/archive/main/<?php echo $fullName; ?>-main.zip
```

## Installation (CLI, Git)

Sysadmins and developers may clone the [Git](https://en.wikipedia.org/wiki/Git) repo for this extension and
install it with the command-line tool [cv](https://github.com/civicrm/cv).

```bash
git clone https://github.com/FIXME/<?php echo $fullName; ?>.git
cv en <?php echo $mainFile . "\n"; ?>
```
or
```bash
git clone https://lab.civicrm.org/extensions/<?php echo $fullName; ?>.git
cv en <?php echo $mainFile . "\n"; ?>
```

## Getting Started

(* FIXME: Where would a new user navigate to get started? What changes would they see? *)

## Known Issues

(* FIXME *)
<div>
  <p>{{ts('Example directive (<?php echo $dirNameHyp ?>)')}}</p>
  <pre>Options: {{myOptions|json}}</pre>
</div>
<?php
echo "<?php\n";
?>

// Note: $b overrides $a
function _civix_phpunit_settings_merge($a, $b) {
  $result = $a;
  $b = (array) $b;
  foreach ($b as $k1 => $v1) {
    foreach ($v1 as $k2 => $v2) {
      $result[$k1][$k2] = $v2;
    }
  }
  return $result;
}

/**
 * Install extensions on test database
 */
function _civix_phpunit_setUp() {
  static $init = FALSE;
  if ($init) {
    return;
  }
  $init = TRUE;

  global $civicrm_setting;
  //print_r(array('install' => $civicrm_setting['Test']['test_extensions']));
  $apiResult = civicrm_api('Extension', 'install', array(
    'version' => 3,
    'keys' => $civicrm_setting['Test']['test_extensions'],
  ));
  register_shutdown_function('_civix_phpunit_tearDown');
  if ($apiResult['is_error'] != 0) {
    throw new Exception("Failed to pre-install extensions: " . $apiResult['error_message']);
  }
}

/**
 * Uninstall extensions on test database
 */
function _civix_phpunit_tearDown() {
  global $civicrm_setting;
  //print_r(array('disable' => $civicrm_setting['Test']['test_extensions']));
  $result = civicrm_api('Extension', 'disable', array(
    'version' => 3,
    'keys' => $civicrm_setting['Test']['test_extensions'],
  ));
  //print_r(array('uninstall' => $civicrm_setting['Test']['test_extensions']));
  $result = civicrm_api('Extension', 'uninstall', array(
    'version' => 3,
    'keys' => $civicrm_setting['Test']['test_extensions'],
    'removeFiles' => FALSE,
  ));
}

global $civicrm_setting;
$civix_civicrm_setting = <?php var_export($civicrm_setting); ?>;
$civicrm_setting = _civix_phpunit_settings_merge($civix_civicrm_setting, $civicrm_setting);
<?php
echo "<?php\n";
?>

use Civi\Test\HeadlessInterface;
use Civi\Test\HookInterface;
use Civi\Test\TransactionalInterface;

/**
* <?php echo $entityNameCamel ?> API Entity Test
* @group headless
*/
class <?php echo $testClassName ?> extends \PHPUnit\Framework\TestCase implements HeadlessInterface, HookInterface, TransactionalInterface {
  use \Civi\Test\Api3TestTrait;

  /**
  * Set up for headless tests.
*
* Civi\Test has many helpers, like install(), uninstall(), sql(), and sqlFile().
*
* See: https://docs.civicrm.org/dev/en/latest/testing/phpunit/#civitest
*/
public function setUpHeadless() {
return \Civi\Test::headless()
->installMe(__DIR__)
->apply();
}

/**
* The setup() method is executed before the test is executed (optional).
*/
public function setUp() {
parent::setUp();
}

/**
* The tearDown() method is executed after the test was executed (optional)
* This can be used for cleanup.
*/
public function tearDown() {
parent::tearDown();
}

/**
* Simple example test case.
*
* Note how the function name begins with the word "test".
*/
public function testApiExample() {
$result = civicrm_api3('<?php echo $entityNameCamel ?>', '<?php echo $actionNameCamel ?>', array('magicword' => 'sesame'));
$this->assertEquals('Twelve', $result['values'][12]['name']);
}

}
/* Add any CSS rules for Angular module "<?php echo $angularModuleName ?>" */
(function(angular, $, _) {
  // Declare a list of dependencies.
  angular.module('<?php echo $angularModuleName ?>', CRM.angRequires('<?php echo $angularModuleName ?>'));
})(angular, CRM.$, CRM._);
<?xml version="1.0"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
    <file source-language="en" datatype="plaintext" original="file.ext">
        <body>
            <trans-unit id="1">
                <source>Symfony2 is great</source>
                <target>J'aime Symfony2</target>
            </trans-unit>
        </body>
    </file>
</xliff>
<?php

namespace CRM\CivixBundle\Utils;

class Formatting
{
    /**
     * @param string $itemFormat
     *   Ex: "Hello %s.\n"
     *   Ex: "Hello %s from %s.\n"
     *   Ex: "Everyone in %2$s says hello to %1$s."
     * @param iterable $list
     *   Ex: ['Alice', 'Bob']
     *   Ex: [['Alice','Argentina'], ['Bob','Britain']]
     * @return string
     *   Ex: "Hello Alice.\nHello Bob.\n"
     *   Ex: "Hello alice from Argentina!\nHello Bob from Britain!"
     */
    public static function ol(string $itemFormat, iterable $list)
    {
        $buf = '';
        foreach ($list as $int => $item) {
            $item = (array) $item;
            $line = \sprintf($itemFormat, ...$item);
            $buf .= 1 + $int . ". " . $line;
        }
        return \rtrim($buf);
    }
}
<?php

namespace CRM\CivixBundle\Utils;

class Versioning
{
    /**
     * @param array $versions
     *   List of versions. Ex: ['4.7', '5.40', '5.41']
     * @param string $mode
     *   Either return the lowest version ('MIN') or the highest version ('MAX').
     * @return string|null
     */
    public static function pickVer(array $versions, string $mode) : ?string
    {
        \usort($versions, 'version_compare');
        switch ($mode) {
            case 'MIN':
                return $versions ? \reset($versions) : NULL;
            case 'MAX':
                return $versions ? \end($versions) : NULL;
            default:
                throw new \RuntimeException("pickVer({$mode}): Unrecognized mode");
        }
    }
}
<?php

namespace CRM\CivixBundle\Utils;

class Files
{
    /**
     * @param $dir
     * @param $pattern
     * @return array
     */
    public static function findFiles($dir, $pattern)
    {
        if (!\is_dir($dir) || !\is_readable($dir)) {
            return [];
        }
        $dir = \rtrim($dir, '/');
        $todos = [$dir];
        $result = [];
        while (!empty($todos)) {
            $subdir = \array_shift($todos);
            $matches = \glob("{$subdir}/{$pattern}");
            if (\is_array($matches)) {
                foreach ($matches as $match) {
                    if (!\is_dir($match)) {
                        $result[] = $match;
                    }
                }
            }
            // Find subdirs to recurse into.
            if ($dh = \opendir($subdir)) {
                while (\FALSE !== ($entry = \readdir($dh))) {
                    $path = $subdir . \DIRECTORY_SEPARATOR . $entry;
                    // Exclude . (self) and .. (parent) to avoid infinite loop.
                    // Exclude configured exclude dirs.
                    // Exclude dirs we can't read.
                    // Exclude anything that's not a dir.
                    if ($entry !== '.' && $entry !== '..' && (empty($excludeDirsPattern) || !\preg_match($excludeDirsPattern, $path)) && \is_dir($path) && \is_readable($path)) {
                        $todos[] = $path;
                    }
                }
                \closedir($dh);
            }
        }
        return $result;
    }
    /**
     * Determine if any files match the regex.
     *
     * @param string $regex
     * @param array $files
     * @return array
     */
    public static function grepFiles(string $regex, array $files) : array
    {
        $result = [];
        foreach ($files as $file) {
            if (!\file_exists($file)) {
                continue;
            }
            $c = \file_get_contents($file);
            if (\preg_match($regex, $c)) {
                $result[] = $file;
            }
        }
        return $result;
    }
    /**
     * Make a file path relative to some base dir.
     *
     * @param $directory
     * @param $basePath
     *
     * @return string
     */
    public static function relativize($directory, $basePath)
    {
        if (\strtoupper(\substr(\PHP_OS, 0, 3)) === 'WIN') {
            $directory = \strtr($directory, '\\', '/');
            $basePath = \strtr($basePath, '\\', '/');
        }
        if (\substr($directory, 0, \strlen($basePath)) == $basePath) {
            return \substr($directory, \strlen($basePath));
        } else {
            return $directory;
        }
    }
}
<?php

namespace CRM\CivixBundle\Utils;

class Path
{
    /**
     * @var string
     */
    protected $basedir;
    public function __construct($basedir)
    {
        $this->basedir = $basedir;
    }
    public function __toString() : string
    {
        return $this->basedir;
    }
    /**
     * Determine the full path to a file underneath this path
     *
     * ex: $basepath = $path->string()
     * ex: $item = $this->string('subdir', 'file.xml');
     *
     * @return string
     */
    public function string()
    {
        $args = \func_get_args();
        \array_unshift($args, $this->basedir);
        return \implode(\DIRECTORY_SEPARATOR, $args);
    }
    /**
     * Construct the full path to a file underneath this path
     *
     * ex: $item = $this->path('subdir', 'file.xml');
     *
     * @return Path
     */
    public function path()
    {
        $args = \func_get_args();
        \array_unshift($args, $this->basedir);
        return new \CRM\CivixBundle\Utils\Path(\implode(\DIRECTORY_SEPARATOR, $args));
    }
    /**
     * Make a folder for this path (if necessary).
     *
     * @param int $mode
     * @return bool
     *   TRUE if folder exists/is-created. FALSE if an error prevented it.
     */
    public function mkdir($mode = 0777)
    {
        $args = \func_get_args();
        $dir = \call_user_func_array([$this, 'string'], $args);
        if (!\is_dir($dir)) {
            return \mkdir($dir, $mode, \TRUE);
        }
        return \TRUE;
    }
    /**
     * Recursively search for files matching $pattern.
     *
     * @param string $pattern
     *   Ex: 'glob:foobar/*.xml' (non-recursive search)
     *   Ex: 'find:*.whizbang.php' (recursive search, under .)
     *   Ex: 'find:meta/*.whizbang.php' (recursive search, under ./meta)
     * @return array
     */
    public function search($pattern) : array
    {
        [$patternType, $patternValue] = \explode(':', $pattern, 2);
        switch ($patternType) {
            case 'glob':
                return (array) \glob($this->string($patternValue));
            case 'find':
                $relDir = \dirname($patternValue);
                $filePat = \basename($patternValue);
                return \CRM\CivixBundle\Utils\Files::findFiles($this->string($relDir), $filePat);
            default:
                throw new \RuntimeException("Unrecognized file pattern: {$pattern}");
        }
    }
}
<?php

namespace CRM\CivixBundle\Utils;

/**
 * Evil Expressions: What happens when you don't import nikic/php-parser.
 */
class EvilEx
{
    /**
     * Find a function-body, and run it through a filter.
     *
     * Limitation: This only matches top-level functions, where the `function x()` begins in the leftmost,
     * and where the closing `}` is als in the leftmost, and where the body is indented.
     *
     * @param string $body
     *   Full-text file.
     * @param string $function
     *   Name of the function to filter.
     * @param callable $filter
     *   Filter the function-body; return new body.
     *   function(string $body): string
     * @return string
     *   Updated body.
     */
    public static function rewriteFunction(string $body, string $function, callable $filter) : string
    {
        $pattern = "/(\nfunction " . $function . "\\([^{]+\\)\\s*{\n)((\n|  [^\n]*\n)*)(}\n)/m";
        return \preg_replace_callback($pattern, function ($m) use($filter) {
            $body = $m[2];
            $newBody = $filter($body);
            return $m[1] . $newBody . $m[4];
        }, $body);
    }
    /**
     * Searches for a chunk of code - and replaces it.
     *
     * When matching the chunk of code, it specifically ignores whitespace and blank lines.
     *
     * @param string $body
     * @param array $matchChunk
     *   A series of lines which should be found somewhere inside $body (modulo whitespace).
     * @param callable $filterChunk
     *   Filter the matching lines; return new lines.
     *   function(array $matchLines): array
     * @return string
     *   Updated body.
     */
    public static function rewriteMultilineChunk(string $body, array $matchChunk, callable $filterChunk)
    {
        $expectLines = \CRM\CivixBundle\Utils\EvilEx::digestLines($matchChunk);
        $actualLines = \CRM\CivixBundle\Utils\EvilEx::digestLines(\explode("\n", $body));
        foreach (\array_keys($actualLines) as $startOffset) {
            $endOffset = NULL;
            $expectLineNum = 0;
            for ($actualLineNum = $startOffset; $actualLineNum < \count($actualLines); $actualLineNum++) {
                if (empty($actualLines[$actualLineNum]['dig'])) {
                    continue;
                }
                if ($expectLines[$expectLineNum]['dig'] !== $actualLines[$actualLineNum]['dig']) {
                    continue 2;
                }
                $expectLineNum++;
                if ($expectLineNum >= \count($expectLines)) {
                    $endOffset = $actualLineNum;
                    break 2;
                }
            }
        }
        if ($endOffset === NULL) {
            return $body;
        }
        $rawActualLines = \array_column($actualLines, 'raw');
        $matchLines = \array_slice($rawActualLines, $startOffset, $endOffset - $startOffset + 1, \TRUE);
        $newLines = $filterChunk($matchLines);
        \array_splice($rawActualLines, $startOffset, $endOffset - $startOffset + 1, $newLines);
        return \implode("\n", $rawActualLines);
    }
    public static function digestLine(string $line) : string
    {
        return \mb_strtolower(\preg_replace('/\\s+/', '', $line));
    }
    public static function digestLines($lines) : array
    {
        $result = [];
        foreach ($lines as $line) {
            $result[] = ['raw' => $line, 'dig' => static::digestLine($line)];
        }
        return $result;
    }
}
<?php

namespace CRM\CivixBundle\Utils;

class NamingTest extends \CivixPhar\PHPUnit\Framework\TestCase
{
    public function getFullNameExamples()
    {
        return [
            // [$name, $expectValid, $expectShort, $expectCamel]
            ['org.example.foo', \TRUE, 'foo', 'Foo'],
            ['org.example.foo-bar-whiz', \TRUE, 'foo_bar_whiz', 'FooBarWhiz'],
            ['.org.example.foo', \FALSE, NULL, NULL],
            ['civicrm-foo-bar', \TRUE, 'civicrm_foo_bar', 'CivicrmFooBar'],
            ['foo-bar', \TRUE, 'foo_bar', 'FooBar'],
            ['foo--bar', \FALSE, NULL, NULL],
            ['foo-2-foo', \TRUE, 'foo_2_foo', 'Foo2Foo'],
            ['-foo', \FALSE, NULL, NULL],
            ['foo-', \FALSE, NULL, NULL],
            ['foo.', \FALSE, NULL, NULL],
            ['org..foobar', \FALSE, NULL, NULL],
            ['org.example.foo--bar', \FALSE, NULL, NULL],
        ];
    }
    /**
     * @dataProvider getFullNameExamples
     */
    public function testIsValidFullName($name, $expectValid, $expectShort, $expectCamel)
    {
        $this->assertEquals($expectValid, \CRM\CivixBundle\Utils\Naming::isValidFullName($name));
    }
    /**
     * @dataProvider getFullNameExamples
     */
    public function testCreateShortName($name, $expectValid, $expectShort, $expectCamel)
    {
        if (!$expectValid) {
            $this->assertTrue(\TRUE);
            return;
        }
        $this->assertEquals($expectShort, \CRM\CivixBundle\Utils\Naming::createShortName($name));
    }
    /**
     * @dataProvider getFullNameExamples
     */
    public function testCreateCamelName($name, $expectValid, $expectShort, $expectCamel)
    {
        if (!$expectValid) {
            $this->assertTrue(\TRUE);
            return;
        }
        $this->assertEquals($expectCamel, \CRM\CivixBundle\Utils\Naming::createCamelName($name));
    }
    public function getTableNameExamples()
    {
        return [
            // [$inputEntityName, $expectTableName]
            ['Foo', 'civicrm_foo'],
            ['Foobar', 'civicrm_foobar'],
            ['FooBar', 'civicrm_foo_bar'],
            ['FooBar2', 'civicrm_foo_bar2'],
            ['Foo2Bar', 'civicrm_foo2_bar'],
        ];
    }
    /**
     * @dataProvider getTableNameExamples
     */
    public function testCreateTableName($inputEntityName, $expectTableName)
    {
        $this->assertEquals($expectTableName, \CRM\CivixBundle\Utils\Naming::createTableName($inputEntityName));
    }
    public function testCreateClassName()
    {
        $this->assertEquals('CRM_Foobar_Upgrade', \CRM\CivixBundle\Utils\Naming::createClassName('CRM/Foobar', 'Upgrade'));
        $this->assertEquals('CRM_Foobar_Upgrade_Base', \CRM\CivixBundle\Utils\Naming::createClassName('CRM/Foobar', 'Upgrade', 'Base'));
        $this->assertEquals('CRM_Foobar_Upgrade_Base', \CRM\CivixBundle\Utils\Naming::createClassName('CRM/Foobar', ['Upgrade', 'Base']));
        $this->assertEquals('Civi\\Foobar\\Upgrade', \CRM\CivixBundle\Utils\Naming::createClassName('Civi/Foobar', 'Upgrade'));
        $this->assertEquals('Civi\\Foobar\\Upgrade\\Base', \CRM\CivixBundle\Utils\Naming::createClassName('Civi/Foobar', 'Upgrade', 'Base'));
        $this->assertEquals('Civi\\Foobar\\Upgrade\\Base', \CRM\CivixBundle\Utils\Naming::createClassName('Civi/Foobar', ['Upgrade', 'Base']));
    }
    public function testCreateClassFile()
    {
        $this->assertEquals('CRM/Foobar/Upgrade.php', \CRM\CivixBundle\Utils\Naming::createClassFile('CRM/Foobar', 'Upgrade'));
        $this->assertEquals('CRM/Foobar/Upgrade/Base.php', \CRM\CivixBundle\Utils\Naming::createClassFile('CRM/Foobar', 'Upgrade', 'Base'));
        $this->assertEquals('CRM/Foobar/Upgrade/Base.php', \CRM\CivixBundle\Utils\Naming::createClassFile('CRM/Foobar', ['Upgrade', 'Base']));
        $this->assertEquals('Civi/Foobar/Upgrade.php', \CRM\CivixBundle\Utils\Naming::createClassFile('Civi/Foobar', 'Upgrade'));
        $this->assertEquals('Civi/Foobar/Upgrade/Base.php', \CRM\CivixBundle\Utils\Naming::createClassFile('Civi/Foobar', 'Upgrade', 'Base'));
        $this->assertEquals('Civi/Foobar/Upgrade/Base.php', \CRM\CivixBundle\Utils\Naming::createClassFile('Civi/Foobar', ['Upgrade', 'Base']));
    }
}
<?php

namespace CRM\CivixBundle\Utils;

class Functions
{
    /**
     * Create a "curried function" in which some arguments are pre-applied.
     *
     * Ex:
     *   $sha256 = Functions::curry('hash', 'sha256');
     *   echo $sha256('hello world');
     *   // Equivalent to `hash('sha256', 'hello world')`
     *
     * @param callable $callable
     * @param mixed ...$args1
     * @return \Closure
     */
    public static function curry($callable, ...$args1)
    {
        return function (...$args2) use($callable, $args1) {
            $allArgs = \array_merge($args1, $args2);
            return $callable(...$allArgs);
        };
    }
}
<?php

namespace CRM\CivixBundle\Utils;

class Naming
{
    /**
     * Determine if an extension's full symbolic name is well-formed.
     *
     * @param string $fullName
     *   Ex: 'org.example.foo'.
     * @return bool
     */
    public static function isValidFullName($fullName)
    {
        // Primarily alphanumeric, with limited symbols
        return \preg_match('/^[a-z][-_a-z0-9\\.]*$/', $fullName) && !\preg_match('/[-_\\.][-_\\.]/', $fullName) && !\preg_match('/[-_\\.]$/', $fullName);
    }
    /**
     * Based on a full name, determine a short name.
     *
     * @param string $fullName
     *   Ex: 'org.example.foo'
     *   Ex: 'foo-bar'
     * @return string
     *   Ex: 'foo'
     *   Ex: 'foo_bar'
     */
    public static function createShortName($fullName)
    {
        // If the extension name has a . in it, only use the end of the extension
        // name for the short name
        $nameParts = \explode('.', $fullName);
        $shortName = \end($nameParts);
        $shortName = \str_replace('-', '_', $shortName);
        return $shortName;
    }
    /**
     * Based on a full name, determine a camel case name.
     *
     * @param string $fullName
     *   Ex: 'org.example.foo'
     *   Ex: 'foo-bar'
     * @return string
     *   Ex: 'Foo'
     *   Ex: 'FooBar'
     */
    public static function createCamelName($fullName)
    {
        $shortName = self::createShortName($fullName);
        $camelCase = '';
        foreach (\explode('_', $shortName) as $shortNamePart) {
            $camelCase .= \ucfirst($shortNamePart);
        }
        return $camelCase;
    }
    /**
     * Generate a table name for an entity.
     *
     * @param string $entity
     *   Ex: 'FooBar'
     * @return string
     *   Ex: 'civicrm_foo_bar'
     */
    public static function createTableName($entity)
    {
        return 'civicrm_' . \strtolower(\implode('_', \array_filter(\preg_split('/(?=[A-Z])/', $entity))));
    }
    /**
     * Construct a class name, within some namespace.
     *
     * @param string $namespace
     *   Ex: 'CRM_Foobar' or 'Civi\Foobar'.
     * @param string[] ...$suffixes
     *   Ex: ['Page', 'Hello']
     * @return string
     *   Ex: 'CRM_Foobar_Page_Hello' or 'Civi\Foobar\Page\Hello'
     */
    public static function createClassName(string $namespace, ...$suffixes) : string
    {
        $delim = \substr($namespace, 0, 4) === 'CRM/' ? '_' : '\\';
        $parts = [$namespace];
        foreach ($suffixes as $suffix) {
            $parts = \array_merge($parts, \is_array($suffix) ? $suffix : [$suffix]);
        }
        return \str_replace('/', $delim, \implode($delim, $parts));
    }
    /**
     * Construct a class file, within some namespace.
     *
     * @param string $namespace
     *   Ex: 'CRM_Foobar' or 'Civi\Foobar'.
     * @param string[] ...$suffixes
     *   Ex: ['Page', 'Hello']
     * @return string
     *   Ex: 'CRM/Foobar/Page/Hello.php' or 'Civi/Foobar/Page/Hello.php'
     */
    public static function createClassFile(string $namespace, ...$suffixes) : string
    {
        return \preg_replace(';[_/\\\\];', '/', static::createClassName($namespace, ...$suffixes)) . '.php';
    }
}
<?php

namespace CRM\CivixBundle\Utils;

use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CivixPhar\Symfony\Component\Process\PhpExecutableFinder;
use CivixPhar\Symfony\Component\Process\Process;
/**
 * Helper for running Symfony commands
 */
class Commands
{
    /**
     * Create a new process which executes a different commands
     *
     * @param string $cmd
     * @return \Symfony\Component\Process\Process
     */
    public static function createProcess($cmd, $timeout = 300)
    {
        $process = new Process(self::createShellCommand($cmd), NULL, NULL, NULL, $timeout);
        return $process;
    }
    /**
     * Generate the shell statement for invoking of the Symfony commands
     *
     * @param $cmd symfony command
     * @return string a valid shell command
     */
    public static function createShellCommand($cmd)
    {
        $php = \escapeshellarg(self::getPhp());
        $console = \escapeshellarg($_SERVER['PHP_SELF']);
        return $php . ' ' . $console . ' ' . $cmd;
    }
    protected static function getPhp()
    {
        $phpFinder = new PhpExecutableFinder();
        if (!($phpPath = $phpFinder->find())) {
            throw new \RuntimeException('The php executable could not be found, add it to your PATH environment variable and try again');
        }
        return $phpPath;
    }
    /**
     * Determine the full path to an executable
     *
     * @param $name
     * @return string|FALSE
     */
    public static function findExecutable($name)
    {
        $paths = \explode(\PATH_SEPARATOR, \getenv('PATH'));
        foreach ($paths as $path) {
            if (\file_exists("{$path}/{$name}")) {
                return "{$path}/{$name}";
            }
        }
        return \FALSE;
    }
}
<?php

namespace CRM\CivixBundle;

class UpgradeList
{
    /**
     * @var array|null
     */
    protected $upgrades = NULL;
    /**
     * Get the highest known version.
     *
     * @return string
     */
    public function getHeadVersion() : string
    {
        return \array_key_last($this->getUpgrades());
    }
    /**
     * @return array
     *   array(string $version => string $filePath)
     */
    public function getUpgrades() : array
    {
        if ($this->upgrades === NULL) {
            $this->upgrades = $this->scan();
        }
        return $this->upgrades;
    }
    /**
     * Get a list of upgrades appropriate to a particular codebase.
     *
     * @param string $startVersion
     *   The initial/start version of the codebase.
     * @return array
     *   array(string $version => string $filePath)
     */
    public function findUpgrades(string $startVersion) : array
    {
        return \array_filter($this->getUpgrades(), function ($upgradeVersion) use($startVersion) {
            return (bool) \version_compare($upgradeVersion, $startVersion, '>');
        }, \ARRAY_FILTER_USE_KEY);
    }
    /**
     * Scan for upgrade files.
     *
     * @return array
     *   array(string $version => string $filePath)
     */
    protected function scan() : array
    {
        $parseVer = function ($file) {
            return \basename($file, '.up.php');
        };
        $upgrades = [];
        $iter = new \DirectoryIterator(\CRM\CivixBundle\Application::findCivixDir() . '/upgrades');
        foreach ($iter as $file) {
            /** @var \SplFileInfo $file */
            if (\preg_match(';\\.up\\.php$;', $file->getBasename())) {
                $upgrades[$parseVer($file->getBasename())] = $file->getPathname();
            }
        }
        \uksort($upgrades, 'version_compare');
        return $upgrades;
    }
}
<?php

namespace CRM\CivixBundle;

use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
interface Builder
{
    public function loadInit(&$ctx);
    public function init(&$ctx);
    public function load(&$ctx);
    public function save(&$ctx, OutputInterface $output);
}
<?php

namespace CRM\CivixBundle;

class SkippedMethodException extends \RuntimeException
{
}
<?php

namespace CRM\CivixBundle;

use CRM\CivixBundle\Command\AddAngularDirectiveCommand;
use CRM\CivixBundle\Command\AddAngularModuleCommand;
use CRM\CivixBundle\Command\AddAngularPageCommand;
use CRM\CivixBundle\Command\AddApiCommand;
use CRM\CivixBundle\Command\AddCaseTypeCommand;
use CRM\CivixBundle\Command\AddCustomDataCommand;
use CRM\CivixBundle\Command\AddEntityCommand;
use CRM\CivixBundle\Command\AddEntityBoilerplateCommand;
use CRM\CivixBundle\Command\AddFormCommand;
use CRM\CivixBundle\Command\AddPageCommand;
use CRM\CivixBundle\Command\AddReportCommand;
use CRM\CivixBundle\Command\AddSearchCommand;
use CRM\CivixBundle\Command\AddTestCommand;
use CRM\CivixBundle\Command\AddThemeCommand;
use CRM\CivixBundle\Command\AddUpgraderCommand;
use CRM\CivixBundle\Command\BuildCommand;
use CRM\CivixBundle\Command\ConfigGetCommand;
use CRM\CivixBundle\Command\ConfigSetCommand;
use CRM\CivixBundle\Command\InfoGetCommand;
use CRM\CivixBundle\Command\InfoSetCommand;
use CRM\CivixBundle\Command\InitCommand;
use CRM\CivixBundle\Command\MixinCommand;
use CRM\CivixBundle\Command\PingCommand;
use CRM\CivixBundle\Command\TestRunCommand;
use CRM\CivixBundle\Command\UpgradeCommand;
class Application extends \CivixPhar\Symfony\Component\Console\Application
{
    /**
     * Primary entry point for execution of the standalone command.
     */
    public static function main($binDir)
    {
        $application = new \CRM\CivixBundle\Application('civix', 'v23.08.2');
        $application->run();
    }
    public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
    {
        parent::__construct($name, $version);
        $this->setCatchExceptions(\TRUE);
        $this->addCommands($this->createCommands());
    }
    /**
     * Construct command objects
     *
     * @return array of Symfony Command objects
     */
    public function createCommands($context = 'default')
    {
        $commands = [];
        $commands[] = new AddAngularDirectiveCommand();
        $commands[] = new AddAngularModuleCommand();
        $commands[] = new AddAngularPageCommand();
        $commands[] = new AddApiCommand();
        $commands[] = new AddCaseTypeCommand();
        $commands[] = new AddCustomDataCommand();
        $commands[] = new AddEntityCommand();
        $commands[] = new AddEntityBoilerplateCommand();
        $commands[] = new AddFormCommand();
        $commands[] = new AddPageCommand();
        $commands[] = new AddReportCommand();
        $commands[] = new AddSearchCommand();
        $commands[] = new AddTestCommand();
        $commands[] = new AddThemeCommand();
        $commands[] = new AddUpgraderCommand();
        $commands[] = new BuildCommand();
        $commands[] = new ConfigGetCommand();
        $commands[] = new ConfigSetCommand();
        $commands[] = new InitCommand();
        $commands[] = new MixinCommand();
        $commands[] = new PingCommand();
        $commands[] = new TestRunCommand();
        $commands[] = new UpgradeCommand();
        $commands[] = new InfoGetCommand();
        $commands[] = new InfoSetCommand();
        return $commands;
    }
    /**
     * Find the base path of the current extension
     *
     * @return string
     *   Ex: "/var/www/extension/org.example.foobar".
     */
    public static function findExtDir()
    {
        $cwd = \rtrim(\getcwd(), '/');
        if (\file_exists("{$cwd}/info.xml")) {
            return $cwd;
        } else {
            throw new \RuntimeException("Failed to find \"info.xml\" ({$cwd}/). Are you running in the right directory?");
        }
    }
    public static function findCivixDir() : string
    {
        return \dirname(__DIR__, 3);
    }
}
<?php

namespace CRM\CivixBundle;

/**
 * Helper methods called via `composer compile`.
 *
 * Note that the application is still being setup, so it may be ill-advised to use higher-level services.
 */
class ComposerCompile
{
    /**
     * Download the mixin files
     *
     * Note: We want to read the list from `mixin-backports.php` because we can track extra metadata.
     *
     * @param array $task
     */
    public static function downloadMixins(array $task) : void
    {
        $civix = \dirname(__DIR__, 3);
        $mixinListFile = "{$civix}/mixin-backports.php";
        $mixinListTimestamp = \filemtime($mixinListFile);
        $mixins = (require $mixinListFile);
        foreach ($mixins as $id => $mixin) {
            $checksum = \file_exists($mixin['local']) ? \hash('sha256', \file_get_contents($mixin['local'])) : '';
            if (!\file_exists($mixin['local']) || $checksum !== $mixin['sha256']) {
                \printf(" - Download %s\n", $mixin['local']);
                $content = \file_get_contents($mixin['remote']);
                $contentChecksum = \hash('sha256', $content);
                if ($contentChecksum !== $mixin['sha256']) {
                    throw new \RuntimeException("Download from {$mixin['remote']} has wrong checksum. (expect={$mixin['sha256']}, actual={$contentChecksum})");
                }
                static::putFile($mixin['local'], $content);
            }
        }
    }
    protected static function putFile(string $path, string $content) : void
    {
        $outDir = \dirname($path);
        if (!\is_dir($outDir)) {
            if (!\mkdir($outDir, 0777, \TRUE)) {
                throw new \RuntimeException("Failed to make dir: {$outDir}");
            }
        }
        if (\FALSE === \file_put_contents($path, $content)) {
            throw new \RuntimeException("Failed to write file: {$path}");
        }
    }
}
<?php

namespace CRM\CivixBundle\Builder;

use CRM\CivixBundle\Services;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
class PHPUnitGenerateInitFiles
{
    /**
     * @param $bootstrapFile
     * @param $ctx
     * @param \Symfony\Component\Console\Output\OutputInterface $output
     * @param $renderTemplateName
     */
    public function initPhpunitBootstrap($bootstrapFile, &$ctx, OutputInterface $output)
    {
        if (!\file_exists($bootstrapFile)) {
            $dirs = new \CRM\CivixBundle\Builder\Dirs([\dirname($bootstrapFile)]);
            $dirs->save($ctx, $output);
            $output->writeln(\sprintf('<info>Write</info> %s', $bootstrapFile));
            \file_put_contents($bootstrapFile, Services::templating()->render('phpunit-boot-cv.php.php', $ctx));
        } else {
            $output->writeln(\sprintf('<comment>Skip %s: file already exists</comment>', $bootstrapFile));
        }
    }
    /**
     * @param $phpunitXmlFile
     * @param $ctx
     * @param \Symfony\Component\Console\Output\OutputInterface $output
     */
    public function initPhpunitXml($phpunitXmlFile, &$ctx, OutputInterface $output)
    {
        if (!\file_exists($phpunitXmlFile)) {
            $phpunitXml = new \CRM\CivixBundle\Builder\PhpUnitXML($phpunitXmlFile);
            $phpunitXml->init($ctx);
            $phpunitXml->save($ctx, $output);
        } else {
            $output->writeln(\sprintf('<comment>Skip %s: file already exists</comment>', $phpunitXmlFile));
        }
    }
}
<?php

namespace CRM\CivixBundle\Builder;

use CRM\CivixBundle\Builder;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
/**
 * Build/update a file based on a template
 */
class CustomDataXML implements Builder
{
    protected $customGroupIds, $ufGroupIds, $path, $overwrite;
    /**
     * @var \CRM_Utils_Migrate_Export
     */
    protected $export;
    /**
     * @param bool|string $overwrite ; TRUE (always overwrite), FALSE (preserve with error), 'ignore' (preserve quietly)
     */
    public function __construct($customGroupIds, $ufGroupIds, $path, $overwrite)
    {
        $this->customGroupIds = $customGroupIds;
        $this->ufGroupIds = $ufGroupIds;
        $this->path = $path;
        $this->overwrite = $overwrite;
        $this->export = new \CRM_Utils_Migrate_Export();
        $this->export->buildCustomGroups($this->customGroupIds);
        $this->export->buildUFGroups($this->ufGroupIds);
    }
    public function loadInit(&$ctx)
    {
    }
    public function init(&$ctx)
    {
    }
    public function load(&$ctx)
    {
    }
    /**
     * Write the xml document
     */
    public function save(&$ctx, OutputInterface $output)
    {
        if (\file_exists($this->path) && $this->overwrite === 'ignore') {
            // do nothing
        } elseif (\file_exists($this->path) && !$this->overwrite) {
            $output->writeln("<error>Skip " . $this->path . ": file already exists</error>");
        } else {
            $output->writeln("<info>Write</info> " . $this->path);
            \file_put_contents($this->path, $this->export->toXML());
        }
    }
}
<?php

namespace CRM\CivixBundle\Builder;

use SimpleXMLElement;
use DOMDocument;
use CRM\CivixBundle\Builder;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
/**
 * Build/update a file based on a template
 */
class License implements Builder
{
    protected $name;
    /**
     * @param $overwrite scalar; TRUE (always overwrite), FALSE (preserve with error), 'ignore' (preserve quietly)
     */
    public function __construct(\CivixPhar\LicenseData\License $license, $path, $overwrite)
    {
        $this->license = $license;
        $this->path = $path;
        $this->overwrite = $overwrite;
    }
    public function loadInit(&$ctx)
    {
    }
    public function init(&$ctx)
    {
    }
    public function load(&$ctx)
    {
    }
    /**
     * Write the xml document
     */
    public function save(&$ctx, OutputInterface $output)
    {
        if (\file_exists($this->path) && $this->overwrite === 'ignore') {
            // do nothing
        } elseif (\file_exists($this->path) && !$this->overwrite) {
            $output->writeln("<error>Skip " . $this->path . ": file already exists</error>");
        } else {
            $output->writeln("<info>Write</info> " . $this->path);
            $text = \strtr($this->license->getText(), ['<YEAR>' => \date('Y'), '<OWNER>' => \sprintf('%s <%s>', $ctx['author'], $ctx['email']), '<TITLE>' => \sprintf('Package: %s', $ctx['fullName'])]);
            \file_put_contents($this->path, $text);
        }
    }
}
<?php

namespace CRM\CivixBundle\Builder;

use CRM\CivixBundle\Builder;
use CRM\CivixBundle\Services;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
/**
 * Build/update a file based on a template
 */
class Template implements Builder
{
    protected $template;
    protected $path;
    protected $xml;
    protected $templateEngine;
    protected $enable;
    /**
     * @param string $template
     * @param string $path
     * @param bool|string $overwrite TRUE (always overwrite), FALSE (preserve with error), 'ignore' (preserve quietly)
     * @param \Symfony\Component\Templating\EngineInterface|null $templateEngine
     * @param
     */
    public function __construct(string $template, string $path, $overwrite, $templateEngine = NULL)
    {
        $this->template = $template;
        $this->path = $path;
        $this->overwrite = $overwrite;
        $this->templateEngine = $templateEngine ?: Services::templating();
        $this->enable = \FALSE;
    }
    public function loadInit(&$ctx)
    {
    }
    public function init(&$ctx)
    {
    }
    public function load(&$ctx)
    {
    }
    /**
     * Write the xml document
     */
    public function save(&$ctx, OutputInterface $output)
    {
        $parent = \dirname($this->path);
        if (!\is_dir($parent)) {
            \mkdir($parent, \CRM\CivixBundle\Builder\Dirs::MODE, \TRUE);
        }
        if (\file_exists($this->path) && $this->overwrite === 'ignore') {
            // do nothing
        } elseif (\file_exists($this->path) && !$this->overwrite) {
            $output->writeln("<error>Skip " . $this->path . ": file already exists</error>");
        } else {
            $output->writeln("<info>Write</info> " . $this->path);
            \file_put_contents($this->path, $this->templateEngine->render($this->template, $ctx));
        }
    }
}
<?php

namespace CRM\CivixBundle\Builder;

use CRM\CivixBundle\Builder;
use CRM\CivixBundle\Services;
use CRM\CivixBundle\Utils\Versioning;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
/**
 * Copy and rename a class.
 *
 * Note: Assumes PEAR-style (one class per file; nameDelimiter=_; no
 * namespace) and extremely distinctive class name (plain string
 * substitution - no PHP parsing)
 */
class Mixins implements Builder
{
    /**
     * @var \CRM\CivixBundle\Builder\Info
     */
    protected $info;
    /**
     * @var string
     */
    protected $outputDir;
    /**
     * @var string[]
     */
    protected $newConstraints;
    /**
     * @var string[]
     */
    protected $removals;
    /**
     * @var array
     */
    protected $allBackports;
    /**
     * Mixins constructor.
     *
     * @param Info $info
     * @param string $outputDir
     * @param string[]|string $newConstraints
     *   List of constraints to be added or updated.
     *   Ex: ['foo@1.1']
     */
    public function __construct(\CRM\CivixBundle\Builder\Info $info, $outputDir, $newConstraints = [])
    {
        $this->info = $info;
        $this->outputDir = $outputDir;
        $this->newConstraints = (array) $newConstraints;
        $this->removals = [];
        $this->allBackports = Services::mixinBackports();
    }
    public function loadInit(&$ctx)
    {
    }
    public function init(&$ctx)
    {
    }
    public function load(&$ctx)
    {
    }
    public function addMixin(string $newMixinConstraint)
    {
        $this->newConstraints[] = $newMixinConstraint;
    }
    public function removeMixin(string $mixinNameOrConstraint)
    {
        [$mixinName] = \explode('@', $mixinNameOrConstraint);
        $this->removals[] = $mixinName;
    }
    public function removeAllMixins()
    {
        foreach ($this->info->get()->xpath('mixins/mixin') as $x) {
            $this->removeMixin((string) $x);
        }
        foreach ($this->getMixinFiles() as $mixinFile) {
            $this->removeMixin($mixinFile);
        }
    }
    protected function addMixinToXml(string $newMixinConstraint)
    {
        [$newMixinName, $newMixinVer] = \explode('@', $newMixinConstraint);
        /** @var \SimpleXMLElement $xml */
        $xml = $this->info->get();
        foreach ($xml->xpath('mixins/mixin') as $existingMixinXml) {
            [$name, $ver] = \explode('@', (string) $existingMixinXml);
            if ($name === $newMixinName) {
                $existingMixinXml[0] = $newMixinConstraint;
                return $this;
            }
        }
        if (empty($xml->xpath('mixins'))) {
            $xml->addChild('mixins');
        }
        foreach ($xml->xpath('mixins') as $mixinsXml) {
            $mixinsXml->addChild('mixin', $newMixinConstraint);
        }
        return $this;
    }
    /**
     * Write the xml document
     */
    public function save(&$ctx, OutputInterface $output)
    {
        foreach ($this->removals as $removedMixin) {
            $nodes = $this->info->get()->xpath('mixins/mixin[starts-with(text(), "' . $removedMixin . '@")]');
            foreach ($nodes as $existingMixinXml) {
                $output->writeln("<info>Unregister</info> " . $existingMixinXml);
                unset($existingMixinXml[0]);
            }
        }
        // Let's clarify the versions we want.
        $actualDeclarations = \array_merge($this->getDeclaredMixinConstraints(), $this->newConstraints);
        $expectedDeclarations = \array_column(Services::mixlib()->resolve($actualDeclarations), 'mixinConstraint');
        foreach ($expectedDeclarations as $newMixin) {
            $this->addMixinToXml($newMixin);
        }
        $this->reconcileMinimums($output);
        $this->reconcileBackports($output);
    }
    /**
     * Look at the list of `<mixin>` tags, and look at the list of `mixin/*.php` files.
     * Do we need to add or remove any  `mixin/*.php` files?
     *
     * @param \Symfony\Component\Console\Output\OutputInterface $output
     */
    protected function reconcileBackports(OutputInterface $output)
    {
        $declarations = $this->getDeclaredMixinConstraints();
        $declarations[] = 'polyfill';
        $expectedBackports = \array_filter($declarations, function ($d) {
            return !$this->isProvidedByCore($d);
        });
        $existingBackports = $this->getMixinFiles(\TRUE);
        $missingBackports = \array_diff($expectedBackports, $existingBackports);
        $extraBackports = \array_diff($existingBackports, $expectedBackports);
        foreach ($missingBackports as $mixinName) {
            $mixinSpec = Services::mixlib()->get($mixinName);
            $this->createBackportFile($output, $mixinSpec);
        }
        foreach ($extraBackports as $extra) {
            $fileExt = $extra === 'polyfill' ? '.php' : '.mixin.php';
            $file = $this->outputDir . '/' . $extra . $fileExt;
            $backportInfo = $this->getBackportInfo($extra);
            if ($this->isProvidedByCore($extra)) {
                $this->removeBackportFile($output, $file);
            } elseif ($backportInfo && !\in_array($extra, $declarations)) {
                $this->removeBackportFile($output, $file);
            } else {
                $output->writeln("<error>Irregular mixin: \"{$file}\" is in the \"mixins/\" folder but is not referenced by \"info.xml\"! Consider deleting it.</error>");
                // Polyfill-loaders are likely to load the file even if it's not mentioned in info.xml. This old+new runtimes disagree about whether load $file.
            }
        }
    }
    protected function createBackportFile(OutputInterface $output, array $mixin)
    {
        $file = $this->outputDir . '/' . $mixin['mixinFile'];
        if (!\is_dir(\dirname($file))) {
            \mkdir(\dirname($file), \CRM\CivixBundle\Builder\Dirs::MODE, \TRUE);
        }
        $output->writeln("<info>Write</info> {$file}");
        \file_put_contents($file, $mixin['src']);
    }
    protected function removeBackportFile(OutputInterface $output, string $file) : void
    {
        if (\file_exists($file)) {
            $output->writeln("<info>Remove</info> {$file}");
            \unlink($file);
        }
    }
    protected function getMixinFiles(bool $includePolyfill = \FALSE) : array
    {
        $filePattern = $this->outputDir . '/*.mixin.php';
        $result = \array_map(function ($f) {
            return \basename($f, '.mixin.php');
        }, (array) \glob($filePattern));
        if ($includePolyfill && \file_exists($this->outputDir . '/polyfill.php')) {
            $result[] = 'polyfill';
        }
        return $result;
    }
    protected function getBackportInfo(string $mixinConstraint) : array
    {
        $mixinMajor = \preg_replace('/^([^@]+@\\d+)(\\..*)/', '\\1', $mixinConstraint);
        return $this->allBackports[$mixinMajor] ?? [];
    }
    protected function isProvidedByCore(string $mixinConstraint) : bool
    {
        $compatVer = $this->info->getCompatibilityVer('MIN');
        $backportInfo = $this->getBackportInfo($mixinConstraint);
        $result = empty($backportInfo['provided-by']) ? \FALSE : \version_compare($compatVer, $backportInfo['provided-by'], '>=');
        // print_r([__FUNCTION__, '$compatVer'=> $compatVer, '$mixinConstraint' => $mixinConstraint, '$backportInfo' => $backportInfo, $result ? 'true' : 'false']);
        return $result;
    }
    protected function reconcileMinimums(OutputInterface $output) : void
    {
        $currentMin = $this->info->getCompatibilityVer();
        $unmetMinimums = $this->findUnmetMinimums($this->getDeclaredMixinConstraints());
        if ($unmetMinimums) {
            $effectiveMin = Versioning::pickVer($unmetMinimums, 'MAX');
            foreach ($unmetMinimums as $mixinConstraint => $mixinMin) {
                $output->writeln("<comment>! [NOTE] The requirements should be increased because \"{$mixinConstraint}\" requires CiviCRM {$mixinMin}.</comment>");
            }
            $output->writeln("<info>Increase minimum CiviCRM requirement from</info> {$currentMin} <info>to</info> {$effectiveMin}");
            $this->info->raiseCompatibilityMinimum($effectiveMin);
        }
    }
    /**
     * Each required mixin may implicitly require some minimum version of Civi.
     * Does the current `<compatibility>` support these minimums?
     *
     * @param array $mixinConstraints
     *   Ex: ['entity-types-php@1.0.0', 'mgd-php@1.0.0', 'ang-php@1.0.0']
     * @return array
     *   Ex: ['entity-types-php@1.0.0' => '5.45']
     */
    protected function findUnmetMinimums(array $mixinConstraints) : array
    {
        $currentMin = $this->info->getCompatibilityVer();
        $result = [];
        foreach ($mixinConstraints as $mixinConstraint) {
            $info = $this->getBackportInfo($mixinConstraint);
            if (isset($info['minimum']) && \version_compare($currentMin, $info['minimum'], '<')) {
                $result[$mixinConstraint] = $info['minimum'];
            }
        }
        return $result;
    }
    /**
     * Get a list of mixin constraints (from info.xml).
     *
     * @return string[]
     *   Ex: ['foo@1.0', 'bar@2.0']
     */
    public function getDeclaredMixinConstraints() : array
    {
        $items = $this->info->get()->xpath('mixins/mixin');
        $mixins = [];
        foreach ($items as $item) {
            if ((string) $item) {
                $mixins[] = (string) $item;
            }
        }
        return $mixins;
    }
}
<?php

namespace CRM\CivixBundle\Builder;

use CRM\CivixBundle\Builder;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
/**
 * Read/write a serialized data file based on PHP's var_export() format
 */
class Ini implements Builder
{
    /**
     * @var string
     */
    protected $path;
    /**
     * @var mixed
     */
    protected $data;
    /**
     * @var
     */
    protected $header;
    public function __construct($path, $header = NULL)
    {
        $this->path = $path;
        $this->header = $header;
    }
    /**
     * Get the xml document
     *
     * @return array
     */
    public function get()
    {
        return $this->data;
    }
    public function set($data)
    {
        $this->data = $data;
    }
    public function loadInit(&$ctx)
    {
        if (\file_exists($this->path)) {
            $this->load($ctx);
        } else {
            $this->init($ctx);
        }
    }
    /**
     * Initialize a new var_export() document
     */
    public function init(&$ctx)
    {
    }
    /**
     * Read from file
     */
    public function load(&$ctx)
    {
        $this->data = \parse_ini_file($this->path, \TRUE);
    }
    /**
     * Write the xml document
     */
    public function save(&$ctx, OutputInterface $output)
    {
        $output->writeln("<info>Write</info> " . $this->path);
        $content = '';
        foreach ($this->data as $topKey => $data) {
            $content .= "[{$topKey}]\n";
            foreach ($data as $key => $value) {
                if (\is_array($value)) {
                    $content .= $this->flatten($key, $value);
                } else {
                    $content .= "{$key}={$value}\n";
                }
            }
        }
        \file_put_contents($this->path, $content);
    }
    protected function flatten($prefix, $values)
    {
        $content = '';
        foreach ($values as $key => $value) {
            if (\is_array($values)) {
                $content .= $this->flatten("{$prefix[$key]}", $value);
            } else {
                $content .= "{$prefix[$key]}={$value}\n";
            }
        }
        return $content;
    }
}
<?php

namespace CRM\CivixBundle\Builder;

use CRM\CivixBundle\Builder;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
/**
 * Copy and rename a class.
 *
 * Note: Assumes PEAR-style (one class per file; nameDelimiter=_; no
 * namespace) and extremely distinctive class name (plain string
 * substitution - no PHP parsing)
 */
class CopyClass implements Builder
{
    protected $srcClassName;
    protected $tgtClassName;
    protected $tgtFile;
    protected $xml;
    protected $enable;
    protected $filter;
    /**
     * @param $overwrite scalar; TRUE (always overwrite), FALSE (preserve with error), 'ignore' (preserve quietly)
     */
    public function __construct($srcClassName, $tgtClassName, $tgtFile, $overwrite, $filter = \FALSE)
    {
        $this->srcClassName = $srcClassName;
        $this->tgtClassName = $tgtClassName;
        $this->tgtFile = $tgtFile;
        $this->overwrite = $overwrite;
        $this->enable = \FALSE;
        $this->filter = $filter;
    }
    public function loadInit(&$ctx)
    {
    }
    public function init(&$ctx)
    {
    }
    public function load(&$ctx)
    {
    }
    /**
     * Write the xml document
     */
    public function save(&$ctx, OutputInterface $output)
    {
        // NOTE: assume classloaders, etal, are already setup
        $clazz = new \ReflectionClass($this->srcClassName);
        if (\file_exists($this->tgtFile) && $this->overwrite == 'ignore') {
            // do nothing
        } elseif (\file_exists($this->tgtFile) && !$this->overwrite) {
            $output->writeln("<error>Skip " . $this->tgtFile . ": file already exists</error>");
        } else {
            $output->writeln("<info>Write</info> " . $this->tgtFile);
            $content = \file_get_contents($clazz->getFileName(), \TRUE);
            // FIXME parser
            $content = \strtr($content, [$this->srcClassName => $this->tgtClassName]);
            if (\is_callable($this->filter)) {
                $content = \call_user_func($this->filter, $content);
            }
            \file_put_contents($this->tgtFile, $content);
        }
    }
}
<?php

namespace CRM\CivixBundle\Builder;

use CRM\CivixBundle\Builder;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
/**
 * A collection of builders
 */
class Collection implements Builder
{
    public function __construct($builders = [])
    {
        $this->builders = $builders;
    }
    public function loadInit(&$ctx)
    {
        foreach ($this->builders as $builder) {
            $builder->loadInit($ctx);
        }
    }
    public function init(&$ctx)
    {
        foreach ($this->builders as $builder) {
            $builder->init($ctx);
        }
    }
    public function load(&$ctx)
    {
        \print_r($this);
        foreach ($this->builders as $builder) {
            $builder->load($ctx);
        }
    }
    public function save(&$ctx, OutputInterface $output)
    {
        foreach ($this->builders as $builder) {
            $builder->save($ctx, $output);
        }
    }
}
<?php

namespace CRM\CivixBundle\Builder;

use CRM\CivixBundle\Builder;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
/**
 * Build/update a file based on a template
 */
class CopyFile implements Builder
{
    protected $from;
    protected $to;
    protected $xml;
    protected $enable;
    /**
     * @param $overwrite scalar; TRUE (always overwrite), FALSE (preserve with error), 'ignore' (preserve quietly)
     */
    public function __construct($from, $to, $overwrite)
    {
        $this->from = $from;
        $this->to = $to;
        $this->overwrite = $overwrite;
        $this->enable = \FALSE;
    }
    public function loadInit(&$ctx)
    {
    }
    public function init(&$ctx)
    {
    }
    public function load(&$ctx)
    {
    }
    /**
     * Write the xml document
     */
    public function save(&$ctx, OutputInterface $output)
    {
        if (\file_exists($this->to) && $this->overwrite == 'ignore') {
            // do nothing
        } elseif (\file_exists($this->to) && !$this->overwrite) {
            $output->writeln("<error>Skip " . $this->to . ": file already exists</error>");
        } else {
            $output->writeln("<info>Write</info> " . $this->to);
            $content = \file_get_contents($this->from, \TRUE);
            \file_put_contents($this->to, $content);
        }
    }
}
<?php

namespace CRM\CivixBundle\Builder;

use CRM\CivixBundle\Builder;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
/**
 * Build/update empty directories
 */
class Dirs implements Builder
{
    // Mask applied to new new directory permissions.
    // Note: Permissions will be further restricted by umask
    const MODE = 0777;
    public function __construct($paths)
    {
        $this->paths = $paths;
    }
    public function loadInit(&$ctx)
    {
    }
    public function init(&$ctx)
    {
    }
    public function load(&$ctx)
    {
    }
    public function save(&$ctx, OutputInterface $output)
    {
        \sort($this->paths);
        foreach ($this->paths as $dir) {
            $parts = \explode(\DIRECTORY_SEPARATOR, $dir);
            if (!\is_dir($dir)) {
                //quiet//$output->writeln("<info>Create ${dir}/</info>");
                \mkdir($dir, self::MODE, \TRUE);
            } else {
                // $output->writeln("<comment>Found ${dir}/</comment>");
            }
        }
    }
}
<?php

namespace CRM\CivixBundle\Builder;

use SimpleXMLElement;
use DOMDocument;
use CRM\CivixBundle\Builder;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
/**
 * Build/update an XML file
 */
class XML implements Builder
{
    protected $path, $xml;
    public function __construct($path)
    {
        $this->path = $path;
    }
    /**
     * Get the xml document
     *
     * @return SimpleXMLElement
     */
    public function get()
    {
        return $this->xml;
    }
    public function set($xml)
    {
        $this->xml = $xml;
    }
    public function loadInit(&$ctx)
    {
        if (\file_exists($this->path)) {
            $this->load($ctx);
        } else {
            $this->init($ctx);
        }
    }
    /**
     * Initialize a new XML document
     */
    public function init(&$ctx)
    {
    }
    /**
     * Read from file
     */
    public function load(&$ctx)
    {
        $dom = new DomDocument();
        $dom->load($this->path);
        $dom->xinclude();
        $this->xml = \simplexml_import_dom($dom);
    }
    /**
     * Write the xml document
     */
    public function save(&$ctx, OutputInterface $output)
    {
        $output->writeln("<info>Write</info> " . $this->path);
        // force pretty printing with encode/decode cycle
        $outXML = $this->get()->saveXML();
        $xml = new DOMDocument();
        $xml->encoding = 'iso-8859-1';
        $xml->preserveWhiteSpace = \FALSE;
        $xml->formatOutput = \TRUE;
        $xml->loadXML($outXML);
        \file_put_contents($this->path, $xml->saveXML());
    }
}
<?php

namespace CRM\CivixBundle\Builder;

use CRM\CivixBundle\Services;
use CRM\CivixBundle\Utils\Versioning;
use CivixPhar\LicenseData\Repository;
use SimpleXMLElement;
/**
 * Build/update info.xml
 */
class Info extends \CRM\CivixBundle\Builder\XML
{
    public function init(&$ctx)
    {
        $ctx += [
            // FIXME: Auto-detect current installed civi version
            'compatibilityVerMin' => 5.45,
        ];
        $xml = new SimpleXMLElement('<extension></extension>');
        $xml->addAttribute('key', $ctx['fullName']);
        $xml->addAttribute('type', $ctx['type']);
        // $xml->addChild('downloadUrl', 'http://FIXME/' . $ctx['fullName'] . '.zip');
        $xml->addChild('file', $ctx['mainFile']);
        $xml->addChild('name', $ctx['fullName']);
        $xml->addChild('description', 'FIXME');
        // urls
        $xml->addChild('license', isset($ctx['license']) ? $ctx['license'] : 'FIXME');
        $maint = $xml->addChild('maintainer');
        $maint->addChild('author', isset($ctx['author']) ? $ctx['author'] : 'FIXME');
        $maint->addChild('email', isset($ctx['email']) ? $ctx['email'] : 'FIXME@example.com');
        $urls = $xml->addChild('urls');
        $urls->addChild('url', 'http://FIXME')->addAttribute('desc', 'Main Extension Page');
        $urls->addChild('url', 'http://FIXME')->addAttribute('desc', 'Documentation');
        $urls->addChild('url', 'http://FIXME')->addAttribute('desc', 'Support');
        $licenses = new Repository();
        if (isset($ctx['license']) && ($license = $licenses->get($ctx['license']))) {
            $urls->addChild('url', $license->getUrl())->addAttribute('desc', 'Licensing');
        } else {
            $urls->addChild('url', 'http://FIXME')->addAttribute('desc', 'Licensing');
        }
        $xml->addChild('releaseDate', \date('Y-m-d'));
        $xml->addChild('version', '1.0');
        $xml->addChild('develStage', 'alpha');
        $xml->addChild('compatibility')->addChild('ver', $ctx['compatibilityVerMin']);
        $xml->addChild('comments', 'This is a new, undeveloped module');
        // APIv4 will look for classes+files matching 'Civi/Api4', and
        // classes for this ext should be 'Civi\MyExt', so this is the
        // simplest default.
        $classloader = $xml->addChild('classloader');
        $crmClassloaderRule = $classloader->addChild('psr0');
        $crmClassloaderRule->addAttribute('prefix', 'CRM_');
        $crmClassloaderRule->addAttribute('path', '.');
        $civiClassloaderRule = $classloader->addChild('psr4');
        $civiClassloaderRule->addAttribute('prefix', 'Civi\\');
        $civiClassloaderRule->addAttribute('path', 'Civi');
        // store extra metadata to facilitate code manipulation
        $civix = $xml->addChild('civix');
        if (isset($ctx['namespace'])) {
            $civix->addChild('namespace', $ctx['namespace']);
        }
        $civix->addChild('format', $ctx['civixFormat'] ?? Services::upgradeList()->getHeadVersion());
        if (isset($ctx['angularModuleName'])) {
            $civix->addChild('angularModule', $ctx['angularModuleName']);
        }
        if (isset($ctx['typeInfo'])) {
            $typeInfo = $xml->addChild('typeInfo');
            foreach ($ctx['typeInfo'] as $key => $value) {
                $typeInfo->addChild($key, $value);
            }
        }
        $this->set($xml);
    }
    public function load(&$ctx)
    {
        parent::load($ctx);
        $attrs = $this->get()->attributes();
        $ctx['fullName'] = (string) $attrs['key'];
        $items = $this->get()->xpath('file');
        $ctx['mainFile'] = (string) \array_shift($items);
        $items = $this->get()->xpath('civix/namespace');
        $ctx['namespace'] = (string) \array_shift($items);
        $items = $this->get()->xpath('civix/angularModule');
        $angularModule = (string) \array_shift($items);
        $ctx['angularModuleName'] = !empty($angularModule) ? $angularModule : $ctx['mainFile'];
        $items = $this->get()->xpath('civix/format');
        $ctx['civixFormat'] = (string) \array_shift($items);
        $ctx['compatibilityVerMin'] = $this->getCompatibilityVer('MIN');
        $ctx['compatibilityVerMax'] = $this->getCompatibilityVer('MAX');
    }
    /**
     * Get the extension's full name
     *
     * @return string (e.g. "com.example.myextension)
     */
    public function getKey()
    {
        $attrs = $this->get()->attributes();
        return (string) $attrs['key'];
    }
    /**
     * Get the extension's file name (short name).
     * @return string
     */
    public function getFile() : string
    {
        $items = $this->get()->xpath('file');
        return (string) \array_shift($items);
    }
    /**
     * Get the extension type
     *
     * @return string (e.g. "module", "report")
     */
    public function getType()
    {
        $attrs = $this->get()->attributes();
        return (string) $attrs['type'];
    }
    /**
     * Get the user-friendly name of the extension.
     *
     * @return string
     */
    public function getExtensionName()
    {
        return empty($this->xml->name) ? 'FIXME' : $this->xml->name;
    }
    /**
     * Get the namespace into which civix should place files
     * @return string
     */
    public function getNamespace() : string
    {
        $items = $this->get()->xpath('civix/namespace');
        $result = (string) \array_shift($items);
        if ($result) {
            return $result;
        } else {
            throw new \RuntimeException("Failed to lookup civix/namespace in info.xml");
        }
    }
    /**
     * Determine the target version of CiviCRM.
     *
     * @param string $mode
     *   The `info.xml` file may list multiple `<ver>` tags, and we will only return one.
     *   Either return the lowest-compatible `<ver>` ('MIN') or the highest-compatible `<ver>` ('MAX').
     * @return string|null
     */
    public function getCompatibilityVer(string $mode = 'MIN') : ?string
    {
        $vers = [];
        foreach ($this->get()->xpath('compatibility/ver') as $ver) {
            $vers[] = (string) $ver;
        }
        return Versioning::pickVer($vers, $mode);
    }
    /**
     * Increase the minimum requirement (`<compatibility><ver>X.Y</ver></compatibility>`).
     *
     * There may be multiple `<ver>` expressions. They will be reconciled as follows:
     * - Any existing constraints (which are < X.Y) will be dropped.
     * - Any existing constraints (which are >= X.Y) will be kept.
     * - If necessary, it will add a constraint for `X.Y`.
     *
     * @param string $newMin
     *   Ex: '5.27'
     */
    public function raiseCompatibilityMinimum(string $newMin) : void
    {
        /** @var \SimpleXMLElement $xml */
        $xml = $this->get();
        $keptConstraints = 0;
        foreach ($xml->xpath('compatibility/ver') as $existingConstraint) {
            if (\version_compare((string) $existingConstraint, $newMin, '>=')) {
                $keptConstraints++;
            } else {
                // dom_import_simplexml($existingConstraint)->remove();
                $dom = \dom_import_simplexml($existingConstraint);
                $dom->parentNode->removeChild($dom);
            }
        }
        if (!$keptConstraints) {
            if (empty($xml->xpath('compatibility'))) {
                $xml->addChild('compatibility');
            }
            $xml->compatibility->addChild('ver', $newMin);
        }
    }
    /**
     * Determine the civix-format version of this extension.
     *
     * If the value isn't explicitly available, inspect some related fields to make an
     * educated  guess.
     *
     * @return string
     */
    public function detectFormat() : string
    {
        $items = $this->get()->xpath('civix/format');
        $explicit = (string) \array_shift($items);
        if ($explicit) {
            return $explicit;
        }
        $mixins = $this->get()->xpath('mixins');
        return empty($mixins) ? '13.10.0' : '22.05.0';
    }
    public function getClassloaders() : array
    {
        $loaders = [];
        foreach (['psr0', 'psr4'] as $type) {
            $items = $this->get()->xpath("classloader/{$type}");
            foreach ($items as $item) {
                $attrs = $item->attributes();
                $loaders[] = ['type' => $type, 'prefix' => (string) $attrs['prefix'], 'path' => (string) $attrs['path']];
            }
        }
        return $loaders;
    }
    /**
     * @param array $loaders
     *   Ex: [['type' => 'psr4', 'prefix' => 'Civi\Foobar\', 'path' => 'src']]
     */
    public function setClassLoaders(array $loaders) : void
    {
        foreach ($this->xml->xpath('classloader/*') as $child) {
            unset($child[0]);
        }
        $classloader = $this->findCreateElement($this->xml, 'classloader');
        foreach ($loaders as $loader) {
            $rule = $classloader->addChild($loader['type']);
            $rule->addAttribute('prefix', $loader['prefix']);
            $rule->addAttribute('path', $loader['path']);
        }
    }
    private function findCreateElement(SimpleXMLElement $base, string $tag) : SimpleXMLElement
    {
        foreach ($base->xpath($tag) as $existingClassloader) {
            return $existingClassloader;
        }
        return $base->addChild($tag);
    }
}
<?php

namespace CRM\CivixBundle\Builder;

use SimpleXMLElement;
use CRM\CivixBundle\Builder\XML;
/**
 * Build/update menu xml file
 */
class Menu extends XML
{
    public function init(&$ctx)
    {
        $xml = new SimpleXMLElement('<menu></menu>');
        $this->set($xml);
    }
    public function hasPath($path)
    {
        $items = $this->get()->xpath(\sprintf('item[path="%s"]', $path));
        return !empty($items);
    }
    public function addItem($ctx, $title, $fullClass, $path)
    {
        $item = $this->get()->addChild('item');
        $item->addChild('path', $path);
        $item->addChild('page_callback', $fullClass);
        $item->addChild('title', $title);
        $item->addChild('access_arguments', 'access CiviCRM');
    }
}
<?php

namespace CRM\CivixBundle\Builder;

use SimpleXMLElement;
use CRM\CivixBundle\Builder\XML;
/**
 * Build/update info.xml
 */
class PhpUnitXML extends XML
{
    public function init(&$ctx)
    {
        $xml = new SimpleXMLElement('<phpunit></phpunit>');
        $xml->addAttribute('backupGlobals', 'false');
        $xml->addAttribute('backupStaticAttributes', 'false');
        $xml->addAttribute('colors', 'true');
        $xml->addAttribute('convertErrorsToExceptions', 'true');
        $xml->addAttribute('convertNoticesToExceptions', 'true');
        $xml->addAttribute('convertWarningsToExceptions', 'true');
        $xml->addAttribute('convertDeprecationsToExceptions', 'true');
        $xml->addAttribute('processIsolation', 'false');
        $xml->addAttribute('stopOnFailure', 'false');
        $xml->addAttribute('cacheResult', 'false');
        $xml->addAttribute('bootstrap', 'tests/phpunit/bootstrap.php');
        $this->set($xml);
        $this->addTestSuite('My Test Suite', ['./tests/phpunit']);
        $this->get()->addChild('filter')->addChild('whitelist')->addChild('directory', './')->addAttribute('suffix', '.php');
        $listenerXml = $this->get()->addChild('listeners')->addChild('listener');
        $listenerXml->addAttribute('class', 'Civi\\Test\\CiviTestListener');
        $listenerXml->addChild('arguments', '');
    }
    /**
     * @param string $name
     * @param array $dirs
     */
    public function addTestSuite($name, $dirs)
    {
        $testsuites = $this->get()->addChild('testsuites');
        // FIXME: find/load
        $testsuite = $testsuites->addChild('testsuite');
        $testsuite->addAttribute('name', $name);
        foreach ($dirs as $dir) {
            $testsuite->addChild('directory', $dir);
        }
    }
}
<?php

namespace CRM\CivixBundle\Builder;

use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CRM\CivixBundle\Builder;
use CRM\CivixBundle\Utils\Path;
class Module implements Builder
{
    public function __construct($templateEngine)
    {
        $this->templateEngine = $templateEngine;
    }
    public function loadInit(&$ctx)
    {
    }
    public function init(&$ctx)
    {
    }
    public function load(&$ctx)
    {
    }
    public function save(&$ctx, OutputInterface $output)
    {
        $basedir = new Path($ctx['basedir']);
        $module = new \CRM\CivixBundle\Builder\Template('module.php.php', $basedir->string($ctx['mainFile'] . '.php'), 'ignore', $this->templateEngine);
        $module->save($ctx, $output);
        $moduleCivix = new \CRM\CivixBundle\Builder\Template('module.civix.php.php', $basedir->string($ctx['mainFile'] . '.civix.php'), \TRUE, $this->templateEngine);
        $moduleCivix->save($ctx, $output);
    }
}
<?php

namespace CRM\CivixBundle\Builder;

use CRM\CivixBundle\Builder;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CivixPhar\Symfony\Component\VarExporter\VarExporter;
/**
 * Read/write a serialized data file based on PHP's var_export() format
 */
class PhpData implements Builder
{
    /**
     * @var string
     */
    protected $path;
    /**
     * @var mixed
     */
    protected $data;
    /**
     * @var
     */
    protected $header;
    public function __construct($path, $header = NULL)
    {
        $this->path = $path;
        $this->header = $header;
    }
    /**
     * Get the xml document
     *
     * @return array
     */
    public function get()
    {
        return $this->data;
    }
    public function set($data)
    {
        $this->data = $data;
    }
    public function loadInit(&$ctx)
    {
        if (\file_exists($this->path)) {
            $this->load($ctx);
        } else {
            $this->init($ctx);
        }
    }
    /**
     * Initialize a new var_export() document
     */
    public function init(&$ctx)
    {
    }
    /**
     * Read from file
     */
    public function load(&$ctx)
    {
        $this->data = (include $this->path);
    }
    /**
     * Write the xml document
     */
    public function save(&$ctx, OutputInterface $output)
    {
        $output->writeln("<info>Write</info> " . $this->path);
        $content = "<?php\n";
        if ($this->header) {
            $content .= $this->header;
        }
        $content .= "\nreturn ";
        $content .= \preg_replace_callback(
            '/^ +/m',
            // VarExporter indents with 4x spaces. Civi/Drupal code standard is 2x spaces.
            function ($m) {
                $spaces = $m[0];
                return \substr($spaces, 0, \ceil(\strlen($spaces) / 2));
            },
            VarExporter::export($this->data)
        );
        $content .= ";\n";
        \file_put_contents($this->path, $content);
    }
}
<?php

namespace CRM\CivixBundle;

use CRM\CivixBundle\Builder\Info;
use CRM\CivixBundle\Builder\Mixins;
use CRM\CivixBundle\Utils\Path;
use CivixPhar\Symfony\Component\Console\Style\SymfonyStyle;
/**
 * The "Upgrader" class is a utility provided to various upgrade-scripts.
 */
class Upgrader
{
    /**
     * @var \Symfony\Component\Console\Input\InputInterface
     * @readonly
     */
    public $input;
    /**
     * @var \Symfony\Component\Console\Output\OutputInterface
     * @readonly
     */
    public $output;
    /**
     * @var \Symfony\Component\Console\Style\SymfonyStyle
     * @readonly
     */
    public $io;
    /**
     * @var \CRM\CivixBundle\Utils\Path
     * @readonly
     */
    public $baseDir;
    /**
     * Reference to the parsed `info.xml` file.
     *
     * @var \CRM\CivixBundle\Builder\Info
     * @readonly
     */
    public $infoXml;
    private $_ctx;
    /**
     * @param \Symfony\Component\Console\Input\InputInterface $input
     * @param \Symfony\Component\Console\Output\OutputInterface $output
     * @param \CRM\CivixBundle\Utils\Path $baseDir
     *   The folder that contains the extension.
     */
    public function __construct(\CivixPhar\Symfony\Component\Console\Input\InputInterface $input, \CivixPhar\Symfony\Component\Console\Output\OutputInterface $output, Path $baseDir)
    {
        $this->input = $input;
        $this->output = $output;
        $this->io = new SymfonyStyle($input, $output);
        $this->baseDir = $baseDir;
        $this->reloadInfo();
    }
    // -----------------------------------------
    // These filters are fairly general-purpose.
    /**
     * Apply a filter to the extension's main `.php` file.
     *
     * @param callable $function
     *   Filter the content of the main `.php` file.
     *   Signature: `function($info, string $content): string`
     */
    public function updateModulePhp(callable $function) : void
    {
        $fileName = $this->baseDir->string($this->infoXml->getFile() . '.php');
        $oldContent = \file_get_contents($fileName);
        $newContent = $function($this->infoXml, $oldContent);
        if ($newContent !== $oldContent) {
            $this->output->writeln('<info>Write</info> ' . $fileName);
            \file_put_contents($fileName, $newContent);
        }
    }
    /**
     * Apply a filter to the `info.xml` file.
     *
     * @param callable $function
     *   This is a filter function which revises the info.xml.
     *   Signature: `function(Info $info): void`
     */
    public function updateInfo(callable $function) : void
    {
        $function($this->infoXml);
        $this->infoXml->save($this->_ctx, $this->output);
    }
    /**
     * @param string $newVersion
     */
    public function updateFormatVersion(string $newVersion)
    {
        $this->updateInfo(function (Info $info) use($newVersion) {
            $this->io->writeln("<info>Set civix format to </info>{$newVersion}<info> in </info>info.xml");
            $info->get()->civix->format = $newVersion;
        });
    }
    /**
     * Apply a filter to the "Mixins" list.
     *
     * @param callable $function
     *   signature: `function(Mixins $mixins): void`
     */
    public function updateMixins(callable $function) : void
    {
        $mixins = new Mixins($this->infoXml, $this->baseDir->string('mixin'));
        $function($mixins);
        $mixins->save($this->_ctx, $this->output);
        $this->infoXml->save($this->_ctx, $this->output);
    }
    /**
     * Update the content of a series of text files.
     *
     * Useful if you just want to do regex.
     *
     * @param iterable $fileNames
     *   List of files to examine.
     * @param callable $function
     *   Filter-function to define updated content.
     *   signature: `function(string $file, string $content): string`
     */
    public function updateTextFiles(iterable $fileNames, callable $function)
    {
        foreach ($fileNames as $fileName) {
            $oldContent = \file_get_contents($fileName);
            $newContent = $function($fileName, $oldContent);
            if ($oldContent !== $newContent) {
                $this->output->writeln('<info>Write</info> ' . $fileName);
                \file_put_contents($fileName, $newContent);
            }
        }
    }
    // -------------------------------------------------
    // These filters are for fairly specific situations.
    /**
     * Add a hook-delegation stub to the main `mymodule.php` file.
     *
     * @param string $hook
     *   Ex: 'civicrm_entityTypes'
     * @param string $mainArg
     *   Ex: '&$entityTypes'
     * @param string|null $help
     *   Explanatory message. Help the user decide whether to add the hook.
     */
    public function addHookDelegation(string $hook, string $mainArg, ?string $help = NULL) : void
    {
        $this->updateModulePhp(function (\CRM\CivixBundle\Builder\Info $infoXml, string $content) use($hook, $mainArg, $help) {
            $io = $this->io;
            $contains = function ($needle) use(&$content) {
                return \strpos($content, $needle) !== \FALSE;
            };
            $mainFunc = $infoXml->getFile() . '_' . $hook;
            $delegateFunc = '_' . $infoXml->getFile() . '_civix_' . $hook;
            $delegateArg = \str_replace('&', '', $mainArg);
            if ($contains($delegateFunc)) {
                // They've already dealt with this.
                return $content;
            }
            $fullHook = 'hook_' . $hook;
            $stub = ["/**", " * Implements {$fullHook}().", " *", " * @link https://docs.civicrm.org/dev/en/latest/hooks/{$fullHook}", " */", "function {$mainFunc}({$mainArg}) {", "  {$delegateFunc}({$delegateArg});", "}"];
            $io->writeln("<info>This extension does not implement </info>{$fullHook}<info>, but this is included in newer templates. This is a typical example:</info>");
            $io->write("\n");
            $this->showCode($stub);
            if ($help) {
                $io->note($help);
            }
            $actions = ['y' => 'Yes. Add live-code.', 'c' => 'Yes. Add comment-code.', 'n' => 'No. Do not add anything.'];
            if ($contains($mainFunc)) {
                $io->note(["This extension may already have a customized version of \"{$mainFunc}()\".\n" . "civix will not add live-code because that could create a conflict."]);
                unset($actions['y']);
            }
            if ($help || $contains($mainFunc)) {
                $io->note(["If you are unsure what to do, you can safely add comment-code. " . "Comment-code will not change the behavior. " . "It merely provides an example to reference if you encounter issues in the future."]);
            }
            $action = $io->choice("Add {$mainFunc}?", $actions, $contains($mainFunc) ? 'c' : 'y');
            switch ($action) {
                case 'y':
                    $content = \rtrim($content, "\n") . "\n\n" . \implode("\n", $stub) . "\n";
                    break;
                case 'c':
                    $content = \rtrim($content, "\n") . "\n\n" . \implode("\n", \array_map(function ($line) {
                        return "// {$line}";
                    }, $stub)) . "\n";
                    break;
                case 'n':
                    break;
            }
            return $content;
        });
    }
    /**
     * Find any calls to a stub function and disable them.
     *
     * @param string[] $names
     *   Ex: '_foobar_civix_civicrm_managed'
     */
    public function removeHookDelegation(array $names) : void
    {
        $this->updateModulePhp(function (\CRM\CivixBundle\Builder\Info $info, string $content) use($names) {
            $mainPhp = $this->infoXml->getFile() . '.php';
            $oldLines = \explode("\n", $content);
            $newLines = [];
            foreach ($oldLines as $lineNum => $line) {
                foreach ($names as $name) {
                    $nameQuoted = \preg_quote($name, '|');
                    if (\preg_match("|^(\\s*)//(\\s*)({$nameQuoted}\\(.*)|", $line, $m)) {
                        // ok, already disabled
                    } elseif (\preg_match("|^(\\s*)return ({$nameQuoted}\\([^;]*;\\s*)\$|", $line, $m)) {
                        // Easy case - we can disable it.
                        $this->io->writeln(\sprintf("<info>Found reference to obsolete function </info>%s()<info> at </info>%s:%d<info>.</info>\n", $name, $mainPhp, 1 + $lineNum));
                        $this->showLine($oldLines, $lineNum);
                        $this->io->writeln(\sprintf("<info>Redacting call in </info>%s:%d<info></info>\n", $mainPhp, 1 + $lineNum));
                        $line = $m[1] . 'return;';
                    } elseif (\preg_match("|^(\\s*)?({$nameQuoted}\\([^;]*;\\s*)\$|", $line, $m)) {
                        // Easy case - we can disable it.
                        $this->io->writeln(\sprintf("<info>Found reference to obsolete function </info>%s()<info> at </info>%s:%d<info>.</info>\n", $name, $mainPhp, 1 + $lineNum));
                        $this->showLine($oldLines, $lineNum);
                        $this->io->writeln(\sprintf("<info>Removing line </info>%s:%d<info></info>\n", $mainPhp, 1 + $lineNum));
                        $line = NULL;
                    } elseif (\preg_match("|{$nameQuoted}|", (string) $line, $m)) {
                        $this->io->writeln(\sprintf("<info>Found reference to obsolete function </info>%s()<info> at </info>%s:%d<info>.</info>\n", $name, $mainPhp, 1 + $lineNum));
                        $this->showLine($oldLines, $lineNum);
                        $this->io->writeln("\n<info>Obsolete functions should usually be removed, but this line looks unusual.</info>");
                        $action = $this->io->choice("What should we do with this line?", ['r' => 'Remove this line', 'k' => 'Keep this line', 'c' => 'Comment out this line', 'f' => 'Add "FIXME" comment']);
                        switch ($action) {
                            case 'c':
                                $line = '// ' . $line;
                                break;
                            case 'f':
                                $line = "// FIXME: The function {$name}() is obsolete.\n" . $line;
                                break;
                            case 'r':
                                $line = NULL;
                                break;
                            case 'k':
                                break;
                            default:
                                throw new \RuntimeException("Error: Unrecongized option ({$action})");
                        }
                    }
                    if ($line === NULL) {
                        // If any $name matches and causes removal, then we don't need to check the other $names.
                        break;
                    }
                }
                if ($line !== NULL) {
                    $newLines[] = $line;
                }
            }
            return \implode("\n", $newLines);
        });
    }
    /**
     * Find any functions like `mymodle_civicrm_foobar(...) {}` (ie with an empty body).
     */
    public function cleanEmptyHooks()
    {
        $this->updateModulePhp(function ($infoXml, $content) {
            $comment = "/\\*\\*\n( \\*.*\n)* \\*/";
            $funcName = $infoXml->getFile() . "_civicrm_[a-zA-Z0-9_]+";
            $funcArgs = "\\([^\\)]*\\)";
            $typeHint = ":[ ]*[|?a-z]+";
            $startBody = "\\{[^\\}]*\\}";
            /* For empty functions, this grabs everything. For non-empty functions, this may just grab the opening segment. */
            $content = \preg_replace_callback(";({$comment})?\n\\s*function ({$funcName})({$funcArgs})[ ]*({$typeHint})?\\s*({$startBody})\n*;m", function ($m) {
                $func = $m[3];
                // Is our start-body basically empty (notwithstanding silly things - like `{}`, `//Comment`, and `return;`)?
                $mStartBody = \explode("\n", $m[6]);
                $mStartBody = \preg_replace(';^\\s*;', '', $mStartBody);
                $mStartBody = \preg_grep(';^\\/\\/;', $mStartBody, \PREG_GREP_INVERT);
                $mStartBody = \preg_grep('/^$/', $mStartBody, \PREG_GREP_INVERT);
                $mStartBody = \preg_grep('/^[\\{\\}]$/', $mStartBody, \PREG_GREP_INVERT);
                $mStartBody = \preg_grep('/^return;$/', $mStartBody, \PREG_GREP_INVERT);
                $mStartBody = \preg_grep('/^\\{\\s*\\}$/', $mStartBody, \PREG_GREP_INVERT);
                if (!empty($mStartBody)) {
                    // There is some kind of substance in here...
                    return $m[0];
                }
                $this->io->note("The function \"{$func}()\" now appears to be empty.");
                $this->showCode(\explode("\n", $m[0]));
                if ($this->io->confirm("Delete the empty function \"{$func}()\"?")) {
                    return "\n\n";
                } else {
                    return $m[0];
                }
            }, $content);
            $content = \preg_replace("|\n}\n\n+|m", "\n}\n\n", $content);
            return $content;
        });
    }
    public function cleanEmptyLines() : void
    {
        $this->updateModulePhp(function ($infoXml, $content) {
            // It might be better to cleanup more stuff, but this is enough to get IdempotentUpgradeTest to pass.
            return \rtrim($content, "\n") . "\n";
        });
    }
    /**
     * Ensure that the `mixin/` folder is in-sync with the current 'info.xml'.
     */
    public function reconcileMixins() : void
    {
        $this->updateMixins(function (\CRM\CivixBundle\Builder\Mixins $mixins) {
            // noop
        });
    }
    public function addMixins(array $mixinConstraints) : void
    {
        $msg = \count($mixinConstraints) > 1 ? 'Enable mixins' : 'Enable mixin';
        $this->io->writeln("<info>{$msg}</info> " . \implode(', ', $mixinConstraints));
        $this->updateMixins(function (\CRM\CivixBundle\Builder\Mixins $mixins) use($mixinConstraints) {
            foreach ($mixinConstraints as $mixinConstraint) {
                $mixins->addMixin($mixinConstraint);
            }
        });
    }
    // -------------------------------------------------
    // These are some helper utilities.
    /**
     * Re-read the `info.xml` file.
     *
     * @return array
     */
    public function reloadInfo() : array
    {
        $this->_ctx = [];
        $this->_ctx['basedir'] = \CRM\CivixBundle\Application::findExtDir();
        $this->_ctx['type'] = 'module';
        $this->infoXml = new Info($this->baseDir->string('info.xml'));
        $this->infoXml->load($this->_ctx);
        return [$this->infoXml, $this->_ctx];
    }
    /**
     * Show a list of lines and highlight a specific line.
     * @param array $lines
     * @param int $focusLine
     */
    public function showLine(array $lines, int $focusLine) : void
    {
        $low = \max(0, $focusLine - 2);
        $high = \min(\count($lines), $focusLine + 2);
        $this->showCode($lines, $low, $high, $focusLine, $focusLine);
    }
    /**
     * Show a chunk of code.
     *
     * @param array $lines
     * @param int|null $low
     *   The first line to show
     * @param int|null $high
     *   The last line to show
     * @param int|null $focusStart
     *   The first line to highlight (within the overall code)
     * @param int|null $focusEnd
     *   The last line to highlight (within the overall code).
     */
    public function showCode(array $lines, ?int $low = NULL, ?int $high = NULL, ?int $focusStart = NULL, ?int $focusEnd = NULL) : void
    {
        if ($low === NULL || $low < 0) {
            $low = 0;
        }
        if ($high === NULL || $high >= \count($lines)) {
            $high = \count($lines) - 1;
        }
        for ($i = $low; $i <= $high; $i++) {
            $fmt = \sprintf('% 5d', 1 + $i);
            if ($focusStart !== NULL && $focusEnd !== NULL && $i >= $focusStart && $i <= $focusEnd) {
                $this->io->write("<error>*{$fmt}: ");
                $this->io->write($lines[$i], SymfonyStyle::OUTPUT_RAW);
                $this->io->write("</error>");
            } else {
                $this->io->write("<comment> {$fmt}:</comment> ");
                $this->io->writeln($lines[$i], SymfonyStyle::OUTPUT_RAW);
            }
        }
    }
}
<?php

namespace CRM\CivixBundle;

use Civi\Cv\Bootstrap;
use CRM\CivixBundle\Utils\Path;
use Mixlib;
use CivixPhar\Symfony\Component\Filesystem\Filesystem;
use CivixPhar\Symfony\Component\Templating\EngineInterface;
use CivixPhar\Symfony\Component\Templating\PhpEngine;
use CivixPhar\Symfony\Component\Templating\TemplateNameParser;
use CivixPhar\Symfony\Component\Templating\Loader\FilesystemLoader;
class Services
{
    protected static $cache;
    public static function boot($options = [])
    {
        if (!isset(self::$cache['boot'])) {
            $cwd = \getcwd();
            // TODO: It might be better for civix commands to use cv's BootTrait.
            if (!empty(\getenv('CIVICRM_BOOT'))) {
                \Civi\Cv\CmsBootstrap::singleton()->addOptions($options)->bootCms()->bootCivi();
            } else {
                $options = \array_merge(['prefetch' => \FALSE], $options);
                Bootstrap::singleton()->boot($options);
                \CRM_Core_Config::singleton();
                \CRM_Utils_System::loadBootStrap([], \FALSE);
            }
            \chdir($cwd);
            self::$cache['boot'] = 1;
        }
    }
    /**
     * Get a reference to the API class.
     *
     * Pre-requisite: call boot() to startup CiviCRM.
     *
     * @return \civicrm_api3
     */
    public static function api3()
    {
        if (!isset(self::$cache['civicrm_api3'])) {
            if (!\stream_resolve_include_path('api/class.api.php')) {
                throw new \RuntimeException("Booted CiviCRM, but failed to find 'api/class.api.php'");
            }
            require_once 'api/class.api.php';
            self::$cache['civicrm_api3'] = new \civicrm_api3();
        }
        return self::$cache['civicrm_api3'];
    }
    /**
     * @return EngineInterface
     */
    public static function templating()
    {
        if (!isset(self::$cache['templating'])) {
            $loader = new FilesystemLoader(__DIR__ . '/Resources/views/Code/%name%');
            self::$cache['templating'] = new PhpEngine(new TemplateNameParser(), $loader);
        }
        return self::$cache['templating'];
    }
    /**
     * Read any config data (~/.civix/civix.ini).
     *
     * @return array
     */
    public static function config()
    {
        if (!isset(self::$cache['config'])) {
            $file = self::configDir()->string('civix.ini');
            if (\file_exists($file)) {
                self::$cache['config'] = \parse_ini_file($file, \TRUE);
            } else {
                self::$cache['config'] = [];
            }
        }
        return self::$cache['config'];
    }
    /**
     * @return Path
     */
    public static function configDir()
    {
        if (!isset(self::$cache['configDir'])) {
            $homes = [
                \getenv('HOME'),
                // Unix
                \getenv('USERPROFILE'),
            ];
            foreach ($homes as $home) {
                if (!empty($home)) {
                    self::$cache['configDir'] = new Path($home . '/.civix');
                    break;
                }
            }
            if (empty($home)) {
                throw new \RuntimeException('Failed to locate home directory. Please set HOME (Unix) or USERPROFILE (Windows).');
            }
        }
        return self::$cache['configDir'];
    }
    /**
     * @return Path
     */
    public static function cacheDir()
    {
        if (!isset(self::$cache['cacheDir'])) {
            self::$cache['cacheDir'] = self::configDir()->path('cache');
        }
        return self::$cache['cacheDir'];
    }
    /**
     * @return \Mixlib
     */
    public static function mixlib() : Mixlib
    {
        if (!isset(self::$cache[__FUNCTION__])) {
            if (!\class_exists('Mixlib')) {
                // For some reason, autoloading rule doesn't for this doesn't survive box/php-scoper/phar transofrmation.
                require_once \dirname(__DIR__, 3) . '/extern/src/Mixlib.php';
            }
            self::$cache[__FUNCTION__] = new Mixlib(\dirname(__DIR__, 3) . '/extern/mixin');
        }
        return self::$cache[__FUNCTION__];
    }
    /**
     * @return array
     */
    public static function mixinBackports() : array
    {
        if (!isset(self::$cache[__FUNCTION__])) {
            self::$cache[__FUNCTION__] = (require \CRM\CivixBundle\Application::findCivixDir() . '/mixin-backports.php');
        }
        return self::$cache[__FUNCTION__];
    }
    /**
     * @return \CRM\CivixBundle\UpgradeList
     */
    public static function upgradeList() : \CRM\CivixBundle\UpgradeList
    {
        if (!isset(self::$cache[__FUNCTION__])) {
            self::$cache[__FUNCTION__] = new \CRM\CivixBundle\UpgradeList();
        }
        return self::$cache[__FUNCTION__];
    }
}
<?php

namespace CRM\CivixBundle\Command;

use CRM\CivixBundle\Builder\Mixins;
use CRM\CivixBundle\Services;
use CivixPhar\Symfony\Component\Console\Helper\Table;
use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CRM\CivixBundle\Utils\Path;
use CivixPhar\Symfony\Component\Console\Style\SymfonyStyle;
class MixinCommand extends \CRM\CivixBundle\Command\AbstractCommand
{
    protected function configure()
    {
        Services::templating();
        $this->setName('mixin')->setDescription('Inspect and update list of mixins')->addArgument('key', InputArgument::OPTIONAL, "Extension identifier (Ex: \"foo-bar\" or \"org.example.foo-bar\")")->addOption('disable', NULL, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'List of mixins to disable')->addOption('enable', NULL, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'List of mixins to enable')->addOption('enable-all', NULL, InputOption::VALUE_NONE, 'Enable all known mixins')->addOption('disable-all', NULL, InputOption::VALUE_NONE, 'Disable all known mixins')->setHelp("Inspect and update list of mixins\n" . "\n" . "<comment>Examples:</comment>\n" . "  civix mixin\n" . "  civix mixin --enable-all\n" . "  civix mixin --enable=ang-php@1,setting-php@1\n" . "  civix mixin --disable=ang-php@1\n" . "  civix mixin --disable-all --enable=mgd-php@1\n" . "\n");
        parent::configure();
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->assertCurrentFormat();
        $ctx = [];
        $ctx['type'] = 'module';
        $ctx['basedir'] = \CRM\CivixBundle\Application::findExtDir();
        $basedir = new Path($ctx['basedir']);
        $info = $this->getModuleInfo($ctx);
        $mixins = new Mixins($info, $basedir->string('mixin'));
        $change = \FALSE;
        if ($input->getOption('disable-all')) {
            $change = \TRUE;
            $this->disableAll($input, $output, $mixins);
        }
        if ($input->getOption('enable-all')) {
            $change = \TRUE;
            $this->enableAll($input, $output, $mixins);
        }
        if ($input->getOption('disable')) {
            $change = \TRUE;
            $this->disableSome($input, $output, $mixins);
        }
        if ($input->getOption('enable')) {
            $change = \TRUE;
            $this->enableSome($input, $output, $mixins);
        }
        if ($change) {
            $mixins->save($ctx, $output);
            $info->save($ctx, $output);
        } else {
            $io = new SymfonyStyle($input, $output);
            $this->showList($io, $mixins);
        }
        return 0;
    }
    protected function enableAll(InputInterface $input, OutputInterface $output, Mixins $mixins)
    {
        $all = $this->findAllMixins();
        foreach ($all as $spec) {
            $mixins->addMixin($spec['mixinConstraint']);
        }
    }
    protected function disableAll(InputInterface $input, OutputInterface $output, Mixins $mixins) : void
    {
        $mixins->removeAllMixins();
    }
    protected function enableSome(InputInterface $input, OutputInterface $output, Mixins $mixins)
    {
        $newMixins = $this->parseOptionList($input, 'enable');
        $this->validateNames($newMixins);
        foreach ($newMixins as $newMixin) {
            $mixins->addMixin($newMixin);
        }
    }
    protected function disableSome(InputInterface $input, OutputInterface $output, Mixins $mixins)
    {
        $removals = $this->parseOptionList($input, 'disable');
        foreach ($removals as $removal) {
            $mixins->removeMixin($removal);
        }
    }
    protected function showList(SymfonyStyle $io, Mixins $mixins)
    {
        $mixlib = Services::mixlib();
        $mixinBackports = \preg_grep(';@;', \array_keys(Services::mixinBackports()));
        $toNameMajor = function ($mixinConstraint) {
            [$mixinName, $mixinVersion] = \explode('@', $mixinConstraint);
            return $mixinName . '@' . \explode('.', $mixinVersion)[0];
        };
        $nameMajors = \array_unique(\array_merge(\array_map($toNameMajor, $mixins->getDeclaredMixinConstraints()), \array_map($toNameMajor, $mixinBackports)));
        \sort($nameMajors);
        $data = [];
        foreach ($nameMajors as $nameMajor) {
            $data[$nameMajor] = ['name' => \explode('@', $nameMajor)[0], 'status' => 'off', 'constraint' => '', 'available' => ''];
        }
        foreach ($mixins->getDeclaredMixinConstraints() as $mixinConstraint) {
            $nameMajor = $toNameMajor($mixinConstraint);
            [$mixinName, $mixinVersion] = \explode('@', $mixinConstraint);
            $data[$nameMajor]['status'] = 'on';
            $data[$nameMajor]['constraint'] = $mixinVersion;
        }
        foreach ($mixinBackports as $availMixin) {
            $mixinInfo = $mixlib->get($availMixin);
            $nameMajor = $toNameMajor($mixinInfo['mixinConstraint']);
            $data[$nameMajor]['available'] = $mixinInfo['mixinVersion'];
        }
        $io->table(['name', 'status', 'constraint', 'available'], $data);
        $io->writeln('<comment>Note: The format of this command may change in the future.</comment>');
    }
    protected function validateNames(array $mixinNames) : array
    {
        foreach ($mixinNames as $mixinName) {
            if (!\preg_match('/^[-_a-zA-Z0-9]+@[\\d\\.]+$/', $mixinName)) {
                throw new \RuntimeException("Malformed or incomplete option \"{$mixinName}\". (Expected \"{name}@{version}\")");
            }
        }
        return $mixinNames;
    }
    protected function parseOptionList(InputInterface $input, string $optionName)
    {
        $optionValue = (array) $input->getOption($optionName);
        $requested = \explode(',', \implode(',', $optionValue));
        return \array_filter(\array_unique($requested));
    }
    protected function findAllMixins() : iterable
    {
        yield from [];
        $mixlib = Services::mixlib();
        $mixinBackports = \preg_grep(';@;', \array_keys(Services::mixinBackports()));
        \sort($mixinBackports);
        foreach ($mixinBackports as $id) {
            (yield $mixlib->get($id));
        }
    }
}
<?php

namespace CRM\CivixBundle\Command;

use CRM\CivixBundle\Services;
use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CRM\CivixBundle\Builder\Collection;
use CRM\CivixBundle\Builder\Dirs;
use CRM\CivixBundle\Builder\Info;
use CRM\CivixBundle\Builder\Template;
use CRM\CivixBundle\Utils\Path;
class AddAngularDirectiveCommand extends \CRM\CivixBundle\Command\AbstractCommand
{
    protected function configure()
    {
        parent::configure();
        $this->setName('generate:angular-directive')->setDescription('Add a new Angular directive (Civi v4.6+)')->addOption('am', NULL, InputOption::VALUE_REQUIRED, 'Name of the Angular module (default: match the Civi module name)')->addArgument('<directive-name>', InputArgument::REQUIRED, 'Directive name (Ex: "my-directive")')->setHelp('An Angular directive is a custom HTML tag implemented in Javascript.
Directives can be used in many ways -- to define new input elements, new
decorations, or chunks of reusable content.

You should generally include a prefix in the directive name.
For example, directives in Angular core use "ng-*", and
directives in CiviCRM core use "crm-*".

For more, see https://docs.angularjs.org/guide/directive');
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->assertCurrentFormat();
        //// Figure out template data ////
        $ctx = [];
        $ctx['type'] = 'module';
        $ctx['basedir'] = \CRM\CivixBundle\Application::findExtDir();
        $basedir = new Path($ctx['basedir']);
        $info = new Info($basedir->string('info.xml'));
        $info->load($ctx);
        $attrs = $info->get()->attributes();
        if ($attrs['type'] != 'module') {
            $output->writeln('<error>Wrong extension type: ' . $attrs['type'] . '</error>');
            return 1;
        }
        $ctx['tsDomain'] = (string) $attrs['key'];
        $ctx['angularModuleName'] = $input->getOption('am') ? $input->getOption('am') : $ctx['angularModuleName'];
        $ctx['dirNameCamel'] = $this->toCamel($input->getArgument('<directive-name>'));
        $ctx['dirNameHyp'] = $this->toHyphen($input->getArgument('<directive-name>'));
        if (\preg_match('/^' . $ctx['angularModuleName'] . '[A-Z]/', $ctx['dirNameCamel'])) {
            $ctx['baseFileName'] = \preg_replace('/^' . $ctx['angularModuleName'] . '/', '', $ctx['dirNameCamel']);
        } else {
            $output->writeln('<error>Warning: Directive name does not begin with module name.</error>');
            $ctx['baseFileName'] = $ctx['dirNameCamel'];
        }
        $ctx['jsPath'] = $basedir->string('ang', $ctx['angularModuleName'], $ctx['baseFileName'] . '.js');
        $ctx['htmlName'] = \implode('/', ['~', $ctx['angularModuleName'], $ctx['baseFileName'] . '.html']);
        $ctx['htmlPath'] = $basedir->string('ang', $ctx['angularModuleName'], $ctx['baseFileName'] . '.html');
        //// Construct files ////
        $output->writeln("<info>Initialize Angular directive</info> " . $ctx['dirNameHyp'] . " <info>(aka </info>" . $ctx['dirNameCamel'] . "<info>)</info>");
        $ext = new Collection();
        $ext->builders['dirs'] = new Dirs([\dirname($ctx['jsPath']), \dirname($ctx['htmlPath'])]);
        $ext->builders['js'] = new Template('angular-dir.js.php', $ctx['jsPath'], \FALSE, Services::templating());
        $ext->builders['html'] = new Template('angular-dir.html.php', $ctx['htmlPath'], \FALSE, Services::templating());
        $ext->init($ctx);
        $ext->save($ctx, $output);
        return 0;
    }
    public function toHyphen($dirName)
    {
        $buf = '';
        foreach (\str_split($dirName) as $char) {
            if ($char >= 'A' && $char <= 'Z') {
                $buf .= '-' . \strtolower($char);
            } else {
                $buf .= $char;
            }
        }
        return \trim(\preg_replace('/-+/', '-', $buf), '-');
    }
    public function toCamel($dirName)
    {
        return \lcfirst(\preg_replace('/ /', '', \ucwords(\preg_replace('/-/', ' ', $dirName))));
    }
}
<?php

namespace CRM\CivixBundle\Command;

use CRM\CivixBundle\Builder\Mixins;
use CRM\CivixBundle\Services;
use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CRM\CivixBundle\Builder\Collection;
use CRM\CivixBundle\Builder\CopyClass;
use CRM\CivixBundle\Builder\CopyFile;
use CRM\CivixBundle\Builder\Dirs;
use CRM\CivixBundle\Builder\PhpData;
use CRM\CivixBundle\Builder\Template;
use CRM\CivixBundle\Utils\Path;
class AddSearchCommand extends \CRM\CivixBundle\Command\AbstractCommand
{
    const GENERIC_SEARCH_TEMPLATE = 'CRM/Contact/Form/Search/Custom.tpl';
    protected function configure()
    {
        parent::configure();
        $this->setName('generate:search')->setDescription('Add a custom search to a module-extension')->addArgument('<ClassName>', InputArgument::REQUIRED, 'Search class name (eg "MySearch")')->addOption('copy', NULL, InputOption::VALUE_OPTIONAL, 'Full class name of an existing search which should be copied (eg "CRM_Contact_Form_Search_Custom_ZipCodeRange")');
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->assertCurrentFormat();
        //// Figure out template data ////
        $ctx = [];
        $ctx['type'] = 'module';
        $ctx['basedir'] = \CRM\CivixBundle\Application::findExtDir();
        $basedir = new Path($ctx['basedir']);
        $info = $this->getModuleInfo($ctx);
        $ctx['searchClassName'] = \strtr($ctx['namespace'], '/', '_') . '_Form_Search_' . $input->getArgument('<ClassName>');
        $ctx['searchClassFile'] = $basedir->string(\strtr($ctx['searchClassName'], '_', '/') . '.php');
        $ctx['searchMgdFile'] = $basedir->string(\strtr($ctx['searchClassName'], '_', '/') . '.mgd.php');
        $ctx['searchTplRelFile'] = \strtr($ctx['searchClassName'], '_', '/') . '.tpl';
        $ctx['searchTplFile'] = $basedir->string('templates', $ctx['searchTplRelFile']);
        //// Construct files ////
        $output->writeln("<info>Initialize search</info> " . $ctx['searchClassName']);
        $ext = new Collection();
        $ext->builders['dirs'] = new Dirs([\dirname($ctx['searchClassFile']), \dirname($ctx['searchMgdFile'])]);
        if (!\file_exists($ctx['searchMgdFile'])) {
            $mgdEntities = [['name' => $ctx['searchClassName'], 'entity' => 'CustomSearch', 'params' => ['version' => 3, 'label' => $input->getArgument('<ClassName>'), 'description' => \sprintf("%s (%s)", $input->getArgument('<ClassName>'), $ctx['fullName']), 'class_name' => $ctx['searchClassName']]]];
            $header = "// This file declares a managed database record of type \"CustomSearch\".\n" . "// The record will be automatically inserted, updated, or deleted from the\n" . "// database as appropriate. For more details, see \"hook_civicrm_managed\" at:\n" . "// https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_managed";
            $ext->builders['mgd.php'] = new PhpData($ctx['searchMgdFile'], $header);
            $ext->builders['mgd.php']->set($mgdEntities);
        }
        if ($srcClassName = $input->getOption('copy')) {
            // we need bootstrap to set up include path to locate file -- but that's it
            Services::boot(['output' => $output]);
            $civicrm_api3 = Services::api3();
            if (!$civicrm_api3 || !$civicrm_api3->local) {
                $output->writeln("<error>--copy requires access to local CiviCRM source tree. Configure civicrm_api3_conf_path.</error>");
                return;
            }
            if (self::findTpl($srcClassName) == self::GENERIC_SEARCH_TEMPLATE) {
                $ext->builders['search.php'] = new CopyClass($srcClassName, $ctx['searchClassName'], $ctx['searchClassFile'], \FALSE);
            } else {
                $ext->builders['dirs']->paths[] = \dirname($ctx['searchTplFile']);
                $origTplFile = self::findTpl($srcClassName);
                $ext->builders['search.php'] = new CopyClass($srcClassName, $ctx['searchClassName'], $ctx['searchClassFile'], \FALSE, function ($phpSrc) use($origTplFile, $ctx) {
                    // i could wile away the hours
                    // conferring with the flowers
                    // consulting with the rain
                    // if i only had a parser
                    return \strtr($phpSrc, [$origTplFile => $ctx['searchTplRelFile']]);
                });
                $ext->builders['page.tpl.php'] = new CopyFile('templates/' . $origTplFile, $ctx['searchTplFile'], \FALSE);
            }
        } else {
            $ext->builders['search.php'] = new Template('search.php.php', $ctx['searchClassFile'], \FALSE, Services::templating());
            // $ext->builders['page.tpl.php'] = new Template('search.tpl.php', $ctx['searchTplFile'], FALSE, Services::templating());
        }
        $ext->builders['mixins'] = new Mixins($info, $basedir->string('mixin'), ['mgd-php@1.0']);
        $ext->builders['info'] = $info;
        $ext->loadInit($ctx);
        $ext->save($ctx, $output);
        return 0;
    }
    /**
     * Determine which template file correlates to the given controller
     *
     * @param string $srcClassName
     * @return string
     */
    protected static function findTpl($srcClassName)
    {
        $formValues = [];
        $search = new $srcClassName($formValues);
        return $search->templateFile();
    }
}
<?php

namespace CRM\CivixBundle\Command;

use CRM\CivixBundle\Builder\Mixins;
use CRM\CivixBundle\Services;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CRM\CivixBundle\Builder\Collection;
use CRM\CivixBundle\Builder\Dirs;
use CRM\CivixBundle\Builder\PhpData;
use CRM\CivixBundle\Builder\Template;
use CRM\CivixBundle\Utils\Path;
class AddAngularModuleCommand extends \CRM\CivixBundle\Command\AbstractCommand
{
    protected function configure()
    {
        parent::configure();
        $this->setName('generate:angular-module')->setDescription('Add a new Angular module (Civi v4.6+)')->addOption('am', NULL, InputOption::VALUE_REQUIRED, 'Name of the Angular module (default: match the Civi module name)');
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->assertCurrentFormat();
        //// Figure out template data ////
        $ctx = [];
        $ctx['type'] = 'module';
        $ctx['basedir'] = \CRM\CivixBundle\Application::findExtDir();
        $basedir = new Path($ctx['basedir']);
        $info = $this->getModuleInfo($ctx);
        $ctx['angularModuleName'] = $input->getOption('am') ? $input->getOption('am') : $ctx['angularModuleName'];
        $ctx['angularModulePhp'] = $basedir->string('ang', $ctx['angularModuleName'] . '.ang.php');
        $ctx['angularModuleJs'] = $basedir->string('ang', $ctx['angularModuleName'] . '.js');
        $ctx['angularModuleCss'] = $basedir->string('ang', $ctx['angularModuleName'] . '.css');
        //// Construct files ////
        $output->writeln("<info>Initialize Angular module</info> " . $ctx['angularModuleName']);
        $ext = new Collection();
        $ext->builders['dirs'] = new Dirs([\dirname($ctx['angularModulePhp']), \dirname($ctx['angularModuleJs'])]);
        if (!\file_exists($ctx['angularModulePhp'])) {
            $angModMeta = ['js' => ['ang/' . $ctx['angularModuleName'] . '.js', 'ang/' . $ctx['angularModuleName'] . '/*.js', 'ang/' . $ctx['angularModuleName'] . '/*/*.js'], 'css' => ['ang/' . $ctx['angularModuleName'] . '.css'], 'partials' => ['ang/' . $ctx['angularModuleName']], 'requires' => ['crmUi', 'crmUtil', 'ngRoute'], 'settings' => []];
            $header = "// This file declares an Angular module which can be autoloaded\n" . "// in CiviCRM. See also:\n" . "// \\https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_angularModules/n";
            $ext->builders['ang.php'] = new PhpData($ctx['angularModulePhp'], $header);
            $ext->builders['ang.php']->set($angModMeta);
        }
        $ext->builders['js'] = new Template('angular-module.js.php', $ctx['angularModuleJs'], \FALSE, Services::templating());
        $ext->builders['css'] = new Template('angular-module.css.php', $ctx['angularModuleCss'], \FALSE, Services::templating());
        $ext->builders['mixins'] = new Mixins($info, $basedir->string('mixin'), ['ang-php@1.0']);
        $ext->builders['info'] = $info;
        $ext->loadInit($ctx);
        $ext->save($ctx, $output);
        return 0;
    }
}
<?php

namespace CRM\CivixBundle\Command;

use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CivixPhar\Symfony\Component\Process\Process;
use CRM\CivixBundle\Builder\Info;
use CRM\CivixBundle\Utils\Path;
class BuildCommand extends \CRM\CivixBundle\Command\AbstractCommand
{
    protected function configure()
    {
        parent::configure();
        $this->setName('build:zip')->setDescription('Build a zip file for a CiviCRM Extension');
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->assertCurrentFormat();
        $ctx = [];
        $ctx['type'] = 'module';
        $ctx['basedir'] = \CRM\CivixBundle\Application::findExtDir();
        $basedir = new Path($ctx['basedir']);
        $info = new Info($basedir->string('info.xml'));
        $info->load($ctx);
        $attrs = $info->get()->attributes();
        if ($attrs['type'] != 'module') {
            $output->writeln('<error>Wrong extension type: ' . $attrs['type'] . '</error>');
            return 1;
        }
        $ctx['zipFile'] = $basedir->string('build', $ctx['fullName'] . '.zip');
        $cmdArgs = ['-r', $ctx['zipFile'], $ctx['fullName'], '--exclude', 'build/*', '*~', '*.bak', '*.git*'];
        $cmd = 'zip ' . \implode(' ', \array_map('escapeshellarg', $cmdArgs));
        \chdir($basedir->string('..'));
        $process = new Process($cmd);
        $process->run(function ($type, $buffer) use($output) {
            $output->writeln($buffer);
        });
        if (!$process->isSuccessful()) {
            throw new \RuntimeException('Failed to create zip');
        }
        print $process->getOutput();
        return 0;
    }
}
<?php

namespace CRM\CivixBundle\Command;

use CRM\CivixBundle\Services;
use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CRM\CivixBundle\Builder\Dirs;
use CRM\CivixBundle\Builder\Info;
use CRM\CivixBundle\Builder\CustomDataXML;
use CRM\CivixBundle\Utils\Path;
class AddCustomDataCommand extends \CRM\CivixBundle\Command\AbstractCommand
{
    protected function configure()
    {
        parent::configure();
        $this->setName('generate:custom-xml')->setDescription('Export custom data and profiles to an XML file')->addArgument('<CustomDataFile.xml>', InputArgument::OPTIONAL, 'The path to write custom data to (default: xml/auto_install.xml)')->addOption('data', NULL, InputOption::VALUE_REQUIRED, 'Comma-separated list of custom data group IDs (from linked dev site)')->addOption('uf', NULL, InputOption::VALUE_REQUIRED, 'Comma-separated list of profile group IDs (from linked dev site)')->addOption('force', 'f', InputOption::VALUE_NONE, 'Overwrite existing files');
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        // load Civi to get access to civicrm_api_get_function_name
        Services::boot(['output' => $output]);
        $civicrm_api3 = Services::api3();
        if (!$civicrm_api3 || !$civicrm_api3->local) {
            $output->writeln("<error>generate:custom-xml requires access to local CiviCRM instance. Configure civicrm_api3_conf_path.</error>");
            return;
        }
        $this->assertCurrentFormat();
        $ctx = [];
        $ctx['type'] = 'module';
        $ctx['basedir'] = \CRM\CivixBundle\Application::findExtDir();
        $basedir = new Path($ctx['basedir']);
        $info = new Info($basedir->string('info.xml'));
        $info->load($ctx);
        $attrs = $info->get()->attributes();
        if ($attrs['type'] != 'module') {
            $output->writeln('<error>Wrong extension type: ' . $attrs['type'] . '</error>');
            return 1;
        }
        $dirs = new Dirs([$basedir->string('xml')]);
        $dirs->save($ctx, $output);
        if ($input->getArgument('<CustomDataFile.xml>')) {
            $customDataXMLFile = $basedir->string($input->getArgument('<CustomDataFile.xml>'));
        } else {
            $customDataXMLFile = $basedir->string('xml', 'auto_install.xml');
        }
        if (!$input->getOption('data') && !$input->getOption('uf')) {
            $output->writeln("<error>generate:custom-xml requires --data and/or --uf</error>");
            return;
        }
        $customDataXML = new CustomDataXML($input->getOption('data') ? \explode(',', $input->getOption('data')) : [], $input->getOption('uf') ? \explode(',', $input->getOption('uf')) : [], $customDataXMLFile, $input->getOption('force'));
        $customDataXML->save($ctx, $output);
        if (\preg_match('/\\/xml\\/.*_install.xml$/', $customDataXMLFile)) {
            $output->writeln(" * NOTE: This filename ends with \"_install.xml\". If you would like to load it automatically on new sites, then make sure there is an install/upgrade class (i.e. run \"civix generate:upgrader\")");
        } else {
            $output->writeln(" * NOTE: By default, this file will not be loaded automatically -- you must define installation or upgrade logic to load the file.");
        }
        return 0;
    }
}
<?php

namespace CRM\CivixBundle\Command;

use CRM\CivixBundle\Builder\CopyFile;
use CRM\CivixBundle\Builder\Mixins;
use CRM\CivixBundle\Builder\Template;
use CRM\CivixBundle\Services;
use CRM\CivixBundle\Utils\Naming;
use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CRM\CivixBundle\Builder\Collection;
use CRM\CivixBundle\Builder\Dirs;
use CRM\CivixBundle\Builder\Info;
use CRM\CivixBundle\Builder\License;
use CRM\CivixBundle\Builder\Module;
use CRM\CivixBundle\Utils\Path;
class InitCommand extends \CRM\CivixBundle\Command\AbstractCommand
{
    protected $defaultMixins = ['setting-php@1', 'mgd-php@1', 'smarty-v2@1'];
    protected function configure()
    {
        Services::templating();
        $this->setName('generate:module')->setDescription('Create a new CiviCRM Module-Extension (Regenerate module.civix.php if \\"key\\" not specified)')->addArgument('key', InputArgument::OPTIONAL, "Extension identifier (Ex: \"foo_bar\" or \"org.example.foo-bar\")")->addOption('enable', NULL, InputOption::VALUE_REQUIRED, 'Whether to auto-enable the new module (yes/no/ask)', 'ask')->addOption('compatibility', NULL, InputOption::VALUE_REQUIRED, 'Version of CiviCRM that we target (eg "5.30" or "current")', 'current')->addOption('mixins', NULL, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Automatically enable the listed mixins')->addOption('license', NULL, InputOption::VALUE_OPTIONAL, 'License for the extension (' . \implode(', ', $this->getLicenses()) . ')', $this->getDefaultLicense())->addOption('author', NULL, InputOption::VALUE_REQUIRED, 'Name of the author', $this->getDefaultAuthor())->addOption('email', NULL, InputOption::VALUE_OPTIONAL, 'Email of the author', $this->getDefaultEmail())->setHelp("Create a new CiviCRM Module-Extension (Regenerate module.civix.php if \"key\" is not specified)\n" . "\n" . "<comment>Identification:</comment>\n" . "  Keys should be lowercase alphanumeric with underscores. Dots and dashes may be used with caveats.\n" . "\n" . "  CiviCRM extensions formally have two names, the \"key\" and the \"file\".\n" . "  Some APIs use the \"key\" name, and other APIs use the \"file\" name.\n" . "  The \"key\" allows a Java-style prefix (reverse domain name), but \"file\" does not.\n" . "\n" . "  If you use a Java-style prefix (dots and dashes), then the extension will have split names.\n" . "\n" . "  If you omit a Java-style prefix (dots and dashes), then the extension will have a single (matching) name.\n" . "\n" . "<comment>Examples:</comment>\n" . "  civix generate:module foo_bar\n" . "  civix generate:module foo_bar --license=AGPL-3.0 --author=\"Alice\" --email=\"alice@example.org\"\n" . "  civix generate:module org.example.foo-bar \n" . "\n");
        parent::configure();
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        Services::boot(['output' => $output]);
        $ctx = [];
        $ctx['type'] = 'module';
        if (!$input->getArgument('key')) {
            throw new \RuntimeException('To update an existing extension, please use "civix upgrade"');
        }
        $licenses = new \CivixPhar\LicenseData\Repository();
        $name = $input->getArgument('key');
        // Name should start with an alpha and only contain alphanumeric, - and .
        if (!Naming::isValidFullName($name)) {
            $output->writeln('<error>Malformed package name</error>');
            return 1;
        }
        $ctx['basedir'] = $name;
        $ctx['fullName'] = $name;
        $ctx['mainFile'] = Naming::createShortName($name);
        $ctx['namespace'] = 'CRM/' . Naming::createCamelName($name);
        $ctx['angularModuleName'] = 'crm' . Naming::createCamelName($name);
        if ($input->getOption('author') && $input->getOption('email')) {
            $ctx['author'] = $input->getOption('author');
            $ctx['email'] = $input->getOption('email');
        } else {
            $output->writeln("<error>Missing author name or email address</error>");
            $output->writeln("<error>Please pass --author and --email, or set defaults in ~/.gitconfig</error>");
            return 1;
        }
        $ctx['license'] = $input->getOption('license');
        if ($licenses->get($ctx['license'])) {
            $output->writeln(\sprintf('<comment>License set to %s (authored by %s \\<%s>)</comment>', $ctx['license'], $ctx['author'], $ctx['email']));
            $output->writeln('<comment>If this is in error, please correct info.xml and LICENSE.txt</comment>');
        } else {
            $output->writeln('<error>Unrecognized license (' . $ctx['license'] . ')</error>');
            return 1;
        }
        if ($input->getOption('compatibility') === 'current') {
            [$verMajor, $verMinor] = \explode('.', \CRM_Utils_System::version());
            $ctx['compatibilityVerMin'] = "{$verMajor}.{$verMinor}";
        } else {
            $ctx['compatibilityVerMin'] = $input->getOption('compatibility');
        }
        if ($ctx['fullName'] !== $ctx['mainFile']) {
            $output->writeln("");
            $output->writeln("<error>ALERT:</error> <comment>The requested command requires split-naming.</comment>");
            $output->writeln("");
            $output->writeln("CiviCRM extensions formally have two names, the \"key\" and the \"file\".");
            $output->writeln("Some APIs use the \"key\" name, and other APIs use the \"file\" name.");
            $output->writeln("");
            $output->writeln("   <comment>\"Key\":</comment> Appears in many strings+indices. Allows Java-style prefix.");
            $output->writeln("         <comment>Requested Value:</comment> {$ctx['fullName']}");
            $output->writeln("         <comment>Example Usage:</comment> addStyleFile('{$ctx['fullName']}', 'example.css')");
            $output->writeln("   <comment>\"File\"</comment>: Appears in PHP files+functions. No Java-style prefix.");
            $output->writeln("         <comment>Requested Value:</comment> {$ctx['mainFile']}");
            $output->writeln("         <comment>Example Usage:</comment> function {$ctx['mainFile']}_civicrm_config() {}");
            $output->writeln("");
            $output->writeln("Many developers find it easier to use matching names, but the");
            $output->writeln("requested command requires splitting the names. You may continue with");
            $output->writeln("split names, or you may cancel and try again with a simpler name.");
            $output->writeln("");
            if (!$this->confirm($input, $output, "Continue with current (split) name? [Y/n] ")) {
                return 1;
            }
        }
        $ext = new Collection();
        $output->writeln("<info>Initalize module</info> " . $ctx['fullName']);
        $basedir = new Path($ctx['basedir']);
        $info = new Info($basedir->string('info.xml'));
        $ext->builders['dirs'] = new Dirs([$basedir->string('build'), $basedir->string('templates'), $basedir->string('xml'), $basedir->string('images'), $basedir->string($ctx['namespace'])]);
        $ext->builders['mixins'] = new Mixins($info, $basedir->string('mixin'), $this->getMixins($input));
        $ext->builders['info'] = $info;
        $ext->builders['module'] = new Module(Services::templating());
        $ext->builders['license'] = new License($licenses->get($ctx['license']), $basedir->string('LICENSE.txt'), \FALSE);
        $ext->builders['readme'] = new Template('readme.md.php', $basedir->string('README.md'), \FALSE, Services::templating());
        $ext->builders['screenshot'] = new CopyFile(\dirname(\dirname(\dirname(\dirname(__DIR__)))) . '/images/placeholder.png', $basedir->string('images/screenshot.png'), \FALSE);
        $ext->loadInit($ctx);
        $ext->save($ctx, $output);
        $this->tryEnable($input, $output, $ctx['fullName']);
        return 0;
    }
    /**
     * Attempt to enable the extension on the linked CiviCRM site
     *
     * @return bool TRUE on success; FALSE if there's no site or if there's an error
     */
    protected function tryEnable(InputInterface $input, OutputInterface $output, $key)
    {
        Services::boot(['output' => $output]);
        $civicrm_api3 = Services::api3();
        if ($civicrm_api3 && $civicrm_api3->local) {
            $siteName = \CRM_Utils_System::baseURL();
            $output->writeln("<info>Refresh extension list for</info> {$siteName}");
            if (!$civicrm_api3->Extension->refresh(['local' => \TRUE, 'remote' => \FALSE])) {
                $output->writeln("<error>Refresh error: " . $civicrm_api3->errorMsg() . "</error>");
                return \FALSE;
            }
            if ($input->getOption('enable') === 'no') {
                return \FALSE;
            }
            if ($input->getOption('enable') === 'yes' || $this->confirm($input, $output, "Enable extension ({$key}) in \"{$siteName}\"? [Y/n] ")) {
                $output->writeln("<info>Enable extension ({$key}) in</info> {$siteName}");
                if (!$civicrm_api3->Extension->install(['key' => $key])) {
                    $output->writeln("<error>Install error: " . $civicrm_api3->errorMsg() . "</error>");
                }
            }
            return \TRUE;
        }
        // fallback
        $output->writeln("NOTE: This might be a good time to refresh the extension list and install \"{$key}\".");
        return \FALSE;
    }
    protected function getDefaultLicense()
    {
        $config = Services::config();
        $license = NULL;
        if (!empty($config['parameters']['license'])) {
            $license = $config['parameters']['license'];
        }
        return empty($license) ? 'AGPL-3.0' : $license;
    }
    protected function getDefaultEmail()
    {
        $config = Services::config();
        $value = NULL;
        if (!empty($config['parameters']['email'])) {
            $value = $config['parameters']['email'];
        }
        return empty($value) ? $this->getGitConfig('user.email', 'FIXME') : $value;
    }
    protected function getDefaultAuthor()
    {
        $config = Services::config();
        $value = NULL;
        if (!empty($config['parameters']['author'])) {
            $value = $config['parameters']['author'];
        }
        return empty($value) ? $this->getGitConfig('user.name', 'FIXME') : $value;
    }
    protected function getLicenses()
    {
        $licenses = new \CivixPhar\LicenseData\Repository();
        return \array_keys($licenses->getAll());
    }
    protected function getGitConfig($key, $default)
    {
        $result = NULL;
        if (\CRM\CivixBundle\Utils\Commands::findExecutable('git')) {
            $result = \trim(`git config --get {$key}`);
        }
        if (empty($result)) {
            $result = $default;
        }
        return $result;
    }
    protected function getMixins(InputInterface $input)
    {
        $requested = \explode(',', \implode(',', $input->getOption('mixins')));
        $merged = \array_unique(\array_merge($this->defaultMixins, $requested));
        return \array_filter($merged);
    }
}
<?php

namespace CRM\CivixBundle\Command;

use CRM\CivixBundle\Builder\Info;
use CRM\CivixBundle\Services;
use CRM\CivixBundle\Utils\Path;
use CivixPhar\Symfony\Component\Console\Command\Command;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CivixPhar\Symfony\Component\Console\Question\ConfirmationQuestion;
abstract class AbstractCommand extends Command
{
    protected function configure()
    {
        $this->addOption('yes', NULL, InputOption::VALUE_NONE, 'Answer yes to any questions');
    }
    protected function confirm(InputInterface $input, OutputInterface $output, $message, $default = \TRUE)
    {
        $message = '<info>' . $message . '</info>';
        /* FIXME Let caller stylize */
        if ($input->getOption('yes')) {
            $output->writeln($message . ($default ? 'Y' : 'N'));
            return $default;
        }
        /** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
        $helper = $this->getHelper('question');
        $question = new ConfirmationQuestion($message, $default);
        return (bool) $helper->ask($input, $output, $question);
    }
    protected function getModuleInfo(&$ctx) : Info
    {
        $basedir = new Path(\CRM\CivixBundle\Application::findExtDir());
        $info = new Info($basedir->string('info.xml'));
        $info->load($ctx);
        $attrs = $info->get()->attributes();
        if ($attrs['type'] != 'module') {
            throw new \RuntimeException('Wrong extension type: ' . $attrs['type']);
        }
        return $info;
    }
    protected function assertCurrentFormat()
    {
        $info = $this->getModuleInfo($ctx);
        $actualVersion = $info->detectFormat();
        $expectedVersion = Services::upgradeList()->getHeadVersion();
        if (\version_compare($actualVersion, $expectedVersion, '<')) {
            throw new \Exception("This extension requires an upgrade for the file-format (current={$actualVersion}; expected={$expectedVersion}). Please run 'civix upgrade' before generating code.");
        }
    }
}
<?php

namespace CRM\CivixBundle\Command;

use CRM\CivixBundle\Builder\Module;
use CRM\CivixBundle\Services;
use CRM\CivixBundle\Upgrader;
use CRM\CivixBundle\Utils\Naming;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CRM\CivixBundle\Utils\Path;
use CivixPhar\Symfony\Component\Console\Style\SymfonyStyle;
class UpgradeCommand extends \CRM\CivixBundle\Command\AbstractCommand
{
    protected function configure()
    {
        Services::templating();
        $this->setName('upgrade')->setDescription('Apply upgrades to the layout of the codebase')->addOption('start', NULL, InputOption::VALUE_REQUIRED, 'Replay the upgrade steps, starting from an older version', 'current')->setHelp('
This command applies incremental upgrade steps, starting from the declared version
(info.xml\'s <civix><format>...</format></civix>) and proceeding to the current.

In some edge-cases (eg merging code-branches from different versions), you may find
it useful to replay upgrade steps. For example:

  civix upgrade --start=0
  civix upgrade --start=13.10.0
  civix upgrade --start=22.05.0

Most upgrade steps should be safe to re-run repeatedly, but this is not guaranteed.
');
        parent::configure();
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $startVer = $input->getOption('start');
        if ($startVer !== 'current') {
            $verAliases = ['0' => '13.10.0'];
            $upgrader = new Upgrader($input, $output, new Path(\CRM\CivixBundle\Application::findExtDir()));
            $upgrader->updateFormatVersion($verAliases[$startVer] ?? $startVer);
        }
        $this->executeIncrementalUpgrades($input, $output);
        $this->executeGenericUpgrade($input, $output);
        return 0;
    }
    protected function executeIncrementalUpgrades(InputInterface $input, OutputInterface $output)
    {
        $io = new SymfonyStyle($input, $output);
        $io->title('Incremental upgrades');
        [$ctx, $info] = $this->loadCtxInfo();
        $startVersion = $ctx['civixFormat'] ?? NULL;
        if (!$startVersion) {
            $startVersion = $info->detectFormat();
            $io->writeln("info.xml does not declare the civix format. Inferred <info>v{$startVersion}</info>.");
        } else {
            $io->writeln("Current civix format is <info>v{$startVersion}</info>.");
        }
        $upgrades = Services::upgradeList()->findUpgrades($startVersion);
        if (empty($upgrades)) {
            $io->writeln("No incremental upgrades required.");
            return 0;
        }
        $lastVersion = $startVersion;
        foreach ($upgrades as $upgradeVersion => $upgradeFile) {
            $io->section("Upgrade <info>v{$lastVersion}</info> => <info>v{$upgradeVersion}</info>");
            $io->writeln("<info>Executing upgrade script</info> {$upgradeFile}");
            $upgrader = new Upgrader($input, $output, new Path(\CRM\CivixBundle\Application::findExtDir()));
            $func = (require $upgradeFile);
            $func($upgrader);
            $upgrader->updateFormatVersion($upgradeVersion);
            $lastVersion = $upgradeVersion;
        }
    }
    protected function executeGenericUpgrade(InputInterface $input, OutputInterface $output) : void
    {
        $io = new SymfonyStyle($input, $output);
        $io->title('General upgrade');
        $upgrader = new Upgrader($input, $output, new Path(\CRM\CivixBundle\Application::findExtDir()));
        $upgrader->cleanEmptyHooks();
        $upgrader->cleanEmptyLines();
        $upgrader->reconcileMixins();
        /**
         * @var \CRM\CivixBundle\Builder\Info $info
         */
        [$ctx, $info] = $this->loadCtxInfo();
        $basedir = new Path(\CRM\CivixBundle\Application::findExtDir());
        $module = new Module(Services::templating());
        $module->loadInit($ctx);
        $module->save($ctx, $output);
        if ($ctx['namespace']) {
            $phpFile = $basedir->string(Naming::createClassFile($ctx['namespace'], 'Upgrader', 'Base.php'));
            if (\file_exists($phpFile)) {
                $output->writeln(\sprintf('<info>Write</info> %s', $phpFile));
                \file_put_contents($phpFile, Services::templating()->render('upgrader-base.php.php', $ctx));
            }
        }
    }
    protected function loadCtxInfo() : array
    {
        $ctx = [];
        $ctx['basedir'] = \CRM\CivixBundle\Application::findExtDir();
        $ctx['type'] = 'module';
        $info = $this->getModuleInfo($ctx);
        return [$ctx, $info];
    }
}
<?php

namespace CRM\CivixBundle\Command;

use CRM\CivixBundle\Builder\Mixins;
use CRM\CivixBundle\Services;
use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CRM\CivixBundle\Builder\Dirs;
use CRM\CivixBundle\Builder\PHPUnitGenerateInitFiles;
use CRM\CivixBundle\Builder\PhpData;
use CRM\CivixBundle\Utils\Path;
use Exception;
use CivixPhar\Symfony\Component\Console\Style\SymfonyStyle;
class AddApiCommand extends \CRM\CivixBundle\Command\AbstractCommand
{
    const API_VERSION = 3;
    public static function getSchedules()
    {
        return ['Daily', 'Hourly', 'Always'];
    }
    protected function configure()
    {
        $this->setName('generate:api')->setDescription('Add a new API function to a CiviCRM Module-Extension')->addArgument('<EntityName>', InputArgument::REQUIRED, 'The entity against which the action runs (eg "Contact", "MyEntity")')->addArgument('<actionname>', InputArgument::REQUIRED, 'The action which will be created (eg "create", "myaction")')->addOption('schedule', NULL, InputOption::VALUE_OPTIONAL, 'Schedule this action as a recurring cron job (' . \implode(', ', self::getSchedules()) . ') [For CiviCRM 4.3+]')->setHelp('Add a new API function to a CiviCRM Module-Extension

This will generate an API entity/action with a standalone PHP file and test-class.

Note: APIv3 naming conventions are somewhat conflicted. In theory, callers may use
entity-names and action-names expressed interchangably as CamelCase or under_score_case.
In practice:

- Entity names are interchangeable, though we typically regard CamelCase as canonical.
- Action names are tempermental -- working+non-working combinations depend on multiple
  variables. The simplest approach believed to work consistently is to use one-word
  actions (e.g. "Getcount"/"getcount" instead of "GetCount"/"getCount"/"get_count").

In keeping, "civix generate:api" expects CamelCase entity names and singleword
action names.
');
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $io = new SymfonyStyle($input, $output);
        // load Civi to get access to civicrm_api_get_function_name
        Services::boot(['output' => $output]);
        $civicrm_api3 = Services::api3();
        if (!$civicrm_api3 || !$civicrm_api3->local) {
            $output->writeln("<error>--copy requires access to local CiviCRM source tree. Configure civicrm_api3_conf_path.</error>");
            return;
        }
        $this->assertCurrentFormat();
        $ctx = [];
        $ctx['type'] = 'module';
        $ctx['basedir'] = \CRM\CivixBundle\Application::findExtDir();
        $basedir = new Path($ctx['basedir']);
        $info = $this->getModuleInfo($ctx);
        if (!\preg_match('/^[A-Za-z0-9]+$/', $input->getArgument('<EntityName>'))) {
            throw new Exception("Entity name must be alphanumeric camel-case");
        }
        if (!\preg_match('/^[A-Za-z][a-z0-9]*$/', $input->getArgument('<actionname>'))) {
            throw new Exception("Action name must be alphanumeric singleword");
        }
        if ($input->getOption('schedule') && !\in_array($input->getOption('schedule'), self::getSchedules())) {
            throw new Exception("Schedule must be one of: " . \implode(', ', self::getSchedules()));
        }
        $ctx['entityNameCamel'] = \ucfirst($input->getArgument('<EntityName>'));
        $ctx['actionNameCamel'] = \ucfirst($input->getArgument('<actionname>'));
        $ctx['actionNameLower'] = \strtolower($input->getArgument('<actionname>'));
        // $ctx['actionNameUnderscore'] = strtolower(implode('_', array_filter(preg_split('/(?=[A-Z])/', $input->getArgument('<actionname>')))));
        if (\function_exists('civicrm_api_get_function_name')) {
            $ctx['apiFunction'] = \strtolower(\civicrm_api_get_function_name($ctx['entityNameCamel'], $ctx['actionNameCamel'], self::API_VERSION));
        } elseif (\function_exists('_civicrm_api_get_entity_name_from_camel')) {
            $ctx['apiFunction'] = 'civicrm_api' . self::API_VERSION . '_' . \_civicrm_api_get_entity_name_from_camel($ctx['entityNameCamel']) . '_' . $ctx['actionNameCamel'];
        } else {
            throw new Exception("Failed to determine proper API function name. Perhaps the API internals have changed?");
        }
        $ctx['apiFile'] = $basedir->string('api', 'v3', $ctx['entityNameCamel'], $ctx['actionNameCamel'] . '.php');
        $ctx['apiCronFile'] = $basedir->string('api', 'v3', $ctx['entityNameCamel'], $ctx['actionNameCamel'] . '.mgd.php');
        $ctx['apiTestFile'] = $basedir->string('tests', 'phpunit', 'api', 'v3', $ctx['entityNameCamel'], $ctx['actionNameCamel'] . 'Test.php');
        $ctx['testClassName'] = "api_v3_{$ctx['entityNameCamel']}_{$ctx['actionNameCamel']}Test";
        $dirs = new Dirs([\dirname($ctx['apiFile'])]);
        $dirs->save($ctx, $output);
        if (!\file_exists($ctx['apiFile'])) {
            $output->writeln(\sprintf('<info>Write</info> %s', $ctx['apiFile']));
            \file_put_contents($ctx['apiFile'], Services::templating()->render('api.php.php', $ctx));
        } else {
            $output->writeln(\sprintf('<error>Skip %s: file already exists</error>', $ctx['apiFile']));
        }
        if ($input->getOption('schedule')) {
            $mixins = new Mixins($info, $basedir->string('mixin'), 'mgd-php@1.0');
            $mixins->save($ctx, $output);
            if (!\file_exists($ctx['apiCronFile'])) {
                $mgdEntities = [['name' => 'Cron:' . $ctx['entityNameCamel'] . '.' . $ctx['actionNameCamel'], 'entity' => 'Job', 'params' => ['version' => 3, 'name' => \sprintf('Call %s.%s API', $ctx['entityNameCamel'], $ctx['actionNameCamel']), 'description' => \sprintf('Call %s.%s API', $ctx['entityNameCamel'], $ctx['actionNameCamel']), 'run_frequency' => $input->getOption('schedule'), 'api_entity' => $ctx['entityNameCamel'], 'api_action' => $ctx['actionNameCamel'], 'parameters' => '']]];
                $header = "// This file declares a managed database record of type \"Job\".\n" . "// The record will be automatically inserted, updated, or deleted from the\n" . "// database as appropriate. For more details, see \"hook_civicrm_managed\" at:\n" . "// https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_managed";
                $mgdBuilder = new PhpData($ctx['apiCronFile'], $header);
                $mgdBuilder->set($mgdEntities);
                $mgdBuilder->save($ctx, $output);
            } else {
                $output->writeln(\sprintf('<error>Skip %s: file already exists</error>', $ctx['apiCronFile']));
            }
        }
        $test_dirs = new Dirs([\dirname($ctx['apiTestFile'])]);
        $test_dirs->save($ctx, $output);
        if (!\file_exists($ctx['apiTestFile'])) {
            $output->writeln(\sprintf('<info>Write</info> %s', $ctx['apiTestFile']));
            \file_put_contents($ctx['apiTestFile'], Services::templating()->render('test-api.php.php', $ctx));
        } else {
            $output->writeln(\sprintf('<error>Skip %s: file already exists</error>', $ctx['apiTestFile']));
        }
        $phpUnitInitFiles = new PHPUnitGenerateInitFiles();
        $phpUnitInitFiles->initPhpunitXml($basedir->string('phpunit.xml.dist'), $ctx, $output);
        $phpUnitInitFiles->initPhpunitBootstrap($basedir->string('tests', 'phpunit', 'bootstrap.php'), $ctx, $output);
        $info->save($ctx, $output);
        return 0;
    }
}
<?php

namespace CRM\CivixBundle\Command;

use CivixPhar\Symfony\Component\Console\Command\Command;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CRM\CivixBundle\Builder\Info;
use CRM\CivixBundle\Utils\Path;
class InfoGetCommand extends Command
{
    protected function configure()
    {
        $fields = ['file', 'name', 'description', 'license', 'releaseDate', 'version', 'develStage', 'comments', 'maintainer/author', 'maintainer/email', 'civix/namespace', 'urls/url[@desc="Documentation"]', 'urls/url[@desc="Support"]'];
        $this->setName('info:get')->setDescription('Read a field from the info.xml file')->addOption('xpath', 'x', InputOption::VALUE_REQUIRED, '(REQUIRED) The XPath expression of the field')->setHelp("Read a single field from the info.xml file.\n\nExamples:\n  civix info:get -x version\n  civix info:get -x maintainer/author\n  civix info:get -x maintainer/email\n\nCommon fields:\n * " . \implode("\n * ", $fields) . "\n");
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $basedir = new Path(\CRM\CivixBundle\Application::findExtDir());
        $info = new Info($basedir->string('info.xml'));
        $ctx = [];
        $info->load($ctx);
        $info->get();
        $xpath = $input->getOption('xpath');
        if (\is_null($xpath)) {
            // missing xpath value so provide help
            $help = $this->getApplication()->get('help');
            // tell help to provide specific help for this function
            $help->setCommand($this);
            return $help->run($input, $output);
        }
        foreach ($info->get()->xpath($xpath) as $node) {
            $output->writeln((string) $node, OutputInterface::OUTPUT_RAW);
        }
        return 0;
    }
}
<?php

namespace CRM\CivixBundle\Command;

use CRM\CivixBundle\Builder\Info;
use CRM\CivixBundle\Services;
use CRM\CivixBundle\Utils\Path;
use CivixPhar\Symfony\Component\Console\Command\Command;
use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CivixPhar\Symfony\Component\Process\PhpExecutableFinder;
use CivixPhar\Symfony\Component\Process\Process;
/**
 * Run unit tests using CiviCRM's copy of PHPUnit
 *
 * This basically involves a couple things:
 *  - Locate CiviCRM's copy of PHPUnit
 *  - Locate the extensions test directory
 *  - Call CiviCRM's copy of PHPUnit while adding the test directory to the include path
 */
class TestRunCommand extends Command
{
    const TIMEOUT = 1000;
    /**
     * The maximum number of seconds to allow the PHPUnit bootstrap file to persist
     */
    const BOOTSTRAP_TTL = 600;
    protected function configure()
    {
        $this->setName('test')->setDescription('Run a unit test (DEPRECATED)')->addArgument('<TestClass>', InputArgument::OPTIONAL, 'Test class name (eg "CRM_Myextension_MyTest")')->addOption('clear', NULL, InputOption::VALUE_NONE, 'Clear the cached PHPUnit bootstrap data')->addOption('filter', NULL, InputOption::VALUE_REQUIRED, 'Restrict tests by name (regex)')->addOption('configuration', 'c', InputOption::VALUE_NONE, 'Run all the tests as configured in the phpunit.xml in the root directory of your extension.')->addOption('debug', NULL, InputOption::VALUE_NONE, 'Run PHPUnit in debug mode.');
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        Services::boot(['output' => $output]);
        $basedir = new Path(\getcwd());
        $output->writeln("<comment>Warning: 'civix test' deprecated.  Run phpunit4 directly from the extension directory instead.</comment>");
        // Find extension metadata
        $info = new Info($basedir->string('info.xml'));
        $info->load($ctx);
        if ($info->getType() != 'module') {
            $output->writeln('<error>Wrong extension type: ' . $attrs['type'] . '</error>');
            return 1;
        }
        // Find the main phpunit
        $civicrm_api3 = Services::api3();
        if (!$civicrm_api3 || !$civicrm_api3->local) {
            $output->writeln("<error>'test' requires access to local CiviCRM source tree. Configure civicrm_api3_conf_path.</error>");
            return 1;
        }
        global $civicrm_root;
        if (empty($civicrm_root) || !\is_dir($civicrm_root)) {
            $output->writeln("<error>Failed to locate CiviCRM root path: {$civicrm_root}</error>");
            return 1;
        }
        $phpunit_bin = "{$civicrm_root}/tools/scripts/phpunit";
        if (!\file_exists($phpunit_bin)) {
            $output->writeln("<error>Failed to locate PHPUnit:\n  {$phpunit_bin}</error>");
            $output->writeln("<error>Have you configured CiviCRM for testing? See also:\n  https://docs.civicrm.org/dev/en/latest/testing/#setup</error>");
            return 1;
        }
        $test_settings_path = "{$civicrm_root}/tests/phpunit/CiviTest/civicrm.settings.php";
        $test_settings_dist_path = "{$civicrm_root}/tests/phpunit/CiviTest/civicrm.settings.dist.php";
        if (!\file_exists($test_settings_path) && !\file_exists($test_settings_dist_path)) {
            $output->writeln("<error>Failed to locate test settings:\n  {$test_settings_path}</error>");
            $output->writeln("<error>Have you configured CiviCRM for testing? See also:\n  https://docs.civicrm.org/dev/en/latest/testing/#setup</error>");
            return 1;
        }
        if (\file_exists($test_settings_path) && self::checkLegacyExtensionSettings($test_settings_path)) {
            $output->writeln("<comment>Warning: Possible conflicts in {$test_settings_path}</comment>");
            $output->writeln("<comment>The following options may conflict with civix-based testing: 'ext_repo_url', 'extensionsDir', and/or 'extensionsURL'.</comment>");
        }
        $phpunit_boot = $this->getBootstrapFile($info->getKey(), $input->getOption('clear'));
        if (empty($phpunit_boot) || !\file_exists($phpunit_boot)) {
            $output->writeln("<error>Failed to create PHPUnit bootstrap file</error>");
            return 1;
        }
        $tests_dir = \implode(\DIRECTORY_SEPARATOR, [\getcwd(), 'tests', 'phpunit']);
        // Prepare the command
        $command = [];
        $command[] = $phpunit_bin;
        $command[] = '--include-path';
        $command[] = $tests_dir;
        $command[] = '--bootstrap';
        $command[] = $phpunit_boot;
        $command[] = '--colors';
        if ($input->getOption('filter')) {
            $command[] = '--filter';
            $command[] = $input->getOption('filter');
        }
        if ($input->getOption('configuration')) {
            $command[] = '--configuration';
            $command[] = $basedir->string('phpunit.xml');
        }
        if ($input->getOption('debug')) {
            $command[] = '--debug';
        }
        $command[] = $input->getArgument('<TestClass>');
        // Run phpunit with our "tests" directory
        \chdir("{$civicrm_root}/tools");
        $process = new Process(\call_user_func_array(['\\CRM\\CivixBundle\\Command\\TestRunCommand', 'createPhpShellCommand'], $command), NULL, NULL, NULL, self::TIMEOUT);
        $process->run(function ($type, $buffer) use($output) {
            $output->write($buffer);
        });
        $output->write("\n");
        return 0;
    }
    /**
     * Generate the shell statement for invoking a PHP script
     *
     * @code
     * $shellCommand = createPhpShellCommand('/path/to/my-script.php', 'argument 1', 'argument 2', ...);
     * @endCode
     *
     * @param string $script
     * @return string a valid shell command
     */
    protected static function createPhpShellCommand($script)
    {
        $php = \escapeshellcmd(self::getPhp());
        // get $script and any others
        $args = \func_get_args();
        $escArgs = \array_map('escapeshellarg', $args);
        $cmd = $php . ' ' . \implode(' ', $escArgs);
        return $cmd;
    }
    protected static function getPhp()
    {
        $phpFinder = new PhpExecutableFinder();
        if (!($phpPath = $phpFinder->find())) {
            throw new \RuntimeException('The php executable could not be found, add it to your PATH environment variable and try again');
        }
        return $phpPath;
    }
    /**
     * Determine whether $file contains any unnecessary extension settings
     *
     * @param string $file readable file path
     * @return bool TRUE if the file contains potentially conflicting settings
     */
    protected static function checkLegacyExtensionSettings($file)
    {
        $content = \file_get_contents($file);
        if (\preg_match('/civicrm_setting..Extension Preferences....ext_repo_url../', $content)) {
            return \TRUE;
        }
        if (\preg_match('/civicrm_setting..Directory Preferences....extensionsDir../', $content)) {
            return \TRUE;
        }
        if (\preg_match('/civicrm_setting..URL Preferences....extensionsURL../', $content)) {
            return \TRUE;
        }
        return \FALSE;
    }
    /**
     * Find (or auto-create) a PHP file with information for bootstrapping the test environment
     *
     * @param string $key the extension for which tests will be run
     * @param bool $clear
     * @return string temp file path
     */
    protected function getBootstrapFile($key, $clear = \FALSE)
    {
        $cacheDir = Services::cacheDir();
        $file = $cacheDir->string("civix-phpunit.{$key}.php");
        if ($clear || !\file_exists($file) || \filemtime($file) < \time() - self::BOOTSTRAP_TTL) {
            $template_vars = [];
            $template_vars['civicrm_setting'] = [];
            // disable extension searching
            $template_vars['civicrm_setting']['Extension Preferences']['ext_repo_url'] = \FALSE;
            // use the same source tree for linked Civi runtime and test Civi runtime
            $template_vars['civicrm_setting']['Directory Preferences']['extensionsDir'] = \CRM_Core_BAO_Setting::getItem('Directory Preferences', 'extensionsDir');
            // extensionsURL of linked Civi runtime may differ from ideal value for test Civi runtime, but that's OK because extensionsURL defines *static* resources
            $template_vars['civicrm_setting']['URL Preferences']['extensionsURL'] = \CRM_Core_BAO_Setting::getItem('URL Preferences', 'extensionsURL');
            $template_vars['civicrm_setting']['Test']['test_extensions'] = \array_keys(\CRM_Core_PseudoConstant::getExtensions());
            \file_put_contents($file, Services::templating()->render('phpunit-boot.php.php', $template_vars));
        }
        return $file;
    }
}
<?php

namespace CRM\CivixBundle\Command;

use CivixPhar\Symfony\Component\Console\Command\Command;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CRM\CivixBundle\Builder\Info;
use CRM\CivixBundle\Utils\Path;
class InfoSetCommand extends Command
{
    protected function configure()
    {
        $fields = ['file', 'name', 'description', 'license', 'releaseDate', 'version', 'develStage', 'comments', 'maintainer/author', 'maintainer/email', 'civix/namespace', 'urls/url[@desc="Documentation"]', 'urls/url[@desc="Support"]'];
        $this->setName('info:set')->setDescription('Set a field in the info.xml file')->addOption('xpath', 'x', InputOption::VALUE_REQUIRED, 'The XPath expression to search on')->addOption('to', 't', InputOption::VALUE_REQUIRED, 'The value of the field')->setHelp("Set a single field in the info.xml file.\n\nExamples:\n  civix info:set -x version --to 2.0.0\n  civix info:set -x maintainer/author --to 'Frank Lloyd Wright'\n  civix info:set -x maintainer/email --to 'flloyd@example.com'\n\nCommon fields:\n  * " . \implode("\n  * ", $fields) . "\n");
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $basedir = new Path(\CRM\CivixBundle\Application::findExtDir());
        $info = new Info($basedir->string('info.xml'));
        $ctx = [];
        $info->load($ctx);
        $info->get();
        $elements = $info->get()->xpath($input->getOption('xpath'));
        if (empty($elements)) {
            $output->writeln("Error: Path (" . $input->getOption('xpath') . ") did not match any elements.");
            return 1;
        }
        foreach ($elements as $element) {
            $element[0] = $input->getOption('to');
        }
        $info->save($ctx, $output);
        return 0;
    }
}
<?php

namespace CRM\CivixBundle\Command;

use CRM\CivixBundle\Services;
use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CRM\CivixBundle\Builder\Collection;
use CRM\CivixBundle\Builder\Dirs;
use CRM\CivixBundle\Builder\Info;
use CRM\CivixBundle\Builder\Template;
use CRM\CivixBundle\Utils\Path;
class AddAngularPageCommand extends \CRM\CivixBundle\Command\AbstractCommand
{
    protected function configure()
    {
        parent::configure();
        $this->setName('generate:angular-page')->setDescription('Add a new Angular page (Civi v4.6+)')->addOption('am', NULL, InputOption::VALUE_REQUIRED, 'Name of the Angular module (default: match the Civi module name)')->addArgument('<Ctrl>', InputArgument::REQUIRED, 'Controller name (Ex: "EditCtrl")')->addArgument('<RelPath>', InputArgument::REQUIRED, 'Web path (Ex: "about/me")')->setHelp('CiviCRM defines a base-page, "civicrm/a", and all Angular pages
are loaded underneath it. For example, if a page the path
"about/me", then the URL would be "civicrm/a/#/about/me".

Before generating an angular page, you\'ll need to generate a module using:
  civix generate:angular-module

To add a new Angular-absed page, this command autogenerates three things:
 * A route (JS)
 * A controller (JS)
 * A view (HTML)

For more, see https://docs.angularjs.org/guide');
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->assertCurrentFormat();
        //// Figure out template data ////
        $ctx = [];
        $ctx['type'] = 'module';
        $ctx['basedir'] = \CRM\CivixBundle\Application::findExtDir();
        $basedir = new Path($ctx['basedir']);
        $info = new Info($basedir->string('info.xml'));
        $info->load($ctx);
        $attrs = $info->get()->attributes();
        if ($attrs['type'] != 'module') {
            $output->writeln('<error>Wrong extension type: ' . $attrs['type'] . '</error>');
            return 1;
        }
        $ctx['tsDomain'] = (string) $attrs['key'];
        $ctx['angularModuleName'] = $input->getOption('am') ? $input->getOption('am') : $ctx['angularModuleName'];
        $ctx['ctrlSuffix'] = $input->getArgument('<Ctrl>');
        $ctx['ctrlRelPath'] = $input->getArgument('<RelPath>');
        $ctx['ctrlName'] = \ucwords($ctx['angularModuleName']) . $ctx['ctrlSuffix'];
        $ctx['jsPath'] = $basedir->string('ang', $ctx['angularModuleName'], $ctx['ctrlSuffix'] . '.js');
        $ctx['htmlName'] = \implode('/', ['~', $ctx['angularModuleName'], $ctx['ctrlSuffix'] . '.html']);
        $ctx['htmlPath'] = $basedir->string('ang', $ctx['angularModuleName'], $ctx['ctrlSuffix'] . '.html');
        $ctx['hlpName'] = 'CRM' . '/' . $ctx['angularModuleName'] . '/' . $ctx['ctrlSuffix'];
        $ctx['hlpPath'] = $basedir->string('templates', $ctx['hlpName'] . '.hlp');
        //// Construct files ////
        $output->writeln("<info>Initialize Angular page</info> " . $ctx['ctrlName'] . " <info>(</info>civicrm/a/#/" . $ctx['ctrlRelPath'] . "<info>)</info>");
        $ext = new Collection();
        $ext->builders['dirs'] = new Dirs([\dirname($ctx['jsPath']), \dirname($ctx['htmlPath']), \dirname($ctx['hlpPath'])]);
        $ext->builders['ctrl.js'] = new Template('angular-page.js.php', $ctx['jsPath'], \FALSE, Services::templating());
        $ext->builders['html'] = new Template('angular-page.html.php', $ctx['htmlPath'], \FALSE, Services::templating());
        $ext->builders['hlp'] = new Template('angular-page.hlp.php', $ctx['hlpPath'], \FALSE, Services::templating());
        $ext->init($ctx);
        $ext->save($ctx, $output);
        return 0;
    }
}
<?php

namespace CRM\CivixBundle\Command;

use CRM\CivixBundle\Services;
use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CRM\CivixBundle\Builder\Collection;
use CRM\CivixBundle\Builder\Ini;
class ConfigSetCommand extends \CRM\CivixBundle\Command\AbstractCommand
{
    protected function configure()
    {
        parent::configure();
        $this->setName('config:set')->setDescription('Set configuration value')->addArgument('key', InputArgument::REQUIRED, 'Parameter name')->addArgument('value', InputArgument::REQUIRED, 'Parameter value');
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $ctx = [];
        $ext = new Collection();
        $output->writeln("<info></info>");
        $configDir = Services::configDir();
        $configDir->mkdir();
        $ext->builders['ini'] = new Ini($configDir->string('civix.ini'));
        $ext->loadInit($ctx);
        $data = $ext->builders['ini']->get();
        if (!\is_array($data)) {
            $data = ['parameters' => []];
        }
        $data['parameters'][$input->getArgument('key')] = $input->getArgument('value');
        $ext->builders['ini']->set($data);
        $ext->save($ctx, $output);
        return 0;
    }
}
<?php
namespace CRM\CivixBundle\Command;

use CRM\CivixBundle\Services;
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 CRM\CivixBundle\Builder\Collection;
use CRM\CivixBundle\Builder\Dirs;
use CRM\CivixBundle\Builder\Info;
use CRM\CivixBundle\Builder\Template;
use CRM\CivixBundle\Utils\Path;

class AddAngularPageCommand extends \Symfony\Component\Console\Command\Command {

  protected function configure() {
    $this
      ->setName('generate:angular-page')
      ->setDescription('Add a new Angular page (Civi v4.6+)')
      ->addOption('am', NULL, InputOption::VALUE_REQUIRED, 'Name of the Angular module (default: match the Civi module name)')
      ->addArgument('<Ctrl>', InputArgument::REQUIRED, 'Controller name (Ex: "EditCtrl")')
      ->addArgument('<RelPath>', InputArgument::REQUIRED, 'Web path (Ex: "about/me")')
      ->setHelp('CiviCRM defines a base-page, "civicrm/a", and all Angular pages
are loaded underneath it. For example, if a page the path
"about/me", then the URL would be "civicrm/a/#/about/me".

Before generating an angular page, you\'ll need to generate a module using:
  civix generate:angular-module

To add a new Angular-absed page, this command autogenerates three things:
 * A route (JS)
 * A controller (JS)
 * A view (HTML)

For more, see https://docs.angularjs.org/guide');
  }

  protected function execute(InputInterface $input, OutputInterface $output) {
    //// Figure out template data ////
    $ctx = [];
    $ctx['type'] = 'module';
    $ctx['basedir'] = \CRM\CivixBundle\Application::findExtDir();
    $basedir = new Path($ctx['basedir']);

    $info = new Info($basedir->string('info.xml'));
    $info->load($ctx);
    $attrs = $info->get()->attributes();
    if ($attrs['type'] != 'module') {
      $output->writeln('<error>Wrong extension type: ' . $attrs['type'] . '</error>');
      return;
    }

    $ctx['tsDomain'] = (string) $attrs['key'];
    $ctx['angularModuleName'] = $input->getOption('am') ? $input->getOption('am') : $ctx['mainFile'];
    $ctx['ctrlSuffix'] = $input->getArgument('<Ctrl>');
    $ctx['ctrlRelPath'] = $input->getArgument('<RelPath>');
    $ctx['ctrlName'] = ucwords($ctx['angularModuleName']) . $ctx['ctrlSuffix'];
    $ctx['jsPath'] = $basedir->string('ang', $ctx['angularModuleName'], $ctx['ctrlSuffix'] . '.js');
    $ctx['htmlName'] = implode('/', ['~', $ctx['angularModuleName'], $ctx['ctrlSuffix'] . '.html']);
    $ctx['htmlPath'] = $basedir->string('ang', $ctx['angularModuleName'], $ctx['ctrlSuffix'] . '.html');
    $ctx['hlpName'] = 'CRM' . '/' . $ctx['angularModuleName'] . '/' . $ctx['ctrlSuffix'];
    $ctx['hlpPath'] = $basedir->string('templates', $ctx['hlpName'] . '.hlp');

    //// Construct files ////
    $output->writeln("<info>Initialize Angular page \"" . $ctx['ctrlName'] . "\" (civicrm/a/#/" . $ctx['ctrlRelPath'] . ")</info>");

    $ext = new Collection();
    $ext->builders['dirs'] = new Dirs([
      dirname($ctx['jsPath']),
      dirname($ctx['htmlPath']),
      dirname($ctx['hlpPath']),
    ]);;

    $ext->builders['ctrl.js'] = new Template('angular-page.js.php', $ctx['jsPath'], FALSE, Services::templating());
    $ext->builders['html'] = new Template('angular-page.html.php', $ctx['htmlPath'], FALSE, Services::templating());
    $ext->builders['hlp'] = new Template('angular-page.hlp.php', $ctx['hlpPath'], FALSE, Services::templating());

    $ext->init($ctx);
    $ext->save($ctx, $output);
  }

}
<?php

namespace CRM\CivixBundle\Command;

use CRM\CivixBundle\Builder\Mixins;
use CRM\CivixBundle\Builder\PHPUnitGenerateInitFiles;
use CRM\CivixBundle\Services;
use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CRM\CivixBundle\Builder\Collection;
use CRM\CivixBundle\Builder\Dirs;
use CRM\CivixBundle\Builder\Info;
use CRM\CivixBundle\Builder\PhpData;
use CRM\CivixBundle\Builder\Template;
use CRM\CivixBundle\Utils\Path;
use CRM\CivixBundle\Utils\Naming;
use Exception;
class AddEntityCommand extends \CRM\CivixBundle\Command\AbstractCommand
{
    const API_VERSION = 3;
    protected function configure()
    {
        parent::configure();
        $this->setName('generate:entity')->setDescription('Add a new API/BAO/GenCode entity to a CiviCRM Module-Extension (*EXPERIMENTAL*)')->addArgument('<EntityName>', InputArgument::REQUIRED, 'The brief, unique name of the entity")')->addOption('table-name', NULL, InputOption::VALUE_OPTIONAL, 'The SQL table name. (see usage)')->addOption('api-version', 'A', InputOption::VALUE_REQUIRED, 'Comma-separated list of versions (3,4)', '4')->setHelp('Add a new API/BAO/GenCode entity to a CiviCRM Module-Extension.
This command is experimental. Developer discretion is advised.

In most cases generate:entity is able to derive a suitable snake_case table name
from The CamelCase <EntityName>. However, in some instances (notably when the
entity contains a number or a capitalised acronym) the table name may differ
from your expectations. In these cases, you may wish to set the table name
explicity.');
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        // load Civi to get access to civicrm_api_get_function_name
        Services::boot(['output' => $output]);
        $civicrm_api3 = Services::api3();
        if (!$civicrm_api3 || !$civicrm_api3->local) {
            $output->writeln("<error>Require access to local CiviCRM source tree. Configure civicrm_api3_conf_path.</error>");
            return 1;
        }
        $this->assertCurrentFormat();
        $apiVersions = \explode(',', $input->getOption('api-version'));
        if (!empty(\array_diff($apiVersions, ['3', '4']))) {
            throw new Exception("In --api-versions, found unrecognized versions. Expected: '3' and/or '4'");
        }
        $ctx = [];
        $ctx['type'] = 'module';
        $ctx['basedir'] = \CRM\CivixBundle\Application::findExtDir();
        $basedir = new Path($ctx['basedir']);
        $info = new Info($basedir->string('info.xml'));
        $info->load($ctx);
        $attrs = $info->get()->attributes();
        if ($attrs['type'] != 'module') {
            $output->writeln('<error>Wrong extension type: ' . $attrs['type'] . '</error>');
            return;
        }
        if (!\preg_match('/^[A-Za-z0-9]+$/', $input->getArgument('<EntityName>'))) {
            throw new Exception("Entity name must be alphanumeric camel-case");
        }
        $ctx['entityNameCamel'] = \ucfirst($input->getArgument('<EntityName>'));
        $ctx['tableName'] = $input->getOption('table-name') ? $input->getOption('table-name') : Naming::createTableName($input->getArgument('<EntityName>'));
        if (\function_exists('_civicrm_api_get_entity_name_from_camel')) {
            $ctx['apiFunctionPrefix'] = 'civicrm_api' . self::API_VERSION . '_' . \_civicrm_api_get_entity_name_from_camel($ctx['entityNameCamel']) . '_';
        } else {
            throw new Exception("Failed to determine proper API function name. Perhaps the API internals have changed?");
        }
        $mixins = new Mixins($info, $basedir->string('mixin'), ['entity-types-php@1.0']);
        $mixins->save($ctx, $output);
        $info->save($ctx, $output);
        $ctx['apiFile'] = $basedir->string('api', 'v3', $ctx['entityNameCamel'] . '.php');
        $ctx['api4File'] = $basedir->string('Civi', 'Api4', $ctx['entityNameCamel'] . '.php');
        $ctx['daoClassName'] = \strtr($ctx['namespace'], '/', '_') . '_DAO_' . $input->getArgument('<EntityName>');
        $ctx['daoClassFile'] = $basedir->string(\strtr($ctx['daoClassName'], '_', '/') . '.php');
        $ctx['baoClassName'] = \strtr($ctx['namespace'], '/', '_') . '_BAO_' . $input->getArgument('<EntityName>');
        $ctx['baoClassFile'] = $basedir->string(\strtr($ctx['baoClassName'], '_', '/') . '.php');
        $ctx['schemaFile'] = $basedir->string('xml', 'schema', $ctx['namespace'], $input->getArgument('<EntityName>') . '.xml');
        $ctx['entityTypeFile'] = $basedir->string('xml', 'schema', $ctx['namespace'], $input->getArgument('<EntityName>') . '.entityType.php');
        $ctx['extensionName'] = $info->getExtensionName();
        $ctx['testApi3ClassName'] = 'api_v3_' . $ctx['entityNameCamel'] . 'Test';
        $ctx['testApi3ClassFile'] = $basedir->string('tests', 'phpunit', \strtr($ctx['testApi3ClassName'], '_', '/') . '.php');
        $ext = new Collection();
        $ext->builders['dirs'] = new Dirs([\dirname($ctx['apiFile']), \dirname($ctx['api4File']), \dirname($ctx['daoClassFile']), \dirname($ctx['baoClassFile']), \dirname($ctx['schemaFile']), \dirname($ctx['testApi3ClassFile'])]);
        $ext->builders['dirs']->save($ctx, $output);
        if (\in_array('3', $apiVersions)) {
            $ext->builders['api.php'] = new Template('entity-api.php.php', $ctx['apiFile'], \FALSE, Services::templating());
            $ext->builders['test.php'] = new Template('entity-api3-test.php.php', $ctx['testApi3ClassFile'], \FALSE, Services::templating());
        }
        if (\in_array('4', $apiVersions)) {
            $ext->builders['api4.php'] = new Template('entity-api4.php.php', $ctx['api4File'], \FALSE, Services::templating());
        }
        $ext->builders['bao.php'] = new Template('entity-bao.php.php', $ctx['baoClassFile'], \FALSE, Services::templating());
        $ext->builders['entity.xml'] = new Template('entity-schema.xml.php', $ctx['schemaFile'], \FALSE, Services::templating());
        if (!\file_exists($ctx['entityTypeFile'])) {
            $mgdEntities = [['name' => $ctx['entityNameCamel'], 'class' => $ctx['daoClassName'], 'table' => $ctx['tableName']]];
            $header = "// This file declares a new entity type. For more details, see \"hook_civicrm_entityTypes\" at:\n" . "// https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_entityTypes";
            $ext->builders['entityType.php'] = new PhpData($ctx['entityTypeFile'], $header);
            $ext->builders['entityType.php']->set($mgdEntities);
        }
        $phpUnitInitFiles = new PHPUnitGenerateInitFiles();
        $phpUnitInitFiles->initPhpunitXml($basedir->string('phpunit.xml.dist'), $ctx, $output);
        $phpUnitInitFiles->initPhpunitBootstrap($basedir->string('tests', 'phpunit', 'bootstrap.php'), $ctx, $output);
        $ext->init($ctx);
        $ext->save($ctx, $output);
        if (\count($apiVersions) >= 2) {
            $output->writeln('<comment>Generated API skeletons for APIv3 and APIv4.</comment>');
        } elseif ($apiVersions == ['3']) {
            $output->writeln('<comment>Generated API skeletons for APIv3. To generate APIv4, specify <info>--api-version=4</info></comment>');
        } elseif ($apiVersions == ['4']) {
            $output->writeln('<comment>Generated API skeletons for APIv4. To generate APIv3, specify <info>--api-version=3</info></comment>');
        }
        $output->writeln('<comment>You should now make any changes to the entity xml file and run `civix generate:entity-boilerplate` to generate necessary boilerplate.</comment>');
        $output->writeln('<comment>Note: no changes have been made to the database. You can update the database by uninstalling and re-enabling the extension.</comment>');
        return 0;
    }
}
<?php

namespace CRM\CivixBundle\Command;

use CRM\CivixBundle\Builder\Mixins;
use CRM\CivixBundle\Services;
use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CRM\CivixBundle\Builder\Collection;
use CRM\CivixBundle\Builder\Dirs;
use CRM\CivixBundle\Builder\Template;
use CRM\CivixBundle\Builder\PhpData;
use CRM\CivixBundle\Utils\Path;
class AddThemeCommand extends \CRM\CivixBundle\Command\AbstractCommand
{
    protected function configure()
    {
        $this->setName('generate:theme')->setDescription('Add a new theme to a CiviCRM Module-Extension (EXPERIMENTAL)')->addArgument('name', InputArgument::OPTIONAL, 'The name of the theme')->setHelp('Add a new theme to a CiviCRM Module-Extension

EXPERIMENTAL: At time of writing, this relies on a hook that has not yet
been released in a stable version of CiviCRM. The final hook should go out
on or after 5.8.x, but it is subject to change and approval.

Example: Generate an eponymous theme directly in the extension
$ civix generate:theme

Example: Generate a theme "foobar" in a subdirectory of the extension
$ civix generate:theme foobar
');
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->assertCurrentFormat();
        //// Figure out template data ////
        $ctx = [];
        $ctx['type'] = 'module';
        $ctx['basedir'] = \CRM\CivixBundle\Application::findExtDir();
        $basedir = new Path($ctx['basedir']);
        $info = $this->getModuleInfo($ctx);
        if (!$input->getArgument('name')) {
            // Make an eponymous theme directly in the extension.
            $ctx['themeName'] = $ctx['mainFile'];
            $ctx['themePrefix'] = NULL;
            $ctx['themePrefixDir'] = $basedir;
        } else {
            // Make a named theme in a subdir.
            $ctx['themeName'] = $input->getArgument('name');
            $ctx['themePrefix'] = $ctx['themeName'] . '/';
            $ctx['themePrefixDir'] = $basedir->path($ctx['themeName']);
        }
        $ctx['themeMetaFile'] = $basedir->string($ctx['themeName'] . '.theme.php');
        $ctx['themeCivicrmCss'] = $ctx['themePrefixDir']->string('css', 'civicrm.css');
        $ctx['themeBootstrapCss'] = $ctx['themePrefixDir']->string('css', 'bootstrap.css');
        //// Construct files ////
        $output->writeln("<info>Initialize theme</info> " . $ctx['themeName']);
        $ext = new Collection();
        $ext->builders['dirs'] = new Dirs([\dirname($ctx['themeMetaFile']), \dirname($ctx['themeCivicrmCss']), \dirname($ctx['themeBootstrapCss'])]);
        $ext->builders['mixins'] = new Mixins($info, $basedir->string('mixin'), ['theme-php@1.0']);
        $ext->builders['info'] = $info;
        if (!\file_exists($ctx['themeMetaFile'])) {
            $header = "// This file declares a CSS theme for CiviCRM.\n";
            // TODO: Add hyperlink for docs.
            $themeMeta = ['name' => $ctx['themeName'], 'title' => \sprintf("%s theme", $ctx['themeName']), 'prefix' => $ctx['themePrefix'], 'url_callback' => '\\Civi\\Core\\Themes\\Resolvers::simple', 'search_order' => array($ctx['themeName'], '_fallback_'), 'excludes' => []];
            $ext->builders['theme.php'] = new PhpData($ctx['themeMetaFile'], $header);
            $ext->builders['theme.php']->set($themeMeta);
        }
        $ext->builders['civicrm.css'] = new Template('civicrm.css.php', $ctx['themeCivicrmCss'], \FALSE, Services::templating());
        $ext->builders['bootstrap.css'] = new Template('bootstrap.css.php', $ctx['themeBootstrapCss'], \FALSE, Services::templating());
        $ext->loadInit($ctx);
        $ext->save($ctx, $output);
        return 0;
    }
}
<?php

namespace CRM\CivixBundle\Command;

use CivixPhar\Symfony\Component\Console\Input\InputInterface;
class AddFormCommand extends \CRM\CivixBundle\Command\AbstractAddPageCommand
{
    protected function configure()
    {
        parent::configure();
        $this->setName('generate:form')->setDescription('Add a basic web form to a CiviCRM Module-Extension');
    }
    protected function getPhpTemplate(InputInterface $input)
    {
        return 'form.php.php';
    }
    protected function getTplTemplate(InputInterface $input)
    {
        return 'form.tpl.php';
    }
    protected function createClassName(InputInterface $input, $ctx)
    {
        $namespace = \str_replace('/', '_', $ctx['namespace']);
        return $namespace . '_Form_' . $ctx['shortClassName'];
    }
    protected function createTplName(InputInterface $input, $ctx)
    {
        return $ctx['namespace'] . '/Form/' . \str_replace('_', '/', $ctx['shortClassName']) . '.tpl';
    }
}
<?php

namespace CRM\CivixBundle\Command;

use CRM\CivixBundle\Services;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CRM\CivixBundle\Builder\Info;
use CRM\CivixBundle\Builder\Module;
use CRM\CivixBundle\Utils\Path;
use Exception;
class AddEntityBoilerplateCommand extends \CRM\CivixBundle\Command\AbstractCommand
{
    const API_VERSION = 3;
    protected function configure()
    {
        parent::configure();
        $this->setName('generate:entity-boilerplate')->setDescription('Generates boilerplate code for entities based on xml schema definition files (*EXPERIMENTAL AND INCOMPLETE*)')->setHelp("Creates DAOs, mysql install and uninstall instructions.\n" . "\n" . "Typically you will run this command after creating or updating one or more\n" . "xml/schema/CRM/NameSpace/EntityName.xml files.\n");
    }
    /**
     * Note: this function replicates a fair amount of the functionality of
     * CRM_Core_CodeGen_Specification (which is a bit messy and hard to interact
     * with). It's tempting to completely rewrite / rethink entity generation. Until
     * then...
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        Services::boot(['output' => $output]);
        $civicrm_api3 = Services::api3();
        if (!$civicrm_api3 || !$civicrm_api3->local) {
            $output->writeln("<error>Require access to local CiviCRM source tree. Configure civicrm_api3_conf_path.</error>");
            return 1;
        }
        if (\version_compare(\CRM_Utils_System::version(), '4.7.0', '<=')) {
            $output->writeln("<error>This command requires CiviCRM 4.7+.</error>");
            return 1;
        }
        $this->assertCurrentFormat();
        $ctx = [];
        $ctx['type'] = 'module';
        $ctx['basedir'] = \CRM\CivixBundle\Application::findExtDir();
        $basedir = new Path($ctx['basedir']);
        $info = new Info($basedir->string('info.xml'));
        $info->load($ctx);
        $attrs = $info->get()->attributes();
        if ($attrs['type'] != 'module') {
            $output->writeln('<error>Wrong extension type: ' . $attrs['type'] . '</error>');
            return;
        }
        $xmlSchemaGlob = "xml/schema/{$ctx['namespace']}/*.xml";
        $absXmlSchemaGlob = $basedir->string($xmlSchemaGlob);
        $xmlSchemas = \glob($absXmlSchemaGlob);
        if (!\count($xmlSchemas)) {
            throw new Exception("Could not find files matching '{$xmlSchemaGlob}'. You may want to run `civix generate:entity` before running this command.");
        }
        $specification = new \CRM_Core_CodeGen_Specification();
        $specification->buildVersion = \CRM_Utils_System::majorVersion();
        $config = new \stdClass();
        $config->phpCodePath = $basedir->string('');
        $config->sqlCodePath = $basedir->string('sql/');
        $config->database = $this->getDefaultDatabase();
        foreach ($xmlSchemas as $xmlSchema) {
            $dom = new \DomDocument();
            $xmlString = \file_get_contents($xmlSchema);
            $dom->loadXML($xmlString);
            $xml = \simplexml_import_dom($dom);
            if (!$xml) {
                $output->writeln('<error>There is an error in the XML for ' . $xmlSchema . '</error>');
                continue;
            }
            /** @var array $tables */
            $specification->getTable($xml, $config->database, $tables);
            $name = (string) $xml->name;
            $tables[$name]['name'] = $name;
            $sourcePath = \strstr($xmlSchema, "/xml/schema/{$ctx['namespace']}/");
            $tables[$name]['sourceFile'] = $ctx['fullName'] . $sourcePath;
        }
        $config->tables = $tables;
        $_namespace = ' ' . \preg_replace(':/:', '_', $ctx['namespace']);
        $this->orderTables($tables, $output);
        $this->resolveForeignKeys($tables);
        $config->tables = $tables;
        foreach ($tables as $table) {
            $dao = new \CRM_Core_CodeGen_DAO($config, (string) $table['name'], "{$_namespace}_ExtensionUtil::ts");
            // Don't display gencode's output
            \ob_start();
            $dao->run();
            \ob_end_clean();
            $daoFileName = $basedir->string("{$table['base']}{$table['fileName']}");
            $output->writeln("<info>Write</info> {$daoFileName}");
        }
        $schema = new \CRM_Core_CodeGen_Schema($config);
        \CRM_Core_CodeGen_Util_File::createDir($config->sqlCodePath);
        /**
         * @param string $generator
         *   The desired $schema->$generator() function which will produce the file.
         * @param string $fileName
         *   The desired basename of the SQL file.
         */
        $createSql = function ($generator, $fileName) use($output, $schema, $config) {
            $filePath = $config->sqlCodePath . $fileName;
            // We're poking into an internal class+function (`$schema->$generator()`) that changed in v5.23.
            // Beginning in 5.23: $schema->$function() returns an array with file content.
            // Before 5.23: $schema->$function($fileName) creates $fileName and returns void.
            $output->writeln("<info>Write</info> {$filePath}");
            if (\version_compare(\CRM_Utils_System::version(), '5.23.alpha1', '>=')) {
                $data = $schema->{$generator}();
                if (!\file_put_contents($filePath, \reset($data))) {
                    $output->writeln("<error>Failed to write data to {$filePath}</error>");
                }
            } else {
                $output->writeln("<error>WARNING</error>: Support for generating entities on <5.23 is deprecated.");
                // Don't display gencode's output
                \ob_start();
                $schema->{$generator}($fileName);
                \ob_end_clean();
            }
        };
        $createSql('generateCreateSql', 'auto_install.sql');
        $createSql('generateDropSql', 'auto_uninstall.sql');
        $module = new Module(Services::templating());
        $module->loadInit($ctx);
        $module->save($ctx, $output);
        $upgraderClass = \str_replace('/', '_', $ctx['namespace']) . '_Upgrader';
        if (!\class_exists($upgraderClass)) {
            $output->writeln('<comment>You are missing an upgrader class. Your generated SQL files will not be executed on enable and uninstall. Fix this by running `civix generate:upgrader`.</comment>');
        }
        return 0;
    }
    private function orderTables(&$tables, $output)
    {
        $ordered = [];
        $abort = \count($tables);
        while (\count($tables)) {
            // Safety valve
            if ($abort-- == 0) {
                $output->writeln("<error>Cannot determine FK ordering of tables.</error>  Do you have circular Foreign Keys?  Change your FK's or fix your auto_install.sql");
                break;
            }
            // Consider each table
            foreach ($tables as $k => $table) {
                // No FK's? Easy - add now
                if (!isset($table['foreignKey'])) {
                    $ordered[$k] = $table;
                    unset($tables[$k]);
                }
                if (isset($table['foreignKey'])) {
                    // If any FK references a table still in our list (but is not a self-reference),
                    // skip this table for now
                    foreach ($table['foreignKey'] as $fKey) {
                        if (\in_array($fKey['table'], \array_keys($tables)) && $fKey['table'] != $table['name']) {
                            continue 2;
                        }
                    }
                    // If we get here, all FK's reference already added tables or external tables so add now
                    $ordered[$k] = $table;
                    unset($tables[$k]);
                }
            }
        }
        $tables = $ordered;
    }
    private function resolveForeignKeys(&$tables)
    {
        foreach ($tables as &$table) {
            if (isset($table['foreignKey'])) {
                foreach ($table['foreignKey'] as &$key) {
                    if (isset($tables[$key['table']])) {
                        $key['className'] = $tables[$key['table']]['className'];
                        $key['fileName'] = $tables[$key['table']]['fileName'];
                        $table['fields'][$key['name']]['FKClassName'] = $key['className'];
                    } else {
                        $key['className'] = \CRM_Core_DAO_AllCoreTables::getClassForTable($key['table']);
                        $key['fileName'] = $key['className'] . '.php';
                        $table['fields'][$key['name']]['FKClassName'] = $key['className'];
                    }
                }
            }
        }
    }
    /**
     * Get general/default database options (eg character set, collation).
     *
     * In civicrm-core, the `database` definition comes from
     * `xml/schema/Schema.xml` and `$spec->getDatabase($dbXml)`.
     *
     * Civix uses different defaults. Explanations are inlined below.
     *
     * @return array
     */
    private function getDefaultDatabase() : array
    {
        return [
            'name' => '',
            'attributes' => '',
            'tableAttributes_modern' => 'ENGINE=InnoDB',
            'tableAttributes_simple' => 'ENGINE=InnoDB',
            // ^^ Set very limited defaults.
            // Existing deployments may be inconsistent with respect to charsets and collations, and
            // it's hard to attune with static code. This represents a compromise (until we can
            // rework the process in a way that clearly addresses the inconsistencies among deployments).
            'comment' => '',
        ];
    }
}
<?php

namespace CRM\CivixBundle\Command;

use CRM\CivixBundle\Builder\Mixins;
use CRM\CivixBundle\Builder\Template;
use CRM\CivixBundle\Services;
use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CRM\CivixBundle\Utils\Path;
use Exception;
class AddCaseTypeCommand extends \CRM\CivixBundle\Command\AbstractCommand
{
    protected function configure()
    {
        parent::configure();
        $this->setName('generate:case-type')->setDescription('Add a CiviCase case-type')->addArgument('<Label>', InputArgument::REQUIRED, 'Printable name of the case type')->addArgument('<Name>', InputArgument::OPTIONAL, 'Code name of the case type (Default: Derive from <Label>)');
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        // load Civi to get access to civicrm_api_get_function_name
        Services::boot(['output' => $output]);
        $civicrm_api3 = Services::api3();
        if (!$civicrm_api3 || !$civicrm_api3->local) {
            $output->writeln("Requires access to local CiviCRM source tree. Configure civicrm_api3_conf_path.</error>");
            return 1;
        }
        $this->assertCurrentFormat();
        if (!\preg_match('/^[A-Z][A-Za-z0-9_ \\.\\-]*$/', $input->getArgument('<Label>'))) {
            throw new Exception("Label should be valid");
        }
        if (!$input->getArgument('<Name>')) {
            // $input->setArgument('<Name>', \CRM_Utils_String::munge(ucwords(str_replace('_', ' ', $input->getArgument('<Label>'))), '', 0));
            $input->setArgument('<Name>', \CRM_Case_XMLProcessor::mungeCasetype($input->getArgument('<Label>')));
        }
        if (!\preg_match('/^[A-Z][A-Za-z0-9]*$/', $input->getArgument('<Name>'))) {
            throw new Exception("Name should be valid (alphanumeric beginning with uppercase)");
        }
        $ctx = [];
        $ctx['type'] = 'module';
        $ctx['basedir'] = \CRM\CivixBundle\Application::findExtDir();
        $ctx['caseTypeLabel'] = $input->getArgument('<Label>');
        $ctx['caseTypeName'] = $input->getArgument('<Name>');
        $basedir = new Path($ctx['basedir']);
        $info = $this->getModuleInfo($ctx);
        $xmlFile = $basedir->string('xml', 'case', $ctx['caseTypeName'] . '.xml');
        $tpl = new Template('case-type.xml.php', $xmlFile, \FALSE);
        $tpl->save($ctx, $output);
        $mixins = new Mixins($info, $basedir->string('mixin'), ['case-xml@1.0']);
        $mixins->save($ctx, $output);
        $info->save($ctx, $output);
        return 0;
    }
}
<?php

namespace CRM\CivixBundle\Command;

use CRM\CivixBundle\Services;
use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CRM\CivixBundle\Builder\Dirs;
use CRM\CivixBundle\Builder\Info;
use CRM\CivixBundle\Utils\Path;
use CRM\CivixBundle\Builder\PHPUnitGenerateInitFiles;
use Exception;
class AddTestCommand extends \CRM\CivixBundle\Command\AbstractCommand
{
    protected function configure()
    {
        parent::configure();
        $this->setName('generate:test')->setDescription('Add a new PHPUnit test to a CiviCRM Module-Extension')->setHelp('
Add a new PHPUnit test to a CiviCRM Module-Extension

In creating a test, you may specify a template:
  headless: A headless test boots CiviCRM once with a headless database, and
            all work can be executed in-process. These are faster and support
            automatic cleanup, but they provide a less thorough simulation
            of real-world systems.
  e2e:      An end-to-end test boots the live installation of CiviCRM and
            the real CMS This provides a more thorough simulation, and you
            may spawn  requests to Civi using HTTP or cv(). However, spawning
            separate requests will be slower, and data-cleanup may take more
            effort.
  legacy:   A variation of `headless` based on CiviUnitTestCase.
            It is provided primarily for testing purposes.
  phpunit:  A test suite based on the PHPUnit_Framework_TestCase. Provides an 
            interface for you extension to implement unittest for your 
            classes/functions

To execute tests, call phpunit 4.x directly, e.g.

  phpunit4 tests/phpunit/CRM/Myextension/MyTest.php

Note: The design of headless and E2E tests prevent them from running
concurrently. If you have a mix of tests, you can execute them
as separate groups:

  phpunit4 --group headless
  phpunit4 --group e2e
')->addOption('template', NULL, InputOption::VALUE_REQUIRED, 'The template of test to generate (headless, e2e, legacy)', 'headless')->addArgument('<CRM_Full_ClassName>', InputArgument::REQUIRED, 'The full class name (eg "CRM_Myextension_MyTest" or "Civi\\Myextension\\MyTest")');
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->assertCurrentFormat();
        $ctx = [];
        $ctx['type'] = 'module';
        $ctx['basedir'] = \CRM\CivixBundle\Application::findExtDir();
        $basedir = new Path($ctx['basedir']);
        $info = new Info($basedir->string('info.xml'));
        $info->load($ctx);
        if ($info->getType() != 'module') {
            $output->writeln('<error>Wrong extension type: ' . $info->getType() . '</error>');
            return;
        }
        $phpUnitInitFiles = new PHPUnitGenerateInitFiles();
        $phpUnitInitFiles->initPhpunitXml($basedir->string('phpunit.xml.dist'), $ctx, $output);
        $phpUnitInitFiles->initPhpunitBootstrap($basedir->string('tests', 'phpunit', 'bootstrap.php'), $ctx, $output);
        $this->initTestClass($input->getArgument('<CRM_Full_ClassName>'), $this->getTestTemplate($input->getOption('template')), $basedir, $ctx, $output);
        return 0;
    }
    protected function getTestTemplate($type)
    {
        $templates = ['e2e' => 'test-e2e.php.php', 'headless' => 'test-headless.php.php', 'legacy' => 'test-legacy.php.php', 'phpunit' => 'test-phpunit.php.php'];
        if (isset($templates[$type])) {
            return $templates[$type];
        } else {
            throw new \Exception("Invalid test template");
        }
    }
    /**
     * @param string $fullClassName
     * @param string $templateName
     * @param \CRM\CivixBundle\Utils\Path $basedir
     * @param array $ctx
     * @param \Symfony\Component\Console\Output\OutputInterface $output
     * @throws \Exception
     */
    protected function initTestClass($fullClassName, $templateName, $basedir, $ctx, OutputInterface $output)
    {
        $fullClassName = \trim($fullClassName, '\\');
        if (!\preg_match('/^[A-Za-z0-9_\\\\]+$/', $fullClassName)) {
            throw new Exception("Class name must be alphanumeric (with underscores and backslashes)");
        }
        if (!\preg_match('/Test$/', $fullClassName)) {
            throw new Exception("Class name must end with the word \"Test\"");
        }
        $parts = \explode('\\', $fullClassName);
        $ctx['testClass'] = \array_pop($parts);
        $ctx['testNamespace'] = \implode('\\', $parts);
        $testFile = \strtr($fullClassName, ['_' => '/', '\\' => '/']) . '.php';
        $testPath = $basedir->string('tests', 'phpunit', $testFile);
        $dirs = new Dirs([\dirname($testPath)]);
        $dirs->save($ctx, $output);
        if (!\file_exists($testPath)) {
            $output->writeln(\sprintf('<info>Write</info> %s', $testPath));
            \file_put_contents($testPath, Services::templating()->render($templateName, $ctx));
        } else {
            $output->writeln(\sprintf('<error>Skip %s: file already exists</error>', $testPath));
        }
    }
}
<?php

namespace CRM\CivixBundle\Command;

use CRM\CivixBundle\Services;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
class PingCommand extends \CRM\CivixBundle\Command\AbstractCommand
{
    protected function configure()
    {
        parent::configure();
        $this->setName('civicrm:ping')->setDescription('Test whether the CiviCRM client is properly configured');
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        Services::boot(['output' => $output]);
        $civicrm_api3 = Services::api3();
        if ($civicrm_api3->Contact->Get(['option.limit' => 1])) {
            if (empty($civicrm_api3->result->values[0]->contact_type)) {
                $output->writeln('<error>Ping failed: Site reported that it found no contacts</error>');
            } else {
                $output->writeln('<info>Ping successful</info>');
            }
        } else {
            $output->writeln('<error>Ping failed: API Error: ' . $civicrm_api3->errorMsg() . '</error>');
        }
        return 0;
    }
}
<?php

namespace CRM\CivixBundle\Command;

use CRM\CivixBundle\Services;
use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
class ConfigGetCommand extends \CRM\CivixBundle\Command\AbstractCommand
{
    protected function configure()
    {
        parent::configure();
        $this->setName('config:get')->setDescription('Get configuration values')->addArgument('parameter', InputArgument::OPTIONAL, 'Parameter name');
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $config = Services::config();
        foreach ($this->getInterestingParameters() as $key) {
            \printf("%-40s \"%s\"\n", $key, @$config['parameters'][$key]);
        }
        return 0;
    }
    protected function getInterestingParameters()
    {
        return ['author', 'email', 'license'];
    }
}
<?php

namespace CRM\CivixBundle\Command;

use CRM\CivixBundle\Builder\Mixins;
use CRM\CivixBundle\Services;
use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CRM\CivixBundle\Builder\Dirs;
use CRM\CivixBundle\Builder\Menu;
use CRM\CivixBundle\Builder\Module;
use CRM\CivixBundle\Utils\Path;
use Exception;
abstract class AbstractAddPageCommand extends \CRM\CivixBundle\Command\AbstractCommand
{
    protected function configure()
    {
        $this->addArgument('<ClassName>', InputArgument::REQUIRED, 'Base name of the controller class name (eg "MyPage")')->addArgument('<web/path>', InputArgument::REQUIRED, 'The path which maps to this page (eg "civicrm/my-page")');
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        if (!\preg_match('/^civicrm\\//', $input->getArgument('<web/path>'))) {
            throw new Exception("Web path must begin with 'civicrm/'");
        }
        if (!\preg_match('/^[A-Z][A-Za-z0-9_]*$/', $input->getArgument('<ClassName>'))) {
            throw new Exception("Class name should be valid (alphanumeric beginning with uppercase)");
        }
        $this->assertCurrentFormat();
        $ctx = [];
        $ctx['type'] = 'module';
        $ctx['basedir'] = \CRM\CivixBundle\Application::findExtDir();
        $ctx['shortClassName'] = $input->getArgument('<ClassName>');
        $basedir = new Path($ctx['basedir']);
        $info = $this->getModuleInfo($ctx);
        $ctx['fullClassName'] = $this->createClassName($input, $ctx);
        $phpFile = $basedir->string(\str_replace('_', '/', $ctx['fullClassName']) . '.php');
        $tplFile = $basedir->string('templates', $this->createTplName($input, $ctx));
        if (\preg_match('/^CRM_/', $input->getArgument('<ClassName>'))) {
            throw new Exception("Class name looks suspicious. Please note the final class would be \"{$ctx['fullClassName']}\"");
        }
        $dirs = new Dirs([$basedir->string('xml', 'Menu'), \dirname($phpFile), \dirname($tplFile)]);
        $dirs->save($ctx, $output);
        $menu = new Menu($basedir->string('xml', 'Menu', $ctx['mainFile'] . '.xml'));
        $menu->loadInit($ctx);
        if (!$menu->hasPath($input->getArgument('<web/path>'))) {
            $menu->addItem($ctx, $input->getArgument('<ClassName>'), $ctx['fullClassName'], $input->getArgument('<web/path>'));
            $menu->save($ctx, $output);
        } else {
            $output->writeln(\sprintf('<error>Failed to bind %s to class %s; %s is already bound</error>', $input->getArgument('<web/path>'), $input->getArgument('<ClassName>'), $input->getArgument('<web/path>')));
        }
        if (!\file_exists($phpFile)) {
            $output->writeln(\sprintf('<info>Write</info> %s', $phpFile));
            \file_put_contents($phpFile, Services::templating()->render($this->getPhpTemplate($input), $ctx));
        } else {
            $output->writeln(\sprintf('<error>Skip %s: file already exists</error>', $phpFile));
        }
        if (!\file_exists($tplFile)) {
            $output->writeln(\sprintf('<info>Write</info> %s', $tplFile));
            \file_put_contents($tplFile, Services::templating()->render($this->getTplTemplate($input), $ctx));
        } else {
            $output->writeln(\sprintf('<error>Skip %s: file already exists</error>', $tplFile));
        }
        $module = new Module(Services::templating());
        $module->loadInit($ctx);
        $module->save($ctx, $output);
        $mixins = new Mixins($info, $basedir->string('mixin'), ['menu-xml@1.0', 'smarty-v2@1.0']);
        $mixins->save($ctx, $output);
        $info->save($ctx, $output);
        return 0;
    }
    protected abstract function getPhpTemplate(InputInterface $input);
    protected abstract function getTplTemplate(InputInterface $input);
    protected abstract function createClassName(InputInterface $input, $ctx);
    protected abstract function createTplName(InputInterface $input, $ctx);
}
<?php
namespace CRM\CivixBundle\Command;

use CRM\CivixBundle\Services;
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 CRM\CivixBundle\Builder\Collection;
use CRM\CivixBundle\Builder\Dirs;
use CRM\CivixBundle\Builder\Info;
use CRM\CivixBundle\Builder\Template;
use CRM\CivixBundle\Utils\Path;

class AddAngularDirectiveCommand extends \Symfony\Component\Console\Command\Command {

  protected function configure() {
    $this
      ->setName('generate:angular-directive')
      ->setDescription('Add a new Angular directive (Civi v4.6+)')
      ->addOption('am', NULL, InputOption::VALUE_REQUIRED, 'Name of the Angular module (default: match the Civi module name)')
      ->addArgument('<directive-name>', InputArgument::REQUIRED, 'Directive name (Ex: "my-directive")')
      ->setHelp('An Angular directive is a custom HTML tag implemented in Javascript.
Directives can be used in many ways -- to define new input elements, new
decorations, or chunks of reusable content.

You should generally include a prefix in the directive name.
For example, directives in Angular core use "ng-*", and
directives in CiviCRM core use "crm-*".

For more, see https://docs.angularjs.org/guide/directive');
  }

  protected function execute(InputInterface $input, OutputInterface $output) {
    //// Figure out template data ////
    $ctx = [];
    $ctx['type'] = 'module';
    $ctx['basedir'] = \CRM\CivixBundle\Application::findExtDir();
    $basedir = new Path($ctx['basedir']);

    $info = new Info($basedir->string('info.xml'));
    $info->load($ctx);
    $attrs = $info->get()->attributes();
    if ($attrs['type'] != 'module') {
      $output->writeln('<error>Wrong extension type: ' . $attrs['type'] . '</error>');
      return;
    }

    $ctx['tsDomain'] = (string) $attrs['key'];
    $ctx['angularModuleName'] = $input->getOption('am') ? $input->getOption('am') : $ctx['mainFile'];
    $ctx['dirNameCamel'] = $this->toCamel($input->getArgument('<directive-name>'));
    $ctx['dirNameHyp'] = $this->toHyphen($input->getArgument('<directive-name>'));

    if (preg_match('/^' . $ctx['angularModuleName'] . '[A-Z]/', $ctx['dirNameCamel'])) {
      $ctx['baseFileName'] = preg_replace('/^' . $ctx['angularModuleName'] . '/', '', $ctx['dirNameCamel']);
    }
    else {
      $output->writeln('<error>Warning: Directive name does not begin with module name.</error>');
      $ctx['baseFileName'] = $ctx['dirNameCamel'];
    }

    $ctx['jsPath'] = $basedir->string('ang', $ctx['angularModuleName'], $ctx['baseFileName'] . '.js');
    $ctx['htmlName'] = implode('/', ['~', $ctx['angularModuleName'], $ctx['baseFileName'] . '.html']);
    $ctx['htmlPath'] = $basedir->string('ang', $ctx['angularModuleName'], $ctx['baseFileName'] . '.html');

    //// Construct files ////
    $output->writeln("<info>Initialize Angular directive \"" . $ctx['dirNameHyp'] . "\" (aka \"" . $ctx['dirNameCamel'] . "\")</info>");

    $ext = new Collection();
    $ext->builders['dirs'] = new Dirs([
      dirname($ctx['jsPath']),
      dirname($ctx['htmlPath']),
    ]);;

    $ext->builders['js'] = new Template('angular-dir.js.php', $ctx['jsPath'], FALSE, Services::templating());
    $ext->builders['html'] = new Template('angular-dir.html.php', $ctx['htmlPath'], FALSE, Services::templating());

    $ext->init($ctx);
    $ext->save($ctx, $output);
  }

  public function toHyphen($dirName) {
    $buf = '';
    foreach (str_split($dirName) as $char) {
      if ($char >= 'A' && $char <= 'Z') {
        $buf .= '-' . strtolower($char);
      }
      else {
        $buf .= $char;
      }
    }
    return trim(preg_replace('/-+/', '-', $buf), '-');
  }

  public function toCamel($dirName) {
    return lcfirst(preg_replace('/ /', '', ucwords(preg_replace('/-/', ' ', $dirName))));
  }

}
<?php

namespace CRM\CivixBundle\Command;

use CivixPhar\Symfony\Component\Console\Input\InputInterface;
class AddPageCommand extends \CRM\CivixBundle\Command\AbstractAddPageCommand
{
    protected function configure()
    {
        parent::configure();
        $this->setName('generate:page')->setDescription('Add a basic web page to a CiviCRM Module-Extension');
    }
    protected function getPhpTemplate(InputInterface $input)
    {
        return 'page.php.php';
    }
    protected function getTplTemplate(InputInterface $input)
    {
        return 'page.tpl.php';
    }
    protected function createClassName(InputInterface $input, $ctx)
    {
        $namespace = \str_replace('/', '_', $ctx['namespace']);
        return $namespace . '_Page_' . $ctx['shortClassName'];
    }
    protected function createTplName(InputInterface $input, $ctx)
    {
        return $ctx['namespace'] . '/Page/' . $ctx['shortClassName'] . '.tpl';
    }
}
<?php

namespace CRM\CivixBundle\Command;

use CRM\CivixBundle\Application;
use CRM\CivixBundle\Services;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CRM\CivixBundle\Builder\Dirs;
use CRM\CivixBundle\Builder\Info;
use CRM\CivixBundle\Builder\Module;
use CRM\CivixBundle\Utils\Path;
class AddUpgraderCommand extends \CRM\CivixBundle\Command\AbstractCommand
{
    protected function configure()
    {
        parent::configure();
        $this->setName('generate:upgrader')->setDescription('Add an example upgrader class to a CiviCRM Module-Extension');
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->assertCurrentFormat();
        $ctx = [];
        $ctx['type'] = 'module';
        $ctx['basedir'] = Application::findExtDir();
        $basedir = new Path($ctx['basedir']);
        $info = new Info($basedir->string('info.xml'));
        $info->load($ctx);
        $attrs = $info->get()->attributes();
        if ($attrs['type'] != 'module') {
            $output->writeln('<error>Wrong extension type: ' . $attrs['type'] . '</error>');
            return 1;
        }
        $dirs = [$basedir->string('sql'), $basedir->string($ctx['namespace'])];
        (new Dirs($dirs))->save($ctx, $output);
        $crmPrefix = \preg_replace(':/:', '_', $ctx['namespace']);
        $ctx['baseUpgrader'] = 'CRM_Extension_Upgrader_Base';
        $phpFile = $basedir->string($ctx['namespace'], 'Upgrader.php');
        if (!\file_exists($phpFile)) {
            $output->writeln(\sprintf('<info>Write</info> %s', $phpFile));
            \file_put_contents($phpFile, Services::templating()->render('upgrader.php.php', $ctx));
        } else {
            $output->writeln(\sprintf('<error>Skip %s: file already exists, defer to customized version</error>', $phpFile));
        }
        if (!$info->get()->xpath('upgrader')) {
            $info->get()->addChild('upgrader', $crmPrefix . '_Upgrader');
        }
        $info->raiseCompatibilityMinimum('5.38');
        $info->save($ctx, $output);
        $module = new Module(Services::templating());
        $module->loadInit($ctx);
        $module->save($ctx, $output);
        return 0;
    }
}
<?php

namespace CRM\CivixBundle\Command;

use CRM\CivixBundle\Builder\Mixins;
use CRM\CivixBundle\Services;
use CivixPhar\Symfony\Component\Console\Input\InputArgument;
use CivixPhar\Symfony\Component\Console\Input\InputInterface;
use CivixPhar\Symfony\Component\Console\Input\InputOption;
use CivixPhar\Symfony\Component\Console\Output\OutputInterface;
use CRM\CivixBundle\Builder\Collection;
use CRM\CivixBundle\Builder\CopyClass;
use CRM\CivixBundle\Builder\CopyFile;
use CRM\CivixBundle\Builder\Dirs;
use CRM\CivixBundle\Builder\PhpData;
use CRM\CivixBundle\Builder\Template;
use CRM\CivixBundle\Utils\Path;
class AddReportCommand extends \CRM\CivixBundle\Command\AbstractCommand
{
    protected function configure()
    {
        parent::configure();
        $this->setName('generate:report')->setDescription('Add a report to a module-extension')->addArgument('<ClassName>', InputArgument::REQUIRED, 'Base name of the report class (eg "MyReport")')->addArgument('<CiviComponent>', InputArgument::REQUIRED, 'CiviCRM Component (' . \implode(', ', $this->getReportComponents()) . ')')->addOption('webPath', NULL, InputOption::VALUE_OPTIONAL, 'Path which maps to this report (eg "civicrm/report/my-report")')->addOption('copy', NULL, InputOption::VALUE_OPTIONAL, 'Full class name of an existing report which should be copied (eg "CRM_Report_Form_Activity")');
    }
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->assertCurrentFormat();
        //// Figure out template data and put it in $ctx ////
        $ctx = [];
        $ctx['type'] = 'module';
        $ctx['basedir'] = \CRM\CivixBundle\Application::findExtDir();
        $basedir = new Path($ctx['basedir']);
        $info = $this->getModuleInfo($ctx);
        if (!\in_array($input->getArgument('<CiviComponent>'), $this->getReportComponents())) {
            throw new \Exception("Component must be one of: " . \implode(', ', $this->getReportComponents()));
        }
        $ctx['reportClassName'] = \strtr($ctx['namespace'], '/', '_') . '_Form_Report_' . $input->getArgument('<ClassName>');
        $ctx['reportClassFile'] = $basedir->string(\strtr($ctx['reportClassName'], '_', '/') . '.php');
        $ctx['reportMgdFile'] = $basedir->string(\strtr($ctx['reportClassName'], '_', '/') . '.mgd.php');
        $ctx['reportTplFile'] = $basedir->string('templates', \strtr($ctx['reportClassName'], '_', '/') . '.tpl');
        $webPath = $input->getOption('webPath');
        if (!empty($webPath)) {
            if (\preg_match('/^civicrm\\/report\\/(.+)$/', $webPath, $matches)) {
                $ctx['reportUrl'] = \strtolower($matches[1]);
            } else {
                throw new \Exception("webPath must begin with \"civicrm/report/\"");
            }
        } else {
            $ctx['reportUrl'] = \strtolower($ctx['fullName'] . '/' . $input->getArgument('<ClassName>'));
        }
        //// Construct files ////
        $output->writeln("<info>Initialize report " . $ctx['reportClassName'] . "</info>");
        $ext = new Collection();
        $ext->builders['dirs'] = new Dirs([\dirname($ctx['reportClassFile']), \dirname($ctx['reportMgdFile']), \dirname($ctx['reportTplFile'])]);
        // Register the report in the DB using api/v3/ReportTemplate and hook_civicrm_managed
        if (!\file_exists($ctx['reportMgdFile'])) {
            $mgdEntities = [['name' => $ctx['reportClassName'], 'entity' => 'ReportTemplate', 'params' => ['version' => 3, 'label' => $input->getArgument('<ClassName>'), 'description' => \sprintf("%s (%s)", $input->getArgument('<ClassName>'), $ctx['fullName']), 'class_name' => $ctx['reportClassName'], 'report_url' => $ctx['reportUrl'], 'component' => $input->getArgument('<CiviComponent>') == 'null' ? '' : $input->getArgument('<CiviComponent>')]]];
            $header = "// This file declares a managed database record of type \"ReportTemplate\".\n" . "// The record will be automatically inserted, updated, or deleted from the\n" . "// database as appropriate. For more details, see \"hook_civicrm_managed\" at:\n" . "// https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_managed";
            $ext->builders['mgd.php'] = new PhpData($ctx['reportMgdFile'], $header);
            $ext->builders['mgd.php']->set($mgdEntities);
        }
        // Create .php & .tpl by either copying from core source tree or using a civix template
        if ($srcClassName = $input->getOption('copy')) {
            // To locate the original file, we need to bootstrap Civi and search the include path
            Services::boot(['output' => $output]);
            $civicrm_api3 = Services::api3();
            if (!$civicrm_api3 || !$civicrm_api3->local) {
                $output->writeln("<error>--copy requires access to local CiviCRM source tree. Configure civicrm_api3_conf_path.</error>");
                return;
            }
            $origTplFile = 'templates/' . \preg_replace('/_/', '/', $srcClassName) . '.tpl';
            $ext->builders['report.php'] = new CopyClass($srcClassName, $ctx['reportClassName'], $ctx['reportClassFile'], \FALSE);
            $ext->builders['page.tpl.php'] = new CopyFile($origTplFile, $ctx['reportTplFile'], \FALSE);
        } else {
            $ext->builders['report.php'] = new Template('report.php.php', $ctx['reportClassFile'], \FALSE, Services::templating());
            $ext->builders['page.tpl.php'] = new Template('report.tpl.php', $ctx['reportTplFile'], \FALSE, Services::templating());
        }
        $ext->builders['mixins'] = new Mixins($info, $basedir->string('mixin'), ['mgd-php@1.0']);
        $ext->builders['info'] = $info;
        $ext->loadInit($ctx);
        $ext->save($ctx, $output);
        return 0;
    }
    /**
     * Get list of components that reports can be associated with
     *
     * @return array(string)
     */
    protected function getReportComponents()
    {
        return ['CiviCampaign', 'CiviCase', 'CiviContribute', 'CiviEvent', 'CiviGrant', 'CiviMail', 'CiviMember', 'CiviPledge', 'null'];
    }
}
<?php

namespace CivixPhar;

/**
 * Mirror a select list of backports from `civicrm-core:mixin/`.
 */
return ['polyfill' => [
    'sha256' => '4a60b871ca6ef75172459667e130d0692998d10b6ee59cfc3be541e50d0da3f7',
    'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/f55a0e7978c92e76c18cd613ece11489052b5b33/mixin/polyfill.php',
    // ^^ This link can be updated when there is tag for 5.58.
    'local' => 'extern/mixin/polyfill.php',
    'provided-by' => '5.45.beta1',
    'minimum' => '5.27',
], 'afform-entity-php@1' => ['version' => '1.0.0', 'sha256' => '1f737bc96e019dac459aade88206778cf141c59d322d5aa56c02ee4afb9eb649', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.50.0/mixin/afform-entity-php@1/mixin.php', 'local' => 'extern/mixin/afform-entity-php@1/mixin.php', 'provided-by' => '5.50.beta1', 'minimum' => '5.31'], 'ang-php@1' => ['version' => '1.0.0', 'sha256' => '7dc91fab620fc6ba74a5a00347a2d8f39846c97c8cf20cf4291a1002d3d9c245', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.45.3/mixin/ang-php@1/mixin.php', 'local' => 'extern/mixin/ang-php@1/mixin.php', 'provided-by' => '5.45.beta1', 'minimum' => '5.27'], 'case-xml@1' => ['version' => '1.0.0', 'sha256' => '23a4f7d128b286c79acf20598a9017a0fac213115a64504d8f84c2096ce1f490', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.45.3/mixin/case-xml@1/mixin.php', 'local' => 'extern/mixin/case-xml@1/mixin.php', 'provided-by' => '5.45.beta1', 'minimum' => '5.27'], 'entity-types-php@1' => ['version' => '1.0.0', 'sha256' => 'f8e10aac991b2b3acac269a1fca81f883a295908990687959e790885a2e410c2', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.57.0/mixin/entity-types-php%401/mixin.php', 'local' => 'extern/mixin/entity-types-php@1/mixin.php', 'provided-by' => '5.57.beta1', 'minimum' => '5.45'], 'menu-xml@1' => ['version' => '1.0.0', 'sha256' => '4f5be44d6764816b22d0a5cdc2e047cfd9ec4acf48e548f82bb20c05db933d0e', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.45.3/mixin/menu-xml@1/mixin.php', 'local' => 'extern/mixin/menu-xml@1/mixin.php', 'provided-by' => '5.45.beta1', 'minimum' => '5.27'], 'mgd-php@1' => ['version' => '1.0.0', 'sha256' => '458fef1ae4b649bae7826bfc9f3b7d55c6a3f577d2eae4cbc1c520c48d6d4d7d', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.45.3/mixin/mgd-php@1/mixin.php', 'local' => 'extern/mixin/mgd-php@1/mixin.php', 'provided-by' => '5.45.beta1', 'minimum' => '5.27'], 'scan-classes@1' => [
    // scan-calsses is not meaningful to backport, but tracking metadata helps with admin.
    'version' => '1.0.0',
    'sha256' => '68b543079255d3d92773a5d75f5b033b3227b595337ece207f6dec865a54f0c4',
    'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/4b0558d911bfcbd81e1f5199b0eb0c837c7c8205/mixin/scan-classes@1/mixin.php',
    'local' => 'extern/mixin/scan-classes@1/mixin.php',
    'provided-by' => '5.51.beta2',
    'minimum' => '5.51',
], 'setting-php@1' => ['version' => '1.0.0', 'sha256' => '5ce236c1a1a63637ce5f0f4fe5bf7f21eaa06c750ca16c0fbf4dd792da0d23c9', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.45.3/mixin/setting-php@1/mixin.php', 'local' => 'extern/mixin/setting-php@1/mixin.php', 'provided-by' => '5.45.beta1', 'minimum' => '5.27'], 'smarty-v2@1' => ['version' => '1.0.1', 'sha256' => '6b1e05facc17d414d8e99faf5bdd9fe694ff92cc3d7f9a05e2fe6fc63e3d1948', 'remote' => 'https://github.com/civicrm/civicrm-core/raw/7168793c03ef57c06bbfe45f5ff873ebb3657806/mixin/smarty-v2%401/mixin.php', 'local' => 'extern/mixin/smarty-v2@1/mixin.php', 'provided-by' => '5.59', 'minimum' => '5.27'], 'theme-php@1' => ['version' => '1.0.0', 'sha256' => '2d4bd2442fde152c8f31805ac265c2249d5cf771185f1ac870fd1fcbb18db3ed', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.45.3/mixin/theme-php@1/mixin.php', 'local' => 'extern/mixin/theme-php@1/mixin.php', 'provided-by' => '5.45.beta1', 'minimum' => '5.27']];
<?php

namespace CivixPhar;

/**
 * I haven't traced why, but it seems that core is getting more eager to scan
 * BAOs/DAOs early on -- in a way that provokes class-loading errors if your
 * extension defines entities and lacks `<psr0>` for `CRM_`
 *
 * Just add the '<psr0>` bit to everything.
 */
return function (\CRM\CivixBundle\Upgrader $upgrader) {
    $upgrader->updateInfo(function (\CRM\CivixBundle\Builder\Info $info) use($upgrader) {
        /* @var \Symfony\Component\Console\Style\SymfonyStyle $io */
        $io = $upgrader->io;
        $loaders = $info->getClassloaders();
        $prefixes = \array_column($loaders, 'prefix');
        if (\file_exists($upgrader->baseDir->string('CRM')) && !\in_array('CRM_', $prefixes)) {
            $io->section('"CRM" Class-loader');
            $io->note(['Older templates enabled class-loading via "hook_config" and "include_path".', 'Newer templates enable class-loading via "info.xml" ("<classloader>"). This fixes some edge-case issues and allows more configuration.', 'It is generally safe for these loaders to coexist. The upgrade will add "<classloader>" for the "CRM" folder.']);
            $io->warning(['If you use the rare (and ill-advised/unsupported) practice of class-overrides, then you may need extra diligence with any changes to class-loading.']);
            if (!$io->confirm('Continue with upgrade?')) {
                throw new \RuntimeException('User stopped upgrade');
            }
            $loaders[] = ['type' => 'psr0', 'prefix' => 'CRM_', 'path' => '.'];
            $info->setClassLoaders($loaders);
        }
    });
};
<?php

namespace CivixPhar;

/**
 * The templates for PHPUnit tests have been updated to match a major
 * transition in PHPUnit -- *all upstream base-classes were renamed*:
 *
 * - `PHPUnit_Framework_TestCase` is the base-class in PHPUnit 4 and earlier
 * - `\PHPUnit\Framework\TestCase` is the base-class in PHPUnit 6 and later
 * - PHPUnit 5 is a transitional version which supports both naming conventions.
 *
 * In recent years, documentation+tooling in Civi have encouraged usage of
 * PHPUnit 5, so (hopefully) most environments are compatible with the newer naming.
 *
 * Going forward, `civix` will generate templates using the newer naming.
 *
 * To be consistent and forward-compatible, you should consider updating your
 * existing unit-tests to use the name base-classes.
 */
return function (\CRM\CivixBundle\Upgrader $upgrader) {
    /* @var \Symfony\Component\Console\Style\SymfonyStyle $io */
    $io = $upgrader->io;
    $testFiles = \CRM\CivixBundle\Utils\Files::findFiles($upgrader->baseDir->string('tests'), '*.php');
    $upgrader->updateTextFiles($testFiles, function (string $file, string $content) use($io, $upgrader) {
        $old = 'PHPUnit_Framework_TestCase';
        $new = 'CivixPhar\\PHPUnit\\Framework\\TestCase';
        $relFile = \CRM\CivixBundle\Utils\Files::relativize($file, $upgrader->baseDir->string() . '/');
        if (\strpos($content, $old) === \FALSE) {
            return $content;
        }
        $io->writeln("<info>PHPUnit 6.x+ changed the name of the standard base-class (</info>{$old}<info> => </info>{$new}<info>).</info>");
        $io->writeln("<info>The file </info>{$relFile}<info> contains at least one reference to the old name.</info>");
        $io->writeln("<info>The upgrader can do an automatic search-replace on this file.</info>");
        if ($io->confirm("Perform search/replace?")) {
            $content = \str_replace($old, $new, $content);
        }
        return $content;
    });
};
<?php

namespace CivixPhar;

use CRM\CivixBundle\Utils\Files;
use CRM\CivixBundle\Utils\Formatting;
use CRM\CivixBundle\Utils\Naming;
/**
 * v5.38 supports an <upgrader> tag and a common base class. Updates:
 * - Remove hook delegations from module.php.
 * - Add <upgrader> to info.xml
 * - Use core's base class
 * - Remove old base class
 */
return function (\CRM\CivixBundle\Upgrader $upgrader) {
    $io = $upgrader->io;
    $io->section('Lifecycle Hooks: Install, Upgrade, etc');
    $info = $upgrader->infoXml;
    $MIN_COMPAT = '5.38';
    $oldCompat = $info->getCompatibilityVer();
    $nameSpace = $info->getNamespace();
    $mainFile = $upgrader->baseDir->string($info->getFile() . '.php');
    $upgraderClass = Naming::createClassName($nameSpace, 'Upgrader');
    $upgraderFile = Naming::createClassFile($nameSpace, 'Upgrader');
    $upgraderBaseClass = Naming::createClassName($nameSpace, 'Upgrader', 'Base');
    $upgraderBaseFile = Naming::createClassFile($nameSpace, 'Upgrader', 'Base');
    $hasUpgrader = \file_exists($upgraderFile);
    $previewChanges = [];
    if ($hasUpgrader) {
        $previewChanges[] = ['info.xml', 'Fill-in <upgrader> tag'];
        $previewChanges[] = [$upgraderClass, 'Use new base-class'];
        $previewChanges[] = [$upgraderBaseClass, 'Remove old base-class'];
    }
    $previewChanges[] = ['*_civix_civicrm_install()', 'Simplify boilerplate'];
    $previewChanges[] = ['*_civix_civicrm_postInstall()', 'Remove boilerplate'];
    $previewChanges[] = ['*_civix_civicrm_enable()', 'Simplify boilerplate'];
    $previewChanges[] = ['*_civix_civicrm_upgrade()', 'Remove boilerplate'];
    $previewChanges[] = ['*_civix_civicrm_disable()', 'Remove boilerplate'];
    $previewChanges[] = ['*_civix_civicrm_uninstall()', 'Remove boilerplate'];
    $io->note(['Civix v22.12 simplifies the boilerplate code used for install/upgrade/uninstall (etc).', 'The following may be affected:', Formatting::ol("%-31s %s\n", $previewChanges)]);
    if ($hasUpgrader && \version_compare($oldCompat, $MIN_COMPAT, '<')) {
        $io->warning("This relies on functionality added by CiviCRM v5.38 (June 2021). The minimum requirements will increase automatically.");
    }
    // The `hook_install`, `hook_uninstall`, etc will no longer fire `_mymodule_civix_civicrm_config()`.
    // For class-loading, this should be OK - since we now have PSR-0 enabled. But Smarty could
    // potentially break. Except... in practice... I could only find 2 ext's in universe that might
    // be impacted. So won't try hard to change them -- we'll merely warn.
    if (!empty(\glob('sql/*.tpl')) || Files::grepFiles(';smarty;i', [$upgraderFile]) || Files::grepFiles(';\\.tpl;i', [$upgraderFile]) || Files::grepFiles(';execute.*Template;i', [$upgraderFile]) || Files::grepFiles(';civicrm_install.*smarty;si', [$mainFile]) || Files::grepFiles(';civicrm_upgrade.*smarty;si', [$mainFile]) || Files::grepFiles(';civicrm_install.*\\.tpl;si', [$mainFile]) || Files::grepFiles(';civicrm_upgrade.*\\.tpl;si', [$mainFile])) {
        $io->warning('If you use the uncommon practice of calling Smarty during installation/upgrade, then you should review/retest these steps. Determine whether the Smarty include-path is sufficiently up-to-date.');
    }
    if (!$io->confirm('Continue with upgrade?')) {
        throw new \RuntimeException('User stopped upgrade');
    }
    $prefix = $info->getFile();
    $upgrader->removeHookDelegation(["_{$prefix}_civix_civicrm_postInstall", "_{$prefix}_civix_civicrm_uninstall", "_{$prefix}_civix_civicrm_disable", "_{$prefix}_civix_civicrm_upgrade"]);
    if ($hasUpgrader) {
        $upgrader->updateInfo(function (\CRM\CivixBundle\Builder\Info $info) use($MIN_COMPAT, $upgraderClass) {
            $info->raiseCompatibilityMinimum($MIN_COMPAT);
            // Add <upgrader> tag
            if (!$info->get()->xpath('upgrader')) {
                $info->get()->addChild('upgrader', $upgraderClass);
            }
        });
        // Switch base class
        $upgrader->updateTextFiles([$upgraderFile], function (string $file, string $content) use($upgraderBaseClass) {
            return \str_replace($upgraderBaseClass, 'CRM_Extension_Upgrader_Base', $content);
        });
    }
    if (\file_exists($upgraderBaseFile)) {
        \unlink($upgraderBaseFile);
    }
};
<?php

namespace CivixPhar;

use CRM\CivixBundle\Builder\Mixins;
use CRM\CivixBundle\Utils\EvilEx;
return function (\CRM\CivixBundle\Upgrader $upgrader) {
    $mixins = new Mixins($upgrader->infoXml, $upgrader->baseDir->string('mixin'));
    $declared = $mixins->getDeclaredMixinConstraints();
    $hasSettingMixin = (bool) \preg_grep('/^setting-php@/', $declared);
    $action = NULL;
    $upgrader->updateModulePhp(function (\CRM\CivixBundle\Builder\Info $info, string $content) use($upgrader, $hasSettingMixin, &$action) {
        $prefix = $upgrader->infoXml->getFile();
        $hookFunc = "{$prefix}_civicrm_alterSettingsFolders";
        $hookBody = ['static $configured = FALSE;', 'if ($configured) return;', '$configured = TRUE;', '$extRoot = dirname( __FILE__ ) . DIRECTORY_SEPARATOR;', '$extDir = $extRoot . \'settings\';', 'if(!in_array($extDir, $metaDataFolders)){', '  $metaDataFolders[] = $extDir;', '}'];
        $newContent = EvilEx::rewriteMultilineChunk($content, $hookBody, function (array $matchLines) use($hookFunc, $content, $upgrader, $hasSettingMixin, &$action) {
            /* @var \Symfony\Component\Console\Style\SymfonyStyle $io */
            $io = $upgrader->io;
            $matchLineKeys = \array_keys($matchLines);
            $allLines = \explode("\n", $content);
            $focusStart = \min($matchLineKeys);
            $focusEnd = \max($matchLineKeys);
            $io->note("The following chunk resembles an older template for \"{$hookFunc}()\".");
            $upgrader->showCode($allLines, $focusStart - 4, $focusEnd + 4, $focusStart, $focusEnd);
            if ($hasSettingMixin) {
                $io->note(["Similar functionality is now provided by the \"setting-php\" mixin, which is already enabled."]);
            } else {
                $io->note(["Similar functionality is now available in the \"setting-php\" mixin, which is currently disabled."]);
            }
            $actions = ['m' => 'Use the mixin ("setting-php") and remove this boilerplate.', 'b' => 'Use the boilerplate and disable the mixin ("setting-php").', 'n' => 'Do nothing. Keep as-is. (You may manually change it later.)'];
            $action = $io->choice("What should we do?", $actions, 'm');
            return $action == 'm' ? [] : $matchLines;
        });
        if ($action === 'm' && !$hasSettingMixin) {
            $upgrader->updateMixins(function (Mixins $mixins) {
                $mixins->addMixin('setting-php@1.0.0');
            });
        } elseif ($action === 'b' && $hasSettingMixin) {
            $upgrader->updateMixins(function (Mixins $mixins) {
                $mixins->removeMixin('setting-php');
            });
        }
        return $newContent;
    });
};
<?php

namespace CivixPhar;

/**
 * Circa v19.11.0, it became a default to add the psr4 rule for "Civi" folders.
 * However, as older extensions adopt newer technologies (like `Civi\Api4`), it helps
 * to add a similar to them.
 */
return function (\CRM\CivixBundle\Upgrader $upgrader) {
    $upgrader->updateInfo(function (\CRM\CivixBundle\Builder\Info $info) use($upgrader) {
        /* @var \Symfony\Component\Console\Style\SymfonyStyle $io */
        $io = $upgrader->io;
        $loaders = $info->getClassloaders();
        $prefixes = \array_column($loaders, 'prefix');
        if (!\in_array('Civi\\', $prefixes)) {
            $io->section('"Civi" Class-loader');
            $io->note(['Technologies like APIv4 may require you to use the "Civi" namespace, which is not enabled on this extension.', 'You can automatically add the "Civi" namespace now to get prepared, or you can skip this.', '(If you change your mind later, then simply edit "info.xml" to add or remove "<classloader>" rules.)']);
            if ($io->confirm('Add the "Civi" namespace?')) {
                $loaders[] = ['type' => 'psr4', 'prefix' => 'Civi\\', 'path' => 'Civi'];
                $info->setClassLoaders($loaders);
            }
        }
    });
};
<?php

namespace CivixPhar;

return function (\CRM\CivixBundle\Upgrader $upgrader) {
    /* @var \Symfony\Component\Console\Style\SymfonyStyle $io */
    $io = $upgrader->io;
    $prefix = $upgrader->infoXml->getFile();
    $io->note(["Civix v22.05 converts several functions to mixins. This reduces code-duplication and will enable easier updates in the future.", "The upgrader will examine your extension, remove old functions, and enable mixins (if needed).", "The following functions+mixins may be affected:\n\n" . \implode("\n", ["1. _*_civix_civicrm_angularModules()        =>  ang-php@1.0.0", "2. _*_civix_civicrm_managed()               =>  mgd-php@1.0.0", "3. _*_civix_civicrm_alterSettingsFolders()  =>  setting-php@1.0.0", "4. _*_civix_civicrm_caseTypes()             =>  case-xml@1.0.0", "5. _*_civix_civicrm_xmlMenu()               =>  menu-xml@1.0.0", "6. _*_civix_civicrm_themes()                =>  theme-php@1.0.0"])]);
    if (!$io->confirm('Continue with upgrade?')) {
        throw new \RuntimeException('User stopped upgrade');
    }
    // Do we need a mixin like `ang-php`? Maybe... check whether we have files like `*.ang.php`.
    $filePatterns = ['glob:ang/*.ang.php' => 'ang-php@1.0.0', 'find:*.mgd.php' => 'mgd-php@1.0.0', 'glob:settings/*.setting.php' => 'setting-php@1.0.0', 'glob:xml/case/*.xml' => 'case-xml@1.0.0', 'glob:xml/Menu/*.xml' => 'menu-xml@1.0.0', 'glob:*.theme.php' => 'theme-php@1.0.0'];
    $mixins = \array_filter($filePatterns, function (string $mixin, string $pattern) use($upgrader, $io) {
        $flagFiles = $upgrader->baseDir->search($pattern);
        $io->note($flagFiles ? "Enable \"{$mixin}\". There are files matching pattern \"{$pattern}\"." : "Skip \"{$mixin}\". There are no files matching pattern \"{$pattern}\".");
        return (bool) $flagFiles;
    }, \ARRAY_FILTER_USE_BOTH);
    $upgrader->addMixins($mixins);
    $upgrader->removeHookDelegation(["_{$prefix}_civix_civicrm_angularModules", "_{$prefix}_civix_civicrm_managed", "_{$prefix}_civix_civicrm_alterSettingsFolders", "_{$prefix}_civix_civicrm_caseTypes", "_{$prefix}_civix_civicrm_xmlMenu", "_{$prefix}_civix_civicrm_themes"]);
};
<?php

namespace CivixPhar;

use CRM\CivixBundle\Utils\Formatting;
return function (\CRM\CivixBundle\Upgrader $upgrader) {
    /* @var \Symfony\Component\Console\Style\SymfonyStyle $io */
    $io = $upgrader->io;
    $previewChanges = [];
    $previewChanges[] = ['*_civix_civicrm_config', 'Remove Smarty boilerplate'];
    // Do we need a mixin like `ang-php`? Maybe... check whether we have files like `*.ang.php`.
    $filePatterns = ['find:*.tpl' => 'smarty-v2@1.0.0'];
    $mixins = \array_filter($filePatterns, function (string $mixin, string $pattern) use($upgrader, $io, &$previewChanges) {
        $flagFiles = $upgrader->baseDir->search($pattern);
        $previewChanges[] = ['info.xml', $flagFiles ? "Enable {$mixin}" : "Skip {$mixin}. (No files match \"{$pattern}\")"];
        return (bool) $flagFiles;
    }, \ARRAY_FILTER_USE_BOTH);
    $io->note(["Civix v23.01 simplifies the boilerplate used for Smarty registration.", "The following may be affected:", Formatting::ol("%-31s %s\n", $previewChanges)]);
    if (!empty($mixins)) {
        $io->warning(["If Smarty templates are used by any lifecycle hooks (install,enable,disable,uninstall,upgrade,managed), then please re-test them."]);
    }
    if (!$io->confirm('Continue with upgrade?')) {
        throw new \RuntimeException('User stopped upgrade');
    }
    $upgrader->addMixins($mixins);
};
<?php

namespace CivixPhar;

/**
 * If you have a generated `phpunit.xml` or `phpunit.xml.dist` file, it may include the old option `syntaxCheck="false"`.
 * You can remove this.  The option has been inert and will raise errors in newer versions of PHPUnit.
 */
return function (\CRM\CivixBundle\Upgrader $upgrader) {
    /* @var \Symfony\Component\Console\Style\SymfonyStyle $io */
    $io = $upgrader->io;
    $files = \array_filter([$upgrader->baseDir->string('phpunit.xml'), $upgrader->baseDir->string('phpunit.xml.dist')], 'file_exists');
    $upgrader->updateTextFiles($files, function (string $file, string $oldContent) use($io, $upgrader) {
        $relFile = \CRM\CivixBundle\Utils\Files::relativize($file, $upgrader->baseDir->string() . '/');
        $content = $oldContent;
        $content = \preg_replace(';(\\s+)syntaxCheck="[^\\"]+">;', '>', $content);
        $content = \preg_replace(';(\\s+)syntaxCheck=\'[^\']+\'>;', '>', $content);
        $content = \preg_replace(';(\\s+)syntaxCheck="[^\\"]+"(\\s+);', '\\1', $content);
        $content = \preg_replace(';(\\s+)syntaxCheck=\'[^\']+\'(\\s+);', '\\1', $content);
        if ($content !== $oldContent) {
            $io->writeln("{$relFile}<info> includes obsolete option </info>syntaxCheck=\"...\"<info>. Removing it.</info> ");
        }
        return $content;
    });
};
<?php

namespace CivixPhar;

/**
 * As long as `CRM_*_Upgrader` classes are wired-up via lifecycle hooks (`hook_install`, etc), we
 * should include `hook_postInstall`.
 *
 * At some point in the future, this step could be removed if we configure `info.xml`'s `<upgrader>` option.
 */
return function (\CRM\CivixBundle\Upgrader $upgrader) {
    $io = $upgrader->io;
    if (!empty($upgrader->infoXml->get()->upgrader)) {
        $io->note("Found <upgrader> tag. Skip hook_postInstall.");
        return;
    }
    // Give a notice if the new `CRM/*/Upgrader/Base` has a substantive change.
    // Note: The change is actually done in the generic regen. This is just a notice.
    $phpBaseClass = \CRM\CivixBundle\Utils\Naming::createClassName($upgrader->infoXml->getNamespace(), 'Upgrader', 'Base');
    $phpBaseFile = \CRM\CivixBundle\Utils\Naming::createClassFile($upgrader->infoXml->getNamespace(), 'Upgrader', 'Base');
    if (\file_exists($phpBaseFile)) {
        $content = \file_get_contents($phpBaseFile);
        if (\preg_match('|CRM_Core_BAO_Setting::setItem\\(.revision, *.Extension.|', $content)) {
            $io->note(["{$phpBaseClass} is based on a very old template.", "When {$phpBaseClass} is regenerated, it will transition an important data element from \"civicrm_setting\" to \"civicrm_extension\".", "Several extensions have made this transition, and there are no known issues.", "See also: https://issues.civicrm.org/jira/browse/CRM-19252"]);
            if (!$io->confirm('Continue with upgrade?')) {
                throw new \RuntimeException('User stopped upgrade');
            }
        }
        $upgrader->addHookDelegation('civicrm_postInstall', '', "This hook is important for supporting the new version of {$phpBaseClass}.");
    } else {
        $upgrader->addHookDelegation('civicrm_postInstall', '', 'If you use civix to facilitate database upgrades ("civix generate:upgrader"), then you should enable this stub. Otherwise, it is not needed.');
    }
};
<?php

namespace CivixPhar;

/**
 * Upgrade hook_civicrm_entityTypes to use mixin
 */
return function (\CRM\CivixBundle\Upgrader $upgrader) {
    $prefix = $upgrader->infoXml->getFile();
    if (\is_dir($upgrader->baseDir->string('xml/schema/CRM'))) {
        $upgrader->io->note(['Civix 23.02 removes `*_civix_civicrm_entityTypes` in favor of a mixin `entity-types-php@1.0`.', 'This reduces code-duplication and will enable easier updates in the future.', 'This may raise the minimum requirements to CiviCRM v5.45.']);
        if (!$upgrader->io->confirm('Continue with upgrade?')) {
            throw new \RuntimeException('User stopped upgrade');
        }
        $upgrader->addMixins(['entity-types-php@1.0']);
    }
    $upgrader->removeHookDelegation(["_{$prefix}_civix_civicrm_entityTypes"]);
};
<?php

// autoload_static.php @generated by Composer

namespace Composer\Autoload;

class ComposerStaticInitHumbugBox436
{
    public static $prefixLengthsPsr4 = array (
        'H' => 
        array (
            'HumbugBox436\\KevinGH\\RequirementChecker\\' => 40,
            'HumbugBox436\\Composer\\Semver\\' => 29,
        ),
    );

    public static $prefixDirsPsr4 = array (
        'HumbugBox436\\KevinGH\\RequirementChecker\\' => 
        array (
            0 => __DIR__ . '/../..' . '/src',
        ),
        'HumbugBox436\\Composer\\Semver\\' => 
        array (
            0 => __DIR__ . '/..' . '/composer/semver/src',
        ),
    );

    public static $classMap = array (
        'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
        'HumbugBox436\\Composer\\Semver\\Comparator' => __DIR__ . '/..' . '/composer/semver/src/Comparator.php',
        'HumbugBox436\\Composer\\Semver\\CompilingMatcher' => __DIR__ . '/..' . '/composer/semver/src/CompilingMatcher.php',
        'HumbugBox436\\Composer\\Semver\\Constraint\\Bound' => __DIR__ . '/..' . '/composer/semver/src/Constraint/Bound.php',
        'HumbugBox436\\Composer\\Semver\\Constraint\\Constraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/Constraint.php',
        'HumbugBox436\\Composer\\Semver\\Constraint\\ConstraintInterface' => __DIR__ . '/..' . '/composer/semver/src/Constraint/ConstraintInterface.php',
        'HumbugBox436\\Composer\\Semver\\Constraint\\MatchAllConstraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/MatchAllConstraint.php',
        'HumbugBox436\\Composer\\Semver\\Constraint\\MatchNoneConstraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/MatchNoneConstraint.php',
        'HumbugBox436\\Composer\\Semver\\Constraint\\MultiConstraint' => __DIR__ . '/..' . '/composer/semver/src/Constraint/MultiConstraint.php',
        'HumbugBox436\\Composer\\Semver\\Interval' => __DIR__ . '/..' . '/composer/semver/src/Interval.php',
        'HumbugBox436\\Composer\\Semver\\Intervals' => __DIR__ . '/..' . '/composer/semver/src/Intervals.php',
        'HumbugBox436\\Composer\\Semver\\Semver' => __DIR__ . '/..' . '/composer/semver/src/Semver.php',
        'HumbugBox436\\Composer\\Semver\\VersionParser' => __DIR__ . '/..' . '/composer/semver/src/VersionParser.php',
        'HumbugBox436\\KevinGH\\RequirementChecker\\Checker' => __DIR__ . '/../..' . '/src/Checker.php',
        'HumbugBox436\\KevinGH\\RequirementChecker\\IO' => __DIR__ . '/../..' . '/src/IO.php',
        'HumbugBox436\\KevinGH\\RequirementChecker\\IsExtensionConflictFulfilled' => __DIR__ . '/../..' . '/src/IsExtensionConflictFulfilled.php',
        'HumbugBox436\\KevinGH\\RequirementChecker\\IsExtensionFulfilled' => __DIR__ . '/../..' . '/src/IsExtensionFulfilled.php',
        'HumbugBox436\\KevinGH\\RequirementChecker\\IsFulfilled' => __DIR__ . '/../..' . '/src/IsFulfilled.php',
        'HumbugBox436\\KevinGH\\RequirementChecker\\IsPhpVersionFulfilled' => __DIR__ . '/../..' . '/src/IsPhpVersionFulfilled.php',
        'HumbugBox436\\KevinGH\\RequirementChecker\\Printer' => __DIR__ . '/../..' . '/src/Printer.php',
        'HumbugBox436\\KevinGH\\RequirementChecker\\Requirement' => __DIR__ . '/../..' . '/src/Requirement.php',
        'HumbugBox436\\KevinGH\\RequirementChecker\\RequirementCollection' => __DIR__ . '/../..' . '/src/RequirementCollection.php',
        'HumbugBox436\\KevinGH\\RequirementChecker\\Terminal' => __DIR__ . '/../..' . '/src/Terminal.php',
    );

    public static function getInitializer(ClassLoader $loader)
    {
        return \Closure::bind(function () use ($loader) {
            $loader->prefixLengthsPsr4 = ComposerStaticInitHumbugBox436::$prefixLengthsPsr4;
            $loader->prefixDirsPsr4 = ComposerStaticInitHumbugBox436::$prefixDirsPsr4;
            $loader->classMap = ComposerStaticInitHumbugBox436::$classMap;

        }, null, ClassLoader::class);
    }
}
<?php

// autoload_real.php @generated by Composer

class ComposerAutoloaderInitHumbugBox436
{
    private static $loader;

    public static function loadClassLoader($class)
    {
        if ('Composer\Autoload\ClassLoader' === $class) {
            require __DIR__ . '/ClassLoader.php';
        }
    }

    /**
     * @return \Composer\Autoload\ClassLoader
     */
    public static function getLoader()
    {
        if (null !== self::$loader) {
            return self::$loader;
        }

        spl_autoload_register(array('ComposerAutoloaderInitHumbugBox436', 'loadClassLoader'), true, true);
        self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
        spl_autoload_unregister(array('ComposerAutoloaderInitHumbugBox436', 'loadClassLoader'));

        require __DIR__ . '/autoload_static.php';
        call_user_func(\Composer\Autoload\ComposerStaticInitHumbugBox436::getInitializer($loader));

        $loader->setClassMapAuthoritative(true);
        $loader->register(true);

        return $loader;
    }
}
<?php

namespace HumbugBox436;

return array('root' => array('name' => 'humbug/requirement-checker', 'pretty_version' => 'dev-main', 'version' => 'dev-main', 'reference' => '85545a4ada048b26040bc54ee81e2b87e84a3ebc', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev' => \true), 'versions' => array('composer/semver' => array('pretty_version' => '3.3.2', 'version' => '3.3.2.0', 'reference' => '3953f23262f2bff1919fc82183ad9acb13ff62c9', 'type' => 'library', 'install_path' => __DIR__ . '/./semver', 'aliases' => array(), 'dev_requirement' => \false), 'doctrine/instantiator' => array('pretty_version' => '1.4.1', 'version' => '1.4.1.0', 'reference' => '10dcfce151b967d20fde1b34ae6640712c3891bc', 'type' => 'library', 'install_path' => __DIR__ . '/../doctrine/instantiator', 'aliases' => array(), 'dev_requirement' => \true), 'ergebnis/composer-normalize' => array('pretty_version' => '2.29.0', 'version' => '2.29.0.0', 'reference' => 'fad0e99b16c625817a5bfd910e4d7e31999c53b2', 'type' => 'composer-plugin', 'install_path' => __DIR__ . '/../ergebnis/composer-normalize', 'aliases' => array(), 'dev_requirement' => \true), 'ergebnis/json-normalizer' => array('pretty_version' => '2.1.0', 'version' => '2.1.0.0', 'reference' => '2039eb11131a243b9204bf51219baa08935e6b1d', 'type' => 'library', 'install_path' => __DIR__ . '/../ergebnis/json-normalizer', 'aliases' => array(), 'dev_requirement' => \true), 'ergebnis/json-printer' => array('pretty_version' => '3.3.0', 'version' => '3.3.0.0', 'reference' => '18920367473b099633f644f0ca6dc8794345148f', 'type' => 'library', 'install_path' => __DIR__ . '/../ergebnis/json-printer', 'aliases' => array(), 'dev_requirement' => \true), 'ergebnis/json-schema-validator' => array('pretty_version' => '2.0.0', 'version' => '2.0.0.0', 'reference' => 'dacd8a47c1cc2c426ec71e952da3609ebe901fac', 'type' => 'library', 'install_path' => __DIR__ . '/../ergebnis/json-schema-validator', 'aliases' => array(), 'dev_requirement' => \true), 'fidry/makefile' => array('pretty_version' => '0.2.1', 'version' => '0.2.1.0', 'reference' => '50abe0df37018458b1ab355e56063618d5ba8d10', 'type' => 'library', 'install_path' => __DIR__ . '/../fidry/makefile', 'aliases' => array(), 'dev_requirement' => \true), 'humbug/requirement-checker' => array('pretty_version' => 'dev-main', 'version' => 'dev-main', 'reference' => '85545a4ada048b26040bc54ee81e2b87e84a3ebc', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev_requirement' => \false), 'justinrainbow/json-schema' => array('pretty_version' => '5.2.12', 'version' => '5.2.12.0', 'reference' => 'ad87d5a5ca981228e0e205c2bc7dfb8e24559b60', 'type' => 'library', 'install_path' => __DIR__ . '/../justinrainbow/json-schema', 'aliases' => array(), 'dev_requirement' => \true), 'localheinz/diff' => array('pretty_version' => '1.1.1', 'version' => '1.1.1.0', 'reference' => '851bb20ea8358c86f677f5f111c4ab031b1c764c', 'type' => 'library', 'install_path' => __DIR__ . '/../localheinz/diff', 'aliases' => array(), 'dev_requirement' => \true), 'myclabs/deep-copy' => array('pretty_version' => '1.11.0', 'version' => '1.11.0.0', 'reference' => '14daed4296fae74d9e3201d2c4925d1acb7aa614', 'type' => 'library', 'install_path' => __DIR__ . '/../myclabs/deep-copy', 'aliases' => array(), 'dev_requirement' => \true), 'nikic/php-parser' => array('pretty_version' => 'v4.14.0', 'version' => '4.14.0.0', 'reference' => '34bea19b6e03d8153165d8f30bba4c3be86184c1', 'type' => 'library', 'install_path' => __DIR__ . '/../nikic/php-parser', 'aliases' => array(), 'dev_requirement' => \true), 'phar-io/manifest' => array('pretty_version' => '2.0.3', 'version' => '2.0.3.0', 'reference' => '97803eca37d319dfa7826cc2437fc020857acb53', 'type' => 'library', 'install_path' => __DIR__ . '/../phar-io/manifest', 'aliases' => array(), 'dev_requirement' => \true), 'phar-io/version' => array('pretty_version' => '3.2.1', 'version' => '3.2.1.0', 'reference' => '4f7fd7836c6f332bb2933569e566a0d6c4cbed74', 'type' => 'library', 'install_path' => __DIR__ . '/../phar-io/version', 'aliases' => array(), 'dev_requirement' => \true), 'phpdocumentor/reflection-common' => array('pretty_version' => '2.2.0', 'version' => '2.2.0.0', 'reference' => '1d01c49d4ed62f25aa84a747ad35d5a16924662b', 'type' => 'library', 'install_path' => __DIR__ . '/../phpdocumentor/reflection-common', 'aliases' => array(), 'dev_requirement' => \true), 'phpdocumentor/reflection-docblock' => array('pretty_version' => '5.3.0', 'version' => '5.3.0.0', 'reference' => '622548b623e81ca6d78b721c5e029f4ce664f170', 'type' => 'library', 'install_path' => __DIR__ . '/../phpdocumentor/reflection-docblock', 'aliases' => array(), 'dev_requirement' => \true), 'phpdocumentor/type-resolver' => array('pretty_version' => '1.6.1', 'version' => '1.6.1.0', 'reference' => '77a32518733312af16a44300404e945338981de3', 'type' => 'library', 'install_path' => __DIR__ . '/../phpdocumentor/type-resolver', 'aliases' => array(), 'dev_requirement' => \true), 'phpspec/prophecy' => array('pretty_version' => 'v1.15.0', 'version' => '1.15.0.0', 'reference' => 'bbcd7380b0ebf3961ee21409db7b38bc31d69a13', 'type' => 'library', 'install_path' => __DIR__ . '/../phpspec/prophecy', 'aliases' => array(), 'dev_requirement' => \true), 'phpunit/php-code-coverage' => array('pretty_version' => '9.2.15', 'version' => '9.2.15.0', 'reference' => '2e9da11878c4202f97915c1cb4bb1ca318a63f5f', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/php-code-coverage', 'aliases' => array(), 'dev_requirement' => \true), 'phpunit/php-file-iterator' => array('pretty_version' => '3.0.6', 'version' => '3.0.6.0', 'reference' => 'cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/php-file-iterator', 'aliases' => array(), 'dev_requirement' => \true), 'phpunit/php-invoker' => array('pretty_version' => '3.1.1', 'version' => '3.1.1.0', 'reference' => '5a10147d0aaf65b58940a0b72f71c9ac0423cc67', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/php-invoker', 'aliases' => array(), 'dev_requirement' => \true), 'phpunit/php-text-template' => array('pretty_version' => '2.0.4', 'version' => '2.0.4.0', 'reference' => '5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/php-text-template', 'aliases' => array(), 'dev_requirement' => \true), 'phpunit/php-timer' => array('pretty_version' => '5.0.3', 'version' => '5.0.3.0', 'reference' => '5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/php-timer', 'aliases' => array(), 'dev_requirement' => \true), 'phpunit/phpunit' => array('pretty_version' => '9.5.21', 'version' => '9.5.21.0', 'reference' => '0e32b76be457de00e83213528f6bb37e2a38fcb1', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/phpunit', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/cli-parser' => array('pretty_version' => '1.0.1', 'version' => '1.0.1.0', 'reference' => '442e7c7e687e42adc03470c7b668bc4b2402c0b2', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/cli-parser', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/code-unit' => array('pretty_version' => '1.0.8', 'version' => '1.0.8.0', 'reference' => '1fc9f64c0927627ef78ba436c9b17d967e68e120', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/code-unit', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/code-unit-reverse-lookup' => array('pretty_version' => '2.0.3', 'version' => '2.0.3.0', 'reference' => 'ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/code-unit-reverse-lookup', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/comparator' => array('pretty_version' => '4.0.6', 'version' => '4.0.6.0', 'reference' => '55f4261989e546dc112258c7a75935a81a7ce382', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/comparator', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/complexity' => array('pretty_version' => '2.0.2', 'version' => '2.0.2.0', 'reference' => '739b35e53379900cc9ac327b2147867b8b6efd88', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/complexity', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/diff' => array('pretty_version' => '4.0.4', 'version' => '4.0.4.0', 'reference' => '3461e3fccc7cfdfc2720be910d3bd73c69be590d', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/diff', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/environment' => array('pretty_version' => '5.1.4', 'version' => '5.1.4.0', 'reference' => '1b5dff7bb151a4db11d49d90e5408e4e938270f7', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/environment', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/exporter' => array('pretty_version' => '4.0.4', 'version' => '4.0.4.0', 'reference' => '65e8b7db476c5dd267e65eea9cab77584d3cfff9', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/exporter', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/global-state' => array('pretty_version' => '5.0.5', 'version' => '5.0.5.0', 'reference' => '0ca8db5a5fc9c8646244e629625ac486fa286bf2', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/global-state', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/lines-of-code' => array('pretty_version' => '1.0.3', 'version' => '1.0.3.0', 'reference' => 'c1c2e997aa3146983ed888ad08b15470a2e22ecc', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/lines-of-code', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/object-enumerator' => array('pretty_version' => '4.0.4', 'version' => '4.0.4.0', 'reference' => '5c9eeac41b290a3712d88851518825ad78f45c71', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/object-enumerator', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/object-reflector' => array('pretty_version' => '2.0.4', 'version' => '2.0.4.0', 'reference' => 'b4f479ebdbf63ac605d183ece17d8d7fe49c15c7', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/object-reflector', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/recursion-context' => array('pretty_version' => '4.0.4', 'version' => '4.0.4.0', 'reference' => 'cd9d8cf3c5804de4341c283ed787f099f5506172', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/recursion-context', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/resource-operations' => array('pretty_version' => '3.0.3', 'version' => '3.0.3.0', 'reference' => '0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/resource-operations', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/type' => array('pretty_version' => '3.0.0', 'version' => '3.0.0.0', 'reference' => 'b233b84bc4465aff7b57cf1c4bc75c86d00d6dad', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/type', 'aliases' => array(), 'dev_requirement' => \true), 'sebastian/version' => array('pretty_version' => '3.0.2', 'version' => '3.0.2.0', 'reference' => 'c6c1022351a901512170118436c764e473f6de8c', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/version', 'aliases' => array(), 'dev_requirement' => \true), 'symfony/polyfill-ctype' => array('pretty_version' => 'v1.27.0', 'version' => '1.27.0.0', 'reference' => '5bbc823adecdae860bb64756d639ecfec17b050a', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-ctype', 'aliases' => array(), 'dev_requirement' => \true), 'symfony/polyfill-php80' => array('pretty_version' => 'v1.27.0', 'version' => '1.27.0.0', 'reference' => '7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-php80', 'aliases' => array(), 'dev_requirement' => \true), 'symfony/polyfill-php81' => array('pretty_version' => 'v1.27.0', 'version' => '1.27.0.0', 'reference' => '707403074c8ea6e2edaf8794b0157a0bfa52157a', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-php81', 'aliases' => array(), 'dev_requirement' => \true), 'symfony/yaml' => array('pretty_version' => 'v6.2.5', 'version' => '6.2.5.0', 'reference' => '2bbfbdacc8a15574f8440c4838ce0d7bb6c86b19', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/yaml', 'aliases' => array(), 'dev_requirement' => \true), 'thecodingmachine/safe' => array('pretty_version' => 'v2.4.0', 'version' => '2.4.0.0', 'reference' => 'e788f3d09dcd36f806350aedb77eac348fafadd3', 'type' => 'library', 'install_path' => __DIR__ . '/../thecodingmachine/safe', 'aliases' => array(), 'dev_requirement' => \true), 'theseer/tokenizer' => array('pretty_version' => '1.2.1', 'version' => '1.2.1.0', 'reference' => '34a41e998c2183e22995f158c581e7b5e755ab9e', 'type' => 'library', 'install_path' => __DIR__ . '/../theseer/tokenizer', 'aliases' => array(), 'dev_requirement' => \true), 'webmozart/assert' => array('pretty_version' => '1.11.0', 'version' => '1.11.0.0', 'reference' => '11cb2199493b2f8a3b53e7f19068fc6aac760991', 'type' => 'library', 'install_path' => __DIR__ . '/../webmozart/assert', 'aliases' => array(), 'dev_requirement' => \true)));
<?php

// autoload_classmap.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
    'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
    'HumbugBox436\\Composer\\Semver\\Comparator' => $vendorDir . '/composer/semver/src/Comparator.php',
    'HumbugBox436\\Composer\\Semver\\CompilingMatcher' => $vendorDir . '/composer/semver/src/CompilingMatcher.php',
    'HumbugBox436\\Composer\\Semver\\Constraint\\Bound' => $vendorDir . '/composer/semver/src/Constraint/Bound.php',
    'HumbugBox436\\Composer\\Semver\\Constraint\\Constraint' => $vendorDir . '/composer/semver/src/Constraint/Constraint.php',
    'HumbugBox436\\Composer\\Semver\\Constraint\\ConstraintInterface' => $vendorDir . '/composer/semver/src/Constraint/ConstraintInterface.php',
    'HumbugBox436\\Composer\\Semver\\Constraint\\MatchAllConstraint' => $vendorDir . '/composer/semver/src/Constraint/MatchAllConstraint.php',
    'HumbugBox436\\Composer\\Semver\\Constraint\\MatchNoneConstraint' => $vendorDir . '/composer/semver/src/Constraint/MatchNoneConstraint.php',
    'HumbugBox436\\Composer\\Semver\\Constraint\\MultiConstraint' => $vendorDir . '/composer/semver/src/Constraint/MultiConstraint.php',
    'HumbugBox436\\Composer\\Semver\\Interval' => $vendorDir . '/composer/semver/src/Interval.php',
    'HumbugBox436\\Composer\\Semver\\Intervals' => $vendorDir . '/composer/semver/src/Intervals.php',
    'HumbugBox436\\Composer\\Semver\\Semver' => $vendorDir . '/composer/semver/src/Semver.php',
    'HumbugBox436\\Composer\\Semver\\VersionParser' => $vendorDir . '/composer/semver/src/VersionParser.php',
    'HumbugBox436\\KevinGH\\RequirementChecker\\Checker' => $baseDir . '/src/Checker.php',
    'HumbugBox436\\KevinGH\\RequirementChecker\\IO' => $baseDir . '/src/IO.php',
    'HumbugBox436\\KevinGH\\RequirementChecker\\IsExtensionConflictFulfilled' => $baseDir . '/src/IsExtensionConflictFulfilled.php',
    'HumbugBox436\\KevinGH\\RequirementChecker\\IsExtensionFulfilled' => $baseDir . '/src/IsExtensionFulfilled.php',
    'HumbugBox436\\KevinGH\\RequirementChecker\\IsFulfilled' => $baseDir . '/src/IsFulfilled.php',
    'HumbugBox436\\KevinGH\\RequirementChecker\\IsPhpVersionFulfilled' => $baseDir . '/src/IsPhpVersionFulfilled.php',
    'HumbugBox436\\KevinGH\\RequirementChecker\\Printer' => $baseDir . '/src/Printer.php',
    'HumbugBox436\\KevinGH\\RequirementChecker\\Requirement' => $baseDir . '/src/Requirement.php',
    'HumbugBox436\\KevinGH\\RequirementChecker\\RequirementCollection' => $baseDir . '/src/RequirementCollection.php',
    'HumbugBox436\\KevinGH\\RequirementChecker\\Terminal' => $baseDir . '/src/Terminal.php',
);
<?php

// autoload_psr4.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
    'HumbugBox436\\KevinGH\\RequirementChecker\\' => array($baseDir . '/src'),
    'HumbugBox436\\Composer\\Semver\\' => array($vendorDir . '/composer/semver/src'),
);
<?php

namespace HumbugBox436\Composer\Semver;

use HumbugBox436\Composer\Semver\Constraint\Constraint;
class Interval
{
    private $start;
    private $end;
    public function __construct(Constraint $start, Constraint $end)
    {
        $this->start = $start;
        $this->end = $end;
    }
    public function getStart()
    {
        return $this->start;
    }
    public function getEnd()
    {
        return $this->end;
    }
    public static function fromZero()
    {
        static $zero;
        if (null === $zero) {
            $zero = new Constraint('>=', '0.0.0.0-dev');
        }
        return $zero;
    }
    public static function untilPositiveInfinity()
    {
        static $positiveInfinity;
        if (null === $positiveInfinity) {
            $positiveInfinity = new Constraint('<', \PHP_INT_MAX . '.0.0.0');
        }
        return $positiveInfinity;
    }
    public static function any()
    {
        return new self(self::fromZero(), self::untilPositiveInfinity());
    }
    public static function anyDev()
    {
        return array('names' => array(), 'exclude' => \true);
    }
    public static function noDev()
    {
        return array('names' => array(), 'exclude' => \false);
    }
}
<?php

namespace HumbugBox436\Composer\Semver;

use HumbugBox436\Composer\Semver\Constraint\ConstraintInterface;
use HumbugBox436\Composer\Semver\Constraint\MatchAllConstraint;
use HumbugBox436\Composer\Semver\Constraint\MultiConstraint;
use HumbugBox436\Composer\Semver\Constraint\Constraint;
class VersionParser
{
    private static $modifierRegex = '[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)((?:[.-]?\\d+)*+)?)?([.-]?dev)?';
    private static $stabilitiesRegex = 'stable|RC|beta|alpha|dev';
    /**
    @phpstan-return
    */
    public static function parseStability($version)
    {
        $version = (string) \preg_replace('{#.+$}', '', (string) $version);
        if (\strpos($version, 'dev-') === 0 || '-dev' === \substr($version, -4)) {
            return 'dev';
        }
        \preg_match('{' . self::$modifierRegex . '(?:\\+.*)?$}i', \strtolower($version), $match);
        if (!empty($match[3])) {
            return 'dev';
        }
        if (!empty($match[1])) {
            if ('beta' === $match[1] || 'b' === $match[1]) {
                return 'beta';
            }
            if ('alpha' === $match[1] || 'a' === $match[1]) {
                return 'alpha';
            }
            if ('rc' === $match[1]) {
                return 'RC';
            }
        }
        return 'stable';
    }
    public static function normalizeStability($stability)
    {
        $stability = \strtolower((string) $stability);
        return $stability === 'rc' ? 'RC' : $stability;
    }
    public function normalize($version, $fullVersion = null)
    {
        $version = \trim((string) $version);
        $origVersion = $version;
        if (null === $fullVersion) {
            $fullVersion = $version;
        }
        if (\preg_match('{^([^,\\s]++) ++as ++([^,\\s]++)$}', $version, $match)) {
            $version = $match[1];
        }
        if (\preg_match('{@(?:' . self::$stabilitiesRegex . ')$}i', $version, $match)) {
            $version = \substr($version, 0, \strlen($version) - \strlen($match[0]));
        }
        if (\in_array($version, array('master', 'trunk', 'default'), \true)) {
            $version = 'dev-' . $version;
        }
        if (\stripos($version, 'dev-') === 0) {
            return 'dev-' . \substr($version, 4);
        }
        if (\preg_match('{^([^,\\s+]++)\\+[^\\s]++$}', $version, $match)) {
            $version = $match[1];
        }
        if (\preg_match('{^v?(\\d{1,5})(\\.\\d++)?(\\.\\d++)?(\\.\\d++)?' . self::$modifierRegex . '$}i', $version, $matches)) {
            $version = $matches[1] . (!empty($matches[2]) ? $matches[2] : '.0') . (!empty($matches[3]) ? $matches[3] : '.0') . (!empty($matches[4]) ? $matches[4] : '.0');
            $index = 5;
        } elseif (\preg_match('{^v?(\\d{4}(?:[.:-]?\\d{2}){1,6}(?:[.:-]?\\d{1,3})?)' . self::$modifierRegex . '$}i', $version, $matches)) {
            $version = \preg_replace('{\\D}', '.', $matches[1]);
            $index = 2;
        }
        if (isset($index)) {
            if (!empty($matches[$index])) {
                if ('stable' === $matches[$index]) {
                    return $version;
                }
                $version .= '-' . $this->expandStability($matches[$index]) . (isset($matches[$index + 1]) && '' !== $matches[$index + 1] ? \ltrim($matches[$index + 1], '.-') : '');
            }
            if (!empty($matches[$index + 2])) {
                $version .= '-dev';
            }
            return $version;
        }
        if (\preg_match('{(.*?)[.-]?dev$}i', $version, $match)) {
            try {
                $normalized = $this->normalizeBranch($match[1]);
                if (\strpos($normalized, 'dev-') === \false) {
                    return $normalized;
                }
            } catch (\Exception $e) {
            }
        }
        $extraMessage = '';
        if (\preg_match('{ +as +' . \preg_quote($version) . '(?:@(?:' . self::$stabilitiesRegex . '))?$}', $fullVersion)) {
            $extraMessage = ' in "' . $fullVersion . '", the alias must be an exact version';
        } elseif (\preg_match('{^' . \preg_quote($version) . '(?:@(?:' . self::$stabilitiesRegex . '))? +as +}', $fullVersion)) {
            $extraMessage = ' in "' . $fullVersion . '", the alias source must be an exact version, if it is a branch name you should prefix it with dev-';
        }
        throw new \UnexpectedValueException('Invalid version string "' . $origVersion . '"' . $extraMessage);
    }
    public function parseNumericAliasPrefix($branch)
    {
        if (\preg_match('{^(?P<version>(\\d++\\.)*\\d++)(?:\\.x)?-dev$}i', (string) $branch, $matches)) {
            return $matches['version'] . '.';
        }
        return \false;
    }
    public function normalizeBranch($name)
    {
        $name = \trim((string) $name);
        if (\preg_match('{^v?(\\d++)(\\.(?:\\d++|[xX*]))?(\\.(?:\\d++|[xX*]))?(\\.(?:\\d++|[xX*]))?$}i', $name, $matches)) {
            $version = '';
            for ($i = 1; $i < 5; ++$i) {
                $version .= isset($matches[$i]) ? \str_replace(array('*', 'X'), 'x', $matches[$i]) : '.x';
            }
            return \str_replace('x', '9999999', $version) . '-dev';
        }
        return 'dev-' . $name;
    }
    public function normalizeDefaultBranch($name)
    {
        if ($name === 'dev-master' || $name === 'dev-default' || $name === 'dev-trunk') {
            return '9999999-dev';
        }
        return (string) $name;
    }
    public function parseConstraints($constraints)
    {
        $prettyConstraint = (string) $constraints;
        $orConstraints = \preg_split('{\\s*\\|\\|?\\s*}', \trim((string) $constraints));
        if (\false === $orConstraints) {
            throw new \RuntimeException('Failed to preg_split string: ' . $constraints);
        }
        $orGroups = array();
        foreach ($orConstraints as $constraints) {
            $andConstraints = \preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $constraints);
            if (\false === $andConstraints) {
                throw new \RuntimeException('Failed to preg_split string: ' . $constraints);
            }
            if (\count($andConstraints) > 1) {
                $constraintObjects = array();
                foreach ($andConstraints as $constraint) {
                    foreach ($this->parseConstraint($constraint) as $parsedConstraint) {
                        $constraintObjects[] = $parsedConstraint;
                    }
                }
            } else {
                $constraintObjects = $this->parseConstraint($andConstraints[0]);
            }
            if (1 === \count($constraintObjects)) {
                $constraint = $constraintObjects[0];
            } else {
                $constraint = new MultiConstraint($constraintObjects);
            }
            $orGroups[] = $constraint;
        }
        $constraint = MultiConstraint::create($orGroups, \false);
        $constraint->setPrettyString($prettyConstraint);
        return $constraint;
    }
    /**
    @phpstan-return
    */
    private function parseConstraint($constraint)
    {
        if (\preg_match('{^([^,\\s]++) ++as ++([^,\\s]++)$}', $constraint, $match)) {
            $constraint = $match[1];
        }
        if (\preg_match('{^([^,\\s]*?)@(' . self::$stabilitiesRegex . ')$}i', $constraint, $match)) {
            $constraint = '' !== $match[1] ? $match[1] : '*';
            if ($match[2] !== 'stable') {
                $stabilityModifier = $match[2];
            }
        }
        if (\preg_match('{^(dev-[^,\\s@]+?|[^,\\s@]+?\\.x-dev)#.+$}i', $constraint, $match)) {
            $constraint = $match[1];
        }
        if (\preg_match('{^(v)?[xX*](\\.[xX*])*$}i', $constraint, $match)) {
            if (!empty($match[1]) || !empty($match[2])) {
                return array(new Constraint('>=', '0.0.0.0-dev'));
            }
            return array(new MatchAllConstraint());
        }
        $versionRegex = 'v?(\\d++)(?:\\.(\\d++))?(?:\\.(\\d++))?(?:\\.(\\d++))?(?:' . self::$modifierRegex . '|\\.([xX*][.-]?dev))(?:\\+[^\\s]+)?';
        if (\preg_match('{^~>?' . $versionRegex . '$}i', $constraint, $matches)) {
            if (\strpos($constraint, '~>') === 0) {
                throw new \UnexpectedValueException('Could not parse version constraint ' . $constraint . ': ' . 'Invalid operator "~>", you probably meant to use the "~" operator');
            }
            if (isset($matches[4]) && '' !== $matches[4] && null !== $matches[4]) {
                $position = 4;
            } elseif (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) {
                $position = 3;
            } elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) {
                $position = 2;
            } else {
                $position = 1;
            }
            if (!empty($matches[8])) {
                $position++;
            }
            $stabilitySuffix = '';
            if (empty($matches[5]) && empty($matches[7]) && empty($matches[8])) {
                $stabilitySuffix .= '-dev';
            }
            $lowVersion = $this->normalize(\substr($constraint . $stabilitySuffix, 1));
            $lowerBound = new Constraint('>=', $lowVersion);
            $highPosition = \max(1, $position - 1);
            $highVersion = $this->manipulateVersionString($matches, $highPosition, 1) . '-dev';
            $upperBound = new Constraint('<', $highVersion);
            return array($lowerBound, $upperBound);
        }
        if (\preg_match('{^\\^' . $versionRegex . '($)}i', $constraint, $matches)) {
            if ('0' !== $matches[1] || '' === $matches[2] || null === $matches[2]) {
                $position = 1;
            } elseif ('0' !== $matches[2] || '' === $matches[3] || null === $matches[3]) {
                $position = 2;
            } else {
                $position = 3;
            }
            $stabilitySuffix = '';
            if (empty($matches[5]) && empty($matches[7]) && empty($matches[8])) {
                $stabilitySuffix .= '-dev';
            }
            $lowVersion = $this->normalize(\substr($constraint . $stabilitySuffix, 1));
            $lowerBound = new Constraint('>=', $lowVersion);
            $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';
            $upperBound = new Constraint('<', $highVersion);
            return array($lowerBound, $upperBound);
        }
        if (\preg_match('{^v?(\\d++)(?:\\.(\\d++))?(?:\\.(\\d++))?(?:\\.[xX*])++$}', $constraint, $matches)) {
            if (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) {
                $position = 3;
            } elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) {
                $position = 2;
            } else {
                $position = 1;
            }
            $lowVersion = $this->manipulateVersionString($matches, $position) . '-dev';
            $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';
            if ($lowVersion === '0.0.0.0-dev') {
                return array(new Constraint('<', $highVersion));
            }
            return array(new Constraint('>=', $lowVersion), new Constraint('<', $highVersion));
        }
        if (\preg_match('{^(?P<from>' . $versionRegex . ') +- +(?P<to>' . $versionRegex . ')($)}i', $constraint, $matches)) {
            $lowStabilitySuffix = '';
            if (empty($matches[6]) && empty($matches[8]) && empty($matches[9])) {
                $lowStabilitySuffix = '-dev';
            }
            $lowVersion = $this->normalize($matches['from']);
            $lowerBound = new Constraint('>=', $lowVersion . $lowStabilitySuffix);
            $empty = function ($x) {
                return $x === 0 || $x === '0' ? \false : empty($x);
            };
            if (!$empty($matches[12]) && !$empty($matches[13]) || !empty($matches[15]) || !empty($matches[17]) || !empty($matches[18])) {
                $highVersion = $this->normalize($matches['to']);
                $upperBound = new Constraint('<=', $highVersion);
            } else {
                $highMatch = array('', $matches[11], $matches[12], $matches[13], $matches[14]);
                $this->normalize($matches['to']);
                $highVersion = $this->manipulateVersionString($highMatch, $empty($matches[12]) ? 1 : 2, 1) . '-dev';
                $upperBound = new Constraint('<', $highVersion);
            }
            return array($lowerBound, $upperBound);
        }
        if (\preg_match('{^(<>|!=|>=?|<=?|==?)?\\s*(.*)}', $constraint, $matches)) {
            try {
                try {
                    $version = $this->normalize($matches[2]);
                } catch (\UnexpectedValueException $e) {
                    if (\substr($matches[2], -4) === '-dev' && \preg_match('{^[0-9a-zA-Z-./]+$}', $matches[2])) {
                        $version = $this->normalize('dev-' . \substr($matches[2], 0, -4));
                    } else {
                        throw $e;
                    }
                }
                $op = $matches[1] ?: '=';
                if ($op !== '==' && $op !== '=' && !empty($stabilityModifier) && self::parseStability($version) === 'stable') {
                    $version .= '-' . $stabilityModifier;
                } elseif ('<' === $op || '>=' === $op) {
                    if (!\preg_match('/-' . self::$modifierRegex . '$/', \strtolower($matches[2]))) {
                        if (\strpos($matches[2], 'dev-') !== 0) {
                            $version .= '-dev';
                        }
                    }
                }
                return array(new Constraint($matches[1] ?: '=', $version));
            } catch (\Exception $e) {
            }
        }
        $message = 'Could not parse version constraint ' . $constraint;
        if (isset($e)) {
            $message .= ': ' . $e->getMessage();
        }
        throw new \UnexpectedValueException($message);
    }
    /**
    @phpstan-param
    */
    private function manipulateVersionString(array $matches, $position, $increment = 0, $pad = '0')
    {
        for ($i = 4; $i > 0; --$i) {
            if ($i > $position) {
                $matches[$i] = $pad;
            } elseif ($i === $position && $increment) {
                $matches[$i] += $increment;
                if ($matches[$i] < 0) {
                    $matches[$i] = $pad;
                    --$position;
                    if ($i === 1) {
                        return null;
                    }
                }
            }
        }
        return $matches[1] . '.' . $matches[2] . '.' . $matches[3] . '.' . $matches[4];
    }
    private function expandStability($stability)
    {
        $stability = \strtolower($stability);
        switch ($stability) {
            case 'a':
                return 'alpha';
            case 'b':
                return 'beta';
            case 'p':
            case 'pl':
                return 'patch';
            case 'rc':
                return 'RC';
            default:
                return $stability;
        }
    }
}
<?php

namespace HumbugBox436\Composer\Semver\Constraint;

class Bound
{
    private $version;
    private $isInclusive;
    public function __construct($version, $isInclusive)
    {
        $this->version = $version;
        $this->isInclusive = $isInclusive;
    }
    public function getVersion()
    {
        return $this->version;
    }
    public function isInclusive()
    {
        return $this->isInclusive;
    }
    public function isZero()
    {
        return $this->getVersion() === '0.0.0.0-dev' && $this->isInclusive();
    }
    public function isPositiveInfinity()
    {
        return $this->getVersion() === \PHP_INT_MAX . '.0.0.0' && !$this->isInclusive();
    }
    public function compareTo(Bound $other, $operator)
    {
        if (!\in_array($operator, array('<', '>'), \true)) {
            throw new \InvalidArgumentException('Does not support any other operator other than > or <.');
        }
        if ($this == $other) {
            return \false;
        }
        $compareResult = \version_compare($this->getVersion(), $other->getVersion());
        if (0 !== $compareResult) {
            return ('>' === $operator ? 1 : -1) === $compareResult;
        }
        return '>' === $operator ? $other->isInclusive() : !$other->isInclusive();
    }
    public function __toString()
    {
        return \sprintf('%s [%s]', $this->getVersion(), $this->isInclusive() ? 'inclusive' : 'exclusive');
    }
    public static function zero()
    {
        return new Bound('0.0.0.0-dev', \true);
    }
    public static function positiveInfinity()
    {
        return new Bound(\PHP_INT_MAX . '.0.0.0', \false);
    }
}
<?php

namespace HumbugBox436\Composer\Semver\Constraint;

class Constraint implements ConstraintInterface
{
    const OP_EQ = 0;
    const OP_LT = 1;
    const OP_LE = 2;
    const OP_GT = 3;
    const OP_GE = 4;
    const OP_NE = 5;
    const STR_OP_EQ = '==';
    const STR_OP_EQ_ALT = '=';
    const STR_OP_LT = '<';
    const STR_OP_LE = '<=';
    const STR_OP_GT = '>';
    const STR_OP_GE = '>=';
    const STR_OP_NE = '!=';
    const STR_OP_NE_ALT = '<>';
    /**
    @phpstan-var
    */
    private static $transOpStr = array('=' => self::OP_EQ, '==' => self::OP_EQ, '<' => self::OP_LT, '<=' => self::OP_LE, '>' => self::OP_GT, '>=' => self::OP_GE, '<>' => self::OP_NE, '!=' => self::OP_NE);
    /**
    @phpstan-var
    */
    private static $transOpInt = array(self::OP_EQ => '==', self::OP_LT => '<', self::OP_LE => '<=', self::OP_GT => '>', self::OP_GE => '>=', self::OP_NE => '!=');
    /**
    @phpstan-var
    */
    protected $operator;
    protected $version;
    protected $prettyString;
    protected $lowerBound;
    protected $upperBound;
    /**
    @phpstan-param
    */
    public function __construct($operator, $version)
    {
        if (!isset(self::$transOpStr[$operator])) {
            throw new \InvalidArgumentException(\sprintf('Invalid operator "%s" given, expected one of: %s', $operator, \implode(', ', self::getSupportedOperators())));
        }
        $this->operator = self::$transOpStr[$operator];
        $this->version = $version;
    }
    public function getVersion()
    {
        return $this->version;
    }
    /**
    @phpstan-return
    */
    public function getOperator()
    {
        return self::$transOpInt[$this->operator];
    }
    public function matches(ConstraintInterface $provider)
    {
        if ($provider instanceof self) {
            return $this->matchSpecific($provider);
        }
        return $provider->matches($this);
    }
    public function setPrettyString($prettyString)
    {
        $this->prettyString = $prettyString;
    }
    public function getPrettyString()
    {
        if ($this->prettyString) {
            return $this->prettyString;
        }
        return $this->__toString();
    }
    /**
    @phpstan-return
    */
    public static function getSupportedOperators()
    {
        return \array_keys(self::$transOpStr);
    }
    /**
    @phpstan-param
    @phpstan-return
    */
    public static function getOperatorConstant($operator)
    {
        return self::$transOpStr[$operator];
    }
    /**
    @phpstan-param
    */
    public function versionCompare($a, $b, $operator, $compareBranches = \false)
    {
        if (!isset(self::$transOpStr[$operator])) {
            throw new \InvalidArgumentException(\sprintf('Invalid operator "%s" given, expected one of: %s', $operator, \implode(', ', self::getSupportedOperators())));
        }
        $aIsBranch = \strpos($a, 'dev-') === 0;
        $bIsBranch = \strpos($b, 'dev-') === 0;
        if ($operator === '!=' && ($aIsBranch || $bIsBranch)) {
            return $a !== $b;
        }
        if ($aIsBranch && $bIsBranch) {
            return $operator === '==' && $a === $b;
        }
        if (!$compareBranches && ($aIsBranch || $bIsBranch)) {
            return \false;
        }
        return \version_compare($a, $b, $operator);
    }
    public function compile($otherOperator)
    {
        if (\strpos($this->version, 'dev-') === 0) {
            if (self::OP_EQ === $this->operator) {
                if (self::OP_EQ === $otherOperator) {
                    return \sprintf('$b && $v === %s', \var_export($this->version, \true));
                }
                if (self::OP_NE === $otherOperator) {
                    return \sprintf('!$b || $v !== %s', \var_export($this->version, \true));
                }
                return 'false';
            }
            if (self::OP_NE === $this->operator) {
                if (self::OP_EQ === $otherOperator) {
                    return \sprintf('!$b || $v !== %s', \var_export($this->version, \true));
                }
                if (self::OP_NE === $otherOperator) {
                    return 'true';
                }
                return '!$b';
            }
            return 'false';
        }
        if (self::OP_EQ === $this->operator) {
            if (self::OP_EQ === $otherOperator) {
                return \sprintf('\\version_compare($v, %s, \'==\')', \var_export($this->version, \true));
            }
            if (self::OP_NE === $otherOperator) {
                return \sprintf('$b || \\version_compare($v, %s, \'!=\')', \var_export($this->version, \true));
            }
            return \sprintf('!$b && \\version_compare(%s, $v, \'%s\')', \var_export($this->version, \true), self::$transOpInt[$otherOperator]);
        }
        if (self::OP_NE === $this->operator) {
            if (self::OP_EQ === $otherOperator) {
                return \sprintf('$b || (!$b && \\version_compare($v, %s, \'!=\'))', \var_export($this->version, \true));
            }
            if (self::OP_NE === $otherOperator) {
                return 'true';
            }
            return '!$b';
        }
        if (self::OP_LT === $this->operator || self::OP_LE === $this->operator) {
            if (self::OP_LT === $otherOperator || self::OP_LE === $otherOperator) {
                return '!$b';
            }
        } else {
            if (self::OP_GT === $otherOperator || self::OP_GE === $otherOperator) {
                return '!$b';
            }
        }
        if (self::OP_NE === $otherOperator) {
            return 'true';
        }
        $codeComparison = \sprintf('\\version_compare($v, %s, \'%s\')', \var_export($this->version, \true), self::$transOpInt[$this->operator]);
        if ($this->operator === self::OP_LE) {
            if ($otherOperator === self::OP_GT) {
                return \sprintf('!$b && \\version_compare($v, %s, \'!=\') && ', \var_export($this->version, \true)) . $codeComparison;
            }
        } elseif ($this->operator === self::OP_GE) {
            if ($otherOperator === self::OP_LT) {
                return \sprintf('!$b && \\version_compare($v, %s, \'!=\') && ', \var_export($this->version, \true)) . $codeComparison;
            }
        }
        return \sprintf('!$b && %s', $codeComparison);
    }
    public function matchSpecific(Constraint $provider, $compareBranches = \false)
    {
        $noEqualOp = \str_replace('=', '', self::$transOpInt[$this->operator]);
        $providerNoEqualOp = \str_replace('=', '', self::$transOpInt[$provider->operator]);
        $isEqualOp = self::OP_EQ === $this->operator;
        $isNonEqualOp = self::OP_NE === $this->operator;
        $isProviderEqualOp = self::OP_EQ === $provider->operator;
        $isProviderNonEqualOp = self::OP_NE === $provider->operator;
        if ($isNonEqualOp || $isProviderNonEqualOp) {
            if ($isNonEqualOp && !$isProviderNonEqualOp && !$isProviderEqualOp && \strpos($provider->version, 'dev-') === 0) {
                return \false;
            }
            if ($isProviderNonEqualOp && !$isNonEqualOp && !$isEqualOp && \strpos($this->version, 'dev-') === 0) {
                return \false;
            }
            if (!$isEqualOp && !$isProviderEqualOp) {
                return \true;
            }
            return $this->versionCompare($provider->version, $this->version, '!=', $compareBranches);
        }
        if ($this->operator !== self::OP_EQ && $noEqualOp === $providerNoEqualOp) {
            return !(\strpos($this->version, 'dev-') === 0 || \strpos($provider->version, 'dev-') === 0);
        }
        $version1 = $isEqualOp ? $this->version : $provider->version;
        $version2 = $isEqualOp ? $provider->version : $this->version;
        $operator = $isEqualOp ? $provider->operator : $this->operator;
        if ($this->versionCompare($version1, $version2, self::$transOpInt[$operator], $compareBranches)) {
            return !(self::$transOpInt[$provider->operator] === $providerNoEqualOp && self::$transOpInt[$this->operator] !== $noEqualOp && \version_compare($provider->version, $this->version, '=='));
        }
        return \false;
    }
    public function __toString()
    {
        return self::$transOpInt[$this->operator] . ' ' . $this->version;
    }
    public function getLowerBound()
    {
        $this->extractBounds();
        return $this->lowerBound;
    }
    public function getUpperBound()
    {
        $this->extractBounds();
        return $this->upperBound;
    }
    private function extractBounds()
    {
        if (null !== $this->lowerBound) {
            return;
        }
        if (\strpos($this->version, 'dev-') === 0) {
            $this->lowerBound = Bound::zero();
            $this->upperBound = Bound::positiveInfinity();
            return;
        }
        switch ($this->operator) {
            case self::OP_EQ:
                $this->lowerBound = new Bound($this->version, \true);
                $this->upperBound = new Bound($this->version, \true);
                break;
            case self::OP_LT:
                $this->lowerBound = Bound::zero();
                $this->upperBound = new Bound($this->version, \false);
                break;
            case self::OP_LE:
                $this->lowerBound = Bound::zero();
                $this->upperBound = new Bound($this->version, \true);
                break;
            case self::OP_GT:
                $this->lowerBound = new Bound($this->version, \false);
                $this->upperBound = Bound::positiveInfinity();
                break;
            case self::OP_GE:
                $this->lowerBound = new Bound($this->version, \true);
                $this->upperBound = Bound::positiveInfinity();
                break;
            case self::OP_NE:
                $this->lowerBound = Bound::zero();
                $this->upperBound = Bound::positiveInfinity();
                break;
        }
    }
}
<?php

namespace HumbugBox436\Composer\Semver\Constraint;

class MultiConstraint implements ConstraintInterface
{
    /**
    @phpstan-var
    */
    protected $constraints;
    protected $prettyString;
    protected $string;
    protected $conjunctive;
    protected $lowerBound;
    protected $upperBound;
    public function __construct(array $constraints, $conjunctive = \true)
    {
        if (\count($constraints) < 2) {
            throw new \InvalidArgumentException('Must provide at least two constraints for a MultiConstraint. Use ' . 'the regular Constraint class for one constraint only or MatchAllConstraint for none. You may use ' . 'MultiConstraint::create() which optimizes and handles those cases automatically.');
        }
        $this->constraints = $constraints;
        $this->conjunctive = $conjunctive;
    }
    public function getConstraints()
    {
        return $this->constraints;
    }
    public function isConjunctive()
    {
        return $this->conjunctive;
    }
    public function isDisjunctive()
    {
        return !$this->conjunctive;
    }
    public function compile($otherOperator)
    {
        $parts = array();
        foreach ($this->constraints as $constraint) {
            $code = $constraint->compile($otherOperator);
            if ($code === 'true') {
                if (!$this->conjunctive) {
                    return 'true';
                }
            } elseif ($code === 'false') {
                if ($this->conjunctive) {
                    return 'false';
                }
            } else {
                $parts[] = '(' . $code . ')';
            }
        }
        if (!$parts) {
            return $this->conjunctive ? 'true' : 'false';
        }
        return $this->conjunctive ? \implode('&&', $parts) : \implode('||', $parts);
    }
    public function matches(ConstraintInterface $provider)
    {
        if (\false === $this->conjunctive) {
            foreach ($this->constraints as $constraint) {
                if ($provider->matches($constraint)) {
                    return \true;
                }
            }
            return \false;
        }
        if ($provider instanceof MultiConstraint && $provider->isDisjunctive()) {
            return $provider->matches($this);
        }
        foreach ($this->constraints as $constraint) {
            if (!$provider->matches($constraint)) {
                return \false;
            }
        }
        return \true;
    }
    public function setPrettyString($prettyString)
    {
        $this->prettyString = $prettyString;
    }
    public function getPrettyString()
    {
        if ($this->prettyString) {
            return $this->prettyString;
        }
        return (string) $this;
    }
    public function __toString()
    {
        if ($this->string !== null) {
            return $this->string;
        }
        $constraints = array();
        foreach ($this->constraints as $constraint) {
            $constraints[] = (string) $constraint;
        }
        return $this->string = '[' . \implode($this->conjunctive ? ' ' : ' || ', $constraints) . ']';
    }
    public function getLowerBound()
    {
        $this->extractBounds();
        if (null === $this->lowerBound) {
            throw new \LogicException('extractBounds should have populated the lowerBound property');
        }
        return $this->lowerBound;
    }
    public function getUpperBound()
    {
        $this->extractBounds();
        if (null === $this->upperBound) {
            throw new \LogicException('extractBounds should have populated the upperBound property');
        }
        return $this->upperBound;
    }
    public static function create(array $constraints, $conjunctive = \true)
    {
        if (0 === \count($constraints)) {
            return new MatchAllConstraint();
        }
        if (1 === \count($constraints)) {
            return $constraints[0];
        }
        $optimized = self::optimizeConstraints($constraints, $conjunctive);
        if ($optimized !== null) {
            list($constraints, $conjunctive) = $optimized;
            if (\count($constraints) === 1) {
                return $constraints[0];
            }
        }
        return new self($constraints, $conjunctive);
    }
    /**
    @phpstan-return
    */
    private static function optimizeConstraints(array $constraints, $conjunctive)
    {
        if (!$conjunctive) {
            $left = $constraints[0];
            $mergedConstraints = array();
            $optimized = \false;
            for ($i = 1, $l = \count($constraints); $i < $l; $i++) {
                $right = $constraints[$i];
                if ($left instanceof self && $left->conjunctive && $right instanceof self && $right->conjunctive && \count($left->constraints) === 2 && \count($right->constraints) === 2 && ($left0 = (string) $left->constraints[0]) && $left0[0] === '>' && $left0[1] === '=' && ($left1 = (string) $left->constraints[1]) && $left1[0] === '<' && ($right0 = (string) $right->constraints[0]) && $right0[0] === '>' && $right0[1] === '=' && ($right1 = (string) $right->constraints[1]) && $right1[0] === '<' && \substr($left1, 2) === \substr($right0, 3)) {
                    $optimized = \true;
                    $left = new MultiConstraint(array($left->constraints[0], $right->constraints[1]), \true);
                } else {
                    $mergedConstraints[] = $left;
                    $left = $right;
                }
            }
            if ($optimized) {
                $mergedConstraints[] = $left;
                return array($mergedConstraints, \false);
            }
        }
        return null;
    }
    private function extractBounds()
    {
        if (null !== $this->lowerBound) {
            return;
        }
        foreach ($this->constraints as $constraint) {
            if (null === $this->lowerBound || null === $this->upperBound) {
                $this->lowerBound = $constraint->getLowerBound();
                $this->upperBound = $constraint->getUpperBound();
                continue;
            }
            if ($constraint->getLowerBound()->compareTo($this->lowerBound, $this->isConjunctive() ? '>' : '<')) {
                $this->lowerBound = $constraint->getLowerBound();
            }
            if ($constraint->getUpperBound()->compareTo($this->upperBound, $this->isConjunctive() ? '<' : '>')) {
                $this->upperBound = $constraint->getUpperBound();
            }
        }
    }
}
<?php

namespace HumbugBox436\Composer\Semver\Constraint;

class MatchNoneConstraint implements ConstraintInterface
{
    protected $prettyString;
    public function matches(ConstraintInterface $provider)
    {
        return \false;
    }
    public function compile($otherOperator)
    {
        return 'false';
    }
    public function setPrettyString($prettyString)
    {
        $this->prettyString = $prettyString;
    }
    public function getPrettyString()
    {
        if ($this->prettyString) {
            return $this->prettyString;
        }
        return (string) $this;
    }
    public function __toString()
    {
        return '[]';
    }
    public function getUpperBound()
    {
        return new Bound('0.0.0.0-dev', \false);
    }
    public function getLowerBound()
    {
        return new Bound('0.0.0.0-dev', \false);
    }
}
<?php

namespace HumbugBox436\Composer\Semver\Constraint;

class MatchAllConstraint implements ConstraintInterface
{
    protected $prettyString;
    public function matches(ConstraintInterface $provider)
    {
        return \true;
    }
    public function compile($otherOperator)
    {
        return 'true';
    }
    public function setPrettyString($prettyString)
    {
        $this->prettyString = $prettyString;
    }
    public function getPrettyString()
    {
        if ($this->prettyString) {
            return $this->prettyString;
        }
        return (string) $this;
    }
    public function __toString()
    {
        return '*';
    }
    public function getUpperBound()
    {
        return Bound::positiveInfinity();
    }
    public function getLowerBound()
    {
        return Bound::zero();
    }
}
<?php

namespace HumbugBox436\Composer\Semver\Constraint;

interface ConstraintInterface
{
    public function matches(ConstraintInterface $provider);
    /**
    @phpstan-param
    */
    public function compile($otherOperator);
    public function getUpperBound();
    public function getLowerBound();
    public function getPrettyString();
    public function setPrettyString($prettyString);
    public function __toString();
}
<?php

namespace HumbugBox436\Composer\Semver;

use HumbugBox436\Composer\Semver\Constraint\Constraint;
class Comparator
{
    public static function greaterThan($version1, $version2)
    {
        return self::compare($version1, '>', $version2);
    }
    public static function greaterThanOrEqualTo($version1, $version2)
    {
        return self::compare($version1, '>=', $version2);
    }
    public static function lessThan($version1, $version2)
    {
        return self::compare($version1, '<', $version2);
    }
    public static function lessThanOrEqualTo($version1, $version2)
    {
        return self::compare($version1, '<=', $version2);
    }
    public static function equalTo($version1, $version2)
    {
        return self::compare($version1, '==', $version2);
    }
    public static function notEqualTo($version1, $version2)
    {
        return self::compare($version1, '!=', $version2);
    }
    /**
    @phpstan-param
    */
    public static function compare($version1, $operator, $version2)
    {
        $constraint = new Constraint($operator, $version2);
        return $constraint->matchSpecific(new Constraint('==', $version1), \true);
    }
}
<?php

namespace HumbugBox436\Composer\Semver;

use HumbugBox436\Composer\Semver\Constraint\Constraint;
class Semver
{
    const SORT_ASC = 1;
    const SORT_DESC = -1;
    private static $versionParser;
    public static function satisfies($version, $constraints)
    {
        if (null === self::$versionParser) {
            self::$versionParser = new VersionParser();
        }
        $versionParser = self::$versionParser;
        $provider = new Constraint('==', $versionParser->normalize($version));
        $parsedConstraints = $versionParser->parseConstraints($constraints);
        return $parsedConstraints->matches($provider);
    }
    public static function satisfiedBy(array $versions, $constraints)
    {
        $versions = \array_filter($versions, function ($version) use($constraints) {
            return Semver::satisfies($version, $constraints);
        });
        return \array_values($versions);
    }
    public static function sort(array $versions)
    {
        return self::usort($versions, self::SORT_ASC);
    }
    public static function rsort(array $versions)
    {
        return self::usort($versions, self::SORT_DESC);
    }
    private static function usort(array $versions, $direction)
    {
        if (null === self::$versionParser) {
            self::$versionParser = new VersionParser();
        }
        $versionParser = self::$versionParser;
        $normalized = array();
        foreach ($versions as $key => $version) {
            $normalizedVersion = $versionParser->normalize($version);
            $normalizedVersion = $versionParser->normalizeDefaultBranch($normalizedVersion);
            $normalized[] = array($normalizedVersion, $key);
        }
        \usort($normalized, function (array $left, array $right) use($direction) {
            if ($left[0] === $right[0]) {
                return 0;
            }
            if (Comparator::lessThan($left[0], $right[0])) {
                return -$direction;
            }
            return $direction;
        });
        $sorted = array();
        foreach ($normalized as $item) {
            $sorted[] = $versions[$item[1]];
        }
        return $sorted;
    }
}
<?php

namespace HumbugBox436\Composer\Semver;

use HumbugBox436\Composer\Semver\Constraint\Constraint;
use HumbugBox436\Composer\Semver\Constraint\ConstraintInterface;
use HumbugBox436\Composer\Semver\Constraint\MatchAllConstraint;
use HumbugBox436\Composer\Semver\Constraint\MatchNoneConstraint;
use HumbugBox436\Composer\Semver\Constraint\MultiConstraint;
class Intervals
{
    /**
    @phpstan-var
    */
    private static $intervalsCache = array();
    /**
    @phpstan-var
    */
    private static $opSortOrder = array('>=' => -3, '<' => -2, '>' => 2, '<=' => 3);
    public static function clear()
    {
        self::$intervalsCache = array();
    }
    public static function isSubsetOf(ConstraintInterface $candidate, ConstraintInterface $constraint)
    {
        if ($constraint instanceof MatchAllConstraint) {
            return \true;
        }
        if ($candidate instanceof MatchNoneConstraint || $constraint instanceof MatchNoneConstraint) {
            return \false;
        }
        $intersectionIntervals = self::get(new MultiConstraint(array($candidate, $constraint), \true));
        $candidateIntervals = self::get($candidate);
        if (\count($intersectionIntervals['numeric']) !== \count($candidateIntervals['numeric'])) {
            return \false;
        }
        foreach ($intersectionIntervals['numeric'] as $index => $interval) {
            if (!isset($candidateIntervals['numeric'][$index])) {
                return \false;
            }
            if ((string) $candidateIntervals['numeric'][$index]->getStart() !== (string) $interval->getStart()) {
                return \false;
            }
            if ((string) $candidateIntervals['numeric'][$index]->getEnd() !== (string) $interval->getEnd()) {
                return \false;
            }
        }
        if ($intersectionIntervals['branches']['exclude'] !== $candidateIntervals['branches']['exclude']) {
            return \false;
        }
        if (\count($intersectionIntervals['branches']['names']) !== \count($candidateIntervals['branches']['names'])) {
            return \false;
        }
        foreach ($intersectionIntervals['branches']['names'] as $index => $name) {
            if ($name !== $candidateIntervals['branches']['names'][$index]) {
                return \false;
            }
        }
        return \true;
    }
    public static function haveIntersections(ConstraintInterface $a, ConstraintInterface $b)
    {
        if ($a instanceof MatchAllConstraint || $b instanceof MatchAllConstraint) {
            return \true;
        }
        if ($a instanceof MatchNoneConstraint || $b instanceof MatchNoneConstraint) {
            return \false;
        }
        $intersectionIntervals = self::generateIntervals(new MultiConstraint(array($a, $b), \true), \true);
        return \count($intersectionIntervals['numeric']) > 0 || $intersectionIntervals['branches']['exclude'] || \count($intersectionIntervals['branches']['names']) > 0;
    }
    public static function compactConstraint(ConstraintInterface $constraint)
    {
        if (!$constraint instanceof MultiConstraint) {
            return $constraint;
        }
        $intervals = self::generateIntervals($constraint);
        $constraints = array();
        $hasNumericMatchAll = \false;
        if (\count($intervals['numeric']) === 1 && (string) $intervals['numeric'][0]->getStart() === (string) Interval::fromZero() && (string) $intervals['numeric'][0]->getEnd() === (string) Interval::untilPositiveInfinity()) {
            $constraints[] = $intervals['numeric'][0]->getStart();
            $hasNumericMatchAll = \true;
        } else {
            $unEqualConstraints = array();
            for ($i = 0, $count = \count($intervals['numeric']); $i < $count; $i++) {
                $interval = $intervals['numeric'][$i];
                if ($interval->getEnd()->getOperator() === '<' && $i + 1 < $count) {
                    $nextInterval = $intervals['numeric'][$i + 1];
                    if ($interval->getEnd()->getVersion() === $nextInterval->getStart()->getVersion() && $nextInterval->getStart()->getOperator() === '>') {
                        if (\count($unEqualConstraints) === 0 && (string) $interval->getStart() !== (string) Interval::fromZero()) {
                            $unEqualConstraints[] = $interval->getStart();
                        }
                        $unEqualConstraints[] = new Constraint('!=', $interval->getEnd()->getVersion());
                        continue;
                    }
                }
                if (\count($unEqualConstraints) > 0) {
                    if ((string) $interval->getEnd() !== (string) Interval::untilPositiveInfinity()) {
                        $unEqualConstraints[] = $interval->getEnd();
                    }
                    if (\count($unEqualConstraints) > 1) {
                        $constraints[] = new MultiConstraint($unEqualConstraints, \true);
                    } else {
                        $constraints[] = $unEqualConstraints[0];
                    }
                    $unEqualConstraints = array();
                    continue;
                }
                if ($interval->getStart()->getVersion() === $interval->getEnd()->getVersion() && $interval->getStart()->getOperator() === '>=' && $interval->getEnd()->getOperator() === '<=') {
                    $constraints[] = new Constraint('==', $interval->getStart()->getVersion());
                    continue;
                }
                if ((string) $interval->getStart() === (string) Interval::fromZero()) {
                    $constraints[] = $interval->getEnd();
                } elseif ((string) $interval->getEnd() === (string) Interval::untilPositiveInfinity()) {
                    $constraints[] = $interval->getStart();
                } else {
                    $constraints[] = new MultiConstraint(array($interval->getStart(), $interval->getEnd()), \true);
                }
            }
        }
        $devConstraints = array();
        if (0 === \count($intervals['branches']['names'])) {
            if ($intervals['branches']['exclude']) {
                if ($hasNumericMatchAll) {
                    return new MatchAllConstraint();
                }
            }
        } else {
            foreach ($intervals['branches']['names'] as $branchName) {
                if ($intervals['branches']['exclude']) {
                    $devConstraints[] = new Constraint('!=', $branchName);
                } else {
                    $devConstraints[] = new Constraint('==', $branchName);
                }
            }
            if ($intervals['branches']['exclude']) {
                if (\count($constraints) > 1) {
                    return new MultiConstraint(\array_merge(array(new MultiConstraint($constraints, \false)), $devConstraints), \true);
                }
                if (\count($constraints) === 1 && (string) $constraints[0] === (string) Interval::fromZero()) {
                    if (\count($devConstraints) > 1) {
                        return new MultiConstraint($devConstraints, \true);
                    }
                    return $devConstraints[0];
                }
                return new MultiConstraint(\array_merge($constraints, $devConstraints), \true);
            }
            $constraints = \array_merge($constraints, $devConstraints);
        }
        if (\count($constraints) > 1) {
            return new MultiConstraint($constraints, \false);
        }
        if (\count($constraints) === 1) {
            return $constraints[0];
        }
        return new MatchNoneConstraint();
    }
    /**
    @phpstan-return
    */
    public static function get(ConstraintInterface $constraint)
    {
        $key = (string) $constraint;
        if (!isset(self::$intervalsCache[$key])) {
            self::$intervalsCache[$key] = self::generateIntervals($constraint);
        }
        return self::$intervalsCache[$key];
    }
    /**
    @phpstan-return
    */
    private static function generateIntervals(ConstraintInterface $constraint, $stopOnFirstValidInterval = \false)
    {
        if ($constraint instanceof MatchAllConstraint) {
            return array('numeric' => array(new Interval(Interval::fromZero(), Interval::untilPositiveInfinity())), 'branches' => Interval::anyDev());
        }
        if ($constraint instanceof MatchNoneConstraint) {
            return array('numeric' => array(), 'branches' => array('names' => array(), 'exclude' => \false));
        }
        if ($constraint instanceof Constraint) {
            return self::generateSingleConstraintIntervals($constraint);
        }
        if (!$constraint instanceof MultiConstraint) {
            throw new \UnexpectedValueException('The constraint passed in should be an MatchAllConstraint, Constraint or MultiConstraint instance, got ' . \get_class($constraint) . '.');
        }
        $constraints = $constraint->getConstraints();
        $numericGroups = array();
        $constraintBranches = array();
        foreach ($constraints as $c) {
            $res = self::get($c);
            $numericGroups[] = $res['numeric'];
            $constraintBranches[] = $res['branches'];
        }
        if ($constraint->isDisjunctive()) {
            $branches = Interval::noDev();
            foreach ($constraintBranches as $b) {
                if ($b['exclude']) {
                    if ($branches['exclude']) {
                        $branches['names'] = \array_intersect($branches['names'], $b['names']);
                    } else {
                        $branches['exclude'] = \true;
                        $branches['names'] = \array_diff($b['names'], $branches['names']);
                    }
                } else {
                    if ($branches['exclude']) {
                        $branches['names'] = \array_diff($branches['names'], $b['names']);
                    } else {
                        $branches['names'] = \array_merge($branches['names'], $b['names']);
                    }
                }
            }
        } else {
            $branches = Interval::anyDev();
            foreach ($constraintBranches as $b) {
                if ($b['exclude']) {
                    if ($branches['exclude']) {
                        $branches['names'] = \array_merge($branches['names'], $b['names']);
                    } else {
                        $branches['names'] = \array_diff($branches['names'], $b['names']);
                    }
                } else {
                    if ($branches['exclude']) {
                        $branches['names'] = \array_diff($b['names'], $branches['names']);
                        $branches['exclude'] = \false;
                    } else {
                        $branches['names'] = \array_intersect($branches['names'], $b['names']);
                    }
                }
            }
        }
        $branches['names'] = \array_unique($branches['names']);
        if (\count($numericGroups) === 1) {
            return array('numeric' => $numericGroups[0], 'branches' => $branches);
        }
        $borders = array();
        foreach ($numericGroups as $group) {
            foreach ($group as $interval) {
                $borders[] = array('version' => $interval->getStart()->getVersion(), 'operator' => $interval->getStart()->getOperator(), 'side' => 'start');
                $borders[] = array('version' => $interval->getEnd()->getVersion(), 'operator' => $interval->getEnd()->getOperator(), 'side' => 'end');
            }
        }
        $opSortOrder = self::$opSortOrder;
        \usort($borders, function ($a, $b) use($opSortOrder) {
            $order = \version_compare($a['version'], $b['version']);
            if ($order === 0) {
                return $opSortOrder[$a['operator']] - $opSortOrder[$b['operator']];
            }
            return $order;
        });
        $activeIntervals = 0;
        $intervals = array();
        $index = 0;
        $activationThreshold = $constraint->isConjunctive() ? \count($numericGroups) : 1;
        $start = null;
        foreach ($borders as $border) {
            if ($border['side'] === 'start') {
                $activeIntervals++;
            } else {
                $activeIntervals--;
            }
            if (!$start && $activeIntervals >= $activationThreshold) {
                $start = new Constraint($border['operator'], $border['version']);
            } elseif ($start && $activeIntervals < $activationThreshold) {
                if (\version_compare($start->getVersion(), $border['version'], '=') && ($start->getOperator() === '>' && $border['operator'] === '<=' || $start->getOperator() === '>=' && $border['operator'] === '<')) {
                    unset($intervals[$index]);
                } else {
                    $intervals[$index] = new Interval($start, new Constraint($border['operator'], $border['version']));
                    $index++;
                    if ($stopOnFirstValidInterval) {
                        break;
                    }
                }
                $start = null;
            }
        }
        return array('numeric' => $intervals, 'branches' => $branches);
    }
    /**
    @phpstan-return
    */
    private static function generateSingleConstraintIntervals(Constraint $constraint)
    {
        $op = $constraint->getOperator();
        if (\strpos($constraint->getVersion(), 'dev-') === 0) {
            $intervals = array();
            $branches = array('names' => array(), 'exclude' => \false);
            if ($op === '!=') {
                $intervals[] = new Interval(Interval::fromZero(), Interval::untilPositiveInfinity());
                $branches = array('names' => array($constraint->getVersion()), 'exclude' => \true);
            } elseif ($op === '==') {
                $branches['names'][] = $constraint->getVersion();
            }
            return array('numeric' => $intervals, 'branches' => $branches);
        }
        if ($op[0] === '>') {
            return array('numeric' => array(new Interval($constraint, Interval::untilPositiveInfinity())), 'branches' => Interval::noDev());
        }
        if ($op[0] === '<') {
            return array('numeric' => array(new Interval(Interval::fromZero(), $constraint)), 'branches' => Interval::noDev());
        }
        if ($op === '!=') {
            return array('numeric' => array(new Interval(Interval::fromZero(), new Constraint('<', $constraint->getVersion())), new Interval(new Constraint('>', $constraint->getVersion()), Interval::untilPositiveInfinity())), 'branches' => Interval::anyDev());
        }
        return array('numeric' => array(new Interval(new Constraint('>=', $constraint->getVersion()), new Constraint('<=', $constraint->getVersion()))), 'branches' => Interval::noDev());
    }
}
<?php

namespace HumbugBox436\Composer\Semver;

use HumbugBox436\Composer\Semver\Constraint\Constraint;
use HumbugBox436\Composer\Semver\Constraint\ConstraintInterface;
class CompilingMatcher
{
    /**
    @phpstan-var
    */
    private static $compiledCheckerCache = array();
    /**
    @phpstan-var
    */
    private static $resultCache = array();
    private static $enabled;
    /**
    @phpstan-var
    */
    private static $transOpInt = array(Constraint::OP_EQ => Constraint::STR_OP_EQ, Constraint::OP_LT => Constraint::STR_OP_LT, Constraint::OP_LE => Constraint::STR_OP_LE, Constraint::OP_GT => Constraint::STR_OP_GT, Constraint::OP_GE => Constraint::STR_OP_GE, Constraint::OP_NE => Constraint::STR_OP_NE);
    public static function clear()
    {
        self::$resultCache = array();
        self::$compiledCheckerCache = array();
    }
    /**
    @phpstan-param
    */
    public static function match(ConstraintInterface $constraint, $operator, $version)
    {
        $resultCacheKey = $operator . $constraint . ';' . $version;
        if (isset(self::$resultCache[$resultCacheKey])) {
            return self::$resultCache[$resultCacheKey];
        }
        if (self::$enabled === null) {
            self::$enabled = !\in_array('eval', \explode(',', (string) \ini_get('disable_functions')), \true);
        }
        if (!self::$enabled) {
            return self::$resultCache[$resultCacheKey] = $constraint->matches(new Constraint(self::$transOpInt[$operator], $version));
        }
        $cacheKey = $operator . $constraint;
        if (!isset(self::$compiledCheckerCache[$cacheKey])) {
            $code = $constraint->compile($operator);
            self::$compiledCheckerCache[$cacheKey] = $function = eval('return function($v, $b){return ' . $code . ';};');
        } else {
            $function = self::$compiledCheckerCache[$cacheKey];
        }
        return self::$resultCache[$resultCacheKey] = $function($version, \strpos($version, 'dev-') === 0);
    }
}
Copyright (C) 2015 Composer

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
<?php

namespace HumbugBox436\Composer;

use HumbugBox436\Composer\Autoload\ClassLoader;
use HumbugBox436\Composer\Semver\VersionParser;
class InstalledVersions
{
    /**
    @psalm-var
    */
    private static $installed;
    private static $canGetVendors;
    /**
    @psalm-var
    */
    private static $installedByVendor = array();
    /**
    @psalm-return
    */
    public static function getInstalledPackages()
    {
        $packages = array();
        foreach (self::getInstalled() as $installed) {
            $packages[] = \array_keys($installed['versions']);
        }
        if (1 === \count($packages)) {
            return $packages[0];
        }
        return \array_keys(\array_flip(\call_user_func_array('array_merge', $packages)));
    }
    /**
    @psalm-return
    */
    public static function getInstalledPackagesByType($type)
    {
        $packagesByType = array();
        foreach (self::getInstalled() as $installed) {
            foreach ($installed['versions'] as $name => $package) {
                if (isset($package['type']) && $package['type'] === $type) {
                    $packagesByType[] = $name;
                }
            }
        }
        return $packagesByType;
    }
    public static function isInstalled($packageName, $includeDevRequirements = \true)
    {
        foreach (self::getInstalled() as $installed) {
            if (isset($installed['versions'][$packageName])) {
                return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
            }
        }
        return \false;
    }
    public static function satisfies(VersionParser $parser, $packageName, $constraint)
    {
        $constraint = $parser->parseConstraints($constraint);
        $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
        return $provided->matches($constraint);
    }
    public static function getVersionRanges($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }
            $ranges = array();
            if (isset($installed['versions'][$packageName]['pretty_version'])) {
                $ranges[] = $installed['versions'][$packageName]['pretty_version'];
            }
            if (\array_key_exists('aliases', $installed['versions'][$packageName])) {
                $ranges = \array_merge($ranges, $installed['versions'][$packageName]['aliases']);
            }
            if (\array_key_exists('replaced', $installed['versions'][$packageName])) {
                $ranges = \array_merge($ranges, $installed['versions'][$packageName]['replaced']);
            }
            if (\array_key_exists('provided', $installed['versions'][$packageName])) {
                $ranges = \array_merge($ranges, $installed['versions'][$packageName]['provided']);
            }
            return \implode(' || ', $ranges);
        }
        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }
    public static function getVersion($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }
            if (!isset($installed['versions'][$packageName]['version'])) {
                return null;
            }
            return $installed['versions'][$packageName]['version'];
        }
        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }
    public static function getPrettyVersion($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }
            if (!isset($installed['versions'][$packageName]['pretty_version'])) {
                return null;
            }
            return $installed['versions'][$packageName]['pretty_version'];
        }
        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }
    public static function getReference($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }
            if (!isset($installed['versions'][$packageName]['reference'])) {
                return null;
            }
            return $installed['versions'][$packageName]['reference'];
        }
        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }
    public static function getInstallPath($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }
            return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
        }
        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }
    /**
    @psalm-return
    */
    public static function getRootPackage()
    {
        $installed = self::getInstalled();
        return $installed[0]['root'];
    }
    /**
    @psalm-return
    */
    public static function getRawData()
    {
        @\trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', \E_USER_DEPRECATED);
        if (null === self::$installed) {
            if (\substr(__DIR__, -8, 1) !== 'C') {
                self::$installed = (include __DIR__ . '/installed.php');
            } else {
                self::$installed = array();
            }
        }
        return self::$installed;
    }
    /**
    @psalm-return
    */
    public static function getAllRawData()
    {
        return self::getInstalled();
    }
    /**
    @psalm-param
    */
    public static function reload($data)
    {
        self::$installed = $data;
        self::$installedByVendor = array();
    }
    /**
    @psalm-return
    */
    private static function getInstalled()
    {
        if (null === self::$canGetVendors) {
            self::$canGetVendors = \method_exists('HumbugBox436\\Composer\\Autoload\\ClassLoader', 'getRegisteredLoaders');
        }
        $installed = array();
        if (self::$canGetVendors) {
            foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
                if (isset(self::$installedByVendor[$vendorDir])) {
                    $installed[] = self::$installedByVendor[$vendorDir];
                } elseif (\is_file($vendorDir . '/composer/installed.php')) {
                    $installed[] = self::$installedByVendor[$vendorDir] = (require $vendorDir . '/composer/installed.php');
                    if (null === self::$installed && \strtr($vendorDir . '/composer', '\\', '/') === \strtr(__DIR__, '\\', '/')) {
                        self::$installed = $installed[\count($installed) - 1];
                    }
                }
            }
        }
        if (null === self::$installed) {
            if (\substr(__DIR__, -8, 1) !== 'C') {
                self::$installed = (require __DIR__ . '/installed.php');
            } else {
                self::$installed = array();
            }
        }
        $installed[] = self::$installed;
        return $installed;
    }
}
<?php

/*
 * This file is part of Composer.
 *
 * (c) Nils Adermann <naderman@naderman.de>
 *     Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Composer\Autoload;

/**
 * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
 *
 *     $loader = new \Composer\Autoload\ClassLoader();
 *
 *     // register classes with namespaces
 *     $loader->add('Symfony\Component', __DIR__.'/component');
 *     $loader->add('Symfony',           __DIR__.'/framework');
 *
 *     // activate the autoloader
 *     $loader->register();
 *
 *     // to enable searching the include path (eg. for PEAR packages)
 *     $loader->setUseIncludePath(true);
 *
 * In this example, if you try to use a class in the Symfony\Component
 * namespace or one of its children (Symfony\Component\Console for instance),
 * the autoloader will first look for the class under the component/
 * directory, and it will then fallback to the framework/ directory if not
 * found before giving up.
 *
 * This class is loosely based on the Symfony UniversalClassLoader.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Jordi Boggiano <j.boggiano@seld.be>
 * @see    https://www.php-fig.org/psr/psr-0/
 * @see    https://www.php-fig.org/psr/psr-4/
 */
class ClassLoader
{
    /** @var \Closure(string):void */
    private static $includeFile;

    /** @var ?string */
    private $vendorDir;

    // PSR-4
    /**
     * @var array[]
     * @psalm-var array<string, array<string, int>>
     */
    private $prefixLengthsPsr4 = array();
    /**
     * @var array[]
     * @psalm-var array<string, array<int, string>>
     */
    private $prefixDirsPsr4 = array();
    /**
     * @var array[]
     * @psalm-var array<string, string>
     */
    private $fallbackDirsPsr4 = array();

    // PSR-0
    /**
     * @var array[]
     * @psalm-var array<string, array<string, string[]>>
     */
    private $prefixesPsr0 = array();
    /**
     * @var array[]
     * @psalm-var array<string, string>
     */
    private $fallbackDirsPsr0 = array();

    /** @var bool */
    private $useIncludePath = false;

    /**
     * @var string[]
     * @psalm-var array<string, string>
     */
    private $classMap = array();

    /** @var bool */
    private $classMapAuthoritative = false;

    /**
     * @var bool[]
     * @psalm-var array<string, bool>
     */
    private $missingClasses = array();

    /** @var ?string */
    private $apcuPrefix;

    /**
     * @var self[]
     */
    private static $registeredLoaders = array();

    /**
     * @param ?string $vendorDir
     */
    public function __construct($vendorDir = null)
    {
        $this->vendorDir = $vendorDir;
        self::initializeIncludeClosure();
    }

    /**
     * @return string[]
     */
    public function getPrefixes()
    {
        if (!empty($this->prefixesPsr0)) {
            return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
        }

        return array();
    }

    /**
     * @return array[]
     * @psalm-return array<string, array<int, string>>
     */
    public function getPrefixesPsr4()
    {
        return $this->prefixDirsPsr4;
    }

    /**
     * @return array[]
     * @psalm-return array<string, string>
     */
    public function getFallbackDirs()
    {
        return $this->fallbackDirsPsr0;
    }

    /**
     * @return array[]
     * @psalm-return array<string, string>
     */
    public function getFallbackDirsPsr4()
    {
        return $this->fallbackDirsPsr4;
    }

    /**
     * @return string[] Array of classname => path
     * @psalm-return array<string, string>
     */
    public function getClassMap()
    {
        return $this->classMap;
    }

    /**
     * @param string[] $classMap Class to filename map
     * @psalm-param array<string, string> $classMap
     *
     * @return void
     */
    public function addClassMap(array $classMap)
    {
        if ($this->classMap) {
            $this->classMap = array_merge($this->classMap, $classMap);
        } else {
            $this->classMap = $classMap;
        }
    }

    /**
     * Registers a set of PSR-0 directories for a given prefix, either
     * appending or prepending to the ones previously set for this prefix.
     *
     * @param string          $prefix  The prefix
     * @param string[]|string $paths   The PSR-0 root directories
     * @param bool            $prepend Whether to prepend the directories
     *
     * @return void
     */
    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
            );
        }
    }

    /**
     * Registers a set of PSR-4 directories for a given namespace, either
     * appending or prepending to the ones previously set for this namespace.
     *
     * @param string          $prefix  The prefix/namespace, with trailing '\\'
     * @param string[]|string $paths   The PSR-4 base directories
     * @param bool            $prepend Whether to prepend the directories
     *
     * @throws \InvalidArgumentException
     *
     * @return void
     */
    public function addPsr4($prefix, $paths, $prepend = false)
    {
        if (!$prefix) {
            // Register directories for the root namespace.
            if ($prepend) {
                $this->fallbackDirsPsr4 = array_merge(
                    (array) $paths,
                    $this->fallbackDirsPsr4
                );
            } else {
                $this->fallbackDirsPsr4 = array_merge(
                    $this->fallbackDirsPsr4,
                    (array) $paths
                );
            }
        } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
            // Register directories for a new namespace.
            $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) {
            // Prepend directories for an already registered namespace.
            $this->prefixDirsPsr4[$prefix] = array_merge(
                (array) $paths,
                $this->prefixDirsPsr4[$prefix]
            );
        } else {
            // Append directories for an already registered namespace.
            $this->prefixDirsPsr4[$prefix] = array_merge(
                $this->prefixDirsPsr4[$prefix],
                (array) $paths
            );
        }
    }

    /**
     * Registers a set of PSR-0 directories for a given prefix,
     * replacing any others previously set for this prefix.
     *
     * @param string          $prefix The prefix
     * @param string[]|string $paths  The PSR-0 base directories
     *
     * @return void
     */
    public function set($prefix, $paths)
    {
        if (!$prefix) {
            $this->fallbackDirsPsr0 = (array) $paths;
        } else {
            $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
        }
    }

    /**
     * Registers a set of PSR-4 directories for a given namespace,
     * replacing any others previously set for this namespace.
     *
     * @param string          $prefix The prefix/namespace, with trailing '\\'
     * @param string[]|string $paths  The PSR-4 base directories
     *
     * @throws \InvalidArgumentException
     *
     * @return void
     */
    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;
        }
    }

    /**
     * Turns on searching the include path for class files.
     *
     * @param bool $useIncludePath
     *
     * @return void
     */
    public function setUseIncludePath($useIncludePath)
    {
        $this->useIncludePath = $useIncludePath;
    }

    /**
     * Can be used to check if the autoloader uses the include path to check
     * for classes.
     *
     * @return bool
     */
    public function getUseIncludePath()
    {
        return $this->useIncludePath;
    }

    /**
     * Turns off searching the prefix and fallback directories for classes
     * that have not been registered with the class map.
     *
     * @param bool $classMapAuthoritative
     *
     * @return void
     */
    public function setClassMapAuthoritative($classMapAuthoritative)
    {
        $this->classMapAuthoritative = $classMapAuthoritative;
    }

    /**
     * Should class lookup fail if not found in the current class map?
     *
     * @return bool
     */
    public function isClassMapAuthoritative()
    {
        return $this->classMapAuthoritative;
    }

    /**
     * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
     *
     * @param string|null $apcuPrefix
     *
     * @return void
     */
    public function setApcuPrefix($apcuPrefix)
    {
        $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
    }

    /**
     * The APCu prefix in use, or null if APCu caching is not enabled.
     *
     * @return string|null
     */
    public function getApcuPrefix()
    {
        return $this->apcuPrefix;
    }

    /**
     * Registers this instance as an autoloader.
     *
     * @param bool $prepend Whether to prepend the autoloader or not
     *
     * @return void
     */
    public function register($prepend = false)
    {
        spl_autoload_register(array($this, 'loadClass'), true, $prepend);

        if (null === $this->vendorDir) {
            return;
        }

        if ($prepend) {
            self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
        } else {
            unset(self::$registeredLoaders[$this->vendorDir]);
            self::$registeredLoaders[$this->vendorDir] = $this;
        }
    }

    /**
     * Unregisters this instance as an autoloader.
     *
     * @return void
     */
    public function unregister()
    {
        spl_autoload_unregister(array($this, 'loadClass'));

        if (null !== $this->vendorDir) {
            unset(self::$registeredLoaders[$this->vendorDir]);
        }
    }

    /**
     * Loads the given class or interface.
     *
     * @param  string    $class The name of the class
     * @return true|null True if loaded, null otherwise
     */
    public function loadClass($class)
    {
        if ($file = $this->findFile($class)) {
            $includeFile = self::$includeFile;
            $includeFile($file);

            return true;
        }

        return null;
    }

    /**
     * Finds the path to the file where the class is defined.
     *
     * @param string $class The name of the class
     *
     * @return string|false The path if found, false otherwise
     */
    public function findFile($class)
    {
        // class map lookup
        if (isset($this->classMap[$class])) {
            return $this->classMap[$class];
        }
        if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
            return false;
        }
        if (null !== $this->apcuPrefix) {
            $file = apcu_fetch($this->apcuPrefix.$class, $hit);
            if ($hit) {
                return $file;
            }
        }

        $file = $this->findFileWithExtension($class, '.php');

        // Search for Hack files if we are running on HHVM
        if (false === $file && defined('HHVM_VERSION')) {
            $file = $this->findFileWithExtension($class, '.hh');
        }

        if (null !== $this->apcuPrefix) {
            apcu_add($this->apcuPrefix.$class, $file);
        }

        if (false === $file) {
            // Remember that this class does not exist.
            $this->missingClasses[$class] = true;
        }

        return $file;
    }

    /**
     * Returns the currently registered loaders indexed by their corresponding vendor directories.
     *
     * @return self[]
     */
    public static function getRegisteredLoaders()
    {
        return self::$registeredLoaders;
    }

    /**
     * @param  string       $class
     * @param  string       $ext
     * @return string|false
     */
    private function findFileWithExtension($class, $ext)
    {
        // PSR-4 lookup
        $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;

        $first = $class[0];
        if (isset($this->prefixLengthsPsr4[$first])) {
            $subPath = $class;
            while (false !== $lastPos = strrpos($subPath, '\\')) {
                $subPath = substr($subPath, 0, $lastPos);
                $search = $subPath . '\\';
                if (isset($this->prefixDirsPsr4[$search])) {
                    $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
                    foreach ($this->prefixDirsPsr4[$search] as $dir) {
                        if (file_exists($file = $dir . $pathEnd)) {
                            return $file;
                        }
                    }
                }
            }
        }

        // PSR-4 fallback dirs
        foreach ($this->fallbackDirsPsr4 as $dir) {
            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
                return $file;
            }
        }

        // PSR-0 lookup
        if (false !== $pos = strrpos($class, '\\')) {
            // namespaced class name
            $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
                . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
        } else {
            // PEAR-like class name
            $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;
                        }
                    }
                }
            }
        }

        // PSR-0 fallback dirs
        foreach ($this->fallbackDirsPsr0 as $dir) {
            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
                return $file;
            }
        }

        // PSR-0 include paths.
        if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
            return $file;
        }

        return false;
    }

    /**
     * @return void
     */
    private static function initializeIncludeClosure()
    {
        if (self::$includeFile !== null) {
            return;
        }

        /**
         * Scope isolated include.
         *
         * Prevents access to $this/self from included files.
         *
         * @param  string $file
         * @return void
         */
        self::$includeFile = \Closure::bind(static function($file) {
            include $file;
        }, null, null);
    }
}

Copyright (c) Nils Adermann, Jordi Boggiano

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

<?php

// autoload_namespaces.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
);
<?php

// autoload.php @generated by Composer

if (PHP_VERSION_ID < 50600) {
    if (!headers_sent()) {
        header('HTTP/1.1 500 Internal Server Error');
    }
    $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
    if (!ini_get('display_errors')) {
        if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
            fwrite(STDERR, $err);
        } elseif (!headers_sent()) {
            echo $err;
        }
    }
    trigger_error(
        $err,
        E_USER_ERROR
    );
}

require_once __DIR__ . '/composer/autoload_real.php';

return ComposerAutoloaderInitHumbugBox436::getLoader();
<?php

declare (strict_types=1);
namespace HumbugBox436\KevinGH\RequirementChecker;

use InvalidArgumentException;
use function count;
use function sprintf;
final class Checker
{
    private static $requirementsConfig;
    public static function checkRequirements() : bool
    {
        $requirements = self::retrieveRequirements();
        $checkPassed = $requirements->evaluateRequirements();
        $io = new IO();
        self::printCheck($checkPassed, new Printer($io->getVerbosity(), $io->hasColorSupport()), $requirements);
        return $checkPassed;
    }
    public static function printCheck($checkPassed, Printer $printer, RequirementCollection $requirements) : void
    {
        if (\false === $checkPassed && IO::VERBOSITY_VERY_VERBOSE > $printer->getVerbosity()) {
            $printer->setVerbosity(IO::VERBOSITY_VERY_VERBOSE);
        }
        $verbosity = IO::VERBOSITY_VERY_VERBOSE;
        $iniPath = $requirements->getPhpIniPath();
        $printer->title('Box Requirements Checker', $verbosity);
        $printer->printv('> Using PHP ', $verbosity);
        $printer->printvln(\PHP_VERSION, $verbosity, 'green');
        $printer->printvln('> PHP is using the following php.ini file:', $verbosity);
        if ($iniPath) {
            $printer->printvln('  ' . $iniPath, $verbosity, 'green');
        } else {
            $printer->printvln('  WARNING: No configuration file (php.ini) used by PHP!', $verbosity, 'yellow');
        }
        $printer->printvln('', $verbosity);
        if (count($requirements) > 0) {
            $printer->printvln('> Checking Box requirements:', $verbosity);
            $printer->printv('  ', $verbosity);
        } else {
            $printer->printvln('> No requirements found.', $verbosity);
        }
        $errorMessages = [];
        foreach ($requirements->getRequirements() as $requirement) {
            if ($errorMessage = $printer->getRequirementErrorMessage($requirement)) {
                if (IO::VERBOSITY_DEBUG === $printer->getVerbosity()) {
                    $printer->printvln('âœ˜ ' . $requirement->getTestMessage(), IO::VERBOSITY_DEBUG, 'red');
                    $printer->printv('  ', IO::VERBOSITY_DEBUG);
                    $errorMessages[] = $errorMessage;
                } else {
                    $printer->printv('E', $verbosity, 'red');
                    $errorMessages[] = $errorMessage;
                }
                continue;
            }
            if (IO::VERBOSITY_DEBUG === $printer->getVerbosity()) {
                $printer->printvln('âœ” ' . $requirement->getTestMessage(), IO::VERBOSITY_DEBUG, 'green');
                $printer->printv('  ', IO::VERBOSITY_DEBUG);
            } else {
                $printer->printv('.', $verbosity, 'green');
            }
        }
        if (IO::VERBOSITY_DEBUG !== $printer->getVerbosity() && count($requirements) > 0) {
            $printer->printvln('', $verbosity);
        }
        if ($requirements->evaluateRequirements()) {
            $printer->block('OK', 'Your system is ready to run the application.', $verbosity, 'success');
        } else {
            $printer->block('ERROR', 'Your system is not ready to run the application.', $verbosity, 'error');
            $printer->title('Fix the following mandatory requirements:', $verbosity, 'red');
            foreach ($errorMessages as $errorMessage) {
                $printer->printv(' * ' . $errorMessage, $verbosity);
            }
        }
        $printer->printvln('', $verbosity);
    }
    private static function retrieveRequirements() : RequirementCollection
    {
        if (null === self::$requirementsConfig) {
            self::$requirementsConfig = __DIR__ . '/../.requirements.php';
        }
        $config = (require self::$requirementsConfig);
        $requirements = new RequirementCollection();
        foreach ($config as $constraint) {
            $requirements->addRequirement(self::createCondition($constraint['type'], $constraint['condition']), $constraint['message'], $constraint['helpMessage']);
        }
        return $requirements;
    }
    private static function createCondition($type, $condition) : IsFulfilled
    {
        switch ($type) {
            case 'php':
                return new IsPhpVersionFulfilled($condition);
            case 'extension':
                return new IsExtensionFulfilled($condition);
            case 'extension-conflict':
                return new IsExtensionConflictFulfilled($condition);
            default:
                throw new InvalidArgumentException(sprintf('Unknown requirement type "%s".', $type));
        }
    }
}
<?php

declare (strict_types=1);
namespace HumbugBox436\KevinGH\RequirementChecker;

use function array_shift;
use function count;
use function explode;
use function ltrim;
use function min;
use function sprintf;
use function str_pad;
use function str_repeat;
use function strlen;
use function trim;
use function wordwrap;
use const PHP_EOL;
final class Printer
{
    private $styles = ['reset' => "\x1b[0m", 'red' => "\x1b[31m", 'green' => "\x1b[32m", 'yellow' => "\x1b[33m", 'title' => "\x1b[33m", 'error' => "\x1b[37;41m", 'success' => "\x1b[30;42m"];
    private $verbosity;
    private $supportColors;
    private $width;
    public function __construct(int $verbosity, bool $supportColors, ?int $width = null)
    {
        if (null === $width) {
            $terminal = new Terminal();
            $width = $terminal->getWidth();
        }
        $this->verbosity = $verbosity;
        $this->supportColors = $supportColors;
        $this->width = $width ?: 80;
    }
    public function getVerbosity() : int
    {
        return $this->verbosity;
    }
    public function setVerbosity($verbosity) : void
    {
        $this->verbosity = $verbosity;
    }
    public function title(string $title, int $verbosity, ?string $style = null) : void
    {
        if (null === $style) {
            $style = 'title';
        }
        $this->printvln('', $verbosity, $style);
        $this->printvln($title, $verbosity, $style);
        $this->printvln(str_repeat('=', min(strlen($title), $this->width)), $verbosity, $style);
        $this->printvln('', $verbosity, $style);
    }
    public function getRequirementErrorMessage(Requirement $requirement) : ?string
    {
        if ($requirement->isFulfilled()) {
            return null;
        }
        return wordwrap($requirement->getHelpText(), $this->width - 3, PHP_EOL . '   ') . PHP_EOL;
    }
    public function block(string $title, string $message, int $verbosity, ?string $style = null) : void
    {
        $prefix = ' [' . $title . '] ';
        $lineLength = $this->width - strlen($prefix) - 1;
        if ($lineLength < 0) {
            $lineLength = 0;
        }
        $message = $prefix . trim($message);
        $lines = [];
        $remainingMessage = $message;
        $wrapped = wordwrap($remainingMessage, $lineLength, 'Â¬');
        $wrapped = explode('Â¬', $wrapped);
        do {
            $line = array_shift($wrapped);
            if ($lines && $lineLength > 0) {
                $line = str_repeat(' ', strlen($prefix)) . ltrim($line);
            }
            $lines[] = str_pad($line, $this->width, ' ', \STR_PAD_RIGHT);
        } while (count($wrapped));
        $this->printvln('', $verbosity);
        $this->printvln(str_repeat(' ', $this->width), $verbosity, $style);
        foreach ($lines as $line) {
            $this->printvln($line, $verbosity, $style);
        }
        $this->printv(str_repeat(' ', $this->width), $verbosity, $style);
        $this->printvln('', $verbosity);
    }
    public function printvln(string $message, int $verbosity, ?string $style = null) : void
    {
        $this->printv($message, $verbosity, $style);
        $this->printv(PHP_EOL, $verbosity, null);
    }
    public function printv(string $message, int $verbosity, ?string $style = null) : void
    {
        if ($verbosity > $this->verbosity) {
            return;
        }
        $message = wordwrap($message, $this->width);
        $message = sprintf('%s%s%s', $this->supportColors && isset($this->styles[$style]) ? $this->styles[$style] : '', $message, $this->supportColors ? $this->styles['reset'] : '');
        if ('1' === \getenv('BOX_REQUIREMENTS_CHECKER_LOG_TO_STDOUT')) {
            echo $message;
        } else {
            \fwrite(\STDERR, $message);
        }
    }
}
<?php

declare (strict_types=1);
namespace HumbugBox436\KevinGH\RequirementChecker;

use function exec;
use function fclose;
use function fopen;
use function function_exists;
use function getenv;
use function is_resource;
use function preg_match;
use function proc_close;
use function proc_open;
use function sapi_windows_vt100_support;
use function stream_get_contents;
use function trim;
use const DIRECTORY_SEPARATOR;
class Terminal
{
    private static $width;
    private static $height;
    private static $stty;
    public function getWidth() : int
    {
        $width = getenv('COLUMNS');
        if (\false !== $width) {
            return (int) trim($width);
        }
        if (!isset(self::$width)) {
            self::initDimensions();
        }
        return self::$width ?: 80;
    }
    public function getHeight() : int
    {
        $height = getenv('LINES');
        if (\false !== $height) {
            return (int) trim($height);
        }
        if (!isset(self::$height)) {
            self::initDimensions();
        }
        return self::$height ?: 50;
    }
    public static function hasSttyAvailable() : bool
    {
        if (isset(self::$stty)) {
            return self::$stty;
        }
        if (!function_exists('exec')) {
            return \false;
        }
        exec('stty 2>&1', $output, $exitcode);
        return self::$stty = 0 === $exitcode;
    }
    private static function initDimensions() : void
    {
        if ('\\' === DIRECTORY_SEPARATOR) {
            if (preg_match('/^(\\d+)x(\\d+)(?: \\((\\d+)x(\\d+)\\))?$/', trim(getenv('ANSICON')), $matches)) {
                self::$width = (int) $matches[1];
                self::$height = isset($matches[4]) ? (int) $matches[4] : (int) $matches[2];
            } elseif (!self::hasVt100Support() && self::hasSttyAvailable()) {
                self::initDimensionsUsingStty();
            } elseif (null !== ($dimensions = self::getConsoleMode())) {
                self::$width = (int) $dimensions[0];
                self::$height = (int) $dimensions[1];
            }
        } else {
            self::initDimensionsUsingStty();
        }
    }
    private static function hasVt100Support() : bool
    {
        return function_exists('sapi_windows_vt100_support') && sapi_windows_vt100_support(fopen('php://stdout', 'wb'));
    }
    private static function initDimensionsUsingStty() : void
    {
        if ($sttyString = self::getSttyColumns()) {
            if (preg_match('/rows.(\\d+);.columns.(\\d+);/i', $sttyString, $matches)) {
                self::$width = (int) $matches[2];
                self::$height = (int) $matches[1];
            } elseif (preg_match('/;.(\\d+).rows;.(\\d+).columns/i', $sttyString, $matches)) {
                self::$width = (int) $matches[2];
                self::$height = (int) $matches[1];
            }
        }
    }
    private static function getConsoleMode() : ?array
    {
        $info = self::readFromProcess('mode CON');
        if (null === $info || !preg_match('/--------+\\r?\\n.+?(\\d+)\\r?\\n.+?(\\d+)\\r?\\n/', $info, $matches)) {
            return null;
        }
        return [(int) $matches[2], (int) $matches[1]];
    }
    private static function getSttyColumns() : ?string
    {
        return self::readFromProcess('stty -a | grep columns');
    }
    private static function readFromProcess(string $command) : ?string
    {
        if (!function_exists('proc_open')) {
            return null;
        }
        $descriptorspec = [1 => ['pipe', 'w'], 2 => ['pipe', 'w']];
        $process = proc_open($command, $descriptorspec, $pipes, null, null, ['suppress_errors' => \true]);
        if (!is_resource($process)) {
            return null;
        }
        $info = stream_get_contents($pipes[1]);
        fclose($pipes[1]);
        fclose($pipes[2]);
        proc_close($process);
        return $info;
    }
}
<?php

declare (strict_types=1);
namespace HumbugBox436\KevinGH\RequirementChecker;

use function fstat;
use function function_exists;
use function getenv;
use function implode;
use function posix_isatty;
use function preg_match;
use function preg_quote;
use function sapi_windows_vt100_support;
use function sprintf;
use function str_replace;
use function stream_isatty;
use const DIRECTORY_SEPARATOR;
use const STDOUT;
final class IO
{
    public const VERBOSITY_QUIET = 16;
    public const VERBOSITY_NORMAL = 32;
    public const VERBOSITY_VERBOSE = 64;
    public const VERBOSITY_VERY_VERBOSE = 128;
    public const VERBOSITY_DEBUG = 256;
    private $interactive;
    private $verbosity = self::VERBOSITY_NORMAL;
    private $colorSupport;
    private $options;
    public function __construct()
    {
        $this->options = implode(' ', $_SERVER['argv']);
        $shellVerbosity = $this->configureVerbosity();
        $this->interactive = $this->checkInteractivity($shellVerbosity);
        $this->colorSupport = $this->checkColorSupport();
    }
    public function isInteractive() : bool
    {
        return $this->interactive;
    }
    public function getVerbosity() : int
    {
        return $this->verbosity;
    }
    public function hasColorSupport() : bool
    {
        return $this->colorSupport;
    }
    public function hasParameter($values) : bool
    {
        $values = (array) $values;
        foreach ($values as $value) {
            $regexp = sprintf('/\\s%s\\b/', str_replace(' ', '\\s+', preg_quote($value, '/')));
            if (1 === preg_match($regexp, $this->options)) {
                return \true;
            }
        }
        return \false;
    }
    private function checkInteractivity(int $shellVerbosity) : bool
    {
        if (-1 === $shellVerbosity) {
            return \false;
        }
        if (\true === $this->hasParameter(['--no-interaction', '-n'])) {
            return \false;
        }
        if (function_exists('posix_isatty') && !@posix_isatty(STDOUT) && \false === getenv('SHELL_INTERACTIVE')) {
            return \false;
        }
        return \true;
    }
    private function configureVerbosity() : int
    {
        switch ($shellVerbosity = (int) getenv('SHELL_VERBOSITY')) {
            case -1:
                $this->verbosity = self::VERBOSITY_QUIET;
                break;
            case 1:
                $this->verbosity = self::VERBOSITY_VERBOSE;
                break;
            case 2:
                $this->verbosity = self::VERBOSITY_VERY_VERBOSE;
                break;
            case 3:
                $this->verbosity = self::VERBOSITY_DEBUG;
                break;
            default:
                $shellVerbosity = 0;
                break;
        }
        if ($this->hasParameter(['--quiet', '-q'])) {
            $this->verbosity = self::VERBOSITY_QUIET;
            $shellVerbosity = -1;
        } elseif ($this->hasParameter(['-vvv', '--verbose=3', '--verbose 3'])) {
            $this->verbosity = self::VERBOSITY_DEBUG;
            $shellVerbosity = 3;
        } elseif ($this->hasParameter(['-vv', '--verbose=2', '--verbose 2'])) {
            $this->verbosity = self::VERBOSITY_VERY_VERBOSE;
            $shellVerbosity = 2;
        } elseif ($this->hasParameter(['-v', '--verbose=1', '--verbose 1', '--verbose'])) {
            $this->verbosity = self::VERBOSITY_VERBOSE;
            $shellVerbosity = 1;
        }
        return $shellVerbosity;
    }
    private function checkColorSupport() : bool
    {
        if ($this->hasParameter(['--ansi'])) {
            return \true;
        }
        if ($this->hasParameter(['--no-ansi'])) {
            return \false;
        }
        if (DIRECTORY_SEPARATOR === '\\') {
            return function_exists('sapi_windows_vt100_support') && sapi_windows_vt100_support(STDOUT) || \false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI') || 'xterm' === getenv('TERM');
        }
        if (function_exists('stream_isatty')) {
            return stream_isatty(STDOUT);
        }
        if (function_exists('posix_isatty')) {
            return posix_isatty(STDOUT);
        }
        $stat = fstat(STDOUT);
        return $stat ? 020000 === ($stat['mode'] & 0170000) : \false;
    }
}
<?php

declare (strict_types=1);
namespace HumbugBox436\KevinGH\RequirementChecker;

use HumbugBox436\Composer\Semver\Semver;
use function sprintf;
use const PHP_MAJOR_VERSION;
use const PHP_MINOR_VERSION;
use const PHP_RELEASE_VERSION;
final class IsPhpVersionFulfilled implements IsFulfilled
{
    private $requiredPhpVersion;
    public function __construct(string $requiredPhpVersion)
    {
        $this->requiredPhpVersion = $requiredPhpVersion;
    }
    public function __invoke() : bool
    {
        return Semver::satisfies(sprintf('%d.%d.%d', PHP_MAJOR_VERSION, PHP_MINOR_VERSION, PHP_RELEASE_VERSION), $this->requiredPhpVersion);
    }
}
<?php

declare (strict_types=1);
namespace HumbugBox436\KevinGH\RequirementChecker;

final class Requirement
{
    private $checkIsFulfilled;
    private $fulfilled;
    private $testMessage;
    private $helpText;
    public function __construct(IsFulfilled $checkIsFulfilled, string $testMessage, string $helpText)
    {
        $this->checkIsFulfilled = $checkIsFulfilled;
        $this->testMessage = $testMessage;
        $this->helpText = $helpText;
    }
    public function isFulfilled() : bool
    {
        if (!isset($this->fulfilled)) {
            $this->fulfilled = $this->checkIsFulfilled->__invoke();
        }
        return $this->fulfilled;
    }
    public function getIsFullfilledChecker() : IsFulfilled
    {
        return $this->checkIsFulfilled;
    }
    public function getTestMessage() : string
    {
        return $this->testMessage;
    }
    public function getHelpText() : string
    {
        return $this->helpText;
    }
}
<?php

declare (strict_types=1);
namespace HumbugBox436\KevinGH\RequirementChecker;

use function extension_loaded;
final class IsExtensionConflictFulfilled implements IsFulfilled
{
    private $conflictingExtension;
    public function __construct(string $requiredExtension)
    {
        $this->conflictingExtension = $requiredExtension;
    }
    public function __invoke() : bool
    {
        return !extension_loaded($this->conflictingExtension);
    }
}
<?php

declare (strict_types=1);
namespace HumbugBox436\KevinGH\RequirementChecker;

use function extension_loaded;
final class IsExtensionFulfilled implements IsFulfilled
{
    private $requiredExtension;
    public function __construct(string $requiredExtension)
    {
        $this->requiredExtension = $requiredExtension;
    }
    public function __invoke() : bool
    {
        return extension_loaded($this->requiredExtension);
    }
}
<?php

declare (strict_types=1);
namespace HumbugBox436\KevinGH\RequirementChecker;

use ArrayIterator;
use Countable;
use IteratorAggregate;
use Traversable;
use function count;
use function get_cfg_var;
final class RequirementCollection implements IteratorAggregate, Countable
{
    private $requirements = [];
    public function getIterator() : Traversable
    {
        return new ArrayIterator($this->requirements);
    }
    public function count() : int
    {
        return count($this->requirements);
    }
    public function add(Requirement $requirement) : void
    {
        $this->requirements[] = $requirement;
    }
    public function addRequirement(IsFulfilled $checkIsFulfilled, string $testMessage, string $helpText) : void
    {
        $this->add(new Requirement($checkIsFulfilled, $testMessage, $helpText));
    }
    public function getRequirements() : array
    {
        return $this->requirements;
    }
    public function getPhpIniPath()
    {
        return get_cfg_var('cfg_file_path');
    }
    public function evaluateRequirements()
    {
        return \array_reduce($this->requirements, function (bool $checkPassed, Requirement $requirement) : bool {
            return $checkPassed && $requirement->isFulfilled();
        }, \true);
    }
}
<?php

declare (strict_types=1);
namespace HumbugBox436\KevinGH\RequirementChecker;

interface IsFulfilled
{
    public function __invoke() : bool;
}
<?php

namespace _HumbugBox89e0edca2b33;

return array (
  0 => 
  array (
    'type' => 'php',
    'condition' => '>=7.3.0',
    'message' => 'The application requires a version matching ">=7.3.0".',
    'helpMessage' => 'The application requires a version matching ">=7.3.0".',
  ),
  1 => 
  array (
    'type' => 'extension',
    'condition' => 'json',
    'message' => 'The package "civicrm/cv-lib" requires the extension "json".',
    'helpMessage' => 'The package "civicrm/cv-lib" requires the extension "json". You either need to enable it or request the application to be shipped with a polyfill for this extension.',
  ),
);<?php

namespace HumbugBox436\KevinGH\RequirementChecker;

if (isset($_SERVER['BOX_REQUIREMENT_CHECKER'])) {
    $enableRequirementChecker = $_SERVER['BOX_REQUIREMENT_CHECKER'];
    if (\is_bool($enableRequirementChecker) && !$enableRequirementChecker) {
        return;
    }
    if (\is_string($enableRequirementChecker) && \in_array(\strtolower($enableRequirementChecker), ['false', '0'], \true)) {
        return;
    }
    if (!\is_bool($enableRequirementChecker) && !\is_string($enableRequirementChecker)) {
        echo \PHP_EOL . 'Unhandled value type for "BOX_REQUIREMENT_CHECKER". Got "' . \gettype($enableRequirementChecker) . '". Proceeding with the requirement checks.' . \PHP_EOL;
    }
}
if (\false === \in_array(\PHP_SAPI, array('cli', 'phpdbg', 'embed', 'micro'), \true)) {
    echo \PHP_EOL . 'The application may only be invoked from a command line, got "' . \PHP_SAPI . '"' . \PHP_EOL;
    exit(1);
}
require __DIR__ . '/../vendor/autoload.php';
if (!Checker::checkRequirements()) {
    exit(1);
}
<?php

namespace CivixPhar;

/**
 * Mirror a select list of backports from `civicrm-core:mixin/`.
 */
return ['polyfill' => [
    'sha256' => '4a60b871ca6ef75172459667e130d0692998d10b6ee59cfc3be541e50d0da3f7',
    'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/f55a0e7978c92e76c18cd613ece11489052b5b33/mixin/polyfill.php',
    // ^^ This link can be updated when there is tag for 5.58.
    'local' => 'extern/mixin/polyfill.php',
    'provided-by' => '5.45.beta1',
    'minimum' => '5.27',
], 'afform-entity-php@1' => ['version' => '1.0.0', 'sha256' => '1f737bc96e019dac459aade88206778cf141c59d322d5aa56c02ee4afb9eb649', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.50.0/mixin/afform-entity-php@1/mixin.php', 'local' => 'extern/mixin/afform-entity-php@1/mixin.php', 'provided-by' => '5.50.beta1', 'minimum' => '5.31'], 'ang-php@1' => ['version' => '1.0.0', 'sha256' => '7dc91fab620fc6ba74a5a00347a2d8f39846c97c8cf20cf4291a1002d3d9c245', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.45.3/mixin/ang-php@1/mixin.php', 'local' => 'extern/mixin/ang-php@1/mixin.php', 'provided-by' => '5.45.beta1', 'minimum' => '5.27'], 'case-xml@1' => ['version' => '1.0.0', 'sha256' => '23a4f7d128b286c79acf20598a9017a0fac213115a64504d8f84c2096ce1f490', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.45.3/mixin/case-xml@1/mixin.php', 'local' => 'extern/mixin/case-xml@1/mixin.php', 'provided-by' => '5.45.beta1', 'minimum' => '5.27'], 'entity-types-php@1' => ['version' => '1.0.0', 'sha256' => 'f8e10aac991b2b3acac269a1fca81f883a295908990687959e790885a2e410c2', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.57.0/mixin/entity-types-php%401/mixin.php', 'local' => 'extern/mixin/entity-types-php@1/mixin.php', 'provided-by' => '5.57.beta1', 'minimum' => '5.45'], 'menu-xml@1' => ['version' => '1.0.0', 'sha256' => '4f5be44d6764816b22d0a5cdc2e047cfd9ec4acf48e548f82bb20c05db933d0e', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.45.3/mixin/menu-xml@1/mixin.php', 'local' => 'extern/mixin/menu-xml@1/mixin.php', 'provided-by' => '5.45.beta1', 'minimum' => '5.27'], 'mgd-php@1' => ['version' => '1.0.0', 'sha256' => '458fef1ae4b649bae7826bfc9f3b7d55c6a3f577d2eae4cbc1c520c48d6d4d7d', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.45.3/mixin/mgd-php@1/mixin.php', 'local' => 'extern/mixin/mgd-php@1/mixin.php', 'provided-by' => '5.45.beta1', 'minimum' => '5.27'], 'scan-classes@1' => [
    // scan-calsses is not meaningful to backport, but tracking metadata helps with admin.
    'version' => '1.0.0',
    'sha256' => '68b543079255d3d92773a5d75f5b033b3227b595337ece207f6dec865a54f0c4',
    'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/4b0558d911bfcbd81e1f5199b0eb0c837c7c8205/mixin/scan-classes@1/mixin.php',
    'local' => 'extern/mixin/scan-classes@1/mixin.php',
    'provided-by' => '5.51.beta2',
    'minimum' => '5.51',
], 'setting-php@1' => ['version' => '1.0.0', 'sha256' => '5ce236c1a1a63637ce5f0f4fe5bf7f21eaa06c750ca16c0fbf4dd792da0d23c9', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.45.3/mixin/setting-php@1/mixin.php', 'local' => 'extern/mixin/setting-php@1/mixin.php', 'provided-by' => '5.45.beta1', 'minimum' => '5.27'], 'smarty-v2@1' => ['version' => '1.0.1', 'sha256' => '6b1e05facc17d414d8e99faf5bdd9fe694ff92cc3d7f9a05e2fe6fc63e3d1948', 'remote' => 'https://github.com/civicrm/civicrm-core/raw/7168793c03ef57c06bbfe45f5ff873ebb3657806/mixin/smarty-v2%401/mixin.php', 'local' => 'extern/mixin/smarty-v2@1/mixin.php', 'provided-by' => '5.59', 'minimum' => '5.27'], 'theme-php@1' => ['version' => '1.0.0', 'sha256' => '2d4bd2442fde152c8f31805ac265c2249d5cf771185f1ac870fd1fcbb18db3ed', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.45.3/mixin/theme-php@1/mixin.php', 'local' => 'extern/mixin/theme-php@1/mixin.php', 'provided-by' => '5.45.beta1', 'minimum' => '5.27']];
<?php

namespace CivixPhar;

/**
 * Mirror a select list of backports from `civicrm-core:mixin/`.
 */
return ['polyfill' => [
    'sha256' => '4a60b871ca6ef75172459667e130d0692998d10b6ee59cfc3be541e50d0da3f7',
    'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/f55a0e7978c92e76c18cd613ece11489052b5b33/mixin/polyfill.php',
    // ^^ This link can be updated when there is tag for 5.58.
    'local' => 'extern/mixin/polyfill.php',
    'provided-by' => '5.45.beta1',
    'minimum' => '5.27',
], 'afform-entity-php@1' => ['version' => '1.0.0', 'sha256' => '1f737bc96e019dac459aade88206778cf141c59d322d5aa56c02ee4afb9eb649', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.50.0/mixin/afform-entity-php@1/mixin.php', 'local' => 'extern/mixin/afform-entity-php@1/mixin.php', 'provided-by' => '5.50.beta1', 'minimum' => '5.31'], 'ang-php@1' => ['version' => '1.0.0', 'sha256' => '7dc91fab620fc6ba74a5a00347a2d8f39846c97c8cf20cf4291a1002d3d9c245', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.45.3/mixin/ang-php@1/mixin.php', 'local' => 'extern/mixin/ang-php@1/mixin.php', 'provided-by' => '5.45.beta1', 'minimum' => '5.27'], 'case-xml@1' => ['version' => '1.0.0', 'sha256' => '23a4f7d128b286c79acf20598a9017a0fac213115a64504d8f84c2096ce1f490', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.45.3/mixin/case-xml@1/mixin.php', 'local' => 'extern/mixin/case-xml@1/mixin.php', 'provided-by' => '5.45.beta1', 'minimum' => '5.27'], 'entity-types-php@1' => ['version' => '1.0.0', 'sha256' => 'f8e10aac991b2b3acac269a1fca81f883a295908990687959e790885a2e410c2', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.57.0/mixin/entity-types-php%401/mixin.php', 'local' => 'extern/mixin/entity-types-php@1/mixin.php', 'provided-by' => '5.57.beta1', 'minimum' => '5.45'], 'menu-xml@1' => ['version' => '1.0.0', 'sha256' => '4f5be44d6764816b22d0a5cdc2e047cfd9ec4acf48e548f82bb20c05db933d0e', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.45.3/mixin/menu-xml@1/mixin.php', 'local' => 'extern/mixin/menu-xml@1/mixin.php', 'provided-by' => '5.45.beta1', 'minimum' => '5.27'], 'mgd-php@1' => ['version' => '1.0.0', 'sha256' => '458fef1ae4b649bae7826bfc9f3b7d55c6a3f577d2eae4cbc1c520c48d6d4d7d', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.45.3/mixin/mgd-php@1/mixin.php', 'local' => 'extern/mixin/mgd-php@1/mixin.php', 'provided-by' => '5.45.beta1', 'minimum' => '5.27'], 'scan-classes@1' => [
    // scan-calsses is not meaningful to backport, but tracking metadata helps with admin.
    'version' => '1.0.0',
    'sha256' => '68b543079255d3d92773a5d75f5b033b3227b595337ece207f6dec865a54f0c4',
    'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/4b0558d911bfcbd81e1f5199b0eb0c837c7c8205/mixin/scan-classes@1/mixin.php',
    'local' => 'extern/mixin/scan-classes@1/mixin.php',
    'provided-by' => '5.51.beta2',
    'minimum' => '5.51',
], 'setting-php@1' => ['version' => '1.0.0', 'sha256' => '5ce236c1a1a63637ce5f0f4fe5bf7f21eaa06c750ca16c0fbf4dd792da0d23c9', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.45.3/mixin/setting-php@1/mixin.php', 'local' => 'extern/mixin/setting-php@1/mixin.php', 'provided-by' => '5.45.beta1', 'minimum' => '5.27'], 'smarty-v2@1' => ['version' => '1.0.1', 'sha256' => '6b1e05facc17d414d8e99faf5bdd9fe694ff92cc3d7f9a05e2fe6fc63e3d1948', 'remote' => 'https://github.com/civicrm/civicrm-core/raw/7168793c03ef57c06bbfe45f5ff873ebb3657806/mixin/smarty-v2%401/mixin.php', 'local' => 'extern/mixin/smarty-v2@1/mixin.php', 'provided-by' => '5.59', 'minimum' => '5.27'], 'theme-php@1' => ['version' => '1.0.0', 'sha256' => '2d4bd2442fde152c8f31805ac265c2249d5cf771185f1ac870fd1fcbb18db3ed', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.45.3/mixin/theme-php@1/mixin.php', 'local' => 'extern/mixin/theme-php@1/mixin.php', 'provided-by' => '5.45.beta1', 'minimum' => '5.27']];
<?php

namespace CivixPhar;

/**
 * Mirror a select list of backports from `civicrm-core:mixin/`.
 */
return ['polyfill' => [
    'sha256' => '4a60b871ca6ef75172459667e130d0692998d10b6ee59cfc3be541e50d0da3f7',
    'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/f55a0e7978c92e76c18cd613ece11489052b5b33/mixin/polyfill.php',
    // ^^ This link can be updated when there is tag for 5.58.
    'local' => 'extern/mixin/polyfill.php',
    'provided-by' => '5.45.beta1',
    'minimum' => '5.27',
], 'afform-entity-php@1' => ['version' => '1.0.0', 'sha256' => '1f737bc96e019dac459aade88206778cf141c59d322d5aa56c02ee4afb9eb649', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.50.0/mixin/afform-entity-php@1/mixin.php', 'local' => 'extern/mixin/afform-entity-php@1/mixin.php', 'provided-by' => '5.50.beta1', 'minimum' => '5.31'], 'ang-php@1' => ['version' => '1.0.0', 'sha256' => '7dc91fab620fc6ba74a5a00347a2d8f39846c97c8cf20cf4291a1002d3d9c245', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.45.3/mixin/ang-php@1/mixin.php', 'local' => 'extern/mixin/ang-php@1/mixin.php', 'provided-by' => '5.45.beta1', 'minimum' => '5.27'], 'case-xml@1' => ['version' => '1.0.0', 'sha256' => '23a4f7d128b286c79acf20598a9017a0fac213115a64504d8f84c2096ce1f490', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.45.3/mixin/case-xml@1/mixin.php', 'local' => 'extern/mixin/case-xml@1/mixin.php', 'provided-by' => '5.45.beta1', 'minimum' => '5.27'], 'entity-types-php@1' => ['version' => '1.0.0', 'sha256' => 'f8e10aac991b2b3acac269a1fca81f883a295908990687959e790885a2e410c2', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.57.0/mixin/entity-types-php%401/mixin.php', 'local' => 'extern/mixin/entity-types-php@1/mixin.php', 'provided-by' => '5.57.beta1', 'minimum' => '5.45'], 'menu-xml@1' => ['version' => '1.0.0', 'sha256' => '4f5be44d6764816b22d0a5cdc2e047cfd9ec4acf48e548f82bb20c05db933d0e', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.45.3/mixin/menu-xml@1/mixin.php', 'local' => 'extern/mixin/menu-xml@1/mixin.php', 'provided-by' => '5.45.beta1', 'minimum' => '5.27'], 'mgd-php@1' => ['version' => '1.0.0', 'sha256' => '458fef1ae4b649bae7826bfc9f3b7d55c6a3f577d2eae4cbc1c520c48d6d4d7d', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.45.3/mixin/mgd-php@1/mixin.php', 'local' => 'extern/mixin/mgd-php@1/mixin.php', 'provided-by' => '5.45.beta1', 'minimum' => '5.27'], 'scan-classes@1' => [
    // scan-calsses is not meaningful to backport, but tracking metadata helps with admin.
    'version' => '1.0.0',
    'sha256' => '68b543079255d3d92773a5d75f5b033b3227b595337ece207f6dec865a54f0c4',
    'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/4b0558d911bfcbd81e1f5199b0eb0c837c7c8205/mixin/scan-classes@1/mixin.php',
    'local' => 'extern/mixin/scan-classes@1/mixin.php',
    'provided-by' => '5.51.beta2',
    'minimum' => '5.51',
], 'setting-php@1' => ['version' => '1.0.0', 'sha256' => '5ce236c1a1a63637ce5f0f4fe5bf7f21eaa06c750ca16c0fbf4dd792da0d23c9', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.45.3/mixin/setting-php@1/mixin.php', 'local' => 'extern/mixin/setting-php@1/mixin.php', 'provided-by' => '5.45.beta1', 'minimum' => '5.27'], 'smarty-v2@1' => ['version' => '1.0.1', 'sha256' => '6b1e05facc17d414d8e99faf5bdd9fe694ff92cc3d7f9a05e2fe6fc63e3d1948', 'remote' => 'https://github.com/civicrm/civicrm-core/raw/7168793c03ef57c06bbfe45f5ff873ebb3657806/mixin/smarty-v2%401/mixin.php', 'local' => 'extern/mixin/smarty-v2@1/mixin.php', 'provided-by' => '5.59', 'minimum' => '5.27'], 'theme-php@1' => ['version' => '1.0.0', 'sha256' => '2d4bd2442fde152c8f31805ac265c2249d5cf771185f1ac870fd1fcbb18db3ed', 'remote' => 'https://raw.githubusercontent.com/civicrm/civicrm-core/5.45.3/mixin/theme-php@1/mixin.php', 'local' => 'extern/mixin/theme-php@1/mixin.php', 'provided-by' => '5.45.beta1', 'minimum' => '5.27']];
<?php

namespace CivixPhar;

\ini_set('display_errors', 1);
if (\PHP_SAPI !== 'cli') {
    \fwrite(\STDERR, "civix is a command-line tool. It requires PHP_SAPI=cli.\n");
    exit(1);
}
if (\version_compare(\phpversion(), '7.1.3', '<')) {
    \fwrite(\STDERR, "This version of civix requires PHP 7.1.3.\n");
    \fwrite(\STDERR, "For PHP 7.0 or older, see civix v20.06.0 or older.\n");
    exit(2);
}
$found = 0;
$autoloaders = array(\dirname(__DIR__) . \DIRECTORY_SEPARATOR . 'vendor' . \DIRECTORY_SEPARATOR . 'autoload.php', \dirname(\dirname(\dirname(__DIR__))) . \DIRECTORY_SEPARATOR . 'autoload.php');
foreach ($autoloaders as $autoloader) {
    if (\file_exists($autoloader)) {
        require_once $autoloader;
        $found = 1;
        break;
    }
}
if (!$found) {
    \fwrite(\STDERR, "Failed to find autoloader\n");
    exit(3);
}
\CRM\CivixBundle\Application::main(__DIR__);
¹&‡äè¾ŒÌÌÁßà±ÀþŽ	çÞÎ   GBMB