From 15961f0c175b6f36971167ecc1535e785dc7712f Mon Sep 17 00:00:00 2001 From: slawkens Date: Mon, 28 Aug 2017 10:02:49 +0200 Subject: [PATCH] * some changes * moved some admin html code from php to twig templates (.html files) * minimum PHP version required by installer is now 5.1.2, cause of spl_autoload_register functon. * depracated Twig to version 1.20.0 cause of Autoloader * removed unused admin stylish template --- admin/{templates/clean => template}/style.css | 0 .../clean => template}/template.php | 0 admin/templates/stylish/Kopia index.html | 281 --- admin/templates/stylish/blank.html | 100 -- admin/templates/stylish/css/Copy of theme.css | 121 -- admin/templates/stylish/css/ie-sucks.css | 21 - admin/templates/stylish/css/iepngfix.htc | 68 - admin/templates/stylish/css/style.css | 397 ----- admin/templates/stylish/css/switch.css | 51 - admin/templates/stylish/css/theme.css | 121 -- admin/templates/stylish/css/theme1.css | 121 -- admin/templates/stylish/css/theme2.css | 121 -- admin/templates/stylish/css/theme3.css | 121 -- admin/templates/stylish/css/theme4.css | 122 -- admin/templates/stylish/img/bg.jpg | Bin 372 -> 0 bytes admin/templates/stylish/img/bg_blue.jpg | Bin 359 -> 0 bytes admin/templates/stylish/img/bg_brown.jpg | Bin 355 -> 0 bytes .../templates/stylish/img/bg_light_green.jpg | Bin 356 -> 0 bytes admin/templates/stylish/img/bg_menu_blue.jpg | Bin 372 -> 0 bytes admin/templates/stylish/img/bg_menu_green.jpg | Bin 383 -> 0 bytes admin/templates/stylish/img/bg_menu_mix.jpg | Bin 379 -> 0 bytes admin/templates/stylish/img/bg_menu_red.jpg | Bin 367 -> 0 bytes admin/templates/stylish/img/bg_mix.jpg | Bin 353 -> 0 bytes admin/templates/stylish/img/form_blue.gif | Bin 272 -> 0 bytes admin/templates/stylish/img/form_brown.gif | Bin 273 -> 0 bytes admin/templates/stylish/img/form_green.gif | Bin 273 -> 0 bytes admin/templates/stylish/img/form_mix.gif | Bin 273 -> 0 bytes admin/templates/stylish/img/form_red.gif | Bin 166 -> 0 bytes admin/templates/stylish/img/graph.jpg | Bin 40975 -> 0 bytes admin/templates/stylish/img/graph2.jpg | Bin 56232 -> 0 bytes admin/templates/stylish/img/icons/add.png | Bin 733 -> 0 bytes .../stylish/img/icons/application_add.png | Bin 619 -> 0 bytes .../stylish/img/icons/arrow_down.png | Bin 379 -> 0 bytes .../stylish/img/icons/arrow_down_mini.gif | Bin 131 -> 0 bytes .../stylish/img/icons/arrow_left.gif | Bin 131 -> 0 bytes .../stylish/img/icons/arrow_right.gif | Bin 130 -> 0 bytes admin/templates/stylish/img/icons/brick.png | Bin 452 -> 0 bytes .../stylish/img/icons/brick_edit.png | Bin 775 -> 0 bytes admin/templates/stylish/img/icons/bricks.png | Bin 825 -> 0 bytes .../stylish/img/icons/bricks_gear.png | Bin 876 -> 0 bytes admin/templates/stylish/img/icons/car.png | Bin 610 -> 0 bytes admin/templates/stylish/img/icons/cart.png | Bin 421 -> 0 bytes .../templates/stylish/img/icons/cart_add.png | Bin 711 -> 0 bytes admin/templates/stylish/img/icons/cog.png | Bin 512 -> 0 bytes admin/templates/stylish/img/icons/coins.png | Bin 732 -> 0 bytes .../stylish/img/icons/color_swatch.png | Bin 209 -> 0 bytes admin/templates/stylish/img/icons/expand.jpg | Bin 773 -> 0 bytes admin/templates/stylish/img/icons/feed.png | Bin 691 -> 0 bytes admin/templates/stylish/img/icons/folder.png | Bin 537 -> 0 bytes .../stylish/img/icons/folder_page.png | Bin 688 -> 0 bytes .../stylish/img/icons/folder_page_add.png | Bin 773 -> 0 bytes .../stylish/img/icons/folder_table.png | Bin 675 -> 0 bytes admin/templates/stylish/img/icons/group.png | Bin 753 -> 0 bytes admin/templates/stylish/img/icons/house.png | Bin 806 -> 0 bytes .../templates/stylish/img/icons/magnifier.png | Bin 615 -> 0 bytes .../templates/stylish/img/icons/page_add.png | Bin 739 -> 0 bytes .../templates/stylish/img/icons/page_gear.png | Bin 833 -> 0 bytes .../stylish/img/icons/page_white_delete.png | Bin 536 -> 0 bytes .../stylish/img/icons/page_white_edit.png | Bin 618 -> 0 bytes .../stylish/img/icons/page_white_link.png | Bin 614 -> 0 bytes .../img/icons/page_white_text_width.png | Bin 315 -> 0 bytes admin/templates/stylish/img/icons/report.png | Bin 649 -> 0 bytes .../stylish/img/icons/report_link.png | Bin 754 -> 0 bytes admin/templates/stylish/img/icons/rss.png | Bin 530 -> 0 bytes admin/templates/stylish/img/icons/user.png | Bin 741 -> 0 bytes .../templates/stylish/img/icons/user_add.png | Bin 746 -> 0 bytes .../stylish/img/icons/user_delete.png | Bin 767 -> 0 bytes .../templates/stylish/img/icons/user_edit.png | Bin 833 -> 0 bytes admin/templates/stylish/img/icons/world.png | Bin 923 -> 0 bytes admin/templates/stylish/psd/template.psd | Bin 967624 -> 0 bytes admin/templates/stylish/template.php | 296 ---- admin/templates/stylish/users.html | 309 ---- install/steps/requirements.php | 2 +- system/cache/twig/.htaccess | 1 + system/init.php | 9 + system/libs/twig/Autoloader.php | 17 +- system/libs/twig/BaseNodeVisitor.php | 62 + system/libs/twig/Cache/CacheInterface.php | 11 - system/libs/twig/Cache/FilesystemCache.php | 11 - system/libs/twig/Cache/NullCache.php | 11 - system/libs/twig/Compiler.php | 275 ++- system/libs/twig/CompilerInterface.php | 36 + system/libs/twig/Environment.php | 1291 +++++++++++++- system/libs/twig/Error.php | 250 +++ system/libs/twig/Error/Error.php | 11 - system/libs/twig/Error/Loader.php | 31 + system/libs/twig/Error/LoaderError.php | 11 - system/libs/twig/Error/Runtime.php | 20 + system/libs/twig/Error/RuntimeError.php | 11 - system/libs/twig/Error/Syntax.php | 20 + system/libs/twig/Error/SyntaxError.php | 11 - system/libs/twig/ExistsLoaderInterface.php | 29 + system/libs/twig/ExpressionParser.php | 622 ++++++- system/libs/twig/Extension.php | 93 + .../libs/twig/Extension/AbstractExtension.php | 11 - system/libs/twig/Extension/Core.php | 1516 +++++++++++++++++ system/libs/twig/Extension/CoreExtension.php | 11 - system/libs/twig/Extension/Debug.php | 71 + system/libs/twig/Extension/DebugExtension.php | 11 - system/libs/twig/Extension/Escaper.php | 113 ++ .../libs/twig/Extension/EscaperExtension.php | 11 - .../twig/Extension/ExtensionInterface.php | 11 - .../libs/twig/Extension/GlobalsInterface.php | 11 - .../twig/Extension/InitRuntimeInterface.php | 11 - system/libs/twig/Extension/Optimizer.php | 35 + .../twig/Extension/OptimizerExtension.php | 11 - system/libs/twig/Extension/Profiler.php | 52 + .../libs/twig/Extension/ProfilerExtension.php | 11 - system/libs/twig/Extension/Sandbox.php | 112 ++ .../libs/twig/Extension/SandboxExtension.php | 11 - system/libs/twig/Extension/Staging.php | 113 ++ .../libs/twig/Extension/StagingExtension.php | 11 - system/libs/twig/Extension/StringLoader.php | 47 + .../twig/Extension/StringLoaderExtension.php | 11 - system/libs/twig/ExtensionInterface.php | 83 + .../twig/FileExtensionEscapingStrategy.php | 48 +- system/libs/twig/Filter.php | 82 + system/libs/twig/Filter/Function.php | 38 + system/libs/twig/Filter/Method.php | 40 + system/libs/twig/Filter/Node.php | 40 + system/libs/twig/FilterCallableInterface.php | 24 + system/libs/twig/FilterInterface.php | 43 + system/libs/twig/Function.php | 72 + system/libs/twig/Function/Function.php | 39 + system/libs/twig/Function/Method.php | 41 + system/libs/twig/Function/Node.php | 40 + .../libs/twig/FunctionCallableInterface.php | 24 + system/libs/twig/FunctionInterface.php | 40 + system/libs/twig/Lexer.php | 404 ++++- system/libs/twig/LexerInterface.php | 32 + system/libs/twig/Loader/Array.php | 97 ++ system/libs/twig/Loader/ArrayLoader.php | 11 - system/libs/twig/Loader/Chain.php | 138 ++ system/libs/twig/Loader/ChainLoader.php | 11 - .../twig/Loader/ExistsLoaderInterface.php | 11 - system/libs/twig/Loader/Filesystem.php | 240 +++ system/libs/twig/Loader/FilesystemLoader.php | 11 - system/libs/twig/Loader/LoaderInterface.php | 11 - .../Loader/SourceContextLoaderInterface.php | 11 - system/libs/twig/Loader/String.php | 59 + system/libs/twig/LoaderInterface.php | 53 + system/libs/twig/Markup.php | 34 +- system/libs/twig/Node.php | 229 +++ system/libs/twig/Node/AutoEscape.php | 39 + system/libs/twig/Node/AutoEscapeNode.php | 11 - system/libs/twig/Node/Block.php | 44 + system/libs/twig/Node/BlockNode.php | 11 - system/libs/twig/Node/BlockReference.php | 37 + system/libs/twig/Node/BlockReferenceNode.php | 11 - system/libs/twig/Node/Body.php | 19 + system/libs/twig/Node/BodyNode.php | 11 - system/libs/twig/Node/CheckSecurity.php | 78 + system/libs/twig/Node/CheckSecurityNode.php | 11 - system/libs/twig/Node/Do.php | 38 + system/libs/twig/Node/DoNode.php | 11 - system/libs/twig/Node/Embed.php | 42 + system/libs/twig/Node/EmbedNode.php | 11 - system/libs/twig/Node/Expression.php | 20 + .../Node/Expression/AbstractExpression.php | 11 - system/libs/twig/Node/Expression/Array.php | 86 + .../twig/Node/Expression/ArrayExpression.php | 11 - .../libs/twig/Node/Expression/AssignName.php | 28 + .../Node/Expression/AssignNameExpression.php | 11 - system/libs/twig/Node/Expression/Binary.php | 40 + .../Node/Expression/Binary/AbstractBinary.php | 11 - .../libs/twig/Node/Expression/Binary/Add.php | 18 + .../twig/Node/Expression/Binary/AddBinary.php | 11 - .../libs/twig/Node/Expression/Binary/And.php | 18 + .../twig/Node/Expression/Binary/AndBinary.php | 11 - .../Node/Expression/Binary/BitwiseAnd.php | 18 + .../Expression/Binary/BitwiseAndBinary.php | 11 - .../twig/Node/Expression/Binary/BitwiseOr.php | 18 + .../Expression/Binary/BitwiseOrBinary.php | 11 - .../Node/Expression/Binary/BitwiseXor.php | 18 + .../Expression/Binary/BitwiseXorBinary.php | 11 - .../twig/Node/Expression/Binary/Concat.php | 18 + .../Node/Expression/Binary/ConcatBinary.php | 11 - .../libs/twig/Node/Expression/Binary/Div.php | 18 + .../twig/Node/Expression/Binary/DivBinary.php | 11 - .../twig/Node/Expression/Binary/EndsWith.php | 30 + .../Node/Expression/Binary/EndsWithBinary.php | 11 - .../twig/Node/Expression/Binary/Equal.php | 17 + .../Node/Expression/Binary/EqualBinary.php | 11 - .../twig/Node/Expression/Binary/FloorDiv.php | 29 + .../Node/Expression/Binary/FloorDivBinary.php | 11 - .../twig/Node/Expression/Binary/Greater.php | 17 + .../Node/Expression/Binary/GreaterBinary.php | 11 - .../Node/Expression/Binary/GreaterEqual.php | 17 + .../Expression/Binary/GreaterEqualBinary.php | 11 - .../libs/twig/Node/Expression/Binary/In.php | 33 + .../twig/Node/Expression/Binary/InBinary.php | 11 - .../libs/twig/Node/Expression/Binary/Less.php | 17 + .../Node/Expression/Binary/LessBinary.php | 11 - .../twig/Node/Expression/Binary/LessEqual.php | 17 + .../Expression/Binary/LessEqualBinary.php | 11 - .../twig/Node/Expression/Binary/Matches.php | 28 + .../Node/Expression/Binary/MatchesBinary.php | 11 - .../libs/twig/Node/Expression/Binary/Mod.php | 18 + .../twig/Node/Expression/Binary/ModBinary.php | 11 - .../libs/twig/Node/Expression/Binary/Mul.php | 18 + .../twig/Node/Expression/Binary/MulBinary.php | 11 - .../twig/Node/Expression/Binary/NotEqual.php | 17 + .../Node/Expression/Binary/NotEqualBinary.php | 11 - .../twig/Node/Expression/Binary/NotIn.php | 33 + .../Node/Expression/Binary/NotInBinary.php | 11 - .../libs/twig/Node/Expression/Binary/Or.php | 18 + .../twig/Node/Expression/Binary/OrBinary.php | 11 - .../twig/Node/Expression/Binary/Power.php | 33 + .../Node/Expression/Binary/PowerBinary.php | 11 - .../twig/Node/Expression/Binary/Range.php | 33 + .../Node/Expression/Binary/RangeBinary.php | 11 - .../Node/Expression/Binary/StartsWith.php | 30 + .../Expression/Binary/StartsWithBinary.php | 11 - .../libs/twig/Node/Expression/Binary/Sub.php | 18 + .../twig/Node/Expression/Binary/SubBinary.php | 11 - .../twig/Node/Expression/BlockReference.php | 51 + .../Expression/BlockReferenceExpression.php | 11 - system/libs/twig/Node/Expression/Call.php | 247 +++ .../twig/Node/Expression/CallExpression.php | 11 - .../libs/twig/Node/Expression/Conditional.php | 31 + .../Node/Expression/ConditionalExpression.php | 11 - system/libs/twig/Node/Expression/Constant.php | 23 + .../Node/Expression/ConstantExpression.php | 11 - .../Node/Expression/ExtensionReference.php | 33 + system/libs/twig/Node/Expression/Filter.php | 39 + .../twig/Node/Expression/Filter/Default.php | 43 + .../Node/Expression/Filter/DefaultFilter.php | 11 - .../twig/Node/Expression/FilterExpression.php | 11 - system/libs/twig/Node/Expression/Function.php | 38 + .../Node/Expression/FunctionExpression.php | 11 - system/libs/twig/Node/Expression/GetAttr.php | 63 + .../Node/Expression/GetAttrExpression.php | 11 - .../libs/twig/Node/Expression/MethodCall.php | 41 + .../Node/Expression/MethodCallExpression.php | 11 - system/libs/twig/Node/Expression/Name.php | 90 + .../twig/Node/Expression/NameExpression.php | 11 - .../Expression/NullCoalesceExpression.php | 11 - system/libs/twig/Node/Expression/Parent.php | 47 + .../twig/Node/Expression/ParentExpression.php | 11 - system/libs/twig/Node/Expression/TempName.php | 26 + .../Node/Expression/TempNameExpression.php | 11 - system/libs/twig/Node/Expression/Test.php | 35 + .../twig/Node/Expression/Test/Constant.php | 46 + .../Node/Expression/Test/ConstantTest.php | 11 - .../twig/Node/Expression/Test/Defined.php | 54 + .../twig/Node/Expression/Test/DefinedTest.php | 11 - .../twig/Node/Expression/Test/Divisibleby.php | 33 + .../Node/Expression/Test/DivisiblebyTest.php | 11 - .../libs/twig/Node/Expression/Test/Even.php | 32 + .../twig/Node/Expression/Test/EvenTest.php | 11 - .../libs/twig/Node/Expression/Test/Null.php | 31 + .../twig/Node/Expression/Test/NullTest.php | 11 - system/libs/twig/Node/Expression/Test/Odd.php | 32 + .../twig/Node/Expression/Test/OddTest.php | 11 - .../libs/twig/Node/Expression/Test/Sameas.php | 29 + .../twig/Node/Expression/Test/SameasTest.php | 11 - .../twig/Node/Expression/TestExpression.php | 11 - system/libs/twig/Node/Expression/Unary.php | 27 + .../Node/Expression/Unary/AbstractUnary.php | 11 - .../libs/twig/Node/Expression/Unary/Neg.php | 18 + .../twig/Node/Expression/Unary/NegUnary.php | 11 - .../libs/twig/Node/Expression/Unary/Not.php | 18 + .../twig/Node/Expression/Unary/NotUnary.php | 11 - .../libs/twig/Node/Expression/Unary/Pos.php | 18 + .../twig/Node/Expression/Unary/PosUnary.php | 11 - system/libs/twig/Node/Flush.php | 36 + system/libs/twig/Node/FlushNode.php | 11 - system/libs/twig/Node/For.php | 112 ++ system/libs/twig/Node/ForLoop.php | 55 + system/libs/twig/Node/ForLoopNode.php | 11 - system/libs/twig/Node/ForNode.php | 11 - system/libs/twig/Node/If.php | 66 + system/libs/twig/Node/IfNode.php | 11 - system/libs/twig/Node/Import.php | 54 + system/libs/twig/Node/ImportNode.php | 11 - system/libs/twig/Node/Include.php | 88 + system/libs/twig/Node/IncludeNode.php | 11 - system/libs/twig/Node/Macro.php | 123 ++ system/libs/twig/Node/MacroNode.php | 11 - system/libs/twig/Node/Module.php | 423 +++++ system/libs/twig/Node/ModuleNode.php | 11 - system/libs/twig/Node/Node.php | 11 - .../libs/twig/Node/NodeCaptureInterface.php | 11 - system/libs/twig/Node/NodeOutputInterface.php | 11 - system/libs/twig/Node/Print.php | 39 + system/libs/twig/Node/PrintNode.php | 11 - system/libs/twig/Node/Sandbox.php | 47 + system/libs/twig/Node/SandboxNode.php | 11 - system/libs/twig/Node/SandboxedPrint.php | 61 + system/libs/twig/Node/SandboxedPrintNode.php | 11 - system/libs/twig/Node/Set.php | 101 ++ system/libs/twig/Node/SetNode.php | 11 - system/libs/twig/Node/SetTemp.php | 35 + system/libs/twig/Node/SetTempNode.php | 11 - system/libs/twig/Node/Spaceless.php | 40 + system/libs/twig/Node/SpacelessNode.php | 11 - system/libs/twig/Node/Text.php | 39 + system/libs/twig/Node/TextNode.php | 11 - system/libs/twig/Node/WithNode.php | 11 - system/libs/twig/NodeInterface.php | 31 + system/libs/twig/NodeOutputInterface.php | 19 + system/libs/twig/NodeTraverser.php | 87 +- .../twig/NodeVisitor/AbstractNodeVisitor.php | 11 - system/libs/twig/NodeVisitor/Escaper.php | 157 ++ .../twig/NodeVisitor/EscaperNodeVisitor.php | 11 - .../twig/NodeVisitor/NodeVisitorInterface.php | 11 - system/libs/twig/NodeVisitor/Optimizer.php | 271 +++ .../twig/NodeVisitor/OptimizerNodeVisitor.php | 11 - system/libs/twig/NodeVisitor/SafeAnalysis.php | 154 ++ .../NodeVisitor/SafeAnalysisNodeVisitor.php | 11 - system/libs/twig/NodeVisitor/Sandbox.php | 82 + .../twig/NodeVisitor/SandboxNodeVisitor.php | 11 - system/libs/twig/NodeVisitorInterface.php | 47 + system/libs/twig/Parser.php | 396 ++++- system/libs/twig/ParserInterface.php | 31 + .../libs/twig/Profiler/Dumper/BaseDumper.php | 11 - .../libs/twig/Profiler/Dumper/Blackfire.php | 68 + .../twig/Profiler/Dumper/BlackfireDumper.php | 11 - system/libs/twig/Profiler/Dumper/Html.php | 43 + .../libs/twig/Profiler/Dumper/HtmlDumper.php | 11 - system/libs/twig/Profiler/Dumper/Text.php | 68 + .../libs/twig/Profiler/Dumper/TextDumper.php | 11 - .../libs/twig/Profiler/Node/EnterProfile.php | 40 + .../twig/Profiler/Node/EnterProfileNode.php | 11 - .../libs/twig/Profiler/Node/LeaveProfile.php | 34 + .../twig/Profiler/Node/LeaveProfileNode.php | 11 - .../twig/Profiler/NodeVisitor/Profiler.php | 72 + .../NodeVisitor/ProfilerNodeVisitor.php | 11 - system/libs/twig/Profiler/Profile.php | 147 +- .../RuntimeLoader/ContainerRuntimeLoader.php | 11 - .../RuntimeLoader/FactoryRuntimeLoader.php | 11 - .../RuntimeLoader/RuntimeLoaderInterface.php | 11 - system/libs/twig/Sandbox/SecurityError.php | 22 +- .../Sandbox/SecurityNotAllowedFilterError.php | 28 +- .../SecurityNotAllowedFunctionError.php | 28 +- .../Sandbox/SecurityNotAllowedMethodError.php | 11 - .../SecurityNotAllowedPropertyError.php | 11 - .../Sandbox/SecurityNotAllowedTagError.php | 28 +- system/libs/twig/Sandbox/SecurityPolicy.php | 116 +- .../twig/Sandbox/SecurityPolicyInterface.php | 25 +- system/libs/twig/SimpleFilter.php | 100 ++ system/libs/twig/SimpleFunction.php | 90 + system/libs/twig/SimpleTest.php | 52 + system/libs/twig/Source.php | 11 - system/libs/twig/Template.php | 568 +++++- system/libs/twig/TemplateInterface.php | 48 + system/libs/twig/TemplateWrapper.php | 11 - system/libs/twig/Test.php | 35 + system/libs/twig/Test/Function.php | 36 + system/libs/twig/Test/IntegrationTestCase.php | 159 +- system/libs/twig/Test/Method.php | 38 + system/libs/twig/Test/Node.php | 38 + system/libs/twig/Test/NodeTestCase.php | 59 +- system/libs/twig/TestCallableInterface.php | 22 + system/libs/twig/TestInterface.php | 27 + system/libs/twig/Token.php | 213 ++- system/libs/twig/TokenParser.php | 33 + .../twig/TokenParser/AbstractTokenParser.php | 11 - system/libs/twig/TokenParser/AutoEscape.php | 89 + .../TokenParser/AutoEscapeTokenParser.php | 11 - system/libs/twig/TokenParser/Block.php | 81 + .../twig/TokenParser/BlockTokenParser.php | 11 - system/libs/twig/TokenParser/Do.php | 42 + .../libs/twig/TokenParser/DoTokenParser.php | 11 - system/libs/twig/TokenParser/Embed.php | 66 + .../twig/TokenParser/EmbedTokenParser.php | 11 - system/libs/twig/TokenParser/Extends.php | 52 + .../twig/TokenParser/ExtendsTokenParser.php | 11 - system/libs/twig/TokenParser/Filter.php | 61 + .../twig/TokenParser/FilterTokenParser.php | 11 - system/libs/twig/TokenParser/Flush.php | 42 + .../twig/TokenParser/FlushTokenParser.php | 11 - system/libs/twig/TokenParser/For.php | 135 ++ .../libs/twig/TokenParser/ForTokenParser.php | 11 - system/libs/twig/TokenParser/From.php | 74 + .../libs/twig/TokenParser/FromTokenParser.php | 11 - system/libs/twig/TokenParser/If.php | 94 + .../libs/twig/TokenParser/IfTokenParser.php | 11 - system/libs/twig/TokenParser/Import.php | 49 + .../twig/TokenParser/ImportTokenParser.php | 11 - system/libs/twig/TokenParser/Include.php | 75 + .../twig/TokenParser/IncludeTokenParser.php | 11 - system/libs/twig/TokenParser/Macro.php | 68 + .../twig/TokenParser/MacroTokenParser.php | 11 - system/libs/twig/TokenParser/Sandbox.php | 68 + .../twig/TokenParser/SandboxTokenParser.php | 11 - system/libs/twig/TokenParser/Set.php | 83 + .../libs/twig/TokenParser/SetTokenParser.php | 11 - system/libs/twig/TokenParser/Spaceless.php | 59 + .../twig/TokenParser/SpacelessTokenParser.php | 11 - .../twig/TokenParser/TokenParserInterface.php | 11 - system/libs/twig/TokenParser/Use.php | 76 + .../libs/twig/TokenParser/UseTokenParser.php | 11 - .../libs/twig/TokenParser/WithTokenParser.php | 11 - system/libs/twig/TokenParserBroker.php | 137 ++ .../libs/twig/TokenParserBrokerInterface.php | 46 + system/libs/twig/TokenParserInterface.php | 43 + system/libs/twig/TokenStream.php | 153 +- system/libs/twig/TwigFilter.php | 11 - system/libs/twig/TwigFunction.php | 11 - system/libs/twig/TwigTest.php | 11 - .../libs/twig/Util/DeprecationCollector.php | 11 - system/libs/twig/Util/TemplateDirIterator.php | 11 - system/pages/admin/dashboard.php | 88 +- system/pages/admin/login.php | 12 +- system/pages/admin/mailer.php | 93 +- system/pages/admin/notepad.php | 54 +- system/pages/admin/plugins.php | 76 +- system/pages/admin/statistics.php | 76 +- system/pages/admin/visitors.php | 25 +- system/templates/admin.dashboard.html | 77 + system/templates/admin.login.html | 9 + system/templates/admin.mailer.html | 46 + system/templates/admin.notepad.html | 51 + system/templates/admin.plugins.form.html | 17 + system/templates/admin.plugins.html | 19 + system/templates/admin.statistics.html | 38 + system/templates/admin.visitors.html | 19 + 418 files changed, 15624 insertions(+), 4322 deletions(-) rename admin/{templates/clean => template}/style.css (100%) rename admin/{templates/clean => template}/template.php (100%) delete mode 100644 admin/templates/stylish/Kopia index.html delete mode 100644 admin/templates/stylish/blank.html delete mode 100644 admin/templates/stylish/css/Copy of theme.css delete mode 100644 admin/templates/stylish/css/ie-sucks.css delete mode 100644 admin/templates/stylish/css/iepngfix.htc delete mode 100644 admin/templates/stylish/css/style.css delete mode 100644 admin/templates/stylish/css/switch.css delete mode 100644 admin/templates/stylish/css/theme.css delete mode 100644 admin/templates/stylish/css/theme1.css delete mode 100644 admin/templates/stylish/css/theme2.css delete mode 100644 admin/templates/stylish/css/theme3.css delete mode 100644 admin/templates/stylish/css/theme4.css delete mode 100644 admin/templates/stylish/img/bg.jpg delete mode 100644 admin/templates/stylish/img/bg_blue.jpg delete mode 100644 admin/templates/stylish/img/bg_brown.jpg delete mode 100644 admin/templates/stylish/img/bg_light_green.jpg delete mode 100644 admin/templates/stylish/img/bg_menu_blue.jpg delete mode 100644 admin/templates/stylish/img/bg_menu_green.jpg delete mode 100644 admin/templates/stylish/img/bg_menu_mix.jpg delete mode 100644 admin/templates/stylish/img/bg_menu_red.jpg delete mode 100644 admin/templates/stylish/img/bg_mix.jpg delete mode 100644 admin/templates/stylish/img/form_blue.gif delete mode 100644 admin/templates/stylish/img/form_brown.gif delete mode 100644 admin/templates/stylish/img/form_green.gif delete mode 100644 admin/templates/stylish/img/form_mix.gif delete mode 100644 admin/templates/stylish/img/form_red.gif delete mode 100644 admin/templates/stylish/img/graph.jpg delete mode 100644 admin/templates/stylish/img/graph2.jpg delete mode 100644 admin/templates/stylish/img/icons/add.png delete mode 100644 admin/templates/stylish/img/icons/application_add.png delete mode 100644 admin/templates/stylish/img/icons/arrow_down.png delete mode 100644 admin/templates/stylish/img/icons/arrow_down_mini.gif delete mode 100644 admin/templates/stylish/img/icons/arrow_left.gif delete mode 100644 admin/templates/stylish/img/icons/arrow_right.gif delete mode 100644 admin/templates/stylish/img/icons/brick.png delete mode 100644 admin/templates/stylish/img/icons/brick_edit.png delete mode 100644 admin/templates/stylish/img/icons/bricks.png delete mode 100644 admin/templates/stylish/img/icons/bricks_gear.png delete mode 100644 admin/templates/stylish/img/icons/car.png delete mode 100644 admin/templates/stylish/img/icons/cart.png delete mode 100644 admin/templates/stylish/img/icons/cart_add.png delete mode 100644 admin/templates/stylish/img/icons/cog.png delete mode 100644 admin/templates/stylish/img/icons/coins.png delete mode 100644 admin/templates/stylish/img/icons/color_swatch.png delete mode 100644 admin/templates/stylish/img/icons/expand.jpg delete mode 100644 admin/templates/stylish/img/icons/feed.png delete mode 100644 admin/templates/stylish/img/icons/folder.png delete mode 100644 admin/templates/stylish/img/icons/folder_page.png delete mode 100644 admin/templates/stylish/img/icons/folder_page_add.png delete mode 100644 admin/templates/stylish/img/icons/folder_table.png delete mode 100644 admin/templates/stylish/img/icons/group.png delete mode 100644 admin/templates/stylish/img/icons/house.png delete mode 100644 admin/templates/stylish/img/icons/magnifier.png delete mode 100644 admin/templates/stylish/img/icons/page_add.png delete mode 100644 admin/templates/stylish/img/icons/page_gear.png delete mode 100644 admin/templates/stylish/img/icons/page_white_delete.png delete mode 100644 admin/templates/stylish/img/icons/page_white_edit.png delete mode 100644 admin/templates/stylish/img/icons/page_white_link.png delete mode 100644 admin/templates/stylish/img/icons/page_white_text_width.png delete mode 100644 admin/templates/stylish/img/icons/report.png delete mode 100644 admin/templates/stylish/img/icons/report_link.png delete mode 100644 admin/templates/stylish/img/icons/rss.png delete mode 100644 admin/templates/stylish/img/icons/user.png delete mode 100644 admin/templates/stylish/img/icons/user_add.png delete mode 100644 admin/templates/stylish/img/icons/user_delete.png delete mode 100644 admin/templates/stylish/img/icons/user_edit.png delete mode 100644 admin/templates/stylish/img/icons/world.png delete mode 100644 admin/templates/stylish/psd/template.psd delete mode 100644 admin/templates/stylish/template.php delete mode 100644 admin/templates/stylish/users.html create mode 100644 system/cache/twig/.htaccess mode change 100644 => 100755 system/libs/twig/Autoloader.php create mode 100755 system/libs/twig/BaseNodeVisitor.php delete mode 100755 system/libs/twig/Cache/CacheInterface.php delete mode 100755 system/libs/twig/Cache/FilesystemCache.php delete mode 100755 system/libs/twig/Cache/NullCache.php create mode 100755 system/libs/twig/CompilerInterface.php create mode 100755 system/libs/twig/Error.php delete mode 100755 system/libs/twig/Error/Error.php create mode 100755 system/libs/twig/Error/Loader.php delete mode 100755 system/libs/twig/Error/LoaderError.php create mode 100755 system/libs/twig/Error/Runtime.php delete mode 100755 system/libs/twig/Error/RuntimeError.php create mode 100755 system/libs/twig/Error/Syntax.php delete mode 100755 system/libs/twig/Error/SyntaxError.php create mode 100755 system/libs/twig/ExistsLoaderInterface.php create mode 100755 system/libs/twig/Extension.php delete mode 100755 system/libs/twig/Extension/AbstractExtension.php create mode 100755 system/libs/twig/Extension/Core.php delete mode 100755 system/libs/twig/Extension/CoreExtension.php create mode 100755 system/libs/twig/Extension/Debug.php delete mode 100755 system/libs/twig/Extension/DebugExtension.php create mode 100755 system/libs/twig/Extension/Escaper.php delete mode 100755 system/libs/twig/Extension/EscaperExtension.php delete mode 100755 system/libs/twig/Extension/ExtensionInterface.php delete mode 100755 system/libs/twig/Extension/GlobalsInterface.php delete mode 100755 system/libs/twig/Extension/InitRuntimeInterface.php create mode 100755 system/libs/twig/Extension/Optimizer.php delete mode 100755 system/libs/twig/Extension/OptimizerExtension.php create mode 100755 system/libs/twig/Extension/Profiler.php delete mode 100755 system/libs/twig/Extension/ProfilerExtension.php create mode 100755 system/libs/twig/Extension/Sandbox.php delete mode 100755 system/libs/twig/Extension/SandboxExtension.php create mode 100755 system/libs/twig/Extension/Staging.php delete mode 100755 system/libs/twig/Extension/StagingExtension.php create mode 100755 system/libs/twig/Extension/StringLoader.php delete mode 100755 system/libs/twig/Extension/StringLoaderExtension.php create mode 100755 system/libs/twig/ExtensionInterface.php create mode 100755 system/libs/twig/Filter.php create mode 100755 system/libs/twig/Filter/Function.php create mode 100755 system/libs/twig/Filter/Method.php create mode 100755 system/libs/twig/Filter/Node.php create mode 100755 system/libs/twig/FilterCallableInterface.php create mode 100755 system/libs/twig/FilterInterface.php create mode 100755 system/libs/twig/Function.php create mode 100755 system/libs/twig/Function/Function.php create mode 100755 system/libs/twig/Function/Method.php create mode 100755 system/libs/twig/Function/Node.php create mode 100755 system/libs/twig/FunctionCallableInterface.php create mode 100755 system/libs/twig/FunctionInterface.php create mode 100755 system/libs/twig/LexerInterface.php create mode 100755 system/libs/twig/Loader/Array.php delete mode 100755 system/libs/twig/Loader/ArrayLoader.php create mode 100755 system/libs/twig/Loader/Chain.php delete mode 100755 system/libs/twig/Loader/ChainLoader.php delete mode 100755 system/libs/twig/Loader/ExistsLoaderInterface.php create mode 100755 system/libs/twig/Loader/Filesystem.php delete mode 100755 system/libs/twig/Loader/FilesystemLoader.php delete mode 100755 system/libs/twig/Loader/LoaderInterface.php delete mode 100755 system/libs/twig/Loader/SourceContextLoaderInterface.php create mode 100755 system/libs/twig/Loader/String.php create mode 100755 system/libs/twig/LoaderInterface.php create mode 100755 system/libs/twig/Node.php create mode 100755 system/libs/twig/Node/AutoEscape.php delete mode 100755 system/libs/twig/Node/AutoEscapeNode.php create mode 100755 system/libs/twig/Node/Block.php delete mode 100755 system/libs/twig/Node/BlockNode.php create mode 100755 system/libs/twig/Node/BlockReference.php delete mode 100755 system/libs/twig/Node/BlockReferenceNode.php create mode 100755 system/libs/twig/Node/Body.php delete mode 100755 system/libs/twig/Node/BodyNode.php create mode 100755 system/libs/twig/Node/CheckSecurity.php delete mode 100755 system/libs/twig/Node/CheckSecurityNode.php create mode 100755 system/libs/twig/Node/Do.php delete mode 100755 system/libs/twig/Node/DoNode.php create mode 100755 system/libs/twig/Node/Embed.php delete mode 100755 system/libs/twig/Node/EmbedNode.php create mode 100755 system/libs/twig/Node/Expression.php delete mode 100755 system/libs/twig/Node/Expression/AbstractExpression.php create mode 100755 system/libs/twig/Node/Expression/Array.php delete mode 100755 system/libs/twig/Node/Expression/ArrayExpression.php create mode 100755 system/libs/twig/Node/Expression/AssignName.php delete mode 100755 system/libs/twig/Node/Expression/AssignNameExpression.php create mode 100755 system/libs/twig/Node/Expression/Binary.php delete mode 100755 system/libs/twig/Node/Expression/Binary/AbstractBinary.php create mode 100755 system/libs/twig/Node/Expression/Binary/Add.php delete mode 100755 system/libs/twig/Node/Expression/Binary/AddBinary.php create mode 100755 system/libs/twig/Node/Expression/Binary/And.php delete mode 100755 system/libs/twig/Node/Expression/Binary/AndBinary.php create mode 100755 system/libs/twig/Node/Expression/Binary/BitwiseAnd.php delete mode 100755 system/libs/twig/Node/Expression/Binary/BitwiseAndBinary.php create mode 100755 system/libs/twig/Node/Expression/Binary/BitwiseOr.php delete mode 100755 system/libs/twig/Node/Expression/Binary/BitwiseOrBinary.php create mode 100755 system/libs/twig/Node/Expression/Binary/BitwiseXor.php delete mode 100755 system/libs/twig/Node/Expression/Binary/BitwiseXorBinary.php create mode 100755 system/libs/twig/Node/Expression/Binary/Concat.php delete mode 100755 system/libs/twig/Node/Expression/Binary/ConcatBinary.php create mode 100755 system/libs/twig/Node/Expression/Binary/Div.php delete mode 100755 system/libs/twig/Node/Expression/Binary/DivBinary.php create mode 100755 system/libs/twig/Node/Expression/Binary/EndsWith.php delete mode 100755 system/libs/twig/Node/Expression/Binary/EndsWithBinary.php create mode 100755 system/libs/twig/Node/Expression/Binary/Equal.php delete mode 100755 system/libs/twig/Node/Expression/Binary/EqualBinary.php create mode 100755 system/libs/twig/Node/Expression/Binary/FloorDiv.php delete mode 100755 system/libs/twig/Node/Expression/Binary/FloorDivBinary.php create mode 100755 system/libs/twig/Node/Expression/Binary/Greater.php delete mode 100755 system/libs/twig/Node/Expression/Binary/GreaterBinary.php create mode 100755 system/libs/twig/Node/Expression/Binary/GreaterEqual.php delete mode 100755 system/libs/twig/Node/Expression/Binary/GreaterEqualBinary.php create mode 100755 system/libs/twig/Node/Expression/Binary/In.php delete mode 100755 system/libs/twig/Node/Expression/Binary/InBinary.php create mode 100755 system/libs/twig/Node/Expression/Binary/Less.php delete mode 100755 system/libs/twig/Node/Expression/Binary/LessBinary.php create mode 100755 system/libs/twig/Node/Expression/Binary/LessEqual.php delete mode 100755 system/libs/twig/Node/Expression/Binary/LessEqualBinary.php create mode 100755 system/libs/twig/Node/Expression/Binary/Matches.php delete mode 100755 system/libs/twig/Node/Expression/Binary/MatchesBinary.php create mode 100755 system/libs/twig/Node/Expression/Binary/Mod.php delete mode 100755 system/libs/twig/Node/Expression/Binary/ModBinary.php create mode 100755 system/libs/twig/Node/Expression/Binary/Mul.php delete mode 100755 system/libs/twig/Node/Expression/Binary/MulBinary.php create mode 100755 system/libs/twig/Node/Expression/Binary/NotEqual.php delete mode 100755 system/libs/twig/Node/Expression/Binary/NotEqualBinary.php create mode 100755 system/libs/twig/Node/Expression/Binary/NotIn.php delete mode 100755 system/libs/twig/Node/Expression/Binary/NotInBinary.php create mode 100755 system/libs/twig/Node/Expression/Binary/Or.php delete mode 100755 system/libs/twig/Node/Expression/Binary/OrBinary.php create mode 100755 system/libs/twig/Node/Expression/Binary/Power.php delete mode 100755 system/libs/twig/Node/Expression/Binary/PowerBinary.php create mode 100755 system/libs/twig/Node/Expression/Binary/Range.php delete mode 100755 system/libs/twig/Node/Expression/Binary/RangeBinary.php create mode 100755 system/libs/twig/Node/Expression/Binary/StartsWith.php delete mode 100755 system/libs/twig/Node/Expression/Binary/StartsWithBinary.php create mode 100755 system/libs/twig/Node/Expression/Binary/Sub.php delete mode 100755 system/libs/twig/Node/Expression/Binary/SubBinary.php create mode 100755 system/libs/twig/Node/Expression/BlockReference.php delete mode 100755 system/libs/twig/Node/Expression/BlockReferenceExpression.php create mode 100755 system/libs/twig/Node/Expression/Call.php delete mode 100755 system/libs/twig/Node/Expression/CallExpression.php create mode 100755 system/libs/twig/Node/Expression/Conditional.php delete mode 100755 system/libs/twig/Node/Expression/ConditionalExpression.php create mode 100755 system/libs/twig/Node/Expression/Constant.php delete mode 100755 system/libs/twig/Node/Expression/ConstantExpression.php create mode 100755 system/libs/twig/Node/Expression/ExtensionReference.php create mode 100755 system/libs/twig/Node/Expression/Filter.php create mode 100755 system/libs/twig/Node/Expression/Filter/Default.php delete mode 100755 system/libs/twig/Node/Expression/Filter/DefaultFilter.php delete mode 100755 system/libs/twig/Node/Expression/FilterExpression.php create mode 100755 system/libs/twig/Node/Expression/Function.php delete mode 100755 system/libs/twig/Node/Expression/FunctionExpression.php create mode 100755 system/libs/twig/Node/Expression/GetAttr.php delete mode 100755 system/libs/twig/Node/Expression/GetAttrExpression.php create mode 100755 system/libs/twig/Node/Expression/MethodCall.php delete mode 100755 system/libs/twig/Node/Expression/MethodCallExpression.php create mode 100755 system/libs/twig/Node/Expression/Name.php delete mode 100755 system/libs/twig/Node/Expression/NameExpression.php delete mode 100755 system/libs/twig/Node/Expression/NullCoalesceExpression.php create mode 100755 system/libs/twig/Node/Expression/Parent.php delete mode 100755 system/libs/twig/Node/Expression/ParentExpression.php create mode 100755 system/libs/twig/Node/Expression/TempName.php delete mode 100755 system/libs/twig/Node/Expression/TempNameExpression.php create mode 100755 system/libs/twig/Node/Expression/Test.php create mode 100755 system/libs/twig/Node/Expression/Test/Constant.php delete mode 100755 system/libs/twig/Node/Expression/Test/ConstantTest.php create mode 100755 system/libs/twig/Node/Expression/Test/Defined.php delete mode 100755 system/libs/twig/Node/Expression/Test/DefinedTest.php create mode 100755 system/libs/twig/Node/Expression/Test/Divisibleby.php delete mode 100755 system/libs/twig/Node/Expression/Test/DivisiblebyTest.php create mode 100755 system/libs/twig/Node/Expression/Test/Even.php delete mode 100755 system/libs/twig/Node/Expression/Test/EvenTest.php create mode 100755 system/libs/twig/Node/Expression/Test/Null.php delete mode 100755 system/libs/twig/Node/Expression/Test/NullTest.php create mode 100755 system/libs/twig/Node/Expression/Test/Odd.php delete mode 100755 system/libs/twig/Node/Expression/Test/OddTest.php create mode 100755 system/libs/twig/Node/Expression/Test/Sameas.php delete mode 100755 system/libs/twig/Node/Expression/Test/SameasTest.php delete mode 100755 system/libs/twig/Node/Expression/TestExpression.php create mode 100755 system/libs/twig/Node/Expression/Unary.php delete mode 100755 system/libs/twig/Node/Expression/Unary/AbstractUnary.php create mode 100755 system/libs/twig/Node/Expression/Unary/Neg.php delete mode 100755 system/libs/twig/Node/Expression/Unary/NegUnary.php create mode 100755 system/libs/twig/Node/Expression/Unary/Not.php delete mode 100755 system/libs/twig/Node/Expression/Unary/NotUnary.php create mode 100755 system/libs/twig/Node/Expression/Unary/Pos.php delete mode 100755 system/libs/twig/Node/Expression/Unary/PosUnary.php create mode 100755 system/libs/twig/Node/Flush.php delete mode 100755 system/libs/twig/Node/FlushNode.php create mode 100755 system/libs/twig/Node/For.php create mode 100755 system/libs/twig/Node/ForLoop.php delete mode 100755 system/libs/twig/Node/ForLoopNode.php delete mode 100755 system/libs/twig/Node/ForNode.php create mode 100755 system/libs/twig/Node/If.php delete mode 100755 system/libs/twig/Node/IfNode.php create mode 100755 system/libs/twig/Node/Import.php delete mode 100755 system/libs/twig/Node/ImportNode.php create mode 100755 system/libs/twig/Node/Include.php delete mode 100755 system/libs/twig/Node/IncludeNode.php create mode 100755 system/libs/twig/Node/Macro.php delete mode 100755 system/libs/twig/Node/MacroNode.php create mode 100755 system/libs/twig/Node/Module.php delete mode 100755 system/libs/twig/Node/ModuleNode.php delete mode 100755 system/libs/twig/Node/Node.php delete mode 100755 system/libs/twig/Node/NodeCaptureInterface.php delete mode 100755 system/libs/twig/Node/NodeOutputInterface.php create mode 100755 system/libs/twig/Node/Print.php delete mode 100755 system/libs/twig/Node/PrintNode.php create mode 100755 system/libs/twig/Node/Sandbox.php delete mode 100755 system/libs/twig/Node/SandboxNode.php create mode 100755 system/libs/twig/Node/SandboxedPrint.php delete mode 100755 system/libs/twig/Node/SandboxedPrintNode.php create mode 100755 system/libs/twig/Node/Set.php delete mode 100755 system/libs/twig/Node/SetNode.php create mode 100755 system/libs/twig/Node/SetTemp.php delete mode 100755 system/libs/twig/Node/SetTempNode.php create mode 100755 system/libs/twig/Node/Spaceless.php delete mode 100755 system/libs/twig/Node/SpacelessNode.php create mode 100755 system/libs/twig/Node/Text.php delete mode 100755 system/libs/twig/Node/TextNode.php delete mode 100755 system/libs/twig/Node/WithNode.php create mode 100755 system/libs/twig/NodeInterface.php create mode 100755 system/libs/twig/NodeOutputInterface.php delete mode 100755 system/libs/twig/NodeVisitor/AbstractNodeVisitor.php create mode 100755 system/libs/twig/NodeVisitor/Escaper.php delete mode 100755 system/libs/twig/NodeVisitor/EscaperNodeVisitor.php delete mode 100755 system/libs/twig/NodeVisitor/NodeVisitorInterface.php create mode 100755 system/libs/twig/NodeVisitor/Optimizer.php delete mode 100755 system/libs/twig/NodeVisitor/OptimizerNodeVisitor.php create mode 100755 system/libs/twig/NodeVisitor/SafeAnalysis.php delete mode 100755 system/libs/twig/NodeVisitor/SafeAnalysisNodeVisitor.php create mode 100755 system/libs/twig/NodeVisitor/Sandbox.php delete mode 100755 system/libs/twig/NodeVisitor/SandboxNodeVisitor.php create mode 100755 system/libs/twig/NodeVisitorInterface.php create mode 100755 system/libs/twig/ParserInterface.php delete mode 100755 system/libs/twig/Profiler/Dumper/BaseDumper.php create mode 100755 system/libs/twig/Profiler/Dumper/Blackfire.php delete mode 100755 system/libs/twig/Profiler/Dumper/BlackfireDumper.php create mode 100755 system/libs/twig/Profiler/Dumper/Html.php delete mode 100755 system/libs/twig/Profiler/Dumper/HtmlDumper.php create mode 100755 system/libs/twig/Profiler/Dumper/Text.php delete mode 100755 system/libs/twig/Profiler/Dumper/TextDumper.php create mode 100755 system/libs/twig/Profiler/Node/EnterProfile.php delete mode 100755 system/libs/twig/Profiler/Node/EnterProfileNode.php create mode 100755 system/libs/twig/Profiler/Node/LeaveProfile.php delete mode 100755 system/libs/twig/Profiler/Node/LeaveProfileNode.php create mode 100755 system/libs/twig/Profiler/NodeVisitor/Profiler.php delete mode 100755 system/libs/twig/Profiler/NodeVisitor/ProfilerNodeVisitor.php delete mode 100755 system/libs/twig/RuntimeLoader/ContainerRuntimeLoader.php delete mode 100755 system/libs/twig/RuntimeLoader/FactoryRuntimeLoader.php delete mode 100755 system/libs/twig/RuntimeLoader/RuntimeLoaderInterface.php delete mode 100755 system/libs/twig/Sandbox/SecurityNotAllowedMethodError.php delete mode 100755 system/libs/twig/Sandbox/SecurityNotAllowedPropertyError.php create mode 100755 system/libs/twig/SimpleFilter.php create mode 100755 system/libs/twig/SimpleFunction.php create mode 100755 system/libs/twig/SimpleTest.php delete mode 100755 system/libs/twig/Source.php create mode 100755 system/libs/twig/TemplateInterface.php delete mode 100755 system/libs/twig/TemplateWrapper.php create mode 100755 system/libs/twig/Test.php create mode 100755 system/libs/twig/Test/Function.php create mode 100755 system/libs/twig/Test/Method.php create mode 100755 system/libs/twig/Test/Node.php create mode 100755 system/libs/twig/TestCallableInterface.php create mode 100755 system/libs/twig/TestInterface.php create mode 100755 system/libs/twig/TokenParser.php delete mode 100755 system/libs/twig/TokenParser/AbstractTokenParser.php create mode 100755 system/libs/twig/TokenParser/AutoEscape.php delete mode 100755 system/libs/twig/TokenParser/AutoEscapeTokenParser.php create mode 100755 system/libs/twig/TokenParser/Block.php delete mode 100755 system/libs/twig/TokenParser/BlockTokenParser.php create mode 100755 system/libs/twig/TokenParser/Do.php delete mode 100755 system/libs/twig/TokenParser/DoTokenParser.php create mode 100755 system/libs/twig/TokenParser/Embed.php delete mode 100755 system/libs/twig/TokenParser/EmbedTokenParser.php create mode 100755 system/libs/twig/TokenParser/Extends.php delete mode 100755 system/libs/twig/TokenParser/ExtendsTokenParser.php create mode 100755 system/libs/twig/TokenParser/Filter.php delete mode 100755 system/libs/twig/TokenParser/FilterTokenParser.php create mode 100755 system/libs/twig/TokenParser/Flush.php delete mode 100755 system/libs/twig/TokenParser/FlushTokenParser.php create mode 100755 system/libs/twig/TokenParser/For.php delete mode 100755 system/libs/twig/TokenParser/ForTokenParser.php create mode 100755 system/libs/twig/TokenParser/From.php delete mode 100755 system/libs/twig/TokenParser/FromTokenParser.php create mode 100755 system/libs/twig/TokenParser/If.php delete mode 100755 system/libs/twig/TokenParser/IfTokenParser.php create mode 100755 system/libs/twig/TokenParser/Import.php delete mode 100755 system/libs/twig/TokenParser/ImportTokenParser.php create mode 100755 system/libs/twig/TokenParser/Include.php delete mode 100755 system/libs/twig/TokenParser/IncludeTokenParser.php create mode 100755 system/libs/twig/TokenParser/Macro.php delete mode 100755 system/libs/twig/TokenParser/MacroTokenParser.php create mode 100755 system/libs/twig/TokenParser/Sandbox.php delete mode 100755 system/libs/twig/TokenParser/SandboxTokenParser.php create mode 100755 system/libs/twig/TokenParser/Set.php delete mode 100755 system/libs/twig/TokenParser/SetTokenParser.php create mode 100755 system/libs/twig/TokenParser/Spaceless.php delete mode 100755 system/libs/twig/TokenParser/SpacelessTokenParser.php delete mode 100755 system/libs/twig/TokenParser/TokenParserInterface.php create mode 100755 system/libs/twig/TokenParser/Use.php delete mode 100755 system/libs/twig/TokenParser/UseTokenParser.php delete mode 100755 system/libs/twig/TokenParser/WithTokenParser.php create mode 100755 system/libs/twig/TokenParserBroker.php create mode 100755 system/libs/twig/TokenParserBrokerInterface.php create mode 100755 system/libs/twig/TokenParserInterface.php delete mode 100755 system/libs/twig/TwigFilter.php delete mode 100755 system/libs/twig/TwigFunction.php delete mode 100755 system/libs/twig/TwigTest.php delete mode 100755 system/libs/twig/Util/DeprecationCollector.php delete mode 100755 system/libs/twig/Util/TemplateDirIterator.php create mode 100644 system/templates/admin.dashboard.html create mode 100644 system/templates/admin.login.html create mode 100644 system/templates/admin.mailer.html create mode 100644 system/templates/admin.notepad.html create mode 100644 system/templates/admin.plugins.form.html create mode 100644 system/templates/admin.plugins.html create mode 100644 system/templates/admin.statistics.html create mode 100644 system/templates/admin.visitors.html diff --git a/admin/templates/clean/style.css b/admin/template/style.css similarity index 100% rename from admin/templates/clean/style.css rename to admin/template/style.css diff --git a/admin/templates/clean/template.php b/admin/template/template.php similarity index 100% rename from admin/templates/clean/template.php rename to admin/template/template.php diff --git a/admin/templates/stylish/Kopia index.html b/admin/templates/stylish/Kopia index.html deleted file mode 100644 index 4662068f..00000000 --- a/admin/templates/stylish/Kopia index.html +++ /dev/null @@ -1,281 +0,0 @@ - - - - -Dashboard - Admin Template - - - - - - - -
- - -
-
-
-

- Right Now - Add New Product - Some Action -
-

-

You have 19 new orders, 12 new users and 5 new reviews, today you made $1523.63 in sales and a total of $328.24 profit -

-
-
-
-

Sales for July

-

-
-
-

Traffic for July

-

a

-
-
-

Last 5 Orders

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CustomerItemsGrand Total
Jennifer Kyrnin114.95 €
Mark Kyrnin234.27 €
Virgílio Cezar261.39 €
Todd Simonides51472.56 €
Carol Elihu19.95 €
-
-
-

Bestsellers

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Product NamePriceOrders
Apple iPhone 3G 8GB199.00 €24
Fuji FinePix S5800365.24 €19
Canon PIXMA MP14059.50 €12
Apple iPhone 3G 16GB199.00 €10
Prenosnik HP 530 1,6GHz499.00 €6
-
-
-

New Customers

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CustomerOrdersAverageTotal
Jennifer Kyrnin15.6€14.95 €
Mark Kyrnin214.97€34.27 €
Virgílio Cezar215.31€61.39 €
Todd Simonides5502.61€1472.56 €
Carol Elihu15.1€9.95 €
-
-
-

Last 5 Reviews

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ReviewerProductAction
Jennifer KyrninApple iPhone 3G 8GB
Mark KyrninPrenosnik HP 530 1,6GHz
Virgílio CezarFuji FinePix S5800
Todd SimonidesCanon PIXMA MP140
Carol ElihuPrenosnik HP 530 1,6GHz
-
-
-
- -
- -
- - diff --git a/admin/templates/stylish/blank.html b/admin/templates/stylish/blank.html deleted file mode 100644 index 01b09cf0..00000000 --- a/admin/templates/stylish/blank.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - -Dashboard - Admin Template - - - - - - - -
- - - - -
- - diff --git a/admin/templates/stylish/css/Copy of theme.css b/admin/templates/stylish/css/Copy of theme.css deleted file mode 100644 index 9a5f2f88..00000000 --- a/admin/templates/stylish/css/Copy of theme.css +++ /dev/null @@ -1,121 +0,0 @@ -body{ - background:#f7f6f0 url(../img/bg.jpg) repeat-x top; - color: #202020; -} -a, a:visited{ - color:#993300; -} -input{ - border:1px solid #e8e7e1; -} -select{ - border:1px solid #e8e7e1; -} -#header h2{ - color:#FFF; -} -#content{ - background:#FFF; -} -#sidebar{ - background:#FFF; -} -#sidebar h3{ - background:#f7f6f0; - border-bottom:1px solid #e8e7e1; -} -#topmenu a,#topmenu a:visited{ - color:#f7f6f0; - background:#cc3300; -} -#topmenu a:hover{ - color: #FFF; -} -#topmenu .current a, #topmenu .current a:hover, #topmenu .current a:visited{ - color:#993400; - background: #FFF url(../img/bg_menu_red.jpg) repeat-x top; - border-left: #FFF 1px solid; - border-right: #FFF 1px solid; -} -#top-panel{ - background:#FFF; -} -table{ - background:none; -} -td, th{ - border:1px solid #e8e7e1; -} -thead{ - background:#f7f6f0; -} -#styleswitcher{ - background:#FFFFFF; -} -#footer{ - background:#FFF; -} -#box{ - border:1px solid #e8e7e1; -} -#box h3{ - background:#f7f6f0; - border-bottom:1px solid #e8e7e1; - color:#993300; -} -/*************** - Forms -***************/ -form#form fieldset { - border:1px solid #e8e7e1; -} -form#form legend { - border:1px solid #e8e7e1; - background:#fff url(../img/form_red.gif) repeat-x center left; - color:#993300; -} -form#form input { - border:1px solid #e8e7e1; - background:#fff url(../img/form_red.gif) repeat-x top left; -} -form#form textarea { - border:1px solid #e8e7e1; - background:#fff url(../img/form_red.gif) repeat-x bottom left; -} -form#form option { - background:#FFF; -} -form#form optgroup { - background:#e8e7e1; -} -form#form optgroup option { - -} -form#form #button1, form#form #button2 { - color:#c00; -} -form#form #button1:hover, form#form #button2:hover { - color:#000; -} -/*************** - Home -***************/ -#infobox{ - border:1px solid #e8e7e1; -} -#infobox h3{ - background:#f7f6f0; - border-bottom:1px solid #e8e7e1; - color:#993300; -} -#rightnow { - border:1px solid #e8e7e1; -} -#rightnow .reallynow { - background:#f7f6f0; - color:#993300; -} -#rightnow h3{ - background:#f7f6f0; - border-bottom:1px solid #e8e7e1; -} \ No newline at end of file diff --git a/admin/templates/stylish/css/ie-sucks.css b/admin/templates/stylish/css/ie-sucks.css deleted file mode 100644 index 27a6c23a..00000000 --- a/admin/templates/stylish/css/ie-sucks.css +++ /dev/null @@ -1,21 +0,0 @@ -#content{ - width:740px; -} -#topmenu{ - margin-top:26px; -} -#sidebar{ - width:160px; -} -#sidebar ul{ - width:150px; -} -#sidebar ul li ul{ - width:140px; -} -#sidebar h3{ - margin-bottom:5px; -} -#rightnow .reallynow a { - padding:0 0 0 10px; -} \ No newline at end of file diff --git a/admin/templates/stylish/css/iepngfix.htc b/admin/templates/stylish/css/iepngfix.htc deleted file mode 100644 index a8c5d312..00000000 --- a/admin/templates/stylish/css/iepngfix.htc +++ /dev/null @@ -1,68 +0,0 @@ - - - - - \ No newline at end of file diff --git a/admin/templates/stylish/css/style.css b/admin/templates/stylish/css/style.css deleted file mode 100644 index 345f94e3..00000000 --- a/admin/templates/stylish/css/style.css +++ /dev/null @@ -1,397 +0,0 @@ -/********************* - HTML Elements -*********************/ -*{ - margin:0; - padding:0; -} -img, div,a { behavior: url(css/iepngfix.htc) } -body{ - font-size: 12px; - font-family: Arial, Tahoma, Verdana; -} -a, a:visited{ - text-decoration:none; -} -img{ - border:0; - margin:1px; -} -p{ - padding:3px; -} -h2{ - -} -input{ - padding:2px; -} -select{ - padding:2px; -} -/********************* - Status -*********************/ -#status { - position: absolute; top: 10px; left: 10px; - margin: 0px; - float: right; - font-size: 12px; -} -#status .success { - margin: 0px: -} -#version { - position: absolute; top: 10px; right: 10px; - float: right; - text-align: right; - font-size: 12px; -} -/********************* - Structure -*********************/ -#container{ - width:960px; - margin-left:auto; - margin-right:auto; -} -#header{ - width:960px; -} -#header h2{ - margin-top:20px; -} -#content{ - width:740px; - float:left; - margin:10px 0 10px 0; - padding:10px; -} -#sidebar{ - background:#FFF; - width:170px; - float:right; - margin:10px 0 10px 0; - padding:10px; -} -#footer{ - clear:both; - padding:5px; - margin-top:10px; -} -#box h3{ - padding:5px; - font-size:14px; -} -/********************* - Sidebar -*********************/ -#sidebar ul{ - list-style:none; - line-height:22px; -} -#sidebar ul li a,#sidebar ul li a:visited{ - padding-left:19px; - text-decoration:none; - margin:0 3px; - display:block; -} -#sidebar ul li a:hover{ - text-decoration:underline; -} -#sidebar ul li ul{ - margin-left:10px; -} -#sidebar h3{ - padding:2px; - font-size:14px; -} -/********************* - TopMenu, Top-Panel -*********************/ -#topmenu{ - margin-top:33px; - width:700px; - float:left; - voice-family:inherit; -} -#topmenu ul{ - list-style:none; - line-height:25px; -} -#topmenu li{ - display:inline; -} -#topmenu a,#topmenu a:visited{ - padding:5px 12px 5px 12px; - text-decoration:none; -} -#topmenu .current a, #topmenu .current a:hover, #topmenu .current a:visited{ - padding:5px 12px 5px 12px; - font-weight:bold; - -} -#top-panel{ - background:#FFF; - padding:5px; - height:20px; - float:left; - width:950px; -} -#top-panel ul{ - list-style:none; -} -#top-panel ul li{ - display:inline; - line-height:20px; -} -#top-panel ul li a{ - padding-left:19px; - text-decoration:none; - margin:0 3px; - display:inline-block; -} -#top-panel a:hover{ - text-decoration:underline; -} -/********************* - Other -*********************/ -.a-right{text-align:right;} -.a-left{text-align:left;} -.a-center{text-align:center;} -#pager{ - margin:5px; - height:25px; -} -#styleswitcher{ - float:right; -} -#styleswitcher ul{ - list-style:none; - line-height:10px; -} -#styleswitcher li{ - height:12px; - display:inline; -} -#footer ul { - list-style:none; -} -#footer li { - display:inline; -} -a#defswitch { - width:15px; - height:10px; - margin: 3px 0 3px 0; - background-color:#bd3f09; - font-size: 8px; - color:#bd3f09; - display:inline-block; -} -a#blueswitch { - width:15px; - height:10px; - margin: 3px 0 3px 0; - background-color:#375b91; - font-size: 8px; - color:#375b91; - display:inline-block; -} -a#greenswitch { - width:15px; - height:10px; - margin: 3px 0 3px 0; - background-color:#d0e0b8; - font-size: 8px; - color:#d0e0b8; - display:inline-block; -} -a#brownswitch { - width:15px; - height:10px; - margin: 3px 0 3px 0; - background-color:#654322; - font-size: 8px; - color:#654322; - display:inline-block; -} -a#mixswitch { - width:15px; - height:10px; - margin: 3px 0 3px 0; - background-color:#294145; - font-size: 8px; - color:#294145; - display:inline-block; -} -#credits{ - clear:both; - width:250px; - float:left; -} -/********************* - Tables -*********************/ -table{ - margin:5px; - border-collapse: collapse; - table-layout:automatic; - width:98%; -} -td, th{ - padding: 2px; -} -thead{ - -} -/********************* - Home -*********************/ -#infowrap li{ - display:inline: -} -#infobox{ - width:365px; - float:left; - margin-top:10px; -} -#infobox h3{ - padding:5px; - font-size:14px; -} -.margin-left{ - margin-left:5px; -} -#rightnow .reallynow { - padding: 5px; - font-size:14px; -} -#rightnow h3{ - padding:2px; - padding: 0 10px; - font-size:14px; -} -#rightnow .reallynow span { - display: block; - text-align: left; - float: left; - padding:0 2px; - font-size:14px -} -#rightnow .reallynow a { - text-decoration:none; - display: block; - text-align: right; - float: right; - padding:0 0 0 18px; - margin-left:4px; - font-weight:normal; - font-size:12px; -} -#rightnow .reallynow a:hover{ - text-decoration:underline; -} -#rightnow .youhave { - font-size: 12px; - padding: 10px; -} -#rightnow a { - font-weight: bold; -} -/********************* - Forms -*********************/ -form{ - padding:10px; - margin:0 auto; -} -form#form fieldset { - display:block; - padding:5px 10px 5px 10px; - line-height:20px; - margin-bottom:10px; -} -form#form legend { - font-size:12px; - font-weight:bold; - margin-bottom:5px; - padding:3px; - width:254px; -} -form#form label { - clear:left; - display:block; - float:left; - width:100px; - text-align:right; - padding-right:10px; - margin-bottom:5px; -} -form#form input { - padding:3px; - margin-bottom:5px; -} -form#form select { - margin-left:5px; -} -form#form textarea { - width:410px; - height:200px; - padding:5px; - overflow:auto; -} -form#form option { - background:#FFF; -} -form#form optgroup option { - -} -form#form #button1, form#form #button2 { - padding-right:5px; - cursor:pointer; - width:205px; - margin-left:8px; - font-weight:bold; -} -form#form #button1:hover, form#form #button2:hover { - background-position:center left; -} - -/********************* - Icons -*********************/ -.icon{ - padding-left:19px; - text-decoration:none; - height:20px; - font-size:12x; - margin:0 3px; - display:inline-block; - line-height:20px; -} -.user{background:transparent url(../img/icons/user.png) no-repeat left;} -.useradd{background:transparent url(../img/icons/user_add.png) no-repeat left;} -.group{background:transparent url(../img/icons/group.png) no-repeat left;} -.search{background:transparent url(../img/icons/magnifier.png) no-repeat left;} -.online{background:transparent url(../img/icons/world.png) no-repeat left;} -.pagenew{background:transparent url(../img/icons/page_add.png) no-repeat left;} -.rss{background:transparent url(../img/icons/rss.png) no-repeat left;} -.feed{background:transparent url(../img/icons/feed.png) no-repeat left;} -.report{background:transparent url(../img/icons/report.png) no-repeat left;} -.house{background:transparent url(../img/icons/house.png) no-repeat left;} -.manage{background:transparent url(../img/icons/cog.png) no-repeat left;} -.manage_page{background:transparent url(../img/icons/page_gear.png) no-repeat left;} -.folder{background:transparent url(../img/icons/folder.png) no-repeat left;} -.promotions{background:transparent url(../img/icons/coins.png) no-repeat left;} -.cart{background:transparent url(../img/icons/cart.png) no-repeat left;} -.folder_table{background:transparent url(../img/icons/folder_page.png) no-repeat left;} -.shipping{background:transparent url(../img/icons/car.png) no-repeat left;} -.invoices{background:transparent url(../img/icons/page_white_text_width.png) no-repeat left;} -.addorder{background:transparent url(../img/icons/folder_page_add.png) no-repeat left;} -.add{background:transparent url(../img/icons/add.png) no-repeat left;} -.app_add{background:transparent url(../img/icons/application_add.png) no-repeat left;} -.report_seo{background:transparent url(../img/icons/report_link.png) no-repeat left;} -.modules{background:transparent url(../img/icons/bricks.png) no-repeat left;} -.modules_manage{background:transparent url(../img/icons/bricks_gear.png) no-repeat left;} \ No newline at end of file diff --git a/admin/templates/stylish/css/switch.css b/admin/templates/stylish/css/switch.css deleted file mode 100644 index 544d9a5a..00000000 --- a/admin/templates/stylish/css/switch.css +++ /dev/null @@ -1,51 +0,0 @@ -#footer ul { - list-style:none; -} -#footer li { - display:inline; -} -a#defswitch { - width:15px; - height:10px; - margin: 3px 0 3px 0; - background-color:#bd3f09; - font-size: 8px; - color:#bd3f09; - display:inline-block; -} -a#blueswitch { - width:15px; - height:10px; - margin: 3px 0 3px 0; - background-color:#375b91; - font-size: 8px; - color:#375b91; - display:inline-block; -} -a#greenswitch { - width:15px; - height:10px; - margin: 3px 0 3px 0; - background-color:#d0e0b8; - font-size: 8px; - color:#d0e0b8; - display:inline-block; -} -a#brownswitch { - width:15px; - height:10px; - margin: 3px 0 3px 0; - background-color:#654322; - font-size: 8px; - color:#654322; - display:inline-block; -} -a#mixswitch { - width:15px; - height:10px; - margin: 3px 0 3px 0; - background-color:#294145; - font-size: 8px; - color:#294145; - display:inline-block; -} diff --git a/admin/templates/stylish/css/theme.css b/admin/templates/stylish/css/theme.css deleted file mode 100644 index 6d341e82..00000000 --- a/admin/templates/stylish/css/theme.css +++ /dev/null @@ -1,121 +0,0 @@ -body{ - background:#f7f6f0 url(../img/bg.jpg) repeat-x top; - color: #202020; -} -a, a:visited{ - color:#a43708; -} -input{ - border:1px solid #e8e7e1; -} -select{ - border:1px solid #e8e7e1; -} -#header h2{ - color:#FFF; -} -#content{ - background:#FFF; -} -#sidebar{ - background:#FFF; -} -#sidebar h3{ - background:#f7f6f0; - border-bottom:1px solid #e8e7e1; -} -#topmenu a,#topmenu a:visited{ - color:#f7f6f0; - background:#bd3f09; -} -#topmenu a:hover{ - color: #FFF; -} -#topmenu .current a, #topmenu .current a:hover, #topmenu .current a:visited{ - color:#993400; - background: #FFF url(../img/bg_menu_red.jpg) repeat-x top; - border-left: #FFF 1px solid; - border-right: #FFF 1px solid; -} -#top-panel{ - background:#FFF; -} -table{ - background:none; -} -td, th{ - border:1px solid #e8e7e1; -} -thead{ - background:#f7f6f0; -} -#styleswitcher{ - background:#FFFFFF; -} -#footer{ - background:#FFF; -} -#box{ - border:1px solid #e8e7e1; -} -#box h3{ - background:#f7f6f0; - border-bottom:1px solid #e8e7e1; - color:#a43708; -} -/*************** - Forms -***************/ -form#form fieldset { - border:1px solid #e8e7e1; -} -form#form legend { - border:1px solid #e8e7e1; - background:#fff url(../img/form_red.gif) repeat-x center left; - color:#a43708; -} -form#form input { - border:1px solid #e8e7e1; - background:#fff url(../img/form_red.gif) repeat-x top left; -} -form#form textarea { - border:1px solid #e8e7e1; - background:#fff url(../img/form_red.gif) repeat-x bottom left; -} -form#form option { - background:#FFF; -} -form#form optgroup { - background:#e8e7e1; -} -form#form optgroup option { - -} -form#form #button1, form#form #button2 { - color:#c00; -} -form#form #button1:hover, form#form #button2:hover { - color:#000; -} -/*************** - Home -***************/ -#infobox{ - border:1px solid #e8e7e1; -} -#infobox h3{ - background:#f7f6f0; - border-bottom:1px solid #e8e7e1; - color:#a43708; -} -#rightnow { - border:1px solid #e8e7e1; -} -#rightnow .reallynow { - background:#f7f6f0; - color:#a43708; -} -#rightnow h3{ - background:#f7f6f0; - border-bottom:1px solid #e8e7e1; -} \ No newline at end of file diff --git a/admin/templates/stylish/css/theme1.css b/admin/templates/stylish/css/theme1.css deleted file mode 100644 index 0e2803e4..00000000 --- a/admin/templates/stylish/css/theme1.css +++ /dev/null @@ -1,121 +0,0 @@ -body{ - background:#f3f9ff url(../img/bg_blue.jpg) repeat-x top; - color: #202020; -} -a, a:visited{ - color:#375b91; -} -input{ - border:1px solid #d9e6f0; -} -select{ - border:1px solid #d9e6f0; -} -#header h2{ - color:#FFF; -} -#content{ - background:#FFF; -} -#sidebar{ - background:#FFF; -} -#sidebar h3{ - background:#f3f9ff; - border-bottom:1px solid #d9e6f0; -} -#topmenu a,#topmenu a:visited{ - color:#FFF; - background:#7e9dcc; -} -#topmenu a:hover{ - color: #FFF; -} -#topmenu .current a, #topmenu .current a:hover, #topmenu .current a:visited{ - color:#375b91; - background: #FFF url(../img/bg_menu_blue.jpg) repeat-x top; - border-left: #FFF 1px solid; - border-right: #FFF 1px solid; -} -#top-panel{ - background:#FFF; -} -table{ - background:none; -} -td, th{ - border:1px solid #d9e6f0; -} -thead{ - background:#f3f9ff; -} -#styleswitcher{ - background:#FFFFFF; -} -#footer{ - background:#FFF; -} -#box{ - border:1px solid #d9e6f0; -} -#box h3{ - background:#f3f9ff; - border-bottom:1px solid #d9e6f0; - color:#375b91; -} -/*************** - Forms -***************/ -form#form fieldset { - border:1px solid #d9e6f0; -} -form#form legend { - border:1px solid #d9e6f0; - background:#fff url(../img/form_blue.gif) repeat-x center left; - color:#375b91; -} -form#form input { - border:1px solid #d9e6f0; - background:#fff url(../img/form_blue.gif) repeat-x top left; -} -form#form textarea { - border:1px solid #d9e6f0; - background:#fff url(../img/form_blue.gif) repeat-x bottom left; -} -form#form option { - background:#FFF; -} -form#form optgroup { - background:#d9e6f0; -} -form#form optgroup option { - -} -form#form #button1, form#form #button2 { - color:#375b91; -} -form#form #button1:hover, form#form #button2:hover { - color:#000; -} -/*************** - Home -***************/ -#infobox{ - border:1px solid #d9e6f0; -} -#infobox h3{ - background:#f3f9ff; - border-bottom:1px solid #d9e6f0; - color:#375b91; -} -#rightnow { - border:1px solid #d9e6f0; -} -#rightnow .reallynow { - background:#f3f9ff; - color:#375b91; -} -#rightnow h3{ - background:#f3f9ff; - border-bottom:1px solid #d9e6f0; -} \ No newline at end of file diff --git a/admin/templates/stylish/css/theme2.css b/admin/templates/stylish/css/theme2.css deleted file mode 100644 index 1876b9fc..00000000 --- a/admin/templates/stylish/css/theme2.css +++ /dev/null @@ -1,121 +0,0 @@ -body{ - background:#f0f7e8 url(../img/bg_light_green.jpg) repeat-x top; - color: #202020; -} -a, a:visited{ - color:#93ad7e; -} -input{ - border:1px solid #e7eedf; -} -select{ - border:1px solid #e7eedf; -} -#header h2{ - color:#FFF; -} -#content{ - background:#FFF; -} -#sidebar{ - background:#FFF; -} -#sidebar h3{ - background:#f0f7e8; - border-bottom:1px solid #e7eedf; -} -#topmenu a,#topmenu a:visited{ - color:#93ad7e; - background:#e7eedc; -} -#topmenu a:hover{ - color: #93ad7e; -} -#topmenu .current a, #topmenu .current a:hover, #topmenu .current a:visited{ - color:#93ad7e; - background: #FFF url(../img/bg_menu_green.jpg) repeat-x top; - border-left: #FFF 1px solid; - border-right: #FFF 1px solid; -} -#top-panel{ - background:#FFF; -} -table{ - background:none; -} -td, th{ - border:1px solid #e7eedf; -} -thead{ - background:#f0f7e8; -} -#styleswitcher{ - background:#FFFFFF; -} -#footer{ - background:#FFF; -} -#box{ - border:1px solid #e7eedf; -} -#box h3{ - background:#f0f7e8; - border-bottom:1px solid #e7eedf; - color:#93ad7e; -} -/*************** - Forms -***************/ -form#form fieldset { - border:1px solid #e7eedf; -} -form#form legend { - border:1px solid #e7eedf; - background:#fff url(../img/form_green.gif) repeat-x center left; - color:#93ad7e; -} -form#form input { - border:1px solid #e7eedf; - background:#fff url(../img/form_green.gif) repeat-x top left; -} -form#form textarea { - border:1px solid #e7eedf; - background:#fff url(../img/form_green.gif) repeat-x bottom left; -} -form#form option { - background:#FFF; -} -form#form optgroup { - background:#e7eedf; -} -form#form optgroup option { - -} -form#form #button1, form#form #button2 { - color:#93ad7e; -} -form#form #button1:hover, form#form #button2:hover { - color:#000; -} -/*************** - Home -***************/ -#infobox{ - border:1px solid #e7eedf; -} -#infobox h3{ - background:#f0f7e8; - border-bottom:1px solid #e7eedf; - color:#93ad7e; -} -#rightnow { - border:1px solid #e7eedf; -} -#rightnow .reallynow { - background:#f0f7e8; - color:#93ad7e; -} -#rightnow h3{ - background:#f0f7e8; - border-bottom:1px solid #e7eedf; -} \ No newline at end of file diff --git a/admin/templates/stylish/css/theme3.css b/admin/templates/stylish/css/theme3.css deleted file mode 100644 index 9fb95faa..00000000 --- a/admin/templates/stylish/css/theme3.css +++ /dev/null @@ -1,121 +0,0 @@ -body{ - background:#f7f6f1 url(../img/bg_brown.jpg) repeat-x top; - color: #202020; -} -a, a:visited{ - color:#654322; -} -input{ - border:1px solid #e9e8e3; -} -select{ - border:1px solid #e9e8e3; -} -#header h2{ - color:#FFF; -} -#content{ - background:#FFF; -} -#sidebar{ - background:#FFF; -} -#sidebar h3{ - background:#f7f6f1; - border-bottom:1px solid #e9e8e3; -} -#topmenu a,#topmenu a:visited{ - color:#FFF; - background:#8f6831; -} -#topmenu a:hover{ - color: #654322; -} -#topmenu .current a, #topmenu .current a:hover, #topmenu .current a:visited{ - color:#654322; - background: #FFF url(../img/bg_menu_brown.jpg) repeat-x top; - border-left: #FFF 1px solid; - border-right: #FFF 1px solid; -} -#top-panel{ - background:#FFF; -} -table{ - background:none; -} -td, th{ - border:1px solid #e9e8e3; -} -thead{ - background:#f7f6f1; -} -#styleswitcher{ - background:#FFFFFF; -} -#footer{ - background:#FFF; -} -#box{ - border:1px solid #e9e8e3; -} -#box h3{ - background:#f7f6f1; - border-bottom:1px solid #e9e8e3; - color:#654322; -} -/*************** - Forms -***************/ -form#form fieldset { - border:1px solid #e9e8e3; -} -form#form legend { - border:1px solid #e9e8e3; - background:#fff url(../img/form_brown.gif) repeat-x center left; - color:#654322; -} -form#form input { - border:1px solid #e9e8e3; - background:#fff url(../img/form_brown.gif) repeat-x top left; -} -form#form textarea { - border:1px solid #e9e8e3; - background:#fff url(../img/form_brown.gif) repeat-x bottom left; -} -form#form option { - background:#FFF; -} -form#form optgroup { - background:#e9e8e3; -} -form#form optgroup option { - -} -form#form #button1, form#form #button2 { - color:#654322; -} -form#form #button1:hover, form#form #button2:hover { - color:#000; -} -/*************** - Home -***************/ -#infobox{ - border:1px solid #e9e8e3; -} -#infobox h3{ - background:#f7f6f1; - border-bottom:1px solid #e9e8e3; - color:#654322; -} -#rightnow { - border:1px solid #e9e8e3; -} -#rightnow .reallynow { - background:#f7f6f1; - color:#654322; -} -#rightnow h3{ - background:#f7f6f1; - border-bottom:1px solid #e9e8e3; -} \ No newline at end of file diff --git a/admin/templates/stylish/css/theme4.css b/admin/templates/stylish/css/theme4.css deleted file mode 100644 index ce4bba24..00000000 --- a/admin/templates/stylish/css/theme4.css +++ /dev/null @@ -1,122 +0,0 @@ -body{ - background:#d9eaed url(../img/bg_mix.jpg) repeat-x top; - color: #202020; -} -a, a:visited{ - color:#294145; - text-decoration:underline; -} -input{ - border:1px solid #c3d7db; -} -select{ - border:1px solid #c3d7db; -} -#header h2{ - color:#FFF; -} -#content{ - background:#FFF; -} -#sidebar{ - background:#FFF; -} -#sidebar h3{ - background:#d9eaed; - border-bottom:1px solid #c3d7db; -} -#topmenu a,#topmenu a:visited{ - color:#FFF; - background:#5d99a3; -} -#topmenu a:hover{ - color: #294145; -} -#topmenu .current a, #topmenu .current a:hover, #topmenu .current a:visited{ - color:#294145; - background: #FFF url(../img/bg_menu_mix.jpg) repeat-x top; - border-left: #FFF 1px solid; - border-right: #FFF 1px solid; -} -#top-panel{ - background:#FFF; -} -table{ - background:none; -} -td, th{ - border:1px solid #c3d7db; -} -thead{ - background:#d9eaed; -} -#styleswitcher{ - background:#FFFFFF; -} -#footer{ - background:#FFF; -} -#box{ - border:1px solid #c3d7db; -} -#box h3{ - background:#d9eaed; - border-bottom:1px solid #c3d7db; - color:#294145; -} -/*************** - Forms -***************/ -form#form fieldset { - border:1px solid #c3d7db; -} -form#form legend { - border:1px solid #c3d7db; - background:#fff url(../img/form_mix.gif) repeat-x center left; - color:#294145; -} -form#form input { - border:1px solid #c3d7db; - background:#fff url(../img/form_mix.gif) repeat-x top left; -} -form#form textarea { - border:1px solid #c3d7db; - background:#fff url(../img/form_mix.gif) repeat-x bottom left; -} -form#form option { - background:#FFF; -} -form#form optgroup { - background:#c3d7db; -} -form#form optgroup option { - -} -form#form #button1, form#form #button2 { - color:#294145; -} -form#form #button1:hover, form#form #button2:hover { - color:#000; -} -/*************** - Home -***************/ -#infobox{ - border:1px solid #c3d7db; -} -#infobox h3{ - background:#d9eaed; - border-bottom:1px solid #c3d7db; - color:#294145; -} -#rightnow { - border:1px solid #c3d7db; -} -#rightnow .reallynow { - background:#d9eaed; - color:#294145; -} -#rightnow h3{ - background:#d9eaed; - border-bottom:1px solid #c3d7db; -} \ No newline at end of file diff --git a/admin/templates/stylish/img/bg.jpg b/admin/templates/stylish/img/bg.jpg deleted file mode 100644 index 1980c13f52beeef49e1aa3ca33b4c6ca1751e18f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 372 zcmex=C5UDGKfoZ!!El0siJ4K5fk}{&S&;Gn5r#OB z!+?%N0$iLRyO0EcOb$)~Mg~S!6hRi|h#5De1cBmA?8p*~OcKmft~?1{8utGd0}nGJ z&@yI027891$3nI}fhi1~ZZzS2lb_+G8?COnKWeTNU6 E0J7mVwEzGB diff --git a/admin/templates/stylish/img/bg_blue.jpg b/admin/templates/stylish/img/bg_blue.jpg deleted file mode 100644 index ad55db4d40738f488d5c2d37f17d7064b3ebd218..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 359 zcmex=C5UDGKfoZ!!El0sk(p7Dfk}{&S&;Gn5r#;R z!+?%N0$iM6yO2Z}7}z;D1sEBaQB^+ASRp0I$iT>oqV)0NlqIR+|8Fty0F^TdG7B=; pGn`g;iZpC5UDGKfoZ!!El0sk(p7Dfk}{&S&;Gn5r#03 z!+?%N0$iLRyO0EcOm+?dMh0e7!RHw(qy#ZU7e7uB|9^{t2dJ1ykXewyp5e$c-^>e8 i;~2wYj>qn~X{UMTaf;cpxxzAAwT}Ax!t7%Ie-i*+I4scs diff --git a/admin/templates/stylish/img/bg_light_green.jpg b/admin/templates/stylish/img/bg_light_green.jpg deleted file mode 100644 index b091ebdf6105f9f4927e46b7636b127df0349aff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 356 zcmex=C5UDGKfoZ!!El0sk(p7Dfk}{&S&;Gn5r$}x z!+?%N0_=~}Eo*S$HHInJ+F_Q`3R-M=1cjng4RV~*|qXS@;{l5tS$OJEv diff --git a/admin/templates/stylish/img/bg_menu_blue.jpg b/admin/templates/stylish/img/bg_menu_blue.jpg deleted file mode 100644 index 0a406082e665df0cc56b734d548708f1000b3fe1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 372 zcmex=C5UDGKfoZ!!63)L$jm6nz$D1XEXer(2tyjk zVL(SB04oC*$S#Bckj28tDgg8!2RpLpheRf!OU%M76Bj-Vnk*6`2n-Vxc?L$|#EDEo zNX3B-@qAsf#-g&(>IB40LEviR1x~@=OFh}H4 S_ipWK33CRUmdC>XZvp_+jX0nH diff --git a/admin/templates/stylish/img/bg_menu_green.jpg b/admin/templates/stylish/img/bg_menu_green.jpg deleted file mode 100644 index 503f7198e2783eb088e16e470d7a67fc548f57e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 383 zcmex=C5UDGKfoZ!!63)L$jm6nz$D1XEXer(2tytN z12ZGgkqE%T%EraWz{HFY0kW7`m{{2afWBttL>6ZhNn~OXoVYM((Iw`PDS|+GCT6qz{H6cnUp3m2ebUY#lQo!jY*JMkinkeZt|{wU-MVbubfhS`R4qhN6O}^*;Vak gO%Dt%Y6dLG<<*EZkz$TkIWyhIe9?g|^8arF09!^mw*UYD diff --git a/admin/templates/stylish/img/bg_menu_mix.jpg b/admin/templates/stylish/img/bg_menu_mix.jpg deleted file mode 100644 index c006525b5a88bcc97e825034a1d66a491b07073d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 379 zcmex=C5UDGKfoZ!!63)L$jm6nz$D1XEXer(2ty{w zVL(SB02?b8$S#Bckj2cxDgg8!D=)HW;6)}8Rz|^z8y^O3y2Q*fMKn|pXgDj1PDVwc z#EDEn%)C5UDGKfoZ!!63)L$jm6nz$D1XEXer(2tyjk zVL(SB04p08*e-+!0|PS?1FHZ70}Bf~vM6Jq$cKd&Sp_FDUuKySD#!>lniW}Ih*6M9 zF>#_&(EnQuJj{$hOPK{3>>2Ltp1pr*;rpU;cDu-5rzgGKSoUO+7E5=`Z)cA)I$2ZI Oq_lz-#I30Re-i+bmo^Ci diff --git a/admin/templates/stylish/img/bg_mix.jpg b/admin/templates/stylish/img/bg_mix.jpg deleted file mode 100644 index f328fb3c6e4e33571521fd8f712775c249ae0a53..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 353 zcmex=C5UDGKfoZ!!El0sk(p7Dfk}{&S&;Gn5r#;h z!+>r?23$Z9W>i6D7B+SP4AJKqE2IP&85miSbu%O`e3&FG^8XeC56}=ML1sY)dxp7U f2am%Pv4$0^mu)Wj)?T9jG1Yt3My3xing2Hd#W5>H diff --git a/admin/templates/stylish/img/form_blue.gif b/admin/templates/stylish/img/form_blue.gif deleted file mode 100644 index 8952f3830e1faf0c4e8bcdb9951587e297d85d3b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 272 zcmZ?wbhEHbWMnX6xXQrr^24`ZfBt^`@%#6mzu$iT{`c?S`>#Krz5Dv~-PhaCKR$W; z<>BkkAHV(j`TOsWUw>{s`|#@H_q#7X-hKJ$(VH*#Uw!)g{nwWtKwbZzzyJE~%a2>n zKRkH#`N8YYkKY1?|GfC{?cU2zzyJQb_59=aUw=M){rUIbzfa$P-Fflx^{4M|KmYji z_uv2j{~0I%ia%Mvx^+M#$WIJxx(B9y2+~*?ve0qC!@?d8Chwz16eNvSig2+q))=t2 WEHaKPFcX=eQe>s-GRs|n!5RQhE|G5l diff --git a/admin/templates/stylish/img/form_brown.gif b/admin/templates/stylish/img/form_brown.gif deleted file mode 100644 index 8e1efcc7f07188174626e887b29fa97a65803bc2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 273 zcmZ?wbhEHbWMnX6xXQrr z|Nrmv$CrQq{C@uU%8MsgpFX(o=-#Pk4=+4_bm{f;n~(3EdGg@ggFDB+e0u%$^P87X zuRpne=HvTkKYx7r^ZV!TUq8NmegEs{w|B1}Fc1wCf3kqp>VQa)pBUKm4s<><%iJ19N_HHaxyvgCqC=NLgf^CS}587BFb5tTzEYB06s~{(~4o@EMC@ zI#s4D6_uJXnJ09fvTsop+R8$tSR+?tK|V#rVmgzWCv@h#A!W=}o)q(#Onq=UUr@2E zj4-ZR7GHH;!~fVdjlV#D<<%232d6Ks@y+H&d#lS18&~fS(dd4(_tx6qergXo&v4!A R?!aa5;Pq}edF-si$uDiTjC241 diff --git a/admin/templates/stylish/img/form_mix.gif b/admin/templates/stylish/img/form_mix.gif deleted file mode 100644 index b7fd05b6c4872c9e1eb6cd1106d957c4c6069050..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 273 zcmZ?wbhEHbWMnX6xXQqA^v0dvfBv4n^Wf9B?|=XO`|<1duRnkO{rmU){l_bho?d`t9|n&lev&zWngX!`E+5-MN4K*4^{> zAAS7x{n*XBPu{-2_3Y)5>$hKg_;}~VtN;K1GY}0Ff3kqp>VQa)pBUKm4n#b6C}824 u)5P*=22aSMW9cQ8iehWJG>Nk%w1VF3U#0K@`uG0+{`2$h`}+C+|Nipv z?Dh2T_Vw}i_w)Dm^8Ebz`T6$p@$2>V@csS#`1kbi@9O#Z_3-cM=;z_>?B?p}R} z>+0n1?&$36<>~0+A^8LV00000EC2ui0096p000Fe;E))^1UyIqSybaN(sBfX5>?mL U?OUJyo*-waDSnPe3?>8sJMlqoYXATM diff --git a/admin/templates/stylish/img/graph.jpg b/admin/templates/stylish/img/graph.jpg deleted file mode 100644 index 56b1469d874ebafe75cee9a62bdd1c1a0747307e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40975 zcmeFZ1yo#Hvo6|52m}bBAvh#~#@#&xryFk?x8N4sAwVDm*QRj`?(QDk-95NNun;Uf z_P@_L|9)?rd(IyBo%ik;@&l{X@_JPcfdMp`bo_ z{Hj0XaTMv#5dZ+~Df$x>R19RK7mu$|000y;6tpL($dAV(KOTUF4nTTZ$LEF%#N(~U zz$egn^KynLVU7|OM;Omeg-{m-afner!vz4IAS0upp*ZTf85l9!2dR@+E#U?jDn5wITM@#nxL-J0Q_J!zIq5x^1dL7o}ZrUpO0iqeX z>&DWMj;@uCTBnZusM-NS_KL`AN57mqTvGoZa~@||Xml}fiO4n2T{Jh>w)ao>aE_nA zRI(t3X$kftp}}fsb4xCGV|h?|s!5^#&&h*^c4!G8s7zUb>{ne1xp2RC^Te2qGtx#p zi53z>xVx_@KIiJ#hz~TrBJl%HHN6O|YByOXj`OW3=%GK}FE3^3zh9|L*K(;1V{bw*ZtgkLpEPlMsH;Y#2-ld2C;GZ^~G%#>0PoPw}1Ap2S7MQ z%y(qZ|B+AsBY*eaQ>9VvVFhVLMh{V9&Sztt<=?ldy)!Vb55tdIxZSx}cUjpkN?;&9&CogGaF>%dUb@x-{+I(#0vgqz|j9 z8QV38_@NHY9&PByZ^{nMH#D_-Rw>Jk{wbIu2yp-XzGQy_Ryl=@T{d(y`D7xVmS$r7 zysmbd(QKKWS8rD&F?nn0Mk=z1XDBbYjljxj3Fy+((OXFpQy24<0D#rbk|X3`_HyIY zmAeJq_lLLRtL?iUg}4vvA6sI{WV2>%8VKR_t%3x*{BjNH8PoZm5mSx67MNYJVA&v8 zs-a&1(q4lJbW7*UQyFQ3rSfTAcarrR&JF)mJAGqY90$E{E(E0G`v^gJIT&f9dzqN8KZ&Eg=O@qpb6Jhia9*%DpD=`SYZH4pDvLl{p$4 z%8=h!%sUm+K_st2rV>l+CMpim@;R+iT#8ZV?JaHbH^>XjpvHF3=M(tCv_Ctd_e<7W z%Q6|@`+jINqKxM+vR8tGSz?5a8i*OdGC>w3#C@;Z>8@&iyd$1NdjI4T0YKyb@$@5K zDV4-=x=0970EJtAVSte!C z<<3aIcMWAQQstJ-U11zobX6T9`99o2BRV}ICTr;2j0Wq(TWXTS?DQ_7=bm`yj%;U$&_X%3oSSZ)NEu% zJZ_FF>6Y=FBShG^9sQLF--i7n;OUi|q#UF1RNEg~L3vV(XtW?gHj06kS`1JO@#VSh zWwYm!&hd{5Z=ZA7yAl@QQbYLhG^CdQYv?>*6}|~xAlB9aR9X{X zRPH1-Md$QryAO#gJ6HJQ__} zG7h(JE1D#WOlXBN&!Ty+Dh4I^0YEtwbK$J|0LW_v-%-W-bT+qLhmc+|*oF{aou>17 z|I}#%&)m83KrB*46z%woO@yH({!+^aCM8}jkujb8?s5^f_A423iyJ2_*snvMAkV6S zfPoyi`D_(ri1?T9m_(m_cH)N&KJS%3C6`Gs&&<(*g-rQn=S@M!l?f2^;Qb%muT$*c zSxit_P26aDja~MJnxs+_*igu^l`j-q=f!ZwWOOm_i^Xck0q5$n(isSu3R6K>G+Zq= znHx6=&rk81AUi#)u~&(){R2lMtfDmq=5JM z6n(O%JhUV{h?+nF+D#*|+R5($g40M`{GRELsd}3$Pe2#%k_n2QxdPBC;bA=6#26iO zvY-y*h<_PqRKbco$u=%yy{GaYS zD_m;QFKj4%`YN|>-aeK=ssdusnG#^U^kH~|i)q1mCLG)@wHQG~u9_cCdlw2-9G_PI zopw$8BjV8)&(9tJ+jO=|1+8>ut34mrZs#5DX|+$k&pXnmiiA$yYSV;GGt862rLD{y zy(0UF>djcqJqqN4w#dQiV8zyQw#1LQP_5I)i2`jQ1;6;{sF)) z?!6^{D*pC2=MK)wVEmrIY9!$qGgw4gRsY6wGrfcFufFmjJ`X%G8N5if?fq=Rnd|gh zS#ckcBo8Yx4gph^q_F=KeeJcD(z1MXd9)heokE_br<+1KK-kdOP^M(Ck5BP_gl{d# z=!HM?i9;NDpwW!Rk7;MSafNBYmohaaPKbT2nL?MT9D2xyVTf{K62kNkaSMOSQ)R_% zBGLZo~qoO#FhV%xk;stj}6eyqmpL&^vR zGS2uCFuCy`wk3*l0!`SBz~+{3!IXA(Bu;Bg(JXpj?*mO!-gnd6%()1joev9R{heg;;`0@OJ$XjU*(|@a($uS5C8x?Inx8k<29t7WLCw;fRN%q>IfErr? z^K|I@4BV%$26RuZ>a%wO_d(y%|8c_l+c4mMAbCB& z>&|TCRZBeUgmW7OcC@9L;*`$w9b#ozk-=$g$UH1v%V@`LM9+%KXel&br{@}F&{Jl; z<6ZFdC8}=umk>-QS_bL{I;y0FuH4}$(|)y%O2Dq0;bLf ztZ7UU^t0F?sT#wW-;xEiyZc2C0L70nzoZ!+0D5>~kc>f8fTMYTjOYb}f}@2+YATHnM+;&kL#UVYgF((M-!P_7 zJH#509WTg9z(!a(-3D`qvfrwQxS*sSs$G2G>^w@XXB?6pkiO)0Fm(nds0cVKrW!y` z#f&!e2)u=LEVKKiR=&M^B|mjcAkoFpB)gqAiM*toZo`;7sm@tYJLTGqpk7r=s=p7s zIs;~k>wlnA7B{3;+BkY)ereU{42^|&aDiejZGrz|PJ7N);(RMps;5zr;l);3swf&@ zT>&74gep37N$;)UB1|61sSd`*pH@*;wGtZ#E5v44_prgiO1bcN;+uF zA^s7zWVx*q_DGYy=SSw(Qzbj+fvgA?!%Hg=kK0>bIHTBvX)Lvb1yt^FTkH6nz}x+Q zLpPCsy6V+mkxgzdRRrE-FVb!zt1EI!^0z4FVk zO{vusk;j*(37ipphD2R&Fg=%Y0uAOaQ{ z;vBOTS{T;Sc9`&v+pZ_|&RuoyMI@4R70f3@Y?W39x=OG1=}9@ryfeYDQ3Ri&LtxL)FnPwJbyqTDBB zZ+&;RGQn3KMd|D%O8DW8q2D0JK(Gx21@(0v<2yuF`JuBukSio0L;xl!%}gf%@scQU z1_o=v)5?&c{k8oN%5DjN+(fuaz-Q`Y&B7H`ahc5Rdc4<1?Hmis^duej)-}?|xyjI* zBa=5ZLTAa~#GGf&onYJ&jqJY-yMn2lc}L`8iFMV}40CgS%EntvP-FQ!&iG6)rLm&o z(T7Aq&VA!?!(dlSN-(*t9kMeLTU6=0l>4VraE(rSdkq&s;16a_Z2W+gSo`Nd3;Mn| zzp!XKcqPpbDA-)ApP{Q}EY=`IW>B<>(~8@&WU%I@DCxWXjg?nCF*Mr>KR1QH&s4r= zXoXX3I8WDnDh1!Vew}?o%ck~>tma}Dr@wRXBOxQ`3qVeHU%PfWNXt8wD)w3DCh61LVst7Tv;OgHg} zf+|qy=IKIT=C1>**JGx&pqcFwQrc9*FvlN%4fmg2o@_7gT`J?=fbulSKe#M+w`v{d zx98~V5mxb8JOJ1fzDQ|=O}*S&aXDDc@eEyGCg|HgelKNXA)Nc#LiuA_>beGV$ojLe z3gUdmImKir?P-aoUHJN@^XQ_>@wIDXc2BI~FTL}%T%mTqV`P3-8O%kct|_k$h@DadjYn05ZF0ta{bt} z3^jsOd}MY1F-h^>?@t?7(n0Zr6D|Hf;JVTC!GqV!!`f8>T*V1H*m+$Q$yP{zs6_yH zxmyQ^IPdAT`~u_l9X4&<5o~A9Cy}T*o(CMRYYNx=$RET_@@w(DuJiDMNq7g-&q!;N z*V)^~H5Ia1sLy^m93k-;!pr!Fjc$>tO&EK6scv;14g!G*K+hyji+B=P9_`oqI9J2E zKP~);x4leosmyW%s&627{JGrJs(W0(o}C@)9#bFxO`~AZSe^12|MYwF}o?eF=n5FNqYwPZKyJS9_WSrTHvBg?+z5S>7sk~8`Dww!!R}@|8=K}JyY7kFPKTtu&7?k-D1nzLP`+{!~s=F z#A1EjpzbsgSJ6SoPcv+hZH%#hc%fN(WZD0sOrcr3g`Zq}2t#<7xOy<0K_zBPM^>;x z`%fo$Vw~HAdgRA@0d;gD8g6ZtS6QxL2@}Qom@6N-dJ|s%Y2sC0KXvy-nSl@}-q^*^ z;kT=!+TlnzBMpD2#VM2N!nZ%PlKk|Y-ld4U}*YWV!Zv(vV+k8W5Xux7NfL zr)d3=fuqaxYnk3}>y>m>+*g?p=jfSU>m}{2()}4~N9-({groh$j%!WRGQI>{E8Y-=zJi?q&toy|$SXQ7;h8ta#n zwOW1HX7ls2b0WW?KUIYpMX zw)IaOD)ZqvQ7jCK9H$oOJ20v}WCL_8r?srO=?>tM??4ObCi$5lEu`!@P( zxR19v`l`Qa zz3U`y!5{~$+3TOFHR$$N{`U~dc*mXIQwS(NIkU*H@q0yLyWc$pZu*!nuH!pr1?x=7 z?z1?3-=2S?mMU~@Me>Q6I^Oes(^7Qzdralk$>RhTbEm8xoXFJ)JDbYVN{O|A0hzIK zFc1WIK|&b^Khdio6#nE7fb){?NZz6Dpgg_UgH``%vWUS}{dOBm=ERH~GZ8+U5$c#l z{XY?Pwk_E;Z(2fn7oKYDT(Rg%aBbC?g%<1OrZ=>fch@fPr?-Nx7t7OP_hv&~^QiLO zeQ6uAcoOY%APydw!DcRu|8Q1T`U9X5(bLoGz1C(P?ns?Vy^;9(Bs7p=v-z|tqwdxC z>Q-D_YOz+4xmq}lLhiJV7HjtmzaYPUz+4)vefAv+1HNBQW-rSXW{*7pbc*gO z#P6+x1lXx!=PL;bSy+{MW(Yp}rzYa8R; zA9d^9)SP^Z5$TXyRv+soiW_qt>~25(G1Kchgg!U$MZ-&Khp2GbCb%kKT!shAcW_Wa zw8~C?Ai-6fe=4btt)r(OL(cIJQ2J+j6QKV0RtC#?o!&j;l0Lz1t+cu$GN&W>h#dtI zx_NN|Z2zGC;!k+`&sN5ti+}G7Z143LK44JKlP9FKr7lf3ab`jKBkUGF$`aR>|1krU z-y`Y$|2v(&mKnUY9=BBmo@B~~M$d{^FE(wh?8lI(hOT*z1|*!LzUU_)OnNo{>y^z$ zzbGlYwECvkt0V-h4-b!$Cd3iPE$kyPpZiir9-QTHOWeffp+?4XUV5lJw zJFz<=jia(J1vyx5S&WfE1-4#aqmN72)vhIy>L1!Z`z=9{MrfgEVz06vh@lfdM(Q;F{ZQGGGQCU)i0lvKsO4b0Rj=?IgJvL3Stmia%#n# zbuqkmL9*U2MDRiHl{j&bb<1T61uGT=(RFx<3KeUrV zP0cMdM@LAjf{lO9{v-JKyYcAyTbD!H91rL9<-NXriud4S^Wj__3usE3-@4{<$TBfr z{TvIg_M6?EMDocvdcjGX~O~05MKv4H>k2ozk%J9dZe*8>mv!7*?pEJTa)P zE(JW-2o`x+dsX^G&Nna6sHa2hDvK}UL~nUJ7+bGFCKsgk+1i!| z!gZT)n;vx|bKm)<#$;>a{=}$zxdt|nl^>NYK43gFsx+lP%t^^9)}~vW@K)O~wi^%am{g5?{xT z(Lg{&=pz|WOd7Uc@zzc)Q?p}2s3JisQ6ixNa?hNNrd>QR3n3{LWEznlHu#eLtk@7L z8413H7R36#cf(B=C4RNjPCZLe0QR1FoKE#Ib;cGYY)QWDiN?Kj2VUeKN&;57d=Ez| z^O_y&!?tQ307Zj6R8;$TrEan`HgaRJOXa(emnkW$Vi2{rlqvh!y5e#-?0cM7K*=2G zYxJ-lX*Yd>)X%_zrq+fKqO-1`8SknP%3kH%$7{B9fFp z+&O$X9yN6oPg#YmvqYOKobO!Ed}Vp??l+(`Yf`GKxsywgVI2KuvZ@1J|HGZ&hNQPJ!HtFx?l&4f3$~ii2d9 znr;<%&ErI&an^#w`mRrmc_!7}qpOYpax$9m!IX6hP6JE@&1^xhKD6RCC77HWMT?C2!!s|b)Z!D6w- z&f~CUP&RNG3hWvt$X}0e-7-y6|yf*2VZ|2t=5>o&=c!} zBL|SJ@&@vdcjd~OJbPsz)KHh!ufkUI+lE1sg$*k`Ow26>Mi0yCC~2}{q1F9Tz34RS zi#rt!hr&50JfNnCwXqUR&R$qGZu-t}cRJ^Fldg8WCXTF5VJa+p8v|?-Co^TdK3Z&H zWu2vXxI|@>V@d6d9i79VcCPhyHbpA?$FD=U4Agsk*(6RamMZ1qIth6xWF9J*(+=#{ zqzpSwe$3Rl`WHniG>CTaw~u9oKl|*B)E4kGnbB-a`-fa>)xj27TnJ=Yy}kj$RYFhI zi&{Wqp~jcgH-vDb$lq=2=v|9sJ+ug^D;2PGzstHC!Yzenfz#&Rlfy5`HIs1`H_VF zf&(}EYl2r_WD9|Io=$6Y?_3`M@8QU9!k<>lvwSmdb9X!1F>GK0!Gl5Y&O+8W?Fp&X zVf&oB9rTN6L;a{hG8`bY2IS`T&s1`<+5)Qu)++Spnek{p?eM zu5R7d6S~-r-~8WriR-ke2-B*#(tvTEX232N-@r_bY*N_ z7|zg!%PFKU82B3G;ZaR!;O=!whi2q3Wu!>gs#vD>qj@aU5E0<3KS%YMGYVce)xeD} zbW5ZtAPGIE8vWfC@3Z~wkuOx)x$t;fiuC~4Gux1|Kl7sfwXeVXsPd%WiBFUu@eJLM zFHaFbN^AV;i9v21RwFgxi6(D_$-H@vb6Jdbrg74iB+AfVCYV|Tz2yM=D`weVZd>BX zW(_(1JuAigLb-A#GGPJxN#FORjH{7avcA7;Vp?G!}O zw9`~Va@7XG@V}|w(OQ%sIppY?Msy1Ulc)6REDV;R!z4k2l#-@}OD9BcvagB`7jJXZ zVyeQLb8d5@T&>cM9Ab!%eLn))TLF^^o5t{zvmTFF2$6AqYkNa{>u)68KR^OAy)3Mr zQK6S~kRk@fCw6&fA7;XZ*cT@_Y~lBQFWTd zcl|cz&YAVX(r2&xub-LwnfCzb6uHs-HTKU>w7W#gkO${D1K{7!zL>7{6BhYh6(v5R`{gFVP84V+$HZ|_nRk8X4}h|* z)$4MRjSuDjrrLPQ$8_*-f%qG4k&Ew5-$2j1FGD+Cw{JZ~Kad1+bquIuj!odeO26V| z@AEh{XLi|z($O54pilfJ&Y0=W*nN-cRRcYh*P(%(P;g@3XpKJrEW?;^2r(7HoD4OH zEqZ~>6u&ZZR4YuQXH;-s)?VW#Sqj_U-mR@`u$cwWSX>500)>g*n_U*i9&Nw0ly1+^ zC3!iiL#w7(B<+qv_ocIM$Cl%%**xZ;kdFhQ*o>1)?ytL-U$&*@qPv$3{bFd&>GtO?D+C)V;q1GBg2OIsWQP3xi;NorQXk>Ib9vkEy9iExCpuVq82@n`|0i$MG0fQ6bu^_lzgWbuC(UN>hdOdvj zNCl|s;*S^JwK?_1Kcx>H7R0D5+*Rl0(0$^gOqA41GLE-0bxDrKakJFIK8k51lNEwv zr3ICKiAKXklC29_G%Hn6@UUmnrUDaY4=sV#?n2nnYt0i?Lh_4qZDOlQ!l#|HS5P(5 z(uy={WbrtmP&lP9mDB^k?lDodd1hkZwh2WP$-j~8&e4j=jNCd%+dq~%nx&^q?YM4q5V&a%6pKC4s$$BZi8_BswM&h#e9>oaJ- z0IcN^uS3~MCNGsafyl4N<7*>`pOTzbHurvIOjP>G<4Z1xA}{M_W}$j*^|i_yRV?Bd zdheuYutzF$!7RHq4t*7eHm$E$nZB8W=^*wMuKL8`iHW0JY+pT9Q?V#7N1*vVL3NxY zvseO8(uKCc`sxEnLdhCaTQ%HFFu2rI6luM zpx=a6-~^W};g1SML5<op zdC0O=a6c-={Lwu*Nk}Roc|X$4%0|kc4TKeDo$bJ{nDDK?+5C@ zIe@MAx19nXfohYBMY>%3+7OcR(4P{B_$oeK47&@$dI=8!bZ=i{gpjefui`qR!&_{Tl*lf}<&nRrvw6wu3c>%JI=Qy)m@3ts#csptrPUi*S; zJtCasi|xU)ad@=_@vCJO8ra>}uS}rx3q-k0(3qTvfioNN`Up+oY^waMRA+vKTR%75 zB^#&m?+Tz=G1iUDDDo^b?Li{W@W)Nx!aI>|YaUN6MoGymnp2fw6}EVppe2sqr+y38 zAe%HyNVNeh1;3aD#2`eE03x5r76lW z963AJ<4{o|-Xrvy3@eYBa7B=_9A$25U|eS~HK=d?Ti+m1WFcZU*ahgok!DJx5d3Q( zSLr|jR4C7AZ9z>fdA~X#rH^RDk@*Jmcy}nzn2#F&6v4<;*!1lgGt}9xJSzLinOl_D z*H4ArD=psxy_YT3SuOSCKcm6(+$EGQJY*IgH^L^~>Q zZYFj#3198Mz~d)0wAkXXF(UPJUv{(G+*QT9LdQjj={pXRx z&TmMof=?!1rg5GjrG7;l^w%K(@dOLEt*=gqz3n#Zly1o3)NeK7sh3nCVWq`zarNz zu&%-Hs`4rRfXkCA@p>qQL#?7fKR=r|w~+aFS^9?+G)d(Th@4tDo#TM1jYr+5^Oy`~ z*5Q1OL@MSGno*ln*L=yB1GQ79U5_M325iB`UJa?u}6n9E!(KuS>nXwoGu|76PpRA!Ii-=!G2C6Ef?MX+@?iU$ z8TQ5~YgQH*Uvd#GR;BR=R0%3jRuwLYwFM<;GDne=WV=!!+*u^Q>f20~U8tyK+|yTy zK4G^b`zG}v#B>MHjQza)Ju3@>phgG#LcIoE&*Il{4*=NoD~(EZtt_5$YdU*6>`Eny zs{{L$@GdeQBR%F(d=wX(-U*zoq|yn-u!A>Q(c5sbl~!?5E?xcmG+fSqQKQ%3_%;_a zz2~QyE>b|op4Vo}*hJjdI0{pVO%)Y+E!2evOl3(IW?Jlj!6j%Va+a$vwpU=F1b;Ub zL*Bb1FdH$Hxhr9GmXuePR?Zk`3{+S9oSCa?!cAX*RhmfilU0q^PxEs6fTSM-Oy_je z*#JYUckHpz@8$EH5&#V;iQMceehO}1^XXv9VTIEw54$v6U%PhBjHqRsk}z9|&RhUK zy;(4_NC?iB$M?c3DNnbX?;2fJzN{~h-s7AQ%pDzUdfVY=xm=_3H9O3_5g3wcQiM!p zKb`uvDuNM5(~6UGObb0Iv|Zb^jyt85C{^OE#0)qtGu-oFwjh`&D$?O#b}ew-w^C`n z$p>F_4CNRoa*C<9`ra#Z*4GmzQ19VX5U3QB7(8LR^5g;FoOxAB_W+>r6B*+@Yr}G>VMWIkRGc5f3K+9G_ve@ zQD*;9J9C~~cL;rWn6|nLn}IcEvRU>?h0ecJJpcO@bI}KRZl_aAH}(}xTYZni`n%z=qL5is()D%@ z`@W~UM{vh-cXuGnA^u6>LPK>LGyNW3|8(KORim!ywL>)r5v-CUaqz?aX#=BSIehF2 z!&1o~JEG((sD0Z)#ZFRe1s*$H8n0&WgqMSu{!pg%Zv&+HUrR#h8;IGS6Rw|muCC?zSp$zeh zvU%DRfeVeUdmS%N zRDuIIYv@+HDZGs9?Dc~>@>~2Cxuc^Agslo#{3hH;6v^zl;P&4pWWPCx!xEc*W#&#N zi!NOAZEUV%2%FW-RKtZ~6bvBdoQ<;5T6jNQvWj^=&rr`bR>_@SS=(5vbJzD_r5R*v zp|8DolPH$@#t~1Tm=Q=q1Nw-=Ug;|p;WbYzrT5iJyg&LeOi-x<$KgSd0nv5zRLQc| zAIrDjUQ3_JrNuJlNZ+-PKk+puzmA^4&Wm^VbZgh*vW6c_raRP#!jAK!e-P8(L1H3n;YFd1{cDND zN`VgQKQi_GNS8wv7GF~7O z7T!@C>VK_G%c~(+OPYyIHqDywkh!?Q)EV~3)*ztg+7qS?m~-H%mGA2^R=I?zs*0;V zhn7qe7kF2yNi-{}QjFD1In#?$qvpcKflHUONAA(-?sG>bMyh(g2HD^_E4&a*xW#6i zCjJg-v9*npOwvMW0i+ef-l&-1V9*xE-#?skvf9oq7PBPb*+j(x;rhvWO zc{4QQ2^DVN%5)s(o7UAs2y&=7Z6?CS#!%Zjp7tiTz&8qmY8F+EGy4WLNwlS?Z@Mza zirM$NqV!_TImqx5e1fH{7*onQ6rvYHF1>1Ar{!H1SX{;gYQ?K$OxglDmFe-1(qh{} zV4rMreN2Cc&wIpw0Nb0M94V(63EG+_O0QLAQW#I_)!(A}U%p^<^wIIXtheqG^Kf7< z)-Azq7mLjTWy#K)5l0hDM_p8ZvEsBTj+R!EZ$y;6q~GG07B$SGqGBnyAkMGg+4Z8{*BJsJ;TYGTGpUw3!Y?X@K;gI*f}6jRpknCp8meaTX@M0A+Ta;af3%0f3ZrJ z(RrRQeba-0*O!q5O6UyIekWxjdDA*V01&;Bf7Vd^X%@`ypTd0jNMrX)5hS?p=q#I0 z#@B7b#!8_oShV)O#WqPlE72%AHwxS&Pc|`mtGl&foGe8X7xy(3#Z$dFU%jbBX|H61 zYHxZL6ej?bcw7A!X3xghzmhkya`=UxbX7IIZ2Xg1P@c}STUQwDI!@i)caUCtw0w5r z3=U`L{?W42Dd+Bo{wEK_-Ww|61yi;yX}pS_oi$`{H58l)vd~ms4=E+7Z*HUcvqt@w zHX-xJJk%_y?uUc;WkFw9KTJW8VK=pXIpqE5YbV!m!3*<_liE~!ss7X(>8ZDsOw zfeW12(bm<08T+KRIfSUzA(JV|Rln6{cgY#X)N;fQCOMSDKPpLVR&wz%V|_nR1wM|X zy)9Q+2{xn@I`bJIrJq%fu&48tYfkOZR@UGzE__AqfP60XJB{&qQa#?(JVK!5>@5DM zU-stLDJYu2R))>Z`6X8FR(1|_N)W)( z1qr2!9ATG+OEV3K1mh$z)!?zPZl;rWl8+=ur1e)H3(Pq8>xg^ve-O;N6_bpeA~U1h z$&aW%PZc-OH4AF{vAcq(E5s2{BpZuc*>6+4FVDuPe?UrWWI3m?;?Z>Q=11NbntFSfb52e;Wl0^HHRQ zv2l(n`?N9DI_gu|Rvhz^I8}Rfd*UuR28a>Jz^<4 zY|4*3vrDhJfg#R0Ku@`}l zoqAvW-^^6M2-Ny%{${4lw5G&oQnTUt5G5rO=2rryf0rLB`#-@CCGou-vvX=e&M!SW zjmtZ^%B*SWHCsBC#YJnUw6GRXrI2QuFI2fDj2jx8Y+E&Ci@Ys>RU=$#fgLVaPZN}b z3;p>Cpk)a2so2`=-xUOvV4rwoR(&ZrSM-G;zvHQiDKBqaQPakP=aF^mxhhv_x&A^1 z%{kZyk5waCOr)7O4?-}Y9t?_)DB2?=uk&$S;eY1q?7eV4XyJ-#8gwR6kwC?JOqf#)3Gz}QN{ zv1$F}H1hqgp2JKo;ZL9N^~*`-DKoMREbf!Ivuh*47X{MC1=5cZStI7xpwM?mo}{cy zhxNg9R&Rp~Ax53Lk_Q53LFKdV(}r~~Cj%eHdq9v3Ui9aEYVutn|=L7Ny+yp0KHNSv#2o5++BKoWVx)d5J4CWMVl7 z55hU}d;F%~fP!Si5wmOx|4&%v_RZ@?Gn`2mZ}G*Syt z4?8L{`lyD2bl10z>ht{3YUih?Q>v&(R14W5sIg+H*7)E~e2%>RxJ(Fs?y~s4msAaj znit!4pJ4faKZg0n+|_ed-9}l#l)`W4HugLwA?FIIc#dwn>^*f|#m$v25*CX^99XmX z10vXDaKce7SOWpMIZb#5d-4MS_sJpmNc|#n!Hyh!0%&ULg({(un11$RkkN|XD1SMs zR7)$#I)hFOXsH!;kBW#+{4GY7mV0nlROXuY8ROPs^0}L$OX^Q`jHgs53LiUw z!yFrTEreJ*LhV~;9J}@milGcnv9Vkpi&YhC?8O}2(g?lO6@rgKEJ@q&Vgw?yCK*}? z+Qitb_rS)c42eh>MH!3XRw>cyy~&4)q`A>XIkKMmGN)Yd{8sx-u>rz!gi67bTC|no zqQIg9GBdaG?0BL3i#%3J5RdF6Z3q~y#f$%i)JW~-_@SHBO`#PQss3)#sw;kW(lmL3gcI#pe28qh3rP?l<5Fn;y1PTkn?sj}uXG=^NlibdWQ+V3fEWW$Yu9sof1l*@E0%HcZPBi^m2D#yHf&%jT)UReTuJ-+2*Gdqu&n8Dt+zB zpVPN$aX31o>wM;80d|^$U41QNJ@uqxAfOS8H@fl~4)mtc72_pTXIR{fRiBvQRV>x` zotbZ5h=5;sPhakR3!6Y}jB#OA+;M1LzqD9X$EFv!e*g$tm+TSFY&TgruNV zL=EPaSrkyp%G&>r-lM<%vIJR;uA(i&ZM>s4QM!jhD$Wuz0zXFI+9{t~Z@J(Hz$vs>@HeN=Y11HO zS(it?gw@4p(er?aoj4)(i}l56KHLkZcyL6HqYwFuXJ;pZ&Lei zlP|dPTNM>fnFzY=|Lh<7uWOMax!qfJDrD}>5e^^}I@-#Ou}cJL5sxRVkG+kb(2E+P zZa(dS^V|$4L52n=ta&xAwW%3C5p6RMtRww(6vY-q0(doD)+C9v&6O8J72~?y zvE+tLx6N@qkFm~q%3XpZv`r?QtN+qhP9X#jZ7&rgKy)T^xQJ@}ikCLq28fSJC#N)p zq8(W=w)N!m^JR!UD<_T&1pHkJA}?rcA#6lRMa9IGi2Dj0RX@_8#W7S=Ym*B0@ZT|B z5rb#r@_jDyvfwJQ6gQS-;)dnqkjM;6Xh{d&YM);_kL_3bG(G^l4V|r(-?9$}l)l>> zE{b}NGdf1r5(x#B*z8Rf%V?TcJD^S0LVS9#cAmZpZ0n)r6)G~NsgyD}s5FP$5+_+q zK&YwFnMwLN#@uj|WCpV@rvqrj{mu-#>RImEqenmV$U>sDLk#H=eDR5fsUV935-quj zOo+T(2DnqxOldEV5NJ{Z`Adh~CG)@bK#7R{pBB0QiWa#a95y9`8DIocqEiAEn37*b z;-yvrSC2qPBGbydm8HYZ=SrSMA!0$X!Zm`~(C}vMi5mK8pn*vc8j2y{9!<{|1unD2 zwtKih`2b+~j8ToJQNTWpud zYML3gb9pU}Ne~;Q-JJ@>ULAZ1Q$974*L?xh4}d8=pkapxq_AA?8t_L_-1Na@22F?TLXpE`URf@Ab=^ zL}zMRyq8U9#i6PQx#@WEk~cmRV8#bP{*-mFlMcbs$8$Gl=P4!_!PDUP=Q4KX9DA(V zqG9ZRX(*BVw}uka|IZpqzV?gEdHQzew1}5E%2F-4V=kU|TsQJId@Q0)21VmOwy)#j8XBdxvi~gcz3l>T zthU7k8n%jsnrm6k6=g#U3&w^8kMb9s>*k%{lSjqF-8qV{rv{}IuC#ToF`6+0{;&4l zGOF!v+xMr1LMc|XxI3k^xKkX0lVHJ$yF;-8E$)&8cM0wg+=>-11lJaKD8*W=f6m@x zKf7m)d&hqE`Ja2wId|;5$;g|G%&a-rTE8iu?Al0|7p(7@XG)%zP?woMDoymaj}2P1@J)#|9u!ki=(f+;*1k%%Yg||HRBL8i7ivMGNck*AG)BoSi30r@>HH>njS15Z@7>15@ zoe3{FALPx_9vc6en)&mlDIY6#VY-}iV5$n4|9UR?HLG#73n`HBIJ+J74fTXbnz!NElCZTg1jsRuhIY2uoJ(f=M3i*@7PZNVh2@a?{4Ys zgP5?=TKbf4)ZN(y^7a|ZXSWX`?NCvJHdDXeNN0}NQ%=kG9ENnBI}8cg4YH>tu-H0* z2VZ$iC?&w0$s5Z<>~R=LW4z>H$4-5DP@L~J#uVJ?m8j=h_> zHmRti#fajYrv%KT@X=UR$TL24l8j6n;p{+o5lxXxXr?}H1-i@{CVD+t5?TQ?+@(&_ zN68RNm1&=G`1Li24;!hC&{FTwQs!R+6&eaCHY!9%FFMb=Bu8LzX~|7iG|5<%)|a8u zdHR>14mM(3SMWCJIj(Z45$rrtG@w7OX_+CZOga9%+o!%)!C?^?GaLHs%&`{-LE-b} zlXeaMH*zGlET(!An@$AtBE-8jCnGt*8+(9pDkLvV>ztlj2r1yf8egm7Q~V;=KB>%_ zhe59iarFx&`pKL~(KqB25C0Sg*OVTg2X;jx6KwMpa!gqq287neHk2C_3Meh4m*{}M z55QEQDhSx!T*8agdDbtFk{XxviLsebv3gn5cX}<0o|{DDKY)q#EG*~~tL&qVfm~nK z)G_h4SGa>cn;a2!61S+5Hoe0D{j+oXF#s?hgjC^Qa>+#tA;)ABFk5yWe#pS-N#f(< zhstonZmHF298a>q;owESw*ZhuR%~abDU}IZWm=%G0!Lncq|pv0^KjtLG!WAil{15V z8_Ut^T8&|7PEwINN7T+VF+-_HidKEC73Qbd(k#kVb|Aed4N%jN zyY#_u92?uac8k^*I=yZzV(gCW?6NYejbxP&6&XEp0$EChX}uD5jglvN6xLIkkC&J( zcpbJKIoJzrBaw~B?iY{E(;3gUwGl63y^w3sTPjF>nGmL0>0*22X{MbcYbsDtV)MA- zuEjzAN)8fWrKfXY>U2!>`J=3#F3)kJcIVQt-Rcoum1JG>y#Z0hK;9uo3#g~i%HWXx z;u0nO)D7Il!vc5>J`k9p<(+2keL@AIwHK>?<3`tq8{bq+N*MA+lS7HkMZflNxGUEU zS#}S-1Aq$GU)kR&Cuq0unL*_88PhFQ2_}jWWQ<7)U|tID(?;rh>I_AF#YOyd#}EwG zE@+zAr~lSMMR8!1!rbvVw9qw&}iG( zJSRsdnfscGL9=O^kEVM#l7&@{+$Qib7RpbPbr$*lfukCu;>9~wBk@~mV<*sZq(ArF2Aitpl8JXdqI?7>+{ z5XAg25HeW*_6!`neSnUxebvaUU(0L&I;h)K*3wJ2b>z|NX7|L?Ff?$boHpLe${TOP zo7U9&ka!1NX_)+3^Qbd%c zW3war;f{eRyT)&WIxEK+p<->xW0@6nG3yfEJJVsKIg>qI&IMmJbP>FjwLAhmdd^6;9zIn!s-W-r!)i&kqq#c;nQc5pqxSl_1tFHa2XR zBo5WrtOF0|`marin4$x)X(g6!B(p-|>~%o;^^-)J zh$)rX>S;;3V2$kJeH$?5XB&8lm^)mTIu8;ksx;H1doIz_ucYNqjPIg5d;X~1)llNO z;N&n1Q)FhM2HTLC3J>huC000$L`kpW%DoIn3V^?FXTSK&$6k3~mY(^lpmyLo8R97{Me=FhVowu=T}8+jo31_7Hll`VvJ)o@aO)1DkeLU?CX* zy#~L`JRNzsVw#F2qDr#uSi~jW73nez_~L=Pc+AEIoD5FV1VUN&7N=6BV$ciN)&*eu znP!#vf+~b6{Lnk2t1tV7Qvn4wEEgXCyNIBmU*ajIa282dcwqrmZ6~%bRefUK+gI`< zYZ)nYj+K&1NEqlrtng!AMPo9Jh*gd^W>*J$TNbRHtMOU}tOyW!Yj7Mv0`LK4D1%&M zx*d58WlAHY7+GTlCrX0=FereaPT*N3Jb_U+7UCWk?&skp4}A$_mAGB_S4fc2Cjmy;ch9${rAf|J?TG~ohdQC8p0BM}p2ln_2L z#zk)Dq!`)aLB?9CiJbZ5%%=0^w@u4%r~1%}3s3=kw?}DEXu#aV(Qc$dCQuW3Lcwk` zR#P~z#2+)0@n;Q4<_Yycj|{Lg%(!0y7_EIp=IBRziwjP*$yx;n{pR;XcHJzHoGt9F zf;6z12~+q(V-u|bfilT}x?;$n!!`dc~6w$wo5f% zz_qS*vAo1U|ACO;GsxAezbg@WaDIk6tvLG76SPA)V2?ua*ipKkbFiOxO_#}b`ks|_ z&_^c5!^MvNXwsg!kd}%Z7=%;Om{r7OZPn;Zn zQzA}n1#mT00zE}l<@_=yO^YYIP6YJr; zTL+^a+pea|D~%xm%%)Kff>Nf(@p*#la-}%znkuY-ktL&+B$;^zNl4pa?C9_JiGEK9YP!$RL(nkfqVv^_k6u_4|DaN!~cG2}v%(;bPpTOPFr1 z;zkf)Dk=5amlO&2r!zP&2!LJwqyb(0(y{Ie+kBM|csMR?6H&C)zAhtuhaPju-DvXLFsm4ZYT88|@~5kAi&MkuTHs>dys3u>~g{e+<`08JK(U z2IUt@?5oDX?QCb=$r@jwQfYJ2xuqez=40}eL)pEDkKkczDBZXD$~oZKHhjB_yJaWi zI{J#O@iWB0&@U7X*TegcKf2z2{1{Yj*13e*3f3z~f9kb19Fg3T_*sofwuoSd=Zth# zXHM_rV?)QKBkPq_gJk~!Z^FZZYYAxrA~pNyfioCeJ%jiIPrbTPLEZOe27f3_qYZ5$|)rM-Q{J3(?Vh-GDE7MTUw=5~ax$4uU2{5BK%F zPClXXNH~vN=>L}L@#S0Uie5tcD!;xZ_~&vxbZISh90$-8ck2U_SX35>grr6E$g8aK zRMRmN1}`@gqlo69d?qKUowgqw$hxl7IYv0hah%+#MRD|o%i-riLC)GYR2WWjFm$3x*MaSNbS<@k*MzAA#`9?EY#1_io$eOePxo^bDWvsQz2SkDm+$Svd@~>@|?0?qbuG#LLq^3JqT-Ig_1{)O@+3?|fqA8UtQuhFv!|9mwU1ULD z>Was`gm=#|CRK3q+O8m{Piq?vBGe3$pC){&JZGXMt8{Hf@2Q)jbx)*}0^iLw1r+$Il?sI02m#&SDMJqn(y zF}=hmU!@0L4Y0jB;pwX3BPUl(-OJZKORcbk7f*3>{zh*)bNw49#N)r3o%Sbd#Q#mf zWY0Dk<)>vyt`@7jsr=qDP;4=@TZbklQnQw>mPHMJH~A~J?(cP|f7oU}QI_3!*E1-- zFX7rj*8YJGn5fVSV3feKcvky49?HR>_*!gV_Wfhuq=u)cMn^+44OG@Bvvu9~bcUvt zN&I%SU1+cIv7PnJXS}iJ5bg#Eg47RI)R-!!P$SqG3Hq+6u5VU(XdsuoTp)#9viD+@ zf8r5Wl)Jvz!r$P7{;_@EeLN%HG;oCfwL|kC(R%(3NF*25aX)%%1jQ@MIH44OCs;4# zgq)JP;`I7qyJEBUI@-%m^jn)eeF) zxCHw8a<+`c(Mv!vW*OoycD9xts#TnkEzeb&D?hm>;<~;VxMF!&z_mr1dorr*$lo9X z{zSC>Av1ant)L+EkToMl-Kx#`vM%gc@9oczeN0*o5Q{7xVCg44LzYsgHp{rKsf?GM zsgIB9<+sg5tYHzdMiv`=$J=<#g=+mwImoKgmuL9F z_?s%(HVCi^aDLpa5G!x-h3ji0AIZo#vMxJAz=~k-u~W7 zMc(?$cm18Uh=uZx;YTq>9u85lx0gQ{Q;dmusKQsDtUE?^yojQ`EU*VA$vAX;m98kJ z&Y;7l9>=?|vwh8p<%`!`h1+@^YN^>iK5h7_;Pdx{=i!|I{44ows^OTjAEP1hqCk0( zCxuDn&I~S`Q~WT0V{lfwl63> z`4;N@uM; z*vcT{4K;PQvh}4~+6_yWuS^qc&aB^s*YM%v=JEJYvHlAz`ac9Lny(|_%^8+*aoot4 zhTE0M!h8I|5?XP|FP4RLJ0sD}BwIN;<1Csqu=y%7?iV-*!kTY)ns57d-=uWp`ih4N z)3WRl&BlyW^)06HE=`7UWDm#Na~>W;uRMTx=U$<3pye*T!>@1ux6 z?xR%y+kP zJPkW?G8v~9JF(N}ZQqvo{0n8dqzW@ONjJ3I0%PYFO0tV!@|J`A-7l0)y0PpaQ-8SIKQASll(8NY4!F3jc0D(HdE84${2kNpftxdv4-BrRc z8#@|oT~v1;v6t-v&WG5*$k^!ODv5i}3y044RK}60(=4=?t!wL!6Ll7jVK2J_KU@yP z{Ty~cuwmY5l|vw0im5n+6JrL2#21QBY3t|8meu)iX2Y#84EGyE7#2e*)qWN)%v`+k%1Z})uJ-{hK5 z_`ZG*?WOWRBl59%+SjV_?81Rk9K2?H8)>MX5VzpwOP?owObOG+s5icRGKYiFrV$dY zp0sJEGG-u?=Sh>Kzhl$qF590BP`5yW#gJXYk_lM|pZ+Nc+xbYTl7Ws{6%b|#j9kTH+CkHb@LmP58 z^~FG(hQuy%8GM>vS50Q2g4Ulp!=@t=O%sd}UgX%1NYwTu?NH08@v!Ra_oP8It~0eI zWnP0^)+zTC74zMIM8%|Nje@f?5|&VwaXE|pxf3nL1}?_5k{Ydsk0iuI+jjxzKFXQg zif`oMx+H=ul*-{f0ls5j(ZS{~Ovu<}eECc5sy%@f^}P77^%HS>o}yYte-?fx7vtEx-i{OL|mr-tw~7 z8E;)!wHAYQ60JK;%Y7+Pj9q&?6SVneM5py>1KN%ZHn!ih(2D z_$ah^cfsM1-82}20CwM02=jS7(sOxQC-9Ta^Cm#_j$-)O$!w+b8&`n3+D)9!@os=m z;g1Rbx0b(9m|pxsiQCTZ@w&JW+y8~~@bVmW!>2Pq>3UkAKk$$`xxNtY@!(Yi)5BL{ zhF{T08NYew)uM4Xiz?JS4pB7QX3|vcrTLbk+ppVmFelsYq(5-eUSUCkO^(B5s(xmX zTclhM6d1pU`EU)%nfrgp-=@?8rnY+sCIW3sH=x}8d6_JQh*M;uu-rXAB!SGG3_s-A zwx!c|&Ep?;-ZuhC)PHlYG4a2<*EdXGMMKkXDU6Vq5S6?LYNN=YQC!m34$sNwTnC|q&^TzUJXxn^;h0CMh3^+u@%ad(}q#$trVu@Qs3rO{Uq z{51y9uzT$$wa_#Uuc${JO=LTw3eh9=WC;Y&$f(~}8}DzcZAHT{eSKxTQqsZu%=f0f zV5LSr`iY`kVA_O|8jsw^t>Ea_#2k&g^+cPQG|&62-pM{#8Rn4Yk=>D=^XtNvjBB>j z15LM?C)X>Ky#&wZ=#+=y8S|t2ohsf zO=YZRK$c@s62>yi*m8}HeA$41Ik`Fg;q+XrJ??%3>1w}~%y{=VM;te7zJ8Y^%}Q8#Tt@b%@<0@l_gzM0sgpp34pFHCXelAo3j{1a)2{X*NLC)X?WX4u z4`g_mcXKd$2Qd7FLi1T7^n1_Z+-21b)|V-=PXp)vcgdHfPBFhbV%*>U(cj!~V%Ha7 zd+&3k5OoH^=@k^oKsAgs4q9mrXm8Zha8Q!Cs}|#d0iSsp)h1#a$}0!#TFa&ebFEur*TV1yQbX{931b6Yl~kDaj?8?eCK zf0qnDSu%lC9<2~&4zlZHHN^*VT3>RjgBI_Jzfi+=sr&x4+HTc1O zB=dLY)S7LP#vg}g=ucSgpxd_x``|Ube5`RXZO4|@q>Q{s4gGwfn*9@GV)Kz4PhRq? z*Bd`{IUlhTVo;gss3Lnh(V|nrx`wLp_GwtoD3XZ;9Sn>xi*)IYj*$I1pMC>ty_3ia zz}XCItT{IR@vO6$CoW;{_Ll1y^o1O&hRs*Ou_ypo4~YwPFf2wxqYD~E^AF7~HzLHw zFOjBM$Wwd@3R`;l2GcT1dK`^2Neo>)5&`Kfm@U1)z#}!T^`s)^UWrjwsNdmvj;Bic z)yw*Of|fk&rNchZj(AY;UTW%xO>9KSh?R z)Oa&at3*~bJgzP-k~sargEZfTC_NNo@2dGIxMnW*kDU-*#EI43W%FCF&7?w<;J$`j z`^T!VVKCBeb=l{}x`X|aU&dPDBA8;_?-cbIYmUnIeo)X=0AZ%uGuZ%fhq=8H;}nD( zg1G?kGR7IdP*@ZuTwD0_vewJI`+#Xr7MeP>E=Vf)Z&IxRl$voxs%Ty$&~Z7Ff11uR zakGHs)N4DbPq*C0Q_H|TRS9?`^G7>WO4`bp`$yiCxx0;0?zwEy9AaKacddnb)Gpy1$FY_ z^Hanc0tit<#hlSnOg?-9BpjdfhbyP4VrmhUvU>uF;FUtZ><_61=5o=HjsqL`OUH>X z)sDHWenlAo>ga4m!eR$oeifO)`vNvZGp1XWT{<``Pl))q%5b|))$TLB@4JjqAzvY^ zE8rv#?MRRmb(~d%gulEOjJ%*=k2!o{>+o7P@i8%MrPz`I zftiGE(;7#;mmz0*r#1>79{KIm9KkWu1jNXOry;rBqPkeD^>_d*w+kE}lIh0>a<)Qx zo7v`jKKVz!9=irdvQyw3!Y3z4rPa!Wqmi!RtCoztcOLN>tS+zn>j@-~! z5yO+6Ji_&b1UfRYkKVbkj#}Gd*HK;RM4&0aJ=H%GYQ`L!=_QaypDRGdU<_K!=9cDO zEVz!fZrpML;+5r@70ioK<-*>~Nsgk3wrlqh_+v%EHAtW|F&7y>k^rJfrD4rYHz^Ce zwspO-S!lrntz|M4u|%JfAji^N2UAb<_8y%=!Rt6q!1`N&4!QeLt`;*tvotiwHA1*> z6AwVl`9qTY0|r=q7eBN7e~AJ3yG#^$-L>2G49k(?<)cQ7eLzaym`#)YBb)U3lIaG5 z4J9^QoUE>cJnR=-L+a#Cb;~4y$L)42mm@1){Mok)M~RtYoU~Uknik#Fh=3NP+U@a> z*=YdXNk`qqkCF4MDfclVKkgPq1tzF@fzRW?H2#q*Jd9hxVh8TCpNvf%i3cpfkb}!V zWVQU`%|8h`h%-em>i)Ib@UPV1AChMOy;FmKskpf=zq?x@!72T**E8d-X%i<4YZyLM zmLu6cQAlVI`o<=KYU&e%D) zuwOv^F6?Mtl=O&~^zyotPTPP(3j~v(5&5%vQXOX}%~lVSMaAn}?}RM9B?nNanm>D` zDE&NpjvW&loSQn3!(bNtxdnSnmCDX0{mm`~9+cHvUGwQXXS);2FN@D&7%wk{Vb`KV zub6nfl9;n+c+HCBpu9BYnSyJw%5tLLl7N@ZrXj2cXu@dEE z(0S)a$+>luE(h|U&ubyk4NU+aq(Pu^bKZpR51Bgeubq)kF1x? zE1HdGXzwY&D$vUbk$F^Hdfu9I^Cs^`rU|0QW&sq8Y>aD}Y~jgZX*QihD)0g$)1za= z=V_@>%4_N++-71W19lz>5_5W&H}h)Ee#1E(*|h4J>2YTf_Q*#A$liGZ`xmS35Vt#$ zicQUJp8AMP*NvSKWt%8$(d=fcUSLmeI%rQb;uENj&m^`Xn9LN69X_#_YR!G#&TtQv z#%n;6GoG`}4|lnQ>KU9KaUQDHm2-kUiuCGuIqOS;_Ga#N|CBT68T8_Jg@4-~e(?NF zbtdU6W_#NWIJlbrbgG1(6bMUhnZ!1%YGotmw6a`_agvAr(M(18OllN~m{+i>0`+VGr z=^bz#zXa_j%25Y69dS8X<7~k&s%;T)hMSvH(_3O8ro;khkk4zQ-s|fMAN>JOC2n?r1!G6Wen<4tmwOW z7r2v^?h_I&R9{izBi!4f%J_}tsfuXeOpjE31v?;$sCY6WflV-*%J>&bc*aD~aI<~l zh%nPDzm^vMv3i73d0|m`QI+&c$s5P>Gxw{wnmy5l3?>4S5Rdj$w}l|>3;B&1fMjEC^K^Mxnry9g;-(FQsf^`V$gvS?jNd`wBsA5Nrm?Q$5> z9KtWiEWo2oFno?L_>9#$+q*aGXZ{m;1+fSQR#qyOoz$EnDXQmc6#%d#VM-QM0Be>< zjM=vLEai6bw+y`9A3}Ds|LukB{zuDo{Z)}{?WQ37syOe9zQ-{`Rb{W)yI#+Vr^wp; zK4Jqt7jJ*%e`_Yn`@77+eZ#wi5ul)KKAm*pdHwuKTYXi!*WvQ~+a=hn$X;;ZWC=)Jc_#KE zOt_sce}g$!3{IM<9Jss0&BFjx%&jP4Tr*lPr#;~mB#%NeZcE^jX=NOY8VXEPjE#Jh zJF zN$iNK@z{~=a_R*9Ur#OnJ0a%(qNkQ0W28~6lPHRj=z3VY=?UFe&(6`5Z$&-H>w-}y73?{MT? zyn@0nSxEZHc*N3n#qc`vvS*K?4{^g(Q<;_4Z`87w-o9o|hDWpOV?z8ltu-1pUIViq z-Dloa*Q{qk_eL>_;WdMG6frJ(?5w#k?~%Ja zZ)&*5uyVFEWGmV6t|@|3-639N4Yi!Wi+9kZ6%wKI95ppNfy9xy)w!^J3(p? z5L>KiNS~8uS8gAv!5oa=;6M&?Bx_oXnq{nDmD_eVNEOnY9~tnx zDf%anrNgw@KQr$aifS|&?Pg<$R`Leq+xgy6d8jy$jG~(?D{!Iu``ri(Q7r7Dt1ad ze0KQk%Kgn)NX55`7;Ov=35vv~Y5+&540u!sDANkSd)V;2FME2LZ`4(UA?9EBDqa-K zo6HQ>>PL8#|5+=BC5N4``|EYX1O3|#w~B_Etn_0Na3ZF0(`jJCs_)(_P+&#(XJ;I_ zCn6GVf7sS1k|S`&(3mx?v0uGf#T_C#{DPOFHIo5wb$uhb z6OQN8WU%Hq6ks5k%37DbNzr%}TzXIcn$^F%a*djEL){j1%4hd)#Ls3ozZ}uwnyfe8 zo$%La4JZaw-BNjU9v4yn-Sgg+K)<{)=v18uD3Zf2yJ`5=Q+6LGtozd|MDKJ$T@~iP z&0DDN)?z9vYzdy5Czoua&7r!qB9+L5-97mf-#TY(;pxv1X`8V@Y2sd7RMQ?>4ZuhrJYc3%%kl+IJ!Q zUa0o2&-GSB_AZl@2jaTe{YktY*V1F}s2elREpCvorEMBFZDW~_iPO6BjH!{vu)Ug7K*hWE7Q=aJTjkr?Qn&@$S@}Oz7R_xQTO* zbQ_M*4I=IsF(YgTva-rU!_|!0u^$n(~8|^W_C2#%VfjD(N&(yRc;Gs)4tJu zSB%|P0PwZ>>ftF@W-9|Q(68cF?>ms}KSZ&B{)(?d-t_RX%~}KH=C`i0Rvb z@*|{XV@p8=&ms8?ysS~Eb;D6m7J4^abS)R)lyzZhp8FRc+k_ci<~^`p+rIS&8%N$1 z@*}zz_3&I~SW^(UhLyySfYUjq*1bkZW#jGH=CkT8j4|gga-dsB2652faZ06ek#*-} z-cA17UnuH{##h4o0bf+b{)isue}DGq{B&3i(~dlTsxe#E#`>cQdn2K4wRR|X(wrbA zVZ{0IwMjxM$En3w41arPb<7K7xproATL?RVEToW@enK*{{{9RNos7!WayJxCjV+X{ z-|&!HvL7EJoNlTg;!ms~wJlMU!UQmIODTNg5dCx?KKd`W;TptZx{;}Avx*m%CFB<0 zUE$NvQU0c9+KZ}Yl?z1srBXzSz$k7$YPWxHg@!Ngn|IqdXBKKRYdo9ESwAB;uii%8 z3cs{sygx!?{j4cR?&Bwzkb0X2!s6jwO2s$WVhaFI7_L2p%1jhAkIH|VBcLIscojiR zz2UVCCSga$LkbFPtW5rin}BTQgsb_cIaRZAO3C&Zglr}TXH=8UeajUYch1G8&cR}+ zA*u!$Pl70SOj^!YAcT+ptQF<~Nh?GR#udYTvt=z(G=dhMG0EIOkg&~!)p}mt_3N#7 z7OBCl8PZU@8wEmwX`wQ{J`F6OSkCi;L7Dhoew}hfpMW%rdJAB`3JZ5{ts?cvyF?H$EvPldz!^R+|-?hjA`4Lo9Z{ovln8Czu! zDa{G0M|Os0!LE^fIiuayko$qyPZUPY@F!9ShrUo2)~`px7P4wDJ)B2*6S6ka5& zV&I|0Zo!bDZ$BvNWjIJtA^=B2d$Tz<0$khFHNh;}XO9QIr2(4o>tN^tQW=%(^`1JAy*B0bwEM*y2Rd)H^&1 zFTU0FKG12w2NEhU zpFnm^L3{P7E~o&6IE)CjUaGf0AVxUPUBbP)@A|cvlm0K1LKKthN4z`VR1Gdp25E&78IsE+V zPHhxM3(9*7wz8JF8-DQ30#Uw;d32{p;|EuPMl@;g!c>W^dbuR|>wN|Tm^_4vRLMt+ zLj|Lrk;tU=F+U2&wfEWJrSvA$-H@X)^9z$Y+v#(Y05d1Z_vUv`Y<;uIHYO4Mr}9UN zT^zn-HQKX^A2vuc^`8_Gse(b0mFy379|KUXx^O@fQ5?%xm)83={#|QK7A*cXK9bn> zH^l`V>~RpVP}uVzxuVhNjPHDm+i}Z;=`qbi;?J6~iwDc@B}VH5ng<^*UOYh9qmT^V zH)YG0)jf>vxvtVQ-PTYwU7hxQ#>vjnL)jeFjbXOzef%Nld# zCreia(^fOBOS@PE6=oL%^cRVOhSY#RPe@TBT3QQkH&ly=k?$g=$I>TF#Rd}EGuxS z8TBjzwDXuqXg5k#Q&*ZrE?K@gdA-f6K<;tHPTWK~0NGS(4o-wP!C7wN*YL$4edX}2#)rC8#$?k2diqAu z3eMyi)TB?v<#fdP@(t)m)T5J`PeHJIRawTzU|tmR+09J<(x$lZH=P@58tW%Us z8iXDgl<)vI`o_}+&4fj;7BDokvF)~Bz5N;XN`^rnh#*C1Y{Ahpv1p$F1>f7BqVQ&$ zRUGTBj@zk+<;?9YF~AW^s9w{0x}jWy&CmJHQdOkZ47Krz(uaKWQa8kTM!s^ZhOV7( z!?+C0(%+|zDNp2qI2>YA9<-n*qLBaEk^Ze zM->p%t@G$}y0UPxYJ`WXW8WjWbBRo%3DAL#PB?R%3N>71#03T)5eg&-c+4n6z4kSi zR^}jq6$CeUaAuPYJTw%`t|MEXGh`t6v2CCl)4^T)66DuHK?(V8q%SUyV(mKHQtE0z zHUzF{+kN={sog~1p%Ijhb!`!e!t?Us?`iVi2N|EE{HK0;xlB6JZJ{O7W`xpp$ez;f zHXE$`Dv2RJ{)ASWljv2Q0O?kHMXPNF6vaH4rI<1I`fle_&au~n694}BfSh-yttB~2 zz*ZNTIvbwey2y_iD?bRj*Xsm3pP4%l3N4+&`7f>82w~@A@%7bkGh0eYZcqMaEEY~U z!7U{E@#q7kjdJ^$3?+I*t|cX|cQ*aPjA8MzU-TDq%=wfpEmfG>sSac~qT^XqQu~B5 i7O2LSup}TGP~ z4uAka1OE0R;N=8>B4lD`WC}3p2EPLFvJ40WK>XtuWnutGC zWue4F6r$p0W&0e|K;7sntSF+)E{X<#fP#X6f`@^FgNKGkhJt~Bgn|J;!=jO)!(r5O zI5%**yk!w0$81z&#p=g~mo%hcqYB0earhXU`$d=%p;jpl*T1eu`9r{GuCpm4$2<|^ z{9bkylfq3W>H@K#M4Fc+z$+;5H$a0z0|)?aZnqNtawPIEeZ5uHtZGXdZ0=d3sg1;{ z*n9A>|3duXy|phPfo3mBF?u0`uTNHN!LldTR*Q#WtGG6LxQf-CxXDRWY&XKBRJycME}I3NDxs#u zG?2ZJ&cfzKeeyzfZLw&JMK|Gj<&rK~LbGu)@6A`O%Ac6490~-Kp}`6*1wg_y-K14q zI+xAsB$zu5!(2R*w0YySL?KzG@r0-!p{9Oer3p5)ffl0th?F&4*0uf9D*1*Tb%Qxk zicZBWFd1de$d6)5rgd5>U{ecyHyOlyf1?$j?ei;Nw11+PVAn4dVMD-I+{!a@_`R@;H zjNkGb3rA)X#B?$b1&Yg?Pz{&cFEC>F<7i-Z^2X>Ib^Ll zBn4_hNu4~JrD|+H@V`9hlTV&RkZU~j?aXB(r2R8J+kSez02Ib&>Z=K~%RbqTgz<_{ z?lf{IKq1@ObHx5Qi*pl+MK`nOGv*$|tfFZJawe^HCqr851dwIQQ)r_o#C$fcj=dQy zX{>UdIsT+i#+EYM2}czjOnheeQS`@rbHN03p|kV`H<@TDPvXQPfBnHShL=StJz=eg zmnw0)ovmc6My-?t`8?%x!c@ZHd7Mz9*excK9*n%L!}cc6^V&odi8E+_3jbsE)_ue( zb*DvBv4U`K1sY31)`YybCT6rn|I{9lFJ3gUh^ISruC+409F>&{X5sgB{uX?l|LpK>0m==zDZOvM2X-A5r9%D4!lV@T1 z_6WVh3{zZrEeA=ZB(212n)-MRYhAyGx*gW1dT#RXU**wQd)ee#($(HITGJgj^qp2M z>T43Ck|Ra+m(?U2FR%FRehp$gum`b*e{h6spijs??kZoNwRCcL-_-MMGhGR;zUZ*9 z3I*LgaMA3u>Sy9__=3AIvNFT5BiYxVYbcx5f*ep}L9i)xQfyQuRG_JGpxoabIYaJf_BAoVl8ZfQx`w$i5bNJ>z6IKn;1-GjND$Kzx|9S zewL4iUr(R-y7q)l-thJSA-C8JaGl%X zOgPFBt(&5CMTLN7arL!n!UF9IZ6Naa_t3Y>+ph7zFVx8~uFzC#eZ)i;5LTtwlUxin+ziva(gwvB~g9o_dWEXmSNpUzrAsN{ui}^`Pq`j3Im7 zfdn%^mFuG77)Fh=>s*n?0K);~g;T949Jnm9(CVl!9HLoz=j?Ia@W48rdFz(UDXTEG zQ?yGa#G0|Oz<^gA;_Bu47w$>6nz|i5=-=Byfl4ZnaRnvj1*J3!NUa-{_xPKV)ALMsWUg;xgQ8t%Mz_W2;tN@ zn9+{VAmf$K7ev+37XJjvwG}>S)d*w@Yy4A zA52Ik=qp`--Wequgm=TLV4snNp;v`nw!uHiC1p2dD?WJ;-hJDqO80Ho|BcDkm|}t) zKAU=_6p@Ld{6Rvh2phU7i?Nis$|y`0Ao>I{RvL3=);JNMnJ;4p3L zk;dSjO2#4KS0*2VXkj|g;~FYWfs=NXpcz$k&1~%Ea;qpK`K6sjD7%&IQ?8463b#a_ zjf_+iuFcnw4Z&#^Ifa%v%QpGCvy?DOMNZFR<=>gm5ev0R)Qjs}SweXhGV#h+=3<6% znhB=a@XV+{-)i?T=ZGTfDeVL^$iDzl3n~5mA;STXz07>X2V{G;hItwGpb=6mE$x!P zw=^!x7SN4y2dD|T2v<}HASD1mIW$9St1?)^x<5)bhP9{m76(x~wp~~{T4<2(GLUKm zan;$%x!>!1a|5Gjsc7Q=hI2~&{Gd>-|KkPlB=fv<_4+5p6Q?hcuYzxW+Ua@Mw(oJk zIovi$zi-I9=SS6>o4fV)cNAOCZ|>G;La$peAMiq+x1W>lso(DF*JU&@o>VxtS5G}W zRs&nQM(iFu?@#SKwGJCANY?Doeb>s5PM7c|KED9kNnCF1d|PjPUGMedcDRYv<9FNz zzFugzrDqMCoQxElfc5Fz!`I4WDy>kPqE7PIdd;r(4hlPB?)bH}ybXS*(#G_~*wH$+ zTu1F(t%u`;TuuPMfd)VU@F(5oO595!e*HdRY;{RQjKgVGb!oC*OS{lq%VtGMC6TH| zsUQYX1)kJTXukXe{oE?7PDgdXxWLicf9u^gX_U=;Mr^ybEoa++Qsatn7ElX2PN|>- zvy{>wp1q-dJbTdDOS4BnrQ8_(C$?N_Ev?qqd=5{e&x=$zP+|inV}n33Y|?G50>vh0 zo5Pt;np9d?5~$|liUEMsEVzKBKGx%Uc4b>Uje7KSX{Wdl%3}ft%HS`nT9^fl?}Erc zppVdD_7mYcs$D}T8lA&+a4B*Ed>hhnZ^I=WQn+za?P2%?wdHbA8mluxP!kJ+C{fp( z#oPObdPWg zE1#l_Wu+;;Zj{MP{mE)xE85n8Mj6%A48h}%R&UuD; zL1kM7Y6VEr-u;X?Xcoc=S@OaKaD)ho_yvpxsF;7hZtXCT;xSt{66}P<9 zBp}|=1_SC4vG$S#HafIibqV=#AcKOYA-5vqu%JO8=63@mzSnSS4ix4k=J}SNO1>Au zPOm%A>-OcT6%@x$0u38`5@5^V1t|lIMU%0c%hnNd3l!r`5Mo?OQ*CTR3A(qIEyrPG zISVhAM?@^$zjMZc6pD3#fJ&{r+41a>W`c3nyi&E^Z5yn*(s%WP<5Owv^WuXo*pn@h z7jQ|}vHgJ`G0G3%+YFH~u{GpWq#YG-$zZrOASa-{%wOfEFBR z6H9?RSBM%mHH8pm{-_9Kz$vQ!D!Qhg5(`X|MMx8(A!=>yJn=KG#--06m1Rr48ZTm& zvfO10;u3%hh=TNLm3T7y51rtLpUi<8xpTr7xjti>VgyIb9V$s^Vk+MkQY(!0rOIeb zYvD)7NoEkjW^zeWN+*{HkPR2(vizftFX=saQcK$@@z*V!g3C8t5953VLu*uW%{0`S zC|n}lm4-!W=0L3y&SmojX9S3RV5WfU5)MnpQmNV?JDMjAwoyc${Zv|qrQ{)bn6FB~ z2wqA&FdSc6MDaojBfxK_7{Mge@h994H~Tg$HSfob)6og`D|V%2Gu3)dEDKvk%MI}czxfCAIo7f1FK|o4OR7?#3Hr~gL8^zbWACNJ({nZo!Wz(yoWG%dn z%aT-et_p#L@bbB|Af*@pWQNSv0+ux^uNi}*^~WTv=BjZ zuXA5L0$wZRT*5jGz7oL=Bzw2wO5SS=}0wizF|qb)Jm&zSt+3qSf^5m z4oZ-sjFXxNW7Gncv0Hh(goMc=OuKid5c#s~TMD<}WgDDmD&)q%cJx3pQYxS%0!R=5 zptF9SrCYcccmXI2G>9e|T_yHz!0-jo`~oQK42`^3KPqM%^(-f>roZxe0nm@w+FhhSuRXUdug$j} zm&4tp_hsLdJ@8%!e>i#poWiYkEU%w*tgk*N@3f#uB<|c1%U^mWo$T(_wzbuj@@mWM zKf0>-XHfhEHL|=>G}%u_52{#VQ*Wf_k5jZ~*D;eBb4*Y)Lg6SABXCt)>);BCQ_WRz zfDJUoWkys_-EiZt5Mf#t5#!uU3>N~{H%ZYt%1t$)OIj1n<${D~ekfrUl%PtMJp_A! zG5uM>vHw~&hOfurZVyr?wp~jk;>%F`s2^|(a>*Iqxxs6PE3lFhNE%cLj;46ax5m-# z3$<~ROX{4yh6>Ny;FT|9Wew9d<1?{Qn{k6^YvJ(c$Rpdz?esE)hv_EExB`S(BXFU| z&iIJu$&zhy^V01{`g0PNvAh>JdK&ROd5kC)3K-&Mdb-VE{7T&YX~FTZ(~{- zR}&j9p!N;q4D*zv&AvM7hHPOol3+xvJ(a=Ryg2MY1}d${D=IC^7?D?Ct+K5hYj~(g zCv|wR_D;rADzL*W%3zBbOD3S&QmC7$s#nRx)OP5zYHff_nBnos+Atp)@hH@Wk8GPC z)w(|>p%J&dNF`j`ZWB&z8eG%C7s5t_sj85qLNTFGFf`%@GST^I_+!CtSdG1glXD<4 zPchH6Y%awrg#;tIv{;{(LLp83WGTcTq>6Yck_I#ky^0+e(f1IGOw{8|5M!)JgKbb! z33|2&T*lqy8WS&;heg6n6S-o9)r!*TpmTYs*vGSroAFs$vr5%^C~SY$&3Cp*41*E9 zNaAht$z+ku`AsrxjF|sNt8#P%kyQ9uT#YD@bXX2HX^>De{w36xnG6XnYJ6I)DmpPs zK`^2#O*vpE0Ht=W=mZ_Q6Vb|q=OG|Ka|B@UZ0RXY#oAefEWjTkOBX2;KWh$N{hXy- zSqMgSg{@RmIZD*T(xQ=%v~r&s*oqIBU@s#|%2aD^m&L5h&>b;Vrx&t>Y0qa zK7Q{ga4;klJ-GL0`X<~DlZ26ozLEe7FC?c1_}qQw{2rY%EI5p_BrHlx!G`e$yr1ykW15t8PA#I~a_Hdbt?%vkC(wij>~ zXDM4y79u+L#30U}=baaWMKl>EaJ%ypHk8znWNk#@ZmItdqLiSrBSS zqVaU*gg2tr3Yi9e7j2?~@JCfn^kX>VBhu`P%*)M-EF;fPN+6K-?yGb~57mmxk{2ut zUPe^FFChcOp=YA&fWrhYy5LxG*%)e}6@Sx)R!TdlaGP>2EcT`3Q9B@V>0ZK;6i_(R zz5uepaw=gwyX_b$W$hRod;6B#^9>^No)_7w;;-;hu&)Y(8U zt0HCgH$bT34i&J9H$m?D5Z%5#A``i#a_H}98nYe9hd7UKQRJUk7GTpD>8cQe1xlT{ z!>&$fmISYqw_eup$^hk|o|9Si2Q?8&y$w6bG1HVpdZWP%Wfd3B$=D7^`*7$2;e&ytYLmf$dlFZ8s2sus3+s4JPvHU;R5yd}a)fi#l|V4wy-$Wep0uMv;v zGd4G;;3(qYh7QnH{2YOaACB;H95vaG-g&Na0qZhpYqkNs5MA|u!#SB<92Dx&FToRt zmaXO@Ee1Wtl1Jq$f5cYwIzsWZi0Jz#BC@sVEF#BT^{4uk&byq z&|YN!BNjeYFmTlI`DhUAWrF|UV6Lxk8mihXyVWtcqN+QD2IgX9Gn~$$RwGM0TW^eQ zuDYmB9z*Dd9SM_n?-G%T0>_h*ZA>eW6rYguLF??QnKWZwp5cXS;W zOvP0bGhOvxoz1)eQ01mO?wUM2Nl#(O0qZjQxi|#d~Idyzez#Ml%*Lr0^;mkorW5;B#B8zgOzJvFVkzegHPk`BhBno z#;zV1S%ut^TvLtfKRwxelS|xR0IzF*bPBq+EZ(^3J~-*X34QOL#0$FFUEM#(qxcb* z=@8+xCbq!nqGHNcb-0;@@4JPtq+AW8T2;}@)^@>&z{w>!O!b-TD8_o2vf8Y0-Mk(7 z3vuELKs0)(>mq*0b@K&q&3mv^*M+O!S6y|e!tJ2eFcYTyZ-z>>-s5ryzlx|gx^k6B zZB+VD>-VaWh;sVh_qQ5B)1-FrslzMGD2A0EKWe7mv7#|q1%;aG3;Ri#MC3>e1>Yu` zfA+Q&Vvy@IyQ30@U}|k-qc7@%vIx$nhp_ zS39t8-Xr;%y1SD=UcQyBd627G+~()pu-s%U1)25)Q5iNtswfnc%ffT)?k^<7oq$ac ztmYH*NR!b&$GR-n=HG`s{b)Fw=RJEg1^&8W;5YfqFEQu^kSB4he znNBMIT}>=<0k9SndN^O&UY#57LT4+Be@OKJhZQhenro&}(-dH%<54fx=RB3ierF){ zll?t+^4~IUJ*v!Ijbr+Cu)UXkip~Q$53tO*u~9tZy`il+~6mYV9fx;z-YIHDc}@IZ`LQgW^8)xJP- zKKs+rTc)DA-LJ|K&-UN5sN(mkXRGfiedb;O30WdtuU`PQ>uPg}w>{5P-ma=*zhLr? z<#(K{bW>aluSPb}e?2_?2g85=o85E$68E?_iM5s_dr&sFn>@XZ`Z?N>NF#&OdY2uX za_f&6cUswcGu_dD*Cf{5c?ro@T5vZeM*f(UdCq{tI`rR(qs4kk(yb*O?;4M2aNh_E zEU-S6d&<$@1zQl2>((2zA zHA*fO>WN6x9|CKNoHPbJG;=nxK!!JvWG&mr7`Z&&-4cD-O6a2z?wJUJQ?9UCSkd# z97Ob^^=w}3>@o8%T>C%er~cg4{Dq(T3(xKehMk{^XkbHc9^kPfKTK+)V@+LfKAS)m zIEOy|3&f>u0>=~kdL54ipU!)`-fXm{jiz(RvEB71xh2VGbt!fIh<#9hR&qyq6nGx= z)>c#BM!HS>xvGkTGa?zSim46u&O3uVKg4-x`KxLNADb!LH|^aK2Nv%>ph!-&=!Y2=9s__E@hHEKDUn&6-a=w(y3am6CA!Wcy-4gn2&#WBPCCh(=N?B zR=cF$1%_!=G!oH-!wBP|3#JyUI`E<0ub?*5U5e=-?+P5MWf*k8zW{VbuPcwas@KBx zk&U}v4=DYGT;=Z~u2$}7SVL8Y(!U*fPi8NGTRHg?7U0pT4}J|i$wMbe_}W8Sh>AM# z1X3S;|M9Ke1OLWNS8o%^_K+x2dtj2x&3#;n`jx0Se#SZI;l~&pcH9eK|D2%78~-`V z#ak~@yfa!n|IP|UU^!x|fK}RdaR~yoC0)9?1ow=LD3NjW+QX3*gOzD~!|%veB4V2x z+q30((9F}Yol5h&-P8flYDz+GyMXB|HyIueZ?yVd+@7j!*@#3Ei79!$(J3no?kP|76ORvw|uA~_9~SA zDZiA20S+bSMBBhg#5T=-yK9y1Q7Ml>$HLen`(PjHe`CD)&+29P-$KX4!*#IP67pU= zBb8RPd{)^O$l!h-YI1k@^Y8hsImJJO?=l~Li{H!jFkSNwdo^)-FPxe?l|(&C^47o> zi?<-mvcN)AZYuXnT$2U1(lV+wFgW80$ZmHyo|;O{z?^ix-z<7Z>i-v}{1-Uz=cfGU zI8gXc;pSh!>faA!%Ltpxwf6rVQ-_|R@hF0YpX`+UDb`h1iaIGSLU%ftkelnlc}{$w zJq0R)7K;89E6DYHd2Ptko)BL5<5%;L7TCHQZ=;9z7b$L&0u^ER-n-R(?*Z0teA}}~ zK+yN^9E(^nDRdt;oM>m&CUX8lj;=%1_EU$~ny)i_1G7@LO;=~tnl zM>~yK%v56RyiF~*DL{*#Dv@*}eiRD!p*m)`XC+jhOtp7{m1{G_n(J2NODY1Q_hO=;PZ>PP+VP`)&uBC%FTpWNS zX=ADU8avZwawZpPXGQqNRV~iz_?JDj-2Wa(d|v#YNaFvFNTSB&_Khlb+1kkjj1)0O zQq_Rvr)zv>+`D}pi8odCVwpn11mQyC9f5fs#LSon(!)~m+oXeTinn zdv0V5-KLx@8Q~pS6HG9cjgAsFN?Vhv_@imXAM|ao4_Bw86c$H(MC$5!Pd8i?81|kzI{KO)dEEFTq57*-cYATAi->W2?xMKtOCs3_&<*Xd4-3B9EREnTFueBaV#w^ zdDG05egjORv^pr=&vEmYsAkqhFSffKs5%__MUYy1A)}-GSgi81LwBZ9pg0*ga5oRn z0Aavkhn*$H4M`!PLbKWy`cd{nj->bp@R^$7#LEo8_@5c{`#}Rv{1}KAzYBMY_4fYk zYs%p`NNmSHwmyCre=vIlFoz0Do-Z9f7Opr>@cFtus8k-U18oRpykQ>WD*n|8$}PT> z^>ii5_eb@4b_AvV>*r)&j2rb{(N3r@&ohtuZIALjF8~iOnh$s0r=jN$*@JzjPgSD) ztLrPoF94>K(?w)gCp+19QFmSWYcq3~4KoW>OLhDg>rW?lZ=9OG3%KLk9Xwxm$y#(2 zGq!Y8t*5qC-#9I*Vr@pZVStYB2IQy^N9n3gFJ(Zvlnj(W2#+i+G8#T9BZNfg_<*P% zb(%q`etY~=aQvx#U7yq@Xdp5ao81LP)~v}YU*EpxBqD$lxq}xV!_q!;yr1*Z>sLtU zH7VJN^`oWRR;)ZE5Wn03XSxa!Bk+sTz9cU6%6)+*TM7l-^(t-^*dCG^f@qn}^mkMx zD9WN3soRvyWB7Wk49W2T!dDbC#bRfZHWb{$i2y`bt+R9jE&8&qSf-vDHL?* zI~&yGoiN^8$6wo#@dW93ZxQp1apz7|W|tL==Zn7p z(rxpF!QU1;7}?jd-Iztm`q*Eb^UJsLNX&QH0r*7vyqrOvlthBdZ6yLnjqi@bOLGv$ zwiGB{l{Y?4mZ3}PM@b?sW4ck((2{+EVUkj!@F&|bjTnOmb17e$xZz(fo;FQ|-h?zT zUwArMDHe{&O-$|QF4*Q|1_*N=gm*UZk!9$&EZauJy|O*kF?X&Ta-zAsKVT;{7rc(j z$(%-`eQ2~TdI8X2gbK!BuPOoowCHd8T&qJE6QhGL}%Sw}th zGeDw$-?=VTyhc1LGGH@RDc8ihEFe)7Ae#no$&^~mQ@WqE4@UOcvuSmd`qI|nkTX3> zJR3c6SUL+;O0kF!a1GsMTTpv)?qCXBGW|?l;gDiOTv;cDbg5t{xgKUI#@8{JCau^L z>gT^2+M{UL^#y>5Tk{Cl&UY&W7i+xAdY2v^o;*EjuXv#3XHGBp*!ktIg9G1_2jKiJ z{gDE4W|gvr#*@oJkIIqTFJ}uuEF>IpL1Kp+B)%4a-pl&Ey8lE8@V|<6Xm*ct&u40DG$NDjx7g8q~)hECgyD1|gM7tLOk zLllI_>?AndV=v84WefwI_sANM5kfIEz&+1leV#TX*z9J(yk1(_RhExZtTw*dYCUNV z`_-AIRwbQ?kG_dF&CS{Xtu z`W`iDGD-$P)Zx}7Ks+WAoe|=z^TZTASvFj3q%Q&3092?}K#k}7M8rFs*RL1Q*ZdaB z)XuCLKG)yNmn+vm$YZcQpAbxICe0Up81ghenUMAC-cis1z(kjTlzN!K2qzf6@tCJnaPV z@@Iu^X`4ua{*^BcIgd1l4F7XhpxWIH#fySt^&zxx7j2uk6v;w zfTbOg)zzmjrxzzDPcaLw;#V_2PSfxCkNNd^b@@Gx%PH0wUjS>TaW~RF$~Un^&()_^ zSM%vhj?3vw$9L(iF928BL`Ch}hgz*HN(vhEAhNG{`TYi;r-gd}5r?Jv!;FHCX`~qw zcx1r_)90}!?J0l_LtNf&%r34*cjgKV`|~FUjD2K}@74ot1OyTV9t{LS_yO8yRrhn6 z{FAbob@Getfd^O)2Y&ICHeQjKu=|TufhRFeWOmyp{g!Sq5g8!N5YDh@EdL29BzQ=+ zszP7N28a=J{||g7!FU1E17dL(22dXZ4Nd_vTZ=nAHL|^fKl|hhI1Up(;~!bu5XTP1KRXG% z>p+VZth(%Du8KhUW{?ubCX5dQBLTG!GMTaz?F;G!>wp=wB(Fa#D<86__095+zK7nW z6nFksj*{tJn)g4hCJ&nw${u8h zP6kEF0Ba)gx|3`h(2cD&;oTW8-_BnW60w}Gm1%3*=o2jqo6Zh6=869-TKKbM^A-Nn z__EVZe1NORwoqXbeTw08MTF>wDREXV-beY_^e>&Mirc_x$Ym){{{6 z2XbH0ljrjTnXPVkZD!)+kXH{QVUskj3w(Ta<#LFmh=(Sj+NA|0RwI^i0?9H!2xy#P zl#0QaaX7K%#1^`Oyoi_vKRy-)ZX}t51`rX%ZcX91Q6yp`tSuL}IbuHApG_NfDQo+x ziWA9IX0|yk=1d}|9Y}L^HpsCA$G^808dxXA((x3i-h&O0_%frQdW`N&W19vjLAx<_ z=BpPQr$Pt_7jpv*n@|RQg2a2P)QxWR(NsoAD2w$o(r}S6x*1{ z^3BcrE$vDCpP)5lmqwRtsh^fE0CtFe=|h#B>s&RL5dpLF?NZgjDoEy!wP);-y!mFW z5baX4iT|sib+pTo8(iD#8t`ET7vt`AALUo|k7*Gv z@g>3Nx^6+earL$Ld~9p$GT~UA>R`X;-F=Sslvf{Lkk@Oo9J(3xy=mL&m|jnK+Og;= ze^`3rD7wyQ+`Vq|F+1s6oiVjaW*V7mbpZX_@w55HAnvJO^E6#Q-2VlD?-^*`yzqe< z`&IT?y?@1+7ipjYYUH>8!p%d@kXQs%$MR}-Z5kW3XWZwZsTTlujCS!oxv}~SfVwpL z5+Ua1O`8vqO;y$nVQ`1G(-14o)nixgf?0@Jr=QR>uvhc!jmK&m96}d7c9>@=nI*<+ zitZ>Tfn3WfpVze-!sQe|5!zQ1wvcugpVwXh7lW)C8>(GsRmaYENwO63J5BXGUY)Vk zqbhnZ=owb0aujJo7IFsjC3>yT_I0c2Jdww3Fm)K8<)<=TPSvLVP;ica^;Q%#69m|kvD4wzJJ&y(bp zxc|aqRU&s&)$Dl_Ih5~~Iw0anxHQ0M@Khn)WKLN)2vyD4PbJ|Fh}4tTg2WDX*Ui;> zZACOPu!@)M=_9^4g71>@6zgqlMQWDfHf(E=cl`uO9_-$OH~6Z4xHlrgeJCiyWsiG; zQ75#XjWM!rt&d!{TOdYs_@i#iW=A^Ot(vZ(C8CW+zfHQ}Y$kf>EoOnGOD2FoZbnb* z54GZV$-fngt7ZPdYVka|=g?7TY8!Zw4+G0yr)jThN|OW6UZp@{*NNOjcCyb4WhsiV zaINgdHA1{{J09#ob%REOc0a1ROi!4G?eQ$@qcx-7 z8Eo+I2-|zh8`YfnT@%}w0ee!tk+EZ)P+EJ#vViKLpb)5^D`j}~!$~a@?%RzX*{t^V z%DM_i1%Ll%4Vxj@c3XQD)F7oD=F-H7$O4T5(gz5BC6~zvx52aSpsextw+`m%2;AwI z=nA7htTFb0Phl|y(czO`!D6lw$(tR(0w!Iq*cmF7 zm{y%F%UpWn*{qE-2!yEqMr#DdFmE85LUX;7lZ^=P#XoYL^D0AgK@ zxvDL^JG76epb@iPsE82A3170o_hya^rp83_r#@l?&TAmw>=j1UCwyOBL)K;ILGRP^ z5E4>w<_YI)b8GarKjV+WNJMY zfG{pU*EmdNBg%_Is|PKHuK652!XsNX=3o36jzEA1d4vEFQyGx(@B+A5%tO0j2?^N* z;&HbUMzm^05tVW-%MH&q)Y603Hk;CC3}=(^@$cD5fV}Lyr)W2cSsSrj^Ay(arewYh zX{Q&K1TJe2X{`*j7sbVvRdLf~F;(NJ&9Yv8=%a$rtI1m5uwT-?~8t-xlM zhC8|cE=zy$ZfeNutG?j{T`rFcCWlu&o0aZwSv;Lz@2ET?kjz@0jQ%P`?;ZSBi^lr- zdoj8KCh4KU?sN6^m0|h)JLD#8P>e)*1#&$dB|3+r{}scGeQV7T?9cP2#@+7`)d!r$ zTm3L0y%fl%dBj*48?+o^9w&yR8RO@-+D`8tjyWt74pcB1by~Ct<@QOqR(MpKWV<5~ zofOsCSl@IGVo`_;U{4!2?Q_%W;^hP=RZYYAs7LWG7gWhyFO1JhSk zferaG7A;mR&6l$~h%6t|AN-<*PT3|r(gkr`jtlo76B400&%9p+0t!8;Y?@Iacnc9} zMCv!VYds|J2lS11XJnzGS?f&7XZRQ6wSA6^A`4G=PQfK*{~+37eFPH{$sZIYMR|2 z$Wvy&)8?we_kPhP|4^v@kLW&m>tG^4p~nrFGdhU!*yVp<#biClHL-`HxuyBe-bFa5%piNQ9 zYl4Yu+6f|dOaL=t8Lqy5B?Rl|gu*@(v#hZ55+m;-LwJ2t;q1zlwJvW4o^1Mqh_-z<6;*ySMIM>vIj#J-E~ZWY#BsZg0U!OaXkR$MvDUe{ zx|FeCJ3D4ZOV9~ULyzyBmpd*Z-wOYMLsEOD7wB7M`k;2*B>#&i`CqO+|22(LuYI|} zA^Bm&QmhUZvySdip@~sy#$16>Sfm|f;akKcetsH7mtlVY$bG3pmz41UvzNYK^Yt=rSxfY`)$UnBOvib%wNy$UIG(JWH zfwWBoku**UAWfSWHcQY2lcZ_TEeJUZVDSsV9bkzt{v7A?=1qK1wBR=^>V%`mq~!Pa z{MlD3H>YAKb2qE&v@HnM@DHAF(}+S8nr?^sUyrV_+U&*i<&E9n1zD)$MMK3hKd217 z8s1{LF|BLIr4rxyDNK;vlvts~SIVb}8YMt3a2(A&F3PlW$w9s8vW@9 zX_p42IKo0CYv@Ct2m(7m2wJwu~->e;{_exBiW!rH=VKY1T}lvG_^6V?p3SsObfeaTI0f zfO0M8JM;SXM4ji|>9d!^n+nBorgGWCU+mhk`QPZZiBn$xa2tX)nE&lmt@o@X>bAL_ ze5NaF`ZcW>?{RaKPnu>z|If1KUj(=dzRK8uMG85vFhO3^^k4gpNr}K zZl^(|!uNiyg@6BRCwkRYUk?hqPN>GrFV2i*j5OBy#>Jv>De2@T8#Xt1De>(=D5BqS z1pyHd=a6Iunx_U3N4eJN+ABs~79y7xog&%KbYs4S0I$y01vwtRmD9EGKo;8Tw5Tt( z86On9liy{G5)+{K9Y7IJd&6iuuTFX?Pu!_@9a$Vp+=*5ZBw`@Y2RuUOYV1?TN(Dde zRLxvK;E_@i`45JC%NH2@OmXzM{6MJFVSgkQFYNr-C8mKaa20a3kbjEzOmK?xg}(oR zu^Oq}n*O``(yLP5HqLup$>q;W&swYZzZ|9G=AGD7z4L6WqkWQB^7BeBWFi zSS00vvwEq%k2J3XYAdiWh*oDz`P z6g9bOO3`7}Zesu_*P@zXus$eA@i=tHjZ1ij8*~(GMf4FI}idhrNn9R zzR9+{c*wn1phfhyVGY8v&7ZNk^r8$MHG;ENtxK8!4JT5J6(ycIJ0Cjoq2z$m8mBgfik8 zMt{3KQ1dbTHE`;P9Q@lcUK?jvabG?fa1nDqnif^L<=g?K7_?wKVEb(wA(juP3?Mo8 zi@#SgM%C1&J{%1*TGuy-3vr&bg;FskF`_4iVni=HavDET>(R z#Lc+Nx}c9=Ka^f1`*+NchB?v0X)Q}XP9pek4a9gxT|1qZTEQaVW-Fh|)>r3U0pRnd zGd@tdgu-(Z%Kfn5 z8@LSzQQheZgmaod&6j@x#LEb5?o>#~!)ooOzhP zhs>}EtCOkTwywKPU~DDB<{OvI^rjjZiq`wA2_TliSwwN?8Z5*M>Z_(afl!u}9wmY+ zh=1c2BakVI?5&r!SlvEuL)4qD&L(BTbsQN*A6b%1!f&aADJ`30Rb$7sg|6a4iJo7h zzR^)oS)nz#ubTo}vRol2i@xTW^`6E=t0Y+kL0Ln0s{XB$Q*d&Ra?WT8zA`AEW(6cfor=dz;TbDT&^OQ%)vqA@34E5c36q@_c@- z?@paHRFSV2+7(e3UgNQ9hZLCY6xmcKGUUcSe&)N1y(wftXP()k25``~`>m`H{rstUJZfq)x$M(#JqMG-hMw#8exB(8KCmkHcmNS!!^;MN z_Um!C54o)0`;Lrl+&%}#=Y!+7Xy*r04(Cm8K|Gd_lRc|)T|)^p@*}&6qZL{Bz0uiT zOhiv>r!mFnm~tB241sZPQ(Kx%+NTpZbJCd!Y>X${zU=d;{a7r?FhkJ)S-^?kw}2Za z&QOSG8a=qE827O>w-jcs8aS0J9LXi92#u-$&Mk1C1-7$R_PD=?q}F_GPqnzp$udufx|6s1doPy@H84S^u>Za}I0nr1vJ;x>#R z`q#IVvQ1X&PO*Nq+h}EI9}0}v$k~o|@`UGNBLuDk0ecY7+=I*+N_L42;qt@2_P&ds z64b9%Z88_rPusGwH369`Fml$5_rRgI&dUb`Y1s*uuuFUF-lyn@$wyaRu$Z>+>*-?g z?UJw>EGcuwov~kVVp6Z`EXXZSUg=+pGVhT+;|=n~jyu-ghILA*hdi*<4L^@`KaIYD zxmk^p+7MdpLtp!voi}2nHDgy{Ywn|5N>`UK&7H%k!NP*E=v;7UYRT@B`2GjNQ+&&_;7a* ztUaPk*P0$AB0{l#P6yF5lxtXGq3^VD7lvAY^sHyX7iWdrQpblLrv|F4s)lKZM@E0n z_%5_qA%DX2_3qt_`|=x45(6t70;tSt0ewW@Dds(?{fL%%1k&(ej{=8$+%N+2lm|n9 zxs9OzhrPEBimTn$eH#ewjk~)Bm*5V;C82S54;BKAOK=YwT!KsE?jGD-6M_W@4!OP7 zt}kEqt$Wt`POW`*?R)Pks`!WMZu*_?9AnIPJmdFh=zLDx+V1IZNyv!qZ7HO!paS{O z$)iZ9AxdiCC*)Q$(H@G%Sha?GMK^WAM@iUQWfgxX8 zTu4?z`yAST0#3Bst)_?^Tf>eFwvgh1Qb*YxihENuA53lY!cx?$i-H-jQ*Io?HCh=|&YZUe4efE9e^#^;tlD z01xnTwaJRoMGPYVF3^T6fK;^rdNu zzJ`qi)gRE}CY7ZyvKWr}o|t=SWx`PsRM)W^#!xIW6|zI+uF1Y>wb~!tV{`e}*!(Qm zlR7@LZsYFw9pNYO(%)m2tz+I9dG*!r4^3mK$?*lfh>`qg`h}@zI=%_T09Sr-)pYs(bL3nnGEH%-}p*MLctd#JD-tA~UNoXq@@Z@J zfQ_@yJrT~;`RKl5TMRGI&ImGyJv7rc<~2*e^O;1&fl+?!cNmSSTjhoGxBg+D@ggaK>qEL)44VwMDXP4b_CbY zZr!s}Sa%rYJ{Pc-T)f)5`h44{f-uvQKDRcWp%3UFN1xc-A*pV+Kt$W!`MSOFzquu_Ja8kyr@>wO#zsGv>o*g*H{Eod>@lt5 z0D>uIjlhp#P}51~Z@_P0b4Hr`ZZgE5W$z}=!tiofB`v+w0fEj!q@;Y;whty@H0w--Se($z6&KyDIfwad6n4Ymp{IIsg#1*hV~!G}&2CS$vZO zMx^ZAIqHD-UZy?rb_|WKUOF?gXzKfVo^58;p=pj`X`@;BT-XbGk&K?s@nUtao45q? zVfRzRBxiD8t_~D3_YY4H_rp^^7dm=o=FNSzcrbOH!Ul>6o1WIMbDyIE%MCLry4ZA> z3k4=@Dgr~bl9^Cg)a(mKC?47^Ijuy$;qc91pI;Nq$MYjK>2dL09XCzadKF`>pjWbQ zy{uq=F+Kk+W|huHsvS?{F6xd5v@^3w+^cI6ZcoXbkxA`921$Purn z$C+KBfJA++Qvu;wRhHytDiLz65%Svj=d#88+v9{fh@*h0n4Jif5BFt!1=?2N5rMt3 z7@qdg46KR)O^=b4IYoHk1&osd+_HCZH8A(Nf+6ce-&TNQv98N$E zMt1Z5KYDg5iM$F^mL*3Vh}Z=LrOy@C9ekMZBlThQ(f6}NFDgP5P%4t;53I~SrA&&% z+fhL|v9O}+8x-(k|3UBcz9)*5j+In-E=&fjYv8W`We11Tgh9sU=he6kE1vgTv@(8O@&qf!w zVv@uJq3UNElqyvc+&jMNH`U%Sa^0;SFD(2(kJP{nP^B=x1G=$CD-c+ki6P-in>y$y zVtqxH#}gOurZb!M_h#*a>mN|U8avxbxs^O;(t2(9n)h9*9BU)%x_cwW`BlTRQ@W;< zfy#ULom@DB;A}hJl`3cYj_)tDJq-B_ZVHF<*D@>>*TO)mZR_^Fd;R*#27IUJQ9(1 z%Bd2yFU|{eYE>xy8hKN+*Jcgg-Kp7VL;ZB!%!|&SgtjD3QK^p>%Q>5wYw$~!nfhLib< zv$Po@U1G0BrS{Ug%vU^|YY{Q5Skz`tbB`g$f zm?Z0&Wp5q*QIE%D>MC`)u%1@cAu9Cnrg~X#-5mXzi#_1S91sQ{6cWtG4=mXX@1j$| zHqPM`ezEoX1y=>FX}qmz1q!g~TSx`twa2waVUc<@1SUr#$Qnf`E;y)#6qK-~`A&N{ zo(4Tmm@+d^TBu>)e%Zkhb+B=EMKQozIahJE5c1+ME&-^oOEO^pAZP=IK7K*JK>1t5 zJEx}%F`^sId%MMt(a^FLY){U=b$W<-ZFG&fUDX60^}V>U+7jh>_`H@)ajPODvcUN` zc%J=8a`|dW*;~v7oV?o+yWo~`C+C*5dgW~><>|As`{s(d`}&Cl-2RH{^5wxY<~qhH z+a;u`^?q>r&b8zCl7ngJJbQ!c)aU+V#&y=|#2ka2=>j0y2%j{_dw!4yw)V|f($_R- zR4~=iT#gLLn;Fo@05$B(M~IZ>$=k}Opbb+#8r7ayGhnues^|N&r znsy<_G)Zi5c?3X!7WgO{?Q?9xITbMSiYv?*^c`E!O_dtI8cAp$(D?NEGf+RR&V{Z9 zk=jsR(HKN!XU&G*+@>+}Ug?v=ZcZ(vB2pig_uXq(^aDN8NtEFkF3lp#PkIs&x~jJ9 z2$8Bp&VsfpY1Fh=MG;h`cvZ5vdzst8i3zx+*u^lm9#&SF^i+v%G`I~<$&mnhp)JIB z!^;S>3Q4b-6tA`FPXg=VsaWhw1X9snpgL0*U4(a%x zuYSc*uc;*k!VtToTfw*%9G;h0&^-q>$XI0}dtqHhX=HL$B8-?-0)d_RvPC;ONW5!;9`hIM4_%h2)2bU_+)g~hXv4GWT zwe_X-_NgebC`CHq_Wp8FfrM-bmSauD=$Y5F1+AAz(8HIopy(8xV%!F(vI(7ugYLPV zKS@A7PRY7^^%51Nc0P0ZNLgd~85gxVjkPAHJjp7}PV;+$=9cCvwMA3jkmdq97$!V? zQ*Bcn^^(*S@4=Pu-A}TNYlNl1WTbEY{sAro9mzCbC81E!CB>i!B;?nOx*)A(KBW-3 z5KR_oK5?1>2{im5ZcBa5&K>GXXbGBR6cKA*P|`D(e7Ta}8rhIoKNnLPPH`->os z7ew*zl>)V^x3t`Q0#h%|T~Ne<5sWHZl8Rcz$RMruGkg*$?u0E3mofP@DRWel*Z2K# zX&F3B=#PS2DEjIFuiY&s4|^k^5S)sJX0D>yi%*64O^AoL@;mnv4Sba7iOs>K%qseq?3bI0v#+>>6wp=9C6mj5y8#z82#@72e3InAq=~Px}wtnik>-s4qraXF&#!>xr39yMgDWLnWbz zJJHfG1BX+_Tk_@4C~sn3@*B9t2E=G=<{&MUh&qu^U=!Pj3+$ky$e_G>U8FSTTIB*^ z!Q!s(G_`3-PzJr;3Rw7(?!oPMx>&-er~X}|(I8SfWUIk1Z72*ULD^`M-I;YyK^4|) zgtCyi;P3uC$%u0f!k?&GudbBx-frWOCSeTL$bqrAWtTJ7Mvc8b&AFMjaWm+rG1=nq z34f-mR5=W1m0(kPUz2V5%*wb1vA@D0BYTL{p`NZ!F}FT04n?ix%XLzm_+rAh7y-Eo zMcU)?s7ACV-!PEbk|-NGg-P64x9H<>FKaHws_^A*uZ$xry1S-5S29e_EBX*dJaju^ zkwNg@ydMFR`hy;!$kgUf04eZky8LDiZe_fW97gxV|MU4#vBy=om>t#NgIne+H@^WT zukW`J!=Qz|FHJ#@p^&Q6r6=;4fN2%*`4QFHv52s%0cjhSGg@1 zhU^MAS>xU`k7wz+f}giHoYBYex(zP;CY-?=24i6q)?Nf}#Owriqf@=f$rU-K$}?NQ z%c-rZS987BdmVRTVK@ZDU)w{?qTh-?^3VzkIox_H^IT@VAyKyEzjwF#Ak}_^(DdCE zc5k^b+a$2oBmicFcXlX+@`_+3@TEX)15-1mlXVXUbWHB(`j&j_*?aQNR+GA;3Y4c5 zGB%2D>JOa@Aew9G_laFi$!tNRN6m5l+jI$h{-Cz{y10f#Uxu~9457QLqHfW8-tMAMTd;el3% zom8Bi#Z}mBh12ElT?9wAN6ig*l2_VIH)P%?2?ov+D5CgsE{q7h#p&oBStAd8vtV=U zK4Y2u#&__{+mCF+n6Q3l*h8T_rn~>y!+f(h{rYYIC7z?xmqP4|YyT@r+wI@5FtllZ zaA95{q6km9Z5Lm&DXP=ahIh9l2;q|Po5Kea!||PQM!Hn) z#V35=W4C?+$lsk0^wuuk%T1PghF$iJpqy`eLCDIV=Q}2E z>F2N}aA|%u5*+2l4`Y1IvBm~(-dk(U1=rr{*?Z+G&K+eUXh^eI6KB>)ME;E9JHEHU zb`0K%IK$)1m`(7F&kwMJt=R3GHImrYfwxl&vTU;fr3*9Mk$7zYw!8UA7zFD&e@H6W%-!-KZtKAryW%5r*SJs@pzz8VXvvYJIrf6w4Z0Y9kM` z-vcL_ogF?Io!)&LzJ^Zsl3n|3<4f}uU5B6DVSf>>sXIAZSpFMp>-jek+15gbCBg263$+!VkX#D zoeu=Q#A-v!rk<_Z@Ns}IPd6!v=dN#-i|46aj`EHX=4ZCjBL?+0d*E;v*s+dmol!Jv z3>si%MhI~cV^hm#`U8__UcyEZC%gT}fF6`g^$UYJWYV_ zu#258QD!(U;C})zdpm#%`F2NCJ~%Tg zd~;NWRSopFM8JL8SxHe|<20LiCeO*Z&%KUmUCU}Lw#j-y=XJ`^n=uQn5~TeI?Ol3Q z-STq(1Uy&TaNo-6B?0$!Z?oO;UP?=~KWyY(#_nF?sEIXlle4Uy7a_O$!GCnN6Ml~1 zss^h0@ZmsU|Dj&}4O=teDC?X^CGpY+s_v|lvlv$2lT}YC!mVDgjIu7nLg0XA(F4MfibBjT`}tOVZfEzf7xy;AK#}5pa~vq6xl#fr`#cB z@HdIBwm4|K#J#1PvDiGEL85|WZ zt+DHjUe%$0y`ybvXIWH*LSYRaq|cu`ORK!=AoVZ)Yp6}y-=-u!UQ}W!E+aT^k>{{Yl%5BzY#$dPmx)_hg3jTndQU!3?!a);gCD#Hn45}yrw_;Ls%zp_S$2h~ z_C&-O#(n}+he5p8R2_GSA^MIG2KS*A_!f8JGLkyAd~LW3zUnu$_QD&73ochu#=YDY zJ}zfxnEh{|5;D4<0O}qWoW$A;%X?3mHVLASn^gjRcFo&nH)enna5(o^Eavj=em=od z+q;&|r#vFD&llj@A_|ubjyLz2DxF2y7g+;>UuFzg8Hg5)PW>X4!SvammaTu|7FQqr zA%E4g`^6^y$G}KP8jtW(dG@~1EyGiN*av;9P8^Ce@H9&nDIwHJX%Gv1_!Dr919JFH z$p7!*h(Fo0zvn$=AJs)A&q!8m>yleoX!T2>JwuVNw7wCtPYL4(KsO1}AGM-Wrc z1ZC@_0K%Mu{-a2eNNcl_ByZU(mAOM})H=3;ug#u~DkqXu0d{d)^_2Z?}lj5N7y~EUdm)MY7AE8Je!UxB-IUqs> zk^mk|2??*gC}tszk@!ma$oEXg+c9s%cl{NRSBvF#T7_NCJPHef(=zWP)m|8n1t9{z zwoReZUwJ;5@8NT7qIpP@K3at4iYDnAzx{eR+yC*{%i&g>{8K%9{U}tAsT=Cf(l}6i zye-y(+iZd5D;n2~aCPUIkn}ObaQgZ;_$K(*B=~&anb`!XYF|y}kN3Y#Jw^R7^i=$3 z&Hs-v+po%zRXb-KDozwg2|I9KdNlO44J4vfMe~Te6s&(^t2opm*O8VV!N-G`ixURE zFz&XZI_^3nc9hw0OZTmkJsKZYt(w8(gFY}t{se?VCQjfDA7S13n7f3Qtk|-*=;Qs%8sC1HtGm;%mcsqA`|ys^BmRCs$5}(N7*a6iRusYV ztfJo;cvJNH!JDfWv|C8&e));mz-Y#op!kQ49?rFB?X_6*^M%Wp-I_|WmWQomM<}VN z8mHvey+Z7_@_jh@mxRfb?ypK^>BGQtiL21dLi-aiA9sNob-iu&gn1|9mLEiM{b3vP z(daSHPPy#Q(&^tb4u5gX{$GT$|KlNs|B@L8Bcw#=a7}V}pma%~s)}MfE?NnlP;N1= z0z6sVO-Mpcp9NCajsQ}h8h54@6{czO#UG@Lzfej?`W;2*8Gx!x%Si&y#!pD{^@GuZ zsE4=sqUNq*kp#P-Bi69)-C3Q3H*f++Pa;iKuI5f4bGb+Tz*Q)X_`}vCq!heQ;AnW? zWD)~cOlKSdWysat0(l-jiW%)sH)+SYqFu<`+jaG*IFl8h5ZPr0&Qfjl$s+R0I*$js z4*CaSdNbfuVKyFJd1X^rT|jSEUda6{nnB~klN95dOQ^(me)p{iSnOWJ9sT}?K62>^ zzGOhHq8P5>!NdZzMODrAb@*tH=Q>)%Fl*yrR>?U%KQUcg`FaD4s82y?@{#=Qrj=`DjVPYAf12`3s^wa@m^kkGhH^cpV=pLwU9 z&H8RTU!}PC8xt|g5?Z^mpIXYuSh3${>lC%axY~*(u0+RC%-nw7yDAanaw zt#xJ&y)oTmX7FU2u>`?mZkPZ*IL2*M1*THgiCk_pR-WatEIb74;KZ>uGBo%&;jl;< z{q4x+v+T#B*rDtNtI^I9(N2XGo!{B3^5uWj(K@rg#>oD$al^d%c76Vz<6AG-d}E8v_-7pD~vp18DIH%D39-G<@~EU z8vNVnAi*o`C{|%qE&kI{r8+J1uB0r1Ig&Sfu5c+yX3oxjDx7QJjc#2eO%H#OC)O}ZPGfXr9nVIi1OQVTdak(J(;j)Y4z#tfX2)IdKG~t$jU={hmnNQli$dunh8jYlYfr|RLb11Zw z#UmDnDOWc0?bE_TMRuKjFbNu8{TfX;KKxw#QF-YKdRH=dx4>HcaoV%9Q*ZP)BZ(BJ zU$ALM@PCno)Z2IWGd$5{t7cx|`7d~43v9g+G?HG2(;x;Z_bv6=_#?H^p*+hK-1lnF zYA=qZ*on8|0pmC*)`_Z7Sa48{L*1T^@i#8-rN7WR);;n`>z2uBM-d%-#`P#?jL0FOCC!kU=WDv}sJzDRP5L|XQ3El&1yX6Oiw?r?O zj^8&_jC!oiz6CHh>Uh2bXpG_ z4ew~);mhOrNLFKR)P*FW^a-0b80;et!o3-!XGFAuVH5`_clj*g!$(OxA6%E-mxjaO z_%Z6Ep*NGaBYr!oFzb&AMdaC4LL4j`QYN;WOq1V?S{==-;HN^q-uC#JDG|de`ch_1 zznP47lYJ`n@+uKM9*TV5p8vhPBh*!+(6nT*w*hympuJ-iH=z-kR&n-&clZjI2^bCJ zZ#BR{ge9|W+!S0ED@>L`6YnB4x{{#aB>mL{_(q5|>kV=Ar0i6q!JCDToiE%Redo=B z_*vQd%+Rso$l+~NjHn^Fr#$i1@aXs&3JQ~08rmPo*HE>Fj*TFZk{+G}w9vMZ^kOQ6 zDK337*|pG?UuN2w^)gJbg+|tuI##fa1}2DdqZaH5JLs$%?)+Va`H8AJge8HCc@j6! zv#J0WXpz?H>&ndHjr<FF9JC>k*oTd?5)Xhqw%AbFh`Xh)_V#xzLI$=KK0Zm}l00)>>8e zrXL=Yjc+_Sf1cyDNYu_3m*NcXfmOLl>>!z(l~NSRfweifYX2OJ9HpbZf><9W4hQ4; zGQ!CgADh;;<|->y1baJ|w{hARs}y@>GkNh?+ckDO?-TLM)l5y;HEaTj0|N)-(&?iKaDSzL@V*Xg8_8RK;F6e!a(cDyX~HO+Al2nY5j zXVq4uSumx+u=+0{oM#7bgLpvJm}sBDk8_%8dkba<#ZR+moLF#(qV-o<2!q zqSC!wU{FtrVWC7stdk-q`Q zV@ZNAU;PJg94t`3)noJa@4)fE$O$PZaJ)A@9B_)py1ln2S&iNb1&*s0Kn|1ZgzTM< zMFS3Jk11`XLOl3Nhfm%+u|a|3yENh%P~i9n20H*0I3Bb12JsC}4iq&@>A`KUzJ-Fx zNGrX}WK)=8+hizP?hS>kW)`a^SnQ|Z1nTDT3-ZViY$dT8>ynGZ)as>1&A(7??Nta9 zad3b_R(Xg8JdPI}gTy_)<*i2_r@R*QDFk9K8#Py5hnF6gl`lICv&9d5C>jC= zFv42B>msBgCiSNoKpSGsC|;BG#)ofRALEIG(}B>eQ+qrmDyO5nQyvq;HL5K4$SmnO zJ6cYajrz$DpoR-GYu^m`ultVuOIjf|)ESi*MwddFt0LzsZ_E?Jd^~ofDpEvBC_XHx=P;-t*7MMw0wUzeYM{*3 z#h{UACdnQ-xU{*iP`?ku=$W2{LlD9>&I*T_rJV!O0NrT;K+zkCs300${dOpG)$ru1 zh@9K9!j`8wW#vwpN9brWvHB2UTqA|AIGEG=demVmL51viB^smQ^;M3anSrc-mN@z3 zWMUhF&Fq0EZ2LjgdC&IgCoPKd{BGWo5bT^PX;Ok>A2bcqG@wU~zrmP?7qbe%%An)( ztJde7u>#z;GNJm+ti?<4?Q&n*g~}Q3aP2bRu|rIZd>+0Q>er^s5YIL8=U#TJYxDyE(s+$VPB;mLu1Vh2; zxdSo*o5l!w#LZsH=Cpck?jM}y=ReP>2T7F$IgWeS^3XW81Wb)>4?yw2#OQlaJn%bM z&A;J+GlilF8I%=N>tSZe(ybM9JCCNW_+;BE2KV^!i~J+m@U0=PuKP05ACRzHVDWmhytyobI9IYLKbeZh>Y$yt zoNTB^`N+_6$)C_pSJmGE2!b=m)Z}ernA@VbgGTu8u2! zheim=9RE+LMOr`=4B_tXkQ7U}OwT~ls~rsT)wWCobn3M|7)+~r{CcsijAdSDGEC?( zc#dY22VdFtl@`QMk4}y@k&cd^INHf*(epKp`WGRfsHE(2s^2}-6G{dg^guy<1HNp% zaccLYr#mCZy!yE1yS4Sict5ix{Bi8$fj@TjiJSs_bWU}O@w9m@i0J7zWYb>u*5=Z4 z;*tI;yECIQyTU^|{=@_7eeOAOzt+igKeXT`cMZ9-Gg$K`8$b4V_qYabFIq0CcnDZr zQw1W&c}p5^PpR)Xn;dSL0z#E%s}Arp1(Z3|tfI<$&eXk!oDId#rnj$V!+BF)ilw-(>Cq+P61?ch>H?PcWGqb-GoiE89txNJCH~r{R2=u5%h(Po@ zUJ&<`5Q1$yM}(q!<>@8%{)Xz6i|!69`wvuaXC}ybi>LkXsNQaw11c!0*JP*<;2DbV z;(DI@8et8J>SdS){ZL%W;uG-rC=NyS#_>}1w32A;Ud!;OKvBKt*g48jRPRe1h(8q7 zJLuQ~*MdBW{}T`=Oaw(bhae^asU2|Zr$>49IcRiVOt<=}XciB1T__=Uvrds@rc+0r zjo@>##!>>7*hUBJ$m!R%3VO2}8lFBS5~Gs}dwgq@$Psp*#K(kwMKdng^TnX(YGmZ5 zE3i>_mP$EXQ4Yh>vqRZ&UMjXYVar2nxH`n7XFZ3|GPa31~S*zZxWEVh*b zHId?iy@>p|sRhWoVhPE`+narkFHPImj-_8@kAr5vx#2Wkrd#u@lp)v(}QqJPfpCDGsU@*DEdgWUo1U;QjJ;v6_MoN$@2@=}Sm!>xcA6DqDjU-_IWvw0 zWclJAUm|NDq*R%59eR$L323K|tJXYFQvt*a;zM^@Yosfc0(Iib(A(bXk~|DU;#TJ11Rrv}Y0K+#j%1|Yp+lN} z;FgMtgzM@;;B`GqAChnM`o_6Y0d5vHF1>}x60mA_C>oief(G8_~x4+3tU{|zqRM!(yG*YkI{yfMaef$Ac|zr*Ft z^SS+Z+djaU!x9ST;~+MBb5;d7LfP_cU)bL6IbmezlgQ=VK}e8^f!l@ApK5(H%0|sU z)_I*x7VXTz5W*~W6EmW3H5wqT0}f&Ty8|oTMhEl|e98!_f<%NGMnAGcK|V$i5$_O# z9*b{`yu85gMK5nu4laZ{(RZ%J!ooK0UxfSgb~cGjNUUwt5#Z|!1rWoItezEP?ZyLWhL7>+qg&}QTsetik!;lgG=o-- z5}7+h7(U$L?dPyZu4ld!3iaSTE=H)Ah=$R-6l|Ak>lg=ff6l?=x;C0UQH zCF*&DXsL(1GQ{iQXTV>%CN_R&^uSv|wMBNnB)3iu+}g~#$tLRIJvtOua-NE!yq7*n z2%FY!dBdzu38+A5c4q*^#E%#H@_{qdr}%V(CTy{80eo@YZf{uznF%@fWPTgab}o9#O|ZSK^j#jXdT zPQ0kM-x8tn^ zj=hin2>_isgP*Emegd|>R+<>M^+ElrbD^vgl;){kiu+Y7GW~@+R=a=0)&Be4p#K{h zkAEW8G}?dbY+(HAY?PP(qUYteBKbRNudLe$+BlcXj2aQ_mir?Z18lDzOW8x2PhuMh zN2sTEk5C_^67F3dTw;vzv+nJ?Y^rX~z-yW9jw5`@F5?!v{YsFQ*6Fy6*zkC>O z{sFxOo-z2G+mw_C`~*18zGGM%KV|GTKDL^USah}ueGx^NFtIZs1yCM5@4}J68-Pk0 za?J%M#QbH329ZC=C%3p$0y2EXvK-+lzB0`&@I393Uo-R(MMTb(E-VIFE;4}%3%3)pL3%f|YVMtl-`WLUx)5R6&(1kPHKrAj4jwHgTxMY>UOWv1gAOMN`Rk4nt- zo_)DCp>F)6%%6U%58~)PwRwsj@q#o|sCK;WWpg0V6E?2*xj zBDAKVY434+EjF)*gU~ER)3GVlkp6rxBt(zzzJ(Q@l5Zm4u8@k8AJiJW!)cTI$rFh_ z9m`9CbIc)~B_J*EzW40xxyM24O7_J1#Ok?~Pu0pzyRVqk-$;dDdBoK=cQ@7NjBF?& zqS2~NyLxYayc+&Zd-ZYU7hCK~bNCAfaN>g1;~%T9?6{ca9_`wpJ-WLN;h%u8qUMmm z3*f7#5U~g5135JCsY|B2o6(n=3jW_LmAPLJD(@P&E?CIElDYVmI)AfMi27qE6#waD zsqO@|YoBiSxmCd43G*}RcIQpyv(2=+2xI-u`ccHM5IjY5RrOGCPId!+jJazluNolu z&hoA0({Ie*;g~->sI~3>G^+g9d@NIa9Tqy0PdK0+w*A*1u(OmICQO+Kb}vsOjGI$r z6g;7B&0h_-A6D{Kjl2VhW~blnQ^)(Ms@$ZYrkQK~CRXYHL#y)jFG>#Ue_K$(Kh{(8 zF9ZDlOzHx^P=_wRoGbphIRK@MDKnf zJ{&-+)DHOuYfqAJMrrQFL4S4SvC~-h;2qH@$C%mPDf{C)#SA(rGvalO@tQNW=q%av z0Vdr{Rk89{{V2PK<#|1*R~KFwS<14Sm6elYiizABr@@gK;nE3)A(P1Zsd1~ujp^|O z*#G-d?9FDAB2>rl;`>j)VgdLR`Dx?;bCrG6QkA;usk{F8C*a!FF#jmcueaYe zzI|H~en(rZKW;|GAMZYDkW6GiFwt5S>IG%Vg)`Xvlawmc5y7+o-BNqBaxrALVEEa2 z{iRPXA16rb`fA_(xPw+k(y_~(=ZQm}TTr;1@ZoZ8C!tYaRpnvHZxb-|f`3fFXjlEI zhWnSqa{mPJ`cL?t*eI!172 zg&sJe?YuY}pk?1-mTV{(hI!=t4k6m{VQk)F#cK`nZshdFjc>Hpnvg_VYP1%u=%llX zz4s)P&Tc$a5EZusd~Y2#K~6hsqe2mci)umw96fo48`8ZVYTdA^mVovE$giKjW3rQv zOzoU+UV}bdA&Z@teKc~>qh5#OrpcXJ^4};^9oOTk+FQ6-abK#p`Bq`|TS-FunnO}- zf$Oo%$AINeANBwL8Kvtc8i|eG-x%T+fa#t?vKdQeccI<^LE4rgnrI`5D2Q)rN`~K$ z6MzMVT9wItd}Oj$X>}$T6lm?q_Y)uP8#Zn}UoHr7g3V4#Kk!9IXL=`yFCy>esuaBC zos)Aawz>V!f}V_DW$(WQJ-_w%S^rQ|Dg4C_|NqMbJqxIw^IYvy1lJ04oHmxm)3;aO zB#2`bUwA$%Xb^0gdhewR11c>O^QN;m%AOsGqNGm;nT1lOIJ#^_l9*XO1TASt*JWm$ zj8HM@Oyxd*o}Iw=#TQXkT^KVjx6OC3pmqYY%S`Rs@PNrDbgh17x#Ss}=0%PZu8#@I zZ6wpPV8*!QcQb50^s~nhy&os1UW;y)dq?Nvg=|4};)|r2nID#RTbRMZvzlM6Ynz#$ z^|L3)Z|A=hk6=I`UtCY>?Oz{4rWx!d94!+@ElbUuOE!2hB+ek-`f9Dg9n4U_BTXA! zh^!!llQWkMcwBD^y7mJ;*WEiVtCX)H^B8Y0s}$;WSkvY83QH;`u|{0A+)G(gRIjdw z0d=XQbN`kvt*ZY3d^ei?PdI@2$MW)jk}?0W81SD6hAmZ~c5+qiYhMEyegXy#893wp zte~y9d#G@`A5!_oMC^KD^g-zJV-nqek_-Mjy8QCd`CY8}|I+Bf?7ct&xpQk}B`ik6XnX#URgo*1G}SOYH-JV(g)(PhQ@AsrrlBAEEJQJ4 z&L>9I>^oaii*D{V+dZO+<1Vqp0tnI8UN!=w@59jc*`U`8IccuZZw0R428$I0`MZ-j zQtcb>BJ!scQJ-n6Bkm~MnNoub*_8u>LPj5I<*E!bPS1AGZEJnqn5-1r;*4NNZREsy zu9IRRCoX6_+1^s$R<$Wpy$-4xDbY^N&EudE!Iv%Gy(nq4a4KiaMP{aA(wG$|&YGoU zveOxlP*hBUf`-Mb+ACU9J=vCd)X3az#92Tj;>?t=jieeR4wN5l9GMu!=M>fCXDZAMM356-ET^z$=geO*5V{I3amRf~NI`?RB;0yhR7q8GO7*+G(uQM;op4TVF695n8Ifje{#VQ^8&h#+?)>ruV36~2%$ zP!XH?IK7Pd_Gh+Dry@_7HPD-2&AUPhB94kLk zV9dS?+URG21`9=lWCw+{$V7F3tQ?I@AzyGqg_^un01G3NGlPq@M%qWTbKy)kphYXR z8@)l{4RKPH$fc8YwOG^B*wsjlZ`qb`NoeQ|7*GtV5DI2au9!Olb!bG`gNC8x6qWrK z{`RvIoAL?pwC^{a6yUrW1mrID(x07_P70=gE)fXv#_a-K=?aQpXP%>)q-DyqNsTv+ zm8vHvy{aRiugTjznUB+olmX=6!cMB(+pRnF720S>MPzahow^EJr8N&u2k)G*J-NO` zFLdHXB%Kads%2D{&_H(RLUrQPxM0>(lAQgd)A*{!_EwRu#*W^5a7p;XIZU0VZ~(PD zZURd{J1zQd<`%`2qcu)TvG~5O-6Wy$E8a@vp_GIyQ@0_uP)is5@0ff$T!pea>V{+b z=>w68tsn^vHe6VLHB<@V<0|h)U~-`X2EFrVn)adNY|8@*MV#2K#@pd9e93LIq;85- z>_fRS@bYwx0JgRzrLj^6HdL*p#}T{EOYqZ2Khlj2Fu3UR=4tHHEE~sWER-_ZfY~g{ zeV6t~`jqj6ck{XN`gDE6^&P`)XXK61fh*HhCC4?zr4=3BshEWzn_o=aZevI6>O$(Z zp;Y366WfTZUdQ^=0YnG$(|}>iR?gH%!7Ofb=Sd1N-iZqJdeV+U zv+9GviUdt8iXl`2*u|N;;)J~{pScAh%gHU5iY%mJWDE-M`iC3*wH-I%RRpb*sDwV+ z*lDQ6e@e=M;Wctj4fQ4q!*j_vIC1&GIUzy19ppCYB%l#Fpe1ErN8MjY+5(N1<*Fh^XQqvV|>EmBLqEz z|3Ehp8LUVvUGh375Y5s%Q>IUftzoQ0EjjWPgn&LEkMfIb=1^a1 ztEd$Ej(g~+RyZ}gd2lww>|*@M@h$qClQ1Inw1Scbi<-Dbw@VM4eFN^rh?G2NdflV( zRr4{5C4>hwob=LTc*Ia2u=Vl;P7;EQS$x$X3i~=^tsX>o9;R01OWB=c&j#9_43L~k zz_r24R-zu;CQl7;K^qB%FmETf6VN9}M8(U7D^|d`fXacPJt@C zpwU!;TY~}7QJb~wAdqD6E_X{)fqW@zzB>f4(~q8tY9B&iV1w!;tXH;r6~YZlXEPt6 z7dGGHU)%sw2*Lk`KSa#acYqdKiW0{b#y(OBYO~ zuBK26Nl>zj;(BDF0_A{wzBHYVe^Z4HvXqGu5{h%N3#!IzD`+gRcVn{{&3sq6Lt#;W z@>!ySO45~RO<#jnD@DC!+23V5bTp(vGP1Hhq>!)i)kkL@bAN0*dR+A6+W9&r6?g6? z;qhrwpv7ckMFO>aIt3|%FuCB?-CXdtaW zKpOGIw~x;)IX746iGEujoa-V0k)ajXQD=j7&$hzK+?L&~V;Qbw7NkUK=4w}WVN}pG zo$+O&vRMNqVAbL$G08N-YUpzhE%cPwVY|hiAMfI@1Fdp;E!cIt3aOy7$?17i#XSt0@-Vy!~>tFa-3kKC#mwGuwll3TfGd%QPhM zC8t9e8#bXk+?)7D8{L%M<;kEe(4yz%C82%cr~qyO-3~P|sM|(A-x`!@LkAH`qT5%z z_^ja6#BJ4H*tInBx>2E~8P7ecj=!OCeg$}1omfT{SPA6*=uV$Bu zNyI)is}odd-Us+&rAoCGrNT9?wveS3E6>0u;HKfN-wj9Q&n_2YF31$Bh;81&xy>ec{=z zl7dQ&;4XeIG;n%_Ww@kiA09^6MU$-yZ*J?-!DSdhDSQRq^tpc1Q zb$L-2%PgZTLAmeKR*|Ks4p(^J=>ike3Z}B~Pf6l=iCtiU?#G97R5~h>Hi(33UC%jR zOi(W%hBmmTY3#V@M9^WoI#MRBG$1QQFEgR44ycYxl zcdvaY<6WqriBBKdU}pqoz%X8_f)(zV?+|Mn?~_ha2^Rh56HSA^v$HPm&-S10?;rWV zi0{Bxxi;WuzNe4XzQf-?&VK%KaJg|-HQ?LX>34OXxFt6JVAKPZx5TSLT)<7xR|_(6 zc;7P(+g-j1qietP+i&Y^IVa6-^>)-uSi8Eu7Wq^S_MF)`)xJDvlekYkMND10v!z() z7fs#c_np~zJWW|!I$4cvb9%B%*b{kQaQv@inB@Jxm|~QDd!c*ELzisyv;NMZWX0hhf`QxrBS43C^=Q!(zJ`^%7N_)Ur zsGKDJ6;OCiOf^@xU{LKI$u>t00AV>K79n8-e8It=MxSF#vQ4lC(Z-AOiu4x`g7uwl zy1Ucn2|}Jk;6-<8RPKDY+AVxMV8kOd5RwVA(K|*E4<~a;u&z=`bj`75uWdR+y_rQ3 z>DK3)%3F=wPGFR7I!>WTIr!O3mA4u92M)7}F_a2{-Y`_d>K+8S3m#_A#&|Fy7BozI zCbn7759|`$!ewao9t@k zf(^3I?sZZBdUygwJEF2Sum@okfb<%wp+iRQ_>LXM?D}mZ+e9k10<>0Z;xTffQ7{q9 zjC9`Z|7JgELk=!7`UWHu3-{930%%!P=5bN!eVG<`Kvm^qGXZd;?q*p3dq3|u|T43+ca5mEL5en88XN^yA(JX1#-FcPh@)L{?Tx%a} z8yx4Ro+1yKSqPT~Zt3;fYMFMRZ7WdRfi<}?%F{B5#(@GsHaWY?EZj&ky8?%rj%*;d z*{d%bi9f^XQ`%5NnJd;~L?k$Ny|*mn5<7=~gk1pg05UU9EqUS}VaUAHL@#f0Oi)@m zBCs-d;m9SQ>;`i;L>GDlFso(bQatU3>Wl+Yt7qLuIXN=~ zb>v`-Rx1IDqo$$N zrtvUBS8vM0F*9(Ajm(t#=*BRTw(thW88s?1?Pw2q{ehn-|D*(K6fY`MNRK;250G@? z0*rO=*~d&Jnm#fziS3Eu?HoCx(k;nX&bv#pcExLRRGFSPe^k-7fDgWrlO5SOQAnW7 zO;djMz~`%i;!jibGxFC{CYpHMe%Vf;86ZrTN?24A+(GQSKjz?O;N@wX16?}00y~Q6 zw1Hix6|aSY?`p^+JOY6FBq-egh02(oEVRH+@FdA&iv#X)a0Dq0)jr{^662hCy>U2s z)5H}2d%pb*cZ-^_F|pN@EbG~z$KDW8-HK>aDq>HeD8gs?Z5STQH+a(lKkmHKI?^V0&Zciw|Dk$vCR{mVsriE|F|p|DS`f#F zcNX#;%m&dM7ePReT%tmcclk9fJ@T1Lxh9)->ySx?EID9bJ&-F4^rkeN}7h`Kd%&;4mO z?qJda+y&*2-d#W1v>yNv)dQY8UabAN`Z?HGY4|ok=xg3>#p`PGh9Twck-Kp(%4Uc} zS!Cq+)WT8@<>EKmy}f-XAtw9vr-gVYWgu~_wG%!k!a@_4WCr{b(Qc6c?RU_6@ThX8 zKw7^KTZd|wRulQ|Y^6)uM&#X#lS+__;%F=%i2!-@)lR$O$!_q!2}XqXe;CFNV8Y{D z#gV4gcHY9`rS``oy2_i%ODtS@69m=6Q&orCWt%nyWSH+JzEPuh=|}y9@%xN~joaiU znx(Aha#wzyms08Yms>vdMzK&I-$xQQK8zOHzH4AgvSNKc5mK1GdX|j?=Oo1S>C@;D zw_NU=*AwD?4yF)@dE*HFI2ix|K*Y@WM2K!{5LuRb>iao5%6}z2p$lx@Vf>4xibXQb zyMV4S+2H=I2@bXgpbXjzwNcfju5bBmtQ0I%lct?3Xl65hdZK{y*m#M&)V9K;u7uwA z-&MLFa|DMR;D${r#X=53RBDy)(7jx=oKjMWO4*g?kahnwXSSSbFW0A#Ikw)F2mb)! z&Hl{mPo($Ctmbl=b`wtD+ir<(nC9n`jjk%SzU}|RS@_wIpSK6PsqASN%Vq=_EH}Xe zOC4!G{1#1Im@h`h!NC(Sbr{1=$}`o)klvYi3Kz})&-l{D&DAtQ6~TL{He%K1;s+sq;H~{6)`m|?uA#Is?yq;0x#{eqoZTSL1^D%uWkfkRE$|Pd!dE2;L=`wbkQ-7D+ zG|pxaZQaD1s5GL(y`wnoAy9DNXs0*mvzz|HGWl7b$5xd(Z)`(UldrC4Qo{#UM#B_$ z^p4)DkZocgMlu2N%>M?t(bSzTkya-{7o2{t?OhR`a|J>@N-$t zf|AMwwTfPBA1x1PQhVne4^;9ZAc^FquF{Dy#Be0m!8!k1>peG_7Gqk!)jq#fA^VtD zJlucIN@BxxYd+uUx+6D3Z0*%|`{R>$nzx4%BOh{2UWog;|JeRotKE}LI7KPgz{ZUZ z{W;t-CNavn3$IQUTN*!`tgF%QwU#G-3vqE(S94G_F6^krMTRd(ZdWuLVX^Flt6uA^ z+biAbOwAj)JTx=*pIGx-WwF7q%KiLyz#EJ_g>Xx1TT^FumrG<$Z->DYB9!aUsVK0! z_0jH%zxxO8CpT`2;_TwSyyow?uTgqTh3Awu z*LqvydY;gOuA|N50{lw~ru7vMKt8udvB1l>YW%Pbj7luCM;_{H=06xW5b)24=32HV zCu(jb#GE-%toweEcjC7OfWmX)B72b zrhYEk!HU(aMTzoQUysT6391TqeUAvhgKiIRUsFz#2QAG&E`@37$}&xBys(s9gb#Y+ z{ChXVgfmp@wOqK*>8rz8jWmmaGoaWUN(-eGEs&vnmT&nYtX$=RLxK)vUE0+9K%Mej zy%N3_8l_{-`KO^zv*@I}7%doC`JRCi>c7k@3PO8YBJ)krFS>VQmHv@u83p{K&-yJf z*u+^S(7rHI*){E(;ePbns7;%Kp8i4M{A4IReR@vnbePwf^w(BePBNIIuvORC`X(cQ zIj|`g$+??pgR{11{2xTTD7`xcZ0lCi<-RN7=~R5{beU`6CjmpgW0b*i3HnV3-s^rQ zKKCd}<8Shi)G#^Q-{XH#kDMbvNsWJ&6i_ZSK@VCi-5Wjp!1y*;Jh^iKw>C>ZS+jqg z25-~s6Y_raQ_!UGJx>Ul4ze`R_$qu;@)MiSsqY@yvL_?!q8C763)WR6sAe$gMeBEt zVuywQ&!Jx{Wr)$*dr9;< z(W+b^LL)_}&a_y>dyw0*sZdyVtHl~aQNE>rqC73ltYM^j)6T&$88?-3GUtZK0%IJZ!WlNAlrVN&S@CE1&T-= zw1&fHkU=k&RFv8)-%-Eil|-Z)YtH`qx1151@gHUFIZN`wQc~@cL2n4#y$J!txa-A8 z>grbg<*dH(;$|kzW`P9=r`?^8;XoCWuhjzGDZn3HAvVx;sLeTUj6PE!BORaOWVPfa z;%3rwPL}m!{3SYS9=q&Z9O!ymOLNAPh=uB=2$yv0UKaMB!3l&mGN8~`tFTF1$zn#L zMRCbBXs;+QR;LE_WW&V^k@oyF&Fa;9mz>P=#ctzbugOq#OBOJR>&Z-~Uv9#X>(Pe& z2GA@=z)F6Uz9|ipI?NH=ruE3Ch^+?bmT>3g16#v@Hc`RfAS(q^)`<>c5l}mrK0aD6 zjxmR!hBpIJCzfOmWBbitmJu;(K~eVl6nV`e;Nl;~PZwxF^gnFBy$C}uQSB95bW z$k*n64*`;#_4A^*WOa$qoIhBfrtwPawW)3b-?%^>&B~aI(Qy*-d3nG`Qay{rl4NNA z1l8^5mgHe{BL7kK|Le+bv+-e*?CIgup<(mKpn^Z`i?+Rc#77K(7@1q;S!epLUM|kC z_3=Q^R&e^~Fp?cwi$FnCu^^RjCTqYnth22&aG`YJ8n{ZeO54&|Iqur-V{>97jT*D3 zv!2Bfen-hssb+1Vn*r1zPUWU$BzMh~-L#w%NyUiw1(iiQj>oSD!BETJYmTP8p0P#V zk-oDRY3m_%=IxdY2PBnDN~H5r%~Dfs+5CcPVTrsbJLu;||K!ESa?QuJ{+g|!0Ckl2 z_Ke&!5y#Eyi-be;wX@MxtTn&>!iPucRN5zbKSQQIPQ2N_$b)N!E_kh3)Kt3(Dyi4` zt9@G*5XN}Z8YU3~f);rizgi6t=1XuJ5hb)O*$~s(wJ@7nFJSULAL`4yp`G$NAG{2A zAi3l+Mb1isukG;{*`@4R7n(`q{jnFGMq=#wo>g1*%kFav_=dB?-w>kX(4cQ)S*;84 zs<7LY(SUUrO%ZRTAj(hoYHn^l<3>IMM4CIf_&Ud*{`s2NZjgL88bdEnYZF^;>Nlr(-S03x{|6)LH7j$p)JbzqT@X}SDXtC}^ z`d=BQWm=38BAo{+D+;+)YrXjJcwr)__9V8YjILk9s_ahTJmbjS!Iqkd+D&|KAP1j+ zSndJ@y6AUt7s{+Rlfz5|StDMx&vm%TID7XpTW5X$f!a}TNB{TR5zk|k+g+EfXgaVN zMz7edn|oJ9h;4z?`R^GEONW8{7Wq$rUq11UTRiJwsSaPDjkr*!oo(g#=IYbiShIgR z-Ed?s1P)$GSuwk2WR2c3@l&U{>eZ`RW@=6!G}5WH5RW5Ev>u!oQjl>^QLw56v4u4r z5edQJxqh(XJ`5I#isEI|TSK}ik*-W+p~U6$tahV*ms0_WimtheSQMOa0|X-34TtBx_V?rY59aSw@OW`q9hp=4h$QZ(7kMd6a}!^&p+}{WBbbTj(3C92)E;u7C;9IbrXjEV7HQC#@wUc0Y~S8 zER5>8xVuOA;P1zq;V0+I4SvLAaZ_KKCk#`~gA{VvQfyIm)C6@T(X5-*GV6NvE>}C1 z)hj5LJCuZ5!gmD{UAUojng1ejHyw=LVz#*w_*1e$z;djHb>Xd#OCVY-m7yL*brTU=kC5YZtt(AT4ewp{ zxtBMaxXHC%`_{nFqM#NX`W`t4%iU}gbG_zxqJc?Zk(iD1ogC}M4vkV~yUAQAR-LQ4 zbn1N~ZxhgBC`Mf{eW5XsGHO){RAj9<9l~^zE7KCS2OSR9@EF%BK*=JAH0I|Jn!!l5 z;N(^3T3`P6V_H|I5{SpybxS@RFv?4^GHc$-w8{=#6v=CFoA6TAYT;5iQT9nMda_QQ z`s%RoWFP3)wJde0Y(MoS*;1G~7Hi!3oZD53#kWs3@HcuND;s%>6Y8@0{ zg;~kB;(Ah;?l5nJ-ndp+F`|D?@72)DY8nxG+YWx{opxDb*J~3miD3YA%whgY{wFw; zf$46y4!ynv=<#y<5Mp_ztb0+RY_%({R9|kA*#c)&%Uk&3^Y0HW{68J)k9%*e$cG#3 zSNX?v$Slm+bC=1arAY)XCGGh%P);l6WC*sXJy>TW?`bhIWcIjc+<5a&&Jz>sm}sAV zHKpiX+vFBkDVbbL1E)@>;^top)(NStvxZVV*`h`&RrIG0UtHnvS@Zcga{qcg#g_qq zu|?Ee-pu#>zoT`#>`X7og=3niJ|82G)Nae7&qR9uYGX?wRh|2}rMxAZN<0`5gq-rEZ)yA`BP|%FnpZC6h$* za-mu}@ywmU6EcRUT?rqRDrnkqB$XnNEC{8wxz`|oCas68Fie#cRh$%)?01W9j5Y`R zt{%tXbfXk18~5_LSr;P{meifVJ03*QvQcXy+Tkm{p+910kHw>4@ph{1*>PET49Jxv z3@N|Nkh(AyW5;cU2vJeuHhAP~(+giAxn9jP)m&7RwJc7h?Zj1JUDitN5XH}8dcW-x zgJc(Lkx5&FdktFsS#NTb0OnFg6RQ=Ii&%i}X5G(dz|zuQQFgUI7U2pkg^*>o%{F}&7hq+IZ{w5M7z|$Y)HLO-jm+zC9Jy|ehux^po3*Qa!bpY&3*APSh zReAEx)<$u==jR!9Q#;(XEE@S z|K7s-5D{$NlVc}qWvk!d_)^Ji8OBPs(J&#Qwge3yfp z`{1yP+?mzLPv4qu4?{DnE2j}29wxmWZQvLQhqBfJ+Q!&Tki^;Ct@gg7`h4MHT5_vz zM^qKH9g&l5K5E435xWqxzj#5%G>>D=))6l6*5@V1jVi9Kh>f0cw@K3At9fjXz zGVmk;Dx=T$SGd}HYf9w`V8t1%n~~an*28Mn9}O>vTPn`JC{dB$BkPpTkE3?jNv$2V zV&LUU65MvGC`xFxFEW75b$3^P<0Zu{jxUQEPs5ncA?he1Azz5JPs~Z7eka?yfq|cT z{|p&Q(t#uPOyS)9Z616S<9c0+6B><BcLuOPz_EZr0Y1lN-_lD|QXRbZ}UBBEW zRAup*ZgyvL&CYi8`6DR?lX~|?y&$dk97aJ}2OH+Ck0#%a#+6IQk_3=uWWRw$~ zFpEJ8Fz;!_Q$1X14?S7eeub9f^s+$`VplnDd$jivRllI-DvABjH6GO_36@s=n}`L) z>z$|Qt+i%Z?;EIhGoNvX86+!8buanhiP%}o^ZB3HTynwO0@*PCr=_ZU3yzU)GA=&T zPEhyyfZSK5#UC75AAIZPj+YH5XbtI!!rm|GSA8U9Poc_Df8Q0nqitkyR#Js;9&BK?eWTJFkW!v?2Av#|Rxm^1Yva#1yVD~(KXBME*4uu> zGyFAP|JVM~`Q3nYDMqaXcM>T|MOek}Pms2Wezm^xu3%5^-=VZEVSKk1)@cwWPr6dHOAqDr9R7F*axnVV8&&WY=+wDcKK12STSic-jxjTcCMzbf1fE zXyzL)Y#(p4(}K7+hzFLc~M+xtX)wDfrv8BYfD`;$JVxO=gI1{Kq&(v z@4KH7u4B@I(}7u|u7333u(VCM(3?T7eA`_QVWquMbt{092y-Kw|6$vFTM+<@`-*sH zT?dWw7ENtfrnIiC+28lUriKOHmhr2}ksCFW)8{5kL|E7$mtHcv%gXd7nYY9~yhp7$ zabyW94;A0B?>H@RAIaC-3kDM;Q%3EHDO0<&%hPlR2^JLA4BrjIw~fGd#V!Zsf=a?8 zOGVjxVtlu5Ju!{9jTe2m`VFx${#fr|BT((Mdc}d8ur}#!75BA%@3!kQ>#6{rd@5X$ z#xs~++anTYS1S=z|5};PEKXZ*E>qc*7qs#+N3;j0oTisN`vq*(aYdNQ4Dsua3P)H9 z2hbGiT=P9fjqKB%%|FC)6RvDzqMn!@U2T8tgjTb~CtIZ2S6w+lr#my+=@#EBworY) zal`3hZoK`9WRev2POKu>LN1Eriq*t#tkqF5Cz3wGk?7lwT_$e@Vb0744)3e5{bvzh zoCLJ22x8`Wau7hAxGN$Y`b|_+v>e-|t?UEoWx_|(l0wq(0=X8Sx^sg=&!_`&YE)@*%NsTU7A^4%(baJES%r%>FEX#cb0A?>OqM&9ic0 z-RAC9et2=Y;e9-=O}PkyxOOCvWN&4{%4+pC&VWY?KwEuMy@(v*!%|-%U&kJN-@c5q zo(9;M{cob^nVWUp$)JYo<&+-fbyUdg7ddP6U+u|f`N+*J1J;k>mDi$6UGhnT3+W~N zAkl^{%O$uMe&;OPBS&|qS$|$NK}k_UZ(hRs86?=7RUk-SH(<3=$!47ILKAu=IgLp@{wS0xoB`Q{*?_m-_6Vk5>wA2d zO1;pRjq1O!oc8)ng?Ck9i6j9C)?_m~fn{|`s83l(CfqEtGc_hY1~;f@R_ zelM_62cKp-q97L;O?Fp+3Lpe9eH)#@Pe&p#akca73C77#l*#wo1~LE9aap}!TtLWd z=sMh|rI~kLm{uWVm?pE+@M__Kz5bkahZH%+&!1YScu`eT8{aN{>x9fTY9X>NDCZ%} zs5C&Zh)M}3uG%EF`?J5}5S--3P=Qz=cLw*h-^yMva`zN!{TOW?7vvc>5aVOhiew;G i;t4ja=!D`7yfADzVwN5MEy3r%8`uA5?w|j?`o91NtDau~ diff --git a/admin/templates/stylish/img/icons/add.png b/admin/templates/stylish/img/icons/add.png deleted file mode 100644 index 6332fefea4be19eeadf211b0b202b272e8564898..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 733 zcmV<30wVp1P)9VHk(~TedF+gQSL8D5xnVSSWAVY>J9b+m>@{iq7_KE}go~11+5s4;8hc+i0Xa zI1j@EX5!S+Me6HNqKzU5YQwL;-W5$p%ZMKMeR<%zp69-~?<4?8|C8S?bklXr4v&Ov zb&06v2|-x?qB`90yn>Qi%Sh2^G4n)$ZdyvTPf9}1)_buUT7>`e2G&2VU@~Bb(o+Mz zi4)>IxlSY${Dj4k={-9RzU^W5g9|2V5RZ2ZulL9s2xQbZ@r6eP9Ra5u(s|C0Nj#&4>wTSkb?%#=9?@ z^oxDy-O@tyN{L@by(WWvQ3%CyEu8x{+#Jb4-h&K9Owi)2pgg+heWDyked|3R$$kL@A z#sp1v-r+=G4B8D6DqsDH0@7OztA7aT9qc1Py{()w`m``?Y0&gi2=ROcc-9+nU^I6< zT=e_Y=vSnG@?3Ue{BW5ONFttcE!R-R_W4O01|0-|K-YNXLo2`4Qv z`r1LxR6#yf3FB%T95gJnaKKivA~Z}S9A(ZxEDK}O3T04USJ P00000NkvXXu0mjf^IS-S diff --git a/admin/templates/stylish/img/icons/application_add.png b/admin/templates/stylish/img/icons/application_add.png deleted file mode 100644 index 2e945076cf7686b3b408d6eb2cf913992100da15..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 619 zcmV-x0+juUP)0Ag3?`k8$#1J0F}NdayEtTz+~+#EG995YAF(1xew#=1J)ogJuY z3Lxu(1VP;KAh`GKm^?X0f~UCV*)Nf5F(3GKr=#9qzp;L29U)FF98>T4&VoHZ|-ho>^FRq4ws;uOVa=V002ovPDHLk FV1kR43LgLf diff --git a/admin/templates/stylish/img/icons/arrow_down.png b/admin/templates/stylish/img/icons/arrow_down.png deleted file mode 100644 index 2c4e279377bf348f9cf53894e76bb673ccf067bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 379 zcmV->0fhdEP)RB*?~^j!LKVQ>(O&A{Xr%)RXLn#U zs4LtZ6rCMFY5|B2$)yG$6aaIF1^DDBbk%W#`m8Mo^~Z-=JluvXG6M=M%Jv0O73_44+acK zK=CIFBLf3BgAPaxWCjC^LBUDS)q5?HkM0ihoS_kK#PIl-D%-2j1P>Oa%ti-AnU~WT VI^xvQF6&qvTT*m#iwgsTH2{W9F7W^W diff --git a/admin/templates/stylish/img/icons/arrow_left.gif b/admin/templates/stylish/img/icons/arrow_left.gif deleted file mode 100644 index 932ade1601685c41edc2dd9bda214ef64a6c1283..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 131 zcmZ?wbhEHb6krfw*v!o^>1^DDBbk%W#`m8Mo^~Z-=JluvXG6M=M%Jv0O73_44+acK zK=CIFBLf3BgAPaxWCjC^LBUDS)q5>oFTFC&>rw8)8@*v1Dr+iMvL^E6%~Eh;Sd$?t WxAs8qPPGtZ@;%yDC2um%9*_%b^H diff --git a/admin/templates/stylish/img/icons/arrow_right.gif b/admin/templates/stylish/img/icons/arrow_right.gif deleted file mode 100644 index 780431c2bb9277f136b819bc3f184cc5ac0916f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 130 zcmZ?wbhEHb6krfw*v!o^>1^DDBbk%W#`m8Mo^~Z-=JluvXG6M=M%Jv0O73_44+acK zK=CIFBLf3BgAPaxWCjC^e!)r4)q5?{mzsonZZAyOp_;)oL)=2bWn-5p2Sa1ShSFIw Ud!#sBtwr7EEh)h($ diff --git a/admin/templates/stylish/img/icons/brick.png b/admin/templates/stylish/img/icons/brick.png deleted file mode 100644 index 7851cf34c946e5667221e3478668503eb1cd733f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 452 zcmV;#0XzPQP)Pdwe5?6tW?r-ok|b$oDQj8FV%kZPq;(MWOV8?8;<)(iP}>hNMU> z7fbz%jjlr7h8uuoQ~J6}n}@Y@PdTk=)PxO{%7zmL?dchpZX*~n;I{!C>*(8cU;q(~ zAS%Po_@naEU!xidrBXD?;hN|x^%W|Ij)0y*r5vi|?W&Fub(NqJ@z0o=O^9OfoSNCh6N{UH*G>^7ov@7G7j2))Sp-vPxR_~|#}oBaGXXEK?XK|Y^H zHk(B1f~_(T2#W< zvaL<2kX^Wk+SW9-V%M=b+k-`2ClPnyl}cXV$lX>%QAD9oKqix6;&?ocXf%qjM~iIW z4r(PA#H9|DR@zYr^SQ^mz+r?4uyTP%4!Uj$G3|@^f^JjEqDb4hL3OR}pcKA@uPUsqI85-ih+cW#mYc zi0T}yV>}fm2znF>#s1x2Qlrr{snu#3KhP}(-}k}y;R(|2Hi+?dY|h`tqN){Y<$y?p zaw0sq=UXrho&gF8gkM~M(ASI^Qdy9lgzj1YCn7%n-^X;n>!?(5DN%7hg_ zql4Wy8ok7Z25lz}lpb~*ktPRPq%ZQ*4qNZB!+VJ-egn1}Am_E)wd|HNMlZ|>D)M67h? zOIjz3DJbk0=97q(mSBd~-ilc0Oupt^z$#N6O&at_s8u-PL@9M^gQuq(+UH^IB$&*DHP!HzH+vkEzC?S52tN1$mKhziPkOR=y$ zhl#aO1Xly_M?EkN>tM6E5T&Ht4dh{0oQr6Q1b3J=sM^ACOsvD=TSP81#0oTC1v|Df zgpp-GhL(KrE_8t&(jeFR1W%(osQ12tvSpHp_}~HR_8G{VUO;FILQv(P-b)es=)ZlJM#c>{Wx-rgY3D#Ol9rJl39A<60Xo5cneo(9g5a4q>ayzV-7%Ue2}0_ z&TIets{Cl`n(nefrZ+9F8|N&Kp}^StU2b+&pVj;XvgEdBL3Wlp00000NkvXXu0mjf DwZ3{L diff --git a/admin/templates/stylish/img/icons/bricks_gear.png b/admin/templates/stylish/img/icons/bricks_gear.png deleted file mode 100644 index 9dda1f3b7f68d85b68bfab89e22adb5761252101..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 876 zcmV-y1C#uTP)}BC?QicMU^5VL?a?LB9X8V39(?I7E*R1R(9AS8WMki$D$Eb?YxS5O;PkQ)zZe7i&(OD*qKgEa-hLrn{EeHY%)w@WN)m^I*?RV}xV51G@XX=oMX|VH5kxA12qd^*JUe-5E5vyz z*o46DI)>u@gYaZIxSbt6Jw2cfv&o8i?f6lefyaC}RD^ct7MQ@-)>afYZHAFv05`fTwOcY(uX{m!`!-R zbgphjLV8VTxDeZP|M7#V{!Bj#W)Tt>QWQd%_&SMvK95SJf@JL+=$e74??o^U;_;6) zHa3pY@d*yfd%?0Sa`IyLfwELOFR3)fI0JubCw8x^M`LXqf*@dGY8oyNY^+Z}*LB?J zAH-O>>eo+1rk%1hOvQ!2cN2d2?-uHXIEo8vToeK|KINWnNa4+Xt#u)Ykn|6RndSZEQHfCZG5CcC=T z`(o_NTOjbCK|GPF4%)<=%>`agEOIe^kJ+gSd~H}=`AYZIyJS-%Y|LeBxc&DE@kHvV zh>Ui%*7I#PNlilw1y@n@6l>qJC^2jm6{4Z3p@!y54^361Eu)pbu{`o1V_kbZ`MR$y zdh|9mIxVK*qV(LJCr#hETgDW!z&|9$wh3`VrtfF?un9PlRLs>2y(-4 zrLKn+LM$+c2R9RpV`rECN`sK@HGt)oU|=2}GdOWzXOuyDL72-1pjr{L%5=%8 zRQ(pEyJS{6KMcTc^`djdIyOcaz(RmDeoTeB8zvcNthS*`>A=K4->m8f9c)wTh(V)x P00000NkvXXu0mjfbTF;3 diff --git a/admin/templates/stylish/img/icons/cart_add.png b/admin/templates/stylish/img/icons/cart_add.png deleted file mode 100644 index 45c2900089c5b3867019ddf2d1c9c41552d66b32..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 711 zcmV;&0yzDNP)uCxwbv=KH9zoUDon>V zr>UxI+l z#KOV?tXAtCMJ|^E)z;P)Ha0epPNyNuGGeh9*4Njuva*6;Fo-}P0FTGRu}4QoI5;?f z$z&=kve_(-kB`yqcK=$PP6rN$<5RocMzvanBuNc}!7!r8WHP+bYPFEh=h197LA^$! zfn+j?{r!DJA`y-Wg+eHo%iPh-%*WOJf!=_4JdR?q$TO(d>pTNeCUT`x=_#{;C=?2$j;X1sGkv$Py1I(P z!$Twz39zJva5zj#0@-C@2}IWEbb{S(Co+D!Mh2YN-Q7j4Rs)eqd1+}0rBaCoa%Hv( z_V)ImR4Tvy@g2C`Zb};S^YgG+ER-}@($Hu$P#T`&g=Gkj-rm5_>p@&oUYt1fLwX|J ze5DHBL!@j);j;`WIfC2L1zdi5R^$Me%XOaFdp9>XM@hqIG(xY}Q_`58p2l6>Rjidv zSo>h6-65tPLP|ZR0blt578bWNJ3BinisDB`9zE&c`pZjrU$*1q7cN?9zz+a>(-SOd zeqB2|JMjDcJn8ZAag2?P;mWgfcq8A3P9ElDU1GT3!LQP4wNR;4n4FyKbHIS=TjBtW t@&m3+C;j&_I88CIp4At!{qxjQ|2w4%;hGY8=Cl9+002ovPDHLkV1ip>OPc@y diff --git a/admin/templates/stylish/img/icons/cog.png b/admin/templates/stylish/img/icons/cog.png deleted file mode 100644 index 67de2c6ccbeac17742f56cf7391e72b2bf5033ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 512 zcmV+b0{{JqP)CQDsH?WF>AIFt zQuJ}i;w2$ZUU#3SZ6RY0Gw;kZ&ol1~2ky^QZ(fom$=jNJZt!z7w_pH~wdQ;R)Gh%BbQFCx+Nm!4SuS-vkr`vhhrX zM*>w%e+v~?m@q~ImPAgtLkR_3U<2F8LP3W5=LJ*ZN|S5p#sf4YFr$p~Q~Z*0Ngxf2 zjk#J#<7EAlhzlrV53~GF&pIzcCN_lz9@05UeoUXiK%N z#x+4o*i_c|6_Uu1+&TIho?3@y4k-#b8Y_o94zW*B3a1ne2-Y5s0uke$$|@=}OP-i= zNYZQA=>PrZu0MfSL=b8UhD_={W4IY1{b{)U)*gc45xtL%IYLY&hF;d`@GzI&7H&D# zh;z_BX$#hqh@q?AY3sJTod2%*Yd)_>YM0#q&ixGuh+PQsneK)F00007$(F5I~EPw2+A2=20Sy*#|n7r8sf)7*RgqMLv3&KWmL+^F4r z7i0Z}>kq&FSJ~Z9+<5!dQFwCOz1ndvw%m_4J#=sT@Q1U19`B}1iL1?~3va{ZF~|VI zfHw0WI@T{zdi2I_>3m@YYk3d;l(JU>d+bPFLOo8G;T$3)1!qp*$dock%HEEk|V0 z3L2&;r~p>tQh+yD{T!MxBF4;%7xC6JH1CtlE}+w%Xkuu&haUcdHC?=ZKr(+GZJfIQ zJ6@GU%>XYSae67{=&NN{rB<>+N;FbBA#_{A0WZW7cXJ0E=}(_?dx9< zr?bEW55s(NboZ^^cb|S1s~AxnBh?-gQ{Ob@*3}OO`vCi&FRqICO$~lSg*6r5QDf7DTmJy^bFNy&p3d3; O0000LZjC;k_h{kHThqfC`(hFmxSO zSd?`bB$R({-*5T0gITA{|Fu6pn0eqpx>}JTL$UWimE@yNe}L98c)I$ztaD0e0sx43 BPNV<; diff --git a/admin/templates/stylish/img/icons/expand.jpg b/admin/templates/stylish/img/icons/expand.jpg deleted file mode 100644 index e7e129fbd17280334c08280cd9f92b3dec71cbd5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 773 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 diff --git a/admin/templates/stylish/img/icons/house.png b/admin/templates/stylish/img/icons/house.png deleted file mode 100644 index fed62219f57cdfb854782dbadf5123c44d056bd4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 806 zcmV+>1KIqEP)v;U&v3%|^C`Ga3?LtY&4dQB4Oz;1v;J%z!D&%WRH@BZ?x; z3)8@IUIv@hG|@IwyHLC`l{1<4BK>wam95g|i|?Cfzt876&-Zx_0f5*l-9`IJI&mHu zE6$@xB)6N}7VeR;!X8D!TAw;;&0Bsj?A071cO>X3K0wl7WZ1;Tg!4LHyNcnzoeQ7t zNW`aSlm8WXYkek&ir$13=ngczvf zV0vnjNpCF&K8px}dunv+`LIb-sOC$_jD(;IBI$xC|7`(+9cA>Vir_V#z{?k7SX^Ah z^71m~W@q439Ycqfhi7+gp#A14n1n1!e>$EdeATG|f798Y=ggzwEKH2Q!qU2QA(Se?dwqG69%>n$6rtE z%F(845Az8c{w(XgimJg96!jLMz?zS6I1HUm2baqQx7&@nx;lhHA!r6vs2|fqJETOu zLxeu2OQ(3(au%dg>AcZsWI(zXn9XJg1cLe8k~0h0wOL=&HK}7X k{AKr*U4z7Szv)i%9gTgghwgU$Q~&?~07*qoM6N<$g31kYk^lez diff --git a/admin/templates/stylish/img/icons/magnifier.png b/admin/templates/stylish/img/icons/magnifier.png deleted file mode 100644 index cf3d97f75e9cde9c143980d89272fe61fc2d64ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 615 zcmV-t0+{`YP)gNuvOO$0ks zMIj=HnnBRUR?tKXG11rxCU4&7dG4NbuvR2_mEvc)n?Cow;~Wve|KR^>9@p5l)|QB+ z$jmun3q#x>;ss-PW_mnr2MHVzLAl1RW&0?VkixF*4t!St0YVb2wnKdU(kmOHiL;aW zK8Xte%(k>MVGG$E4no6dcNnb>BhVHHGD&1pv4YZ68kE2V03t5#PCEFm7=ad$6)+3B zTCmn*?A?=u(o~ET7~-7g0)ZB=6|lumi4}B}MLgy~Ysy6)Q5%Al7|05&1z3Jpu>cF8 z3?VXs*3<}%h3`5Wld)N2zJnk%Agw<~3k)sPTLFd=F5;d8-bj-09SkQuynfflNcZLN z!^_37fdZvzrq=9~mp*($%mcDRKC&qvaaZuX+C=AT6O*~tHl>0mcP<_q>-z%$xO(@! zYluq5a8VQI$S@4?r*v;gPo!QQ%pX3A#>xx4t=w-L6COWx?aj&`f+!YePsFtj=hOQR zP3=E2j@9L7s8;T^&s?u(Hdpu?CubjMrGn{t_37>9$|AD)QE08weJlKn8|OyjL~7oP zC8mPT`jzuH*Dh^I0048RGafUIT)4H~*m8m>egI0iH=(LB%b@@O002ovPDHLkV1lw0 B3BG67=JY6c|L1R-#TR>fC$3^Y%QEnYO1xHsf)+GU`3F<{J0kR(;pbF3)zyg$H+idfnl-wl5Wkh!vUH z4Z32YP=l_}1rZd1W_D&^$A($A+&a0e&P?xx0!ctY2}*<#p+qPVN*B(YzvAWXa*%bzq z7Fz41LKILT(GWohi9|LgIzSZBhb*Zf6R6O}WYQ4GOi&71s9lmll0x6;8&ILOl$j(c z0Z1T(6Tg09{?wd{moFHNN6PS?$|e>1MxSJ(0Z7o2)J-Zv|>acY@f`(Y@g7GwsEj5NLQo+q|HsxQ5}XSX_d@*^A9ZT9=A{W~j+$GyI1 zc4oqTHx@1FlRjw4XWyPN5i2~l_F3@aBk!0yu^aoRDvXy}8@HCjUVQUsuSH4$T5|r< zzZOn^?Wfa6y|Q($Hx4{ws+)wX6-HP4zo!S?4KJ@7PG@G3G{CjXs(p*kIrj6rHs7_y z+=<-=Q62s9FuWa^X~WKgJIAAZJR&XBB002ovPDHLkV1jCMPILeO diff --git a/admin/templates/stylish/img/icons/page_gear.png b/admin/templates/stylish/img/icons/page_gear.png deleted file mode 100644 index 8e83281c5f8f0381c43adab760e0b29d28f16629..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 833 zcmV-H1HSx;P)m{q03skAA);_bv3q{k31qwVo&s-q`Z?_e+j^w(WL? zl+uETs5+~xBU2};OqEE9ETLGwsMGe1%iTRNue)9}|0~E4B*@5#oRXZ9oRXZ9TqRep zPrGZuoOON4n@=uPbyP1y4G=+HktC6l(gZoFD>@_lXDrN?wo+zozGt3P=Qh+3L7+}q z2!WK7geXLnO3Vw;o12Skp%_E#+N#9;DDWP?Q-VS3B$v~Ha)dDzWn0zG~O(^_1!n0HYp-( z+;wPIdoFgQlpYV!10V>5@a)1LyGBMvoa}miyp(bxbMTM-FYNyx;V@TfYddyT00000 LNkvXXu0mjf90!wr diff --git a/admin/templates/stylish/img/icons/page_white_delete.png b/admin/templates/stylish/img/icons/page_white_delete.png deleted file mode 100644 index af1ecaf2981fa37628c8b8b15ee389f9575e5f6b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 536 zcmV+z0_XjSP)(?iiXTHIMmcoLoO94I8;j@ zv^2DJ5#orqydFJX|Gm$_Bi_vyew+j6{r}$Qc@D1%fQqeAhJj)1!z4pP83k2MV2~s! zSt^w(<#HLFVBg_#xz1W8ioi(WY&Hu~6zil?DI^jJgu`K35(hkP)H%@Imesbg#5!Ps_$Ni*SiR8&sKb9?M`0-mH)gtg&YgRX#*TXz@Z+| z;|2H@xzE0TfuORhuO2k6#K8#sW^J`mQ0+E@$K`QkFV+DTlI$w{GJ;zid{*v9xeIe_ z$|Bp`@iKkgoFK3{4Z)#DWKV~W4K@5WZN+Ql_7%YxNqSx7%cWud&cX>)_PvD*UzxZg a%Kia9Rjz_59@~-t0000$>5Y&axjp2O=VLu>*f>1L;s0)kkvKC!*u?s6CVL=HJ6oP~pNfZc; zsKr=bq;7MITw8NXw{SZm%59TId2x_9BQ zV86`NuvGI!>o^V!Na!=$7GJE{Cq`b+XwknM{UcGHFTTfmuS+ zm-zYC!P3+zmY;SG$?!fYkOih`QYaLxyF}A86h$GGN}kFj)_o*0e zjPMP%zTG7FYMAfO2Nn1D`D0Cj?Wl>5q%@CE10nX)KxpNmwk+!IWkzywiYD( zqUXiYYIq3qcRyMGJ;IY`(Gz~E$J$zu2+R{)xGlE*88b3WK6V*J>}2iPY1HH|tER0W z_+^^FdppY?o)Gt5M2`%xwRDH@R3G}^i1l4|6uchm0X0f!@&YdVLB5K&dd7Rv{)DXX zt^&vP;}kqj3f>94j+4xd93>s|Q!Ezi>?r8(Il$P}PFxSqu{d*!Y%*#cX(R0f|Juz# z3o0_xI14Al->1uky@W-rCI_%l&>OOAS;jTeL{ZSdz-%)SMH9tDF;N4B6%j=d15J&5qy`F#vB?Ar zqS1nH@%ny_XSI*Y>) z1f5QYdmzT>YciP<3WehS<{GovEaLGv27>{*-7f0&I$yJ^L%ZGPv1YT$V|u;*+ZCWz ztHI~CDVsuy($SfR6-`N~K?9GTB#l%%0h7 z-q`K-y~E)+s8lMyTrPL8^_pUo)9G|SluG5pPqw6!LJB_PzyJUM07*qoM6N<$f^=yZ AYybcN diff --git a/admin/templates/stylish/img/icons/page_white_text_width.png b/admin/templates/stylish/img/icons/page_white_text_width.png deleted file mode 100644 index d9cf13256f44ae8092e07e88b0f4243a8efa9f0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 315 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^zbpD<_bdI{u9mbgZg z1m~xflqVLYGB~E>C#5QQ<|d}62BjvZR2H60wE-$R>*?YcqH(@;f-l!01CbW>s1Izr z3LkoHh<3E?TVANoG4CX|$empRCCS=R(U(hVJfm~E?IkDKRK&NP2|n`v>d(vV;W1uY zrFGVdwn;4b{qUtE`?GB`)E1ga&i2|7ncUL1b!KMq^QnT#_gn?_Z8(c`1Q~Vy3oL!N z$M8vHL&U1J3SJF!56azQU3B6>r|Zsm$HQ(N)Ek< zrc#vXMLdW}TWpphCZsGREkUZr{Mg;M&b;luZ0IGA9rnH1`DVU1->eh_0hG(-dw<@) z-1S-xc+D!@wd^?Z=a`M%%phe@J_EnT0QpH7V3 jcG~XA#&PRl)Zh6(yXt(^KFGF}00000NkvXXu0mjfDwr>g diff --git a/admin/templates/stylish/img/icons/report_link.png b/admin/templates/stylish/img/icons/report_link.png deleted file mode 100644 index 23f2611e993021b5c01f473fa2ef17e599680b1a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 754 zcmV8`o}o+HVTUg~@9%wnpXc-b-uGnzU`3-*UT|g@ zo0_}${PYS~EY{64<|1jn77mAt-?u~fu^oW-Nf+w%`k6u@8ja@M>gwvyr|A)Vn;(Jq zaTh9;N=r(m5{kuQGx>ZTM@L7;fK~%PHXd~T2WUVVDHIB*)oQH<8-@{t98zrD@5JHZ zAeQ1{U@q&rkwFmX$9#l+-MHA38*g7^?AM8Z6TBRY)Oa3%mOx}M#nz zh*gWh`lJ+JUrX?Dpo7v${ylY!X;i*V;Q5;bok6)={&T9q+Pw}sAOdJS3JE!pJUeO5 z<#Nbovqc8bb7C+dL2z~$YohjM^VqvRC>D|!olijSh(k8_3$j-~kxr+P$z)EM!ImFx zVLQBDFU)2$oK7cV9tr$gQX9rVLQxFP;kVqu3*=*2iwR9~I z2%y*NDMYDM7ETPbVvIfF!JwO<05UKhj|ZR6he#xXU@!=e#{({xOJ5@aFraFS!OXM) za*3D%bUGdS`uf1(a3B(iXvmt>8U|9SG*1mwD%GXs{;O~d^x$DXhboiPR#sMEx7(pm zD8THaYf^K&-E;=0BjsO4v diff --git a/admin/templates/stylish/img/icons/rss.png b/admin/templates/stylish/img/icons/rss.png deleted file mode 100644 index 1dc6ff30ba5020600aa4ba2646beb9eb25dc978f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 530 zcmV+t0`2{YP)8MDR)G%QU0LxY1jsDL`i z5Y)<<0mFa+Gyv?I-SF1`9OhtF)?#(7@ZwPg0IYohcf#rgRl*cR36-)JAyh$ycISTR z#|RJ*0Y`3-+O5RfdxRPJ@Fmbb_UtP8y?FXu?dZjo$& zzrG9Rp9<^S_%m{rBJa8vxT8 UVM82oKL7v#07*qoM6N<$f={^a^#A|> diff --git a/admin/templates/stylish/img/icons/user.png b/admin/templates/stylish/img/icons/user.png deleted file mode 100644 index 79f35ccbdad44489dbf07d1bf688c411aa3b612c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 741 zcmVz1iyEv%?$mbQ(# zwJpuiQJP8?X_`#S8b+U_G6=ziYB!xPAcq{)ZJ0bECH@ zYx#`n8^Wzn^J!4>=q^bltNO15ry?0ecSLkjpT@vlid!jk)Fjf7&)q_V5zGs#3N%6* zbW~7Hg=&P0&~Y(|g>$hC9FL?;ttzPDZbpZu9OLb33^e2;FNTGJxScp1&q4M+y2ntQ z?C(=hpU$3~`Thx0eHwi0x`q+!d5k@|0_WHe%sG3e-s^MM`xM-ig!VcIA7H}X1ot~L zg=MLB4w-Q;Bi!!u2|I+Qb;0{{4Q53YX6+4_aXena{nmt*!YG7ua~`qc>o=?@U?rOU znS7%>klzi*muXnbM6i@4FR@s^8vTjDgy&%J?w?`u>NYMDFa_2%0SQ(qJE<3=<8Bzo zfdU60e*y(^$RF%r$kl)p7=7tlCDa$+J7w>}DU(O#~fk>pYuRvHi1E9^msg{tLeV XM&GIRvfA7%00000NkvXXu0mjf&%8>| diff --git a/admin/templates/stylish/img/icons/user_add.png b/admin/templates/stylish/img/icons/user_add.png deleted file mode 100644 index deae99bcff9815d8530a920e754d743700ddd5fb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 746 zcmVR5;6} zkbg*1Q547RkCGx=+ZrJV#zL@SQK$qJV#CSW)Px1IG~1R7@Ce7&_JfOHMV?!rlp(uU_DLu%oT329{ zvd}^m>Zu}~l!lF)$vj*+!9ivWYi3=6E`B>+7|Su$tH+R~2!#ne6eorwU&M#{7<<90 zO$iMuFlR;n2z>v9nKwp!?XQQ|aSfBtZ^J)10wQ zP}rH=KSJQ4N-!Ms3A?4X%~8iSR-zylzlSXd_?|M%f3%_Vax4V#xlec^^VT&5JP8rX z6}RO@h&}Lqo`s_<751_e20DK|@e2`2FToK$y2KTlwyhFyPdYY*B{>w4$%B}fnn&9d zQ0xQp-T@b00q1)Ft+NxwMg`RMry#!}42Vk(RW1t-$ePmK0V@&mp4&IBO>%w~~-qNFem8*NKi5C3*h;eH{=}2kRqEdNlF-|c6B{jNg1xE|{xZ_qq=T!wMF|0iq|AK>&MHw6~-ksQ9RtH+=$?!G=zinz|BNIO*d}XYdmm2K>Qw%i9j?X9SgRBJn4W5%uAclWG_T7f?M4s9q5$`w5b| z31S}-Tq~-?NahjDw3mU5cfqF5z)+g+pPplGDyLv1f8WAnTQ+Xiw;{fhcBLH^j|gI# z2~IT;7{m9#PQ$2>16f?4#0x*vLFksSJ~;)W1wO>uQ-rAG1{C+&5Zw%%))Pc(2_k9< z`smoi)Pkk!SK)SAcOy>0d#x(Rl;b_GP?XFE#P>r%M^9Kn>j@#I>kHsrS$qYvKE>lwZZUsXcw4nFNHZZ~?%71a&2u7&aV|47ZvJKBUVO{)!ekB`ACp}1 xSnjsa#jtYM{A~v!cV^R$X2;lcpKyd7^}lwPp>~q=QF{OY002ovPDHLkV1lJ{Vb%Zu diff --git a/admin/templates/stylish/img/icons/user_edit.png b/admin/templates/stylish/img/icons/user_edit.png deleted file mode 100644 index c1974cda745278a404b9e29fa91e0503a84accb1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 833 zcmV-H1HSx;P)wKwNApj*j?`*x8fjj}+T^cdNV;=~VOf{An4CI`(Q%x}`$a=uBQ`IcOG~+O zhFmpv$jQAVt#pVn<-FwXyxzC#)@;^BTYr4EXV3Qe?Ah}?KRp0?|HEG!QT7K}`6R>T z0?GlfNd&N5h)SxRamGIduGtwfO1+4h$^b)DXu0o8M7BEtF^>B+6kDUTT?1tl0&27( zTPtN#enUj2hcV)v4ROVeu()d=+i@S-%91h3XQQ_&2GLH&h;==J>*q}oafY~7o8YOx zW1up~WKKQv35z{tnCiF(G50p)FLR-gi@=FATO4h+zckVifX~k}G4#+4;u7niZGj@H zRkx!55oQOPpc>+6Y1FM1A`bW&7GI~k7+8?J0DewkUh)LOJkrdTe3;U(*Zgc$Er)&@ zD+5(f%bInl-ZwzNw#9d8%I4~~7EHgs3zhUKHpaRkt%*?UWMg-Zz7eUOc8t^s*~Buq zNnU77^3>6u=K_U{g-umARHHXA*H6dCx-dv81Ap`v`JB`FJi0MFsY3lE z5Gw;{eLz-+019a$Hq}BXzXU@)LB-NA6Y>hD8BxCLDcvPn`&N6q`mxc}yMb~sKo@Ed zDbOI5^9}?Dhz0FQMoKPVwk00IILo!IfS6^eQMBJdKtv5PI+Tbj;^0Fo6JmY=Cj0!M zlv6P`lmJPo4+6tWG2fYveukB1DzkD{lX z41Nw7E`C*@hclIfDYh$GCw<#Tk~h)}QkWS=$Gv&wY2h|l6&7Q)uMmBi&Zxg?1_yGk z;>5+4_M6eEhsL=ygB_>Q-+`#k4z^f-l|x?d%y)UiW7wGPG|s;O<A9)b<7tX~vT z$e)FfZ+`X4_uKyq#wJHC;J3lH{lhQkUc~Wid;*pnjhM12xe-bPByd^xuQ9zgeM^Mm z*tc)|P}LtTnHXr@Gkmmbkg^O2bqyhO>LP|qjIwW2@Di+4EuKm~&tOO2!N3o{128Hl z9v%fgerM0C#)7P|PMvxr*!Gf?eGA8f{OT6fS`9l>LQCg)p=~c$Zr|AT_0+_?F*JJk zlapOT2Q(wWx-LMq(TxXxLn+U;!LV)MhNp~ommdh+fo8T*&g-yQbbG&ze&=>tC(Ar=&^1xlA;Jc(6 zcCi_xs8k}-S&#ONOHm%e@#nGC7F++8C~r29Or!_{(QGQEG)+O^J1BCPmgM4JAzC8I z`jS9bO>|}Jq_#$IRzp0d34>)&3L%7MN)eTv!0B!^nn}f4z2*vFE@jv3dn zG>H)u>FR7_d2JcsjvfZ$vkP~xik@T^(_N)nx=tqJV+tQjQ`owJ83bf`zX6Ear*=Mhzn5QUuXE|v zR33Qyi8G!0{H2r##d#6R6YmYbZz4NTssT;cXiGb6lxO+k@{ba@2D~*hKDY6N;Bkh> xhhCRLejsJkAIT{5sICHcfU`5>bKmUb{{y)0nR3PMMxX!y002ovPDHLkV1nl+t-}BS diff --git a/admin/templates/stylish/psd/template.psd b/admin/templates/stylish/psd/template.psd deleted file mode 100644 index d9004ae87dfabffa963c854f000ffc1a7ec8b80e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 967624 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�$TxF0b2oE0b2oE0b2oE0b9XWZ7blc!smH^ zzkSAj)tuq^kmMveTLD`ETLD`ETLD`ETLD`ETLD`ETS06qFh9)D$Ff@5exsparD-Uc zJY(ijev z{)k~PM+{#Gfz7QQ`XB%S2tWV=UmXG*Gi>Xbf-my%UmY)aCJ=xC1R(I0AYhx{WOU?r z8DlNYNn7cI3%)1;oKPa<1Ww?D64*8;E?XU3U%>pDbmA{czYy%dV@qa)dk;MDV<+1h z%yktm+t~4wXfFg;TxbrixM(C=TdB;0=BV+bT(Wo9SyBfK_F>^eE_ zr}Fyfmn#Utr(HgDwjbe@nqpUNaz7FN^vm_E;M2~}@VZ{HYkavM3m^LB>Syq2=TCSQ zxY!lp+>eA0{c^25__XsUyk=nR`hl(|eCU@eE5heX^(VYuW$fCO?uWvkez~eAeA@ZB zL;K;slEf>t#-^K-w$cX|d{F{8p+v|DoWKbsfD=lDoWKd3Py#riM92x8zzHRQ6H0`f zzzLjC0yv>W$O)Xl2_=9NN`#!i37k*@IH5$y37o(QC4du3gq*+$oKONdp+v|DoWKbs zfD=lDoWKd3Py#riM92x8zzHRQ6H0`fzzLjC0yv>W$O)Xl2_=9NN`#!i37k*@IH5$y z37o(QC4du3gq*+$oKONdp+v|DoWKbsfD=lDoWKd3Py#riM92x8zzHRQ6H0`fz=@sO ziDJ9hG53yjbJEt>IQn3w1aLx$u&v+(PACDKP$H@3#AU_7HDM>%6C87o)$W8Bg8g@l zDkI?WGJX{AWLv`r_6L`JkmQ=DA2_C`+1%-ekJs^)5$P z`jh}%lt|1PxWGjT;Di!kTfqsOPy#riM92x8zzHRQ6H0`fzzLjC0yv>W$O)Xl2_=9N zN`#!i37k*@IH5$y37o(QC4du3gq*+$oKONdp+v|DoWKbsfD=lDoWKd3Py#riM92x8 zzzHRQ6H0`fzzLjC0yv>W$O)Xl2_=9NN`#!i37k*@IH5$y37o(QC4du3gq*+$oKONd zp+v|DoWKbsfD=lDoWKd3Py#riM92x8zzHRQ6H0`fzzLjC0yv>W$cY`ui7Y$IG53yj zbJEt>IQn3w1aLx$u&v+(PACDKP$H@3#AR8*bz!^N-5hg|)o!;Jg8g@lDkI?WGJa(3 zWLv{Jd);O0l3W*donv~M&7J-)fKSKkVz%c?zg|~$$KuoRx}xo$KmB^$(Jz-z$Ln^s z|NHdobv-{HpN`kPZ2x%r^}3j!k59+zO16JI{d(QW_Ix^Cmy!O&%-W6eq0R_vGqlmJ|mNX#0zz(on*gc4y}!3msD0yv>W$O)Xl2_=9NN`#!i z37k*@IH5$y37o(QC4du3gq*+$oKONdp+v|DoWKbsfD=lDoWKd3Py#riM92x8zzHRQ z6H0`fzzLjC0yv>W$O)Xl2_=9NN`#!i37k*@IH5$y37o(QC4du3gq*+$oKONdp+v|D zoWKbsfD=lDoWKd3Py#riM92x8zzHRQ6H0`fzzLjC0yv>W$O)Xl2_=9NN`#!i37k*@ MIH5$yiRN|x4=&Kw#sB~S diff --git a/admin/templates/stylish/template.php b/admin/templates/stylish/template.php deleted file mode 100644 index a064b847..00000000 --- a/admin/templates/stylish/template.php +++ /dev/null @@ -1,296 +0,0 @@ - - - - - - <?php echo $title . $config['title_separator'] . $config['lua']['serverName']; ?> - Powered by MyAAC - - - - - - - -
- - -
-
-
-

- Right Now - Add New Product - Some Action -
-

-

You have 19 new orders, 12 new users and 5 new reviews, today you made $1523.63 in sales and a total of $328.24 profit -

-
-
-
-

Sales for July

-

-
-
-

Traffic for July

-

a

-
-
-

Last 5 Orders

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CustomerItemsGrand Total
Jennifer Kyrnin114.95 €
Mark Kyrnin234.27 €
Virgílio Cezar261.39 €
Todd Simonides51472.56 €
Carol Elihu19.95 €
-
-
-

Bestsellers

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Product NamePriceOrders
Apple iPhone 3G 8GB199.00 €24
Fuji FinePix S5800365.24 €19
Canon PIXMA MP14059.50 €12
Apple iPhone 3G 16GB199.00 €10
Prenosnik HP 530 1,6GHz499.00 €6
-
-
-

New Customers

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CustomerOrdersAverageTotal
Jennifer Kyrnin15.6€14.95 €
Mark Kyrnin214.97€34.27 €
Virgílio Cezar215.31€61.39 €
Todd Simonides5502.61€1472.56 €
Carol Elihu15.1€9.95 €
-
-
-

Last 5 Reviews

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ReviewerProductAction
Jennifer KyrninApple iPhone 3G 8GB
Mark KyrninPrenosnik HP 530 1,6GHz
Virgílio CezarFuji FinePix S5800
Todd SimonidesCanon PIXMA MP140
Carol ElihuPrenosnik HP 530 1,6GHz
-
-
-
- -
- -
- - diff --git a/admin/templates/stylish/users.html b/admin/templates/stylish/users.html deleted file mode 100644 index 30694291..00000000 --- a/admin/templates/stylish/users.html +++ /dev/null @@ -1,309 +0,0 @@ - - - - -Users - Admin Template - - - - - - - -
- - -
-
-
-

Users

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
IDFull NameEmailGroupZIPRegisteredAction
232Jennifer Hodesjennifer.hodes@gmail.comGeneral1000July 2, 2008
231Mark Kyrninmark.kyrnin@hotmail.comAffiliate8310June 17, 2008
230Virgílio Cezarvirgilio@somecompany.czGeneral6200June 31, 2008
229Todd Simonidestodd.simonides@gmail.comWholesale2010June 5, 2008
228Carol Elihucarol@herbusiness.comGeneral3120May 23, 2008
232Jennifer Hodesjennifer.hodes@gmail.comGeneral1000July 2, 2008
231Mark Kyrninmark.kyrnin@hotmail.comAffiliate8310June 17, 2008
230Virgílio Cezarvirgilio@somecompany.czGeneral6200June 31, 2008
229Todd Simonidestodd.simonides@gmail.comWholesale2010June 5, 2008
228Carol Elihucarol@herbusiness.comGeneral3120May 23, 2008
-
- Page - - of 42 - pages | View - per page | Total 420 records found -
-
-
-
-

Add user

-
-
- PERSONAL INFORMATION - - -
- - -
- - -
-

Send auto generated password -

- - -
- - -
-
-
- Address - - -
- - -
- - -
- - -
- - -
- - -
-
- OPTIONS - - -
-
- - -
-
- -
-
- -
- -
- - diff --git a/install/steps/requirements.php b/install/steps/requirements.php index 3669b1c9..a5864188 100644 --- a/install/steps/requirements.php +++ b/install/steps/requirements.php @@ -22,7 +22,7 @@ function version_check($name, $ok, $info = '', $warning = false) $failed = false; // start validating -version_check($locale['step_requirements_php_version'], (PHP_VERSION_ID >= 50000), PHP_VERSION); +version_check($locale['step_requirements_php_version'], (PHP_VERSION_ID >= 50102), PHP_VERSION); foreach(array('config.local.php', 'images/guilds', 'images/houses', 'images/screenshots') as $value) { $perms = (int) substr(decoct(fileperms(BASE . $value)), 2); diff --git a/system/cache/twig/.htaccess b/system/cache/twig/.htaccess new file mode 100644 index 00000000..3418e55a --- /dev/null +++ b/system/cache/twig/.htaccess @@ -0,0 +1 @@ +deny from all \ No newline at end of file diff --git a/system/init.php b/system/init.php index b6add809..6b2436ec 100644 --- a/system/init.php +++ b/system/init.php @@ -26,6 +26,15 @@ if($config['gzip_output'] && (strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') ! require_once(SYSTEM . 'libs/cache.php'); $cache = Cache::getInstance($config['cache_engine'], $config['cache_prefix']); +// twig +require_once LIBS . 'twig/Autoloader.php'; +Twig_Autoloader::register(); + +$loader = new Twig_Loader_Filesystem(SYSTEM . 'templates'); +$twig = new Twig_Environment($loader, array( + 'cache' => CACHE . 'twig/', +)); + // trim values we receive if(isset($_POST)) { diff --git a/system/libs/twig/Autoloader.php b/system/libs/twig/Autoloader.php old mode 100644 new mode 100755 index be622337..87f74153 --- a/system/libs/twig/Autoloader.php +++ b/system/libs/twig/Autoloader.php @@ -1,4 +1,5 @@ + */ +abstract class Twig_BaseNodeVisitor implements Twig_NodeVisitorInterface +{ + /** + * {@inheritdoc} + */ + final public function enterNode(Twig_NodeInterface $node, Twig_Environment $env) + { + if (!$node instanceof Twig_Node) { + throw new LogicException('Twig_BaseNodeVisitor only supports Twig_Node instances.'); + } + + return $this->doEnterNode($node, $env); + } + + /** + * {@inheritdoc} + */ + final public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env) + { + if (!$node instanceof Twig_Node) { + throw new LogicException('Twig_BaseNodeVisitor only supports Twig_Node instances.'); + } + + return $this->doLeaveNode($node, $env); + } + + /** + * Called before child nodes are visited. + * + * @param Twig_Node $node The node to visit + * @param Twig_Environment $env The Twig environment instance + * + * @return Twig_Node The modified node + */ + abstract protected function doEnterNode(Twig_Node $node, Twig_Environment $env); + + /** + * Called after child nodes are visited. + * + * @param Twig_Node $node The node to visit + * @param Twig_Environment $env The Twig environment instance + * + * @return Twig_Node|false The modified node or false if the node must be removed + */ + abstract protected function doLeaveNode(Twig_Node $node, Twig_Environment $env); +} diff --git a/system/libs/twig/Cache/CacheInterface.php b/system/libs/twig/Cache/CacheInterface.php deleted file mode 100755 index 2e35e3ba..00000000 --- a/system/libs/twig/Cache/CacheInterface.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Compiler implements Twig_CompilerInterface +{ + protected $lastLine; + protected $source; + protected $indentation; + protected $env; + protected $debugInfo; + protected $sourceOffset; + protected $sourceLine; + protected $filename; -if (\false) { - class Compiler extends \Twig_Compiler + /** + * Constructor. + * + * @param Twig_Environment $env The twig environment instance + */ + public function __construct(Twig_Environment $env) { + $this->env = $env; + $this->debugInfo = array(); + } + + public function getFilename() + { + return $this->filename; + } + + /** + * Returns the environment instance related to this compiler. + * + * @return Twig_Environment The environment instance + */ + public function getEnvironment() + { + return $this->env; + } + + /** + * Gets the current PHP code after compilation. + * + * @return string The PHP code + */ + public function getSource() + { + return $this->source; + } + + /** + * Compiles a node. + * + * @param Twig_NodeInterface $node The node to compile + * @param int $indentation The current indentation + * + * @return Twig_Compiler The current compiler instance + */ + public function compile(Twig_NodeInterface $node, $indentation = 0) + { + $this->lastLine = null; + $this->source = ''; + $this->debugInfo = array(); + $this->sourceOffset = 0; + // source code starts at 1 (as we then increment it when we encounter new lines) + $this->sourceLine = 1; + $this->indentation = $indentation; + + if ($node instanceof Twig_Node_Module) { + $this->filename = $node->getAttribute('filename'); + } + + $node->compile($this); + + return $this; + } + + public function subcompile(Twig_NodeInterface $node, $raw = true) + { + if (false === $raw) { + $this->addIndentation(); + } + + $node->compile($this); + + return $this; + } + + /** + * Adds a raw string to the compiled code. + * + * @param string $string The string + * + * @return Twig_Compiler The current compiler instance + */ + public function raw($string) + { + $this->source .= $string; + + return $this; + } + + /** + * Writes a string to the compiled code by adding indentation. + * + * @return Twig_Compiler The current compiler instance + */ + public function write() + { + $strings = func_get_args(); + foreach ($strings as $string) { + $this->addIndentation(); + $this->source .= $string; + } + + return $this; + } + + /** + * Appends an indentation to the current PHP code after compilation. + * + * @return Twig_Compiler The current compiler instance + */ + public function addIndentation() + { + $this->source .= str_repeat(' ', $this->indentation * 4); + + return $this; + } + + /** + * Adds a quoted string to the compiled code. + * + * @param string $value The string + * + * @return Twig_Compiler The current compiler instance + */ + public function string($value) + { + $this->source .= sprintf('"%s"', addcslashes($value, "\0\t\"\$\\")); + + return $this; + } + + /** + * Returns a PHP representation of a given value. + * + * @param mixed $value The value to convert + * + * @return Twig_Compiler The current compiler instance + */ + public function repr($value) + { + if (is_int($value) || is_float($value)) { + if (false !== $locale = setlocale(LC_NUMERIC, 0)) { + setlocale(LC_NUMERIC, 'C'); + } + + $this->raw($value); + + if (false !== $locale) { + setlocale(LC_NUMERIC, $locale); + } + } elseif (null === $value) { + $this->raw('null'); + } elseif (is_bool($value)) { + $this->raw($value ? 'true' : 'false'); + } elseif (is_array($value)) { + $this->raw('array('); + $first = true; + foreach ($value as $key => $v) { + if (!$first) { + $this->raw(', '); + } + $first = false; + $this->repr($key); + $this->raw(' => '); + $this->repr($v); + } + $this->raw(')'); + } else { + $this->string($value); + } + + return $this; + } + + /** + * Adds debugging information. + * + * @param Twig_NodeInterface $node The related twig node + * + * @return Twig_Compiler The current compiler instance + */ + public function addDebugInfo(Twig_NodeInterface $node) + { + if ($node->getLine() != $this->lastLine) { + $this->write(sprintf("// line %d\n", $node->getLine())); + + // when mbstring.func_overload is set to 2 + // mb_substr_count() replaces substr_count() + // but they have different signatures! + if (((int) ini_get('mbstring.func_overload')) & 2) { + // this is much slower than the "right" version + $this->sourceLine += mb_substr_count(mb_substr($this->source, $this->sourceOffset), "\n"); + } else { + $this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset); + } + $this->sourceOffset = strlen($this->source); + $this->debugInfo[$this->sourceLine] = $node->getLine(); + + $this->lastLine = $node->getLine(); + } + + return $this; + } + + public function getDebugInfo() + { + ksort($this->debugInfo); + + return $this->debugInfo; + } + + /** + * Indents the generated code. + * + * @param int $step The number of indentation to add + * + * @return Twig_Compiler The current compiler instance + */ + public function indent($step = 1) + { + $this->indentation += $step; + + return $this; + } + + /** + * Outdents the generated code. + * + * @param int $step The number of indentation to remove + * + * @return Twig_Compiler The current compiler instance + * + * @throws LogicException When trying to outdent too much so the indentation would become negative + */ + public function outdent($step = 1) + { + // can't outdent by more steps than the current indentation level + if ($this->indentation < $step) { + throw new LogicException('Unable to call outdent() as the indentation would become negative'); + } + + $this->indentation -= $step; + + return $this; + } + + public function getVarName() + { + return sprintf('__internal_%s', hash('sha256', uniqid(mt_rand(), true), false)); } } diff --git a/system/libs/twig/CompilerInterface.php b/system/libs/twig/CompilerInterface.php new file mode 100755 index 00000000..272c7672 --- /dev/null +++ b/system/libs/twig/CompilerInterface.php @@ -0,0 +1,36 @@ + + * + * @deprecated since 1.12 (to be removed in 3.0) + */ +interface Twig_CompilerInterface +{ + /** + * Compiles a node. + * + * @param Twig_NodeInterface $node The node to compile + * + * @return Twig_CompilerInterface The current compiler instance + */ + public function compile(Twig_NodeInterface $node); + + /** + * Gets the current PHP code after compilation. + * + * @return string The PHP code + */ + public function getSource(); +} diff --git a/system/libs/twig/Environment.php b/system/libs/twig/Environment.php index e0f9edcd..3ac91242 100755 --- a/system/libs/twig/Environment.php +++ b/system/libs/twig/Environment.php @@ -1,11 +1,1294 @@ + */ +class Twig_Environment +{ + const VERSION = '1.20.0'; -if (\false) { - class Environment extends \Twig_Environment + protected $charset; + protected $loader; + protected $debug; + protected $autoReload; + protected $cache; + protected $lexer; + protected $parser; + protected $compiler; + protected $baseTemplateClass; + protected $extensions; + protected $parsers; + protected $visitors; + protected $filters; + protected $tests; + protected $functions; + protected $globals; + protected $runtimeInitialized; + protected $extensionInitialized; + protected $loadedTemplates; + protected $strictVariables; + protected $unaryOperators; + protected $binaryOperators; + protected $templateClassPrefix = '__TwigTemplate_'; + protected $functionCallbacks; + protected $filterCallbacks; + protected $staging; + + /** + * Constructor. + * + * Available options: + * + * * debug: When set to true, it automatically set "auto_reload" to true as + * well (default to false). + * + * * charset: The charset used by the templates (default to UTF-8). + * + * * base_template_class: The base template class to use for generated + * templates (default to Twig_Template). + * + * * cache: An absolute path where to store the compiled templates, or + * false to disable compilation cache (default). + * + * * auto_reload: Whether to reload the template if the original source changed. + * If you don't provide the auto_reload option, it will be + * determined automatically based on the debug value. + * + * * strict_variables: Whether to ignore invalid variables in templates + * (default to false). + * + * * autoescape: Whether to enable auto-escaping (default to html): + * * false: disable auto-escaping + * * true: equivalent to html + * * html, js: set the autoescaping to one of the supported strategies + * * filename: set the autoescaping strategy based on the template filename extension + * * PHP callback: a PHP callback that returns an escaping strategy based on the template "filename" + * + * * optimizations: A flag that indicates which optimizations to apply + * (default to -1 which means that all optimizations are enabled; + * set it to 0 to disable). + * + * @param Twig_LoaderInterface $loader A Twig_LoaderInterface instance + * @param array $options An array of options + */ + public function __construct(Twig_LoaderInterface $loader = null, $options = array()) { + if (null !== $loader) { + $this->setLoader($loader); + } + + $options = array_merge(array( + 'debug' => false, + 'charset' => 'UTF-8', + 'base_template_class' => 'Twig_Template', + 'strict_variables' => false, + 'autoescape' => 'html', + 'cache' => false, + 'auto_reload' => null, + 'optimizations' => -1, + ), $options); + + $this->debug = (bool) $options['debug']; + $this->charset = strtoupper($options['charset']); + $this->baseTemplateClass = $options['base_template_class']; + $this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload']; + $this->strictVariables = (bool) $options['strict_variables']; + $this->runtimeInitialized = false; + $this->setCache($options['cache']); + $this->functionCallbacks = array(); + $this->filterCallbacks = array(); + + $this->addExtension(new Twig_Extension_Core()); + $this->addExtension(new Twig_Extension_Escaper($options['autoescape'])); + $this->addExtension(new Twig_Extension_Optimizer($options['optimizations'])); + $this->extensionInitialized = false; + $this->staging = new Twig_Extension_Staging(); + } + + /** + * Gets the base template class for compiled templates. + * + * @return string The base template class name + */ + public function getBaseTemplateClass() + { + return $this->baseTemplateClass; + } + + /** + * Sets the base template class for compiled templates. + * + * @param string $class The base template class name + */ + public function setBaseTemplateClass($class) + { + $this->baseTemplateClass = $class; + } + + /** + * Enables debugging mode. + */ + public function enableDebug() + { + $this->debug = true; + } + + /** + * Disables debugging mode. + */ + public function disableDebug() + { + $this->debug = false; + } + + /** + * Checks if debug mode is enabled. + * + * @return bool true if debug mode is enabled, false otherwise + */ + public function isDebug() + { + return $this->debug; + } + + /** + * Enables the auto_reload option. + */ + public function enableAutoReload() + { + $this->autoReload = true; + } + + /** + * Disables the auto_reload option. + */ + public function disableAutoReload() + { + $this->autoReload = false; + } + + /** + * Checks if the auto_reload option is enabled. + * + * @return bool true if auto_reload is enabled, false otherwise + */ + public function isAutoReload() + { + return $this->autoReload; + } + + /** + * Enables the strict_variables option. + */ + public function enableStrictVariables() + { + $this->strictVariables = true; + } + + /** + * Disables the strict_variables option. + */ + public function disableStrictVariables() + { + $this->strictVariables = false; + } + + /** + * Checks if the strict_variables option is enabled. + * + * @return bool true if strict_variables is enabled, false otherwise + */ + public function isStrictVariables() + { + return $this->strictVariables; + } + + /** + * Gets the cache directory or false if cache is disabled. + * + * @return string|false + */ + public function getCache() + { + return $this->cache; + } + + /** + * Sets the cache directory or false if cache is disabled. + * + * @param string|false $cache The absolute path to the compiled templates, + * or false to disable cache + */ + public function setCache($cache) + { + $this->cache = $cache ? $cache : false; + } + + /** + * Gets the cache filename for a given template. + * + * @param string $name The template name + * + * @return string|false The cache file name or false when caching is disabled + */ + public function getCacheFilename($name) + { + if (false === $this->cache) { + return false; + } + + $class = substr($this->getTemplateClass($name), strlen($this->templateClassPrefix)); + + return $this->getCache().'/'.$class[0].'/'.$class[1].'/'.$class.'.php'; + } + + /** + * Gets the template class associated with the given string. + * + * @param string $name The name for which to calculate the template class name + * @param int $index The index if it is an embedded template + * + * @return string The template class name + */ + public function getTemplateClass($name, $index = null) + { + return $this->templateClassPrefix.hash('sha256', $this->getLoader()->getCacheKey($name)).(null === $index ? '' : '_'.$index); + } + + /** + * Gets the template class prefix. + * + * @return string The template class prefix + */ + public function getTemplateClassPrefix() + { + return $this->templateClassPrefix; + } + + /** + * Renders a template. + * + * @param string $name The template name + * @param array $context An array of parameters to pass to the template + * + * @return string The rendered template + * + * @throws Twig_Error_Loader When the template cannot be found + * @throws Twig_Error_Syntax When an error occurred during compilation + * @throws Twig_Error_Runtime When an error occurred during rendering + */ + public function render($name, array $context = array()) + { + return $this->loadTemplate($name)->render($context); + } + + /** + * Displays a template. + * + * @param string $name The template name + * @param array $context An array of parameters to pass to the template + * + * @throws Twig_Error_Loader When the template cannot be found + * @throws Twig_Error_Syntax When an error occurred during compilation + * @throws Twig_Error_Runtime When an error occurred during rendering + */ + public function display($name, array $context = array()) + { + $this->loadTemplate($name)->display($context); + } + + /** + * Loads a template by name. + * + * @param string $name The template name + * @param int $index The index if it is an embedded template + * + * @return Twig_TemplateInterface A template instance representing the given template name + * + * @throws Twig_Error_Loader When the template cannot be found + * @throws Twig_Error_Syntax When an error occurred during compilation + */ + public function loadTemplate($name, $index = null) + { + $cls = $this->getTemplateClass($name, $index); + + if (isset($this->loadedTemplates[$cls])) { + return $this->loadedTemplates[$cls]; + } + + if (!class_exists($cls, false)) { + if (false === $cache = $this->getCacheFilename($name)) { + eval('?>'.$this->compileSource($this->getLoader()->getSource($name), $name)); + } else { + if (!is_file($cache) || ($this->isAutoReload() && !$this->isTemplateFresh($name, filemtime($cache)))) { + $this->writeCacheFile($cache, $this->compileSource($this->getLoader()->getSource($name), $name)); + } + + require_once $cache; + } + } + + if (!$this->runtimeInitialized) { + $this->initRuntime(); + } + + return $this->loadedTemplates[$cls] = new $cls($this); + } + + /** + * Creates a template from source. + * + * This method should not be used as a generic way to load templates. + * + * @param string $template The template name + * + * @return Twig_Template A template instance representing the given template name + * + * @throws Twig_Error_Loader When the template cannot be found + * @throws Twig_Error_Syntax When an error occurred during compilation + */ + public function createTemplate($template) + { + $name = sprintf('__string_template__%s', hash('sha256', uniqid(mt_rand(), true), false)); + + $loader = new Twig_Loader_Chain(array( + new Twig_Loader_Array(array($name => $template)), + $current = $this->getLoader(), + )); + + $this->setLoader($loader); + try { + $template = $this->loadTemplate($name); + } catch (Exception $e) { + $this->setLoader($current); + + throw $e; + } + $this->setLoader($current); + + return $template; + } + + /** + * Returns true if the template is still fresh. + * + * Besides checking the loader for freshness information, + * this method also checks if the enabled extensions have + * not changed. + * + * @param string $name The template name + * @param int $time The last modification time of the cached template + * + * @return bool true if the template is fresh, false otherwise + */ + public function isTemplateFresh($name, $time) + { + foreach ($this->extensions as $extension) { + $r = new ReflectionObject($extension); + if (filemtime($r->getFileName()) > $time) { + return false; + } + } + + return $this->getLoader()->isFresh($name, $time); + } + + /** + * Tries to load a template consecutively from an array. + * + * Similar to loadTemplate() but it also accepts Twig_TemplateInterface instances and an array + * of templates where each is tried to be loaded. + * + * @param string|Twig_Template|array $names A template or an array of templates to try consecutively + * + * @return Twig_Template + * + * @throws Twig_Error_Loader When none of the templates can be found + * @throws Twig_Error_Syntax When an error occurred during compilation + */ + public function resolveTemplate($names) + { + if (!is_array($names)) { + $names = array($names); + } + + foreach ($names as $name) { + if ($name instanceof Twig_Template) { + return $name; + } + + try { + return $this->loadTemplate($name); + } catch (Twig_Error_Loader $e) { + } + } + + if (1 === count($names)) { + throw $e; + } + + throw new Twig_Error_Loader(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names))); + } + + /** + * Clears the internal template cache. + * + * @deprecated since 1.18.3 (to be removed in 2.0) + */ + public function clearTemplateCache() + { + $this->loadedTemplates = array(); + } + + /** + * Clears the template cache files on the filesystem. + */ + public function clearCacheFiles() + { + if (false === $this->cache) { + return; + } + + foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->cache), RecursiveIteratorIterator::LEAVES_ONLY) as $file) { + if ($file->isFile()) { + @unlink($file->getPathname()); + } + } + } + + /** + * Gets the Lexer instance. + * + * @return Twig_LexerInterface A Twig_LexerInterface instance + */ + public function getLexer() + { + if (null === $this->lexer) { + $this->lexer = new Twig_Lexer($this); + } + + return $this->lexer; + } + + /** + * Sets the Lexer instance. + * + * @param Twig_LexerInterface $lexer A Twig_LexerInterface instance + */ + public function setLexer(Twig_LexerInterface $lexer) + { + $this->lexer = $lexer; + } + + /** + * Tokenizes a source code. + * + * @param string $source The template source code + * @param string $name The template name + * + * @return Twig_TokenStream A Twig_TokenStream instance + * + * @throws Twig_Error_Syntax When the code is syntactically wrong + */ + public function tokenize($source, $name = null) + { + return $this->getLexer()->tokenize($source, $name); + } + + /** + * Gets the Parser instance. + * + * @return Twig_ParserInterface A Twig_ParserInterface instance + */ + public function getParser() + { + if (null === $this->parser) { + $this->parser = new Twig_Parser($this); + } + + return $this->parser; + } + + /** + * Sets the Parser instance. + * + * @param Twig_ParserInterface $parser A Twig_ParserInterface instance + */ + public function setParser(Twig_ParserInterface $parser) + { + $this->parser = $parser; + } + + /** + * Converts a token stream to a node tree. + * + * @param Twig_TokenStream $stream A token stream instance + * + * @return Twig_Node_Module A node tree + * + * @throws Twig_Error_Syntax When the token stream is syntactically or semantically wrong + */ + public function parse(Twig_TokenStream $stream) + { + return $this->getParser()->parse($stream); + } + + /** + * Gets the Compiler instance. + * + * @return Twig_CompilerInterface A Twig_CompilerInterface instance + */ + public function getCompiler() + { + if (null === $this->compiler) { + $this->compiler = new Twig_Compiler($this); + } + + return $this->compiler; + } + + /** + * Sets the Compiler instance. + * + * @param Twig_CompilerInterface $compiler A Twig_CompilerInterface instance + */ + public function setCompiler(Twig_CompilerInterface $compiler) + { + $this->compiler = $compiler; + } + + /** + * Compiles a node and returns the PHP code. + * + * @param Twig_NodeInterface $node A Twig_NodeInterface instance + * + * @return string The compiled PHP source code + */ + public function compile(Twig_NodeInterface $node) + { + return $this->getCompiler()->compile($node)->getSource(); + } + + /** + * Compiles a template source code. + * + * @param string $source The template source code + * @param string $name The template name + * + * @return string The compiled PHP source code + * + * @throws Twig_Error_Syntax When there was an error during tokenizing, parsing or compiling + */ + public function compileSource($source, $name = null) + { + try { + return $this->compile($this->parse($this->tokenize($source, $name))); + } catch (Twig_Error $e) { + $e->setTemplateFile($name); + throw $e; + } catch (Exception $e) { + throw new Twig_Error_Syntax(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $name, $e); + } + } + + /** + * Sets the Loader instance. + * + * @param Twig_LoaderInterface $loader A Twig_LoaderInterface instance + */ + public function setLoader(Twig_LoaderInterface $loader) + { + $this->loader = $loader; + } + + /** + * Gets the Loader instance. + * + * @return Twig_LoaderInterface A Twig_LoaderInterface instance + */ + public function getLoader() + { + if (null === $this->loader) { + throw new LogicException('You must set a loader first.'); + } + + return $this->loader; + } + + /** + * Sets the default template charset. + * + * @param string $charset The default charset + */ + public function setCharset($charset) + { + $this->charset = strtoupper($charset); + } + + /** + * Gets the default template charset. + * + * @return string The default charset + */ + public function getCharset() + { + return $this->charset; + } + + /** + * Initializes the runtime environment. + */ + public function initRuntime() + { + $this->runtimeInitialized = true; + + foreach ($this->getExtensions() as $extension) { + $extension->initRuntime($this); + } + } + + /** + * Returns true if the given extension is registered. + * + * @param string $name The extension name + * + * @return bool Whether the extension is registered or not + */ + public function hasExtension($name) + { + return isset($this->extensions[$name]); + } + + /** + * Gets an extension by name. + * + * @param string $name The extension name + * + * @return Twig_ExtensionInterface A Twig_ExtensionInterface instance + */ + public function getExtension($name) + { + if (!isset($this->extensions[$name])) { + throw new Twig_Error_Runtime(sprintf('The "%s" extension is not enabled.', $name)); + } + + return $this->extensions[$name]; + } + + /** + * Registers an extension. + * + * @param Twig_ExtensionInterface $extension A Twig_ExtensionInterface instance + */ + public function addExtension(Twig_ExtensionInterface $extension) + { + if ($this->extensionInitialized) { + throw new LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $extension->getName())); + } + + $this->extensions[$extension->getName()] = $extension; + } + + /** + * Removes an extension by name. + * + * This method is deprecated and you should not use it. + * + * @param string $name The extension name + * + * @deprecated since 1.12 (to be removed in 2.0) + */ + public function removeExtension($name) + { + if ($this->extensionInitialized) { + throw new LogicException(sprintf('Unable to remove extension "%s" as extensions have already been initialized.', $name)); + } + + unset($this->extensions[$name]); + } + + /** + * Registers an array of extensions. + * + * @param array $extensions An array of extensions + */ + public function setExtensions(array $extensions) + { + foreach ($extensions as $extension) { + $this->addExtension($extension); + } + } + + /** + * Returns all registered extensions. + * + * @return array An array of extensions + */ + public function getExtensions() + { + return $this->extensions; + } + + /** + * Registers a Token Parser. + * + * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance + */ + public function addTokenParser(Twig_TokenParserInterface $parser) + { + if ($this->extensionInitialized) { + throw new LogicException('Unable to add a token parser as extensions have already been initialized.'); + } + + $this->staging->addTokenParser($parser); + } + + /** + * Gets the registered Token Parsers. + * + * @return Twig_TokenParserBrokerInterface A broker containing token parsers + */ + public function getTokenParsers() + { + if (!$this->extensionInitialized) { + $this->initExtensions(); + } + + return $this->parsers; + } + + /** + * Gets registered tags. + * + * Be warned that this method cannot return tags defined by Twig_TokenParserBrokerInterface classes. + * + * @return Twig_TokenParserInterface[] An array of Twig_TokenParserInterface instances + */ + public function getTags() + { + $tags = array(); + foreach ($this->getTokenParsers()->getParsers() as $parser) { + if ($parser instanceof Twig_TokenParserInterface) { + $tags[$parser->getTag()] = $parser; + } + } + + return $tags; + } + + /** + * Registers a Node Visitor. + * + * @param Twig_NodeVisitorInterface $visitor A Twig_NodeVisitorInterface instance + */ + public function addNodeVisitor(Twig_NodeVisitorInterface $visitor) + { + if ($this->extensionInitialized) { + throw new LogicException('Unable to add a node visitor as extensions have already been initialized.'); + } + + $this->staging->addNodeVisitor($visitor); + } + + /** + * Gets the registered Node Visitors. + * + * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances + */ + public function getNodeVisitors() + { + if (!$this->extensionInitialized) { + $this->initExtensions(); + } + + return $this->visitors; + } + + /** + * Registers a Filter. + * + * @param string|Twig_SimpleFilter $name The filter name or a Twig_SimpleFilter instance + * @param Twig_FilterInterface|Twig_SimpleFilter $filter A Twig_FilterInterface instance or a Twig_SimpleFilter instance + */ + public function addFilter($name, $filter = null) + { + if (!$name instanceof Twig_SimpleFilter && !($filter instanceof Twig_SimpleFilter || $filter instanceof Twig_FilterInterface)) { + throw new LogicException('A filter must be an instance of Twig_FilterInterface or Twig_SimpleFilter'); + } + + if ($name instanceof Twig_SimpleFilter) { + $filter = $name; + $name = $filter->getName(); + } + + if ($this->extensionInitialized) { + throw new LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $name)); + } + + $this->staging->addFilter($name, $filter); + } + + /** + * Get a filter by name. + * + * Subclasses may override this method and load filters differently; + * so no list of filters is available. + * + * @param string $name The filter name + * + * @return Twig_Filter|false A Twig_Filter instance or false if the filter does not exist + */ + public function getFilter($name) + { + if (!$this->extensionInitialized) { + $this->initExtensions(); + } + + if (isset($this->filters[$name])) { + return $this->filters[$name]; + } + + foreach ($this->filters as $pattern => $filter) { + $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count); + + if ($count) { + if (preg_match('#^'.$pattern.'$#', $name, $matches)) { + array_shift($matches); + $filter->setArguments($matches); + + return $filter; + } + } + } + + foreach ($this->filterCallbacks as $callback) { + if (false !== $filter = call_user_func($callback, $name)) { + return $filter; + } + } + + return false; + } + + public function registerUndefinedFilterCallback($callable) + { + $this->filterCallbacks[] = $callable; + } + + /** + * Gets the registered Filters. + * + * Be warned that this method cannot return filters defined with registerUndefinedFunctionCallback. + * + * @return Twig_FilterInterface[] An array of Twig_FilterInterface instances + * + * @see registerUndefinedFilterCallback + */ + public function getFilters() + { + if (!$this->extensionInitialized) { + $this->initExtensions(); + } + + return $this->filters; + } + + /** + * Registers a Test. + * + * @param string|Twig_SimpleTest $name The test name or a Twig_SimpleTest instance + * @param Twig_TestInterface|Twig_SimpleTest $test A Twig_TestInterface instance or a Twig_SimpleTest instance + */ + public function addTest($name, $test = null) + { + if (!$name instanceof Twig_SimpleTest && !($test instanceof Twig_SimpleTest || $test instanceof Twig_TestInterface)) { + throw new LogicException('A test must be an instance of Twig_TestInterface or Twig_SimpleTest'); + } + + if ($name instanceof Twig_SimpleTest) { + $test = $name; + $name = $test->getName(); + } + + if ($this->extensionInitialized) { + throw new LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $name)); + } + + $this->staging->addTest($name, $test); + } + + /** + * Gets the registered Tests. + * + * @return Twig_TestInterface[] An array of Twig_TestInterface instances + */ + public function getTests() + { + if (!$this->extensionInitialized) { + $this->initExtensions(); + } + + return $this->tests; + } + + /** + * Gets a test by name. + * + * @param string $name The test name + * + * @return Twig_Test|false A Twig_Test instance or false if the test does not exist + */ + public function getTest($name) + { + if (!$this->extensionInitialized) { + $this->initExtensions(); + } + + if (isset($this->tests[$name])) { + return $this->tests[$name]; + } + + return false; + } + + /** + * Registers a Function. + * + * @param string|Twig_SimpleFunction $name The function name or a Twig_SimpleFunction instance + * @param Twig_FunctionInterface|Twig_SimpleFunction $function A Twig_FunctionInterface instance or a Twig_SimpleFunction instance + */ + public function addFunction($name, $function = null) + { + if (!$name instanceof Twig_SimpleFunction && !($function instanceof Twig_SimpleFunction || $function instanceof Twig_FunctionInterface)) { + throw new LogicException('A function must be an instance of Twig_FunctionInterface or Twig_SimpleFunction'); + } + + if ($name instanceof Twig_SimpleFunction) { + $function = $name; + $name = $function->getName(); + } + + if ($this->extensionInitialized) { + throw new LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $name)); + } + + $this->staging->addFunction($name, $function); + } + + /** + * Get a function by name. + * + * Subclasses may override this method and load functions differently; + * so no list of functions is available. + * + * @param string $name function name + * + * @return Twig_Function|false A Twig_Function instance or false if the function does not exist + */ + public function getFunction($name) + { + if (!$this->extensionInitialized) { + $this->initExtensions(); + } + + if (isset($this->functions[$name])) { + return $this->functions[$name]; + } + + foreach ($this->functions as $pattern => $function) { + $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count); + + if ($count) { + if (preg_match('#^'.$pattern.'$#', $name, $matches)) { + array_shift($matches); + $function->setArguments($matches); + + return $function; + } + } + } + + foreach ($this->functionCallbacks as $callback) { + if (false !== $function = call_user_func($callback, $name)) { + return $function; + } + } + + return false; + } + + public function registerUndefinedFunctionCallback($callable) + { + $this->functionCallbacks[] = $callable; + } + + /** + * Gets registered functions. + * + * Be warned that this method cannot return functions defined with registerUndefinedFunctionCallback. + * + * @return Twig_FunctionInterface[] An array of Twig_FunctionInterface instances + * + * @see registerUndefinedFunctionCallback + */ + public function getFunctions() + { + if (!$this->extensionInitialized) { + $this->initExtensions(); + } + + return $this->functions; + } + + /** + * Registers a Global. + * + * New globals can be added before compiling or rendering a template; + * but after, you can only update existing globals. + * + * @param string $name The global name + * @param mixed $value The global value + */ + public function addGlobal($name, $value) + { + if ($this->extensionInitialized || $this->runtimeInitialized) { + if (null === $this->globals) { + $this->globals = $this->initGlobals(); + } + + /* This condition must be uncommented in Twig 2.0 + if (!array_key_exists($name, $this->globals)) { + throw new LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name)); + } + */ + } + + if ($this->extensionInitialized || $this->runtimeInitialized) { + // update the value + $this->globals[$name] = $value; + } else { + $this->staging->addGlobal($name, $value); + } + } + + /** + * Gets the registered Globals. + * + * @return array An array of globals + */ + public function getGlobals() + { + if (!$this->runtimeInitialized && !$this->extensionInitialized) { + return $this->initGlobals(); + } + + if (null === $this->globals) { + $this->globals = $this->initGlobals(); + } + + return $this->globals; + } + + /** + * Merges a context with the defined globals. + * + * @param array $context An array representing the context + * + * @return array The context merged with the globals + */ + public function mergeGlobals(array $context) + { + // we don't use array_merge as the context being generally + // bigger than globals, this code is faster. + foreach ($this->getGlobals() as $key => $value) { + if (!array_key_exists($key, $context)) { + $context[$key] = $value; + } + } + + return $context; + } + + /** + * Gets the registered unary Operators. + * + * @return array An array of unary operators + */ + public function getUnaryOperators() + { + if (!$this->extensionInitialized) { + $this->initExtensions(); + } + + return $this->unaryOperators; + } + + /** + * Gets the registered binary Operators. + * + * @return array An array of binary operators + */ + public function getBinaryOperators() + { + if (!$this->extensionInitialized) { + $this->initExtensions(); + } + + return $this->binaryOperators; + } + + public function computeAlternatives($name, $items) + { + $alternatives = array(); + foreach ($items as $item) { + $lev = levenshtein($name, $item); + if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) { + $alternatives[$item] = $lev; + } + } + asort($alternatives); + + return array_keys($alternatives); + } + + protected function initGlobals() + { + $globals = array(); + foreach ($this->extensions as $extension) { + $extGlob = $extension->getGlobals(); + if (!is_array($extGlob)) { + throw new UnexpectedValueException(sprintf('"%s::getGlobals()" must return an array of globals.', get_class($extension))); + } + + $globals[] = $extGlob; + } + + $globals[] = $this->staging->getGlobals(); + + return call_user_func_array('array_merge', $globals); + } + + protected function initExtensions() + { + if ($this->extensionInitialized) { + return; + } + + $this->extensionInitialized = true; + $this->parsers = new Twig_TokenParserBroker(); + $this->filters = array(); + $this->functions = array(); + $this->tests = array(); + $this->visitors = array(); + $this->unaryOperators = array(); + $this->binaryOperators = array(); + + foreach ($this->extensions as $extension) { + $this->initExtension($extension); + } + $this->initExtension($this->staging); + } + + protected function initExtension(Twig_ExtensionInterface $extension) + { + // filters + foreach ($extension->getFilters() as $name => $filter) { + if ($name instanceof Twig_SimpleFilter) { + $filter = $name; + $name = $filter->getName(); + } elseif ($filter instanceof Twig_SimpleFilter) { + $name = $filter->getName(); + } + + $this->filters[$name] = $filter; + } + + // functions + foreach ($extension->getFunctions() as $name => $function) { + if ($name instanceof Twig_SimpleFunction) { + $function = $name; + $name = $function->getName(); + } elseif ($function instanceof Twig_SimpleFunction) { + $name = $function->getName(); + } + + $this->functions[$name] = $function; + } + + // tests + foreach ($extension->getTests() as $name => $test) { + if ($name instanceof Twig_SimpleTest) { + $test = $name; + $name = $test->getName(); + } elseif ($test instanceof Twig_SimpleTest) { + $name = $test->getName(); + } + + $this->tests[$name] = $test; + } + + // token parsers + foreach ($extension->getTokenParsers() as $parser) { + if ($parser instanceof Twig_TokenParserInterface) { + $this->parsers->addTokenParser($parser); + } elseif ($parser instanceof Twig_TokenParserBrokerInterface) { + $this->parsers->addTokenParserBroker($parser); + } else { + throw new LogicException('getTokenParsers() must return an array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances'); + } + } + + // node visitors + foreach ($extension->getNodeVisitors() as $visitor) { + $this->visitors[] = $visitor; + } + + // operators + if ($operators = $extension->getOperators()) { + if (2 !== count($operators)) { + throw new InvalidArgumentException(sprintf('"%s::getOperators()" does not return a valid operators array.', get_class($extension))); + } + + $this->unaryOperators = array_merge($this->unaryOperators, $operators[0]); + $this->binaryOperators = array_merge($this->binaryOperators, $operators[1]); + } + } + + protected function writeCacheFile($file, $content) + { + $dir = dirname($file); + if (!is_dir($dir)) { + if (false === @mkdir($dir, 0777, true)) { + clearstatcache(false, $dir); + if (!is_dir($dir)) { + throw new RuntimeException(sprintf('Unable to create the cache directory (%s).', $dir)); + } + } + } elseif (!is_writable($dir)) { + throw new RuntimeException(sprintf('Unable to write in the cache directory (%s).', $dir)); + } + + $tmpFile = tempnam($dir, basename($file)); + if (false !== @file_put_contents($tmpFile, $content)) { + // rename does not work on Win32 before 5.2.6 + if (@rename($tmpFile, $file) || (@copy($tmpFile, $file) && unlink($tmpFile))) { + @chmod($file, 0666 & ~umask()); + + return; + } + } + + throw new RuntimeException(sprintf('Failed to write cache file "%s".', $file)); } } diff --git a/system/libs/twig/Error.php b/system/libs/twig/Error.php new file mode 100755 index 00000000..90650c5f --- /dev/null +++ b/system/libs/twig/Error.php @@ -0,0 +1,250 @@ + + */ +class Twig_Error extends Exception +{ + protected $lineno; + protected $filename; + protected $rawMessage; + protected $previous; + + /** + * Constructor. + * + * Set both the line number and the filename to false to + * disable automatic guessing of the original template name + * and line number. + * + * Set the line number to -1 to enable its automatic guessing. + * Set the filename to null to enable its automatic guessing. + * + * By default, automatic guessing is enabled. + * + * @param string $message The error message + * @param int $lineno The template line where the error occurred + * @param string $filename The template file name where the error occurred + * @param Exception $previous The previous exception + */ + public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null) + { + if (PHP_VERSION_ID < 50300) { + $this->previous = $previous; + parent::__construct(''); + } else { + parent::__construct('', 0, $previous); + } + + $this->lineno = $lineno; + $this->filename = $filename; + + if (-1 === $this->lineno || null === $this->filename) { + $this->guessTemplateInfo(); + } + + $this->rawMessage = $message; + + $this->updateRepr(); + } + + /** + * Gets the raw message. + * + * @return string The raw message + */ + public function getRawMessage() + { + return $this->rawMessage; + } + + /** + * Gets the filename where the error occurred. + * + * @return string The filename + */ + public function getTemplateFile() + { + return $this->filename; + } + + /** + * Sets the filename where the error occurred. + * + * @param string $filename The filename + */ + public function setTemplateFile($filename) + { + $this->filename = $filename; + + $this->updateRepr(); + } + + /** + * Gets the template line where the error occurred. + * + * @return int The template line + */ + public function getTemplateLine() + { + return $this->lineno; + } + + /** + * Sets the template line where the error occurred. + * + * @param int $lineno The template line + */ + public function setTemplateLine($lineno) + { + $this->lineno = $lineno; + + $this->updateRepr(); + } + + public function guess() + { + $this->guessTemplateInfo(); + $this->updateRepr(); + } + + /** + * For PHP < 5.3.0, provides access to the getPrevious() method. + * + * @param string $method The method name + * @param array $arguments The parameters to be passed to the method + * + * @return Exception The previous exception or null + * + * @throws BadMethodCallException + */ + public function __call($method, $arguments) + { + if ('getprevious' == strtolower($method)) { + return $this->previous; + } + + throw new BadMethodCallException(sprintf('Method "Twig_Error::%s()" does not exist.', $method)); + } + + protected function updateRepr() + { + $this->message = $this->rawMessage; + + $dot = false; + if ('.' === substr($this->message, -1)) { + $this->message = substr($this->message, 0, -1); + $dot = true; + } + + if ($this->filename) { + if (is_string($this->filename) || (is_object($this->filename) && method_exists($this->filename, '__toString'))) { + $filename = sprintf('"%s"', $this->filename); + } else { + $filename = json_encode($this->filename); + } + $this->message .= sprintf(' in %s', $filename); + } + + if ($this->lineno && $this->lineno >= 0) { + $this->message .= sprintf(' at line %d', $this->lineno); + } + + if ($dot) { + $this->message .= '.'; + } + } + + protected function guessTemplateInfo() + { + $template = null; + $templateClass = null; + + if (PHP_VERSION_ID >= 50306) { + $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT); + } else { + $backtrace = debug_backtrace(); + } + + foreach ($backtrace as $trace) { + if (isset($trace['object']) && $trace['object'] instanceof Twig_Template && 'Twig_Template' !== get_class($trace['object'])) { + $currentClass = get_class($trace['object']); + $isEmbedContainer = 0 === strpos($templateClass, $currentClass); + if (null === $this->filename || ($this->filename == $trace['object']->getTemplateName() && !$isEmbedContainer)) { + $template = $trace['object']; + $templateClass = get_class($trace['object']); + } + } + } + + // update template filename + if (null !== $template && null === $this->filename) { + $this->filename = $template->getTemplateName(); + } + + if (null === $template || $this->lineno > -1) { + return; + } + + $r = new ReflectionObject($template); + $file = $r->getFileName(); + + // hhvm has a bug where eval'ed files comes out as the current directory + if (is_dir($file)) { + $file = ''; + } + + $exceptions = array($e = $this); + while (($e instanceof self || method_exists($e, 'getPrevious')) && $e = $e->getPrevious()) { + $exceptions[] = $e; + } + + while ($e = array_pop($exceptions)) { + $traces = $e->getTrace(); + array_unshift($traces, array('file' => $e->getFile(), 'line' => $e->getLine())); + + while ($trace = array_shift($traces)) { + if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) { + continue; + } + + foreach ($template->getDebugInfo() as $codeLine => $templateLine) { + if ($codeLine <= $trace['line']) { + // update template line + $this->lineno = $templateLine; + + return; + } + } + } + } + } +} diff --git a/system/libs/twig/Error/Error.php b/system/libs/twig/Error/Error.php deleted file mode 100755 index 52224d8a..00000000 --- a/system/libs/twig/Error/Error.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Error_Loader extends Twig_Error +{ + public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null) + { + parent::__construct($message, false, false, $previous); + } +} diff --git a/system/libs/twig/Error/LoaderError.php b/system/libs/twig/Error/LoaderError.php deleted file mode 100755 index df731b15..00000000 --- a/system/libs/twig/Error/LoaderError.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Error_Runtime extends Twig_Error +{ +} diff --git a/system/libs/twig/Error/RuntimeError.php b/system/libs/twig/Error/RuntimeError.php deleted file mode 100755 index b29ec536..00000000 --- a/system/libs/twig/Error/RuntimeError.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Error_Syntax extends Twig_Error +{ +} diff --git a/system/libs/twig/Error/SyntaxError.php b/system/libs/twig/Error/SyntaxError.php deleted file mode 100755 index 1b31520e..00000000 --- a/system/libs/twig/Error/SyntaxError.php +++ /dev/null @@ -1,11 +0,0 @@ - + * + * @deprecated since 1.12 (to be removed in 3.0) + */ +interface Twig_ExistsLoaderInterface +{ + /** + * Check if we have the source code of a template, given its name. + * + * @param string $name The name of the template to check if we can load + * + * @return bool If the template source code is handled by this loader or not + */ + public function exists($name); +} diff --git a/system/libs/twig/ExpressionParser.php b/system/libs/twig/ExpressionParser.php index 0cbbdbc2..135958a3 100755 --- a/system/libs/twig/ExpressionParser.php +++ b/system/libs/twig/ExpressionParser.php @@ -1,11 +1,625 @@ + */ +class Twig_ExpressionParser +{ + const OPERATOR_LEFT = 1; + const OPERATOR_RIGHT = 2; -if (\false) { - class ExpressionParser extends \Twig_ExpressionParser + protected $parser; + protected $unaryOperators; + protected $binaryOperators; + + public function __construct(Twig_Parser $parser, array $unaryOperators, array $binaryOperators) { + $this->parser = $parser; + $this->unaryOperators = $unaryOperators; + $this->binaryOperators = $binaryOperators; + } + + public function parseExpression($precedence = 0) + { + $expr = $this->getPrimary(); + $token = $this->parser->getCurrentToken(); + while ($this->isBinary($token) && $this->binaryOperators[$token->getValue()]['precedence'] >= $precedence) { + $op = $this->binaryOperators[$token->getValue()]; + $this->parser->getStream()->next(); + + if (isset($op['callable'])) { + $expr = call_user_func($op['callable'], $this->parser, $expr); + } else { + $expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']); + $class = $op['class']; + $expr = new $class($expr, $expr1, $token->getLine()); + } + + $token = $this->parser->getCurrentToken(); + } + + if (0 === $precedence) { + return $this->parseConditionalExpression($expr); + } + + return $expr; + } + + protected function getPrimary() + { + $token = $this->parser->getCurrentToken(); + + if ($this->isUnary($token)) { + $operator = $this->unaryOperators[$token->getValue()]; + $this->parser->getStream()->next(); + $expr = $this->parseExpression($operator['precedence']); + $class = $operator['class']; + + return $this->parsePostfixExpression(new $class($expr, $token->getLine())); + } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '(')) { + $this->parser->getStream()->next(); + $expr = $this->parseExpression(); + $this->parser->getStream()->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'An opened parenthesis is not properly closed'); + + return $this->parsePostfixExpression($expr); + } + + return $this->parsePrimaryExpression(); + } + + protected function parseConditionalExpression($expr) + { + while ($this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, '?')) { + if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) { + $expr2 = $this->parseExpression(); + if ($this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) { + $expr3 = $this->parseExpression(); + } else { + $expr3 = new Twig_Node_Expression_Constant('', $this->parser->getCurrentToken()->getLine()); + } + } else { + $expr2 = $expr; + $expr3 = $this->parseExpression(); + } + + $expr = new Twig_Node_Expression_Conditional($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine()); + } + + return $expr; + } + + protected function isUnary(Twig_Token $token) + { + return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->unaryOperators[$token->getValue()]); + } + + protected function isBinary(Twig_Token $token) + { + return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->getValue()]); + } + + public function parsePrimaryExpression() + { + $token = $this->parser->getCurrentToken(); + switch ($token->getType()) { + case Twig_Token::NAME_TYPE: + $this->parser->getStream()->next(); + switch ($token->getValue()) { + case 'true': + case 'TRUE': + $node = new Twig_Node_Expression_Constant(true, $token->getLine()); + break; + + case 'false': + case 'FALSE': + $node = new Twig_Node_Expression_Constant(false, $token->getLine()); + break; + + case 'none': + case 'NONE': + case 'null': + case 'NULL': + $node = new Twig_Node_Expression_Constant(null, $token->getLine()); + break; + + default: + if ('(' === $this->parser->getCurrentToken()->getValue()) { + $node = $this->getFunctionNode($token->getValue(), $token->getLine()); + } else { + $node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine()); + } + } + break; + + case Twig_Token::NUMBER_TYPE: + $this->parser->getStream()->next(); + $node = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine()); + break; + + case Twig_Token::STRING_TYPE: + case Twig_Token::INTERPOLATION_START_TYPE: + $node = $this->parseStringExpression(); + break; + + case Twig_Token::OPERATOR_TYPE: + if (preg_match(Twig_Lexer::REGEX_NAME, $token->getValue(), $matches) && $matches[0] == $token->getValue()) { + // in this context, string operators are variable names + $this->parser->getStream()->next(); + $node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine()); + break; + } elseif (isset($this->unaryOperators[$token->getValue()])) { + $class = $this->unaryOperators[$token->getValue()]['class']; + + $ref = new ReflectionClass($class); + $negClass = 'Twig_Node_Expression_Unary_Neg'; + $posClass = 'Twig_Node_Expression_Unary_Pos'; + if (!(in_array($ref->getName(), array($negClass, $posClass)) || $ref->isSubclassOf($negClass) || $ref->isSubclassOf($posClass))) { + throw new Twig_Error_Syntax(sprintf('Unexpected unary operator "%s"', $token->getValue()), $token->getLine(), $this->parser->getFilename()); + } + + $this->parser->getStream()->next(); + $expr = $this->parsePrimaryExpression(); + + $node = new $class($expr, $token->getLine()); + break; + } + + default: + if ($token->test(Twig_Token::PUNCTUATION_TYPE, '[')) { + $node = $this->parseArrayExpression(); + } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) { + $node = $this->parseHashExpression(); + } else { + throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getFilename()); + } + } + + return $this->parsePostfixExpression($node); + } + + public function parseStringExpression() + { + $stream = $this->parser->getStream(); + + $nodes = array(); + // a string cannot be followed by another string in a single expression + $nextCanBeString = true; + while (true) { + if ($nextCanBeString && $token = $stream->nextIf(Twig_Token::STRING_TYPE)) { + $nodes[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine()); + $nextCanBeString = false; + } elseif ($stream->nextIf(Twig_Token::INTERPOLATION_START_TYPE)) { + $nodes[] = $this->parseExpression(); + $stream->expect(Twig_Token::INTERPOLATION_END_TYPE); + $nextCanBeString = true; + } else { + break; + } + } + + $expr = array_shift($nodes); + foreach ($nodes as $node) { + $expr = new Twig_Node_Expression_Binary_Concat($expr, $node, $node->getLine()); + } + + return $expr; + } + + public function parseArrayExpression() + { + $stream = $this->parser->getStream(); + $stream->expect(Twig_Token::PUNCTUATION_TYPE, '[', 'An array element was expected'); + + $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine()); + $first = true; + while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) { + if (!$first) { + $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'An array element must be followed by a comma'); + + // trailing ,? + if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) { + break; + } + } + $first = false; + + $node->addElement($this->parseExpression()); + } + $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']', 'An opened array is not properly closed'); + + return $node; + } + + public function parseHashExpression() + { + $stream = $this->parser->getStream(); + $stream->expect(Twig_Token::PUNCTUATION_TYPE, '{', 'A hash element was expected'); + + $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine()); + $first = true; + while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) { + if (!$first) { + $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'A hash value must be followed by a comma'); + + // trailing ,? + if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) { + break; + } + } + $first = false; + + // a hash key can be: + // + // * a number -- 12 + // * a string -- 'a' + // * a name, which is equivalent to a string -- a + // * an expression, which must be enclosed in parentheses -- (1 + 2) + if (($token = $stream->nextIf(Twig_Token::STRING_TYPE)) || ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) || $token = $stream->nextIf(Twig_Token::NUMBER_TYPE)) { + $key = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine()); + } elseif ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) { + $key = $this->parseExpression(); + } else { + $current = $stream->getCurrent(); + + throw new Twig_Error_Syntax(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($current->getType()), $current->getValue()), $current->getLine(), $this->parser->getFilename()); + } + + $stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)'); + $value = $this->parseExpression(); + + $node->addElement($value, $key); + } + $stream->expect(Twig_Token::PUNCTUATION_TYPE, '}', 'An opened hash is not properly closed'); + + return $node; + } + + public function parsePostfixExpression($node) + { + while (true) { + $token = $this->parser->getCurrentToken(); + if ($token->getType() == Twig_Token::PUNCTUATION_TYPE) { + if ('.' == $token->getValue() || '[' == $token->getValue()) { + $node = $this->parseSubscriptExpression($node); + } elseif ('|' == $token->getValue()) { + $node = $this->parseFilterExpression($node); + } else { + break; + } + } else { + break; + } + } + + return $node; + } + + public function getFunctionNode($name, $line) + { + switch ($name) { + case 'parent': + $this->parseArguments(); + if (!count($this->parser->getBlockStack())) { + throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line, $this->parser->getFilename()); + } + + if (!$this->parser->getParent() && !$this->parser->hasTraits()) { + throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden', $line, $this->parser->getFilename()); + } + + return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line); + case 'block': + return new Twig_Node_Expression_BlockReference($this->parseArguments()->getNode(0), false, $line); + case 'attribute': + $args = $this->parseArguments(); + if (count($args) < 2) { + throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line, $this->parser->getFilename()); + } + + return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : null, Twig_Template::ANY_CALL, $line); + default: + if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) { + $arguments = new Twig_Node_Expression_Array(array(), $line); + foreach ($this->parseArguments() as $n) { + $arguments->addElement($n); + } + + $node = new Twig_Node_Expression_MethodCall($alias['node'], $alias['name'], $arguments, $line); + $node->setAttribute('safe', true); + + return $node; + } + + $args = $this->parseArguments(true); + $class = $this->getFunctionNodeClass($name, $line); + + return new $class($name, $args, $line); + } + } + + public function parseSubscriptExpression($node) + { + $stream = $this->parser->getStream(); + $token = $stream->next(); + $lineno = $token->getLine(); + $arguments = new Twig_Node_Expression_Array(array(), $lineno); + $type = Twig_Template::ANY_CALL; + if ($token->getValue() == '.') { + $token = $stream->next(); + if ( + $token->getType() == Twig_Token::NAME_TYPE + || + $token->getType() == Twig_Token::NUMBER_TYPE + || + ($token->getType() == Twig_Token::OPERATOR_TYPE && preg_match(Twig_Lexer::REGEX_NAME, $token->getValue())) + ) { + $arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno); + + if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) { + $type = Twig_TemplateInterface::METHOD_CALL; + foreach ($this->parseArguments() as $n) { + $arguments->addElement($n); + } + } + } else { + throw new Twig_Error_Syntax('Expected name or number', $lineno, $this->parser->getFilename()); + } + + if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) { + if (!$arg instanceof Twig_Node_Expression_Constant) { + throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s")', $node->getAttribute('name')), $token->getLine(), $this->parser->getFilename()); + } + + $name = $arg->getAttribute('value'); + + if ($this->parser->isReservedMacroName($name)) { + throw new Twig_Error_Syntax(sprintf('"%s" cannot be called as macro as it is a reserved keyword', $name), $token->getLine(), $this->parser->getFilename()); + } + + $node = new Twig_Node_Expression_MethodCall($node, 'get'.$name, $arguments, $lineno); + $node->setAttribute('safe', true); + + return $node; + } + } else { + $type = Twig_Template::ARRAY_CALL; + + // slice? + $slice = false; + if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) { + $slice = true; + $arg = new Twig_Node_Expression_Constant(0, $token->getLine()); + } else { + $arg = $this->parseExpression(); + } + + if ($stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) { + $slice = true; + } + + if ($slice) { + if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) { + $length = new Twig_Node_Expression_Constant(null, $token->getLine()); + } else { + $length = $this->parseExpression(); + } + + $class = $this->getFilterNodeClass('slice', $token->getLine()); + $arguments = new Twig_Node(array($arg, $length)); + $filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine()); + + $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']'); + + return $filter; + } + + $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']'); + } + + return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno); + } + + public function parseFilterExpression($node) + { + $this->parser->getStream()->next(); + + return $this->parseFilterExpressionRaw($node); + } + + public function parseFilterExpressionRaw($node, $tag = null) + { + while (true) { + $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE); + + $name = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine()); + if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '(')) { + $arguments = new Twig_Node(); + } else { + $arguments = $this->parseArguments(true); + } + + $class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine()); + + $node = new $class($node, $name, $arguments, $token->getLine(), $tag); + + if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '|')) { + break; + } + + $this->parser->getStream()->next(); + } + + return $node; + } + + /** + * Parses arguments. + * + * @param bool $namedArguments Whether to allow named arguments or not + * @param bool $definition Whether we are parsing arguments for a function definition + * + * @return Twig_Node + * + * @throws Twig_Error_Syntax + */ + public function parseArguments($namedArguments = false, $definition = false) + { + $args = array(); + $stream = $this->parser->getStream(); + + $stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis'); + while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) { + if (!empty($args)) { + $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma'); + } + + if ($definition) { + $token = $stream->expect(Twig_Token::NAME_TYPE, null, 'An argument must be a name'); + $value = new Twig_Node_Expression_Name($token->getValue(), $this->parser->getCurrentToken()->getLine()); + } else { + $value = $this->parseExpression(); + } + + $name = null; + if ($namedArguments && $token = $stream->nextIf(Twig_Token::OPERATOR_TYPE, '=')) { + if (!$value instanceof Twig_Node_Expression_Name) { + throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given', get_class($value)), $token->getLine(), $this->parser->getFilename()); + } + $name = $value->getAttribute('name'); + + if ($definition) { + $value = $this->parsePrimaryExpression(); + + if (!$this->checkConstantExpression($value)) { + throw new Twig_Error_Syntax(sprintf('A default value for an argument must be a constant (a boolean, a string, a number, or an array).'), $token->getLine(), $this->parser->getFilename()); + } + } else { + $value = $this->parseExpression(); + } + } + + if ($definition) { + if (null === $name) { + $name = $value->getAttribute('name'); + $value = new Twig_Node_Expression_Constant(null, $this->parser->getCurrentToken()->getLine()); + } + $args[$name] = $value; + } else { + if (null === $name) { + $args[] = $value; + } else { + $args[$name] = $value; + } + } + } + $stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis'); + + return new Twig_Node($args); + } + + public function parseAssignmentExpression() + { + $targets = array(); + while (true) { + $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to'); + if (in_array($token->getValue(), array('true', 'false', 'none'))) { + throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s"', $token->getValue()), $token->getLine(), $this->parser->getFilename()); + } + $targets[] = new Twig_Node_Expression_AssignName($token->getValue(), $token->getLine()); + + if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) { + break; + } + } + + return new Twig_Node($targets); + } + + public function parseMultitargetExpression() + { + $targets = array(); + while (true) { + $targets[] = $this->parseExpression(); + if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) { + break; + } + } + + return new Twig_Node($targets); + } + + protected function getFunctionNodeClass($name, $line) + { + $env = $this->parser->getEnvironment(); + + if (false === $function = $env->getFunction($name)) { + $message = sprintf('The function "%s" does not exist', $name); + if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFunctions()))) { + $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); + } + + throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename()); + } + + if ($function instanceof Twig_SimpleFunction) { + return $function->getNodeClass(); + } + + return $function instanceof Twig_Function_Node ? $function->getClass() : 'Twig_Node_Expression_Function'; + } + + protected function getFilterNodeClass($name, $line) + { + $env = $this->parser->getEnvironment(); + + if (false === $filter = $env->getFilter($name)) { + $message = sprintf('The filter "%s" does not exist', $name); + if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFilters()))) { + $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); + } + + throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename()); + } + + if ($filter instanceof Twig_SimpleFilter) { + return $filter->getNodeClass(); + } + + return $filter instanceof Twig_Filter_Node ? $filter->getClass() : 'Twig_Node_Expression_Filter'; + } + + // checks that the node only contains "constant" elements + protected function checkConstantExpression(Twig_NodeInterface $node) + { + if (!($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array + || $node instanceof Twig_Node_Expression_Unary_Neg || $node instanceof Twig_Node_Expression_Unary_Pos + )) { + return false; + } + + foreach ($node as $n) { + if (!$this->checkConstantExpression($n)) { + return false; + } + } + + return true; } } diff --git a/system/libs/twig/Extension.php b/system/libs/twig/Extension.php new file mode 100755 index 00000000..5c8ad5c9 --- /dev/null +++ b/system/libs/twig/Extension.php @@ -0,0 +1,93 @@ +escapers[$strategy] = $callable; + } + + /** + * Gets all defined escapers. + * + * @return array An array of escapers + */ + public function getEscapers() + { + return $this->escapers; + } + + /** + * Sets the default format to be used by the date filter. + * + * @param string $format The default date format string + * @param string $dateIntervalFormat The default date interval format string + */ + public function setDateFormat($format = null, $dateIntervalFormat = null) + { + if (null !== $format) { + $this->dateFormats[0] = $format; + } + + if (null !== $dateIntervalFormat) { + $this->dateFormats[1] = $dateIntervalFormat; + } + } + + /** + * Gets the default format to be used by the date filter. + * + * @return array The default date format string and the default date interval format string + */ + public function getDateFormat() + { + return $this->dateFormats; + } + + /** + * Sets the default timezone to be used by the date filter. + * + * @param DateTimeZone|string $timezone The default timezone string or a DateTimeZone object + */ + public function setTimezone($timezone) + { + $this->timezone = $timezone instanceof DateTimeZone ? $timezone : new DateTimeZone($timezone); + } + + /** + * Gets the default timezone to be used by the date filter. + * + * @return DateTimeZone The default timezone currently in use + */ + public function getTimezone() + { + if (null === $this->timezone) { + $this->timezone = new DateTimeZone(date_default_timezone_get()); + } + + return $this->timezone; + } + + /** + * Sets the default format to be used by the number_format filter. + * + * @param int $decimal The number of decimal places to use. + * @param string $decimalPoint The character(s) to use for the decimal point. + * @param string $thousandSep The character(s) to use for the thousands separator. + */ + public function setNumberFormat($decimal, $decimalPoint, $thousandSep) + { + $this->numberFormat = array($decimal, $decimalPoint, $thousandSep); + } + + /** + * Get the default format used by the number_format filter. + * + * @return array The arguments for number_format() + */ + public function getNumberFormat() + { + return $this->numberFormat; + } + + /** + * Returns the token parser instance to add to the existing list. + * + * @return Twig_TokenParser[] An array of Twig_TokenParser instances + */ + public function getTokenParsers() + { + return array( + new Twig_TokenParser_For(), + new Twig_TokenParser_If(), + new Twig_TokenParser_Extends(), + new Twig_TokenParser_Include(), + new Twig_TokenParser_Block(), + new Twig_TokenParser_Use(), + new Twig_TokenParser_Filter(), + new Twig_TokenParser_Macro(), + new Twig_TokenParser_Import(), + new Twig_TokenParser_From(), + new Twig_TokenParser_Set(), + new Twig_TokenParser_Spaceless(), + new Twig_TokenParser_Flush(), + new Twig_TokenParser_Do(), + new Twig_TokenParser_Embed(), + ); + } + + /** + * Returns a list of filters to add to the existing list. + * + * @return array An array of filters + */ + public function getFilters() + { + $filters = array( + // formatting filters + new Twig_SimpleFilter('date', 'twig_date_format_filter', array('needs_environment' => true)), + new Twig_SimpleFilter('date_modify', 'twig_date_modify_filter', array('needs_environment' => true)), + new Twig_SimpleFilter('format', 'sprintf'), + new Twig_SimpleFilter('replace', 'strtr'), + new Twig_SimpleFilter('number_format', 'twig_number_format_filter', array('needs_environment' => true)), + new Twig_SimpleFilter('abs', 'abs'), + new Twig_SimpleFilter('round', 'twig_round'), + + // encoding + new Twig_SimpleFilter('url_encode', 'twig_urlencode_filter'), + new Twig_SimpleFilter('json_encode', 'twig_jsonencode_filter'), + new Twig_SimpleFilter('convert_encoding', 'twig_convert_encoding'), + + // string filters + new Twig_SimpleFilter('title', 'twig_title_string_filter', array('needs_environment' => true)), + new Twig_SimpleFilter('capitalize', 'twig_capitalize_string_filter', array('needs_environment' => true)), + new Twig_SimpleFilter('upper', 'strtoupper'), + new Twig_SimpleFilter('lower', 'strtolower'), + new Twig_SimpleFilter('striptags', 'strip_tags'), + new Twig_SimpleFilter('trim', 'trim'), + new Twig_SimpleFilter('nl2br', 'nl2br', array('pre_escape' => 'html', 'is_safe' => array('html'))), + + // array helpers + new Twig_SimpleFilter('join', 'twig_join_filter'), + new Twig_SimpleFilter('split', 'twig_split_filter', array('needs_environment' => true)), + new Twig_SimpleFilter('sort', 'twig_sort_filter'), + new Twig_SimpleFilter('merge', 'twig_array_merge'), + new Twig_SimpleFilter('batch', 'twig_array_batch'), + + // string/array filters + new Twig_SimpleFilter('reverse', 'twig_reverse_filter', array('needs_environment' => true)), + new Twig_SimpleFilter('length', 'twig_length_filter', array('needs_environment' => true)), + new Twig_SimpleFilter('slice', 'twig_slice', array('needs_environment' => true)), + new Twig_SimpleFilter('first', 'twig_first', array('needs_environment' => true)), + new Twig_SimpleFilter('last', 'twig_last', array('needs_environment' => true)), + + // iteration and runtime + new Twig_SimpleFilter('default', '_twig_default_filter', array('node_class' => 'Twig_Node_Expression_Filter_Default')), + new Twig_SimpleFilter('keys', 'twig_get_array_keys_filter'), + + // escaping + new Twig_SimpleFilter('escape', 'twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')), + new Twig_SimpleFilter('e', 'twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')), + ); + + if (function_exists('mb_get_info')) { + $filters[] = new Twig_SimpleFilter('upper', 'twig_upper_filter', array('needs_environment' => true)); + $filters[] = new Twig_SimpleFilter('lower', 'twig_lower_filter', array('needs_environment' => true)); + } + + return $filters; + } + + /** + * Returns a list of global functions to add to the existing list. + * + * @return array An array of global functions + */ + public function getFunctions() + { + return array( + new Twig_SimpleFunction('max', 'max'), + new Twig_SimpleFunction('min', 'min'), + new Twig_SimpleFunction('range', 'range'), + new Twig_SimpleFunction('constant', 'twig_constant'), + new Twig_SimpleFunction('cycle', 'twig_cycle'), + new Twig_SimpleFunction('random', 'twig_random', array('needs_environment' => true)), + new Twig_SimpleFunction('date', 'twig_date_converter', array('needs_environment' => true)), + new Twig_SimpleFunction('include', 'twig_include', array('needs_environment' => true, 'needs_context' => true, 'is_safe' => array('all'))), + new Twig_SimpleFunction('source', 'twig_source', array('needs_environment' => true, 'is_safe' => array('all'))), + ); + } + + /** + * Returns a list of tests to add to the existing list. + * + * @return array An array of tests + */ + public function getTests() + { + return array( + new Twig_SimpleTest('even', null, array('node_class' => 'Twig_Node_Expression_Test_Even')), + new Twig_SimpleTest('odd', null, array('node_class' => 'Twig_Node_Expression_Test_Odd')), + new Twig_SimpleTest('defined', null, array('node_class' => 'Twig_Node_Expression_Test_Defined')), + new Twig_SimpleTest('sameas', null, array('node_class' => 'Twig_Node_Expression_Test_Sameas')), + new Twig_SimpleTest('same as', null, array('node_class' => 'Twig_Node_Expression_Test_Sameas')), + new Twig_SimpleTest('none', null, array('node_class' => 'Twig_Node_Expression_Test_Null')), + new Twig_SimpleTest('null', null, array('node_class' => 'Twig_Node_Expression_Test_Null')), + new Twig_SimpleTest('divisibleby', null, array('node_class' => 'Twig_Node_Expression_Test_Divisibleby')), + new Twig_SimpleTest('divisible by', null, array('node_class' => 'Twig_Node_Expression_Test_Divisibleby')), + new Twig_SimpleTest('constant', null, array('node_class' => 'Twig_Node_Expression_Test_Constant')), + new Twig_SimpleTest('empty', 'twig_test_empty'), + new Twig_SimpleTest('iterable', 'twig_test_iterable'), + ); + } + + /** + * Returns a list of operators to add to the existing list. + * + * @return array An array of operators + */ + public function getOperators() + { + return array( + array( + 'not' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'), + '-' => array('precedence' => 500, 'class' => 'Twig_Node_Expression_Unary_Neg'), + '+' => array('precedence' => 500, 'class' => 'Twig_Node_Expression_Unary_Pos'), + ), + array( + 'or' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + 'and' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + 'b-or' => array('precedence' => 16, 'class' => 'Twig_Node_Expression_Binary_BitwiseOr', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + 'b-xor' => array('precedence' => 17, 'class' => 'Twig_Node_Expression_Binary_BitwiseXor', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + 'b-and' => array('precedence' => 18, 'class' => 'Twig_Node_Expression_Binary_BitwiseAnd', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '==' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Equal', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '!=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '<' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Less', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '>' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Greater', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '>=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_GreaterEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '<=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_LessEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + 'not in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotIn', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + 'in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_In', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + 'matches' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Matches', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + 'starts with' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_StartsWith', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + 'ends with' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_EndsWith', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '..' => array('precedence' => 25, 'class' => 'Twig_Node_Expression_Binary_Range', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '+' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Add', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '-' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Sub', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '~' => array('precedence' => 40, 'class' => 'Twig_Node_Expression_Binary_Concat', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '*' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mul', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '/' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Div', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '//' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_FloorDiv', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '%' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mod', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + 'is' => array('precedence' => 100, 'callable' => array($this, 'parseTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + 'is not' => array('precedence' => 100, 'callable' => array($this, 'parseNotTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '**' => array('precedence' => 200, 'class' => 'Twig_Node_Expression_Binary_Power', 'associativity' => Twig_ExpressionParser::OPERATOR_RIGHT), + ), + ); + } + + public function parseNotTestExpression(Twig_Parser $parser, Twig_NodeInterface $node) + { + return new Twig_Node_Expression_Unary_Not($this->parseTestExpression($parser, $node), $parser->getCurrentToken()->getLine()); + } + + public function parseTestExpression(Twig_Parser $parser, Twig_NodeInterface $node) + { + $stream = $parser->getStream(); + $name = $this->getTestName($parser, $node->getLine()); + $class = $this->getTestNodeClass($parser, $name); + $arguments = null; + if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) { + $arguments = $parser->getExpressionParser()->parseArguments(true); + } + + return new $class($node, $name, $arguments, $parser->getCurrentToken()->getLine()); + } + + protected function getTestName(Twig_Parser $parser, $line) + { + $stream = $parser->getStream(); + $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); + $env = $parser->getEnvironment(); + $testMap = $env->getTests(); + + if (isset($testMap[$name])) { + return $name; + } + + if ($stream->test(Twig_Token::NAME_TYPE)) { + // try 2-words tests + $name = $name.' '.$parser->getCurrentToken()->getValue(); + + if (isset($testMap[$name])) { + $parser->getStream()->next(); + + return $name; + } + } + + $message = sprintf('The test "%s" does not exist', $name); + if ($alternatives = $env->computeAlternatives($name, array_keys($testMap))) { + $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); + } + + throw new Twig_Error_Syntax($message, $line, $parser->getFilename()); + } + + protected function getTestNodeClass(Twig_Parser $parser, $name) + { + $env = $parser->getEnvironment(); + $testMap = $env->getTests(); + + if ($testMap[$name] instanceof Twig_SimpleTest) { + return $testMap[$name]->getNodeClass(); + } + + return $testMap[$name] instanceof Twig_Test_Node ? $testMap[$name]->getClass() : 'Twig_Node_Expression_Test'; + } + + /** + * Returns the name of the extension. + * + * @return string The extension name + */ + public function getName() + { + return 'core'; + } +} + +/** + * Cycles over a value. + * + * @param ArrayAccess|array $values An array or an ArrayAccess instance + * @param int $position The cycle position + * + * @return string The next value in the cycle + */ +function twig_cycle($values, $position) +{ + if (!is_array($values) && !$values instanceof ArrayAccess) { + return $values; + } + + return $values[$position % count($values)]; +} + +/** + * Returns a random value depending on the supplied parameter type: + * - a random item from a Traversable or array + * - a random character from a string + * - a random integer between 0 and the integer parameter. + * + * @param Twig_Environment $env A Twig_Environment instance + * @param Traversable|array|int|string $values The values to pick a random item from + * + * @throws Twig_Error_Runtime When $values is an empty array (does not apply to an empty string which is returned as is). + * + * @return mixed A random value from the given sequence + */ +function twig_random(Twig_Environment $env, $values = null) +{ + if (null === $values) { + return mt_rand(); + } + + if (is_int($values) || is_float($values)) { + return $values < 0 ? mt_rand($values, 0) : mt_rand(0, $values); + } + + if ($values instanceof Traversable) { + $values = iterator_to_array($values); + } elseif (is_string($values)) { + if ('' === $values) { + return ''; + } + if (null !== $charset = $env->getCharset()) { + if ('UTF-8' != $charset) { + $values = twig_convert_encoding($values, 'UTF-8', $charset); + } + + // unicode version of str_split() + // split at all positions, but not after the start and not before the end + $values = preg_split('/(? $value) { + $values[$i] = twig_convert_encoding($value, $charset, 'UTF-8'); + } + } + } else { + return $values[mt_rand(0, strlen($values) - 1)]; + } + } + + if (!is_array($values)) { + return $values; + } + + if (0 === count($values)) { + throw new Twig_Error_Runtime('The random function cannot pick from an empty array.'); + } + + return $values[array_rand($values, 1)]; +} + +/** + * Converts a date to the given format. + * + *
+ *   {{ post.published_at|date("m/d/Y") }}
+ * 
+ * + * @param Twig_Environment $env A Twig_Environment instance + * @param DateTime|DateTimeInterface|DateInterval|string $date A date + * @param string|null $format The target format, null to use the default + * @param DateTimeZone|string|null|false $timezone The target timezone, null to use the default, false to leave unchanged + * + * @return string The formatted date + */ +function twig_date_format_filter(Twig_Environment $env, $date, $format = null, $timezone = null) +{ + if (null === $format) { + $formats = $env->getExtension('core')->getDateFormat(); + $format = $date instanceof DateInterval ? $formats[1] : $formats[0]; + } + + if ($date instanceof DateInterval) { + return $date->format($format); + } + + return twig_date_converter($env, $date, $timezone)->format($format); +} + +/** + * Returns a new date object modified. + * + *
+ *   {{ post.published_at|date_modify("-1day")|date("m/d/Y") }}
+ * 
+ * + * @param Twig_Environment $env A Twig_Environment instance + * @param DateTime|string $date A date + * @param string $modifier A modifier string + * + * @return DateTime A new date object + */ +function twig_date_modify_filter(Twig_Environment $env, $date, $modifier) +{ + $date = twig_date_converter($env, $date, false); + $resultDate = $date->modify($modifier); + + // This is a hack to ensure PHP 5.2 support and support for DateTimeImmutable + // DateTime::modify does not return the modified DateTime object < 5.3.0 + // and DateTimeImmutable does not modify $date. + return null === $resultDate ? $date : $resultDate; +} + +/** + * Converts an input to a DateTime instance. + * + *
+ *    {% if date(user.created_at) < date('+2days') %}
+ *      {# do something #}
+ *    {% endif %}
+ * 
+ * + * @param Twig_Environment $env A Twig_Environment instance + * @param DateTime|DateTimeInterface|string|null $date A date + * @param DateTimeZone|string|null|false $timezone The target timezone, null to use the default, false to leave unchanged + * + * @return DateTime A DateTime instance + */ +function twig_date_converter(Twig_Environment $env, $date = null, $timezone = null) +{ + // determine the timezone + if (false !== $timezone) { + if (null === $timezone) { + $timezone = $env->getExtension('core')->getTimezone(); + } elseif (!$timezone instanceof DateTimeZone) { + $timezone = new DateTimeZone($timezone); + } + } + + // immutable dates + if ($date instanceof DateTimeImmutable) { + return false !== $timezone ? $date->setTimezone($timezone) : $date; + } + + if ($date instanceof DateTime || $date instanceof DateTimeInterface) { + $date = clone $date; + if (false !== $timezone) { + $date->setTimezone($timezone); + } + + return $date; + } + + $asString = (string) $date; + if (ctype_digit($asString) || (!empty($asString) && '-' === $asString[0] && ctype_digit(substr($asString, 1)))) { + $date = '@'.$date; + } + + $date = new DateTime($date, $env->getExtension('core')->getTimezone()); + if (false !== $timezone) { + $date->setTimezone($timezone); + } + + return $date; +} + +/** + * Rounds a number. + * + * @param int|float $value The value to round + * @param int|float $precision The rounding precision + * @param string $method The method to use for rounding + * + * @return int|float The rounded number + */ +function twig_round($value, $precision = 0, $method = 'common') +{ + if ('common' == $method) { + return round($value, $precision); + } + + if ('ceil' != $method && 'floor' != $method) { + throw new Twig_Error_Runtime('The round filter only supports the "common", "ceil", and "floor" methods.'); + } + + return $method($value * pow(10, $precision)) / pow(10, $precision); +} + +/** + * Number format filter. + * + * All of the formatting options can be left null, in that case the defaults will + * be used. Supplying any of the parameters will override the defaults set in the + * environment object. + * + * @param Twig_Environment $env A Twig_Environment instance + * @param mixed $number A float/int/string of the number to format + * @param int $decimal The number of decimal points to display. + * @param string $decimalPoint The character(s) to use for the decimal point. + * @param string $thousandSep The character(s) to use for the thousands separator. + * + * @return string The formatted number + */ +function twig_number_format_filter(Twig_Environment $env, $number, $decimal = null, $decimalPoint = null, $thousandSep = null) +{ + $defaults = $env->getExtension('core')->getNumberFormat(); + if (null === $decimal) { + $decimal = $defaults[0]; + } + + if (null === $decimalPoint) { + $decimalPoint = $defaults[1]; + } + + if (null === $thousandSep) { + $thousandSep = $defaults[2]; + } + + return number_format((float) $number, $decimal, $decimalPoint, $thousandSep); +} + +/** + * URL encodes (RFC 3986) a string as a path segment or an array as a query string. + * + * @param string|array $url A URL or an array of query parameters + * + * @return string The URL encoded value + */ +function twig_urlencode_filter($url) +{ + if (is_array($url)) { + if (defined('PHP_QUERY_RFC3986')) { + return http_build_query($url, '', '&', PHP_QUERY_RFC3986); + } + + return http_build_query($url, '', '&'); + } + + return rawurlencode($url); +} + +if (PHP_VERSION_ID < 50300) { + /** + * JSON encodes a variable. + * + * @param mixed $value The value to encode. + * @param int $options Not used on PHP 5.2.x + * + * @return mixed The JSON encoded value + */ + function twig_jsonencode_filter($value, $options = 0) + { + if ($value instanceof Twig_Markup) { + $value = (string) $value; + } elseif (is_array($value)) { + array_walk_recursive($value, '_twig_markup2string'); + } + + return json_encode($value); + } +} else { + /** + * JSON encodes a variable. + * + * @param mixed $value The value to encode. + * @param int $options Bitmask consisting of JSON_HEX_QUOT, JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_NUMERIC_CHECK, JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES, JSON_FORCE_OBJECT + * + * @return mixed The JSON encoded value + */ + function twig_jsonencode_filter($value, $options = 0) + { + if ($value instanceof Twig_Markup) { + $value = (string) $value; + } elseif (is_array($value)) { + array_walk_recursive($value, '_twig_markup2string'); + } + + return json_encode($value, $options); + } +} + +function _twig_markup2string(&$value) +{ + if ($value instanceof Twig_Markup) { + $value = (string) $value; + } +} + +/** + * Merges an array with another one. + * + *
+ *  {% set items = { 'apple': 'fruit', 'orange': 'fruit' } %}
+ *
+ *  {% set items = items|merge({ 'peugeot': 'car' }) %}
+ *
+ *  {# items now contains { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car' } #}
+ * 
+ * + * @param array $arr1 An array + * @param array $arr2 An array + * + * @return array The merged array + */ +function twig_array_merge($arr1, $arr2) +{ + if (!is_array($arr1) || !is_array($arr2)) { + throw new Twig_Error_Runtime(sprintf('The merge filter only works with arrays or hashes; %s and %s given.', gettype($arr1), gettype($arr2))); + } + + return array_merge($arr1, $arr2); +} + +/** + * Slices a variable. + * + * @param Twig_Environment $env A Twig_Environment instance + * @param mixed $item A variable + * @param int $start Start of the slice + * @param int $length Size of the slice + * @param bool $preserveKeys Whether to preserve key or not (when the input is an array) + * + * @return mixed The sliced variable + */ +function twig_slice(Twig_Environment $env, $item, $start, $length = null, $preserveKeys = false) +{ + if ($item instanceof Traversable) { + if ($item instanceof IteratorAggregate) { + $item = $item->getIterator(); + } + + if ($start >= 0 && $length >= 0 && $item instanceof Iterator) { + try { + return iterator_to_array(new LimitIterator($item, $start, $length === null ? -1 : $length), $preserveKeys); + } catch (OutOfBoundsException $exception) { + return array(); + } + } + + $item = iterator_to_array($item, $preserveKeys); + } + + if (is_array($item)) { + return array_slice($item, $start, $length, $preserveKeys); + } + + $item = (string) $item; + + if (function_exists('mb_get_info') && null !== $charset = $env->getCharset()) { + return (string) mb_substr($item, $start, null === $length ? mb_strlen($item, $charset) - $start : $length, $charset); + } + + return (string) (null === $length ? substr($item, $start) : substr($item, $start, $length)); +} + +/** + * Returns the first element of the item. + * + * @param Twig_Environment $env A Twig_Environment instance + * @param mixed $item A variable + * + * @return mixed The first element of the item + */ +function twig_first(Twig_Environment $env, $item) +{ + $elements = twig_slice($env, $item, 0, 1, false); + + return is_string($elements) ? $elements : current($elements); +} + +/** + * Returns the last element of the item. + * + * @param Twig_Environment $env A Twig_Environment instance + * @param mixed $item A variable + * + * @return mixed The last element of the item + */ +function twig_last(Twig_Environment $env, $item) +{ + $elements = twig_slice($env, $item, -1, 1, false); + + return is_string($elements) ? $elements : current($elements); +} + +/** + * Joins the values to a string. + * + * The separator between elements is an empty string per default, you can define it with the optional parameter. + * + *
+ *  {{ [1, 2, 3]|join('|') }}
+ *  {# returns 1|2|3 #}
+ *
+ *  {{ [1, 2, 3]|join }}
+ *  {# returns 123 #}
+ * 
+ * + * @param array $value An array + * @param string $glue The separator + * + * @return string The concatenated string + */ +function twig_join_filter($value, $glue = '') +{ + if ($value instanceof Traversable) { + $value = iterator_to_array($value, false); + } + + return implode($glue, (array) $value); +} + +/** + * Splits the string into an array. + * + *
+ *  {{ "one,two,three"|split(',') }}
+ *  {# returns [one, two, three] #}
+ *
+ *  {{ "one,two,three,four,five"|split(',', 3) }}
+ *  {# returns [one, two, "three,four,five"] #}
+ *
+ *  {{ "123"|split('') }}
+ *  {# returns [1, 2, 3] #}
+ *
+ *  {{ "aabbcc"|split('', 2) }}
+ *  {# returns [aa, bb, cc] #}
+ * 
+ * + * @param string $value A string + * @param string $delimiter The delimiter + * @param int $limit The limit + * + * @return array The split string as an array + */ +function twig_split_filter(Twig_Environment $env, $value, $delimiter, $limit = null) +{ + if (!empty($delimiter)) { + return null === $limit ? explode($delimiter, $value) : explode($delimiter, $value, $limit); + } + + if (!function_exists('mb_get_info') || null === $charset = $env->getCharset()) { + return str_split($value, null === $limit ? 1 : $limit); + } + + if ($limit <= 1) { + return preg_split('/(? + * {% for key in array|keys %} + * {# ... #} + * {% endfor %} + * + * + * @param array $array An array + * + * @return array The keys + */ +function twig_get_array_keys_filter($array) +{ + if (is_object($array) && $array instanceof Traversable) { + return array_keys(iterator_to_array($array)); + } + + if (!is_array($array)) { + return array(); + } + + return array_keys($array); +} + +/** + * Reverses a variable. + * + * @param Twig_Environment $env A Twig_Environment instance + * @param array|Traversable|string $item An array, a Traversable instance, or a string + * @param bool $preserveKeys Whether to preserve key or not + * + * @return mixed The reversed input + */ +function twig_reverse_filter(Twig_Environment $env, $item, $preserveKeys = false) +{ + if (is_object($item) && $item instanceof Traversable) { + return array_reverse(iterator_to_array($item), $preserveKeys); + } + + if (is_array($item)) { + return array_reverse($item, $preserveKeys); + } + + if (null !== $charset = $env->getCharset()) { + $string = (string) $item; + + if ('UTF-8' != $charset) { + $item = twig_convert_encoding($string, 'UTF-8', $charset); + } + + preg_match_all('/./us', $item, $matches); + + $string = implode('', array_reverse($matches[0])); + + if ('UTF-8' != $charset) { + $string = twig_convert_encoding($string, $charset, 'UTF-8'); + } + + return $string; + } + + return strrev((string) $item); +} + +/** + * Sorts an array. + * + * @param array $array + * + * @return array + */ +function twig_sort_filter($array) +{ + asort($array); + + return $array; +} + +/* used internally */ +function twig_in_filter($value, $compare) +{ + if (is_array($compare)) { + return in_array($value, $compare, is_object($value) || is_resource($value)); + } elseif (is_string($compare) && (is_string($value) || is_int($value) || is_float($value))) { + return '' === $value || false !== strpos($compare, (string) $value); + } elseif ($compare instanceof Traversable) { + return in_array($value, iterator_to_array($compare, false), is_object($value) || is_resource($value)); + } + + return false; +} + +/** + * Escapes a string. + * + * @param Twig_Environment $env A Twig_Environment instance + * @param string $string The value to be escaped + * @param string $strategy The escaping strategy + * @param string $charset The charset + * @param bool $autoescape Whether the function is called by the auto-escaping feature (true) or by the developer (false) + * + * @return string + */ +function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false) +{ + if ($autoescape && $string instanceof Twig_Markup) { + return $string; + } + + if (!is_string($string)) { + if (is_object($string) && method_exists($string, '__toString')) { + $string = (string) $string; + } else { + return $string; + } + } + + if (null === $charset) { + $charset = $env->getCharset(); + } + + switch ($strategy) { + case 'html': + // see http://php.net/htmlspecialchars + + // Using a static variable to avoid initializing the array + // each time the function is called. Moving the declaration on the + // top of the function slow downs other escaping strategies. + static $htmlspecialcharsCharsets; + + if (null === $htmlspecialcharsCharsets) { + if (defined('HHVM_VERSION')) { + $htmlspecialcharsCharsets = array('utf-8' => true, 'UTF-8' => true); + } else { + $htmlspecialcharsCharsets = array( + 'ISO-8859-1' => true, 'ISO8859-1' => true, + 'ISO-8859-15' => true, 'ISO8859-15' => true, + 'utf-8' => true, 'UTF-8' => true, + 'CP866' => true, 'IBM866' => true, '866' => true, + 'CP1251' => true, 'WINDOWS-1251' => true, 'WIN-1251' => true, + '1251' => true, + 'CP1252' => true, 'WINDOWS-1252' => true, '1252' => true, + 'KOI8-R' => true, 'KOI8-RU' => true, 'KOI8R' => true, + 'BIG5' => true, '950' => true, + 'GB2312' => true, '936' => true, + 'BIG5-HKSCS' => true, + 'SHIFT_JIS' => true, 'SJIS' => true, '932' => true, + 'EUC-JP' => true, 'EUCJP' => true, + 'ISO8859-5' => true, 'ISO-8859-5' => true, 'MACROMAN' => true, + ); + } + } + + if (isset($htmlspecialcharsCharsets[$charset])) { + return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset); + } + + if (isset($htmlspecialcharsCharsets[strtoupper($charset)])) { + // cache the lowercase variant for future iterations + $htmlspecialcharsCharsets[$charset] = true; + + return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset); + } + + $string = twig_convert_encoding($string, 'UTF-8', $charset); + $string = htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); + + return twig_convert_encoding($string, $charset, 'UTF-8'); + + case 'js': + // escape all non-alphanumeric characters + // into their \xHH or \uHHHH representations + if ('UTF-8' != $charset) { + $string = twig_convert_encoding($string, 'UTF-8', $charset); + } + + if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) { + throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.'); + } + + $string = preg_replace_callback('#[^a-zA-Z0-9,\._]#Su', '_twig_escape_js_callback', $string); + + if ('UTF-8' != $charset) { + $string = twig_convert_encoding($string, $charset, 'UTF-8'); + } + + return $string; + + case 'css': + if ('UTF-8' != $charset) { + $string = twig_convert_encoding($string, 'UTF-8', $charset); + } + + if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) { + throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.'); + } + + $string = preg_replace_callback('#[^a-zA-Z0-9]#Su', '_twig_escape_css_callback', $string); + + if ('UTF-8' != $charset) { + $string = twig_convert_encoding($string, $charset, 'UTF-8'); + } + + return $string; + + case 'html_attr': + if ('UTF-8' != $charset) { + $string = twig_convert_encoding($string, 'UTF-8', $charset); + } + + if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) { + throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.'); + } + + $string = preg_replace_callback('#[^a-zA-Z0-9,\.\-_]#Su', '_twig_escape_html_attr_callback', $string); + + if ('UTF-8' != $charset) { + $string = twig_convert_encoding($string, $charset, 'UTF-8'); + } + + return $string; + + case 'url': + if (PHP_VERSION_ID < 50300) { + return str_replace('%7E', '~', rawurlencode($string)); + } + + return rawurlencode($string); + + default: + static $escapers; + + if (null === $escapers) { + $escapers = $env->getExtension('core')->getEscapers(); + } + + if (isset($escapers[$strategy])) { + return call_user_func($escapers[$strategy], $env, $string, $charset); + } + + $validStrategies = implode(', ', array_merge(array('html', 'js', 'url', 'css', 'html_attr'), array_keys($escapers))); + + throw new Twig_Error_Runtime(sprintf('Invalid escaping strategy "%s" (valid ones: %s).', $strategy, $validStrategies)); + } +} + +/* used internally */ +function twig_escape_filter_is_safe(Twig_Node $filterArgs) +{ + foreach ($filterArgs as $arg) { + if ($arg instanceof Twig_Node_Expression_Constant) { + return array($arg->getAttribute('value')); + } + + return array(); + } + + return array('html'); +} + +if (function_exists('mb_convert_encoding')) { + function twig_convert_encoding($string, $to, $from) + { + return mb_convert_encoding($string, $to, $from); + } +} elseif (function_exists('iconv')) { + function twig_convert_encoding($string, $to, $from) + { + return iconv($from, $to, $string); + } +} else { + function twig_convert_encoding($string, $to, $from) + { + throw new Twig_Error_Runtime('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).'); + } +} + +function _twig_escape_js_callback($matches) +{ + $char = $matches[0]; + + // \xHH + if (!isset($char[1])) { + return '\\x'.strtoupper(substr('00'.bin2hex($char), -2)); + } + + // \uHHHH + $char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8'); + + return '\\u'.strtoupper(substr('0000'.bin2hex($char), -4)); +} + +function _twig_escape_css_callback($matches) +{ + $char = $matches[0]; + + // \xHH + if (!isset($char[1])) { + $hex = ltrim(strtoupper(bin2hex($char)), '0'); + if (0 === strlen($hex)) { + $hex = '0'; + } + + return '\\'.$hex.' '; + } + + // \uHHHH + $char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8'); + + return '\\'.ltrim(strtoupper(bin2hex($char)), '0').' '; +} + +/** + * This function is adapted from code coming from Zend Framework. + * + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +function _twig_escape_html_attr_callback($matches) +{ + /* + * While HTML supports far more named entities, the lowest common denominator + * has become HTML5's XML Serialisation which is restricted to the those named + * entities that XML supports. Using HTML entities would result in this error: + * XML Parsing Error: undefined entity + */ + static $entityMap = array( + 34 => 'quot', /* quotation mark */ + 38 => 'amp', /* ampersand */ + 60 => 'lt', /* less-than sign */ + 62 => 'gt', /* greater-than sign */ + ); + + $chr = $matches[0]; + $ord = ord($chr); + + /* + * The following replaces characters undefined in HTML with the + * hex entity for the Unicode replacement character. + */ + if (($ord <= 0x1f && $chr != "\t" && $chr != "\n" && $chr != "\r") || ($ord >= 0x7f && $ord <= 0x9f)) { + return '�'; + } + + /* + * Check if the current character to escape has a name entity we should + * replace it with while grabbing the hex value of the character. + */ + if (strlen($chr) == 1) { + $hex = strtoupper(substr('00'.bin2hex($chr), -2)); + } else { + $chr = twig_convert_encoding($chr, 'UTF-16BE', 'UTF-8'); + $hex = strtoupper(substr('0000'.bin2hex($chr), -4)); + } + + $int = hexdec($hex); + if (array_key_exists($int, $entityMap)) { + return sprintf('&%s;', $entityMap[$int]); + } + + /* + * Per OWASP recommendations, we'll use hex entities for any other + * characters where a named entity does not exist. + */ + return sprintf('&#x%s;', $hex); +} + +// add multibyte extensions if possible +if (function_exists('mb_get_info')) { + /** + * Returns the length of a variable. + * + * @param Twig_Environment $env A Twig_Environment instance + * @param mixed $thing A variable + * + * @return int The length of the value + */ + function twig_length_filter(Twig_Environment $env, $thing) + { + return is_scalar($thing) ? mb_strlen($thing, $env->getCharset()) : count($thing); + } + + /** + * Converts a string to uppercase. + * + * @param Twig_Environment $env A Twig_Environment instance + * @param string $string A string + * + * @return string The uppercased string + */ + function twig_upper_filter(Twig_Environment $env, $string) + { + if (null !== ($charset = $env->getCharset())) { + return mb_strtoupper($string, $charset); + } + + return strtoupper($string); + } + + /** + * Converts a string to lowercase. + * + * @param Twig_Environment $env A Twig_Environment instance + * @param string $string A string + * + * @return string The lowercased string + */ + function twig_lower_filter(Twig_Environment $env, $string) + { + if (null !== ($charset = $env->getCharset())) { + return mb_strtolower($string, $charset); + } + + return strtolower($string); + } + + /** + * Returns a titlecased string. + * + * @param Twig_Environment $env A Twig_Environment instance + * @param string $string A string + * + * @return string The titlecased string + */ + function twig_title_string_filter(Twig_Environment $env, $string) + { + if (null !== ($charset = $env->getCharset())) { + return mb_convert_case($string, MB_CASE_TITLE, $charset); + } + + return ucwords(strtolower($string)); + } + + /** + * Returns a capitalized string. + * + * @param Twig_Environment $env A Twig_Environment instance + * @param string $string A string + * + * @return string The capitalized string + */ + function twig_capitalize_string_filter(Twig_Environment $env, $string) + { + if (null !== ($charset = $env->getCharset())) { + return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset). + mb_strtolower(mb_substr($string, 1, mb_strlen($string, $charset), $charset), $charset); + } + + return ucfirst(strtolower($string)); + } +} +// and byte fallback +else { + /** + * Returns the length of a variable. + * + * @param Twig_Environment $env A Twig_Environment instance + * @param mixed $thing A variable + * + * @return int The length of the value + */ + function twig_length_filter(Twig_Environment $env, $thing) + { + return is_scalar($thing) ? strlen($thing) : count($thing); + } + + /** + * Returns a titlecased string. + * + * @param Twig_Environment $env A Twig_Environment instance + * @param string $string A string + * + * @return string The titlecased string + */ + function twig_title_string_filter(Twig_Environment $env, $string) + { + return ucwords(strtolower($string)); + } + + /** + * Returns a capitalized string. + * + * @param Twig_Environment $env A Twig_Environment instance + * @param string $string A string + * + * @return string The capitalized string + */ + function twig_capitalize_string_filter(Twig_Environment $env, $string) + { + return ucfirst(strtolower($string)); + } +} + +/* used internally */ +function twig_ensure_traversable($seq) +{ + if ($seq instanceof Traversable || is_array($seq)) { + return $seq; + } + + return array(); +} + +/** + * Checks if a variable is empty. + * + *
+ * {# evaluates to true if the foo variable is null, false, or the empty string #}
+ * {% if foo is empty %}
+ *     {# ... #}
+ * {% endif %}
+ * 
+ * + * @param mixed $value A variable + * + * @return bool true if the value is empty, false otherwise + */ +function twig_test_empty($value) +{ + if ($value instanceof Countable) { + return 0 == count($value); + } + + return '' === $value || false === $value || null === $value || array() === $value; +} + +/** + * Checks if a variable is traversable. + * + *
+ * {# evaluates to true if the foo variable is an array or a traversable object #}
+ * {% if foo is traversable %}
+ *     {# ... #}
+ * {% endif %}
+ * 
+ * + * @param mixed $value A variable + * + * @return bool true if the value is traversable + */ +function twig_test_iterable($value) +{ + return $value instanceof Traversable || is_array($value); +} + +/** + * Renders a template. + * + * @param Twig_Environment $env + * @param array $context + * @param string|array $template The template to render or an array of templates to try consecutively + * @param array $variables The variables to pass to the template + * @param bool $withContext + * @param bool $ignoreMissing Whether to ignore missing templates or not + * @param bool $sandboxed Whether to sandbox the template or not + * + * @return string The rendered template + */ +function twig_include(Twig_Environment $env, $context, $template, $variables = array(), $withContext = true, $ignoreMissing = false, $sandboxed = false) +{ + $alreadySandboxed = false; + $sandbox = null; + if ($withContext) { + $variables = array_merge($context, $variables); + } + + if ($isSandboxed = $sandboxed && $env->hasExtension('sandbox')) { + $sandbox = $env->getExtension('sandbox'); + if (!$alreadySandboxed = $sandbox->isSandboxed()) { + $sandbox->enableSandbox(); + } + } + + $result = null; + try { + $result = $env->resolveTemplate($template)->render($variables); + } catch (Twig_Error_Loader $e) { + if (!$ignoreMissing) { + if ($isSandboxed && !$alreadySandboxed) { + $sandbox->disableSandbox(); + } + + throw $e; + } + } + + if ($isSandboxed && !$alreadySandboxed) { + $sandbox->disableSandbox(); + } + + return $result; +} + +/** + * Returns a template content without rendering it. + * + * @param string $name The template name + * @param bool $ignoreMissing Whether to ignore missing templates or not + * + * @return string The template source + */ +function twig_source(Twig_Environment $env, $name, $ignoreMissing = false) +{ + try { + return $env->getLoader()->getSource($name); + } catch (Twig_Error_Loader $e) { + if (!$ignoreMissing) { + throw $e; + } + } +} + +/** + * Provides the ability to get constants from instances as well as class/global constants. + * + * @param string $constant The name of the constant + * @param null|object $object The object to get the constant from + * + * @return string + */ +function twig_constant($constant, $object = null) +{ + if (null !== $object) { + $constant = get_class($object).'::'.$constant; + } + + return constant($constant); +} + +/** + * Batches item. + * + * @param array $items An array of items + * @param int $size The size of the batch + * @param mixed $fill A value used to fill missing items + * + * @return array + */ +function twig_array_batch($items, $size, $fill = null) +{ + if ($items instanceof Traversable) { + $items = iterator_to_array($items, false); + } + + $size = ceil($size); + + $result = array_chunk($items, $size, true); + + if (null !== $fill && !empty($result)) { + $last = count($result) - 1; + if ($fillCount = $size - count($result[$last])) { + $result[$last] = array_merge( + $result[$last], + array_fill(0, $fillCount, $fill) + ); + } + } + + return $result; +} diff --git a/system/libs/twig/Extension/CoreExtension.php b/system/libs/twig/Extension/CoreExtension.php deleted file mode 100755 index 6f66a44d..00000000 --- a/system/libs/twig/Extension/CoreExtension.php +++ /dev/null @@ -1,11 +0,0 @@ - $isDumpOutputHtmlSafe ? array('html') : array(), 'needs_context' => true, 'needs_environment' => true)), + ); + } + + /** + * Returns the name of the extension. + * + * @return string The extension name + */ + public function getName() + { + return 'debug'; + } +} + +function twig_var_dump(Twig_Environment $env, $context) +{ + if (!$env->isDebug()) { + return; + } + + ob_start(); + + $count = func_num_args(); + if (2 === $count) { + $vars = array(); + foreach ($context as $key => $value) { + if (!$value instanceof Twig_Template) { + $vars[$key] = $value; + } + } + + var_dump($vars); + } else { + for ($i = 2; $i < $count; ++$i) { + var_dump(func_get_arg($i)); + } + } + + return ob_get_clean(); +} diff --git a/system/libs/twig/Extension/DebugExtension.php b/system/libs/twig/Extension/DebugExtension.php deleted file mode 100755 index d196850c..00000000 --- a/system/libs/twig/Extension/DebugExtension.php +++ /dev/null @@ -1,11 +0,0 @@ -setDefaultStrategy($defaultStrategy); + } + + /** + * Returns the token parser instances to add to the existing list. + * + * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances + */ + public function getTokenParsers() + { + return array(new Twig_TokenParser_AutoEscape()); + } + + /** + * Returns the node visitor instances to add to the existing list. + * + * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances + */ + public function getNodeVisitors() + { + return array(new Twig_NodeVisitor_Escaper()); + } + + /** + * Returns a list of filters to add to the existing list. + * + * @return array An array of filters + */ + public function getFilters() + { + return array( + new Twig_SimpleFilter('raw', 'twig_raw_filter', array('is_safe' => array('all'))), + ); + } + + /** + * Sets the default strategy to use when not defined by the user. + * + * The strategy can be a valid PHP callback that takes the template + * "filename" as an argument and returns the strategy to use. + * + * @param mixed $defaultStrategy An escaping strategy + */ + public function setDefaultStrategy($defaultStrategy) + { + // for BC + if (true === $defaultStrategy) { + $defaultStrategy = 'html'; + } + + if ('filename' === $defaultStrategy) { + $defaultStrategy = array('Twig_FileExtensionEscapingStrategy', 'guess'); + } + + $this->defaultStrategy = $defaultStrategy; + } + + /** + * Gets the default strategy to use when not defined by the user. + * + * @param string $filename The template "filename" + * + * @return string The default strategy to use for the template + */ + public function getDefaultStrategy($filename) + { + // disable string callables to avoid calling a function named html or js, + // or any other upcoming escaping strategy + if (!is_string($this->defaultStrategy) && is_callable($this->defaultStrategy)) { + return call_user_func($this->defaultStrategy, $filename); + } + + return $this->defaultStrategy; + } + + /** + * Returns the name of the extension. + * + * @return string The extension name + */ + public function getName() + { + return 'escaper'; + } +} + +/** + * Marks a variable as being safe. + * + * @param string $string A PHP variable + * + * @return string + */ +function twig_raw_filter($string) +{ + return $string; +} diff --git a/system/libs/twig/Extension/EscaperExtension.php b/system/libs/twig/Extension/EscaperExtension.php deleted file mode 100755 index c6d60b5e..00000000 --- a/system/libs/twig/Extension/EscaperExtension.php +++ /dev/null @@ -1,11 +0,0 @@ -optimizers = $optimizers; + } + + /** + * {@inheritdoc} + */ + public function getNodeVisitors() + { + return array(new Twig_NodeVisitor_Optimizer($this->optimizers)); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'optimizer'; + } +} diff --git a/system/libs/twig/Extension/OptimizerExtension.php b/system/libs/twig/Extension/OptimizerExtension.php deleted file mode 100755 index 5aa6ea34..00000000 --- a/system/libs/twig/Extension/OptimizerExtension.php +++ /dev/null @@ -1,11 +0,0 @@ -actives = array($profile); + } + + public function enter(Twig_Profiler_Profile $profile) + { + $this->actives[0]->addProfile($profile); + array_unshift($this->actives, $profile); + } + + public function leave(Twig_Profiler_Profile $profile) + { + $profile->leave(); + array_shift($this->actives); + + if (1 === count($this->actives)) { + $this->actives[0]->leave(); + } + } + + /** + * {@inheritdoc} + */ + public function getNodeVisitors() + { + return array(new Twig_Profiler_NodeVisitor_Profiler($this->getName())); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'profiler'; + } +} diff --git a/system/libs/twig/Extension/ProfilerExtension.php b/system/libs/twig/Extension/ProfilerExtension.php deleted file mode 100755 index 58fb5bc8..00000000 --- a/system/libs/twig/Extension/ProfilerExtension.php +++ /dev/null @@ -1,11 +0,0 @@ -policy = $policy; + $this->sandboxedGlobally = $sandboxed; + } + + /** + * Returns the token parser instances to add to the existing list. + * + * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances + */ + public function getTokenParsers() + { + return array(new Twig_TokenParser_Sandbox()); + } + + /** + * Returns the node visitor instances to add to the existing list. + * + * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances + */ + public function getNodeVisitors() + { + return array(new Twig_NodeVisitor_Sandbox()); + } + + public function enableSandbox() + { + $this->sandboxed = true; + } + + public function disableSandbox() + { + $this->sandboxed = false; + } + + public function isSandboxed() + { + return $this->sandboxedGlobally || $this->sandboxed; + } + + public function isSandboxedGlobally() + { + return $this->sandboxedGlobally; + } + + public function setSecurityPolicy(Twig_Sandbox_SecurityPolicyInterface $policy) + { + $this->policy = $policy; + } + + public function getSecurityPolicy() + { + return $this->policy; + } + + public function checkSecurity($tags, $filters, $functions) + { + if ($this->isSandboxed()) { + $this->policy->checkSecurity($tags, $filters, $functions); + } + } + + public function checkMethodAllowed($obj, $method) + { + if ($this->isSandboxed()) { + $this->policy->checkMethodAllowed($obj, $method); + } + } + + public function checkPropertyAllowed($obj, $method) + { + if ($this->isSandboxed()) { + $this->policy->checkPropertyAllowed($obj, $method); + } + } + + public function ensureToStringAllowed($obj) + { + if ($this->isSandboxed() && is_object($obj)) { + $this->policy->checkMethodAllowed($obj, '__toString'); + } + + return $obj; + } + + /** + * Returns the name of the extension. + * + * @return string The extension name + */ + public function getName() + { + return 'sandbox'; + } +} diff --git a/system/libs/twig/Extension/SandboxExtension.php b/system/libs/twig/Extension/SandboxExtension.php deleted file mode 100755 index 0c244ffc..00000000 --- a/system/libs/twig/Extension/SandboxExtension.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Extension_Staging extends Twig_Extension +{ + protected $functions = array(); + protected $filters = array(); + protected $visitors = array(); + protected $tokenParsers = array(); + protected $globals = array(); + protected $tests = array(); + + public function addFunction($name, $function) + { + $this->functions[$name] = $function; + } + + /** + * {@inheritdoc} + */ + public function getFunctions() + { + return $this->functions; + } + + public function addFilter($name, $filter) + { + $this->filters[$name] = $filter; + } + + /** + * {@inheritdoc} + */ + public function getFilters() + { + return $this->filters; + } + + public function addNodeVisitor(Twig_NodeVisitorInterface $visitor) + { + $this->visitors[] = $visitor; + } + + /** + * {@inheritdoc} + */ + public function getNodeVisitors() + { + return $this->visitors; + } + + public function addTokenParser(Twig_TokenParserInterface $parser) + { + $this->tokenParsers[] = $parser; + } + + /** + * {@inheritdoc} + */ + public function getTokenParsers() + { + return $this->tokenParsers; + } + + public function addGlobal($name, $value) + { + $this->globals[$name] = $value; + } + + /** + * {@inheritdoc} + */ + public function getGlobals() + { + return $this->globals; + } + + public function addTest($name, $test) + { + $this->tests[$name] = $test; + } + + /** + * {@inheritdoc} + */ + public function getTests() + { + return $this->tests; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'staging'; + } +} diff --git a/system/libs/twig/Extension/StagingExtension.php b/system/libs/twig/Extension/StagingExtension.php deleted file mode 100755 index 62016fae..00000000 --- a/system/libs/twig/Extension/StagingExtension.php +++ /dev/null @@ -1,11 +0,0 @@ - true)), + ); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'string_loader'; + } +} + +/** + * Loads a template from a string. + * + *
+ * {{ include(template_from_string("Hello {{ name }}")) }}
+ * 
+ * + * @param Twig_Environment $env A Twig_Environment instance + * @param string $template A template as a string + * + * @return Twig_Template A Twig_Template instance + */ +function twig_template_from_string(Twig_Environment $env, $template) +{ + return $env->createTemplate($template); +} diff --git a/system/libs/twig/Extension/StringLoaderExtension.php b/system/libs/twig/Extension/StringLoaderExtension.php deleted file mode 100755 index 0474432d..00000000 --- a/system/libs/twig/Extension/StringLoaderExtension.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +interface Twig_ExtensionInterface +{ + /** + * Initializes the runtime environment. + * + * This is where you can load some file that contains filter functions for instance. + * + * @param Twig_Environment $environment The current Twig_Environment instance + */ + public function initRuntime(Twig_Environment $environment); + + /** + * Returns the token parser instances to add to the existing list. + * + * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances + */ + public function getTokenParsers(); + + /** + * Returns the node visitor instances to add to the existing list. + * + * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances + */ + public function getNodeVisitors(); + + /** + * Returns a list of filters to add to the existing list. + * + * @return array An array of filters + */ + public function getFilters(); + + /** + * Returns a list of tests to add to the existing list. + * + * @return array An array of tests + */ + public function getTests(); + + /** + * Returns a list of functions to add to the existing list. + * + * @return array An array of functions + */ + public function getFunctions(); + + /** + * Returns a list of operators to add to the existing list. + * + * @return array An array of operators + */ + public function getOperators(); + + /** + * Returns a list of global variables to add to the existing list. + * + * @return array An array of global variables + */ + public function getGlobals(); + + /** + * Returns the name of the extension. + * + * @return string The extension name + */ + public function getName(); +} diff --git a/system/libs/twig/FileExtensionEscapingStrategy.php b/system/libs/twig/FileExtensionEscapingStrategy.php index 189f8132..b1ace7dc 100755 --- a/system/libs/twig/FileExtensionEscapingStrategy.php +++ b/system/libs/twig/FileExtensionEscapingStrategy.php @@ -1,11 +1,49 @@ + */ +class Twig_FileExtensionEscapingStrategy +{ + /** + * Guesses the best autoescaping strategy based on the file name. + * + * @param string $filename The template file name + * + * @return string The escaping strategy name to use + */ + public static function guess($filename) { + if (!preg_match('{\.(js|css|txt)(?:\.[^/\\\\]+)?$}', $filename, $match)) { + return 'html'; + } + + switch ($match[1]) { + case 'js': + return 'js'; + + case 'css': + return 'css'; + + case 'txt': + return false; + } } } diff --git a/system/libs/twig/Filter.php b/system/libs/twig/Filter.php new file mode 100755 index 00000000..a6e923d3 --- /dev/null +++ b/system/libs/twig/Filter.php @@ -0,0 +1,82 @@ + + * + * @deprecated since 1.12 (to be removed in 2.0) + */ +abstract class Twig_Filter implements Twig_FilterInterface, Twig_FilterCallableInterface +{ + protected $options; + protected $arguments = array(); + + public function __construct(array $options = array()) + { + $this->options = array_merge(array( + 'needs_environment' => false, + 'needs_context' => false, + 'pre_escape' => null, + 'preserves_safety' => null, + 'callable' => null, + ), $options); + } + + public function setArguments($arguments) + { + $this->arguments = $arguments; + } + + public function getArguments() + { + return $this->arguments; + } + + public function needsEnvironment() + { + return $this->options['needs_environment']; + } + + public function needsContext() + { + return $this->options['needs_context']; + } + + public function getSafe(Twig_Node $filterArgs) + { + if (isset($this->options['is_safe'])) { + return $this->options['is_safe']; + } + + if (isset($this->options['is_safe_callback'])) { + return call_user_func($this->options['is_safe_callback'], $filterArgs); + } + } + + public function getPreservesSafety() + { + return $this->options['preserves_safety']; + } + + public function getPreEscape() + { + return $this->options['pre_escape']; + } + + public function getCallable() + { + return $this->options['callable']; + } +} diff --git a/system/libs/twig/Filter/Function.php b/system/libs/twig/Filter/Function.php new file mode 100755 index 00000000..45c14c76 --- /dev/null +++ b/system/libs/twig/Filter/Function.php @@ -0,0 +1,38 @@ + + * + * @deprecated since 1.12 (to be removed in 2.0) + */ +class Twig_Filter_Function extends Twig_Filter +{ + protected $function; + + public function __construct($function, array $options = array()) + { + $options['callable'] = $function; + + parent::__construct($options); + + $this->function = $function; + } + + public function compile() + { + return $this->function; + } +} diff --git a/system/libs/twig/Filter/Method.php b/system/libs/twig/Filter/Method.php new file mode 100755 index 00000000..f32435ff --- /dev/null +++ b/system/libs/twig/Filter/Method.php @@ -0,0 +1,40 @@ + + * + * @deprecated since 1.12 (to be removed in 2.0) + */ +class Twig_Filter_Method extends Twig_Filter +{ + protected $extension; + protected $method; + + public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array()) + { + $options['callable'] = array($extension, $method); + + parent::__construct($options); + + $this->extension = $extension; + $this->method = $method; + } + + public function compile() + { + return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method); + } +} diff --git a/system/libs/twig/Filter/Node.php b/system/libs/twig/Filter/Node.php new file mode 100755 index 00000000..efbcc29d --- /dev/null +++ b/system/libs/twig/Filter/Node.php @@ -0,0 +1,40 @@ + + * + * @deprecated since 1.12 (to be removed in 2.0) + */ +class Twig_Filter_Node extends Twig_Filter +{ + protected $class; + + public function __construct($class, array $options = array()) + { + parent::__construct($options); + + $this->class = $class; + } + + public function getClass() + { + return $this->class; + } + + public function compile() + { + } +} diff --git a/system/libs/twig/FilterCallableInterface.php b/system/libs/twig/FilterCallableInterface.php new file mode 100755 index 00000000..56798613 --- /dev/null +++ b/system/libs/twig/FilterCallableInterface.php @@ -0,0 +1,24 @@ + + * + * @deprecated since 1.12 (to be removed in 2.0) + */ +interface Twig_FilterCallableInterface +{ + public function getCallable(); +} diff --git a/system/libs/twig/FilterInterface.php b/system/libs/twig/FilterInterface.php new file mode 100755 index 00000000..6b0be0e3 --- /dev/null +++ b/system/libs/twig/FilterInterface.php @@ -0,0 +1,43 @@ + + * + * @deprecated since 1.12 (to be removed in 2.0) + */ +interface Twig_FilterInterface +{ + /** + * Compiles a filter. + * + * @return string The PHP code for the filter + */ + public function compile(); + + public function needsEnvironment(); + + public function needsContext(); + + public function getSafe(Twig_Node $filterArgs); + + public function getPreservesSafety(); + + public function getPreEscape(); + + public function setArguments($arguments); + + public function getArguments(); +} diff --git a/system/libs/twig/Function.php b/system/libs/twig/Function.php new file mode 100755 index 00000000..0f6ac97e --- /dev/null +++ b/system/libs/twig/Function.php @@ -0,0 +1,72 @@ + + * + * @deprecated since 1.12 (to be removed in 2.0) + */ +abstract class Twig_Function implements Twig_FunctionInterface, Twig_FunctionCallableInterface +{ + protected $options; + protected $arguments = array(); + + public function __construct(array $options = array()) + { + $this->options = array_merge(array( + 'needs_environment' => false, + 'needs_context' => false, + 'callable' => null, + ), $options); + } + + public function setArguments($arguments) + { + $this->arguments = $arguments; + } + + public function getArguments() + { + return $this->arguments; + } + + public function needsEnvironment() + { + return $this->options['needs_environment']; + } + + public function needsContext() + { + return $this->options['needs_context']; + } + + public function getSafe(Twig_Node $functionArgs) + { + if (isset($this->options['is_safe'])) { + return $this->options['is_safe']; + } + + if (isset($this->options['is_safe_callback'])) { + return call_user_func($this->options['is_safe_callback'], $functionArgs); + } + + return array(); + } + + public function getCallable() + { + return $this->options['callable']; + } +} diff --git a/system/libs/twig/Function/Function.php b/system/libs/twig/Function/Function.php new file mode 100755 index 00000000..e7f3845a --- /dev/null +++ b/system/libs/twig/Function/Function.php @@ -0,0 +1,39 @@ + + * + * @deprecated since 1.12 (to be removed in 2.0) + */ +class Twig_Function_Function extends Twig_Function +{ + protected $function; + + public function __construct($function, array $options = array()) + { + $options['callable'] = $function; + + parent::__construct($options); + + $this->function = $function; + } + + public function compile() + { + return $this->function; + } +} diff --git a/system/libs/twig/Function/Method.php b/system/libs/twig/Function/Method.php new file mode 100755 index 00000000..17a7bd87 --- /dev/null +++ b/system/libs/twig/Function/Method.php @@ -0,0 +1,41 @@ + + * + * @deprecated since 1.12 (to be removed in 2.0) + */ +class Twig_Function_Method extends Twig_Function +{ + protected $extension; + protected $method; + + public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array()) + { + $options['callable'] = array($extension, $method); + + parent::__construct($options); + + $this->extension = $extension; + $this->method = $method; + } + + public function compile() + { + return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method); + } +} diff --git a/system/libs/twig/Function/Node.php b/system/libs/twig/Function/Node.php new file mode 100755 index 00000000..550a379c --- /dev/null +++ b/system/libs/twig/Function/Node.php @@ -0,0 +1,40 @@ + + * + * @deprecated since 1.12 (to be removed in 2.0) + */ +class Twig_Function_Node extends Twig_Function +{ + protected $class; + + public function __construct($class, array $options = array()) + { + parent::__construct($options); + + $this->class = $class; + } + + public function getClass() + { + return $this->class; + } + + public function compile() + { + } +} diff --git a/system/libs/twig/FunctionCallableInterface.php b/system/libs/twig/FunctionCallableInterface.php new file mode 100755 index 00000000..87d795eb --- /dev/null +++ b/system/libs/twig/FunctionCallableInterface.php @@ -0,0 +1,24 @@ + + * + * @deprecated since 1.12 (to be removed in 2.0) + */ +interface Twig_FunctionCallableInterface +{ + public function getCallable(); +} diff --git a/system/libs/twig/FunctionInterface.php b/system/libs/twig/FunctionInterface.php new file mode 100755 index 00000000..f4492344 --- /dev/null +++ b/system/libs/twig/FunctionInterface.php @@ -0,0 +1,40 @@ + + * + * @deprecated since 1.12 (to be removed in 2.0) + */ +interface Twig_FunctionInterface +{ + /** + * Compiles a function. + * + * @return string The PHP code for the function + */ + public function compile(); + + public function needsEnvironment(); + + public function needsContext(); + + public function getSafe(Twig_Node $filterArgs); + + public function setArguments($arguments); + + public function getArguments(); +} diff --git a/system/libs/twig/Lexer.php b/system/libs/twig/Lexer.php index f141afe6..d03a1bf0 100755 --- a/system/libs/twig/Lexer.php +++ b/system/libs/twig/Lexer.php @@ -1,11 +1,407 @@ + */ +class Twig_Lexer implements Twig_LexerInterface +{ + protected $tokens; + protected $code; + protected $cursor; + protected $lineno; + protected $end; + protected $state; + protected $states; + protected $brackets; + protected $env; + protected $filename; + protected $options; + protected $regexes; + protected $position; + protected $positions; + protected $currentVarBlockLine; -if (\false) { - class Lexer extends \Twig_Lexer + const STATE_DATA = 0; + const STATE_BLOCK = 1; + const STATE_VAR = 2; + const STATE_STRING = 3; + const STATE_INTERPOLATION = 4; + + const REGEX_NAME = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A'; + const REGEX_NUMBER = '/[0-9]+(?:\.[0-9]+)?/A'; + const REGEX_STRING = '/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As'; + const REGEX_DQ_STRING_DELIM = '/"/A'; + const REGEX_DQ_STRING_PART = '/[^#"\\\\]*(?:(?:\\\\.|#(?!\{))[^#"\\\\]*)*/As'; + const PUNCTUATION = '()[]{}?:.,|'; + + public function __construct(Twig_Environment $env, array $options = array()) { + $this->env = $env; + + $this->options = array_merge(array( + 'tag_comment' => array('{#', '#}'), + 'tag_block' => array('{%', '%}'), + 'tag_variable' => array('{{', '}}'), + 'whitespace_trim' => '-', + 'interpolation' => array('#{', '}'), + ), $options); + + $this->regexes = array( + 'lex_var' => '/\s*'.preg_quote($this->options['whitespace_trim'].$this->options['tag_variable'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_variable'][1], '/').'/A', + 'lex_block' => '/\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')\n?/A', + 'lex_raw_data' => '/('.preg_quote($this->options['tag_block'][0].$this->options['whitespace_trim'], '/').'|'.preg_quote($this->options['tag_block'][0], '/').')\s*(?:end%s)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/s', + 'operator' => $this->getOperatorRegex(), + 'lex_comment' => '/(?:'.preg_quote($this->options['whitespace_trim'], '/').preg_quote($this->options['tag_comment'][1], '/').'\s*|'.preg_quote($this->options['tag_comment'][1], '/').')\n?/s', + 'lex_block_raw' => '/\s*(raw|verbatim)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/As', + 'lex_block_line' => '/\s*line\s+(\d+)\s*'.preg_quote($this->options['tag_block'][1], '/').'/As', + 'lex_tokens_start' => '/('.preg_quote($this->options['tag_variable'][0], '/').'|'.preg_quote($this->options['tag_block'][0], '/').'|'.preg_quote($this->options['tag_comment'][0], '/').')('.preg_quote($this->options['whitespace_trim'], '/').')?/s', + 'interpolation_start' => '/'.preg_quote($this->options['interpolation'][0], '/').'\s*/A', + 'interpolation_end' => '/\s*'.preg_quote($this->options['interpolation'][1], '/').'/A', + ); + } + + /** + * {@inheritdoc} + */ + public function tokenize($code, $filename = null) + { + if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) { + $mbEncoding = mb_internal_encoding(); + mb_internal_encoding('ASCII'); + } else { + $mbEncoding = null; + } + + $this->code = str_replace(array("\r\n", "\r"), "\n", $code); + $this->filename = $filename; + $this->cursor = 0; + $this->lineno = 1; + $this->end = strlen($this->code); + $this->tokens = array(); + $this->state = self::STATE_DATA; + $this->states = array(); + $this->brackets = array(); + $this->position = -1; + + // find all token starts in one go + preg_match_all($this->regexes['lex_tokens_start'], $this->code, $matches, PREG_OFFSET_CAPTURE); + $this->positions = $matches; + + while ($this->cursor < $this->end) { + // dispatch to the lexing functions depending + // on the current state + switch ($this->state) { + case self::STATE_DATA: + $this->lexData(); + break; + + case self::STATE_BLOCK: + $this->lexBlock(); + break; + + case self::STATE_VAR: + $this->lexVar(); + break; + + case self::STATE_STRING: + $this->lexString(); + break; + + case self::STATE_INTERPOLATION: + $this->lexInterpolation(); + break; + } + } + + $this->pushToken(Twig_Token::EOF_TYPE); + + if (!empty($this->brackets)) { + list($expect, $lineno) = array_pop($this->brackets); + throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename); + } + + if ($mbEncoding) { + mb_internal_encoding($mbEncoding); + } + + return new Twig_TokenStream($this->tokens, $this->filename); + } + + protected function lexData() + { + // if no matches are left we return the rest of the template as simple text token + if ($this->position == count($this->positions[0]) - 1) { + $this->pushToken(Twig_Token::TEXT_TYPE, substr($this->code, $this->cursor)); + $this->cursor = $this->end; + + return; + } + + // Find the first token after the current cursor + $position = $this->positions[0][++$this->position]; + while ($position[1] < $this->cursor) { + if ($this->position == count($this->positions[0]) - 1) { + return; + } + $position = $this->positions[0][++$this->position]; + } + + // push the template text first + $text = $textContent = substr($this->code, $this->cursor, $position[1] - $this->cursor); + if (isset($this->positions[2][$this->position][0])) { + $text = rtrim($text); + } + $this->pushToken(Twig_Token::TEXT_TYPE, $text); + $this->moveCursor($textContent.$position[0]); + + switch ($this->positions[1][$this->position][0]) { + case $this->options['tag_comment'][0]: + $this->lexComment(); + break; + + case $this->options['tag_block'][0]: + // raw data? + if (preg_match($this->regexes['lex_block_raw'], $this->code, $match, null, $this->cursor)) { + $this->moveCursor($match[0]); + $this->lexRawData($match[1]); + // {% line \d+ %} + } elseif (preg_match($this->regexes['lex_block_line'], $this->code, $match, null, $this->cursor)) { + $this->moveCursor($match[0]); + $this->lineno = (int) $match[1]; + } else { + $this->pushToken(Twig_Token::BLOCK_START_TYPE); + $this->pushState(self::STATE_BLOCK); + $this->currentVarBlockLine = $this->lineno; + } + break; + + case $this->options['tag_variable'][0]: + $this->pushToken(Twig_Token::VAR_START_TYPE); + $this->pushState(self::STATE_VAR); + $this->currentVarBlockLine = $this->lineno; + break; + } + } + + protected function lexBlock() + { + if (empty($this->brackets) && preg_match($this->regexes['lex_block'], $this->code, $match, null, $this->cursor)) { + $this->pushToken(Twig_Token::BLOCK_END_TYPE); + $this->moveCursor($match[0]); + $this->popState(); + } else { + $this->lexExpression(); + } + } + + protected function lexVar() + { + if (empty($this->brackets) && preg_match($this->regexes['lex_var'], $this->code, $match, null, $this->cursor)) { + $this->pushToken(Twig_Token::VAR_END_TYPE); + $this->moveCursor($match[0]); + $this->popState(); + } else { + $this->lexExpression(); + } + } + + protected function lexExpression() + { + // whitespace + if (preg_match('/\s+/A', $this->code, $match, null, $this->cursor)) { + $this->moveCursor($match[0]); + + if ($this->cursor >= $this->end) { + throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $this->state === self::STATE_BLOCK ? 'block' : 'variable'), $this->currentVarBlockLine, $this->filename); + } + } + + // operators + if (preg_match($this->regexes['operator'], $this->code, $match, null, $this->cursor)) { + $this->pushToken(Twig_Token::OPERATOR_TYPE, preg_replace('/\s+/', ' ', $match[0])); + $this->moveCursor($match[0]); + } + // names + elseif (preg_match(self::REGEX_NAME, $this->code, $match, null, $this->cursor)) { + $this->pushToken(Twig_Token::NAME_TYPE, $match[0]); + $this->moveCursor($match[0]); + } + // numbers + elseif (preg_match(self::REGEX_NUMBER, $this->code, $match, null, $this->cursor)) { + $number = (float) $match[0]; // floats + if (ctype_digit($match[0]) && $number <= PHP_INT_MAX) { + $number = (int) $match[0]; // integers lower than the maximum + } + $this->pushToken(Twig_Token::NUMBER_TYPE, $number); + $this->moveCursor($match[0]); + } + // punctuation + elseif (false !== strpos(self::PUNCTUATION, $this->code[$this->cursor])) { + // opening bracket + if (false !== strpos('([{', $this->code[$this->cursor])) { + $this->brackets[] = array($this->code[$this->cursor], $this->lineno); + } + // closing bracket + elseif (false !== strpos(')]}', $this->code[$this->cursor])) { + if (empty($this->brackets)) { + throw new Twig_Error_Syntax(sprintf('Unexpected "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename); + } + + list($expect, $lineno) = array_pop($this->brackets); + if ($this->code[$this->cursor] != strtr($expect, '([{', ')]}')) { + throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename); + } + } + + $this->pushToken(Twig_Token::PUNCTUATION_TYPE, $this->code[$this->cursor]); + ++$this->cursor; + } + // strings + elseif (preg_match(self::REGEX_STRING, $this->code, $match, null, $this->cursor)) { + $this->pushToken(Twig_Token::STRING_TYPE, stripcslashes(substr($match[0], 1, -1))); + $this->moveCursor($match[0]); + } + // opening double quoted string + elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) { + $this->brackets[] = array('"', $this->lineno); + $this->pushState(self::STATE_STRING); + $this->moveCursor($match[0]); + } + // unlexable + else { + throw new Twig_Error_Syntax(sprintf('Unexpected character "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename); + } + } + + protected function lexRawData($tag) + { + if (!preg_match(str_replace('%s', $tag, $this->regexes['lex_raw_data']), $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) { + throw new Twig_Error_Syntax(sprintf('Unexpected end of file: Unclosed "%s" block', $tag), $this->lineno, $this->filename); + } + + $text = substr($this->code, $this->cursor, $match[0][1] - $this->cursor); + $this->moveCursor($text.$match[0][0]); + + if (false !== strpos($match[1][0], $this->options['whitespace_trim'])) { + $text = rtrim($text); + } + + $this->pushToken(Twig_Token::TEXT_TYPE, $text); + } + + protected function lexComment() + { + if (!preg_match($this->regexes['lex_comment'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) { + throw new Twig_Error_Syntax('Unclosed comment', $this->lineno, $this->filename); + } + + $this->moveCursor(substr($this->code, $this->cursor, $match[0][1] - $this->cursor).$match[0][0]); + } + + protected function lexString() + { + if (preg_match($this->regexes['interpolation_start'], $this->code, $match, null, $this->cursor)) { + $this->brackets[] = array($this->options['interpolation'][0], $this->lineno); + $this->pushToken(Twig_Token::INTERPOLATION_START_TYPE); + $this->moveCursor($match[0]); + $this->pushState(self::STATE_INTERPOLATION); + } elseif (preg_match(self::REGEX_DQ_STRING_PART, $this->code, $match, null, $this->cursor) && strlen($match[0]) > 0) { + $this->pushToken(Twig_Token::STRING_TYPE, stripcslashes($match[0])); + $this->moveCursor($match[0]); + } elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) { + list($expect, $lineno) = array_pop($this->brackets); + if ($this->code[$this->cursor] != '"') { + throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename); + } + + $this->popState(); + ++$this->cursor; + } + } + + protected function lexInterpolation() + { + $bracket = end($this->brackets); + if ($this->options['interpolation'][0] === $bracket[0] && preg_match($this->regexes['interpolation_end'], $this->code, $match, null, $this->cursor)) { + array_pop($this->brackets); + $this->pushToken(Twig_Token::INTERPOLATION_END_TYPE); + $this->moveCursor($match[0]); + $this->popState(); + } else { + $this->lexExpression(); + } + } + + protected function pushToken($type, $value = '') + { + // do not push empty text tokens + if (Twig_Token::TEXT_TYPE === $type && '' === $value) { + return; + } + + $this->tokens[] = new Twig_Token($type, $value, $this->lineno); + } + + protected function moveCursor($text) + { + $this->cursor += strlen($text); + $this->lineno += substr_count($text, "\n"); + } + + protected function getOperatorRegex() + { + $operators = array_merge( + array('='), + array_keys($this->env->getUnaryOperators()), + array_keys($this->env->getBinaryOperators()) + ); + + $operators = array_combine($operators, array_map('strlen', $operators)); + arsort($operators); + + $regex = array(); + foreach ($operators as $operator => $length) { + // an operator that ends with a character must be followed by + // a whitespace or a parenthesis + if (ctype_alpha($operator[$length - 1])) { + $r = preg_quote($operator, '/').'(?=[\s()])'; + } else { + $r = preg_quote($operator, '/'); + } + + // an operator with a space can be any amount of whitespaces + $r = preg_replace('/\s+/', '\s+', $r); + + $regex[] = $r; + } + + return '/'.implode('|', $regex).'/A'; + } + + protected function pushState($state) + { + $this->states[] = $this->state; + $this->state = $state; + } + + protected function popState() + { + if (0 === count($this->states)) { + throw new Exception('Cannot pop state without a previous state'); + } + + $this->state = array_pop($this->states); } } diff --git a/system/libs/twig/LexerInterface.php b/system/libs/twig/LexerInterface.php new file mode 100755 index 00000000..24a94787 --- /dev/null +++ b/system/libs/twig/LexerInterface.php @@ -0,0 +1,32 @@ + + * + * @deprecated since 1.12 (to be removed in 3.0) + */ +interface Twig_LexerInterface +{ + /** + * Tokenizes a source code. + * + * @param string $code The source code + * @param string $filename A unique identifier for the source code + * + * @return Twig_TokenStream A token stream instance + * + * @throws Twig_Error_Syntax When the code is syntactically wrong + */ + public function tokenize($code, $filename = null); +} diff --git a/system/libs/twig/Loader/Array.php b/system/libs/twig/Loader/Array.php new file mode 100755 index 00000000..436edd81 --- /dev/null +++ b/system/libs/twig/Loader/Array.php @@ -0,0 +1,97 @@ + + */ +class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterface +{ + protected $templates = array(); + + /** + * Constructor. + * + * @param array $templates An array of templates (keys are the names, and values are the source code) + * + * @see Twig_Loader + */ + public function __construct(array $templates) + { + $this->templates = $templates; + } + + /** + * Adds or overrides a template. + * + * @param string $name The template name + * @param string $template The template source + */ + public function setTemplate($name, $template) + { + $this->templates[(string) $name] = $template; + } + + /** + * {@inheritdoc} + */ + public function getSource($name) + { + $name = (string) $name; + if (!isset($this->templates[$name])) { + throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); + } + + return $this->templates[$name]; + } + + /** + * {@inheritdoc} + */ + public function exists($name) + { + return isset($this->templates[(string) $name]); + } + + /** + * {@inheritdoc} + */ + public function getCacheKey($name) + { + $name = (string) $name; + if (!isset($this->templates[$name])) { + throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); + } + + return $this->templates[$name]; + } + + /** + * {@inheritdoc} + */ + public function isFresh($name, $time) + { + $name = (string) $name; + if (!isset($this->templates[$name])) { + throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); + } + + return true; + } +} diff --git a/system/libs/twig/Loader/ArrayLoader.php b/system/libs/twig/Loader/ArrayLoader.php deleted file mode 100755 index 9f5de3c7..00000000 --- a/system/libs/twig/Loader/ArrayLoader.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterface +{ + private $hasSourceCache = array(); + protected $loaders = array(); + + /** + * Constructor. + * + * @param Twig_LoaderInterface[] $loaders An array of loader instances + */ + public function __construct(array $loaders = array()) + { + foreach ($loaders as $loader) { + $this->addLoader($loader); + } + } + + /** + * Adds a loader instance. + * + * @param Twig_LoaderInterface $loader A Loader instance + */ + public function addLoader(Twig_LoaderInterface $loader) + { + $this->loaders[] = $loader; + $this->hasSourceCache = array(); + } + + /** + * {@inheritdoc} + */ + public function getSource($name) + { + $exceptions = array(); + foreach ($this->loaders as $loader) { + if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) { + continue; + } + + try { + return $loader->getSource($name); + } catch (Twig_Error_Loader $e) { + $exceptions[] = $e->getMessage(); + } + } + + throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(', ', $exceptions))); + } + + /** + * {@inheritdoc} + */ + public function exists($name) + { + $name = (string) $name; + + if (isset($this->hasSourceCache[$name])) { + return $this->hasSourceCache[$name]; + } + + foreach ($this->loaders as $loader) { + if ($loader instanceof Twig_ExistsLoaderInterface) { + if ($loader->exists($name)) { + return $this->hasSourceCache[$name] = true; + } + + continue; + } + + try { + $loader->getSource($name); + + return $this->hasSourceCache[$name] = true; + } catch (Twig_Error_Loader $e) { + } + } + + return $this->hasSourceCache[$name] = false; + } + + /** + * {@inheritdoc} + */ + public function getCacheKey($name) + { + $exceptions = array(); + foreach ($this->loaders as $loader) { + if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) { + continue; + } + + try { + return $loader->getCacheKey($name); + } catch (Twig_Error_Loader $e) { + $exceptions[] = get_class($loader).': '.$e->getMessage(); + } + } + + throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions))); + } + + /** + * {@inheritdoc} + */ + public function isFresh($name, $time) + { + $exceptions = array(); + foreach ($this->loaders as $loader) { + if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) { + continue; + } + + try { + return $loader->isFresh($name, $time); + } catch (Twig_Error_Loader $e) { + $exceptions[] = get_class($loader).': '.$e->getMessage(); + } + } + + throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions))); + } +} diff --git a/system/libs/twig/Loader/ChainLoader.php b/system/libs/twig/Loader/ChainLoader.php deleted file mode 100755 index 396eca52..00000000 --- a/system/libs/twig/Loader/ChainLoader.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderInterface +{ + /** Identifier of the main namespace. */ + const MAIN_NAMESPACE = '__main__'; + + protected $paths = array(); + protected $cache = array(); + + /** + * Constructor. + * + * @param string|array $paths A path or an array of paths where to look for templates + */ + public function __construct($paths = array()) + { + if ($paths) { + $this->setPaths($paths); + } + } + + /** + * Returns the paths to the templates. + * + * @param string $namespace A path namespace + * + * @return array The array of paths where to look for templates + */ + public function getPaths($namespace = self::MAIN_NAMESPACE) + { + return isset($this->paths[$namespace]) ? $this->paths[$namespace] : array(); + } + + /** + * Returns the path namespaces. + * + * The main namespace is always defined. + * + * @return array The array of defined namespaces + */ + public function getNamespaces() + { + return array_keys($this->paths); + } + + /** + * Sets the paths where templates are stored. + * + * @param string|array $paths A path or an array of paths where to look for templates + * @param string $namespace A path namespace + */ + public function setPaths($paths, $namespace = self::MAIN_NAMESPACE) + { + if (!is_array($paths)) { + $paths = array($paths); + } + + $this->paths[$namespace] = array(); + foreach ($paths as $path) { + $this->addPath($path, $namespace); + } + } + + /** + * Adds a path where templates are stored. + * + * @param string $path A path where to look for templates + * @param string $namespace A path name + * + * @throws Twig_Error_Loader + */ + public function addPath($path, $namespace = self::MAIN_NAMESPACE) + { + // invalidate the cache + $this->cache = array(); + + if (!is_dir($path)) { + throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path)); + } + + $this->paths[$namespace][] = rtrim($path, '/\\'); + } + + /** + * Prepends a path where templates are stored. + * + * @param string $path A path where to look for templates + * @param string $namespace A path name + * + * @throws Twig_Error_Loader + */ + public function prependPath($path, $namespace = self::MAIN_NAMESPACE) + { + // invalidate the cache + $this->cache = array(); + + if (!is_dir($path)) { + throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path)); + } + + $path = rtrim($path, '/\\'); + + if (!isset($this->paths[$namespace])) { + $this->paths[$namespace][] = $path; + } else { + array_unshift($this->paths[$namespace], $path); + } + } + + /** + * {@inheritdoc} + */ + public function getSource($name) + { + return file_get_contents($this->findTemplate($name)); + } + + /** + * {@inheritdoc} + */ + public function getCacheKey($name) + { + return $this->findTemplate($name); + } + + /** + * {@inheritdoc} + */ + public function exists($name) + { + $name = $this->normalizeName($name); + + if (isset($this->cache[$name])) { + return true; + } + + try { + $this->findTemplate($name); + + return true; + } catch (Twig_Error_Loader $exception) { + return false; + } + } + + /** + * {@inheritdoc} + */ + public function isFresh($name, $time) + { + return filemtime($this->findTemplate($name)) <= $time; + } + + protected function findTemplate($name) + { + $name = $this->normalizeName($name); + + if (isset($this->cache[$name])) { + return $this->cache[$name]; + } + + $this->validateName($name); + + list($namespace, $shortname) = $this->parseName($name); + + if (!isset($this->paths[$namespace])) { + throw new Twig_Error_Loader(sprintf('There are no registered paths for namespace "%s".', $namespace)); + } + + foreach ($this->paths[$namespace] as $path) { + if (is_file($path.'/'.$shortname)) { + if (false !== $realpath = realpath($path.'/'.$shortname)) { + return $this->cache[$name] = $realpath; + } + + return $this->cache[$name] = $path.'/'.$shortname; + } + } + + throw new Twig_Error_Loader(sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace]))); + } + + protected function parseName($name, $default = self::MAIN_NAMESPACE) + { + if (isset($name[0]) && '@' == $name[0]) { + if (false === $pos = strpos($name, '/')) { + throw new Twig_Error_Loader(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name)); + } + + $namespace = substr($name, 1, $pos - 1); + $shortname = substr($name, $pos + 1); + + return array($namespace, $shortname); + } + + return array($default, $name); + } + + protected function normalizeName($name) + { + return preg_replace('#/{2,}#', '/', strtr((string) $name, '\\', '/')); + } + + protected function validateName($name) + { + if (false !== strpos($name, "\0")) { + throw new Twig_Error_Loader('A template name cannot contain NUL bytes.'); + } + + $name = ltrim($name, '/'); + $parts = explode('/', $name); + $level = 0; + foreach ($parts as $part) { + if ('..' === $part) { + --$level; + } elseif ('.' !== $part) { + ++$level; + } + + if ($level < 0) { + throw new Twig_Error_Loader(sprintf('Looks like you try to load a template outside configured directories (%s).', $name)); + } + } + } +} diff --git a/system/libs/twig/Loader/FilesystemLoader.php b/system/libs/twig/Loader/FilesystemLoader.php deleted file mode 100755 index 83e8833f..00000000 --- a/system/libs/twig/Loader/FilesystemLoader.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Loader_String implements Twig_LoaderInterface, Twig_ExistsLoaderInterface +{ + /** + * {@inheritdoc} + */ + public function getSource($name) + { + return $name; + } + + /** + * {@inheritdoc} + */ + public function exists($name) + { + return true; + } + + /** + * {@inheritdoc} + */ + public function getCacheKey($name) + { + return $name; + } + + /** + * {@inheritdoc} + */ + public function isFresh($name, $time) + { + return true; + } +} diff --git a/system/libs/twig/LoaderInterface.php b/system/libs/twig/LoaderInterface.php new file mode 100755 index 00000000..544ea4e3 --- /dev/null +++ b/system/libs/twig/LoaderInterface.php @@ -0,0 +1,53 @@ + + */ +interface Twig_LoaderInterface +{ + /** + * Gets the source code of a template, given its name. + * + * @param string $name The name of the template to load + * + * @return string The template source code + * + * @throws Twig_Error_Loader When $name is not found + */ + public function getSource($name); + + /** + * Gets the cache key to use for the cache for a given template name. + * + * @param string $name The name of the template to load + * + * @return string The cache key + * + * @throws Twig_Error_Loader When $name is not found + */ + public function getCacheKey($name); + + /** + * Returns true if the template is still fresh. + * + * @param string $name The template name + * @param int $time Timestamp of the last modification time of the + * cached template + * + * @return bool true if the template is fresh, false otherwise + * + * @throws Twig_Error_Loader When $name is not found + */ + public function isFresh($name, $time); +} diff --git a/system/libs/twig/Markup.php b/system/libs/twig/Markup.php index 8dad0822..69871fcb 100755 --- a/system/libs/twig/Markup.php +++ b/system/libs/twig/Markup.php @@ -1,11 +1,37 @@ + */ +class Twig_Markup implements Countable +{ + protected $content; + protected $charset; -if (\false) { - class Markup extends \Twig_Markup + public function __construct($content, $charset) { + $this->content = (string) $content; + $this->charset = $charset; + } + + public function __toString() + { + return $this->content; + } + + public function count() + { + return function_exists('mb_get_info') ? mb_strlen($this->content, $this->charset) : strlen($this->content); } } diff --git a/system/libs/twig/Node.php b/system/libs/twig/Node.php new file mode 100755 index 00000000..1c78e7b2 --- /dev/null +++ b/system/libs/twig/Node.php @@ -0,0 +1,229 @@ + + */ +class Twig_Node implements Twig_NodeInterface +{ + protected $nodes; + protected $attributes; + protected $lineno; + protected $tag; + + /** + * Constructor. + * + * The nodes are automatically made available as properties ($this->node). + * The attributes are automatically made available as array items ($this['name']). + * + * @param array $nodes An array of named nodes + * @param array $attributes An array of attributes (should not be nodes) + * @param int $lineno The line number + * @param string $tag The tag name associated with the Node + */ + public function __construct(array $nodes = array(), array $attributes = array(), $lineno = 0, $tag = null) + { + $this->nodes = $nodes; + $this->attributes = $attributes; + $this->lineno = $lineno; + $this->tag = $tag; + } + + public function __toString() + { + $attributes = array(); + foreach ($this->attributes as $name => $value) { + $attributes[] = sprintf('%s: %s', $name, str_replace("\n", '', var_export($value, true))); + } + + $repr = array(get_class($this).'('.implode(', ', $attributes)); + + if (count($this->nodes)) { + foreach ($this->nodes as $name => $node) { + $len = strlen($name) + 4; + $noderepr = array(); + foreach (explode("\n", (string) $node) as $line) { + $noderepr[] = str_repeat(' ', $len).$line; + } + + $repr[] = sprintf(' %s: %s', $name, ltrim(implode("\n", $noderepr))); + } + + $repr[] = ')'; + } else { + $repr[0] .= ')'; + } + + return implode("\n", $repr); + } + + /** + * @deprecated since 1.16.1 (to be removed in 2.0) + */ + public function toXml($asDom = false) + { + $dom = new DOMDocument('1.0', 'UTF-8'); + $dom->formatOutput = true; + $dom->appendChild($xml = $dom->createElement('twig')); + + $xml->appendChild($node = $dom->createElement('node')); + $node->setAttribute('class', get_class($this)); + + foreach ($this->attributes as $name => $value) { + $node->appendChild($attribute = $dom->createElement('attribute')); + $attribute->setAttribute('name', $name); + $attribute->appendChild($dom->createTextNode($value)); + } + + foreach ($this->nodes as $name => $n) { + if (null === $n) { + continue; + } + + $child = $n->toXml(true)->getElementsByTagName('node')->item(0); + $child = $dom->importNode($child, true); + $child->setAttribute('name', $name); + + $node->appendChild($child); + } + + return $asDom ? $dom : $dom->saveXml(); + } + + public function compile(Twig_Compiler $compiler) + { + foreach ($this->nodes as $node) { + $node->compile($compiler); + } + } + + public function getLine() + { + return $this->lineno; + } + + public function getNodeTag() + { + return $this->tag; + } + + /** + * Returns true if the attribute is defined. + * + * @param string $name The attribute name + * + * @return bool true if the attribute is defined, false otherwise + */ + public function hasAttribute($name) + { + return array_key_exists($name, $this->attributes); + } + + /** + * Gets an attribute value by name. + * + * @param string $name + * + * @return mixed + */ + public function getAttribute($name) + { + if (!array_key_exists($name, $this->attributes)) { + throw new LogicException(sprintf('Attribute "%s" does not exist for Node "%s".', $name, get_class($this))); + } + + return $this->attributes[$name]; + } + + /** + * Sets an attribute by name to a value. + * + * @param string $name + * @param mixed $value + */ + public function setAttribute($name, $value) + { + $this->attributes[$name] = $value; + } + + /** + * Removes an attribute by name. + * + * @param string $name + */ + public function removeAttribute($name) + { + unset($this->attributes[$name]); + } + + /** + * Returns true if the node with the given name exists. + * + * @param string $name + * + * @return bool + */ + public function hasNode($name) + { + return array_key_exists($name, $this->nodes); + } + + /** + * Gets a node by name. + * + * @param string $name + * + * @return Twig_Node + */ + public function getNode($name) + { + if (!array_key_exists($name, $this->nodes)) { + throw new LogicException(sprintf('Node "%s" does not exist for Node "%s".', $name, get_class($this))); + } + + return $this->nodes[$name]; + } + + /** + * Sets a node. + * + * @param string $name + * @param Twig_Node $node + */ + public function setNode($name, $node = null) + { + $this->nodes[$name] = $node; + } + + /** + * Removes a node by name. + * + * @param string $name + */ + public function removeNode($name) + { + unset($this->nodes[$name]); + } + + public function count() + { + return count($this->nodes); + } + + public function getIterator() + { + return new ArrayIterator($this->nodes); + } +} diff --git a/system/libs/twig/Node/AutoEscape.php b/system/libs/twig/Node/AutoEscape.php new file mode 100755 index 00000000..fcabf903 --- /dev/null +++ b/system/libs/twig/Node/AutoEscape.php @@ -0,0 +1,39 @@ + + */ +class Twig_Node_AutoEscape extends Twig_Node +{ + public function __construct($value, Twig_NodeInterface $body, $lineno, $tag = 'autoescape') + { + parent::__construct(array('body' => $body), array('value' => $value), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + $compiler->subcompile($this->getNode('body')); + } +} diff --git a/system/libs/twig/Node/AutoEscapeNode.php b/system/libs/twig/Node/AutoEscapeNode.php deleted file mode 100755 index 9edb8e3d..00000000 --- a/system/libs/twig/Node/AutoEscapeNode.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Node_Block extends Twig_Node +{ + public function __construct($name, Twig_NodeInterface $body, $lineno, $tag = null) + { + parent::__construct(array('body' => $body), array('name' => $name), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->addDebugInfo($this) + ->write(sprintf("public function block_%s(\$context, array \$blocks = array())\n", $this->getAttribute('name')), "{\n") + ->indent() + ; + + $compiler + ->subcompile($this->getNode('body')) + ->outdent() + ->write("}\n\n") + ; + } +} diff --git a/system/libs/twig/Node/BlockNode.php b/system/libs/twig/Node/BlockNode.php deleted file mode 100755 index 27e30f98..00000000 --- a/system/libs/twig/Node/BlockNode.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Node_BlockReference extends Twig_Node implements Twig_NodeOutputInterface +{ + public function __construct($name, $lineno, $tag = null) + { + parent::__construct(array(), array('name' => $name), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->addDebugInfo($this) + ->write(sprintf("\$this->displayBlock('%s', \$context, \$blocks);\n", $this->getAttribute('name'))) + ; + } +} diff --git a/system/libs/twig/Node/BlockReferenceNode.php b/system/libs/twig/Node/BlockReferenceNode.php deleted file mode 100755 index 87bdd1f9..00000000 --- a/system/libs/twig/Node/BlockReferenceNode.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Node_Body extends Twig_Node +{ +} diff --git a/system/libs/twig/Node/BodyNode.php b/system/libs/twig/Node/BodyNode.php deleted file mode 100755 index 013bda3b..00000000 --- a/system/libs/twig/Node/BodyNode.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Node_CheckSecurity extends Twig_Node +{ + protected $usedFilters; + protected $usedTags; + protected $usedFunctions; + + public function __construct(array $usedFilters, array $usedTags, array $usedFunctions) + { + $this->usedFilters = $usedFilters; + $this->usedTags = $usedTags; + $this->usedFunctions = $usedFunctions; + + parent::__construct(); + } + + public function compile(Twig_Compiler $compiler) + { + $tags = $filters = $functions = array(); + foreach (array('tags', 'filters', 'functions') as $type) { + foreach ($this->{'used'.ucfirst($type)} as $name => $node) { + if ($node instanceof Twig_Node) { + ${$type}[$name] = $node->getLine(); + } else { + ${$type}[$node] = null; + } + } + } + + $compiler + ->write('$tags = ')->repr(array_filter($tags))->raw(";\n") + ->write('$filters = ')->repr(array_filter($filters))->raw(";\n") + ->write('$functions = ')->repr(array_filter($functions))->raw(";\n\n") + ->write("try {\n") + ->indent() + ->write("\$this->env->getExtension('sandbox')->checkSecurity(\n") + ->indent() + ->write(!$tags ? "array(),\n" : "array('".implode("', '", array_keys($tags))."'),\n") + ->write(!$filters ? "array(),\n" : "array('".implode("', '", array_keys($filters))."'),\n") + ->write(!$functions ? "array()\n" : "array('".implode("', '", array_keys($functions))."')\n") + ->outdent() + ->write(");\n") + ->outdent() + ->write("} catch (Twig_Sandbox_SecurityError \$e) {\n") + ->indent() + ->write("\$e->setTemplateFile(\$this->getTemplateName());\n\n") + ->write("if (\$e instanceof Twig_Sandbox_SecurityNotAllowedTagError && isset(\$tags[\$e->getTagName()])) {\n") + ->indent() + ->write("\$e->setTemplateLine(\$tags[\$e->getTagName()]);\n") + ->outdent() + ->write("} elseif (\$e instanceof Twig_Sandbox_SecurityNotAllowedFilterError && isset(\$filters[\$e->getFilterName()])) {\n") + ->indent() + ->write("\$e->setTemplateLine(\$filters[\$e->getFilterName()]);\n") + ->outdent() + ->write("} elseif (\$e instanceof Twig_Sandbox_SecurityNotAllowedFunctionError && isset(\$functions[\$e->getFunctionName()])) {\n") + ->indent() + ->write("\$e->setTemplateLine(\$functions[\$e->getFunctionName()]);\n") + ->outdent() + ->write("}\n\n") + ->write("throw \$e;\n") + ->outdent() + ->write("}\n\n") + ; + } +} diff --git a/system/libs/twig/Node/CheckSecurityNode.php b/system/libs/twig/Node/CheckSecurityNode.php deleted file mode 100755 index 6510086b..00000000 --- a/system/libs/twig/Node/CheckSecurityNode.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Node_Do extends Twig_Node +{ + public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null) + { + parent::__construct(array('expr' => $expr), array(), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->addDebugInfo($this) + ->write('') + ->subcompile($this->getNode('expr')) + ->raw(";\n") + ; + } +} diff --git a/system/libs/twig/Node/DoNode.php b/system/libs/twig/Node/DoNode.php deleted file mode 100755 index 1a972ff3..00000000 --- a/system/libs/twig/Node/DoNode.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Node_Embed extends Twig_Node_Include +{ + // we don't inject the module to avoid node visitors to traverse it twice (as it will be already visited in the main module) + public function __construct($filename, $index, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null) + { + parent::__construct(new Twig_Node_Expression_Constant('not_used', $lineno), $variables, $only, $ignoreMissing, $lineno, $tag); + + $this->setAttribute('filename', $filename); + $this->setAttribute('index', $index); + } + + protected function addGetTemplate(Twig_Compiler $compiler) + { + $compiler + ->write('$this->loadTemplate(') + ->string($this->getAttribute('filename')) + ->raw(', ') + ->repr($compiler->getFilename()) + ->raw(', ') + ->repr($this->getLine()) + ->raw(', ') + ->string($this->getAttribute('index')) + ->raw(')') + ; + } +} diff --git a/system/libs/twig/Node/EmbedNode.php b/system/libs/twig/Node/EmbedNode.php deleted file mode 100755 index 96094239..00000000 --- a/system/libs/twig/Node/EmbedNode.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +abstract class Twig_Node_Expression extends Twig_Node +{ +} diff --git a/system/libs/twig/Node/Expression/AbstractExpression.php b/system/libs/twig/Node/Expression/AbstractExpression.php deleted file mode 100755 index 1fdbea85..00000000 --- a/system/libs/twig/Node/Expression/AbstractExpression.php +++ /dev/null @@ -1,11 +0,0 @@ -index = -1; + foreach ($this->getKeyValuePairs() as $pair) { + if ($pair['key'] instanceof Twig_Node_Expression_Constant && ctype_digit((string) $pair['key']->getAttribute('value')) && $pair['key']->getAttribute('value') > $this->index) { + $this->index = $pair['key']->getAttribute('value'); + } + } + } + + public function getKeyValuePairs() + { + $pairs = array(); + + foreach (array_chunk($this->nodes, 2) as $pair) { + $pairs[] = array( + 'key' => $pair[0], + 'value' => $pair[1], + ); + } + + return $pairs; + } + + public function hasElement(Twig_Node_Expression $key) + { + foreach ($this->getKeyValuePairs() as $pair) { + // we compare the string representation of the keys + // to avoid comparing the line numbers which are not relevant here. + if ((string) $key == (string) $pair['key']) { + return true; + } + } + + return false; + } + + public function addElement(Twig_Node_Expression $value, Twig_Node_Expression $key = null) + { + if (null === $key) { + $key = new Twig_Node_Expression_Constant(++$this->index, $value->getLine()); + } + + array_push($this->nodes, $key, $value); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + $compiler->raw('array('); + $first = true; + foreach ($this->getKeyValuePairs() as $pair) { + if (!$first) { + $compiler->raw(', '); + } + $first = false; + + $compiler + ->subcompile($pair['key']) + ->raw(' => ') + ->subcompile($pair['value']) + ; + } + $compiler->raw(')'); + } +} diff --git a/system/libs/twig/Node/Expression/ArrayExpression.php b/system/libs/twig/Node/Expression/ArrayExpression.php deleted file mode 100755 index c4086579..00000000 --- a/system/libs/twig/Node/Expression/ArrayExpression.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('$context[') + ->string($this->getAttribute('name')) + ->raw(']') + ; + } +} diff --git a/system/libs/twig/Node/Expression/AssignNameExpression.php b/system/libs/twig/Node/Expression/AssignNameExpression.php deleted file mode 100755 index f1cd3a1a..00000000 --- a/system/libs/twig/Node/Expression/AssignNameExpression.php +++ /dev/null @@ -1,11 +0,0 @@ - $left, 'right' => $right), array(), $lineno); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->raw('(') + ->subcompile($this->getNode('left')) + ->raw(' ') + ; + $this->operator($compiler); + $compiler + ->raw(' ') + ->subcompile($this->getNode('right')) + ->raw(')') + ; + } + + abstract public function operator(Twig_Compiler $compiler); +} diff --git a/system/libs/twig/Node/Expression/Binary/AbstractBinary.php b/system/libs/twig/Node/Expression/Binary/AbstractBinary.php deleted file mode 100755 index 7462a8cf..00000000 --- a/system/libs/twig/Node/Expression/Binary/AbstractBinary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('+'); + } +} diff --git a/system/libs/twig/Node/Expression/Binary/AddBinary.php b/system/libs/twig/Node/Expression/Binary/AddBinary.php deleted file mode 100755 index 9bb84168..00000000 --- a/system/libs/twig/Node/Expression/Binary/AddBinary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('&&'); + } +} diff --git a/system/libs/twig/Node/Expression/Binary/AndBinary.php b/system/libs/twig/Node/Expression/Binary/AndBinary.php deleted file mode 100755 index 06034a60..00000000 --- a/system/libs/twig/Node/Expression/Binary/AndBinary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('&'); + } +} diff --git a/system/libs/twig/Node/Expression/Binary/BitwiseAndBinary.php b/system/libs/twig/Node/Expression/Binary/BitwiseAndBinary.php deleted file mode 100755 index da98ce06..00000000 --- a/system/libs/twig/Node/Expression/Binary/BitwiseAndBinary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('|'); + } +} diff --git a/system/libs/twig/Node/Expression/Binary/BitwiseOrBinary.php b/system/libs/twig/Node/Expression/Binary/BitwiseOrBinary.php deleted file mode 100755 index 16b434c4..00000000 --- a/system/libs/twig/Node/Expression/Binary/BitwiseOrBinary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('^'); + } +} diff --git a/system/libs/twig/Node/Expression/Binary/BitwiseXorBinary.php b/system/libs/twig/Node/Expression/Binary/BitwiseXorBinary.php deleted file mode 100755 index ee6a6880..00000000 --- a/system/libs/twig/Node/Expression/Binary/BitwiseXorBinary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('.'); + } +} diff --git a/system/libs/twig/Node/Expression/Binary/ConcatBinary.php b/system/libs/twig/Node/Expression/Binary/ConcatBinary.php deleted file mode 100755 index 29dfda34..00000000 --- a/system/libs/twig/Node/Expression/Binary/ConcatBinary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('/'); + } +} diff --git a/system/libs/twig/Node/Expression/Binary/DivBinary.php b/system/libs/twig/Node/Expression/Binary/DivBinary.php deleted file mode 100755 index 7326bde6..00000000 --- a/system/libs/twig/Node/Expression/Binary/DivBinary.php +++ /dev/null @@ -1,11 +0,0 @@ -getVarName(); + $right = $compiler->getVarName(); + $compiler + ->raw(sprintf('(is_string($%s = ', $left)) + ->subcompile($this->getNode('left')) + ->raw(sprintf(') && is_string($%s = ', $right)) + ->subcompile($this->getNode('right')) + ->raw(sprintf(') && (\'\' === $%2$s || $%2$s === substr($%1$s, -strlen($%2$s))))', $left, $right)) + ; + } + + public function operator(Twig_Compiler $compiler) + { + return $compiler->raw(''); + } +} diff --git a/system/libs/twig/Node/Expression/Binary/EndsWithBinary.php b/system/libs/twig/Node/Expression/Binary/EndsWithBinary.php deleted file mode 100755 index 9845ad16..00000000 --- a/system/libs/twig/Node/Expression/Binary/EndsWithBinary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('=='); + } +} diff --git a/system/libs/twig/Node/Expression/Binary/EqualBinary.php b/system/libs/twig/Node/Expression/Binary/EqualBinary.php deleted file mode 100755 index 97e4889a..00000000 --- a/system/libs/twig/Node/Expression/Binary/EqualBinary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('intval(floor('); + parent::compile($compiler); + $compiler->raw('))'); + } + + public function operator(Twig_Compiler $compiler) + { + return $compiler->raw('/'); + } +} diff --git a/system/libs/twig/Node/Expression/Binary/FloorDivBinary.php b/system/libs/twig/Node/Expression/Binary/FloorDivBinary.php deleted file mode 100755 index 9e8676f4..00000000 --- a/system/libs/twig/Node/Expression/Binary/FloorDivBinary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('>'); + } +} diff --git a/system/libs/twig/Node/Expression/Binary/GreaterBinary.php b/system/libs/twig/Node/Expression/Binary/GreaterBinary.php deleted file mode 100755 index 8dde9d2a..00000000 --- a/system/libs/twig/Node/Expression/Binary/GreaterBinary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('>='); + } +} diff --git a/system/libs/twig/Node/Expression/Binary/GreaterEqualBinary.php b/system/libs/twig/Node/Expression/Binary/GreaterEqualBinary.php deleted file mode 100755 index 455f6d84..00000000 --- a/system/libs/twig/Node/Expression/Binary/GreaterEqualBinary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('twig_in_filter(') + ->subcompile($this->getNode('left')) + ->raw(', ') + ->subcompile($this->getNode('right')) + ->raw(')') + ; + } + + public function operator(Twig_Compiler $compiler) + { + return $compiler->raw('in'); + } +} diff --git a/system/libs/twig/Node/Expression/Binary/InBinary.php b/system/libs/twig/Node/Expression/Binary/InBinary.php deleted file mode 100755 index 3e3cf2fe..00000000 --- a/system/libs/twig/Node/Expression/Binary/InBinary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('<'); + } +} diff --git a/system/libs/twig/Node/Expression/Binary/LessBinary.php b/system/libs/twig/Node/Expression/Binary/LessBinary.php deleted file mode 100755 index 84bcfe6b..00000000 --- a/system/libs/twig/Node/Expression/Binary/LessBinary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('<='); + } +} diff --git a/system/libs/twig/Node/Expression/Binary/LessEqualBinary.php b/system/libs/twig/Node/Expression/Binary/LessEqualBinary.php deleted file mode 100755 index 0f3018a4..00000000 --- a/system/libs/twig/Node/Expression/Binary/LessEqualBinary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('preg_match(') + ->subcompile($this->getNode('right')) + ->raw(', ') + ->subcompile($this->getNode('left')) + ->raw(')') + ; + } + + public function operator(Twig_Compiler $compiler) + { + return $compiler->raw(''); + } +} diff --git a/system/libs/twig/Node/Expression/Binary/MatchesBinary.php b/system/libs/twig/Node/Expression/Binary/MatchesBinary.php deleted file mode 100755 index d8b039a7..00000000 --- a/system/libs/twig/Node/Expression/Binary/MatchesBinary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('%'); + } +} diff --git a/system/libs/twig/Node/Expression/Binary/ModBinary.php b/system/libs/twig/Node/Expression/Binary/ModBinary.php deleted file mode 100755 index d39d5a46..00000000 --- a/system/libs/twig/Node/Expression/Binary/ModBinary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('*'); + } +} diff --git a/system/libs/twig/Node/Expression/Binary/MulBinary.php b/system/libs/twig/Node/Expression/Binary/MulBinary.php deleted file mode 100755 index 46d6d3f6..00000000 --- a/system/libs/twig/Node/Expression/Binary/MulBinary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('!='); + } +} diff --git a/system/libs/twig/Node/Expression/Binary/NotEqualBinary.php b/system/libs/twig/Node/Expression/Binary/NotEqualBinary.php deleted file mode 100755 index 09a546fd..00000000 --- a/system/libs/twig/Node/Expression/Binary/NotEqualBinary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('!twig_in_filter(') + ->subcompile($this->getNode('left')) + ->raw(', ') + ->subcompile($this->getNode('right')) + ->raw(')') + ; + } + + public function operator(Twig_Compiler $compiler) + { + return $compiler->raw('not in'); + } +} diff --git a/system/libs/twig/Node/Expression/Binary/NotInBinary.php b/system/libs/twig/Node/Expression/Binary/NotInBinary.php deleted file mode 100755 index 3ef89954..00000000 --- a/system/libs/twig/Node/Expression/Binary/NotInBinary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('||'); + } +} diff --git a/system/libs/twig/Node/Expression/Binary/OrBinary.php b/system/libs/twig/Node/Expression/Binary/OrBinary.php deleted file mode 100755 index f0311fd2..00000000 --- a/system/libs/twig/Node/Expression/Binary/OrBinary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('pow(') + ->subcompile($this->getNode('left')) + ->raw(', ') + ->subcompile($this->getNode('right')) + ->raw(')') + ; + } + + public function operator(Twig_Compiler $compiler) + { + return $compiler->raw('**'); + } +} diff --git a/system/libs/twig/Node/Expression/Binary/PowerBinary.php b/system/libs/twig/Node/Expression/Binary/PowerBinary.php deleted file mode 100755 index f4033cb1..00000000 --- a/system/libs/twig/Node/Expression/Binary/PowerBinary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('range(') + ->subcompile($this->getNode('left')) + ->raw(', ') + ->subcompile($this->getNode('right')) + ->raw(')') + ; + } + + public function operator(Twig_Compiler $compiler) + { + return $compiler->raw('..'); + } +} diff --git a/system/libs/twig/Node/Expression/Binary/RangeBinary.php b/system/libs/twig/Node/Expression/Binary/RangeBinary.php deleted file mode 100755 index 7ffe00a0..00000000 --- a/system/libs/twig/Node/Expression/Binary/RangeBinary.php +++ /dev/null @@ -1,11 +0,0 @@ -getVarName(); + $right = $compiler->getVarName(); + $compiler + ->raw(sprintf('(is_string($%s = ', $left)) + ->subcompile($this->getNode('left')) + ->raw(sprintf(') && is_string($%s = ', $right)) + ->subcompile($this->getNode('right')) + ->raw(sprintf(') && (\'\' === $%2$s || 0 === strpos($%1$s, $%2$s)))', $left, $right)) + ; + } + + public function operator(Twig_Compiler $compiler) + { + return $compiler->raw(''); + } +} diff --git a/system/libs/twig/Node/Expression/Binary/StartsWithBinary.php b/system/libs/twig/Node/Expression/Binary/StartsWithBinary.php deleted file mode 100755 index 3548ce47..00000000 --- a/system/libs/twig/Node/Expression/Binary/StartsWithBinary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('-'); + } +} diff --git a/system/libs/twig/Node/Expression/Binary/SubBinary.php b/system/libs/twig/Node/Expression/Binary/SubBinary.php deleted file mode 100755 index 1bd35cc3..00000000 --- a/system/libs/twig/Node/Expression/Binary/SubBinary.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Node_Expression_BlockReference extends Twig_Node_Expression +{ + public function __construct(Twig_NodeInterface $name, $asString = false, $lineno, $tag = null) + { + parent::__construct(array('name' => $name), array('as_string' => $asString, 'output' => false), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + if ($this->getAttribute('as_string')) { + $compiler->raw('(string) '); + } + + if ($this->getAttribute('output')) { + $compiler + ->addDebugInfo($this) + ->write('$this->displayBlock(') + ->subcompile($this->getNode('name')) + ->raw(", \$context, \$blocks);\n") + ; + } else { + $compiler + ->raw('$this->renderBlock(') + ->subcompile($this->getNode('name')) + ->raw(', $context, $blocks)') + ; + } + } +} diff --git a/system/libs/twig/Node/Expression/BlockReferenceExpression.php b/system/libs/twig/Node/Expression/BlockReferenceExpression.php deleted file mode 100755 index 4d4439e3..00000000 --- a/system/libs/twig/Node/Expression/BlockReferenceExpression.php +++ /dev/null @@ -1,11 +0,0 @@ -hasAttribute('callable') && $callable = $this->getAttribute('callable')) { + if (is_string($callable)) { + $compiler->raw($callable); + } elseif (is_array($callable) && $callable[0] instanceof Twig_ExtensionInterface) { + $compiler->raw(sprintf('$this->env->getExtension(\'%s\')->%s', $callable[0]->getName(), $callable[1])); + } else { + $type = ucfirst($this->getAttribute('type')); + $compiler->raw(sprintf('call_user_func_array($this->env->get%s(\'%s\')->getCallable(), array', $type, $this->getAttribute('name'))); + $closingParenthesis = true; + } + } else { + $compiler->raw($this->getAttribute('thing')->compile()); + } + + $this->compileArguments($compiler); + + if ($closingParenthesis) { + $compiler->raw(')'); + } + } + + protected function compileArguments(Twig_Compiler $compiler) + { + $compiler->raw('('); + + $first = true; + + if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) { + $compiler->raw('$this->env'); + $first = false; + } + + if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) { + if (!$first) { + $compiler->raw(', '); + } + $compiler->raw('$context'); + $first = false; + } + + if ($this->hasAttribute('arguments')) { + foreach ($this->getAttribute('arguments') as $argument) { + if (!$first) { + $compiler->raw(', '); + } + $compiler->string($argument); + $first = false; + } + } + + if ($this->hasNode('node')) { + if (!$first) { + $compiler->raw(', '); + } + $compiler->subcompile($this->getNode('node')); + $first = false; + } + + if ($this->hasNode('arguments') && null !== $this->getNode('arguments')) { + $callable = $this->hasAttribute('callable') ? $this->getAttribute('callable') : null; + + $arguments = $this->getArguments($callable, $this->getNode('arguments')); + + foreach ($arguments as $node) { + if (!$first) { + $compiler->raw(', '); + } + $compiler->subcompile($node); + $first = false; + } + } + + $compiler->raw(')'); + } + + protected function getArguments($callable, $arguments) + { + $callType = $this->getAttribute('type'); + $callName = $this->getAttribute('name'); + + $parameters = array(); + $named = false; + foreach ($arguments as $name => $node) { + if (!is_int($name)) { + $named = true; + $name = $this->normalizeName($name); + } elseif ($named) { + throw new Twig_Error_Syntax(sprintf('Positional arguments cannot be used after named arguments for %s "%s".', $callType, $callName)); + } + + $parameters[$name] = $node; + } + + $isVariadic = $this->hasAttribute('is_variadic') && $this->getAttribute('is_variadic'); + if (!$named && !$isVariadic) { + return $parameters; + } + + if (!$callable) { + if ($named) { + $message = sprintf('Named arguments are not supported for %s "%s".', $callType, $callName); + } else { + $message = sprintf('Arbitrary positional arguments are not supported for %s "%s".', $callType, $callName); + } + + throw new LogicException($message); + } + + // manage named arguments + if (is_array($callable)) { + $r = new ReflectionMethod($callable[0], $callable[1]); + } elseif (is_object($callable) && !$callable instanceof Closure) { + $r = new ReflectionObject($callable); + $r = $r->getMethod('__invoke'); + } elseif (is_string($callable) && false !== strpos($callable, '::')) { + $r = new ReflectionMethod($callable); + } else { + $r = new ReflectionFunction($callable); + } + + $definition = $r->getParameters(); + if ($this->hasNode('node')) { + array_shift($definition); + } + if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) { + array_shift($definition); + } + if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) { + array_shift($definition); + } + if ($this->hasAttribute('arguments') && null !== $this->getAttribute('arguments')) { + foreach ($this->getAttribute('arguments') as $argument) { + array_shift($definition); + } + } + if ($isVariadic) { + $argument = end($definition); + if ($argument && $argument->isArray() && $argument->isDefaultValueAvailable() && array() === $argument->getDefaultValue()) { + array_pop($definition); + } else { + $callableName = $r->name; + if ($r->getDeclaringClass()) { + $callableName = $r->getDeclaringClass()->name.'::'.$callableName; + } + + throw new LogicException(sprintf('The last parameter of "%s" for %s "%s" must be an array with default value, eg. "array $arg = array()".', $callableName, $callType, $callName)); + } + } + + $arguments = array(); + $names = array(); + $missingArguments = array(); + $optionalArguments = array(); + $pos = 0; + foreach ($definition as $param) { + $names[] = $name = $this->normalizeName($param->name); + + if (array_key_exists($name, $parameters)) { + if (array_key_exists($pos, $parameters)) { + throw new Twig_Error_Syntax(sprintf('Argument "%s" is defined twice for %s "%s".', $name, $callType, $callName)); + } + + if (!empty($missingArguments)) { + throw new Twig_Error_Syntax(sprintf( + 'Argument "%s" could not be assigned for %s "%s(%s)" because it is mapped to an internal PHP function which cannot determine default value for optional argument%s "%s".', + $name, $callType, $callName, implode(', ', $names), count($missingArguments) > 1 ? 's' : '', implode('", "', $missingArguments)) + ); + } + + $arguments = array_merge($arguments, $optionalArguments); + $arguments[] = $parameters[$name]; + unset($parameters[$name]); + $optionalArguments = array(); + } elseif (array_key_exists($pos, $parameters)) { + $arguments = array_merge($arguments, $optionalArguments); + $arguments[] = $parameters[$pos]; + unset($parameters[$pos]); + $optionalArguments = array(); + ++$pos; + } elseif ($param->isDefaultValueAvailable()) { + $optionalArguments[] = new Twig_Node_Expression_Constant($param->getDefaultValue(), -1); + } elseif ($param->isOptional()) { + if (empty($parameters)) { + break; + } else { + $missingArguments[] = $name; + } + } else { + throw new Twig_Error_Syntax(sprintf('Value for argument "%s" is required for %s "%s".', $name, $callType, $callName)); + } + } + + if ($isVariadic) { + $arbitraryArguments = new Twig_Node_Expression_Array(array(), -1); + foreach ($parameters as $key => $value) { + if (is_int($key)) { + $arbitraryArguments->addElement($value); + } else { + $arbitraryArguments->addElement($value, new Twig_Node_Expression_Constant($key, -1)); + } + unset($parameters[$key]); + } + + if ($arbitraryArguments->count()) { + $arguments = array_merge($arguments, $optionalArguments); + $arguments[] = $arbitraryArguments; + } + } + + if (!empty($parameters)) { + $unknownParameter = null; + foreach ($parameters as $parameter) { + if ($parameter instanceof Twig_Node) { + $unknownParameter = $parameter; + break; + } + } + + throw new Twig_Error_Syntax(sprintf( + 'Unknown argument%s "%s" for %s "%s(%s)".', + count($parameters) > 1 ? 's' : '', implode('", "', array_keys($parameters)), $callType, $callName, implode(', ', $names) + ), $unknownParameter ? $unknownParameter->getLine() : -1); + } + + return $arguments; + } + + protected function normalizeName($name) + { + return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), $name)); + } +} diff --git a/system/libs/twig/Node/Expression/CallExpression.php b/system/libs/twig/Node/Expression/CallExpression.php deleted file mode 100755 index f9af30b2..00000000 --- a/system/libs/twig/Node/Expression/CallExpression.php +++ /dev/null @@ -1,11 +0,0 @@ - $expr1, 'expr2' => $expr2, 'expr3' => $expr3), array(), $lineno); + } + + public function compile(Twig_Compiler $compiler) + { + $compiler + ->raw('((') + ->subcompile($this->getNode('expr1')) + ->raw(') ? (') + ->subcompile($this->getNode('expr2')) + ->raw(') : (') + ->subcompile($this->getNode('expr3')) + ->raw('))') + ; + } +} diff --git a/system/libs/twig/Node/Expression/ConditionalExpression.php b/system/libs/twig/Node/Expression/ConditionalExpression.php deleted file mode 100755 index 507d085e..00000000 --- a/system/libs/twig/Node/Expression/ConditionalExpression.php +++ /dev/null @@ -1,11 +0,0 @@ - $value), $lineno); + } + + public function compile(Twig_Compiler $compiler) + { + $compiler->repr($this->getAttribute('value')); + } +} diff --git a/system/libs/twig/Node/Expression/ConstantExpression.php b/system/libs/twig/Node/Expression/ConstantExpression.php deleted file mode 100755 index ef197ba0..00000000 --- a/system/libs/twig/Node/Expression/ConstantExpression.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Node_Expression_ExtensionReference extends Twig_Node_Expression +{ + public function __construct($name, $lineno, $tag = null) + { + parent::__construct(array(), array('name' => $name), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + $compiler->raw(sprintf("\$this->env->getExtension('%s')", $this->getAttribute('name'))); + } +} diff --git a/system/libs/twig/Node/Expression/Filter.php b/system/libs/twig/Node/Expression/Filter.php new file mode 100755 index 00000000..a906232e --- /dev/null +++ b/system/libs/twig/Node/Expression/Filter.php @@ -0,0 +1,39 @@ + $node, 'filter' => $filterName, 'arguments' => $arguments), array(), $lineno, $tag); + } + + public function compile(Twig_Compiler $compiler) + { + $name = $this->getNode('filter')->getAttribute('value'); + $filter = $compiler->getEnvironment()->getFilter($name); + + $this->setAttribute('name', $name); + $this->setAttribute('type', 'filter'); + $this->setAttribute('thing', $filter); + $this->setAttribute('needs_environment', $filter->needsEnvironment()); + $this->setAttribute('needs_context', $filter->needsContext()); + $this->setAttribute('arguments', $filter->getArguments()); + if ($filter instanceof Twig_FilterCallableInterface || $filter instanceof Twig_SimpleFilter) { + $this->setAttribute('callable', $filter->getCallable()); + } + if ($filter instanceof Twig_SimpleFilter) { + $this->setAttribute('is_variadic', $filter->isVariadic()); + } + + $this->compileCallable($compiler); + } +} diff --git a/system/libs/twig/Node/Expression/Filter/Default.php b/system/libs/twig/Node/Expression/Filter/Default.php new file mode 100755 index 00000000..1827c888 --- /dev/null +++ b/system/libs/twig/Node/Expression/Filter/Default.php @@ -0,0 +1,43 @@ + + * {{ var.foo|default('foo item on var is not defined') }} + * + * + * @author Fabien Potencier + */ +class Twig_Node_Expression_Filter_Default extends Twig_Node_Expression_Filter +{ + public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null) + { + $default = new Twig_Node_Expression_Filter($node, new Twig_Node_Expression_Constant('default', $node->getLine()), $arguments, $node->getLine()); + + if ('default' === $filterName->getAttribute('value') && ($node instanceof Twig_Node_Expression_Name || $node instanceof Twig_Node_Expression_GetAttr)) { + $test = new Twig_Node_Expression_Test_Defined(clone $node, 'defined', new Twig_Node(), $node->getLine()); + $false = count($arguments) ? $arguments->getNode(0) : new Twig_Node_Expression_Constant('', $node->getLine()); + + $node = new Twig_Node_Expression_Conditional($test, $default, $false, $node->getLine()); + } else { + $node = $default; + } + + parent::__construct($node, $filterName, $arguments, $lineno, $tag); + } + + public function compile(Twig_Compiler $compiler) + { + $compiler->subcompile($this->getNode('node')); + } +} diff --git a/system/libs/twig/Node/Expression/Filter/DefaultFilter.php b/system/libs/twig/Node/Expression/Filter/DefaultFilter.php deleted file mode 100755 index 2eb573c2..00000000 --- a/system/libs/twig/Node/Expression/Filter/DefaultFilter.php +++ /dev/null @@ -1,11 +0,0 @@ - $arguments), array('name' => $name), $lineno); + } + + public function compile(Twig_Compiler $compiler) + { + $name = $this->getAttribute('name'); + $function = $compiler->getEnvironment()->getFunction($name); + + $this->setAttribute('name', $name); + $this->setAttribute('type', 'function'); + $this->setAttribute('thing', $function); + $this->setAttribute('needs_environment', $function->needsEnvironment()); + $this->setAttribute('needs_context', $function->needsContext()); + $this->setAttribute('arguments', $function->getArguments()); + if ($function instanceof Twig_FunctionCallableInterface || $function instanceof Twig_SimpleFunction) { + $this->setAttribute('callable', $function->getCallable()); + } + if ($function instanceof Twig_SimpleFunction) { + $this->setAttribute('is_variadic', $function->isVariadic()); + } + + $this->compileCallable($compiler); + } +} diff --git a/system/libs/twig/Node/Expression/FunctionExpression.php b/system/libs/twig/Node/Expression/FunctionExpression.php deleted file mode 100755 index 9ab002fb..00000000 --- a/system/libs/twig/Node/Expression/FunctionExpression.php +++ /dev/null @@ -1,11 +0,0 @@ - $node, 'attribute' => $attribute, 'arguments' => $arguments), array('type' => $type, 'is_defined_test' => false, 'ignore_strict_check' => false, 'disable_c_ext' => false), $lineno); + } + + public function compile(Twig_Compiler $compiler) + { + if (function_exists('twig_template_get_attributes') && !$this->getAttribute('disable_c_ext')) { + $compiler->raw('twig_template_get_attributes($this, '); + } else { + $compiler->raw('$this->getAttribute('); + } + + if ($this->getAttribute('ignore_strict_check')) { + $this->getNode('node')->setAttribute('ignore_strict_check', true); + } + + $compiler->subcompile($this->getNode('node')); + + $compiler->raw(', ')->subcompile($this->getNode('attribute')); + + // only generate optional arguments when needed (to make generated code more readable) + $needFourth = $this->getAttribute('ignore_strict_check'); + $needThird = $needFourth || $this->getAttribute('is_defined_test'); + $needSecond = $needThird || Twig_Template::ANY_CALL !== $this->getAttribute('type'); + $needFirst = $needSecond || null !== $this->getNode('arguments'); + + if ($needFirst) { + if (null !== $this->getNode('arguments')) { + $compiler->raw(', ')->subcompile($this->getNode('arguments')); + } else { + $compiler->raw(', array()'); + } + } + + if ($needSecond) { + $compiler->raw(', ')->repr($this->getAttribute('type')); + } + + if ($needThird) { + $compiler->raw(', ')->repr($this->getAttribute('is_defined_test')); + } + + if ($needFourth) { + $compiler->raw(', ')->repr($this->getAttribute('ignore_strict_check')); + } + + $compiler->raw(')'); + } +} diff --git a/system/libs/twig/Node/Expression/GetAttrExpression.php b/system/libs/twig/Node/Expression/GetAttrExpression.php deleted file mode 100755 index 6e810c7f..00000000 --- a/system/libs/twig/Node/Expression/GetAttrExpression.php +++ /dev/null @@ -1,11 +0,0 @@ - $node, 'arguments' => $arguments), array('method' => $method, 'safe' => false), $lineno); + + if ($node instanceof Twig_Node_Expression_Name) { + $node->setAttribute('always_defined', true); + } + } + + public function compile(Twig_Compiler $compiler) + { + $compiler + ->subcompile($this->getNode('node')) + ->raw('->') + ->raw($this->getAttribute('method')) + ->raw('(') + ; + $first = true; + foreach ($this->getNode('arguments')->getKeyValuePairs() as $pair) { + if (!$first) { + $compiler->raw(', '); + } + $first = false; + + $compiler->subcompile($pair['value']); + } + $compiler->raw(')'); + } +} diff --git a/system/libs/twig/Node/Expression/MethodCallExpression.php b/system/libs/twig/Node/Expression/MethodCallExpression.php deleted file mode 100755 index e751c31b..00000000 --- a/system/libs/twig/Node/Expression/MethodCallExpression.php +++ /dev/null @@ -1,11 +0,0 @@ - '$this', + '_context' => '$context', + '_charset' => '$this->env->getCharset()', + ); + + public function __construct($name, $lineno) + { + parent::__construct(array(), array('name' => $name, 'is_defined_test' => false, 'ignore_strict_check' => false, 'always_defined' => false), $lineno); + } + + public function compile(Twig_Compiler $compiler) + { + $name = $this->getAttribute('name'); + + $compiler->addDebugInfo($this); + + if ($this->getAttribute('is_defined_test')) { + if ($this->isSpecial()) { + $compiler->repr(true); + } else { + $compiler->raw('array_key_exists(')->repr($name)->raw(', $context)'); + } + } elseif ($this->isSpecial()) { + $compiler->raw($this->specialVars[$name]); + } elseif ($this->getAttribute('always_defined')) { + $compiler + ->raw('$context[') + ->string($name) + ->raw(']') + ; + } else { + // remove the non-PHP 5.4 version when PHP 5.3 support is dropped + // as the non-optimized version is just a workaround for slow ternary operator + // when the context has a lot of variables + if (PHP_VERSION_ID >= 50400) { + // PHP 5.4 ternary operator performance was optimized + $compiler + ->raw('(isset($context[') + ->string($name) + ->raw(']) ? $context[') + ->string($name) + ->raw('] : ') + ; + + if ($this->getAttribute('ignore_strict_check') || !$compiler->getEnvironment()->isStrictVariables()) { + $compiler->raw('null)'); + } else { + $compiler->raw('$this->getContext($context, ')->string($name)->raw('))'); + } + } else { + $compiler + ->raw('$this->getContext($context, ') + ->string($name) + ; + + if ($this->getAttribute('ignore_strict_check')) { + $compiler->raw(', true'); + } + + $compiler + ->raw(')') + ; + } + } + } + + public function isSpecial() + { + return isset($this->specialVars[$this->getAttribute('name')]); + } + + public function isSimple() + { + return !$this->isSpecial() && !$this->getAttribute('is_defined_test'); + } +} diff --git a/system/libs/twig/Node/Expression/NameExpression.php b/system/libs/twig/Node/Expression/NameExpression.php deleted file mode 100755 index c32981af..00000000 --- a/system/libs/twig/Node/Expression/NameExpression.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Node_Expression_Parent extends Twig_Node_Expression +{ + public function __construct($name, $lineno, $tag = null) + { + parent::__construct(array(), array('output' => false, 'name' => $name), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + if ($this->getAttribute('output')) { + $compiler + ->addDebugInfo($this) + ->write('$this->displayParentBlock(') + ->string($this->getAttribute('name')) + ->raw(", \$context, \$blocks);\n") + ; + } else { + $compiler + ->raw('$this->renderParentBlock(') + ->string($this->getAttribute('name')) + ->raw(', $context, $blocks)') + ; + } + } +} diff --git a/system/libs/twig/Node/Expression/ParentExpression.php b/system/libs/twig/Node/Expression/ParentExpression.php deleted file mode 100755 index 70b0e360..00000000 --- a/system/libs/twig/Node/Expression/ParentExpression.php +++ /dev/null @@ -1,11 +0,0 @@ - $name), $lineno); + } + + public function compile(Twig_Compiler $compiler) + { + $compiler + ->raw('$_') + ->raw($this->getAttribute('name')) + ->raw('_') + ; + } +} diff --git a/system/libs/twig/Node/Expression/TempNameExpression.php b/system/libs/twig/Node/Expression/TempNameExpression.php deleted file mode 100755 index 178b6dec..00000000 --- a/system/libs/twig/Node/Expression/TempNameExpression.php +++ /dev/null @@ -1,11 +0,0 @@ - $node, 'arguments' => $arguments), array('name' => $name), $lineno); + } + + public function compile(Twig_Compiler $compiler) + { + $name = $this->getAttribute('name'); + $test = $compiler->getEnvironment()->getTest($name); + + $this->setAttribute('name', $name); + $this->setAttribute('type', 'test'); + $this->setAttribute('thing', $test); + if ($test instanceof Twig_TestCallableInterface || $test instanceof Twig_SimpleTest) { + $this->setAttribute('callable', $test->getCallable()); + } + if ($test instanceof Twig_SimpleTest) { + $this->setAttribute('is_variadic', $test->isVariadic()); + } + + $this->compileCallable($compiler); + } +} diff --git a/system/libs/twig/Node/Expression/Test/Constant.php b/system/libs/twig/Node/Expression/Test/Constant.php new file mode 100755 index 00000000..de55f5f5 --- /dev/null +++ b/system/libs/twig/Node/Expression/Test/Constant.php @@ -0,0 +1,46 @@ + + * {% if post.status is constant('Post::PUBLISHED') %} + * the status attribute is exactly the same as Post::PUBLISHED + * {% endif %} + * + * + * @author Fabien Potencier + */ +class Twig_Node_Expression_Test_Constant extends Twig_Node_Expression_Test +{ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->raw('(') + ->subcompile($this->getNode('node')) + ->raw(' === constant(') + ; + + if ($this->getNode('arguments')->hasNode(1)) { + $compiler + ->raw('get_class(') + ->subcompile($this->getNode('arguments')->getNode(1)) + ->raw(')."::".') + ; + } + + $compiler + ->subcompile($this->getNode('arguments')->getNode(0)) + ->raw('))') + ; + } +} diff --git a/system/libs/twig/Node/Expression/Test/ConstantTest.php b/system/libs/twig/Node/Expression/Test/ConstantTest.php deleted file mode 100755 index b54b2801..00000000 --- a/system/libs/twig/Node/Expression/Test/ConstantTest.php +++ /dev/null @@ -1,11 +0,0 @@ - + * {# defined works with variable names and variable attributes #} + * {% if foo is defined %} + * {# ... #} + * {% endif %} + * + * + * @author Fabien Potencier + */ +class Twig_Node_Expression_Test_Defined extends Twig_Node_Expression_Test +{ + public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno) + { + parent::__construct($node, $name, $arguments, $lineno); + + if ($node instanceof Twig_Node_Expression_Name) { + $node->setAttribute('is_defined_test', true); + } elseif ($node instanceof Twig_Node_Expression_GetAttr) { + $node->setAttribute('is_defined_test', true); + + $this->changeIgnoreStrictCheck($node); + } else { + throw new Twig_Error_Syntax('The "defined" test only works with simple variables', $this->getLine()); + } + } + + protected function changeIgnoreStrictCheck(Twig_Node_Expression_GetAttr $node) + { + $node->setAttribute('ignore_strict_check', true); + + if ($node->getNode('node') instanceof Twig_Node_Expression_GetAttr) { + $this->changeIgnoreStrictCheck($node->getNode('node')); + } + } + + public function compile(Twig_Compiler $compiler) + { + $compiler->subcompile($this->getNode('node')); + } +} diff --git a/system/libs/twig/Node/Expression/Test/DefinedTest.php b/system/libs/twig/Node/Expression/Test/DefinedTest.php deleted file mode 100755 index 69c36a0b..00000000 --- a/system/libs/twig/Node/Expression/Test/DefinedTest.php +++ /dev/null @@ -1,11 +0,0 @@ - + * {% if loop.index is divisible by(3) %} + * + * + * @author Fabien Potencier + */ +class Twig_Node_Expression_Test_Divisibleby extends Twig_Node_Expression_Test +{ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->raw('(0 == ') + ->subcompile($this->getNode('node')) + ->raw(' % ') + ->subcompile($this->getNode('arguments')->getNode(0)) + ->raw(')') + ; + } +} diff --git a/system/libs/twig/Node/Expression/Test/DivisiblebyTest.php b/system/libs/twig/Node/Expression/Test/DivisiblebyTest.php deleted file mode 100755 index e9d91004..00000000 --- a/system/libs/twig/Node/Expression/Test/DivisiblebyTest.php +++ /dev/null @@ -1,11 +0,0 @@ - + * {{ var is even }} + * + * + * @author Fabien Potencier + */ +class Twig_Node_Expression_Test_Even extends Twig_Node_Expression_Test +{ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->raw('(') + ->subcompile($this->getNode('node')) + ->raw(' % 2 == 0') + ->raw(')') + ; + } +} diff --git a/system/libs/twig/Node/Expression/Test/EvenTest.php b/system/libs/twig/Node/Expression/Test/EvenTest.php deleted file mode 100755 index feb3a89c..00000000 --- a/system/libs/twig/Node/Expression/Test/EvenTest.php +++ /dev/null @@ -1,11 +0,0 @@ - + * {{ var is none }} + * + * + * @author Fabien Potencier + */ +class Twig_Node_Expression_Test_Null extends Twig_Node_Expression_Test +{ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->raw('(null === ') + ->subcompile($this->getNode('node')) + ->raw(')') + ; + } +} diff --git a/system/libs/twig/Node/Expression/Test/NullTest.php b/system/libs/twig/Node/Expression/Test/NullTest.php deleted file mode 100755 index 2263b1b2..00000000 --- a/system/libs/twig/Node/Expression/Test/NullTest.php +++ /dev/null @@ -1,11 +0,0 @@ - + * {{ var is odd }} + * + * + * @author Fabien Potencier + */ +class Twig_Node_Expression_Test_Odd extends Twig_Node_Expression_Test +{ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->raw('(') + ->subcompile($this->getNode('node')) + ->raw(' % 2 == 1') + ->raw(')') + ; + } +} diff --git a/system/libs/twig/Node/Expression/Test/OddTest.php b/system/libs/twig/Node/Expression/Test/OddTest.php deleted file mode 100755 index 86ddb224..00000000 --- a/system/libs/twig/Node/Expression/Test/OddTest.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Node_Expression_Test_Sameas extends Twig_Node_Expression_Test +{ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->raw('(') + ->subcompile($this->getNode('node')) + ->raw(' === ') + ->subcompile($this->getNode('arguments')->getNode(0)) + ->raw(')') + ; + } +} diff --git a/system/libs/twig/Node/Expression/Test/SameasTest.php b/system/libs/twig/Node/Expression/Test/SameasTest.php deleted file mode 100755 index 26a8f0ea..00000000 --- a/system/libs/twig/Node/Expression/Test/SameasTest.php +++ /dev/null @@ -1,11 +0,0 @@ - $node), array(), $lineno); + } + + public function compile(Twig_Compiler $compiler) + { + $compiler->raw(' '); + $this->operator($compiler); + $compiler->subcompile($this->getNode('node')); + } + + abstract public function operator(Twig_Compiler $compiler); +} diff --git a/system/libs/twig/Node/Expression/Unary/AbstractUnary.php b/system/libs/twig/Node/Expression/Unary/AbstractUnary.php deleted file mode 100755 index 7d998559..00000000 --- a/system/libs/twig/Node/Expression/Unary/AbstractUnary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('-'); + } +} diff --git a/system/libs/twig/Node/Expression/Unary/NegUnary.php b/system/libs/twig/Node/Expression/Unary/NegUnary.php deleted file mode 100755 index 344b1216..00000000 --- a/system/libs/twig/Node/Expression/Unary/NegUnary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('!'); + } +} diff --git a/system/libs/twig/Node/Expression/Unary/NotUnary.php b/system/libs/twig/Node/Expression/Unary/NotUnary.php deleted file mode 100755 index 79c24628..00000000 --- a/system/libs/twig/Node/Expression/Unary/NotUnary.php +++ /dev/null @@ -1,11 +0,0 @@ -raw('+'); + } +} diff --git a/system/libs/twig/Node/Expression/Unary/PosUnary.php b/system/libs/twig/Node/Expression/Unary/PosUnary.php deleted file mode 100755 index 24d88ccb..00000000 --- a/system/libs/twig/Node/Expression/Unary/PosUnary.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Node_Flush extends Twig_Node +{ + public function __construct($lineno, $tag) + { + parent::__construct(array(), array(), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->addDebugInfo($this) + ->write("flush();\n") + ; + } +} diff --git a/system/libs/twig/Node/FlushNode.php b/system/libs/twig/Node/FlushNode.php deleted file mode 100755 index c06306e1..00000000 --- a/system/libs/twig/Node/FlushNode.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Node_For extends Twig_Node +{ + protected $loop; + + public function __construct(Twig_Node_Expression_AssignName $keyTarget, Twig_Node_Expression_AssignName $valueTarget, Twig_Node_Expression $seq, Twig_Node_Expression $ifexpr = null, Twig_NodeInterface $body, Twig_NodeInterface $else = null, $lineno, $tag = null) + { + $body = new Twig_Node(array($body, $this->loop = new Twig_Node_ForLoop($lineno, $tag))); + + if (null !== $ifexpr) { + $body = new Twig_Node_If(new Twig_Node(array($ifexpr, $body)), null, $lineno, $tag); + } + + parent::__construct(array('key_target' => $keyTarget, 'value_target' => $valueTarget, 'seq' => $seq, 'body' => $body, 'else' => $else), array('with_loop' => true, 'ifexpr' => null !== $ifexpr), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->addDebugInfo($this) + // the (array) cast bypasses a PHP 5.2.6 bug + ->write("\$context['_parent'] = (array) \$context;\n") + ->write("\$context['_seq'] = twig_ensure_traversable(") + ->subcompile($this->getNode('seq')) + ->raw(");\n") + ; + + if (null !== $this->getNode('else')) { + $compiler->write("\$context['_iterated'] = false;\n"); + } + + if ($this->getAttribute('with_loop')) { + $compiler + ->write("\$context['loop'] = array(\n") + ->write(" 'parent' => \$context['_parent'],\n") + ->write(" 'index0' => 0,\n") + ->write(" 'index' => 1,\n") + ->write(" 'first' => true,\n") + ->write(");\n") + ; + + if (!$this->getAttribute('ifexpr')) { + $compiler + ->write("if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_seq'] instanceof Countable)) {\n") + ->indent() + ->write("\$length = count(\$context['_seq']);\n") + ->write("\$context['loop']['revindex0'] = \$length - 1;\n") + ->write("\$context['loop']['revindex'] = \$length;\n") + ->write("\$context['loop']['length'] = \$length;\n") + ->write("\$context['loop']['last'] = 1 === \$length;\n") + ->outdent() + ->write("}\n") + ; + } + } + + $this->loop->setAttribute('else', null !== $this->getNode('else')); + $this->loop->setAttribute('with_loop', $this->getAttribute('with_loop')); + $this->loop->setAttribute('ifexpr', $this->getAttribute('ifexpr')); + + $compiler + ->write("foreach (\$context['_seq'] as ") + ->subcompile($this->getNode('key_target')) + ->raw(' => ') + ->subcompile($this->getNode('value_target')) + ->raw(") {\n") + ->indent() + ->subcompile($this->getNode('body')) + ->outdent() + ->write("}\n") + ; + + if (null !== $this->getNode('else')) { + $compiler + ->write("if (!\$context['_iterated']) {\n") + ->indent() + ->subcompile($this->getNode('else')) + ->outdent() + ->write("}\n") + ; + } + + $compiler->write("\$_parent = \$context['_parent'];\n"); + + // remove some "private" loop variables (needed for nested loops) + $compiler->write('unset($context[\'_seq\'], $context[\'_iterated\'], $context[\''.$this->getNode('key_target')->getAttribute('name').'\'], $context[\''.$this->getNode('value_target')->getAttribute('name').'\'], $context[\'_parent\'], $context[\'loop\']);'."\n"); + + // keep the values set in the inner context for variables defined in the outer context + $compiler->write("\$context = array_intersect_key(\$context, \$_parent) + \$_parent;\n"); + } +} diff --git a/system/libs/twig/Node/ForLoop.php b/system/libs/twig/Node/ForLoop.php new file mode 100755 index 00000000..d330283e --- /dev/null +++ b/system/libs/twig/Node/ForLoop.php @@ -0,0 +1,55 @@ + + */ +class Twig_Node_ForLoop extends Twig_Node +{ + public function __construct($lineno, $tag = null) + { + parent::__construct(array(), array('with_loop' => false, 'ifexpr' => false, 'else' => false), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + if ($this->getAttribute('else')) { + $compiler->write("\$context['_iterated'] = true;\n"); + } + + if ($this->getAttribute('with_loop')) { + $compiler + ->write("++\$context['loop']['index0'];\n") + ->write("++\$context['loop']['index'];\n") + ->write("\$context['loop']['first'] = false;\n") + ; + + if (!$this->getAttribute('ifexpr')) { + $compiler + ->write("if (isset(\$context['loop']['length'])) {\n") + ->indent() + ->write("--\$context['loop']['revindex0'];\n") + ->write("--\$context['loop']['revindex'];\n") + ->write("\$context['loop']['last'] = 0 === \$context['loop']['revindex0'];\n") + ->outdent() + ->write("}\n") + ; + } + } + } +} diff --git a/system/libs/twig/Node/ForLoopNode.php b/system/libs/twig/Node/ForLoopNode.php deleted file mode 100755 index e8e3936c..00000000 --- a/system/libs/twig/Node/ForLoopNode.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Node_If extends Twig_Node +{ + public function __construct(Twig_NodeInterface $tests, Twig_NodeInterface $else = null, $lineno, $tag = null) + { + parent::__construct(array('tests' => $tests, 'else' => $else), array(), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + $compiler->addDebugInfo($this); + for ($i = 0, $count = count($this->getNode('tests')); $i < $count; $i += 2) { + if ($i > 0) { + $compiler + ->outdent() + ->write('} elseif (') + ; + } else { + $compiler + ->write('if (') + ; + } + + $compiler + ->subcompile($this->getNode('tests')->getNode($i)) + ->raw(") {\n") + ->indent() + ->subcompile($this->getNode('tests')->getNode($i + 1)) + ; + } + + if ($this->hasNode('else') && null !== $this->getNode('else')) { + $compiler + ->outdent() + ->write("} else {\n") + ->indent() + ->subcompile($this->getNode('else')) + ; + } + + $compiler + ->outdent() + ->write("}\n"); + } +} diff --git a/system/libs/twig/Node/IfNode.php b/system/libs/twig/Node/IfNode.php deleted file mode 100755 index 2710ead0..00000000 --- a/system/libs/twig/Node/IfNode.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Node_Import extends Twig_Node +{ + public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $var, $lineno, $tag = null) + { + parent::__construct(array('expr' => $expr, 'var' => $var), array(), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->addDebugInfo($this) + ->write('') + ->subcompile($this->getNode('var')) + ->raw(' = ') + ; + + if ($this->getNode('expr') instanceof Twig_Node_Expression_Name && '_self' === $this->getNode('expr')->getAttribute('name')) { + $compiler->raw('$this'); + } else { + $compiler + ->raw('$this->loadTemplate(') + ->subcompile($this->getNode('expr')) + ->raw(', ') + ->repr($compiler->getFilename()) + ->raw(', ') + ->repr($this->getLine()) + ->raw(')') + ; + } + + $compiler->raw(";\n"); + } +} diff --git a/system/libs/twig/Node/ImportNode.php b/system/libs/twig/Node/ImportNode.php deleted file mode 100755 index 0bc23f33..00000000 --- a/system/libs/twig/Node/ImportNode.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Node_Include extends Twig_Node implements Twig_NodeOutputInterface +{ + public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null) + { + parent::__construct(array('expr' => $expr, 'variables' => $variables), array('only' => (bool) $only, 'ignore_missing' => (bool) $ignoreMissing), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + $compiler->addDebugInfo($this); + + if ($this->getAttribute('ignore_missing')) { + $compiler + ->write("try {\n") + ->indent() + ; + } + + $this->addGetTemplate($compiler); + + $compiler->raw('->display('); + + $this->addTemplateArguments($compiler); + + $compiler->raw(");\n"); + + if ($this->getAttribute('ignore_missing')) { + $compiler + ->outdent() + ->write("} catch (Twig_Error_Loader \$e) {\n") + ->indent() + ->write("// ignore missing template\n") + ->outdent() + ->write("}\n\n") + ; + } + } + + protected function addGetTemplate(Twig_Compiler $compiler) + { + $compiler + ->write('$this->loadTemplate(') + ->subcompile($this->getNode('expr')) + ->raw(', ') + ->repr($compiler->getFilename()) + ->raw(', ') + ->repr($this->getLine()) + ->raw(')') + ; + } + + protected function addTemplateArguments(Twig_Compiler $compiler) + { + if (null === $this->getNode('variables')) { + $compiler->raw(false === $this->getAttribute('only') ? '$context' : 'array()'); + } elseif (false === $this->getAttribute('only')) { + $compiler + ->raw('array_merge($context, ') + ->subcompile($this->getNode('variables')) + ->raw(')') + ; + } else { + $compiler->subcompile($this->getNode('variables')); + } + } +} diff --git a/system/libs/twig/Node/IncludeNode.php b/system/libs/twig/Node/IncludeNode.php deleted file mode 100755 index d557efee..00000000 --- a/system/libs/twig/Node/IncludeNode.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Node_Macro extends Twig_Node +{ + const VARARGS_NAME = 'varargs'; + + public function __construct($name, Twig_NodeInterface $body, Twig_NodeInterface $arguments, $lineno, $tag = null) + { + foreach ($arguments as $argumentName => $argument) { + if (self::VARARGS_NAME === $argumentName) { + throw new Twig_Error_Syntax(sprintf('The argument "%s" in macro "%s" cannot be defined because the variable "%s" is reserved for arbitrary arguments', self::VARARGS_NAME, $name, self::VARARGS_NAME), $argument->getLine()); + } + } + + parent::__construct(array('body' => $body, 'arguments' => $arguments), array('name' => $name), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->addDebugInfo($this) + ->write(sprintf('public function get%s(', $this->getAttribute('name'))) + ; + + $count = count($this->getNode('arguments')); + $pos = 0; + foreach ($this->getNode('arguments') as $name => $default) { + $compiler + ->raw('$__'.$name.'__ = ') + ->subcompile($default) + ; + + if (++$pos < $count) { + $compiler->raw(', '); + } + } + + if (PHP_VERSION_ID >= 50600) { + if ($count) { + $compiler->raw(', '); + } + + $compiler->raw('...$__varargs__'); + } + + $compiler + ->raw(")\n") + ->write("{\n") + ->indent() + ; + + $compiler + ->write("\$context = \$this->env->mergeGlobals(array(\n") + ->indent() + ; + + foreach ($this->getNode('arguments') as $name => $default) { + $compiler + ->addIndentation() + ->string($name) + ->raw(' => $__'.$name.'__') + ->raw(",\n") + ; + } + + $compiler + ->addIndentation() + ->string(self::VARARGS_NAME) + ->raw(' => ') + ; + + if (PHP_VERSION_ID >= 50600) { + $compiler->raw("\$__varargs__,\n"); + } else { + $compiler + ->raw('func_num_args() > ') + ->repr($count) + ->raw(' ? array_slice(func_get_args(), ') + ->repr($count) + ->raw(") : array(),\n") + ; + } + + $compiler + ->outdent() + ->write("));\n\n") + ->write("\$blocks = array();\n\n") + ->write("ob_start();\n") + ->write("try {\n") + ->indent() + ->subcompile($this->getNode('body')) + ->outdent() + ->write("} catch (Exception \$e) {\n") + ->indent() + ->write("ob_end_clean();\n\n") + ->write("throw \$e;\n") + ->outdent() + ->write("}\n\n") + ->write("return ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset());\n") + ->outdent() + ->write("}\n\n") + ; + } +} diff --git a/system/libs/twig/Node/MacroNode.php b/system/libs/twig/Node/MacroNode.php deleted file mode 100755 index 5752c6c8..00000000 --- a/system/libs/twig/Node/MacroNode.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Node_Module extends Twig_Node +{ + public function __construct(Twig_NodeInterface $body, Twig_Node_Expression $parent = null, Twig_NodeInterface $blocks, Twig_NodeInterface $macros, Twig_NodeInterface $traits, $embeddedTemplates, $filename) + { + // embedded templates are set as attributes so that they are only visited once by the visitors + parent::__construct(array( + 'parent' => $parent, + 'body' => $body, + 'blocks' => $blocks, + 'macros' => $macros, + 'traits' => $traits, + 'display_start' => new Twig_Node(), + 'display_end' => new Twig_Node(), + 'constructor_start' => new Twig_Node(), + 'constructor_end' => new Twig_Node(), + 'class_end' => new Twig_Node(), + ), array( + 'filename' => $filename, + 'index' => null, + 'embedded_templates' => $embeddedTemplates, + ), 1); + } + + public function setIndex($index) + { + $this->setAttribute('index', $index); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + $this->compileTemplate($compiler); + + foreach ($this->getAttribute('embedded_templates') as $template) { + $compiler->subcompile($template); + } + } + + protected function compileTemplate(Twig_Compiler $compiler) + { + if (!$this->getAttribute('index')) { + $compiler->write('compileClassHeader($compiler); + + if ( + count($this->getNode('blocks')) + || count($this->getNode('traits')) + || null === $this->getNode('parent') + || $this->getNode('parent') instanceof Twig_Node_Expression_Constant + || count($this->getNode('constructor_start')) + || count($this->getNode('constructor_end')) + ) { + $this->compileConstructor($compiler); + } + + $this->compileGetParent($compiler); + + $this->compileDisplay($compiler); + + $compiler->subcompile($this->getNode('blocks')); + + $this->compileMacros($compiler); + + $this->compileGetTemplateName($compiler); + + $this->compileIsTraitable($compiler); + + $this->compileDebugInfo($compiler); + + $this->compileClassFooter($compiler); + } + + protected function compileGetParent(Twig_Compiler $compiler) + { + if (null === $parent = $this->getNode('parent')) { + return; + } + + $compiler + ->write("protected function doGetParent(array \$context)\n", "{\n") + ->indent() + ->addDebugInfo($parent) + ->write('return ') + ; + + if ($parent instanceof Twig_Node_Expression_Constant) { + $compiler->subcompile($parent); + } else { + $compiler + ->raw('$this->loadTemplate(') + ->subcompile($parent) + ->raw(', ') + ->repr($compiler->getFilename()) + ->raw(', ') + ->repr($this->getNode('parent')->getLine()) + ->raw(')') + ; + } + + $compiler + ->raw(";\n") + ->outdent() + ->write("}\n\n") + ; + } + + protected function compileClassHeader(Twig_Compiler $compiler) + { + $compiler + ->write("\n\n") + // if the filename contains */, add a blank to avoid a PHP parse error + ->write('/* '.str_replace('*/', '* /', $this->getAttribute('filename'))." */\n") + ->write('class '.$compiler->getEnvironment()->getTemplateClass($this->getAttribute('filename'), $this->getAttribute('index'))) + ->raw(sprintf(" extends %s\n", $compiler->getEnvironment()->getBaseTemplateClass())) + ->write("{\n") + ->indent() + ; + } + + protected function compileConstructor(Twig_Compiler $compiler) + { + $compiler + ->write("public function __construct(Twig_Environment \$env)\n", "{\n") + ->indent() + ->subcompile($this->getNode('constructor_start')) + ->write("parent::__construct(\$env);\n\n") + ; + + // parent + if (null === $parent = $this->getNode('parent')) { + $compiler->write("\$this->parent = false;\n\n"); + } elseif ($parent instanceof Twig_Node_Expression_Constant) { + $compiler + ->addDebugInfo($parent) + ->write('$this->parent = $this->loadTemplate(') + ->subcompile($parent) + ->raw(', ') + ->repr($compiler->getFilename()) + ->raw(', ') + ->repr($this->getNode('parent')->getLine()) + ->raw(");\n") + ; + } + + $countTraits = count($this->getNode('traits')); + if ($countTraits) { + // traits + foreach ($this->getNode('traits') as $i => $trait) { + $this->compileLoadTemplate($compiler, $trait->getNode('template'), sprintf('$_trait_%s', $i)); + + $compiler + ->addDebugInfo($trait->getNode('template')) + ->write(sprintf("if (!\$_trait_%s->isTraitable()) {\n", $i)) + ->indent() + ->write("throw new Twig_Error_Runtime('Template \"'.") + ->subcompile($trait->getNode('template')) + ->raw(".'\" cannot be used as a trait.');\n") + ->outdent() + ->write("}\n") + ->write(sprintf("\$_trait_%s_blocks = \$_trait_%s->getBlocks();\n\n", $i, $i)) + ; + + foreach ($trait->getNode('targets') as $key => $value) { + $compiler + ->write(sprintf('if (!isset($_trait_%s_blocks[', $i)) + ->string($key) + ->raw("])) {\n") + ->indent() + ->write("throw new Twig_Error_Runtime(sprintf('Block ") + ->string($key) + ->raw(' is not defined in trait ') + ->subcompile($trait->getNode('template')) + ->raw(".'));\n") + ->outdent() + ->write("}\n\n") + + ->write(sprintf('$_trait_%s_blocks[', $i)) + ->subcompile($value) + ->raw(sprintf('] = $_trait_%s_blocks[', $i)) + ->string($key) + ->raw(sprintf(']; unset($_trait_%s_blocks[', $i)) + ->string($key) + ->raw("]);\n\n") + ; + } + } + + if ($countTraits > 1) { + $compiler + ->write("\$this->traits = array_merge(\n") + ->indent() + ; + + for ($i = 0; $i < $countTraits; ++$i) { + $compiler + ->write(sprintf('$_trait_%s_blocks'.($i == $countTraits - 1 ? '' : ',')."\n", $i)) + ; + } + + $compiler + ->outdent() + ->write(");\n\n") + ; + } else { + $compiler + ->write("\$this->traits = \$_trait_0_blocks;\n\n") + ; + } + + $compiler + ->write("\$this->blocks = array_merge(\n") + ->indent() + ->write("\$this->traits,\n") + ->write("array(\n") + ; + } else { + $compiler + ->write("\$this->blocks = array(\n") + ; + } + + // blocks + $compiler + ->indent() + ; + + foreach ($this->getNode('blocks') as $name => $node) { + $compiler + ->write(sprintf("'%s' => array(\$this, 'block_%s'),\n", $name, $name)) + ; + } + + if ($countTraits) { + $compiler + ->outdent() + ->write(")\n") + ; + } + + $compiler + ->outdent() + ->write(");\n") + ->outdent() + ->subcompile($this->getNode('constructor_end')) + ->write("}\n\n") + ; + } + + protected function compileDisplay(Twig_Compiler $compiler) + { + $compiler + ->write("protected function doDisplay(array \$context, array \$blocks = array())\n", "{\n") + ->indent() + ->subcompile($this->getNode('display_start')) + ->subcompile($this->getNode('body')) + ; + + if (null !== $parent = $this->getNode('parent')) { + $compiler->addDebugInfo($parent); + if ($parent instanceof Twig_Node_Expression_Constant) { + $compiler->write('$this->parent'); + } else { + $compiler->write('$this->getParent($context)'); + } + $compiler->raw("->display(\$context, array_merge(\$this->blocks, \$blocks));\n"); + } + + $compiler + ->subcompile($this->getNode('display_end')) + ->outdent() + ->write("}\n\n") + ; + } + + protected function compileClassFooter(Twig_Compiler $compiler) + { + $compiler + ->subcompile($this->getNode('class_end')) + ->outdent() + ->write("}\n") + ; + } + + protected function compileMacros(Twig_Compiler $compiler) + { + $compiler->subcompile($this->getNode('macros')); + } + + protected function compileGetTemplateName(Twig_Compiler $compiler) + { + $compiler + ->write("public function getTemplateName()\n", "{\n") + ->indent() + ->write('return ') + ->repr($this->getAttribute('filename')) + ->raw(";\n") + ->outdent() + ->write("}\n\n") + ; + } + + protected function compileIsTraitable(Twig_Compiler $compiler) + { + // A template can be used as a trait if: + // * it has no parent + // * it has no macros + // * it has no body + // + // Put another way, a template can be used as a trait if it + // only contains blocks and use statements. + $traitable = null === $this->getNode('parent') && 0 === count($this->getNode('macros')); + if ($traitable) { + if ($this->getNode('body') instanceof Twig_Node_Body) { + $nodes = $this->getNode('body')->getNode(0); + } else { + $nodes = $this->getNode('body'); + } + + if (!count($nodes)) { + $nodes = new Twig_Node(array($nodes)); + } + + foreach ($nodes as $node) { + if (!count($node)) { + continue; + } + + if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) { + continue; + } + + if ($node instanceof Twig_Node_BlockReference) { + continue; + } + + $traitable = false; + break; + } + } + + if ($traitable) { + return; + } + + $compiler + ->write("public function isTraitable()\n", "{\n") + ->indent() + ->write(sprintf("return %s;\n", $traitable ? 'true' : 'false')) + ->outdent() + ->write("}\n\n") + ; + } + + protected function compileDebugInfo(Twig_Compiler $compiler) + { + $compiler + ->write("public function getDebugInfo()\n", "{\n") + ->indent() + ->write(sprintf("return %s;\n", str_replace("\n", '', var_export(array_reverse($compiler->getDebugInfo(), true), true)))) + ->outdent() + ->write("}\n") + ; + } + + protected function compileLoadTemplate(Twig_Compiler $compiler, $node, $var) + { + if ($node instanceof Twig_Node_Expression_Constant) { + $compiler + ->write(sprintf('%s = $this->loadTemplate(', $var)) + ->subcompile($node) + ->raw(', ') + ->repr($compiler->getFilename()) + ->raw(', ') + ->repr($node->getLine()) + ->raw(");\n") + ; + } else { + $compiler + ->write(sprintf('%s = ', $var)) + ->subcompile($node) + ->raw(";\n") + ->write(sprintf('if (!%s', $var)) + ->raw(" instanceof Twig_Template) {\n") + ->indent() + ->write(sprintf('%s = $this->loadTemplate(%s') + ->raw(', ') + ->repr($compiler->getFilename()) + ->raw(', ') + ->repr($node->getLine()) + ->raw(");\n", $var, $var)) + ->outdent() + ->write("}\n") + ; + } + } +} diff --git a/system/libs/twig/Node/ModuleNode.php b/system/libs/twig/Node/ModuleNode.php deleted file mode 100755 index d39c6ff0..00000000 --- a/system/libs/twig/Node/ModuleNode.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Node_Print extends Twig_Node implements Twig_NodeOutputInterface +{ + public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null) + { + parent::__construct(array('expr' => $expr), array(), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->addDebugInfo($this) + ->write('echo ') + ->subcompile($this->getNode('expr')) + ->raw(";\n") + ; + } +} diff --git a/system/libs/twig/Node/PrintNode.php b/system/libs/twig/Node/PrintNode.php deleted file mode 100755 index 4ff2ed61..00000000 --- a/system/libs/twig/Node/PrintNode.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Node_Sandbox extends Twig_Node +{ + public function __construct(Twig_NodeInterface $body, $lineno, $tag = null) + { + parent::__construct(array('body' => $body), array(), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->addDebugInfo($this) + ->write("\$sandbox = \$this->env->getExtension('sandbox');\n") + ->write("if (!\$alreadySandboxed = \$sandbox->isSandboxed()) {\n") + ->indent() + ->write("\$sandbox->enableSandbox();\n") + ->outdent() + ->write("}\n") + ->subcompile($this->getNode('body')) + ->write("if (!\$alreadySandboxed) {\n") + ->indent() + ->write("\$sandbox->disableSandbox();\n") + ->outdent() + ->write("}\n") + ; + } +} diff --git a/system/libs/twig/Node/SandboxNode.php b/system/libs/twig/Node/SandboxNode.php deleted file mode 100755 index a24219f1..00000000 --- a/system/libs/twig/Node/SandboxNode.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Node_SandboxedPrint extends Twig_Node_Print +{ + public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null) + { + parent::__construct($expr, $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->addDebugInfo($this) + ->write('echo $this->env->getExtension(\'sandbox\')->ensureToStringAllowed(') + ->subcompile($this->getNode('expr')) + ->raw(");\n") + ; + } + + /** + * Removes node filters. + * + * This is mostly needed when another visitor adds filters (like the escaper one). + * + * @param Twig_Node $node A Node + * + * @return Twig_Node + */ + protected function removeNodeFilter($node) + { + if ($node instanceof Twig_Node_Expression_Filter) { + return $this->removeNodeFilter($node->getNode('node')); + } + + return $node; + } +} diff --git a/system/libs/twig/Node/SandboxedPrintNode.php b/system/libs/twig/Node/SandboxedPrintNode.php deleted file mode 100755 index a9f42bd5..00000000 --- a/system/libs/twig/Node/SandboxedPrintNode.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Node_Set extends Twig_Node +{ + public function __construct($capture, Twig_NodeInterface $names, Twig_NodeInterface $values, $lineno, $tag = null) + { + parent::__construct(array('names' => $names, 'values' => $values), array('capture' => $capture, 'safe' => false), $lineno, $tag); + + /* + * Optimizes the node when capture is used for a large block of text. + * + * {% set foo %}foo{% endset %} is compiled to $context['foo'] = new Twig_Markup("foo"); + */ + if ($this->getAttribute('capture')) { + $this->setAttribute('safe', true); + + $values = $this->getNode('values'); + if ($values instanceof Twig_Node_Text) { + $this->setNode('values', new Twig_Node_Expression_Constant($values->getAttribute('data'), $values->getLine())); + $this->setAttribute('capture', false); + } + } + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + $compiler->addDebugInfo($this); + + if (count($this->getNode('names')) > 1) { + $compiler->write('list('); + foreach ($this->getNode('names') as $idx => $node) { + if ($idx) { + $compiler->raw(', '); + } + + $compiler->subcompile($node); + } + $compiler->raw(')'); + } else { + if ($this->getAttribute('capture')) { + $compiler + ->write("ob_start();\n") + ->subcompile($this->getNode('values')) + ; + } + + $compiler->subcompile($this->getNode('names'), false); + + if ($this->getAttribute('capture')) { + $compiler->raw(" = ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset())"); + } + } + + if (!$this->getAttribute('capture')) { + $compiler->raw(' = '); + + if (count($this->getNode('names')) > 1) { + $compiler->write('array('); + foreach ($this->getNode('values') as $idx => $value) { + if ($idx) { + $compiler->raw(', '); + } + + $compiler->subcompile($value); + } + $compiler->raw(')'); + } else { + if ($this->getAttribute('safe')) { + $compiler + ->raw("('' === \$tmp = ") + ->subcompile($this->getNode('values')) + ->raw(") ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset())") + ; + } else { + $compiler->subcompile($this->getNode('values')); + } + } + } + + $compiler->raw(";\n"); + } +} diff --git a/system/libs/twig/Node/SetNode.php b/system/libs/twig/Node/SetNode.php deleted file mode 100755 index d45f133e..00000000 --- a/system/libs/twig/Node/SetNode.php +++ /dev/null @@ -1,11 +0,0 @@ - $name), $lineno); + } + + public function compile(Twig_Compiler $compiler) + { + $name = $this->getAttribute('name'); + $compiler + ->addDebugInfo($this) + ->write('if (isset($context[') + ->string($name) + ->raw('])) { $_') + ->raw($name) + ->raw('_ = $context[') + ->repr($name) + ->raw(']; } else { $_') + ->raw($name) + ->raw("_ = null; }\n") + ; + } +} diff --git a/system/libs/twig/Node/SetTempNode.php b/system/libs/twig/Node/SetTempNode.php deleted file mode 100755 index 90915d2f..00000000 --- a/system/libs/twig/Node/SetTempNode.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Node_Spaceless extends Twig_Node +{ + public function __construct(Twig_NodeInterface $body, $lineno, $tag = 'spaceless') + { + parent::__construct(array('body' => $body), array(), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->addDebugInfo($this) + ->write("ob_start();\n") + ->subcompile($this->getNode('body')) + ->write("echo trim(preg_replace('/>\s+<', ob_get_clean()));\n") + ; + } +} diff --git a/system/libs/twig/Node/SpacelessNode.php b/system/libs/twig/Node/SpacelessNode.php deleted file mode 100755 index 08cf9d08..00000000 --- a/system/libs/twig/Node/SpacelessNode.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Node_Text extends Twig_Node implements Twig_NodeOutputInterface +{ + public function __construct($data, $lineno) + { + parent::__construct(array(), array('data' => $data), $lineno); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->addDebugInfo($this) + ->write('echo ') + ->string($this->getAttribute('data')) + ->raw(";\n") + ; + } +} diff --git a/system/libs/twig/Node/TextNode.php b/system/libs/twig/Node/TextNode.php deleted file mode 100755 index daff7647..00000000 --- a/system/libs/twig/Node/TextNode.php +++ /dev/null @@ -1,11 +0,0 @@ - + * + * @deprecated since 1.12 (to be removed in 3.0) + */ +interface Twig_NodeInterface extends Countable, IteratorAggregate +{ + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler $compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler); + + public function getLine(); + + public function getNodeTag(); +} diff --git a/system/libs/twig/NodeOutputInterface.php b/system/libs/twig/NodeOutputInterface.php new file mode 100755 index 00000000..22172c09 --- /dev/null +++ b/system/libs/twig/NodeOutputInterface.php @@ -0,0 +1,19 @@ + + */ +interface Twig_NodeOutputInterface +{ +} diff --git a/system/libs/twig/NodeTraverser.php b/system/libs/twig/NodeTraverser.php index 7fe843b7..6024e65d 100755 --- a/system/libs/twig/NodeTraverser.php +++ b/system/libs/twig/NodeTraverser.php @@ -1,11 +1,90 @@ + */ +class Twig_NodeTraverser +{ + protected $env; + protected $visitors; -if (\false) { - class NodeTraverser extends \Twig_NodeTraverser + /** + * Constructor. + * + * @param Twig_Environment $env A Twig_Environment instance + * @param Twig_NodeVisitorInterface[] $visitors An array of Twig_NodeVisitorInterface instances + */ + public function __construct(Twig_Environment $env, array $visitors = array()) { + $this->env = $env; + $this->visitors = array(); + foreach ($visitors as $visitor) { + $this->addVisitor($visitor); + } + } + + /** + * Adds a visitor. + * + * @param Twig_NodeVisitorInterface $visitor A Twig_NodeVisitorInterface instance + */ + public function addVisitor(Twig_NodeVisitorInterface $visitor) + { + if (!isset($this->visitors[$visitor->getPriority()])) { + $this->visitors[$visitor->getPriority()] = array(); + } + + $this->visitors[$visitor->getPriority()][] = $visitor; + } + + /** + * Traverses a node and calls the registered visitors. + * + * @param Twig_NodeInterface $node A Twig_NodeInterface instance + * + * @return Twig_NodeInterface + */ + public function traverse(Twig_NodeInterface $node) + { + ksort($this->visitors); + foreach ($this->visitors as $visitors) { + foreach ($visitors as $visitor) { + $node = $this->traverseForVisitor($visitor, $node); + } + } + + return $node; + } + + protected function traverseForVisitor(Twig_NodeVisitorInterface $visitor, Twig_NodeInterface $node = null) + { + if (null === $node) { + return; + } + + $node = $visitor->enterNode($node, $this->env); + + foreach ($node as $k => $n) { + if (false !== $n = $this->traverseForVisitor($visitor, $n)) { + $node->setNode($k, $n); + } else { + $node->removeNode($k); + } + } + + return $visitor->leaveNode($node, $this->env); } } diff --git a/system/libs/twig/NodeVisitor/AbstractNodeVisitor.php b/system/libs/twig/NodeVisitor/AbstractNodeVisitor.php deleted file mode 100755 index 30e956fb..00000000 --- a/system/libs/twig/NodeVisitor/AbstractNodeVisitor.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_NodeVisitor_Escaper extends Twig_BaseNodeVisitor +{ + protected $statusStack = array(); + protected $blocks = array(); + protected $safeAnalysis; + protected $traverser; + protected $defaultStrategy = false; + protected $safeVars = array(); + + public function __construct() + { + $this->safeAnalysis = new Twig_NodeVisitor_SafeAnalysis(); + } + + /** + * {@inheritdoc} + */ + protected function doEnterNode(Twig_Node $node, Twig_Environment $env) + { + if ($node instanceof Twig_Node_Module) { + if ($env->hasExtension('escaper') && $defaultStrategy = $env->getExtension('escaper')->getDefaultStrategy($node->getAttribute('filename'))) { + $this->defaultStrategy = $defaultStrategy; + } + $this->safeVars = array(); + } elseif ($node instanceof Twig_Node_AutoEscape) { + $this->statusStack[] = $node->getAttribute('value'); + } elseif ($node instanceof Twig_Node_Block) { + $this->statusStack[] = isset($this->blocks[$node->getAttribute('name')]) ? $this->blocks[$node->getAttribute('name')] : $this->needEscaping($env); + } elseif ($node instanceof Twig_Node_Import) { + $this->safeVars[] = $node->getNode('var')->getAttribute('name'); + } + + return $node; + } + + /** + * {@inheritdoc} + */ + protected function doLeaveNode(Twig_Node $node, Twig_Environment $env) + { + if ($node instanceof Twig_Node_Module) { + $this->defaultStrategy = false; + $this->safeVars = array(); + } elseif ($node instanceof Twig_Node_Expression_Filter) { + return $this->preEscapeFilterNode($node, $env); + } elseif ($node instanceof Twig_Node_Print) { + return $this->escapePrintNode($node, $env, $this->needEscaping($env)); + } + + if ($node instanceof Twig_Node_AutoEscape || $node instanceof Twig_Node_Block) { + array_pop($this->statusStack); + } elseif ($node instanceof Twig_Node_BlockReference) { + $this->blocks[$node->getAttribute('name')] = $this->needEscaping($env); + } + + return $node; + } + + protected function escapePrintNode(Twig_Node_Print $node, Twig_Environment $env, $type) + { + if (false === $type) { + return $node; + } + + $expression = $node->getNode('expr'); + + if ($this->isSafeFor($type, $expression, $env)) { + return $node; + } + + $class = get_class($node); + + return new $class( + $this->getEscaperFilter($type, $expression), + $node->getLine() + ); + } + + protected function preEscapeFilterNode(Twig_Node_Expression_Filter $filter, Twig_Environment $env) + { + $name = $filter->getNode('filter')->getAttribute('value'); + + $type = $env->getFilter($name)->getPreEscape(); + if (null === $type) { + return $filter; + } + + $node = $filter->getNode('node'); + if ($this->isSafeFor($type, $node, $env)) { + return $filter; + } + + $filter->setNode('node', $this->getEscaperFilter($type, $node)); + + return $filter; + } + + protected function isSafeFor($type, Twig_NodeInterface $expression, $env) + { + $safe = $this->safeAnalysis->getSafe($expression); + + if (null === $safe) { + if (null === $this->traverser) { + $this->traverser = new Twig_NodeTraverser($env, array($this->safeAnalysis)); + } + + $this->safeAnalysis->setSafeVars($this->safeVars); + + $this->traverser->traverse($expression); + $safe = $this->safeAnalysis->getSafe($expression); + } + + return in_array($type, $safe) || in_array('all', $safe); + } + + protected function needEscaping(Twig_Environment $env) + { + if (count($this->statusStack)) { + return $this->statusStack[count($this->statusStack) - 1]; + } + + return $this->defaultStrategy ? $this->defaultStrategy : false; + } + + protected function getEscaperFilter($type, Twig_NodeInterface $node) + { + $line = $node->getLine(); + $name = new Twig_Node_Expression_Constant('escape', $line); + $args = new Twig_Node(array(new Twig_Node_Expression_Constant((string) $type, $line), new Twig_Node_Expression_Constant(null, $line), new Twig_Node_Expression_Constant(true, $line))); + + return new Twig_Node_Expression_Filter($node, $name, $args, $line); + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return 0; + } +} diff --git a/system/libs/twig/NodeVisitor/EscaperNodeVisitor.php b/system/libs/twig/NodeVisitor/EscaperNodeVisitor.php deleted file mode 100755 index 68c28322..00000000 --- a/system/libs/twig/NodeVisitor/EscaperNodeVisitor.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_NodeVisitor_Optimizer extends Twig_BaseNodeVisitor +{ + const OPTIMIZE_ALL = -1; + const OPTIMIZE_NONE = 0; + const OPTIMIZE_FOR = 2; + const OPTIMIZE_RAW_FILTER = 4; + const OPTIMIZE_VAR_ACCESS = 8; + + protected $loops = array(); + protected $loopsTargets = array(); + protected $optimizers; + protected $prependedNodes = array(); + protected $inABody = false; + + /** + * Constructor. + * + * @param int $optimizers The optimizer mode + */ + public function __construct($optimizers = -1) + { + if (!is_int($optimizers) || $optimizers > (self::OPTIMIZE_FOR | self::OPTIMIZE_RAW_FILTER | self::OPTIMIZE_VAR_ACCESS)) { + throw new InvalidArgumentException(sprintf('Optimizer mode "%s" is not valid.', $optimizers)); + } + + $this->optimizers = $optimizers; + } + + /** + * {@inheritdoc} + */ + protected function doEnterNode(Twig_Node $node, Twig_Environment $env) + { + if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) { + $this->enterOptimizeFor($node, $env); + } + + if (PHP_VERSION_ID < 50400 && self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) { + if ($this->inABody) { + if (!$node instanceof Twig_Node_Expression) { + if (get_class($node) !== 'Twig_Node') { + array_unshift($this->prependedNodes, array()); + } + } else { + $node = $this->optimizeVariables($node, $env); + } + } elseif ($node instanceof Twig_Node_Body) { + $this->inABody = true; + } + } + + return $node; + } + + /** + * {@inheritdoc} + */ + protected function doLeaveNode(Twig_Node $node, Twig_Environment $env) + { + $expression = $node instanceof Twig_Node_Expression; + + if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) { + $this->leaveOptimizeFor($node, $env); + } + + if (self::OPTIMIZE_RAW_FILTER === (self::OPTIMIZE_RAW_FILTER & $this->optimizers)) { + $node = $this->optimizeRawFilter($node, $env); + } + + $node = $this->optimizePrintNode($node, $env); + + if (self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) { + if ($node instanceof Twig_Node_Body) { + $this->inABody = false; + } elseif ($this->inABody) { + if (!$expression && get_class($node) !== 'Twig_Node' && $prependedNodes = array_shift($this->prependedNodes)) { + $nodes = array(); + foreach (array_unique($prependedNodes) as $name) { + $nodes[] = new Twig_Node_SetTemp($name, $node->getLine()); + } + + $nodes[] = $node; + $node = new Twig_Node($nodes); + } + } + } + + return $node; + } + + protected function optimizeVariables(Twig_NodeInterface $node, Twig_Environment $env) + { + if ('Twig_Node_Expression_Name' === get_class($node) && $node->isSimple()) { + $this->prependedNodes[0][] = $node->getAttribute('name'); + + return new Twig_Node_Expression_TempName($node->getAttribute('name'), $node->getLine()); + } + + return $node; + } + + /** + * Optimizes print nodes. + * + * It replaces: + * + * * "echo $this->render(Parent)Block()" with "$this->display(Parent)Block()" + * + * @param Twig_NodeInterface $node A Node + * @param Twig_Environment $env The current Twig environment + * + * @return Twig_NodeInterface + */ + protected function optimizePrintNode(Twig_NodeInterface $node, Twig_Environment $env) + { + if (!$node instanceof Twig_Node_Print) { + return $node; + } + + if ( + $node->getNode('expr') instanceof Twig_Node_Expression_BlockReference || + $node->getNode('expr') instanceof Twig_Node_Expression_Parent + ) { + $node->getNode('expr')->setAttribute('output', true); + + return $node->getNode('expr'); + } + + return $node; + } + + /** + * Removes "raw" filters. + * + * @param Twig_NodeInterface $node A Node + * @param Twig_Environment $env The current Twig environment + * + * @return Twig_NodeInterface + */ + protected function optimizeRawFilter(Twig_NodeInterface $node, Twig_Environment $env) + { + if ($node instanceof Twig_Node_Expression_Filter && 'raw' == $node->getNode('filter')->getAttribute('value')) { + return $node->getNode('node'); + } + + return $node; + } + + /** + * Optimizes "for" tag by removing the "loop" variable creation whenever possible. + * + * @param Twig_NodeInterface $node A Node + * @param Twig_Environment $env The current Twig environment + */ + protected function enterOptimizeFor(Twig_NodeInterface $node, Twig_Environment $env) + { + if ($node instanceof Twig_Node_For) { + // disable the loop variable by default + $node->setAttribute('with_loop', false); + array_unshift($this->loops, $node); + array_unshift($this->loopsTargets, $node->getNode('value_target')->getAttribute('name')); + array_unshift($this->loopsTargets, $node->getNode('key_target')->getAttribute('name')); + } elseif (!$this->loops) { + // we are outside a loop + return; + } + + // when do we need to add the loop variable back? + + // the loop variable is referenced for the current loop + elseif ($node instanceof Twig_Node_Expression_Name && 'loop' === $node->getAttribute('name')) { + $node->setAttribute('always_defined', true); + $this->addLoopToCurrent(); + } + + // optimize access to loop targets + elseif ($node instanceof Twig_Node_Expression_Name && in_array($node->getAttribute('name'), $this->loopsTargets)) { + $node->setAttribute('always_defined', true); + } + + // block reference + elseif ($node instanceof Twig_Node_BlockReference || $node instanceof Twig_Node_Expression_BlockReference) { + $this->addLoopToCurrent(); + } + + // include without the only attribute + elseif ($node instanceof Twig_Node_Include && !$node->getAttribute('only')) { + $this->addLoopToAll(); + } + + // include function without the with_context=false parameter + elseif ($node instanceof Twig_Node_Expression_Function + && 'include' === $node->getAttribute('name') + && (!$node->getNode('arguments')->hasNode('with_context') + || false !== $node->getNode('arguments')->getNode('with_context')->getAttribute('value') + ) + ) { + $this->addLoopToAll(); + } + + // the loop variable is referenced via an attribute + elseif ($node instanceof Twig_Node_Expression_GetAttr + && (!$node->getNode('attribute') instanceof Twig_Node_Expression_Constant + || 'parent' === $node->getNode('attribute')->getAttribute('value') + ) + && (true === $this->loops[0]->getAttribute('with_loop') + || ($node->getNode('node') instanceof Twig_Node_Expression_Name + && 'loop' === $node->getNode('node')->getAttribute('name') + ) + ) + ) { + $this->addLoopToAll(); + } + } + + /** + * Optimizes "for" tag by removing the "loop" variable creation whenever possible. + * + * @param Twig_NodeInterface $node A Node + * @param Twig_Environment $env The current Twig environment + */ + protected function leaveOptimizeFor(Twig_NodeInterface $node, Twig_Environment $env) + { + if ($node instanceof Twig_Node_For) { + array_shift($this->loops); + array_shift($this->loopsTargets); + array_shift($this->loopsTargets); + } + } + + protected function addLoopToCurrent() + { + $this->loops[0]->setAttribute('with_loop', true); + } + + protected function addLoopToAll() + { + foreach ($this->loops as $loop) { + $loop->setAttribute('with_loop', true); + } + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return 255; + } +} diff --git a/system/libs/twig/NodeVisitor/OptimizerNodeVisitor.php b/system/libs/twig/NodeVisitor/OptimizerNodeVisitor.php deleted file mode 100755 index 9ed37a55..00000000 --- a/system/libs/twig/NodeVisitor/OptimizerNodeVisitor.php +++ /dev/null @@ -1,11 +0,0 @@ -safeVars = $safeVars; + } + + public function getSafe(Twig_NodeInterface $node) + { + $hash = spl_object_hash($node); + if (!isset($this->data[$hash])) { + return; + } + + foreach ($this->data[$hash] as $bucket) { + if ($bucket['key'] !== $node) { + continue; + } + + if (in_array('html_attr', $bucket['value'])) { + $bucket['value'][] = 'html'; + } + + return $bucket['value']; + } + } + + protected function setSafe(Twig_NodeInterface $node, array $safe) + { + $hash = spl_object_hash($node); + if (isset($this->data[$hash])) { + foreach ($this->data[$hash] as &$bucket) { + if ($bucket['key'] === $node) { + $bucket['value'] = $safe; + + return; + } + } + } + $this->data[$hash][] = array( + 'key' => $node, + 'value' => $safe, + ); + } + + /** + * {@inheritdoc} + */ + protected function doEnterNode(Twig_Node $node, Twig_Environment $env) + { + return $node; + } + + /** + * {@inheritdoc} + */ + protected function doLeaveNode(Twig_Node $node, Twig_Environment $env) + { + if ($node instanceof Twig_Node_Expression_Constant) { + // constants are marked safe for all + $this->setSafe($node, array('all')); + } elseif ($node instanceof Twig_Node_Expression_BlockReference) { + // blocks are safe by definition + $this->setSafe($node, array('all')); + } elseif ($node instanceof Twig_Node_Expression_Parent) { + // parent block is safe by definition + $this->setSafe($node, array('all')); + } elseif ($node instanceof Twig_Node_Expression_Conditional) { + // intersect safeness of both operands + $safe = $this->intersectSafe($this->getSafe($node->getNode('expr2')), $this->getSafe($node->getNode('expr3'))); + $this->setSafe($node, $safe); + } elseif ($node instanceof Twig_Node_Expression_Filter) { + // filter expression is safe when the filter is safe + $name = $node->getNode('filter')->getAttribute('value'); + $args = $node->getNode('arguments'); + if (false !== $filter = $env->getFilter($name)) { + $safe = $filter->getSafe($args); + if (null === $safe) { + $safe = $this->intersectSafe($this->getSafe($node->getNode('node')), $filter->getPreservesSafety()); + } + $this->setSafe($node, $safe); + } else { + $this->setSafe($node, array()); + } + } elseif ($node instanceof Twig_Node_Expression_Function) { + // function expression is safe when the function is safe + $name = $node->getAttribute('name'); + $args = $node->getNode('arguments'); + $function = $env->getFunction($name); + if (false !== $function) { + $this->setSafe($node, $function->getSafe($args)); + } else { + $this->setSafe($node, array()); + } + } elseif ($node instanceof Twig_Node_Expression_MethodCall) { + if ($node->getAttribute('safe')) { + $this->setSafe($node, array('all')); + } else { + $this->setSafe($node, array()); + } + } elseif ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name) { + $name = $node->getNode('node')->getAttribute('name'); + // attributes on template instances are safe + if ('_self' == $name || in_array($name, $this->safeVars)) { + $this->setSafe($node, array('all')); + } else { + $this->setSafe($node, array()); + } + } else { + $this->setSafe($node, array()); + } + + return $node; + } + + protected function intersectSafe(array $a = null, array $b = null) + { + if (null === $a || null === $b) { + return array(); + } + + if (in_array('all', $a)) { + return $b; + } + + if (in_array('all', $b)) { + return $a; + } + + return array_intersect($a, $b); + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return 0; + } +} diff --git a/system/libs/twig/NodeVisitor/SafeAnalysisNodeVisitor.php b/system/libs/twig/NodeVisitor/SafeAnalysisNodeVisitor.php deleted file mode 100755 index 8906b37c..00000000 --- a/system/libs/twig/NodeVisitor/SafeAnalysisNodeVisitor.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_NodeVisitor_Sandbox extends Twig_BaseNodeVisitor +{ + protected $inAModule = false; + protected $tags; + protected $filters; + protected $functions; + + /** + * {@inheritdoc} + */ + protected function doEnterNode(Twig_Node $node, Twig_Environment $env) + { + if ($node instanceof Twig_Node_Module) { + $this->inAModule = true; + $this->tags = array(); + $this->filters = array(); + $this->functions = array(); + + return $node; + } elseif ($this->inAModule) { + // look for tags + if ($node->getNodeTag() && !isset($this->tags[$node->getNodeTag()])) { + $this->tags[$node->getNodeTag()] = $node; + } + + // look for filters + if ($node instanceof Twig_Node_Expression_Filter && !isset($this->filters[$node->getNode('filter')->getAttribute('value')])) { + $this->filters[$node->getNode('filter')->getAttribute('value')] = $node; + } + + // look for functions + if ($node instanceof Twig_Node_Expression_Function && !isset($this->functions[$node->getAttribute('name')])) { + $this->functions[$node->getAttribute('name')] = $node; + } + + // wrap print to check __toString() calls + if ($node instanceof Twig_Node_Print) { + return new Twig_Node_SandboxedPrint($node->getNode('expr'), $node->getLine(), $node->getNodeTag()); + } + } + + return $node; + } + + /** + * {@inheritdoc} + */ + protected function doLeaveNode(Twig_Node $node, Twig_Environment $env) + { + if ($node instanceof Twig_Node_Module) { + $this->inAModule = false; + + $node->setNode('display_start', new Twig_Node(array(new Twig_Node_CheckSecurity($this->filters, $this->tags, $this->functions), $node->getNode('display_start')))); + } + + return $node; + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return 0; + } +} diff --git a/system/libs/twig/NodeVisitor/SandboxNodeVisitor.php b/system/libs/twig/NodeVisitor/SandboxNodeVisitor.php deleted file mode 100755 index 1e4632f3..00000000 --- a/system/libs/twig/NodeVisitor/SandboxNodeVisitor.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +interface Twig_NodeVisitorInterface +{ + /** + * Called before child nodes are visited. + * + * @param Twig_NodeInterface $node The node to visit + * @param Twig_Environment $env The Twig environment instance + * + * @return Twig_NodeInterface The modified node + */ + public function enterNode(Twig_NodeInterface $node, Twig_Environment $env); + + /** + * Called after child nodes are visited. + * + * @param Twig_NodeInterface $node The node to visit + * @param Twig_Environment $env The Twig environment instance + * + * @return Twig_NodeInterface|false The modified node or false if the node must be removed + */ + public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env); + + /** + * Returns the priority for this visitor. + * + * Priority should be between -10 and 10 (0 is the default). + * + * @return int The priority level + */ + public function getPriority(); +} diff --git a/system/libs/twig/Parser.php b/system/libs/twig/Parser.php index 738a4047..dd9c1fc3 100755 --- a/system/libs/twig/Parser.php +++ b/system/libs/twig/Parser.php @@ -1,11 +1,399 @@ + */ +class Twig_Parser implements Twig_ParserInterface +{ + protected $stack = array(); + protected $stream; + protected $parent; + protected $handlers; + protected $visitors; + protected $expressionParser; + protected $blocks; + protected $blockStack; + protected $macros; + protected $env; + protected $reservedMacroNames; + protected $importedSymbols; + protected $traits; + protected $embeddedTemplates = array(); -if (\false) { - class Parser extends \Twig_Parser + /** + * Constructor. + * + * @param Twig_Environment $env A Twig_Environment instance + */ + public function __construct(Twig_Environment $env) { + $this->env = $env; + } + + public function getEnvironment() + { + return $this->env; + } + + public function getVarName() + { + return sprintf('__internal_%s', hash('sha256', uniqid(mt_rand(), true), false)); + } + + public function getFilename() + { + return $this->stream->getFilename(); + } + + /** + * {@inheritdoc} + */ + public function parse(Twig_TokenStream $stream, $test = null, $dropNeedle = false) + { + // push all variables into the stack to keep the current state of the parser + $vars = get_object_vars($this); + unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser']); + $this->stack[] = $vars; + + // tag handlers + if (null === $this->handlers) { + $this->handlers = $this->env->getTokenParsers(); + $this->handlers->setParser($this); + } + + // node visitors + if (null === $this->visitors) { + $this->visitors = $this->env->getNodeVisitors(); + } + + if (null === $this->expressionParser) { + $this->expressionParser = new Twig_ExpressionParser($this, $this->env->getUnaryOperators(), $this->env->getBinaryOperators()); + } + + $this->stream = $stream; + $this->parent = null; + $this->blocks = array(); + $this->macros = array(); + $this->traits = array(); + $this->blockStack = array(); + $this->importedSymbols = array(array()); + $this->embeddedTemplates = array(); + + try { + $body = $this->subparse($test, $dropNeedle); + + if (null !== $this->parent) { + if (null === $body = $this->filterBodyNodes($body)) { + $body = new Twig_Node(); + } + } + } catch (Twig_Error_Syntax $e) { + if (!$e->getTemplateFile()) { + $e->setTemplateFile($this->getFilename()); + } + + if (!$e->getTemplateLine()) { + $e->setTemplateLine($this->stream->getCurrent()->getLine()); + } + + throw $e; + } + + $node = new Twig_Node_Module(new Twig_Node_Body(array($body)), $this->parent, new Twig_Node($this->blocks), new Twig_Node($this->macros), new Twig_Node($this->traits), $this->embeddedTemplates, $this->getFilename()); + + $traverser = new Twig_NodeTraverser($this->env, $this->visitors); + + $node = $traverser->traverse($node); + + // restore previous stack so previous parse() call can resume working + foreach (array_pop($this->stack) as $key => $val) { + $this->$key = $val; + } + + return $node; + } + + public function subparse($test, $dropNeedle = false) + { + $lineno = $this->getCurrentToken()->getLine(); + $rv = array(); + while (!$this->stream->isEOF()) { + switch ($this->getCurrentToken()->getType()) { + case Twig_Token::TEXT_TYPE: + $token = $this->stream->next(); + $rv[] = new Twig_Node_Text($token->getValue(), $token->getLine()); + break; + + case Twig_Token::VAR_START_TYPE: + $token = $this->stream->next(); + $expr = $this->expressionParser->parseExpression(); + $this->stream->expect(Twig_Token::VAR_END_TYPE); + $rv[] = new Twig_Node_Print($expr, $token->getLine()); + break; + + case Twig_Token::BLOCK_START_TYPE: + $this->stream->next(); + $token = $this->getCurrentToken(); + + if ($token->getType() !== Twig_Token::NAME_TYPE) { + throw new Twig_Error_Syntax('A block must start with a tag name', $token->getLine(), $this->getFilename()); + } + + if (null !== $test && call_user_func($test, $token)) { + if ($dropNeedle) { + $this->stream->next(); + } + + if (1 === count($rv)) { + return $rv[0]; + } + + return new Twig_Node($rv, array(), $lineno); + } + + $subparser = $this->handlers->getTokenParser($token->getValue()); + if (null === $subparser) { + if (null !== $test) { + $error = sprintf('Unexpected tag name "%s"', $token->getValue()); + if (is_array($test) && isset($test[0]) && $test[0] instanceof Twig_TokenParserInterface) { + $error .= sprintf(' (expecting closing tag for the "%s" tag defined near line %s)', $test[0]->getTag(), $lineno); + } + + throw new Twig_Error_Syntax($error, $token->getLine(), $this->getFilename()); + } + + $message = sprintf('Unknown tag name "%s"', $token->getValue()); + if ($alternatives = $this->env->computeAlternatives($token->getValue(), array_keys($this->env->getTags()))) { + $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); + } + + throw new Twig_Error_Syntax($message, $token->getLine(), $this->getFilename()); + } + + $this->stream->next(); + + $node = $subparser->parse($token); + if (null !== $node) { + $rv[] = $node; + } + break; + + default: + throw new Twig_Error_Syntax('Lexer or parser ended up in unsupported state.', 0, $this->getFilename()); + } + } + + if (1 === count($rv)) { + return $rv[0]; + } + + return new Twig_Node($rv, array(), $lineno); + } + + public function addHandler($name, $class) + { + $this->handlers[$name] = $class; + } + + public function addNodeVisitor(Twig_NodeVisitorInterface $visitor) + { + $this->visitors[] = $visitor; + } + + public function getBlockStack() + { + return $this->blockStack; + } + + public function peekBlockStack() + { + return $this->blockStack[count($this->blockStack) - 1]; + } + + public function popBlockStack() + { + array_pop($this->blockStack); + } + + public function pushBlockStack($name) + { + $this->blockStack[] = $name; + } + + public function hasBlock($name) + { + return isset($this->blocks[$name]); + } + + public function getBlock($name) + { + return $this->blocks[$name]; + } + + public function setBlock($name, Twig_Node_Block $value) + { + $this->blocks[$name] = new Twig_Node_Body(array($value), array(), $value->getLine()); + } + + public function hasMacro($name) + { + return isset($this->macros[$name]); + } + + public function setMacro($name, Twig_Node_Macro $node) + { + if ($this->isReservedMacroName($name)) { + throw new Twig_Error_Syntax(sprintf('"%s" cannot be used as a macro name as it is a reserved keyword', $name), $node->getLine(), $this->getFilename()); + } + + $this->macros[$name] = $node; + } + + public function isReservedMacroName($name) + { + if (null === $this->reservedMacroNames) { + $this->reservedMacroNames = array(); + $r = new ReflectionClass($this->env->getBaseTemplateClass()); + foreach ($r->getMethods() as $method) { + $methodName = strtolower($method->getName()); + + if ('get' === substr($methodName, 0, 3) && isset($methodName[3])) { + $this->reservedMacroNames[] = substr($methodName, 3); + } + } + } + + return in_array(strtolower($name), $this->reservedMacroNames); + } + + public function addTrait($trait) + { + $this->traits[] = $trait; + } + + public function hasTraits() + { + return count($this->traits) > 0; + } + + public function embedTemplate(Twig_Node_Module $template) + { + $template->setIndex(mt_rand()); + + $this->embeddedTemplates[] = $template; + } + + public function addImportedSymbol($type, $alias, $name = null, Twig_Node_Expression $node = null) + { + $this->importedSymbols[0][$type][$alias] = array('name' => $name, 'node' => $node); + } + + public function getImportedSymbol($type, $alias) + { + foreach ($this->importedSymbols as $functions) { + if (isset($functions[$type][$alias])) { + return $functions[$type][$alias]; + } + } + } + + public function isMainScope() + { + return 1 === count($this->importedSymbols); + } + + public function pushLocalScope() + { + array_unshift($this->importedSymbols, array()); + } + + public function popLocalScope() + { + array_shift($this->importedSymbols); + } + + /** + * Gets the expression parser. + * + * @return Twig_ExpressionParser The expression parser + */ + public function getExpressionParser() + { + return $this->expressionParser; + } + + public function getParent() + { + return $this->parent; + } + + public function setParent($parent) + { + $this->parent = $parent; + } + + /** + * Gets the token stream. + * + * @return Twig_TokenStream The token stream + */ + public function getStream() + { + return $this->stream; + } + + /** + * Gets the current token. + * + * @return Twig_Token The current token + */ + public function getCurrentToken() + { + return $this->stream->getCurrent(); + } + + protected function filterBodyNodes(Twig_NodeInterface $node) + { + // check that the body does not contain non-empty output nodes + if ( + ($node instanceof Twig_Node_Text && !ctype_space($node->getAttribute('data'))) + || + (!$node instanceof Twig_Node_Text && !$node instanceof Twig_Node_BlockReference && $node instanceof Twig_NodeOutputInterface) + ) { + if (false !== strpos((string) $node, chr(0xEF).chr(0xBB).chr(0xBF))) { + throw new Twig_Error_Syntax('A template that extends another one cannot have a body but a byte order mark (BOM) has been detected; it must be removed.', $node->getLine(), $this->getFilename()); + } + + throw new Twig_Error_Syntax('A template that extends another one cannot have a body.', $node->getLine(), $this->getFilename()); + } + + // bypass "set" nodes as they "capture" the output + if ($node instanceof Twig_Node_Set) { + return $node; + } + + if ($node instanceof Twig_NodeOutputInterface) { + return; + } + + foreach ($node as $k => $n) { + if (null !== $n && null === $this->filterBodyNodes($n)) { + $node->removeNode($k); + } + } + + return $node; } } diff --git a/system/libs/twig/ParserInterface.php b/system/libs/twig/ParserInterface.php new file mode 100755 index 00000000..8e7cc0a8 --- /dev/null +++ b/system/libs/twig/ParserInterface.php @@ -0,0 +1,31 @@ + + * + * @deprecated since 1.12 (to be removed in 3.0) + */ +interface Twig_ParserInterface +{ + /** + * Converts a token stream to a node tree. + * + * @param Twig_TokenStream $stream A token stream instance + * + * @return Twig_Node_Module A node tree + * + * @throws Twig_Error_Syntax When the token stream is syntactically or semantically wrong + */ + public function parse(Twig_TokenStream $stream); +} diff --git a/system/libs/twig/Profiler/Dumper/BaseDumper.php b/system/libs/twig/Profiler/Dumper/BaseDumper.php deleted file mode 100755 index 33c32801..00000000 --- a/system/libs/twig/Profiler/Dumper/BaseDumper.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Profiler_Dumper_Blackfire +{ + public function dump(Twig_Profiler_Profile $profile) + { + $data = array(); + $this->dumpProfile('main()', $profile, $data); + $this->dumpChildren('main()', $profile, $data); + + $start = microtime(true); + $str = << $values) { + $str .= "{$name}//{$values['ct']} {$values['wt']} {$values['mu']} {$values['pmu']}\n"; + } + + return $str; + } + + private function dumpChildren($parent, Twig_Profiler_Profile $profile, &$data) + { + foreach ($profile as $p) { + if ($p->isTemplate()) { + $name = $p->getTemplate(); + } else { + $name = sprintf('%s::%s(%s)', $p->getTemplate(), $p->getType(), $p->getName()); + } + $this->dumpProfile(sprintf('%s==>%s', $parent, $name), $p, $data); + $this->dumpChildren($name, $p, $data); + } + } + + private function dumpProfile($edge, Twig_Profiler_Profile $profile, &$data) + { + if (isset($data[$edge])) { + $data[$edge]['ct'] += 1; + $data[$edge]['wt'] += floor($profile->getDuration() * 1000000); + $data[$edge]['mu'] += $profile->getMemoryUsage(); + $data[$edge]['pmu'] += $profile->getPeakMemoryUsage(); + } else { + $data[$edge] = array( + 'ct' => 1, + 'wt' => floor($profile->getDuration() * 1000000), + 'mu' => $profile->getMemoryUsage(), + 'pmu' => $profile->getPeakMemoryUsage(), + ); + } + } +} diff --git a/system/libs/twig/Profiler/Dumper/BlackfireDumper.php b/system/libs/twig/Profiler/Dumper/BlackfireDumper.php deleted file mode 100755 index afab9394..00000000 --- a/system/libs/twig/Profiler/Dumper/BlackfireDumper.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Profiler_Dumper_Html extends Twig_Profiler_Dumper_Text +{ + private static $colors = array( + 'block' => '#dfd', + 'macro' => '#ddf', + 'template' => '#ffd', + 'big' => '#d44', + ); + + public function dump(Twig_Profiler_Profile $profile) + { + return '
'.parent::dump($profile).'
'; + } + + protected function formatTemplate(Twig_Profiler_Profile $profile, $prefix) + { + return sprintf('%s└ %s', $prefix, self::$colors['template'], $profile->getTemplate()); + } + + protected function formatNonTemplate(Twig_Profiler_Profile $profile, $prefix) + { + return sprintf('%s└ %s::%s(%s)', $prefix, $profile->getTemplate(), $profile->getType(), isset(self::$colors[$profile->getType()]) ? self::$colors[$profile->getType()] : 'auto', $profile->getName()); + } + + protected function formatTime(Twig_Profiler_Profile $profile, $percent) + { + return sprintf('%.2fms/%.0f%%', $percent > 20 ? self::$colors['big'] : 'auto', $profile->getDuration() * 1000, $percent); + } +} diff --git a/system/libs/twig/Profiler/Dumper/HtmlDumper.php b/system/libs/twig/Profiler/Dumper/HtmlDumper.php deleted file mode 100755 index 51654d2d..00000000 --- a/system/libs/twig/Profiler/Dumper/HtmlDumper.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Profiler_Dumper_Text +{ + private $root; + + public function dump(Twig_Profiler_Profile $profile) + { + return $this->dumpProfile($profile); + } + + protected function formatTemplate(Twig_Profiler_Profile $profile, $prefix) + { + return sprintf('%s└ %s', $prefix, $profile->getTemplate()); + } + + protected function formatNonTemplate(Twig_Profiler_Profile $profile, $prefix) + { + return sprintf('%s└ %s::%s(%s)', $prefix, $profile->getTemplate(), $profile->getType(), $profile->getName()); + } + + protected function formatTime(Twig_Profiler_Profile $profile, $percent) + { + return sprintf('%.2fms/%.0f%%', $profile->getDuration() * 1000, $percent); + } + + private function dumpProfile(Twig_Profiler_Profile $profile, $prefix = '', $sibling = false) + { + if ($profile->isRoot()) { + $this->root = $profile->getDuration(); + $start = $profile->getName(); + } else { + if ($profile->isTemplate()) { + $start = $this->formatTemplate($profile, $prefix); + } else { + $start = $this->formatNonTemplate($profile, $prefix); + } + $prefix .= $sibling ? '│ ' : ' '; + } + + $percent = $this->root ? $profile->getDuration() / $this->root * 100 : 0; + + if ($profile->getDuration() * 1000 < 1) { + $str = $start."\n"; + } else { + $str = sprintf("%s %s\n", $start, $this->formatTime($profile, $percent)); + } + + $nCount = count($profile->getProfiles()); + foreach ($profile as $i => $p) { + $str .= $this->dumpProfile($p, $prefix, $i + 1 !== $nCount); + } + + return $str; + } +} diff --git a/system/libs/twig/Profiler/Dumper/TextDumper.php b/system/libs/twig/Profiler/Dumper/TextDumper.php deleted file mode 100755 index a9ec4efa..00000000 --- a/system/libs/twig/Profiler/Dumper/TextDumper.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Profiler_Node_EnterProfile extends Twig_Node +{ + public function __construct($extensionName, $type, $name, $varName) + { + parent::__construct(array(), array('extension_name' => $extensionName, 'name' => $name, 'type' => $type, 'var_name' => $varName)); + } + + /** + * {@inheritdoc} + */ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->write(sprintf('$%s = $this->env->getExtension(', $this->getAttribute('var_name'))) + ->repr($this->getAttribute('extension_name')) + ->raw(");\n") + ->write(sprintf('$%s->enter($%s = new Twig_Profiler_Profile($this->getTemplateName(), ', $this->getAttribute('var_name'), $this->getAttribute('var_name').'_prof')) + ->repr($this->getAttribute('type')) + ->raw(', ') + ->repr($this->getAttribute('name')) + ->raw("));\n\n") + ; + } +} diff --git a/system/libs/twig/Profiler/Node/EnterProfileNode.php b/system/libs/twig/Profiler/Node/EnterProfileNode.php deleted file mode 100755 index 3b9786b2..00000000 --- a/system/libs/twig/Profiler/Node/EnterProfileNode.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Profiler_Node_LeaveProfile extends Twig_Node +{ + public function __construct($varName) + { + parent::__construct(array(), array('var_name' => $varName)); + } + + /** + * {@inheritdoc} + */ + public function compile(Twig_Compiler $compiler) + { + $compiler + ->write("\n") + ->write(sprintf("\$%s->leave(\$%s);\n\n", $this->getAttribute('var_name'), $this->getAttribute('var_name').'_prof')) + ; + } +} diff --git a/system/libs/twig/Profiler/Node/LeaveProfileNode.php b/system/libs/twig/Profiler/Node/LeaveProfileNode.php deleted file mode 100755 index c4024f3e..00000000 --- a/system/libs/twig/Profiler/Node/LeaveProfileNode.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Profiler_NodeVisitor_Profiler extends Twig_BaseNodeVisitor +{ + private $extensionName; + + public function __construct($extensionName) + { + $this->extensionName = $extensionName; + } + + /** + * {@inheritdoc} + */ + protected function doEnterNode(Twig_Node $node, Twig_Environment $env) + { + return $node; + } + + /** + * {@inheritdoc} + */ + protected function doLeaveNode(Twig_Node $node, Twig_Environment $env) + { + if ($node instanceof Twig_Node_Module) { + $varName = $this->getVarName(); + $node->setNode('display_start', new Twig_Node(array(new Twig_Profiler_Node_EnterProfile($this->extensionName, Twig_Profiler_Profile::TEMPLATE, $node->getAttribute('filename'), $varName), $node->getNode('display_start')))); + $node->setNode('display_end', new Twig_Node(array(new Twig_Profiler_Node_LeaveProfile($varName), $node->getNode('display_end')))); + } elseif ($node instanceof Twig_Node_Block) { + $varName = $this->getVarName(); + $node->setNode('body', new Twig_Node_Body(array( + new Twig_Profiler_Node_EnterProfile($this->extensionName, Twig_Profiler_Profile::BLOCK, $node->getAttribute('name'), $varName), + $node->getNode('body'), + new Twig_Profiler_Node_LeaveProfile($varName), + ))); + } elseif ($node instanceof Twig_Node_Macro) { + $varName = $this->getVarName(); + $node->setNode('body', new Twig_Node_Body(array( + new Twig_Profiler_Node_EnterProfile($this->extensionName, Twig_Profiler_Profile::MACRO, $node->getAttribute('name'), $varName), + $node->getNode('body'), + new Twig_Profiler_Node_LeaveProfile($varName), + ))); + } + + return $node; + } + + private function getVarName() + { + return sprintf('__internal_%s', hash('sha256', uniqid(mt_rand(), true), false)); + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return 0; + } +} diff --git a/system/libs/twig/Profiler/NodeVisitor/ProfilerNodeVisitor.php b/system/libs/twig/Profiler/NodeVisitor/ProfilerNodeVisitor.php deleted file mode 100755 index 0e401a73..00000000 --- a/system/libs/twig/Profiler/NodeVisitor/ProfilerNodeVisitor.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Profiler_Profile implements IteratorAggregate, Serializable +{ + const ROOT = 'ROOT'; + const BLOCK = 'block'; + const TEMPLATE = 'template'; + const MACRO = 'macro'; -if (\false) { - class Profile extends \Twig_Profiler_Profile + private $template; + private $name; + private $type; + private $starts = array(); + private $ends = array(); + private $profiles = array(); + + public function __construct($template = 'main', $type = self::ROOT, $name = 'main') { + $this->template = $template; + $this->type = $type; + $this->name = 0 === strpos($name, '__internal_') ? 'INTERNAL' : $name; + $this->enter(); + } + + public function getTemplate() + { + return $this->template; + } + + public function getType() + { + return $this->type; + } + + public function getName() + { + return $this->name; + } + + public function isRoot() + { + return self::ROOT === $this->type; + } + + public function isTemplate() + { + return self::TEMPLATE === $this->type; + } + + public function isBlock() + { + return self::BLOCK === $this->type; + } + + public function isMacro() + { + return self::MACRO === $this->type; + } + + public function getProfiles() + { + return $this->profiles; + } + + public function addProfile(Twig_Profiler_Profile $profile) + { + $this->profiles[] = $profile; + } + + /** + * Returns the duration in microseconds. + * + * @return int + */ + public function getDuration() + { + return isset($this->ends['wt']) && isset($this->starts['wt']) ? $this->ends['wt'] - $this->starts['wt'] : 0; + } + + /** + * Returns the memory usage in bytes. + * + * @return int + */ + public function getMemoryUsage() + { + return isset($this->ends['mu']) && isset($this->starts['mu']) ? $this->ends['mu'] - $this->starts['mu'] : 0; + } + + /** + * Returns the peak memory usage in bytes. + * + * @return int + */ + public function getPeakMemoryUsage() + { + return isset($this->ends['pmu']) && isset($this->starts['pmu']) ? $this->ends['pmu'] - $this->starts['pmu'] : 0; + } + + /** + * Starts the profiling. + */ + public function enter() + { + $this->starts = array( + 'wt' => microtime(true), + 'mu' => memory_get_usage(), + 'pmu' => memory_get_peak_usage(), + ); + } + + /** + * Stops the profiling. + */ + public function leave() + { + $this->ends = array( + 'wt' => microtime(true), + 'mu' => memory_get_usage(), + 'pmu' => memory_get_peak_usage(), + ); + } + + public function getIterator() + { + return new ArrayIterator($this->profiles); + } + + public function serialize() + { + return serialize(array($this->template, $this->name, $this->type, $this->starts, $this->ends, $this->profiles)); + } + + public function unserialize($data) + { + list($this->template, $this->name, $this->type, $this->starts, $this->ends, $this->profiles) = unserialize($data); } } diff --git a/system/libs/twig/RuntimeLoader/ContainerRuntimeLoader.php b/system/libs/twig/RuntimeLoader/ContainerRuntimeLoader.php deleted file mode 100755 index 35ff7afb..00000000 --- a/system/libs/twig/RuntimeLoader/ContainerRuntimeLoader.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Sandbox_SecurityError extends Twig_Error +{ } diff --git a/system/libs/twig/Sandbox/SecurityNotAllowedFilterError.php b/system/libs/twig/Sandbox/SecurityNotAllowedFilterError.php index b56d2c9b..99faba9d 100755 --- a/system/libs/twig/Sandbox/SecurityNotAllowedFilterError.php +++ b/system/libs/twig/Sandbox/SecurityNotAllowedFilterError.php @@ -1,11 +1,31 @@ + */ +class Twig_Sandbox_SecurityNotAllowedFilterError extends Twig_Sandbox_SecurityError +{ + private $filterName; -if (\false) { - class SecurityNotAllowedFilterError extends \Twig_Sandbox_SecurityNotAllowedFilterError + public function __construct($message, $functionName, $lineno = -1, $filename = null, Exception $previous = null) { + parent::__construct($message, $lineno, $filename, $previous); + $this->filterName = $functionName; + } + + public function getFilterName() + { + return $this->filterName; } } diff --git a/system/libs/twig/Sandbox/SecurityNotAllowedFunctionError.php b/system/libs/twig/Sandbox/SecurityNotAllowedFunctionError.php index 1a91764f..05cf488a 100755 --- a/system/libs/twig/Sandbox/SecurityNotAllowedFunctionError.php +++ b/system/libs/twig/Sandbox/SecurityNotAllowedFunctionError.php @@ -1,11 +1,31 @@ + */ +class Twig_Sandbox_SecurityNotAllowedFunctionError extends Twig_Sandbox_SecurityError +{ + private $functionName; -if (\false) { - class SecurityNotAllowedFunctionError extends \Twig_Sandbox_SecurityNotAllowedFunctionError + public function __construct($message, $functionName, $lineno = -1, $filename = null, Exception $previous = null) { + parent::__construct($message, $lineno, $filename, $previous); + $this->functionName = $functionName; + } + + public function getFunctionName() + { + return $this->functionName; } } diff --git a/system/libs/twig/Sandbox/SecurityNotAllowedMethodError.php b/system/libs/twig/Sandbox/SecurityNotAllowedMethodError.php deleted file mode 100755 index 9f81c69e..00000000 --- a/system/libs/twig/Sandbox/SecurityNotAllowedMethodError.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +class Twig_Sandbox_SecurityNotAllowedTagError extends Twig_Sandbox_SecurityError +{ + private $tagName; -if (\false) { - class SecurityNotAllowedTagError extends \Twig_Sandbox_SecurityNotAllowedTagError + public function __construct($message, $tagName, $lineno = -1, $filename = null, Exception $previous = null) { + parent::__construct($message, $lineno, $filename, $previous); + $this->tagName = $tagName; + } + + public function getTagName() + { + return $this->tagName; } } diff --git a/system/libs/twig/Sandbox/SecurityPolicy.php b/system/libs/twig/Sandbox/SecurityPolicy.php index b45b2852..c4dd03df 100755 --- a/system/libs/twig/Sandbox/SecurityPolicy.php +++ b/system/libs/twig/Sandbox/SecurityPolicy.php @@ -1,11 +1,119 @@ + */ +class Twig_Sandbox_SecurityPolicy implements Twig_Sandbox_SecurityPolicyInterface +{ + protected $allowedTags; + protected $allowedFilters; + protected $allowedMethods; + protected $allowedProperties; + protected $allowedFunctions; -if (\false) { - class SecurityPolicy extends \Twig_Sandbox_SecurityPolicy + public function __construct(array $allowedTags = array(), array $allowedFilters = array(), array $allowedMethods = array(), array $allowedProperties = array(), array $allowedFunctions = array()) { + $this->allowedTags = $allowedTags; + $this->allowedFilters = $allowedFilters; + $this->setAllowedMethods($allowedMethods); + $this->allowedProperties = $allowedProperties; + $this->allowedFunctions = $allowedFunctions; + } + + public function setAllowedTags(array $tags) + { + $this->allowedTags = $tags; + } + + public function setAllowedFilters(array $filters) + { + $this->allowedFilters = $filters; + } + + public function setAllowedMethods(array $methods) + { + $this->allowedMethods = array(); + foreach ($methods as $class => $m) { + $this->allowedMethods[$class] = array_map('strtolower', is_array($m) ? $m : array($m)); + } + } + + public function setAllowedProperties(array $properties) + { + $this->allowedProperties = $properties; + } + + public function setAllowedFunctions(array $functions) + { + $this->allowedFunctions = $functions; + } + + public function checkSecurity($tags, $filters, $functions) + { + foreach ($tags as $tag) { + if (!in_array($tag, $this->allowedTags)) { + throw new Twig_Sandbox_SecurityNotAllowedTagError(sprintf('Tag "%s" is not allowed.', $tag), $tag); + } + } + + foreach ($filters as $filter) { + if (!in_array($filter, $this->allowedFilters)) { + throw new Twig_Sandbox_SecurityNotAllowedFilterError(sprintf('Filter "%s" is not allowed.', $filter), $filter); + } + } + + foreach ($functions as $function) { + if (!in_array($function, $this->allowedFunctions)) { + throw new Twig_Sandbox_SecurityNotAllowedFunctionError(sprintf('Function "%s" is not allowed.', $function), $function); + } + } + } + + public function checkMethodAllowed($obj, $method) + { + if ($obj instanceof Twig_TemplateInterface || $obj instanceof Twig_Markup) { + return true; + } + + $allowed = false; + $method = strtolower($method); + foreach ($this->allowedMethods as $class => $methods) { + if ($obj instanceof $class) { + $allowed = in_array($method, $methods); + + break; + } + } + + if (!$allowed) { + throw new Twig_Sandbox_SecurityError(sprintf('Calling "%s" method on a "%s" object is not allowed.', $method, get_class($obj))); + } + } + + public function checkPropertyAllowed($obj, $property) + { + $allowed = false; + foreach ($this->allowedProperties as $class => $properties) { + if ($obj instanceof $class) { + $allowed = in_array($property, is_array($properties) ? $properties : array($properties)); + + break; + } + } + + if (!$allowed) { + throw new Twig_Sandbox_SecurityError(sprintf('Calling "%s" property on a "%s" object is not allowed.', $property, get_class($obj))); + } } } diff --git a/system/libs/twig/Sandbox/SecurityPolicyInterface.php b/system/libs/twig/Sandbox/SecurityPolicyInterface.php index 78a84e38..6ab48e3c 100755 --- a/system/libs/twig/Sandbox/SecurityPolicyInterface.php +++ b/system/libs/twig/Sandbox/SecurityPolicyInterface.php @@ -1,11 +1,24 @@ + */ +interface Twig_Sandbox_SecurityPolicyInterface +{ + public function checkSecurity($tags, $filters, $functions); -if (\false) { - interface SecurityPolicyInterface extends \Twig_Sandbox_SecurityPolicyInterface - { - } + public function checkMethodAllowed($obj, $method); + + public function checkPropertyAllowed($obj, $method); } diff --git a/system/libs/twig/SimpleFilter.php b/system/libs/twig/SimpleFilter.php new file mode 100755 index 00000000..5d6d27bf --- /dev/null +++ b/system/libs/twig/SimpleFilter.php @@ -0,0 +1,100 @@ + + */ +class Twig_SimpleFilter +{ + protected $name; + protected $callable; + protected $options; + protected $arguments = array(); + + public function __construct($name, $callable, array $options = array()) + { + $this->name = $name; + $this->callable = $callable; + $this->options = array_merge(array( + 'needs_environment' => false, + 'needs_context' => false, + 'is_variadic' => false, + 'is_safe' => null, + 'is_safe_callback' => null, + 'pre_escape' => null, + 'preserves_safety' => null, + 'node_class' => 'Twig_Node_Expression_Filter', + ), $options); + } + + public function getName() + { + return $this->name; + } + + public function getCallable() + { + return $this->callable; + } + + public function getNodeClass() + { + return $this->options['node_class']; + } + + public function setArguments($arguments) + { + $this->arguments = $arguments; + } + + public function getArguments() + { + return $this->arguments; + } + + public function needsEnvironment() + { + return $this->options['needs_environment']; + } + + public function needsContext() + { + return $this->options['needs_context']; + } + + public function getSafe(Twig_Node $filterArgs) + { + if (null !== $this->options['is_safe']) { + return $this->options['is_safe']; + } + + if (null !== $this->options['is_safe_callback']) { + return call_user_func($this->options['is_safe_callback'], $filterArgs); + } + } + + public function getPreservesSafety() + { + return $this->options['preserves_safety']; + } + + public function getPreEscape() + { + return $this->options['pre_escape']; + } + + public function isVariadic() + { + return $this->options['is_variadic']; + } +} diff --git a/system/libs/twig/SimpleFunction.php b/system/libs/twig/SimpleFunction.php new file mode 100755 index 00000000..8085f578 --- /dev/null +++ b/system/libs/twig/SimpleFunction.php @@ -0,0 +1,90 @@ + + */ +class Twig_SimpleFunction +{ + protected $name; + protected $callable; + protected $options; + protected $arguments = array(); + + public function __construct($name, $callable, array $options = array()) + { + $this->name = $name; + $this->callable = $callable; + $this->options = array_merge(array( + 'needs_environment' => false, + 'needs_context' => false, + 'is_variadic' => false, + 'is_safe' => null, + 'is_safe_callback' => null, + 'node_class' => 'Twig_Node_Expression_Function', + ), $options); + } + + public function getName() + { + return $this->name; + } + + public function getCallable() + { + return $this->callable; + } + + public function getNodeClass() + { + return $this->options['node_class']; + } + + public function setArguments($arguments) + { + $this->arguments = $arguments; + } + + public function getArguments() + { + return $this->arguments; + } + + public function needsEnvironment() + { + return $this->options['needs_environment']; + } + + public function needsContext() + { + return $this->options['needs_context']; + } + + public function getSafe(Twig_Node $functionArgs) + { + if (null !== $this->options['is_safe']) { + return $this->options['is_safe']; + } + + if (null !== $this->options['is_safe_callback']) { + return call_user_func($this->options['is_safe_callback'], $functionArgs); + } + + return array(); + } + + public function isVariadic() + { + return $this->options['is_variadic']; + } +} diff --git a/system/libs/twig/SimpleTest.php b/system/libs/twig/SimpleTest.php new file mode 100755 index 00000000..87b09354 --- /dev/null +++ b/system/libs/twig/SimpleTest.php @@ -0,0 +1,52 @@ + + */ +class Twig_SimpleTest +{ + protected $name; + protected $callable; + protected $options; + + public function __construct($name, $callable, array $options = array()) + { + $this->name = $name; + $this->callable = $callable; + $this->options = array_merge(array( + 'is_variadic' => false, + 'node_class' => 'Twig_Node_Expression_Test', + ), $options); + } + + public function getName() + { + return $this->name; + } + + public function getCallable() + { + return $this->callable; + } + + public function getNodeClass() + { + return $this->options['node_class']; + } + + public function isVariadic() + { + return $this->options['is_variadic']; + } +} diff --git a/system/libs/twig/Source.php b/system/libs/twig/Source.php deleted file mode 100755 index b4978136..00000000 --- a/system/libs/twig/Source.php +++ /dev/null @@ -1,11 +0,0 @@ - + */ +abstract class Twig_Template implements Twig_TemplateInterface +{ + protected static $cache = array(); -if (\false) { - class Template extends \Twig_Template + protected $parent; + protected $parents = array(); + protected $env; + protected $blocks; + protected $traits; + + /** + * Constructor. + * + * @param Twig_Environment $env A Twig_Environment instance + */ + public function __construct(Twig_Environment $env) { + $this->env = $env; + $this->blocks = array(); + $this->traits = array(); + } + + /** + * Returns the template name. + * + * @return string The template name + */ + abstract public function getTemplateName(); + + /** + * @deprecated since 1.20 (to be removed in 2.0) + */ + public function getEnvironment() + { + @trigger_error('The '.__METHOD__.' method is deprecated since version 1.20 and will be removed in 2.0.', E_USER_DEPRECATED); + + return $this->env; + } + + /** + * Returns the parent template. + * + * This method is for internal use only and should never be called + * directly. + * + * @param array $context + * + * @return Twig_TemplateInterface|false The parent template or false if there is no parent + */ + public function getParent(array $context) + { + if (null !== $this->parent) { + return $this->parent; + } + + try { + $parent = $this->doGetParent($context); + + if (false === $parent) { + return false; + } + + if ($parent instanceof self) { + return $this->parents[$parent->getTemplateName()] = $parent; + } + + if (!isset($this->parents[$parent])) { + $this->parents[$parent] = $this->loadTemplate($parent); + } + } catch (Twig_Error_Loader $e) { + $e->setTemplateFile(null); + $e->guess(); + + throw $e; + } + + return $this->parents[$parent]; + } + + protected function doGetParent(array $context) + { + return false; + } + + public function isTraitable() + { + return true; + } + + /** + * Displays a parent block. + * + * This method is for internal use only and should never be called + * directly. + * + * @param string $name The block name to display from the parent + * @param array $context The context + * @param array $blocks The current set of blocks + */ + public function displayParentBlock($name, array $context, array $blocks = array()) + { + $name = (string) $name; + + if (isset($this->traits[$name])) { + $this->traits[$name][0]->displayBlock($name, $context, $blocks, false); + } elseif (false !== $parent = $this->getParent($context)) { + $parent->displayBlock($name, $context, $blocks, false); + } else { + throw new Twig_Error_Runtime(sprintf('The template has no parent and no traits defining the "%s" block', $name), -1, $this->getTemplateName()); + } + } + + /** + * Displays a block. + * + * This method is for internal use only and should never be called + * directly. + * + * @param string $name The block name to display + * @param array $context The context + * @param array $blocks The current set of blocks + * @param bool $useBlocks Whether to use the current set of blocks + */ + public function displayBlock($name, array $context, array $blocks = array(), $useBlocks = true) + { + $name = (string) $name; + + if ($useBlocks && isset($blocks[$name])) { + $template = $blocks[$name][0]; + $block = $blocks[$name][1]; + } elseif (isset($this->blocks[$name])) { + $template = $this->blocks[$name][0]; + $block = $this->blocks[$name][1]; + } else { + $template = null; + $block = null; + } + + if (null !== $template) { + // avoid RCEs when sandbox is enabled + if (!$template instanceof Twig_Template) { + throw new \LogicException('A block must be a method on a Twig_Template instance.'); + } + + try { + $template->$block($context, $blocks); + } catch (Twig_Error $e) { + if (!$e->getTemplateFile()) { + $e->setTemplateFile($template->getTemplateName()); + } + + // this is mostly useful for Twig_Error_Loader exceptions + // see Twig_Error_Loader + if (false === $e->getTemplateLine()) { + $e->setTemplateLine(-1); + $e->guess(); + } + + throw $e; + } catch (Exception $e) { + throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $template->getTemplateName(), $e); + } + } elseif (false !== $parent = $this->getParent($context)) { + $parent->displayBlock($name, $context, array_merge($this->blocks, $blocks), false); + } + } + + /** + * Renders a parent block. + * + * This method is for internal use only and should never be called + * directly. + * + * @param string $name The block name to render from the parent + * @param array $context The context + * @param array $blocks The current set of blocks + * + * @return string The rendered block + */ + public function renderParentBlock($name, array $context, array $blocks = array()) + { + ob_start(); + $this->displayParentBlock($name, $context, $blocks); + + return ob_get_clean(); + } + + /** + * Renders a block. + * + * This method is for internal use only and should never be called + * directly. + * + * @param string $name The block name to render + * @param array $context The context + * @param array $blocks The current set of blocks + * @param bool $useBlocks Whether to use the current set of blocks + * + * @return string The rendered block + */ + public function renderBlock($name, array $context, array $blocks = array(), $useBlocks = true) + { + ob_start(); + $this->displayBlock($name, $context, $blocks, $useBlocks); + + return ob_get_clean(); + } + + /** + * Returns whether a block exists or not. + * + * This method is for internal use only and should never be called + * directly. + * + * This method does only return blocks defined in the current template + * or defined in "used" traits. + * + * It does not return blocks from parent templates as the parent + * template name can be dynamic, which is only known based on the + * current context. + * + * @param string $name The block name + * + * @return bool true if the block exists, false otherwise + */ + public function hasBlock($name) + { + return isset($this->blocks[(string) $name]); + } + + /** + * Returns all block names. + * + * This method is for internal use only and should never be called + * directly. + * + * @return array An array of block names + * + * @see hasBlock + */ + public function getBlockNames() + { + return array_keys($this->blocks); + } + + protected function loadTemplate($template, $templateName = null, $line = null, $index = null) + { + try { + if (is_array($template)) { + return $this->env->resolveTemplate($template); + } + + if ($template instanceof self) { + return $template; + } + + return $this->env->loadTemplate($template, $index); + } catch (Twig_Error $e) { + if (!$e->getTemplateFile()) { + $e->setTemplateFile($templateName ? $templateName : $this->getTemplateName()); + } + + if ($e->getTemplateLine()) { + throw $e; + } + + if (!$line) { + $e->guess(); + } else { + $e->setTemplateLine($line); + } + + throw $e; + } + } + + /** + * Returns all blocks. + * + * This method is for internal use only and should never be called + * directly. + * + * @return array An array of blocks + * + * @see hasBlock + */ + public function getBlocks() + { + return $this->blocks; + } + + /** + * {@inheritdoc} + */ + public function display(array $context, array $blocks = array()) + { + $this->displayWithErrorHandling($this->env->mergeGlobals($context), array_merge($this->blocks, $blocks)); + } + + /** + * {@inheritdoc} + */ + public function render(array $context) + { + $level = ob_get_level(); + ob_start(); + try { + $this->display($context); + } catch (Exception $e) { + while (ob_get_level() > $level) { + ob_end_clean(); + } + + throw $e; + } + + return ob_get_clean(); + } + + protected function displayWithErrorHandling(array $context, array $blocks = array()) + { + try { + $this->doDisplay($context, $blocks); + } catch (Twig_Error $e) { + if (!$e->getTemplateFile()) { + $e->setTemplateFile($this->getTemplateName()); + } + + // this is mostly useful for Twig_Error_Loader exceptions + // see Twig_Error_Loader + if (false === $e->getTemplateLine()) { + $e->setTemplateLine(-1); + $e->guess(); + } + + throw $e; + } catch (Exception $e) { + throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $this->getTemplateName(), $e); + } + } + + /** + * Auto-generated method to display the template with the given context. + * + * @param array $context An array of parameters to pass to the template + * @param array $blocks An array of blocks to pass to the template + */ + abstract protected function doDisplay(array $context, array $blocks = array()); + + /** + * Returns a variable from the context. + * + * This method is for internal use only and should never be called + * directly. + * + * This method should not be overridden in a sub-class as this is an + * implementation detail that has been introduced to optimize variable + * access for versions of PHP before 5.4. This is not a way to override + * the way to get a variable value. + * + * @param array $context The context + * @param string $item The variable to return from the context + * @param bool $ignoreStrictCheck Whether to ignore the strict variable check or not + * + * @return mixed The content of the context variable + * + * @throws Twig_Error_Runtime if the variable does not exist and Twig is running in strict mode + */ + final protected function getContext($context, $item, $ignoreStrictCheck = false) + { + if (!array_key_exists($item, $context)) { + if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { + return; + } + + throw new Twig_Error_Runtime(sprintf('Variable "%s" does not exist', $item), -1, $this->getTemplateName()); + } + + return $context[$item]; + } + + /** + * Returns the attribute value for a given array/object. + * + * @param mixed $object The object or array from where to get the item + * @param mixed $item The item to get from the array or object + * @param array $arguments An array of arguments to pass if the item is an object method + * @param string $type The type of attribute (@see Twig_Template constants) + * @param bool $isDefinedTest Whether this is only a defined check + * @param bool $ignoreStrictCheck Whether to ignore the strict attribute check or not + * + * @return mixed The attribute value, or a Boolean when $isDefinedTest is true, or null when the attribute is not set and $ignoreStrictCheck is true + * + * @throws Twig_Error_Runtime if the attribute does not exist and Twig is running in strict mode and $isDefinedTest is false + */ + protected function getAttribute($object, $item, array $arguments = array(), $type = self::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false) + { + // array + if (self::METHOD_CALL !== $type) { + $arrayItem = is_bool($item) || is_float($item) ? (int) $item : $item; + + if ((is_array($object) && array_key_exists($arrayItem, $object)) + || ($object instanceof ArrayAccess && isset($object[$arrayItem])) + ) { + if ($isDefinedTest) { + return true; + } + + return $object[$arrayItem]; + } + + if (self::ARRAY_CALL === $type || !is_object($object)) { + if ($isDefinedTest) { + return false; + } + + if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { + return; + } + + if ($object instanceof ArrayAccess) { + $message = sprintf('Key "%s" in object with ArrayAccess of class "%s" does not exist', $arrayItem, get_class($object)); + } elseif (is_object($object)) { + $message = sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface', $item, get_class($object)); + } elseif (is_array($object)) { + if (empty($object)) { + $message = sprintf('Key "%s" does not exist as the array is empty', $arrayItem); + } else { + $message = sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object))); + } + } elseif (self::ARRAY_CALL === $type) { + if (null === $object) { + $message = sprintf('Impossible to access a key ("%s") on a null variable', $item); + } else { + $message = sprintf('Impossible to access a key ("%s") on a %s variable ("%s")', $item, gettype($object), $object); + } + } elseif (null === $object) { + $message = sprintf('Impossible to access an attribute ("%s") on a null variable', $item); + } else { + $message = sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s")', $item, gettype($object), $object); + } + + throw new Twig_Error_Runtime($message, -1, $this->getTemplateName()); + } + } + + if (!is_object($object)) { + if ($isDefinedTest) { + return false; + } + + if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { + return; + } + + if (null === $object) { + $message = sprintf('Impossible to invoke a method ("%s") on a null variable', $item); + } else { + $message = sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s")', $item, gettype($object), $object); + } + + throw new Twig_Error_Runtime($message, -1, $this->getTemplateName()); + } + + // object property + if (self::METHOD_CALL !== $type && !$object instanceof self) { // Twig_Template does not have public properties, and we don't want to allow access to internal ones + if (isset($object->$item) || array_key_exists((string) $item, $object)) { + if ($isDefinedTest) { + return true; + } + + if ($this->env->hasExtension('sandbox')) { + $this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item); + } + + return $object->$item; + } + } + + $class = get_class($object); + + // object method + if (!isset(self::$cache[$class]['methods'])) { + // get_class_methods returns all methods accessible in the scope, but we only want public ones to be accessible in templates + if ($object instanceof self) { + $ref = new ReflectionClass($class); + $methods = array(); + + foreach ($ref->getMethods(ReflectionMethod::IS_PUBLIC) as $refMethod) { + $methodName = strtolower($refMethod->name); + + // Accessing the environment from templates is forbidden to prevent untrusted changes to the environment + if ('getenvironment' !== $methodName) { + $methods[$methodName] = true; + } + } + + self::$cache[$class]['methods'] = $methods; + } else { + self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object))); + } + } + + $call = false; + $lcItem = strtolower($item); + if (isset(self::$cache[$class]['methods'][$lcItem])) { + $method = (string) $item; + } elseif (isset(self::$cache[$class]['methods']['get'.$lcItem])) { + $method = 'get'.$item; + } elseif (isset(self::$cache[$class]['methods']['is'.$lcItem])) { + $method = 'is'.$item; + } elseif (isset(self::$cache[$class]['methods']['__call'])) { + $method = (string) $item; + $call = true; + } else { + if ($isDefinedTest) { + return false; + } + + if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { + return; + } + + throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object)), -1, $this->getTemplateName()); + } + + if ($isDefinedTest) { + return true; + } + + if ($this->env->hasExtension('sandbox')) { + $this->env->getExtension('sandbox')->checkMethodAllowed($object, $method); + } + + // Some objects throw exceptions when they have __call, and the method we try + // to call is not supported. If ignoreStrictCheck is true, we should return null. + try { + $ret = call_user_func_array(array($object, $method), $arguments); + } catch (BadMethodCallException $e) { + if ($call && ($ignoreStrictCheck || !$this->env->isStrictVariables())) { + return; + } + throw $e; + } + + // useful when calling a template method from a template + // this is not supported but unfortunately heavily used in the Symfony profiler + if ($object instanceof Twig_TemplateInterface) { + return $ret === '' ? '' : new Twig_Markup($ret, $this->env->getCharset()); + } + + return $ret; } } diff --git a/system/libs/twig/TemplateInterface.php b/system/libs/twig/TemplateInterface.php new file mode 100755 index 00000000..32746407 --- /dev/null +++ b/system/libs/twig/TemplateInterface.php @@ -0,0 +1,48 @@ + + * + * @deprecated since 1.12 (to be removed in 3.0) + */ +interface Twig_TemplateInterface +{ + const ANY_CALL = 'any'; + const ARRAY_CALL = 'array'; + const METHOD_CALL = 'method'; + + /** + * Renders the template with the given context and returns it as string. + * + * @param array $context An array of parameters to pass to the template + * + * @return string The rendered template + */ + public function render(array $context); + + /** + * Displays the template with the given context. + * + * @param array $context An array of parameters to pass to the template + * @param array $blocks An array of blocks to pass to the template + */ + public function display(array $context, array $blocks = array()); + + /** + * Returns the bound environment for this template. + * + * @return Twig_Environment The current environment + */ + public function getEnvironment(); +} diff --git a/system/libs/twig/TemplateWrapper.php b/system/libs/twig/TemplateWrapper.php deleted file mode 100755 index d11ad81c..00000000 --- a/system/libs/twig/TemplateWrapper.php +++ /dev/null @@ -1,11 +0,0 @@ - + * + * @deprecated since 1.12 (to be removed in 2.0) + */ +abstract class Twig_Test implements Twig_TestInterface, Twig_TestCallableInterface +{ + protected $options; + protected $arguments = array(); + + public function __construct(array $options = array()) + { + $this->options = array_merge(array( + 'callable' => null, + ), $options); + } + + public function getCallable() + { + return $this->options['callable']; + } +} diff --git a/system/libs/twig/Test/Function.php b/system/libs/twig/Test/Function.php new file mode 100755 index 00000000..30e1c623 --- /dev/null +++ b/system/libs/twig/Test/Function.php @@ -0,0 +1,36 @@ + + * + * @deprecated since 1.12 (to be removed in 2.0) + */ +class Twig_Test_Function extends Twig_Test +{ + protected $function; + + public function __construct($function, array $options = array()) + { + $options['callable'] = $function; + + parent::__construct($options); + + $this->function = $function; + } + + public function compile() + { + return $this->function; + } +} diff --git a/system/libs/twig/Test/IntegrationTestCase.php b/system/libs/twig/Test/IntegrationTestCase.php index 50f90ac4..261acd41 100755 --- a/system/libs/twig/Test/IntegrationTestCase.php +++ b/system/libs/twig/Test/IntegrationTestCase.php @@ -1,11 +1,162 @@ + * @author Karma Dordrak + */ +abstract class Twig_Test_IntegrationTestCase extends PHPUnit_Framework_TestCase +{ + abstract protected function getExtensions(); + abstract protected function getFixturesDir(); -if (\false) { - class IntegrationTestCase extends \Twig_Test_IntegrationTestCase + /** + * @dataProvider getTests + */ + public function testIntegration($file, $message, $condition, $templates, $exception, $outputs) { + $this->doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs); + } + + public function getTests() + { + $fixturesDir = realpath($this->getFixturesDir()); + $tests = array(); + + foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($fixturesDir), RecursiveIteratorIterator::LEAVES_ONLY) as $file) { + if (!preg_match('/\.test$/', $file)) { + continue; + } + + $test = file_get_contents($file->getRealpath()); + + if (preg_match('/ + --TEST--\s*(.*?)\s*(?:--CONDITION--\s*(.*))?\s*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)\s*(?:--DATA--\s*(.*))?\s*--EXCEPTION--\s*(.*)/sx', $test, $match)) { + $message = $match[1]; + $condition = $match[2]; + $templates = $this->parseTemplates($match[3]); + $exception = $match[5]; + $outputs = array(array(null, $match[4], null, '')); + } elseif (preg_match('/--TEST--\s*(.*?)\s*(?:--CONDITION--\s*(.*))?\s*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)--DATA--.*?--EXPECT--.*/s', $test, $match)) { + $message = $match[1]; + $condition = $match[2]; + $templates = $this->parseTemplates($match[3]); + $exception = false; + preg_match_all('/--DATA--(.*?)(?:--CONFIG--(.*?))?--EXPECT--(.*?)(?=\-\-DATA\-\-|$)/s', $test, $outputs, PREG_SET_ORDER); + } else { + throw new InvalidArgumentException(sprintf('Test "%s" is not valid.', str_replace($fixturesDir.'/', '', $file))); + } + + $tests[] = array(str_replace($fixturesDir.'/', '', $file), $message, $condition, $templates, $exception, $outputs); + } + + return $tests; + } + + protected function doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs) + { + if ($condition) { + eval('$ret = '.$condition.';'); + if (!$ret) { + $this->markTestSkipped($condition); + } + } + + $loader = new Twig_Loader_Array($templates); + + foreach ($outputs as $i => $match) { + $config = array_merge(array( + 'cache' => false, + 'strict_variables' => true, + ), $match[2] ? eval($match[2].';') : array()); + $twig = new Twig_Environment($loader, $config); + $twig->addGlobal('global', 'global'); + foreach ($this->getExtensions() as $extension) { + $twig->addExtension($extension); + } + + // avoid using the same PHP class name for different cases + // only for PHP 5.2+ + if (PHP_VERSION_ID >= 50300) { + $p = new ReflectionProperty($twig, 'templateClassPrefix'); + $p->setAccessible(true); + $p->setValue($twig, '__TwigTemplate_'.hash('sha256', uniqid(mt_rand(), true), false).'_'); + } + + try { + $template = $twig->loadTemplate('index.twig'); + } catch (Exception $e) { + if (false !== $exception) { + $this->assertEquals(trim($exception), trim(sprintf('%s: %s', get_class($e), $e->getMessage()))); + + return; + } + + if ($e instanceof Twig_Error_Syntax) { + $e->setTemplateFile($file); + + throw $e; + } + + throw new Twig_Error(sprintf('%s: %s', get_class($e), $e->getMessage()), -1, $file, $e); + } + + try { + $output = trim($template->render(eval($match[1].';')), "\n "); + } catch (Exception $e) { + if (false !== $exception) { + $this->assertEquals(trim($exception), trim(sprintf('%s: %s', get_class($e), $e->getMessage()))); + + return; + } + + if ($e instanceof Twig_Error_Syntax) { + $e->setTemplateFile($file); + } else { + $e = new Twig_Error(sprintf('%s: %s', get_class($e), $e->getMessage()), -1, $file, $e); + } + + $output = trim(sprintf('%s: %s', get_class($e), $e->getMessage())); + } + + if (false !== $exception) { + list($class) = explode(':', $exception); + $this->assertThat(null, new PHPUnit_Framework_Constraint_Exception($class)); + } + + $expected = trim($match[3], "\n "); + + if ($expected != $output) { + printf("Compiled templates that failed on case %d:\n", $i + 1); + + foreach (array_keys($templates) as $name) { + echo "Template: $name\n"; + $source = $loader->getSource($name); + echo $twig->compile($twig->parse($twig->tokenize($source, $name))); + } + } + $this->assertEquals($expected, $output, $message.' (in '.$file.')'); + } + } + + protected static function parseTemplates($test) + { + $templates = array(); + preg_match_all('/--TEMPLATE(?:\((.*?)\))?--(.*?)(?=\-\-TEMPLATE|$)/s', $test, $matches, PREG_SET_ORDER); + foreach ($matches as $match) { + $templates[($match[1] ? $match[1] : 'index.twig')] = $match[2]; + } + + return $templates; } } diff --git a/system/libs/twig/Test/Method.php b/system/libs/twig/Test/Method.php new file mode 100755 index 00000000..7fc250ba --- /dev/null +++ b/system/libs/twig/Test/Method.php @@ -0,0 +1,38 @@ + + * + * @deprecated since 1.12 (to be removed in 2.0) + */ +class Twig_Test_Method extends Twig_Test +{ + protected $extension; + protected $method; + + public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array()) + { + $options['callable'] = array($extension, $method); + + parent::__construct($options); + + $this->extension = $extension; + $this->method = $method; + } + + public function compile() + { + return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method); + } +} diff --git a/system/libs/twig/Test/Node.php b/system/libs/twig/Test/Node.php new file mode 100755 index 00000000..cdf0b24a --- /dev/null +++ b/system/libs/twig/Test/Node.php @@ -0,0 +1,38 @@ + + * + * @deprecated since 1.12 (to be removed in 2.0) + */ +class Twig_Test_Node extends Twig_Test +{ + protected $class; + + public function __construct($class, array $options = array()) + { + parent::__construct($options); + + $this->class = $class; + } + + public function getClass() + { + return $this->class; + } + + public function compile() + { + } +} diff --git a/system/libs/twig/Test/NodeTestCase.php b/system/libs/twig/Test/NodeTestCase.php index bf56b974..bf865211 100755 --- a/system/libs/twig/Test/NodeTestCase.php +++ b/system/libs/twig/Test/NodeTestCase.php @@ -1,11 +1,60 @@ assertNodeCompilation($source, $node, $environment); + } + + public function assertNodeCompilation($source, Twig_Node $node, Twig_Environment $environment = null) + { + $compiler = $this->getCompiler($environment); + $compiler->compile($node); + + $this->assertEquals($source, trim($compiler->getSource())); + } + + protected function getCompiler(Twig_Environment $environment = null) + { + return new Twig_Compiler(null === $environment ? $this->getEnvironment() : $environment); + } + + protected function getEnvironment() + { + return new Twig_Environment(); + } + + protected function getVariableGetter($name, $line = false) + { + $line = $line > 0 ? "// line {$line}\n" : ''; + + if (PHP_VERSION_ID >= 50400) { + return sprintf('%s(isset($context["%s"]) ? $context["%s"] : null)', $line, $name, $name); + } + + return sprintf('%s$this->getContext($context, "%s")', $line, $name); + } + + protected function getAttributeGetter() + { + if (function_exists('twig_template_get_attributes')) { + return 'twig_template_get_attributes($this, '; + } + + return '$this->getAttribute('; } } diff --git a/system/libs/twig/TestCallableInterface.php b/system/libs/twig/TestCallableInterface.php new file mode 100755 index 00000000..98d34578 --- /dev/null +++ b/system/libs/twig/TestCallableInterface.php @@ -0,0 +1,22 @@ + + * + * @deprecated since 1.12 (to be removed in 2.0) + */ +interface Twig_TestCallableInterface +{ + public function getCallable(); +} diff --git a/system/libs/twig/TestInterface.php b/system/libs/twig/TestInterface.php new file mode 100755 index 00000000..2fa821ca --- /dev/null +++ b/system/libs/twig/TestInterface.php @@ -0,0 +1,27 @@ + + * + * @deprecated since 1.12 (to be removed in 2.0) + */ +interface Twig_TestInterface +{ + /** + * Compiles a test. + * + * @return string The PHP code for the test + */ + public function compile(); +} diff --git a/system/libs/twig/Token.php b/system/libs/twig/Token.php index c7751aa4..a0a029bc 100755 --- a/system/libs/twig/Token.php +++ b/system/libs/twig/Token.php @@ -1,11 +1,216 @@ + */ +class Twig_Token +{ + protected $value; + protected $type; + protected $lineno; -if (\false) { - class Token extends \Twig_Token + const EOF_TYPE = -1; + const TEXT_TYPE = 0; + const BLOCK_START_TYPE = 1; + const VAR_START_TYPE = 2; + const BLOCK_END_TYPE = 3; + const VAR_END_TYPE = 4; + const NAME_TYPE = 5; + const NUMBER_TYPE = 6; + const STRING_TYPE = 7; + const OPERATOR_TYPE = 8; + const PUNCTUATION_TYPE = 9; + const INTERPOLATION_START_TYPE = 10; + const INTERPOLATION_END_TYPE = 11; + + /** + * Constructor. + * + * @param int $type The type of the token + * @param string $value The token value + * @param int $lineno The line position in the source + */ + public function __construct($type, $value, $lineno) { + $this->type = $type; + $this->value = $value; + $this->lineno = $lineno; + } + + /** + * Returns a string representation of the token. + * + * @return string A string representation of the token + */ + public function __toString() + { + return sprintf('%s(%s)', self::typeToString($this->type, true), $this->value); + } + + /** + * Tests the current token for a type and/or a value. + * + * Parameters may be: + * * just type + * * type and value (or array of possible values) + * * just value (or array of possible values) (NAME_TYPE is used as type) + * + * @param array|int $type The type to test + * @param array|string|null $values The token value + * + * @return bool + */ + public function test($type, $values = null) + { + if (null === $values && !is_int($type)) { + $values = $type; + $type = self::NAME_TYPE; + } + + return ($this->type === $type) && ( + null === $values || + (is_array($values) && in_array($this->value, $values)) || + $this->value == $values + ); + } + + /** + * Gets the line. + * + * @return int The source line + */ + public function getLine() + { + return $this->lineno; + } + + /** + * Gets the token type. + * + * @return int The token type + */ + public function getType() + { + return $this->type; + } + + /** + * Gets the token value. + * + * @return string The token value + */ + public function getValue() + { + return $this->value; + } + + /** + * Returns the constant representation (internal) of a given type. + * + * @param int $type The type as an integer + * @param bool $short Whether to return a short representation or not + * + * @return string The string representation + */ + public static function typeToString($type, $short = false) + { + switch ($type) { + case self::EOF_TYPE: + $name = 'EOF_TYPE'; + break; + case self::TEXT_TYPE: + $name = 'TEXT_TYPE'; + break; + case self::BLOCK_START_TYPE: + $name = 'BLOCK_START_TYPE'; + break; + case self::VAR_START_TYPE: + $name = 'VAR_START_TYPE'; + break; + case self::BLOCK_END_TYPE: + $name = 'BLOCK_END_TYPE'; + break; + case self::VAR_END_TYPE: + $name = 'VAR_END_TYPE'; + break; + case self::NAME_TYPE: + $name = 'NAME_TYPE'; + break; + case self::NUMBER_TYPE: + $name = 'NUMBER_TYPE'; + break; + case self::STRING_TYPE: + $name = 'STRING_TYPE'; + break; + case self::OPERATOR_TYPE: + $name = 'OPERATOR_TYPE'; + break; + case self::PUNCTUATION_TYPE: + $name = 'PUNCTUATION_TYPE'; + break; + case self::INTERPOLATION_START_TYPE: + $name = 'INTERPOLATION_START_TYPE'; + break; + case self::INTERPOLATION_END_TYPE: + $name = 'INTERPOLATION_END_TYPE'; + break; + default: + throw new LogicException(sprintf('Token of type "%s" does not exist.', $type)); + } + + return $short ? $name : 'Twig_Token::'.$name; + } + + /** + * Returns the english representation of a given type. + * + * @param int $type The type as an integer + * + * @return string The string representation + */ + public static function typeToEnglish($type) + { + switch ($type) { + case self::EOF_TYPE: + return 'end of template'; + case self::TEXT_TYPE: + return 'text'; + case self::BLOCK_START_TYPE: + return 'begin of statement block'; + case self::VAR_START_TYPE: + return 'begin of print statement'; + case self::BLOCK_END_TYPE: + return 'end of statement block'; + case self::VAR_END_TYPE: + return 'end of print statement'; + case self::NAME_TYPE: + return 'name'; + case self::NUMBER_TYPE: + return 'number'; + case self::STRING_TYPE: + return 'string'; + case self::OPERATOR_TYPE: + return 'operator'; + case self::PUNCTUATION_TYPE: + return 'punctuation'; + case self::INTERPOLATION_START_TYPE: + return 'begin of string interpolation'; + case self::INTERPOLATION_END_TYPE: + return 'end of string interpolation'; + default: + throw new LogicException(sprintf('Token of type "%s" does not exist.', $type)); + } } } diff --git a/system/libs/twig/TokenParser.php b/system/libs/twig/TokenParser.php new file mode 100755 index 00000000..fa9b6d86 --- /dev/null +++ b/system/libs/twig/TokenParser.php @@ -0,0 +1,33 @@ + + */ +abstract class Twig_TokenParser implements Twig_TokenParserInterface +{ + /** + * @var Twig_Parser + */ + protected $parser; + + /** + * Sets the parser associated with this token parser. + * + * @param Twig_Parser $parser A Twig_Parser instance + */ + public function setParser(Twig_Parser $parser) + { + $this->parser = $parser; + } +} diff --git a/system/libs/twig/TokenParser/AbstractTokenParser.php b/system/libs/twig/TokenParser/AbstractTokenParser.php deleted file mode 100755 index 6ae78a59..00000000 --- a/system/libs/twig/TokenParser/AbstractTokenParser.php +++ /dev/null @@ -1,11 +0,0 @@ - + * {% autoescape true %} + * Everything will be automatically escaped in this block + * {% endautoescape %} + * + * {% autoescape false %} + * Everything will be outputed as is in this block + * {% endautoescape %} + * + * {% autoescape true js %} + * Everything will be automatically escaped in this block + * using the js escaping strategy + * {% endautoescape %} + * + */ +class Twig_TokenParser_AutoEscape extends Twig_TokenParser +{ + /** + * Parses a token and returns a node. + * + * @param Twig_Token $token A Twig_Token instance + * + * @return Twig_NodeInterface A Twig_NodeInterface instance + */ + public function parse(Twig_Token $token) + { + $lineno = $token->getLine(); + $stream = $this->parser->getStream(); + + if ($stream->test(Twig_Token::BLOCK_END_TYPE)) { + $value = 'html'; + } else { + $expr = $this->parser->getExpressionParser()->parseExpression(); + if (!$expr instanceof Twig_Node_Expression_Constant) { + throw new Twig_Error_Syntax('An escaping strategy must be a string or a Boolean.', $stream->getCurrent()->getLine(), $stream->getFilename()); + } + $value = $expr->getAttribute('value'); + + $compat = true === $value || false === $value; + + if (true === $value) { + $value = 'html'; + } + + if ($compat && $stream->test(Twig_Token::NAME_TYPE)) { + if (false === $value) { + throw new Twig_Error_Syntax('Unexpected escaping strategy as you set autoescaping to false.', $stream->getCurrent()->getLine(), $stream->getFilename()); + } + + $value = $stream->next()->getValue(); + } + } + + $stream->expect(Twig_Token::BLOCK_END_TYPE); + $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true); + $stream->expect(Twig_Token::BLOCK_END_TYPE); + + return new Twig_Node_AutoEscape($value, $body, $lineno, $this->getTag()); + } + + public function decideBlockEnd(Twig_Token $token) + { + return $token->test('endautoescape'); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'autoescape'; + } +} diff --git a/system/libs/twig/TokenParser/AutoEscapeTokenParser.php b/system/libs/twig/TokenParser/AutoEscapeTokenParser.php deleted file mode 100755 index 68a99da5..00000000 --- a/system/libs/twig/TokenParser/AutoEscapeTokenParser.php +++ /dev/null @@ -1,11 +0,0 @@ - + * {% block head %} + * + * {% block title %}{% endblock %} - My Webpage + * {% endblock %} + * + */ +class Twig_TokenParser_Block extends Twig_TokenParser +{ + /** + * Parses a token and returns a node. + * + * @param Twig_Token $token A Twig_Token instance + * + * @return Twig_NodeInterface A Twig_NodeInterface instance + */ + public function parse(Twig_Token $token) + { + $lineno = $token->getLine(); + $stream = $this->parser->getStream(); + $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); + if ($this->parser->hasBlock($name)) { + throw new Twig_Error_Syntax(sprintf("The block '$name' has already been defined line %d", $this->parser->getBlock($name)->getLine()), $stream->getCurrent()->getLine(), $stream->getFilename()); + } + $this->parser->setBlock($name, $block = new Twig_Node_Block($name, new Twig_Node(array()), $lineno)); + $this->parser->pushLocalScope(); + $this->parser->pushBlockStack($name); + + if ($stream->nextIf(Twig_Token::BLOCK_END_TYPE)) { + $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true); + if ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) { + $value = $token->getValue(); + + if ($value != $name) { + throw new Twig_Error_Syntax(sprintf('Expected endblock for block "%s" (but "%s" given)', $name, $value), $stream->getCurrent()->getLine(), $stream->getFilename()); + } + } + } else { + $body = new Twig_Node(array( + new Twig_Node_Print($this->parser->getExpressionParser()->parseExpression(), $lineno), + )); + } + $stream->expect(Twig_Token::BLOCK_END_TYPE); + + $block->setNode('body', $body); + $this->parser->popBlockStack(); + $this->parser->popLocalScope(); + + return new Twig_Node_BlockReference($name, $lineno, $this->getTag()); + } + + public function decideBlockEnd(Twig_Token $token) + { + return $token->test('endblock'); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'block'; + } +} diff --git a/system/libs/twig/TokenParser/BlockTokenParser.php b/system/libs/twig/TokenParser/BlockTokenParser.php deleted file mode 100755 index 8be16830..00000000 --- a/system/libs/twig/TokenParser/BlockTokenParser.php +++ /dev/null @@ -1,11 +0,0 @@ -parser->getExpressionParser()->parseExpression(); + + $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); + + return new Twig_Node_Do($expr, $token->getLine(), $this->getTag()); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'do'; + } +} diff --git a/system/libs/twig/TokenParser/DoTokenParser.php b/system/libs/twig/TokenParser/DoTokenParser.php deleted file mode 100755 index a40b166d..00000000 --- a/system/libs/twig/TokenParser/DoTokenParser.php +++ /dev/null @@ -1,11 +0,0 @@ -parser->getStream(); + + $parent = $this->parser->getExpressionParser()->parseExpression(); + + list($variables, $only, $ignoreMissing) = $this->parseArguments(); + + // inject a fake parent to make the parent() function work + $stream->injectTokens(array( + new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', $token->getLine()), + new Twig_Token(Twig_Token::NAME_TYPE, 'extends', $token->getLine()), + new Twig_Token(Twig_Token::STRING_TYPE, '__parent__', $token->getLine()), + new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', $token->getLine()), + )); + + $module = $this->parser->parse($stream, array($this, 'decideBlockEnd'), true); + + // override the parent with the correct one + $module->setNode('parent', $parent); + + $this->parser->embedTemplate($module); + + $stream->expect(Twig_Token::BLOCK_END_TYPE); + + return new Twig_Node_Embed($module->getAttribute('filename'), $module->getAttribute('index'), $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag()); + } + + public function decideBlockEnd(Twig_Token $token) + { + return $token->test('endembed'); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'embed'; + } +} diff --git a/system/libs/twig/TokenParser/EmbedTokenParser.php b/system/libs/twig/TokenParser/EmbedTokenParser.php deleted file mode 100755 index f557db9d..00000000 --- a/system/libs/twig/TokenParser/EmbedTokenParser.php +++ /dev/null @@ -1,11 +0,0 @@ - + * {% extends "base.html" %} + * + */ +class Twig_TokenParser_Extends extends Twig_TokenParser +{ + /** + * Parses a token and returns a node. + * + * @param Twig_Token $token A Twig_Token instance + * + * @return Twig_NodeInterface A Twig_NodeInterface instance + */ + public function parse(Twig_Token $token) + { + if (!$this->parser->isMainScope()) { + throw new Twig_Error_Syntax('Cannot extend from a block', $token->getLine(), $this->parser->getFilename()); + } + + if (null !== $this->parser->getParent()) { + throw new Twig_Error_Syntax('Multiple extends tags are forbidden', $token->getLine(), $this->parser->getFilename()); + } + $this->parser->setParent($this->parser->getExpressionParser()->parseExpression()); + + $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'extends'; + } +} diff --git a/system/libs/twig/TokenParser/ExtendsTokenParser.php b/system/libs/twig/TokenParser/ExtendsTokenParser.php deleted file mode 100755 index cf929ab4..00000000 --- a/system/libs/twig/TokenParser/ExtendsTokenParser.php +++ /dev/null @@ -1,11 +0,0 @@ - + * {% filter upper %} + * This text becomes uppercase + * {% endfilter %} + * + */ +class Twig_TokenParser_Filter extends Twig_TokenParser +{ + /** + * Parses a token and returns a node. + * + * @param Twig_Token $token A Twig_Token instance + * + * @return Twig_NodeInterface A Twig_NodeInterface instance + */ + public function parse(Twig_Token $token) + { + $name = $this->parser->getVarName(); + $ref = new Twig_Node_Expression_BlockReference(new Twig_Node_Expression_Constant($name, $token->getLine()), true, $token->getLine(), $this->getTag()); + + $filter = $this->parser->getExpressionParser()->parseFilterExpressionRaw($ref, $this->getTag()); + $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); + + $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true); + $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); + + $block = new Twig_Node_Block($name, $body, $token->getLine()); + $this->parser->setBlock($name, $block); + + return new Twig_Node_Print($filter, $token->getLine(), $this->getTag()); + } + + public function decideBlockEnd(Twig_Token $token) + { + return $token->test('endfilter'); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'filter'; + } +} diff --git a/system/libs/twig/TokenParser/FilterTokenParser.php b/system/libs/twig/TokenParser/FilterTokenParser.php deleted file mode 100755 index de9d6ab4..00000000 --- a/system/libs/twig/TokenParser/FilterTokenParser.php +++ /dev/null @@ -1,11 +0,0 @@ -parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); + + return new Twig_Node_Flush($token->getLine(), $this->getTag()); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'flush'; + } +} diff --git a/system/libs/twig/TokenParser/FlushTokenParser.php b/system/libs/twig/TokenParser/FlushTokenParser.php deleted file mode 100755 index ce130264..00000000 --- a/system/libs/twig/TokenParser/FlushTokenParser.php +++ /dev/null @@ -1,11 +0,0 @@ - + *
    + * {% for user in users %} + *
  • {{ user.username|e }}
  • + * {% endfor %} + *
+ * + */ +class Twig_TokenParser_For extends Twig_TokenParser +{ + /** + * Parses a token and returns a node. + * + * @param Twig_Token $token A Twig_Token instance + * + * @return Twig_NodeInterface A Twig_NodeInterface instance + */ + public function parse(Twig_Token $token) + { + $lineno = $token->getLine(); + $stream = $this->parser->getStream(); + $targets = $this->parser->getExpressionParser()->parseAssignmentExpression(); + $stream->expect(Twig_Token::OPERATOR_TYPE, 'in'); + $seq = $this->parser->getExpressionParser()->parseExpression(); + + $ifexpr = null; + if ($stream->nextIf(Twig_Token::NAME_TYPE, 'if')) { + $ifexpr = $this->parser->getExpressionParser()->parseExpression(); + } + + $stream->expect(Twig_Token::BLOCK_END_TYPE); + $body = $this->parser->subparse(array($this, 'decideForFork')); + if ($stream->next()->getValue() == 'else') { + $stream->expect(Twig_Token::BLOCK_END_TYPE); + $else = $this->parser->subparse(array($this, 'decideForEnd'), true); + } else { + $else = null; + } + $stream->expect(Twig_Token::BLOCK_END_TYPE); + + if (count($targets) > 1) { + $keyTarget = $targets->getNode(0); + $keyTarget = new Twig_Node_Expression_AssignName($keyTarget->getAttribute('name'), $keyTarget->getLine()); + $valueTarget = $targets->getNode(1); + $valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getLine()); + } else { + $keyTarget = new Twig_Node_Expression_AssignName('_key', $lineno); + $valueTarget = $targets->getNode(0); + $valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getLine()); + } + + if ($ifexpr) { + $this->checkLoopUsageCondition($stream, $ifexpr); + $this->checkLoopUsageBody($stream, $body); + } + + return new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, $lineno, $this->getTag()); + } + + public function decideForFork(Twig_Token $token) + { + return $token->test(array('else', 'endfor')); + } + + public function decideForEnd(Twig_Token $token) + { + return $token->test('endfor'); + } + + // the loop variable cannot be used in the condition + protected function checkLoopUsageCondition(Twig_TokenStream $stream, Twig_NodeInterface $node) + { + if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) { + throw new Twig_Error_Syntax('The "loop" variable cannot be used in a looping condition', $node->getLine(), $stream->getFilename()); + } + + foreach ($node as $n) { + if (!$n) { + continue; + } + + $this->checkLoopUsageCondition($stream, $n); + } + } + + // check usage of non-defined loop-items + // it does not catch all problems (for instance when a for is included into another or when the variable is used in an include) + protected function checkLoopUsageBody(Twig_TokenStream $stream, Twig_NodeInterface $node) + { + if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) { + $attribute = $node->getNode('attribute'); + if ($attribute instanceof Twig_Node_Expression_Constant && in_array($attribute->getAttribute('value'), array('length', 'revindex0', 'revindex', 'last'))) { + throw new Twig_Error_Syntax(sprintf('The "loop.%s" variable is not defined when looping with a condition', $attribute->getAttribute('value')), $node->getLine(), $stream->getFilename()); + } + } + + // should check for parent.loop.XXX usage + if ($node instanceof Twig_Node_For) { + return; + } + + foreach ($node as $n) { + if (!$n) { + continue; + } + + $this->checkLoopUsageBody($stream, $n); + } + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'for'; + } +} diff --git a/system/libs/twig/TokenParser/ForTokenParser.php b/system/libs/twig/TokenParser/ForTokenParser.php deleted file mode 100755 index 25ddcea3..00000000 --- a/system/libs/twig/TokenParser/ForTokenParser.php +++ /dev/null @@ -1,11 +0,0 @@ - + * {% from 'forms.html' import forms %} + * + */ +class Twig_TokenParser_From extends Twig_TokenParser +{ + /** + * Parses a token and returns a node. + * + * @param Twig_Token $token A Twig_Token instance + * + * @return Twig_NodeInterface A Twig_NodeInterface instance + */ + public function parse(Twig_Token $token) + { + $macro = $this->parser->getExpressionParser()->parseExpression(); + $stream = $this->parser->getStream(); + $stream->expect('import'); + + $targets = array(); + do { + $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); + + $alias = $name; + if ($stream->nextIf('as')) { + $alias = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); + } + + $targets[$name] = $alias; + + if (!$stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) { + break; + } + } while (true); + + $stream->expect(Twig_Token::BLOCK_END_TYPE); + + $node = new Twig_Node_Import($macro, new Twig_Node_Expression_AssignName($this->parser->getVarName(), $token->getLine()), $token->getLine(), $this->getTag()); + + foreach ($targets as $name => $alias) { + if ($this->parser->isReservedMacroName($name)) { + throw new Twig_Error_Syntax(sprintf('"%s" cannot be an imported macro as it is a reserved keyword', $name), $token->getLine(), $stream->getFilename()); + } + + $this->parser->addImportedSymbol('function', $alias, 'get'.$name, $node->getNode('var')); + } + + return $node; + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'from'; + } +} diff --git a/system/libs/twig/TokenParser/FromTokenParser.php b/system/libs/twig/TokenParser/FromTokenParser.php deleted file mode 100755 index 1e5a4bc0..00000000 --- a/system/libs/twig/TokenParser/FromTokenParser.php +++ /dev/null @@ -1,11 +0,0 @@ - + * {% if users %} + *
    + * {% for user in users %} + *
  • {{ user.username|e }}
  • + * {% endfor %} + *
+ * {% endif %} + * + */ +class Twig_TokenParser_If extends Twig_TokenParser +{ + /** + * Parses a token and returns a node. + * + * @param Twig_Token $token A Twig_Token instance + * + * @return Twig_NodeInterface A Twig_NodeInterface instance + */ + public function parse(Twig_Token $token) + { + $lineno = $token->getLine(); + $expr = $this->parser->getExpressionParser()->parseExpression(); + $stream = $this->parser->getStream(); + $stream->expect(Twig_Token::BLOCK_END_TYPE); + $body = $this->parser->subparse(array($this, 'decideIfFork')); + $tests = array($expr, $body); + $else = null; + + $end = false; + while (!$end) { + switch ($stream->next()->getValue()) { + case 'else': + $stream->expect(Twig_Token::BLOCK_END_TYPE); + $else = $this->parser->subparse(array($this, 'decideIfEnd')); + break; + + case 'elseif': + $expr = $this->parser->getExpressionParser()->parseExpression(); + $stream->expect(Twig_Token::BLOCK_END_TYPE); + $body = $this->parser->subparse(array($this, 'decideIfFork')); + $tests[] = $expr; + $tests[] = $body; + break; + + case 'endif': + $end = true; + break; + + default: + throw new Twig_Error_Syntax(sprintf('Unexpected end of template. Twig was looking for the following tags "else", "elseif", or "endif" to close the "if" block started at line %d)', $lineno), $stream->getCurrent()->getLine(), $stream->getFilename()); + } + } + + $stream->expect(Twig_Token::BLOCK_END_TYPE); + + return new Twig_Node_If(new Twig_Node($tests), $else, $lineno, $this->getTag()); + } + + public function decideIfFork(Twig_Token $token) + { + return $token->test(array('elseif', 'else', 'endif')); + } + + public function decideIfEnd(Twig_Token $token) + { + return $token->test(array('endif')); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'if'; + } +} diff --git a/system/libs/twig/TokenParser/IfTokenParser.php b/system/libs/twig/TokenParser/IfTokenParser.php deleted file mode 100755 index 1852cf1e..00000000 --- a/system/libs/twig/TokenParser/IfTokenParser.php +++ /dev/null @@ -1,11 +0,0 @@ - + * {% import 'forms.html' as forms %} + * + */ +class Twig_TokenParser_Import extends Twig_TokenParser +{ + /** + * Parses a token and returns a node. + * + * @param Twig_Token $token A Twig_Token instance + * + * @return Twig_NodeInterface A Twig_NodeInterface instance + */ + public function parse(Twig_Token $token) + { + $macro = $this->parser->getExpressionParser()->parseExpression(); + $this->parser->getStream()->expect('as'); + $var = new Twig_Node_Expression_AssignName($this->parser->getStream()->expect(Twig_Token::NAME_TYPE)->getValue(), $token->getLine()); + $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); + + $this->parser->addImportedSymbol('template', $var->getAttribute('name')); + + return new Twig_Node_Import($macro, $var, $token->getLine(), $this->getTag()); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'import'; + } +} diff --git a/system/libs/twig/TokenParser/ImportTokenParser.php b/system/libs/twig/TokenParser/ImportTokenParser.php deleted file mode 100755 index 1a42d012..00000000 --- a/system/libs/twig/TokenParser/ImportTokenParser.php +++ /dev/null @@ -1,11 +0,0 @@ - + * {% include 'header.html' %} + * Body + * {% include 'footer.html' %} + * + */ +class Twig_TokenParser_Include extends Twig_TokenParser +{ + /** + * Parses a token and returns a node. + * + * @param Twig_Token $token A Twig_Token instance + * + * @return Twig_NodeInterface A Twig_NodeInterface instance + */ + public function parse(Twig_Token $token) + { + $expr = $this->parser->getExpressionParser()->parseExpression(); + + list($variables, $only, $ignoreMissing) = $this->parseArguments(); + + return new Twig_Node_Include($expr, $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag()); + } + + protected function parseArguments() + { + $stream = $this->parser->getStream(); + + $ignoreMissing = false; + if ($stream->nextIf(Twig_Token::NAME_TYPE, 'ignore')) { + $stream->expect(Twig_Token::NAME_TYPE, 'missing'); + + $ignoreMissing = true; + } + + $variables = null; + if ($stream->nextIf(Twig_Token::NAME_TYPE, 'with')) { + $variables = $this->parser->getExpressionParser()->parseExpression(); + } + + $only = false; + if ($stream->nextIf(Twig_Token::NAME_TYPE, 'only')) { + $only = true; + } + + $stream->expect(Twig_Token::BLOCK_END_TYPE); + + return array($variables, $only, $ignoreMissing); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'include'; + } +} diff --git a/system/libs/twig/TokenParser/IncludeTokenParser.php b/system/libs/twig/TokenParser/IncludeTokenParser.php deleted file mode 100755 index 7f8c061f..00000000 --- a/system/libs/twig/TokenParser/IncludeTokenParser.php +++ /dev/null @@ -1,11 +0,0 @@ - + * {% macro input(name, value, type, size) %} + * + * {% endmacro %} + * + */ +class Twig_TokenParser_Macro extends Twig_TokenParser +{ + /** + * Parses a token and returns a node. + * + * @param Twig_Token $token A Twig_Token instance + * + * @return Twig_NodeInterface A Twig_NodeInterface instance + */ + public function parse(Twig_Token $token) + { + $lineno = $token->getLine(); + $stream = $this->parser->getStream(); + $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); + + $arguments = $this->parser->getExpressionParser()->parseArguments(true, true); + + $stream->expect(Twig_Token::BLOCK_END_TYPE); + $this->parser->pushLocalScope(); + $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true); + if ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) { + $value = $token->getValue(); + + if ($value != $name) { + throw new Twig_Error_Syntax(sprintf('Expected endmacro for macro "%s" (but "%s" given)', $name, $value), $stream->getCurrent()->getLine(), $stream->getFilename()); + } + } + $this->parser->popLocalScope(); + $stream->expect(Twig_Token::BLOCK_END_TYPE); + + $this->parser->setMacro($name, new Twig_Node_Macro($name, new Twig_Node_Body(array($body)), $arguments, $lineno, $this->getTag())); + } + + public function decideBlockEnd(Twig_Token $token) + { + return $token->test('endmacro'); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'macro'; + } +} diff --git a/system/libs/twig/TokenParser/MacroTokenParser.php b/system/libs/twig/TokenParser/MacroTokenParser.php deleted file mode 100755 index 152fb267..00000000 --- a/system/libs/twig/TokenParser/MacroTokenParser.php +++ /dev/null @@ -1,11 +0,0 @@ - + * {% sandbox %} + * {% include 'user.html' %} + * {% endsandbox %} + * + * + * @see http://www.twig-project.org/doc/api.html#sandbox-extension for details + */ +class Twig_TokenParser_Sandbox extends Twig_TokenParser +{ + /** + * Parses a token and returns a node. + * + * @param Twig_Token $token A Twig_Token instance + * + * @return Twig_NodeInterface A Twig_NodeInterface instance + */ + public function parse(Twig_Token $token) + { + $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); + $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true); + $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); + + // in a sandbox tag, only include tags are allowed + if (!$body instanceof Twig_Node_Include) { + foreach ($body as $node) { + if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) { + continue; + } + + if (!$node instanceof Twig_Node_Include) { + throw new Twig_Error_Syntax('Only "include" tags are allowed within a "sandbox" section', $node->getLine(), $this->parser->getFilename()); + } + } + } + + return new Twig_Node_Sandbox($body, $token->getLine(), $this->getTag()); + } + + public function decideBlockEnd(Twig_Token $token) + { + return $token->test('endsandbox'); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'sandbox'; + } +} diff --git a/system/libs/twig/TokenParser/SandboxTokenParser.php b/system/libs/twig/TokenParser/SandboxTokenParser.php deleted file mode 100755 index e54c315a..00000000 --- a/system/libs/twig/TokenParser/SandboxTokenParser.php +++ /dev/null @@ -1,11 +0,0 @@ - + * {% set foo = 'foo' %} + * + * {% set foo = [1, 2] %} + * + * {% set foo = {'foo': 'bar'} %} + * + * {% set foo = 'foo' ~ 'bar' %} + * + * {% set foo, bar = 'foo', 'bar' %} + * + * {% set foo %}Some content{% endset %} + * + */ +class Twig_TokenParser_Set extends Twig_TokenParser +{ + /** + * Parses a token and returns a node. + * + * @param Twig_Token $token A Twig_Token instance + * + * @return Twig_NodeInterface A Twig_NodeInterface instance + */ + public function parse(Twig_Token $token) + { + $lineno = $token->getLine(); + $stream = $this->parser->getStream(); + $names = $this->parser->getExpressionParser()->parseAssignmentExpression(); + + $capture = false; + if ($stream->nextIf(Twig_Token::OPERATOR_TYPE, '=')) { + $values = $this->parser->getExpressionParser()->parseMultitargetExpression(); + + $stream->expect(Twig_Token::BLOCK_END_TYPE); + + if (count($names) !== count($values)) { + throw new Twig_Error_Syntax('When using set, you must have the same number of variables and assignments.', $stream->getCurrent()->getLine(), $stream->getFilename()); + } + } else { + $capture = true; + + if (count($names) > 1) { + throw new Twig_Error_Syntax('When using set with a block, you cannot have a multi-target.', $stream->getCurrent()->getLine(), $stream->getFilename()); + } + + $stream->expect(Twig_Token::BLOCK_END_TYPE); + + $values = $this->parser->subparse(array($this, 'decideBlockEnd'), true); + $stream->expect(Twig_Token::BLOCK_END_TYPE); + } + + return new Twig_Node_Set($capture, $names, $values, $lineno, $this->getTag()); + } + + public function decideBlockEnd(Twig_Token $token) + { + return $token->test('endset'); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'set'; + } +} diff --git a/system/libs/twig/TokenParser/SetTokenParser.php b/system/libs/twig/TokenParser/SetTokenParser.php deleted file mode 100755 index a9d04d7d..00000000 --- a/system/libs/twig/TokenParser/SetTokenParser.php +++ /dev/null @@ -1,11 +0,0 @@ - + * {% spaceless %} + *
+ * foo + *
+ * {% endspaceless %} + * + * {# output will be
foo
#} + * + */ +class Twig_TokenParser_Spaceless extends Twig_TokenParser +{ + /** + * Parses a token and returns a node. + * + * @param Twig_Token $token A Twig_Token instance + * + * @return Twig_NodeInterface A Twig_NodeInterface instance + */ + public function parse(Twig_Token $token) + { + $lineno = $token->getLine(); + + $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); + $body = $this->parser->subparse(array($this, 'decideSpacelessEnd'), true); + $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); + + return new Twig_Node_Spaceless($body, $lineno, $this->getTag()); + } + + public function decideSpacelessEnd(Twig_Token $token) + { + return $token->test('endspaceless'); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'spaceless'; + } +} diff --git a/system/libs/twig/TokenParser/SpacelessTokenParser.php b/system/libs/twig/TokenParser/SpacelessTokenParser.php deleted file mode 100755 index 5e7e3dd9..00000000 --- a/system/libs/twig/TokenParser/SpacelessTokenParser.php +++ /dev/null @@ -1,11 +0,0 @@ - + * {% extends "base.html" %} + * + * {% use "blocks.html" %} + * + * {% block title %}{% endblock %} + * {% block content %}{% endblock %} + * + * + * @see http://www.twig-project.org/doc/templates.html#horizontal-reuse for details. + */ +class Twig_TokenParser_Use extends Twig_TokenParser +{ + /** + * Parses a token and returns a node. + * + * @param Twig_Token $token A Twig_Token instance + * + * @return Twig_NodeInterface A Twig_NodeInterface instance + */ + public function parse(Twig_Token $token) + { + $template = $this->parser->getExpressionParser()->parseExpression(); + $stream = $this->parser->getStream(); + + if (!$template instanceof Twig_Node_Expression_Constant) { + throw new Twig_Error_Syntax('The template references in a "use" statement must be a string.', $stream->getCurrent()->getLine(), $stream->getFilename()); + } + + $targets = array(); + if ($stream->nextIf('with')) { + do { + $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); + + $alias = $name; + if ($stream->nextIf('as')) { + $alias = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); + } + + $targets[$name] = new Twig_Node_Expression_Constant($alias, -1); + + if (!$stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) { + break; + } + } while (true); + } + + $stream->expect(Twig_Token::BLOCK_END_TYPE); + + $this->parser->addTrait(new Twig_Node(array('template' => $template, 'targets' => new Twig_Node($targets)))); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'use'; + } +} diff --git a/system/libs/twig/TokenParser/UseTokenParser.php b/system/libs/twig/TokenParser/UseTokenParser.php deleted file mode 100755 index db58a605..00000000 --- a/system/libs/twig/TokenParser/UseTokenParser.php +++ /dev/null @@ -1,11 +0,0 @@ - + * + * @deprecated since 1.12 (to be removed in 2.0) + */ +class Twig_TokenParserBroker implements Twig_TokenParserBrokerInterface +{ + protected $parser; + protected $parsers = array(); + protected $brokers = array(); + + /** + * Constructor. + * + * @param array|Traversable $parsers A Traversable of Twig_TokenParserInterface instances + * @param array|Traversable $brokers A Traversable of Twig_TokenParserBrokerInterface instances + */ + public function __construct($parsers = array(), $brokers = array()) + { + foreach ($parsers as $parser) { + if (!$parser instanceof Twig_TokenParserInterface) { + throw new LogicException('$parsers must a an array of Twig_TokenParserInterface'); + } + $this->parsers[$parser->getTag()] = $parser; + } + foreach ($brokers as $broker) { + if (!$broker instanceof Twig_TokenParserBrokerInterface) { + throw new LogicException('$brokers must a an array of Twig_TokenParserBrokerInterface'); + } + $this->brokers[] = $broker; + } + } + + /** + * Adds a TokenParser. + * + * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance + */ + public function addTokenParser(Twig_TokenParserInterface $parser) + { + $this->parsers[$parser->getTag()] = $parser; + } + + /** + * Removes a TokenParser. + * + * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance + */ + public function removeTokenParser(Twig_TokenParserInterface $parser) + { + $name = $parser->getTag(); + if (isset($this->parsers[$name]) && $parser === $this->parsers[$name]) { + unset($this->parsers[$name]); + } + } + + /** + * Adds a TokenParserBroker. + * + * @param Twig_TokenParserBroker $broker A Twig_TokenParserBroker instance + */ + public function addTokenParserBroker(Twig_TokenParserBroker $broker) + { + $this->brokers[] = $broker; + } + + /** + * Removes a TokenParserBroker. + * + * @param Twig_TokenParserBroker $broker A Twig_TokenParserBroker instance + */ + public function removeTokenParserBroker(Twig_TokenParserBroker $broker) + { + if (false !== $pos = array_search($broker, $this->brokers)) { + unset($this->brokers[$pos]); + } + } + + /** + * Gets a suitable TokenParser for a tag. + * + * First looks in parsers, then in brokers. + * + * @param string $tag A tag name + * + * @return null|Twig_TokenParserInterface A Twig_TokenParserInterface or null if no suitable TokenParser was found + */ + public function getTokenParser($tag) + { + if (isset($this->parsers[$tag])) { + return $this->parsers[$tag]; + } + $broker = end($this->brokers); + while (false !== $broker) { + $parser = $broker->getTokenParser($tag); + if (null !== $parser) { + return $parser; + } + $broker = prev($this->brokers); + } + } + + public function getParsers() + { + return $this->parsers; + } + + public function getParser() + { + return $this->parser; + } + + public function setParser(Twig_ParserInterface $parser) + { + $this->parser = $parser; + foreach ($this->parsers as $tokenParser) { + $tokenParser->setParser($parser); + } + foreach ($this->brokers as $broker) { + $broker->setParser($parser); + } + } +} diff --git a/system/libs/twig/TokenParserBrokerInterface.php b/system/libs/twig/TokenParserBrokerInterface.php new file mode 100755 index 00000000..3ec2a880 --- /dev/null +++ b/system/libs/twig/TokenParserBrokerInterface.php @@ -0,0 +1,46 @@ + + * + * @deprecated since 1.12 (to be removed in 2.0) + */ +interface Twig_TokenParserBrokerInterface +{ + /** + * Gets a TokenParser suitable for a tag. + * + * @param string $tag A tag name + * + * @return null|Twig_TokenParserInterface A Twig_TokenParserInterface or null if no suitable TokenParser was found + */ + public function getTokenParser($tag); + + /** + * Calls Twig_TokenParserInterface::setParser on all parsers the implementation knows of. + * + * @param Twig_ParserInterface $parser A Twig_ParserInterface interface + */ + public function setParser(Twig_ParserInterface $parser); + + /** + * Gets the Twig_ParserInterface. + * + * @return null|Twig_ParserInterface A Twig_ParserInterface instance or null + */ + public function getParser(); +} diff --git a/system/libs/twig/TokenParserInterface.php b/system/libs/twig/TokenParserInterface.php new file mode 100755 index 00000000..12ec3961 --- /dev/null +++ b/system/libs/twig/TokenParserInterface.php @@ -0,0 +1,43 @@ + + */ +interface Twig_TokenParserInterface +{ + /** + * Sets the parser associated with this token parser. + * + * @param Twig_Parser $parser A Twig_Parser instance + */ + public function setParser(Twig_Parser $parser); + + /** + * Parses a token and returns a node. + * + * @param Twig_Token $token A Twig_Token instance + * + * @return Twig_NodeInterface A Twig_NodeInterface instance + * + * @throws Twig_Error_Syntax + */ + public function parse(Twig_Token $token); + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag(); +} diff --git a/system/libs/twig/TokenStream.php b/system/libs/twig/TokenStream.php index 2dcf38ea..89d2575a 100755 --- a/system/libs/twig/TokenStream.php +++ b/system/libs/twig/TokenStream.php @@ -1,11 +1,156 @@ + */ +class Twig_TokenStream +{ + protected $tokens; + protected $current; + protected $filename; -if (\false) { - class TokenStream extends \Twig_TokenStream + /** + * Constructor. + * + * @param array $tokens An array of tokens + * @param string $filename The name of the filename which tokens are associated with + */ + public function __construct(array $tokens, $filename = null) { + $this->tokens = $tokens; + $this->current = 0; + $this->filename = $filename; + } + + /** + * Returns a string representation of the token stream. + * + * @return string + */ + public function __toString() + { + return implode("\n", $this->tokens); + } + + public function injectTokens(array $tokens) + { + $this->tokens = array_merge(array_slice($this->tokens, 0, $this->current), $tokens, array_slice($this->tokens, $this->current)); + } + + /** + * Sets the pointer to the next token and returns the old one. + * + * @return Twig_Token + */ + public function next() + { + if (!isset($this->tokens[++$this->current])) { + throw new Twig_Error_Syntax('Unexpected end of template', $this->tokens[$this->current - 1]->getLine(), $this->filename); + } + + return $this->tokens[$this->current - 1]; + } + + /** + * Tests a token, sets the pointer to the next one and returns it or throws a syntax error. + * + * @return Twig_Token|null The next token if the condition is true, null otherwise + */ + public function nextIf($primary, $secondary = null) + { + if ($this->tokens[$this->current]->test($primary, $secondary)) { + return $this->next(); + } + } + + /** + * Tests a token and returns it or throws a syntax error. + * + * @return Twig_Token + */ + public function expect($type, $value = null, $message = null) + { + $token = $this->tokens[$this->current]; + if (!$token->test($type, $value)) { + $line = $token->getLine(); + throw new Twig_Error_Syntax(sprintf('%sUnexpected token "%s" of value "%s" ("%s" expected%s)', + $message ? $message.'. ' : '', + Twig_Token::typeToEnglish($token->getType()), $token->getValue(), + Twig_Token::typeToEnglish($type), $value ? sprintf(' with value "%s"', $value) : ''), + $line, + $this->filename + ); + } + $this->next(); + + return $token; + } + + /** + * Looks at the next token. + * + * @param int $number + * + * @return Twig_Token + */ + public function look($number = 1) + { + if (!isset($this->tokens[$this->current + $number])) { + throw new Twig_Error_Syntax('Unexpected end of template', $this->tokens[$this->current + $number - 1]->getLine(), $this->filename); + } + + return $this->tokens[$this->current + $number]; + } + + /** + * Tests the current token. + * + * @return bool + */ + public function test($primary, $secondary = null) + { + return $this->tokens[$this->current]->test($primary, $secondary); + } + + /** + * Checks if end of stream was reached. + * + * @return bool + */ + public function isEOF() + { + return $this->tokens[$this->current]->getType() === Twig_Token::EOF_TYPE; + } + + /** + * Gets the current token. + * + * @return Twig_Token + */ + public function getCurrent() + { + return $this->tokens[$this->current]; + } + + /** + * Gets the filename associated with this stream. + * + * @return string + */ + public function getFilename() + { + return $this->filename; } } diff --git a/system/libs/twig/TwigFilter.php b/system/libs/twig/TwigFilter.php deleted file mode 100755 index 8207048f..00000000 --- a/system/libs/twig/TwigFilter.php +++ /dev/null @@ -1,11 +0,0 @@ -enabled()) { else error('Error while clearing cache.'); } - -?> - - - - -
Clear cache
- -
- - - - - - - - - - - - - -
Maintenance -
Site status: - -
Message: (only if closed) - - -
- -
-
-
-
- -

Status: Online
-
- -

- -
- Server:

- Version:

- - Monsters:
- Map: , author: , size:
- MOTD:


- - Last updated: -
-

- -

Status: Offline

- -
- - - -render('admin.dashboard.html', array( + 'is_closed' => $is_closed, + 'closed_message' => $closed_message, + 'status' => $status +)); function clearCache() { diff --git a/system/pages/admin/login.php b/system/pages/admin/login.php index b03f5e4f..834d7e1c 100644 --- a/system/pages/admin/login.php +++ b/system/pages/admin/login.php @@ -19,14 +19,6 @@ if(isset($errors)) { error($error); } } -?> -Please login. -
-
-
- -
- - -
\ No newline at end of file +echo $twig->render('admin.login.html'); +?> \ No newline at end of file diff --git a/system/pages/admin/mailer.php b/system/pages/admin/mailer.php index b71abe30..988f02e4 100644 --- a/system/pages/admin/mailer.php +++ b/system/pages/admin/mailer.php @@ -29,82 +29,43 @@ $preview = isset($_REQUEST['preview']); $preview_done = false; if($preview) { - if(!empty($mail_content) && !empty($mail_subject)) + if(!empty($mail_content) && !empty($mail_subject)) { $preview_done = _mail($account_logged->getCustomField('email'), $mail_subject, $mail_content); - - if(!$preview_done) - error('Error while sending preview mail: ' . $mailer->ErrorInfo); + + if(!$preview_done) + error('Error while sending preview mail: ' . $mailer->ErrorInfo); + } } -?> - - - - - - - - - - - - - - - - - -
-

Sending mails may take some time if there are much users in db.

-
- - - -
- -
- Done.' : ''); ?>
-
-fieldName('email_verified') . ' = 1'; - $add = ''; - if($config['account_mail_verify']) - $add = ' AND ' . $db->fieldName('email_verified') . ' = 1'; - - $query = $db->query('SELECT ' . $db->fieldName('email') . ' FROM ' . $db->tableName('accounts') . ' WHERE ' . $db->fieldName('email') . ' != ""' . $add); - foreach($query as $email) +$query = $db->query('SELECT ' . $db->fieldName('email') . ' FROM ' . $db->tableName('accounts') . ' WHERE ' . $db->fieldName('email') . ' != ""' . $add); +foreach($query as $email) +{ + if(_mail($email['email'], $mail_subject, $mail_content)) + $success++; + else { - if(_mail($email['email'], $mail_subject, $mail_content)) - $success++; - else - { - $failed++; - echo '
'; - error('An error occorred while sending email to ' . $email['email'] . '. Error: ' . $mailer->ErrorInfo); - } + $failed++; + echo '
'; + error('An error occorred while sending email to ' . $email['email'] . '. Error: ' . $mailer->ErrorInfo); } +} ?> Mailing finished.

emails delivered.


diff --git a/system/pages/admin/notepad.php b/system/pages/admin/notepad.php index bf38ac21..e4545a54 100644 --- a/system/pages/admin/notepad.php +++ b/system/pages/admin/notepad.php @@ -27,61 +27,9 @@ else if($notepad_content !== false) $_content = $notepad_content; } -?> - - - - - - - - - - - - -
-

This is your personal notepad. Be sure to save it each time you modify something.

-
- -
- -
+echo $twig->render('admin.notepad.html', array('content' => $_content)); - - - - -
- - - - - - - - - -
Install plugin:
- - - -
-
-

-render('admin.plugins.form.html'); + $message = ''; if(isset($_FILES["plugin"]["name"])) { @@ -136,35 +119,30 @@ if(isset($_FILES["plugin"]["name"])) } echo $message; -?> -Installed plugins: - - - - - - - - - - - - - - '; - } +$plugins = array(); +$rows = array(); -?> -
Plugin name (Description on hover)FilenameVersionAuthorContact
' . $plugin_info['name'] . '
' . $file . '' . $plugin_info['version'] . '' . $plugin_info['author'] . '' . $plugin_info['contact'] . '
\ No newline at end of file +$path = PLUGINS; +foreach(scandir($path) as $file) +{ + $file_info = explode('.', $file); + if($file == '.' || $file == '..' || $file == 'disabled' || $file == 'example.json' || is_dir($path . $file) || !$file_info[1] || $file_info[1] != 'json') + continue; + + $string = file_get_contents(BASE . 'plugins/' . $file_info[0] . '.json'); + $plugin_info = json_decode($string, true); + $rows[] = array( + 'name' => $plugin_info['name'], + 'description' => $plugin_info['description'], + 'version' => $plugin_info['version'], + 'author' => $plugin_info['author'], + 'contact' => $plugin_info['contact'], + 'file' => $file, + ); +} + +echo $twig->render('admin.plugins.html', array( + 'plugins' => $rows +)); +?> \ No newline at end of file diff --git a/system/pages/admin/statistics.php b/system/pages/admin/statistics.php index a6f6b544..d042e914 100644 --- a/system/pages/admin/statistics.php +++ b/system/pages/admin/statistics.php @@ -10,51 +10,31 @@ */ defined('MYAAC') or die('Direct access not allowed!'); $title = 'Statistics'; -?> - - - - - -
- - - - query('SELECT count(*) as `how_much` FROM `accounts`;'); - $query = $query->fetch(); - echo ''; - ?> - - query('SELECT count(*) as `how_much` FROM `players`;'); - $query = $query->fetch(); - echo ''; - ?> - - query('SELECT count(*) as `how_much` FROM `guilds`;'); - $query = $query->fetch(); - echo ''; - ?> - - query('SELECT count(*) as `how_much` FROM `houses`;'); - $query = $query->fetch(); - echo ''; - ?> -
Statistics
Total accounts:' . $query['how_much'] . '
Total players:' . $query['how_much'] . '
Total guilds:' . $query['how_much'] . '
Total houses:' . $query['how_much'] . '
-
- - - - query('SELECT `premium_points`, `' . (USE_ACCOUNT_NAME ? 'name' : 'id') . '` as `name` FROM `accounts` ORDER BY `premium_points` DESC LIMIT 10;'); - $i = 0; - foreach($query as $result) - { - echo ''; - } - ?> -
TOP 10 - Most wealth accounts
#Account Premium points
' . ++$i . '.' . $result['name'] . '' . $result['premium_points'] . '
-
\ No newline at end of file + +$query = $db->query('SELECT count(*) as `how_much` FROM `accounts`;'); +$query = $query->fetch(); +$total_accounts = $query['how_much']; + +$query = $db->query('SELECT count(*) as `how_much` FROM `players`;'); +$query = $query->fetch(); +$total_players = $query['how_much']; + +$query = $db->query('SELECT count(*) as `how_much` FROM `guilds`;'); +$query = $query->fetch(); +$total_guilds = $query['how_much']; + +$query = $db->query('SELECT count(*) as `how_much` FROM `houses`;'); +$query = $query->fetch(); +$total_houses = $query['how_much']; + +$points = $db->query('SELECT `premium_points`, `' . (USE_ACCOUNT_NAME ? 'name' : 'id') . '` as `name` FROM `accounts` ORDER BY `premium_points` DESC LIMIT 10;'); + +echo $twig->render('admin.statistics.html', array( + 'total_accounts' => $total_accounts, + 'total_players' => $total_players, + 'total_guilds' => $total_guilds, + 'total_houses' => $total_houses, + 'account_type' => (USE_ACCOUNT_NAME ? 'name' : 'number'), + 'points' => $points +)); +?> \ No newline at end of file diff --git a/system/pages/admin/visitors.php b/system/pages/admin/visitors.php index 24e61d02..0d8b0359 100644 --- a/system/pages/admin/visitors.php +++ b/system/pages/admin/visitors.php @@ -21,15 +21,6 @@ endif; require(SYSTEM . 'libs/visitors.php'); $visitors = new Visitors($config['visitors_counter_ttl']); -?> -Users being active within last minutes.

- - - - - - - $b['lastvisit'] ? -1 : 1; @@ -38,16 +29,8 @@ function compare($a, $b) { $tmp = $visitors->getVisitors(); usort($tmp, 'compare'); -$i = 0; -foreach($tmp as $visitor) -{ +echo $twig->render('admin.visitors.html', array( + 'config_visitors_counter_ttl' => $config['visitors_counter_ttl'], + 'visitors' => $tmp +)); ?> - - - - - - -
IPLast visitPage
diff --git a/system/templates/admin.dashboard.html b/system/templates/admin.dashboard.html new file mode 100644 index 00000000..ceefbbdc --- /dev/null +++ b/system/templates/admin.dashboard.html @@ -0,0 +1,77 @@ + + + + +
Clear cache
+
+ + + + + + + + + + + + + +
Maintenance +
Site status: + +
Message: (only if closed) + + +
+ +
+
+
+
+ {% if status.online %} +

Status: Online
+ {{ status.uptimeReadable }}, {{ status.players }}/{{ status.playersMax }}
+ {{ status.lua.ip }} : {{ status.lua.loginPort }} +

+ + +
+ Server:
{{ status.server }} {{ status.serverVersion }}
+ Version: {{ status.clientVersion }}

+ + Monsters: {{ status.monsters }}
+ Map: {{ status.mapName }}, author: {{ status.mapAuthor }}, size: {{ status.mapWidth }} x {{ status.mapHeight }}
+ MOTD:
{{ status.motd }}

+ + Last updated: {{ status.lastCheck|date("H:i:s") }} +
+

+ {% else %} +

Status: Offline

+ {% endif %} +
+{% if status.online %} + +{% endif %} \ No newline at end of file diff --git a/system/templates/admin.login.html b/system/templates/admin.login.html new file mode 100644 index 00000000..7805582f --- /dev/null +++ b/system/templates/admin.login.html @@ -0,0 +1,9 @@ +Please login. +
+
+
+ +
+ + +
\ No newline at end of file diff --git a/system/templates/admin.mailer.html b/system/templates/admin.mailer.html new file mode 100644 index 00000000..bc1b4d39 --- /dev/null +++ b/system/templates/admin.mailer.html @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + +
+

Sending mails may take some time if there are much users in db.

+
+ + + +
+ +
+ {% if preview_done %} - Done.{% endif %}
+
\ No newline at end of file diff --git a/system/templates/admin.notepad.html b/system/templates/admin.notepad.html new file mode 100644 index 00000000..9ea80832 --- /dev/null +++ b/system/templates/admin.notepad.html @@ -0,0 +1,51 @@ + + + + + + + + + + + + +
+

This is your personal notepad. Be sure to save it each time you modify something.

+
+ +
+ +
+{# #} + +{# confirm leaving current page if content of the notepad has been modified #} + + \ No newline at end of file diff --git a/system/templates/admin.plugins.form.html b/system/templates/admin.plugins.form.html new file mode 100644 index 00000000..09d43275 --- /dev/null +++ b/system/templates/admin.plugins.form.html @@ -0,0 +1,17 @@ +
+ + + + + + + + + +
Install plugin:
+ + + +
+
+

\ No newline at end of file diff --git a/system/templates/admin.plugins.html b/system/templates/admin.plugins.html new file mode 100644 index 00000000..0933bfa2 --- /dev/null +++ b/system/templates/admin.plugins.html @@ -0,0 +1,19 @@ +Installed plugins: + + + + + + + + + {% for plugin in plugins %} + + + + + + + + {% endfor %} +
Plugin name (Description on hover)FilenameVersionAuthorContact
{{ plugin.name }}
{{ plugin.file }}{{ plugin.version }}{{ plugin.author }}{{ plugin.contact }}
\ No newline at end of file diff --git a/system/templates/admin.statistics.html b/system/templates/admin.statistics.html new file mode 100644 index 00000000..2bfd443d --- /dev/null +++ b/system/templates/admin.statistics.html @@ -0,0 +1,38 @@ + + + + + +
+ + + + + + + + + + + + + + + + +
Statistics
Total accounts:{{ total_accounts }}
Total players:{{ total_players }}
Total guilds:{{ total_guilds }}
Total houses:{{ total_houses }}
+
+ + + + {% set i = 0 %} + {% for result in points %} + {% set i = i + 1 %} + + + + + + {% endfor %} +
TOP 10 - Most wealth accounts
#Account {{ account_type }}Premium points
{{ i }}{{ result.name }}{{ result.premium_points }}
+
\ No newline at end of file diff --git a/system/templates/admin.visitors.html b/system/templates/admin.visitors.html new file mode 100644 index 00000000..08fe6723 --- /dev/null +++ b/system/templates/admin.visitors.html @@ -0,0 +1,19 @@ +Users being active within last {{ config_visitors_counter_ttl }} minutes.

+ + + + + + +{% set i = 0 %} +{% for visitor in visitors %} + {% set i = i + 1 %} + + + + + +{% endfor %} +
IPLast visitPage
{{ visitor.ip }}{{ visitor.lastvisit|date("H:i:s") }} + {{ visitor.page|slice(0, 50) }} +
\ No newline at end of file