From fdfbc0c11fcf8a8a538ce371e0b93a3c29285d3f Mon Sep 17 00:00:00 2001 From: ljf Date: Tue, 29 Mar 2022 01:30:21 +0200 Subject: [PATCH] Add a development environment for docker --- .gitignore | 3 + Dockerfile | 82 + README.md | 5 + dev/plugins/admin/.gitattributes | 8 + dev/plugins/admin/.github/FUNDING.yml | 8 + dev/plugins/admin/CHANGELOG.md | 2510 ++ dev/plugins/admin/CONTRIBUTING.md | 1 + dev/plugins/admin/LICENSE | 21 + dev/plugins/admin/README.md | 152 + dev/plugins/admin/UPGRADE.md | 6 + dev/plugins/admin/admin.php | 1353 + dev/plugins/admin/admin.yaml | 84 + dev/plugins/admin/assets/admin-dashboard.png | Bin 0 -> 241372 bytes dev/plugins/admin/blueprints.yaml | 781 + .../admin/blueprints/config/media.yaml | 36 + dev/plugins/admin/classes/plugin/Admin.php | 2493 ++ .../classes/plugin/AdminBaseController.php | 1167 + .../admin/classes/plugin/AdminController.php | 3066 ++ .../admin/classes/plugin/AdminForm.php | 182 + .../admin/classes/plugin/AdminFormFactory.php | 44 + .../plugin/Controllers/AbstractController.php | 407 + .../plugin/Controllers/AdminController.php | 359 + .../Controllers/Login/LoginController.php | 637 + dev/plugins/admin/classes/plugin/Gpm.php | 435 + .../admin/classes/plugin/Popularity.php | 303 + dev/plugins/admin/classes/plugin/Router.php | 72 + .../classes/plugin/Routers/LoginRouter.php | 93 + .../admin/classes/plugin/ScssCompiler.php | 55 + dev/plugins/admin/classes/plugin/ScssList.php | 52 + dev/plugins/admin/classes/plugin/Themes.php | 22 + .../plugin/Twig/AdminTwigExtension.php | 131 + dev/plugins/admin/classes/plugin/Utils.php | 54 + .../admin/classes/plugin/WhiteLabel.php | 93 + dev/plugins/admin/codeception.yml | 18 + dev/plugins/admin/composer.json | 58 + dev/plugins/admin/composer.lock | 3896 +++ dev/plugins/admin/languages/ar.yaml | 307 + dev/plugins/admin/languages/bg.yaml | 356 + dev/plugins/admin/languages/bn.yaml | 4 + dev/plugins/admin/languages/br.yaml | 592 + dev/plugins/admin/languages/ca.yaml | 643 + dev/plugins/admin/languages/cs.yaml | 1112 + dev/plugins/admin/languages/cy.yaml | 89 + dev/plugins/admin/languages/da.yaml | 760 + dev/plugins/admin/languages/de.yaml | 965 + dev/plugins/admin/languages/el.yaml | 710 + dev/plugins/admin/languages/en.yaml | 1142 + dev/plugins/admin/languages/eo.yaml | 766 + dev/plugins/admin/languages/es.yaml | 989 + dev/plugins/admin/languages/et.yaml | 896 + dev/plugins/admin/languages/eu.yaml | 181 + dev/plugins/admin/languages/fa.yaml | 878 + dev/plugins/admin/languages/fi.yaml | 259 + dev/plugins/admin/languages/fr.yaml | 1112 + dev/plugins/admin/languages/gl.yaml | 867 + dev/plugins/admin/languages/he.yaml | 410 + dev/plugins/admin/languages/hr.yaml | 600 + dev/plugins/admin/languages/hu.yaml | 777 + dev/plugins/admin/languages/id.yaml | 708 + dev/plugins/admin/languages/it.yaml | 1112 + dev/plugins/admin/languages/ja.yaml | 759 + dev/plugins/admin/languages/ko.yaml | 107 + dev/plugins/admin/languages/ku.yaml | 121 + dev/plugins/admin/languages/lt.yaml | 359 + dev/plugins/admin/languages/mn.yaml | 1112 + dev/plugins/admin/languages/nl.yaml | 853 + dev/plugins/admin/languages/no.yaml | 730 + dev/plugins/admin/languages/pl.yaml | 795 + dev/plugins/admin/languages/pt.yaml | 620 + dev/plugins/admin/languages/ro.yaml | 1106 + dev/plugins/admin/languages/ru.yaml | 1103 + dev/plugins/admin/languages/si.yaml | 98 + dev/plugins/admin/languages/sk.yaml | 548 + dev/plugins/admin/languages/sl.yaml | 242 + dev/plugins/admin/languages/sr.yaml | 805 + dev/plugins/admin/languages/sv.yaml | 670 + dev/plugins/admin/languages/th.yaml | 688 + dev/plugins/admin/languages/tlh.yaml | 8 + dev/plugins/admin/languages/tr.yaml | 862 + dev/plugins/admin/languages/uk.yaml | 600 + dev/plugins/admin/languages/vi.yaml | 452 + dev/plugins/admin/languages/zh-cn.yaml | 1112 + dev/plugins/admin/languages/zh-tw.yaml | 718 + dev/plugins/admin/languages/zh.yaml | 1112 + dev/plugins/admin/permissions.yaml | 48 + dev/plugins/admin/presets.yaml | 370 + dev/plugins/admin/tests/_bootstrap.php | 11 + .../admin/tests/_support/Helper/Unit.php | 80 + .../admin/tests/_support/UnitTester.php | 26 + dev/plugins/admin/tests/unit.suite.yml | 9 + dev/plugins/admin/tests/unit/_bootstrap.php | 3 + .../tests/unit/classes/controllerTest.php | 42 + dev/plugins/admin/twig/AdminTwigExtension.php | 7 + dev/plugins/admin/vendor/autoload.php | 7 + dev/plugins/admin/vendor/bin/picofeed | 107 + dev/plugins/admin/vendor/bin/pscss | 107 + .../admin/vendor/composer/ClassLoader.php | 572 + .../vendor/composer/InstalledVersions.php | 350 + dev/plugins/admin/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 11 + .../admin/vendor/composer/autoload_files.php | 10 + .../vendor/composer/autoload_namespaces.php | 10 + .../admin/vendor/composer/autoload_psr4.php | 13 + .../admin/vendor/composer/autoload_real.php | 80 + .../admin/vendor/composer/autoload_static.php | 73 + .../admin/vendor/composer/installed.json | 274 + .../admin/vendor/composer/installed.php | 77 + .../admin/vendor/composer/platform_check.php | 26 + .../vendor/laminas/laminas-xml/COPYRIGHT.md | 1 + .../vendor/laminas/laminas-xml/LICENSE.md | 26 + .../vendor/laminas/laminas-xml/README.md | 51 + .../vendor/laminas/laminas-xml/composer.json | 55 + .../vendor/laminas/laminas-xml/composer.lock | 2285 ++ .../src/Exception/ExceptionInterface.php | 7 + .../Exception/InvalidArgumentException.php | 10 + .../src/Exception/RuntimeException.php | 10 + .../laminas/laminas-xml/src/Security.php | 407 + .../.github/FUNDING.yml | 1 + .../.laminas-ci.json | 5 + .../laminas-zendframework-bridge/COPYRIGHT.md | 1 + .../laminas-zendframework-bridge/LICENSE.md | 26 + .../laminas-zendframework-bridge/README.md | 30 + .../composer.json | 61 + .../composer.lock | 3841 +++ .../config/replacements.php | 372 + .../psalm-baseline.xml | 345 + .../psalm.xml.dist | 33 + .../src/Autoloader.php | 181 + .../src/ConfigPostProcessor.php | 426 + .../src/Module.php | 48 + .../src/Replacements.php | 40 + .../src/RewriteRules.php | 73 + .../src/autoload.php | 3 + dev/plugins/admin/vendor/p3k/picofeed/LICENSE | 21 + .../vendor/p3k/picofeed/lib/PicoFeed/Base.php | 38 + .../picofeed/lib/PicoFeed/Client/Client.php | 712 + .../lib/PicoFeed/Client/ClientException.php | 14 + .../p3k/picofeed/lib/PicoFeed/Client/Curl.php | 412 + .../PicoFeed/Client/ForbiddenException.php | 10 + .../lib/PicoFeed/Client/HttpHeaders.php | 79 + .../Client/InvalidCertificateException.php | 12 + .../PicoFeed/Client/InvalidUrlException.php | 12 + .../PicoFeed/Client/MaxRedirectException.php | 12 + .../lib/PicoFeed/Client/MaxSizeException.php | 12 + .../picofeed/lib/PicoFeed/Client/Stream.php | 205 + .../lib/PicoFeed/Client/TimeoutException.php | 12 + .../PicoFeed/Client/UnauthorizedException.php | 10 + .../p3k/picofeed/lib/PicoFeed/Client/Url.php | 283 + .../picofeed/lib/PicoFeed/Config/Config.php | 102 + .../lib/PicoFeed/Encoding/Encoding.php | 33 + .../lib/PicoFeed/Filter/Attribute.php | 700 + .../picofeed/lib/PicoFeed/Filter/Filter.php | 144 + .../p3k/picofeed/lib/PicoFeed/Filter/Html.php | 243 + .../p3k/picofeed/lib/PicoFeed/Filter/Tag.php | 208 + .../Generator/ContentGeneratorInterface.php | 23 + .../Generator/FileContentGenerator.php | 36 + .../Generator/YoutubeContentGenerator.php | 67 + .../picofeed/lib/PicoFeed/Logging/Logger.php | 114 + .../p3k/picofeed/lib/PicoFeed/Parser/Atom.php | 395 + .../lib/PicoFeed/Parser/DateParser.php | 128 + .../p3k/picofeed/lib/PicoFeed/Parser/Feed.php | 315 + .../p3k/picofeed/lib/PicoFeed/Parser/Item.php | 562 + .../PicoFeed/Parser/MalformedXmlException.php | 13 + .../picofeed/lib/PicoFeed/Parser/Parser.php | 397 + .../lib/PicoFeed/Parser/ParserException.php | 15 + .../lib/PicoFeed/Parser/ParserInterface.php | 191 + .../picofeed/lib/PicoFeed/Parser/Rss10.php | 318 + .../picofeed/lib/PicoFeed/Parser/Rss20.php | 330 + .../picofeed/lib/PicoFeed/Parser/Rss91.php | 13 + .../picofeed/lib/PicoFeed/Parser/Rss92.php | 13 + .../PicoFeed/Parser/XmlEntityException.php | 13 + .../lib/PicoFeed/Parser/XmlParser.php | 249 + .../lib/PicoFeed/PicoFeedException.php | 14 + .../Processor/ContentFilterProcessor.php | 39 + .../Processor/ContentGeneratorProcessor.php | 49 + .../PicoFeed/Processor/ItemPostProcessor.php | 106 + .../Processor/ItemProcessorInterface.php | 25 + .../PicoFeed/Processor/ScraperProcessor.php | 96 + .../picofeed/lib/PicoFeed/Reader/Favicon.php | 186 + .../picofeed/lib/PicoFeed/Reader/Reader.php | 189 + .../lib/PicoFeed/Reader/ReaderException.php | 14 + .../Reader/SubscriptionNotFoundException.php | 12 + .../Reader/UnsupportedFeedFormatException.php | 12 + .../lib/PicoFeed/Rules/.blog.lemonde.fr.php | 14 + .../lib/PicoFeed/Rules/.blogs.nytimes.com.php | 15 + .../picofeed/lib/PicoFeed/Rules/.igen.fr.php | 13 + .../lib/PicoFeed/Rules/.nytimes.com.php | 11 + .../lib/PicoFeed/Rules/.over-blog.com.php | 11 + .../lib/PicoFeed/Rules/.phoronix.com.php | 12 + .../lib/PicoFeed/Rules/.slate.com.php | 20 + .../lib/PicoFeed/Rules/.theguardian.com.php | 14 + .../lib/PicoFeed/Rules/.wikipedia.org.php | 29 + .../lib/PicoFeed/Rules/.wired.com.php | 44 + .../picofeed/lib/PicoFeed/Rules/.wsj.com.php | 15 + .../picofeed/lib/PicoFeed/Rules/01net.com.php | 18 + .../p3k/picofeed/lib/PicoFeed/Rules/24.hu.php | 16 + .../picofeed/lib/PicoFeed/Rules/444.hu.php | 19 + .../picofeed/lib/PicoFeed/Rules/888.hu.php | 16 + .../lib/PicoFeed/Rules/abstrusegoose.com.php | 8 + .../lib/PicoFeed/Rules/achgut.com.php | 16 + .../PicoFeed/Rules/adventuregamers.com.php | 23 + .../lib/PicoFeed/Rules/alainonline.net.php | 14 + .../lib/PicoFeed/Rules/aljazeera.com.php | 25 + .../lib/PicoFeed/Rules/allafrica.com.php | 20 + .../PicoFeed/Rules/allgemeine-zeitung.de.php | 23 + .../PicoFeed/Rules/amazingsuperpowers.com.php | 8 + .../lib/PicoFeed/Rules/anythingcomic.com.php | 13 + .../picofeed/lib/PicoFeed/Rules/ap.org.php | 13 + .../lib/PicoFeed/Rules/areadvd.de.php | 10 + .../lib/PicoFeed/Rules/arstechnica.com.php | 25 + .../picofeed/lib/PicoFeed/Rules/atv.hu.php | 18 + .../lib/PicoFeed/Rules/awkwardzombie.com.php | 10 + .../lib/PicoFeed/Rules/backchannel.com.php | 18 + .../lib/PicoFeed/Rules/bangkokpost.com.php | 19 + .../lib/PicoFeed/Rules/bauerwilli.com.php | 17 + .../picofeed/lib/PicoFeed/Rules/bgr.com.php | 15 + .../lib/PicoFeed/Rules/bigfootjustice.com.php | 8 + .../lib/PicoFeed/Rules/bigpicture.ru.php | 31 + .../lib/PicoFeed/Rules/bizjournals.com.php | 12 + .../lib/PicoFeed/Rules/biztimes.com.php | 22 + .../PicoFeed/Rules/bleepingcomputer.com.php | 15 + .../lib/PicoFeed/Rules/blog.fefe.de.php | 13 + .../lib/PicoFeed/Rules/blog.mapillary.com.php | 11 + .../lib/PicoFeed/Rules/brewers.mlb.com.php | 22 + .../PicoFeed/Rules/buenosairesherald.com.php | 17 + .../lib/PicoFeed/Rules/bunicomic.com.php | 13 + .../lib/PicoFeed/Rules/buttersafe.com.php | 13 + .../lib/PicoFeed/Rules/cad-comic.com.php | 12 + .../Rules/chaoslife.findchaos.com.php | 10 + .../lib/PicoFeed/Rules/chinafile.com.php | 18 + .../picofeed/lib/PicoFeed/Rules/cicero.de.php | 17 + .../lib/PicoFeed/Rules/cliquerefresh.com.php | 10 + .../picofeed/lib/PicoFeed/Rules/cnet.com.php | 37 + .../lib/PicoFeed/Rules/coinwelt.de.php | 14 + .../lib/PicoFeed/Rules/consomac.fr.php | 13 + .../lib/PicoFeed/Rules/cowbirdsinlove.com.php | 8 + .../picofeed/lib/PicoFeed/Rules/crash.net.php | 18 + .../lib/PicoFeed/Rules/csmonitor.com.php | 19 + .../lib/PicoFeed/Rules/dailyjs.com.php | 19 + .../lib/PicoFeed/Rules/dailyreporter.com.php | 15 + .../lib/PicoFeed/Rules/dailytech.com.php | 13 + .../lib/PicoFeed/Rules/degroupnews.com.php | 14 + .../lib/PicoFeed/Rules/derstandard.at.php | 14 + .../lib/PicoFeed/Rules/dilbert.com.php | 11 + .../PicoFeed/Rules/discovermagazine.com.php | 26 + .../lib/PicoFeed/Rules/distrowatch.com.php | 13 + .../lib/PicoFeed/Rules/dozodomo.com.php | 15 + .../PicoFeed/Rules/drawingboardcomic.com.php | 15 + .../picofeed/lib/PicoFeed/Rules/e-w-e.ru.php | 22 + .../lib/PicoFeed/Rules/economist.com.php | 25 + .../Rules/encyclopedie.naheulbeuk.com.php | 13 + .../lib/PicoFeed/Rules/endlessorigami.com.php | 8 + .../lib/PicoFeed/Rules/engadget.com.php | 10 + .../PicoFeed/Rules/escapistmagazine.com.php | 45 + .../lib/PicoFeed/Rules/espn.go.com.php | 11 + .../lib/PicoFeed/Rules/exocomics.com.php | 15 + .../lib/PicoFeed/Rules/explosm.net.php | 13 + .../Rules/extrafabulouscomics.com.php | 8 + .../lib/PicoFeed/Rules/factroom.ru.php | 27 + .../lib/PicoFeed/Rules/fastcodesign.com.php | 13 + .../lib/PicoFeed/Rules/fastcoexist.com.php | 13 + .../lib/PicoFeed/Rules/fastcompany.com.php | 13 + .../lib/PicoFeed/Rules/ffworld.com.php | 13 + .../lib/PicoFeed/Rules/foreignpolicy.com.php | 21 + .../lib/PicoFeed/Rules/fossbytes.com.php | 18 + .../lib/PicoFeed/Rules/fototelegraf.ru.php | 19 + .../PicoFeed/Rules/fowllanguagecomics.com.php | 10 + .../lib/PicoFeed/Rules/gamechannel.hu.php | 15 + .../lib/PicoFeed/Rules/gamestar.hu.php | 17 + .../picofeed/lib/PicoFeed/Rules/geek.com.php | 17 + .../lib/PicoFeed/Rules/geektimes.ru.php | 12 + .../PicoFeed/Rules/gerbilwithajetpack.com.php | 12 + .../lib/PicoFeed/Rules/giantitp.com.php | 12 + .../lib/PicoFeed/Rules/github.com.php | 14 + .../lib/PicoFeed/Rules/gocomics.com.php | 12 + .../picofeed/lib/PicoFeed/Rules/golem.de.php | 21 + .../lib/PicoFeed/Rules/gondola.hu.php | 22 + .../lib/PicoFeed/Rules/gorabbit.ru.php | 19 + .../lib/PicoFeed/Rules/habrahabr.ru.php | 12 + .../lib/PicoFeed/Rules/happletea.com.php | 18 + .../lib/PicoFeed/Rules/hardware.fr.php | 11 + .../picofeed/lib/PicoFeed/Rules/heise.de.php | 79 + .../lib/PicoFeed/Rules/hirek.prim.hu.php | 14 + .../lib/PicoFeed/Rules/hotshowlife.com.php | 23 + .../lib/PicoFeed/Rules/huffingtonpost.com.php | 13 + .../picofeed/lib/PicoFeed/Rules/hvg.hu.php | 17 + .../picofeed/lib/PicoFeed/Rules/idokep.hu.php | 18 + .../lib/PicoFeed/Rules/imogenquest.net.php | 8 + .../picofeed/lib/PicoFeed/Rules/index.hu.php | 29 + .../lib/PicoFeed/Rules/indiehaven.com.php | 11 + .../lib/PicoFeed/Rules/inforadio.hu.php | 25 + .../picofeed/lib/PicoFeed/Rules/ing.dk.php | 12 + .../lib/PicoFeed/Rules/invisiblebread.com.php | 8 + .../lib/PicoFeed/Rules/ir.amd.com.php | 10 + .../lib/PicoFeed/Rules/japantimes.co.jp.php | 21 + .../lib/PicoFeed/Rules/japantoday.com.php | 15 + .../lib/PicoFeed/Rules/journaldugeek.com.php | 11 + .../lib/PicoFeed/Rules/jsonline.com.php | 37 + .../lib/PicoFeed/Rules/justcoolidea.ru.php | 19 + .../picofeed/lib/PicoFeed/Rules/kanpai.fr.php | 13 + .../PicoFeed/Rules/karriere.jobfinder.dk.php | 12 + .../lib/PicoFeed/Rules/kisalfold.hu.php | 17 + .../lib/PicoFeed/Rules/kiszamolo.hu.php | 14 + .../picofeed/lib/PicoFeed/Rules/kodi.tv.php | 11 + .../lib/PicoFeed/Rules/koreaherald.com.php | 11 + .../lib/PicoFeed/Rules/koreatimes.php | 14 + .../PicoFeed/Rules/lastplacecomics.com.php | 8 + .../lib/PicoFeed/Rules/legorafi.fr.php | 22 + .../lib/PicoFeed/Rules/lejapon.fr.php | 17 + .../lib/PicoFeed/Rules/lesjoiesducode.fr.php | 13 + .../picofeed/lib/PicoFeed/Rules/lfg.co.php | 12 + .../lib/PicoFeed/Rules/lifehacker.com.php | 18 + .../lib/PicoFeed/Rules/lifehacker.ru.php | 22 + .../lib/PicoFeed/Rules/linux-magazin.de.php | 16 + .../picofeed/lib/PicoFeed/Rules/linux.org.php | 14 + .../lib/PicoFeed/Rules/linux.org.ru.php | 13 + .../lib/PicoFeed/Rules/linuxinsider.com.php | 20 + .../p3k/picofeed/lib/PicoFeed/Rules/lists.php | 13 + .../lib/PicoFeed/Rules/loadingartist.com.php | 8 + .../lib/PicoFeed/Rules/loldwell.com.php | 10 + .../lib/PicoFeed/Rules/lukesurl.com.php | 15 + .../picofeed/lib/PicoFeed/Rules/macg.co.php | 13 + .../lib/PicoFeed/Rules/maclife.de.php | 11 + .../lib/PicoFeed/Rules/magyarkurir.hu.php | 21 + .../picofeed/lib/PicoFeed/Rules/marc.info.php | 13 + .../PicoFeed/Rules/marriedtothesea.com.php | 12 + .../lib/PicoFeed/Rules/marycagle.com.php | 13 + .../Rules/maximumble.thebookofbiff.com.php | 10 + .../lib/PicoFeed/Rules/medium.com.php | 19 + .../lib/PicoFeed/Rules/mercworks.net.php | 17 + .../lib/PicoFeed/Rules/metronieuws.nl.php | 10 + .../lib/PicoFeed/Rules/milwaukeenns.php | 14 + .../picofeed/lib/PicoFeed/Rules/mno.hu.php | 14 + .../Rules/mokepon.smackjeeves.com.php | 10 + .../lib/PicoFeed/Rules/monandroid.com.php | 13 + .../lib/PicoFeed/Rules/monwindows.com.php | 13 + .../lib/PicoFeed/Rules/moya-planeta.ru.php | 21 + .../lib/PicoFeed/Rules/mrlovenstein.com.php | 9 + .../lib/PicoFeed/Rules/muckrock.com.php | 20 + .../PicoFeed/Rules/mynorthshorenow.com.php | 27 + .../lib/PicoFeed/Rules/nakedCapitalism.php | 11 + .../picofeed/lib/PicoFeed/Rules/nasa.gov.php | 14 + .../lib/PicoFeed/Rules/nat-geo.ru.php | 11 + .../PicoFeed/Rules/nationaljournal.com.php | 15 + .../lib/PicoFeed/Rules/nature.com.php | 13 + .../picofeed/lib/PicoFeed/Rules/nba.com.php | 15 + .../lib/PicoFeed/Rules/nedroid.com.php | 8 + .../lib/PicoFeed/Rules/networkworld.com.php | 20 + .../lib/PicoFeed/Rules/neustadt-ticker.de.php | 15 + .../lib/PicoFeed/Rules/nextinpact.com.php | 18 + .../lib/PicoFeed/Rules/niceteethcomic.com.php | 10 + .../lib/PicoFeed/Rules/nichtlustig.de.php | 8 + .../picofeed/lib/PicoFeed/Rules/nlcafe.hu.php | 18 + .../lib/PicoFeed/Rules/novo-argumente.com.php | 16 + .../picofeed/lib/PicoFeed/Rules/oglaf.com.php | 19 + .../picofeed/lib/PicoFeed/Rules/onhax.net.php | 15 + .../lib/PicoFeed/Rules/onlinekosten.de.php | 13 + .../lib/PicoFeed/Rules/onmilwaukee.php | 24 + .../lib/PicoFeed/Rules/openculture.com.php | 11 + .../lib/PicoFeed/Rules/opennet.ru.php | 13 + .../PicoFeed/Rules/openrightsgroup.org.php | 20 + .../lib/PicoFeed/Rules/opensource.com.php | 22 + .../lib/PicoFeed/Rules/optipess.com.php | 8 + .../picofeed/lib/PicoFeed/Rules/origo.hu.php | 14 + .../lib/PicoFeed/Rules/osnews.com.php | 11 + .../lib/PicoFeed/Rules/pastebin.com.php | 13 + .../lib/PicoFeed/Rules/pcgameshardware.de.php | 16 + .../lib/PicoFeed/Rules/peebleslab.com.php | 9 + .../lib/PicoFeed/Rules/penny-arcade.com.php | 21 + .../lib/PicoFeed/Rules/pixelbeat.org.php | 12 + .../lib/PicoFeed/Rules/plus.google.com.php | 11 + .../lib/PicoFeed/Rules/popstrip.com.php | 8 + .../lib/PicoFeed/Rules/portfolio.hu.php | 15 + .../lib/PicoFeed/Rules/pro-linux.de.php | 16 + .../PicoFeed/Rules/publicpolicyforum.org.php | 15 + .../picofeed/lib/PicoFeed/Rules/publy.ru.php | 24 + .../lib/PicoFeed/Rules/putaindecode.fr.php | 16 + .../lib/PicoFeed/Rules/recode.net.php | 20 + .../PicoFeed/Rules/retractionwatch.com.php | 18 + .../PicoFeed/Rules/rockpapershotgun.com.php | 11 + .../PicoFeed/Rules/rue89.nouvelobs.com.php | 13 + .../lib/PicoFeed/Rules/rugbyrama.fr.php | 20 + .../lib/PicoFeed/Rules/salonkolumnisten.com | 17 + .../lib/PicoFeed/Rules/satwcomic.com.php | 13 + .../PicoFeed/Rules/science-skeptical.de.php | 14 + .../lib/PicoFeed/Rules/scrumalliance.org.php | 12 + .../lib/PicoFeed/Rules/securityfocus.com.php | 17 + .../PicoFeed/Rules/sentfromthemoon.com.php | 18 + .../lib/PicoFeed/Rules/sitepoint.com.php | 13 + .../lib/PicoFeed/Rules/slashdot.org.php | 11 + .../PicoFeed/Rules/smallhousebliss.com.php | 19 + .../lib/PicoFeed/Rules/smarthomewelt.de.php | 10 + .../PicoFeed/Rules/smashingmagazine.com.php | 10 + .../lib/PicoFeed/Rules/smbc-comics.com.php | 14 + .../lib/PicoFeed/Rules/snopes.com.php | 22 + .../lib/PicoFeed/Rules/soundandvision.com.php | 21 + .../lib/PicoFeed/Rules/spiegel.de.php | 14 + .../lib/PicoFeed/Rules/stereophile.com.php | 11 + .../lib/PicoFeed/Rules/stupidfox.net.php | 13 + .../lib/PicoFeed/Rules/subtraction.com.php | 15 + .../p3k/picofeed/lib/PicoFeed/Rules/sz.de.php | 10 + .../lib/PicoFeed/Rules/takprosto.cc.php | 21 + .../lib/PicoFeed/Rules/techcrunch.com.php | 15 + .../PicoFeed/Rules/the-ebook-reader.com.php | 15 + .../lib/PicoFeed/Rules/theatlantic.com.php | 23 + .../lib/PicoFeed/Rules/theawkwardyeti.com.php | 12 + .../lib/PicoFeed/Rules/thecodinglove.com.php | 10 + .../PicoFeed/Rules/thedoghousediaries.com.php | 18 + .../lib/PicoFeed/Rules/thegamercat.com.php | 10 + .../lib/PicoFeed/Rules/thehindu.com.php | 19 + .../lib/PicoFeed/Rules/thelocal.se.php | 17 + .../lib/PicoFeed/Rules/themerepublic.net.php | 10 + .../lib/PicoFeed/Rules/themoscowtimes.com.php | 18 + .../lib/PicoFeed/Rules/thenewslens.com.php | 21 + .../lib/PicoFeed/Rules/theodd1sout.com.php | 8 + .../lib/PicoFeed/Rules/theonion.com.php | 12 + .../lib/PicoFeed/Rules/theregister.co.uk.php | 18 + .../lib/PicoFeed/Rules/thestandard.com.hk.php | 22 + .../lib/PicoFeed/Rules/theverge.com.php | 16 + .../lib/PicoFeed/Rules/threepanelsoul.com.php | 11 + .../lib/PicoFeed/Rules/tichyseinblick.de.php | 22 + .../Rules/timesofindia.indiatimes.com.php | 14 + .../lib/PicoFeed/Rules/totalcar.hu.php | 18 + .../lib/PicoFeed/Rules/tozsdeforum.hu.php | 15 + .../lib/PicoFeed/Rules/travel-dealz.de.php | 15 + .../lib/PicoFeed/Rules/travelo.hu.php | 17 + .../lib/PicoFeed/Rules/treehugger.com.php | 14 + .../lib/PicoFeed/Rules/treelobsters.com.php | 8 + .../lib/PicoFeed/Rules/tutorialzine.com.php | 20 + .../lib/PicoFeed/Rules/twogag.com.php | 8 + .../PicoFeed/Rules/twokinds.keenspot.com.php | 10 + .../lib/PicoFeed/Rules/undeadly.org.php | 14 + .../picofeed/lib/PicoFeed/Rules/upi.com.php | 15 + .../lib/PicoFeed/Rules/usatoday.com.php | 27 + .../lib/PicoFeed/Rules/version2.dk.php | 12 + .../picofeed/lib/PicoFeed/Rules/vezess.hu.php | 20 + .../lib/PicoFeed/Rules/vgcats.com.php | 15 + .../picofeed/lib/PicoFeed/Rules/vuxml.org.php | 17 + .../PicoFeed/Rules/wausaudailyherald.com.php | 27 + .../picofeed/lib/PicoFeed/Rules/welt.de.php | 20 + .../lib/PicoFeed/Rules/westfalen-blatt.de.php | 16 + .../lib/PicoFeed/Rules/www.bbc.co.uk.php | 33 + .../lib/PicoFeed/Rules/www.bdgest.com.php | 15 + .../lib/PicoFeed/Rules/www.bgr.in.php | 23 + .../PicoFeed/Rules/www.businessweek.com.php | 15 + .../lib/PicoFeed/Rules/www.cnn.com.php | 24 + .../lib/PicoFeed/Rules/www.developpez.com.php | 21 + .../lib/PicoFeed/Rules/www.egscomics.com.php | 12 + .../Rules/www.fakingnews.firstpost.com.php | 17 + .../lib/PicoFeed/Rules/www.forbes.com.php | 20 + .../PicoFeed/Rules/www.franceculture.fr.php | 14 + .../Rules/www.futura-sciences.com.php | 19 + .../PicoFeed/Rules/www.geekculture.com.php | 13 + .../lib/PicoFeed/Rules/www.howtogeek.com.php | 14 + .../lib/PicoFeed/Rules/www.lepoint.fr.php | 18 + .../PicoFeed/Rules/www.lesnumeriques.com.php | 25 + .../lib/PicoFeed/Rules/www.mac4ever.com.php | 13 + .../lib/PicoFeed/Rules/www.makeuseof.com.php | 18 + .../Rules/www.monsieur-le-chien.fr.php | 11 + .../lib/PicoFeed/Rules/www.npr.org.php | 28 + .../lib/PicoFeed/Rules/www.numerama.com.php | 15 + .../lib/PicoFeed/Rules/www.oneindia.com.php | 14 + .../Rules/www.pseudo-sciences.org.php | 16 + .../lib/PicoFeed/Rules/www.sciencemag.org.php | 16 + .../lib/PicoFeed/Rules/www.slate.fr.php | 19 + .../PicoFeed/Rules/www.universfreebox.com.php | 15 + .../lib/PicoFeed/Rules/www.zeit.de.php | 41 + .../picofeed/lib/PicoFeed/Rules/xkcd.com.php | 8 + .../lib/PicoFeed/Rules/ymatuhin.ru.php | 21 + .../lib/PicoFeed/Rules/zarojel.hu.php | 19 + .../picofeed/lib/PicoFeed/Rules/zdnet.com.php | 23 + .../picofeed/lib/PicoFeed/Rules/zoom.hu.php | 17 + .../lib/PicoFeed/Scraper/CandidateParser.php | 281 + .../lib/PicoFeed/Scraper/ParserInterface.php | 20 + .../lib/PicoFeed/Scraper/RuleLoader.php | 104 + .../lib/PicoFeed/Scraper/RuleParser.php | 102 + .../picofeed/lib/PicoFeed/Scraper/Scraper.php | 282 + .../PicoFeed/Serialization/Subscription.php | 175 + .../Serialization/SubscriptionList.php | 75 + .../Serialization/SubscriptionListBuilder.php | 204 + .../Serialization/SubscriptionListParser.php | 100 + .../Serialization/SubscriptionParser.php | 142 + .../PicoFeed/Syndication/AtomFeedBuilder.php | 65 + .../lib/PicoFeed/Syndication/AtomHelper.php | 139 + .../PicoFeed/Syndication/AtomItemBuilder.php | 63 + .../lib/PicoFeed/Syndication/FeedBuilder.php | 185 + .../lib/PicoFeed/Syndication/ItemBuilder.php | 209 + .../PicoFeed/Syndication/Rss20FeedBuilder.php | 76 + .../lib/PicoFeed/Syndication/Rss20Helper.php | 115 + .../PicoFeed/Syndication/Rss20ItemBuilder.php | 67 + .../admin/vendor/p3k/picofeed/picofeed | 135 + .../admin/vendor/scssphp/scssphp/LICENSE.md | 20 + .../admin/vendor/scssphp/scssphp/README.md | 71 + .../admin/vendor/scssphp/scssphp/bin/pscss | 244 + .../vendor/scssphp/scssphp/composer.json | 111 + .../vendor/scssphp/scssphp/phpcs.xml.dist | 12 + .../admin/vendor/scssphp/scssphp/scss.inc.php | 21 + .../vendor/scssphp/scssphp/src/Base/Range.php | 57 + .../vendor/scssphp/scssphp/src/Block.php | 73 + .../scssphp/scssphp/src/Block/AtRootBlock.php | 37 + .../scssphp/src/Block/CallableBlock.php | 45 + .../scssphp/src/Block/ContentBlock.php | 38 + .../scssphp/src/Block/DirectiveBlock.php | 37 + .../scssphp/scssphp/src/Block/EachBlock.php | 37 + .../scssphp/scssphp/src/Block/ElseBlock.php | 27 + .../scssphp/scssphp/src/Block/ElseifBlock.php | 32 + .../scssphp/scssphp/src/Block/ForBlock.php | 47 + .../scssphp/scssphp/src/Block/IfBlock.php | 37 + .../scssphp/scssphp/src/Block/MediaBlock.php | 37 + .../scssphp/src/Block/NestedPropertyBlock.php | 37 + .../scssphp/scssphp/src/Block/WhileBlock.php | 32 + .../vendor/scssphp/scssphp/src/Cache.php | 272 + .../vendor/scssphp/scssphp/src/Colors.php | 247 + .../scssphp/scssphp/src/CompilationResult.php | 69 + .../vendor/scssphp/scssphp/src/Compiler.php | 10355 +++++++ .../scssphp/src/Compiler/CachedResult.php | 77 + .../scssphp/src/Compiler/Environment.php | 68 + .../src/Exception/CompilerException.php | 24 + .../scssphp/src/Exception/ParserException.php | 50 + .../scssphp/src/Exception/RangeException.php | 24 + .../scssphp/src/Exception/SassException.php | 7 + .../src/Exception/SassScriptException.php | 32 + .../scssphp/src/Exception/ServerException.php | 26 + .../vendor/scssphp/scssphp/src/Formatter.php | 364 + .../scssphp/scssphp/src/Formatter/Compact.php | 52 + .../scssphp/src/Formatter/Compressed.php | 83 + .../scssphp/src/Formatter/Crunched.php | 87 + .../scssphp/scssphp/src/Formatter/Debug.php | 127 + .../scssphp/src/Formatter/Expanded.php | 70 + .../scssphp/scssphp/src/Formatter/Nested.php | 236 + .../scssphp/src/Formatter/OutputBlock.php | 68 + .../scssphp/src/Logger/LoggerInterface.php | 48 + .../scssphp/src/Logger/QuietLogger.php | 27 + .../scssphp/src/Logger/StreamLogger.php | 60 + .../admin/vendor/scssphp/scssphp/src/Node.php | 43 + .../scssphp/scssphp/src/Node/Number.php | 804 + .../scssphp/scssphp/src/OutputStyle.php | 9 + .../vendor/scssphp/scssphp/src/Parser.php | 4176 +++ .../scssphp/scssphp/src/SourceMap/Base64.php | 187 + .../scssphp/src/SourceMap/Base64VLQ.php | 151 + .../src/SourceMap/SourceMapGenerator.php | 381 + .../admin/vendor/scssphp/scssphp/src/Type.php | 208 + .../admin/vendor/scssphp/scssphp/src/Util.php | 184 + .../vendor/scssphp/scssphp/src/Util/Path.php | 77 + .../scssphp/scssphp/src/ValueConverter.php | 95 + .../vendor/scssphp/scssphp/src/Version.php | 23 + .../admin/vendor/scssphp/scssphp/src/Warn.php | 84 + dev/plugins/anchors/.idea/vcs.xml | 6 + dev/plugins/anchors/CHANGELOG.md | 65 + dev/plugins/anchors/LICENSE | 21 + dev/plugins/anchors/README.md | 106 + dev/plugins/anchors/anchors.php | 109 + dev/plugins/anchors/anchors.yaml | 9 + dev/plugins/anchors/blueprints.yaml | 107 + dev/plugins/anchors/hebe.json | 15 + dev/plugins/anchors/js/anchor.min.js | 9 + dev/plugins/anchors/js/clipboard.min.js | 7 + .../anchors/twig/AnchorsTwigExtension.php | 142 + dev/plugins/breadcrumbs/CHANGELOG.md | 67 + dev/plugins/breadcrumbs/LICENSE | 21 + dev/plugins/breadcrumbs/README.md | 101 + dev/plugins/breadcrumbs/assets/readme_1.png | Bin 0 -> 61887 bytes dev/plugins/breadcrumbs/blueprints.yaml | 99 + dev/plugins/breadcrumbs/breadcrumbs.php | 70 + dev/plugins/breadcrumbs/breadcrumbs.yaml | 8 + .../classes/plugin/Breadcrumbs.php | 123 + dev/plugins/breadcrumbs/composer.json | 32 + dev/plugins/breadcrumbs/composer.lock | 24 + dev/plugins/breadcrumbs/css/breadcrumbs.css | 18 + dev/plugins/breadcrumbs/hebe.json | 15 + dev/plugins/breadcrumbs/languages.yaml | 32 + .../templates/partials/breadcrumbs.html.twig | 38 + dev/plugins/breadcrumbs/vendor/autoload.php | 7 + .../vendor/composer/ClassLoader.php | 445 + .../breadcrumbs/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 10 + .../vendor/composer/autoload_namespaces.php | 9 + .../vendor/composer/autoload_psr4.php | 10 + .../vendor/composer/autoload_real.php | 52 + .../vendor/composer/autoload_static.php | 36 + .../vendor/composer/installed.json | 1 + dev/plugins/email/CHANGELOG.md | 320 + dev/plugins/email/LICENSE | 21 + dev/plugins/email/README.md | 491 + dev/plugins/email/blueprints.yaml | 251 + dev/plugins/email/classes/Email.php | 560 + dev/plugins/email/classes/Utils.php | 48 + .../email/cli/ClearQueueFailuresCommand.php | 62 + dev/plugins/email/cli/FlushQueueCommand.php | 63 + dev/plugins/email/cli/TestEmailCommand.php | 107 + dev/plugins/email/composer.json | 33 + dev/plugins/email/composer.lock | 652 + dev/plugins/email/email.php | 181 + dev/plugins/email/email.yaml | 23 + dev/plugins/email/languages.yaml | 165 + .../email/templates/email/base.html.twig | 214 + dev/plugins/email/vendor/autoload.php | 7 + .../email/vendor/composer/ClassLoader.php | 572 + .../vendor/composer/InstalledVersions.php | 350 + dev/plugins/email/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 12 + .../email/vendor/composer/autoload_files.php | 15 + .../vendor/composer/autoload_namespaces.php | 9 + .../email/vendor/composer/autoload_psr4.php | 18 + .../email/vendor/composer/autoload_real.php | 75 + .../email/vendor/composer/autoload_static.php | 96 + .../email/vendor/composer/installed.json | 661 + .../email/vendor/composer/installed.php | 95 + .../email/vendor/composer/platform_check.php | 26 + .../email/vendor/doctrine/lexer/LICENSE | 19 + .../email/vendor/doctrine/lexer/README.md | 9 + .../email/vendor/doctrine/lexer/composer.json | 41 + .../Doctrine/Common/Lexer/AbstractLexer.php | 328 + .../egulias/email-validator/CHANGELOG.md | 33 + .../egulias/email-validator/CONTRIBUTING.md | 153 + .../vendor/egulias/email-validator/LICENSE | 19 + .../egulias/email-validator/composer.json | 38 + .../egulias/email-validator/composer.lock | 4440 +++ .../email-validator/src/EmailLexer.php | 361 + .../email-validator/src/EmailParser.php | 91 + .../email-validator/src/EmailValidator.php | 67 + .../email-validator/src/MessageIDParser.php | 93 + .../egulias/email-validator/src/Parser.php | 78 + .../email-validator/src/Parser/Comment.php | 103 + .../CommentStrategy/CommentStrategy.php | 18 + .../Parser/CommentStrategy/DomainComment.php | 37 + .../Parser/CommentStrategy/LocalComment.php | 37 + .../src/Parser/DomainLiteral.php | 212 + .../email-validator/src/Parser/DomainPart.php | 312 + .../src/Parser/DoubleQuote.php | 87 + .../src/Parser/FoldingWhiteSpace.php | 82 + .../email-validator/src/Parser/IDLeftPart.php | 16 + .../src/Parser/IDRightPart.php | 29 + .../email-validator/src/Parser/LocalPart.php | 164 + .../email-validator/src/Parser/PartParser.php | 63 + .../src/Result/InvalidEmail.php | 46 + .../src/Result/MultipleErrors.php | 56 + .../src/Result/Reason/AtextAfterCFWS.php | 16 + .../src/Result/Reason/CRLFAtTheEnd.php | 19 + .../src/Result/Reason/CRLFX2.php | 16 + .../src/Result/Reason/CRNoLF.php | 16 + .../src/Result/Reason/CharNotAllowed.php | 16 + .../src/Result/Reason/CommaInDomain.php | 16 + .../src/Result/Reason/CommentsInIDRight.php | 16 + .../src/Result/Reason/ConsecutiveAt.php | 17 + .../src/Result/Reason/ConsecutiveDot.php | 16 + .../src/Result/Reason/DetailedReason.php | 13 + .../src/Result/Reason/DomainAcceptsNoMail.php | 16 + .../src/Result/Reason/DomainHyphened.php | 16 + .../src/Result/Reason/DomainTooLong.php | 16 + .../src/Result/Reason/DotAtEnd.php | 16 + .../src/Result/Reason/DotAtStart.php | 16 + .../src/Result/Reason/EmptyReason.php | 16 + .../src/Result/Reason/ExceptionFound.php | 26 + .../src/Result/Reason/ExpectingATEXT.php | 16 + .../src/Result/Reason/ExpectingCTEXT.php | 16 + .../src/Result/Reason/ExpectingDTEXT.php | 16 + .../Reason/ExpectingDomainLiteralClose.php | 16 + .../src/Result/Reason/LabelTooLong.php | 16 + .../Result/Reason/LocalOrReservedDomain.php | 16 + .../src/Result/Reason/NoDNSRecord.php | 16 + .../src/Result/Reason/NoDomainPart.php | 16 + .../src/Result/Reason/NoLocalPart.php | 16 + .../src/Result/Reason/RFCWarnings.php | 16 + .../src/Result/Reason/Reason.php | 16 + .../src/Result/Reason/SpoofEmail.php | 17 + .../src/Result/Reason/UnOpenedComment.php | 16 + .../Result/Reason/UnableToGetDNSRecord.php | 19 + .../src/Result/Reason/UnclosedComment.php | 16 + .../Result/Reason/UnclosedQuotedString.php | 16 + .../src/Result/Reason/UnusualElements.php | 26 + .../email-validator/src/Result/Result.php | 27 + .../email-validator/src/Result/SpoofEmail.php | 14 + .../email-validator/src/Result/ValidEmail.php | 27 + .../src/Validation/DNSCheckValidation.php | 184 + .../src/Validation/EmailValidation.php | 34 + .../Exception/EmptyValidationList.php | 16 + .../Validation/Extra/SpoofCheckValidation.php | 52 + .../src/Validation/MessageIDValidation.php | 51 + .../Validation/MultipleValidationWithAnd.php | 117 + .../Validation/NoRFCWarningsValidation.php | 41 + .../src/Validation/RFCValidation.php | 55 + .../src/Warning/AddressLiteral.php | 14 + .../src/Warning/CFWSNearAt.php | 13 + .../src/Warning/CFWSWithFWS.php | 13 + .../email-validator/src/Warning/Comment.php | 13 + .../src/Warning/DeprecatedComment.php | 13 + .../src/Warning/DomainLiteral.php | 14 + .../src/Warning/EmailTooLong.php | 15 + .../src/Warning/IPV6BadChar.php | 14 + .../src/Warning/IPV6ColonEnd.php | 14 + .../src/Warning/IPV6ColonStart.php | 14 + .../src/Warning/IPV6Deprecated.php | 14 + .../src/Warning/IPV6DoubleColon.php | 14 + .../src/Warning/IPV6GroupCount.php | 14 + .../src/Warning/IPV6MaxGroups.php | 14 + .../src/Warning/LocalTooLong.php | 15 + .../src/Warning/NoDNSMXRecord.php | 14 + .../src/Warning/ObsoleteDTEXT.php | 14 + .../src/Warning/QuotedPart.php | 17 + .../src/Warning/QuotedString.php | 17 + .../email-validator/src/Warning/TLD.php | 13 + .../email-validator/src/Warning/Warning.php | 47 + .../swiftmailer/swiftmailer/.gitattributes | 11 + .../swiftmailer/.github/ISSUE_TEMPLATE.md | 19 + .../.github/PULL_REQUEST_TEMPLATE.md | 14 + .../swiftmailer/swiftmailer/.php_cs.dist | 21 + .../vendor/swiftmailer/swiftmailer/CHANGES | 391 + .../vendor/swiftmailer/swiftmailer/LICENSE | 19 + .../vendor/swiftmailer/swiftmailer/README.md | 25 + .../swiftmailer/swiftmailer/composer.json | 44 + .../swiftmailer/swiftmailer/doc/headers.rst | 621 + .../swiftmailer/swiftmailer/doc/index.rst | 12 + .../swiftmailer/doc/introduction.rst | 67 + .../swiftmailer/swiftmailer/doc/japanese.rst | 19 + .../swiftmailer/swiftmailer/doc/messages.rst | 949 + .../swiftmailer/swiftmailer/doc/plugins.rst | 337 + .../swiftmailer/swiftmailer/doc/sending.rst | 464 + .../swiftmailer/lib/classes/Swift.php | 78 + .../lib/classes/Swift/AddressEncoder.php | 25 + .../AddressEncoder/IdnAddressEncoder.php | 50 + .../AddressEncoder/Utf8AddressEncoder.php | 36 + .../classes/Swift/AddressEncoderException.php | 32 + .../lib/classes/Swift/Attachment.php | 54 + .../AbstractFilterableInputStream.php | 176 + .../Swift/ByteStream/ArrayByteStream.php | 178 + .../Swift/ByteStream/FileByteStream.php | 214 + .../ByteStream/TemporaryFileByteStream.php | 52 + .../lib/classes/Swift/CharacterReader.php | 67 + .../GenericFixedWidthReader.php | 97 + .../Swift/CharacterReader/UsAsciiReader.php | 84 + .../Swift/CharacterReader/Utf8Reader.php | 176 + .../classes/Swift/CharacterReaderFactory.php | 26 + .../SimpleCharacterReaderFactory.php | 124 + .../lib/classes/Swift/CharacterStream.php | 87 + .../CharacterStream/ArrayCharacterStream.php | 291 + .../CharacterStream/NgCharacterStream.php | 262 + .../lib/classes/Swift/ConfigurableSpool.php | 63 + .../lib/classes/Swift/DependencyContainer.php | 387 + .../lib/classes/Swift/DependencyException.php | 27 + .../lib/classes/Swift/EmbeddedFile.php | 53 + .../swiftmailer/lib/classes/Swift/Encoder.php | 28 + .../classes/Swift/Encoder/Base64Encoder.php | 58 + .../lib/classes/Swift/Encoder/QpEncoder.php | 300 + .../classes/Swift/Encoder/Rfc2231Encoder.php | 90 + .../lib/classes/Swift/Events/CommandEvent.php | 64 + .../classes/Swift/Events/CommandListener.php | 22 + .../lib/classes/Swift/Events/Event.php | 38 + .../classes/Swift/Events/EventDispatcher.php | 70 + .../classes/Swift/Events/EventListener.php | 18 + .../lib/classes/Swift/Events/EventObject.php | 61 + .../classes/Swift/Events/ResponseEvent.php | 64 + .../classes/Swift/Events/ResponseListener.php | 22 + .../lib/classes/Swift/Events/SendEvent.php | 126 + .../lib/classes/Swift/Events/SendListener.php | 27 + .../Swift/Events/SimpleEventDispatcher.php | 142 + .../Swift/Events/TransportChangeEvent.php | 27 + .../Swift/Events/TransportChangeListener.php | 37 + .../Swift/Events/TransportExceptionEvent.php | 43 + .../Events/TransportExceptionListener.php | 22 + .../lib/classes/Swift/FailoverTransport.php | 33 + .../lib/classes/Swift/FileSpool.php | 208 + .../lib/classes/Swift/FileStream.php | 24 + .../lib/classes/Swift/Filterable.php | 31 + .../lib/classes/Swift/IdGenerator.php | 22 + .../swiftmailer/lib/classes/Swift/Image.php | 43 + .../lib/classes/Swift/InputByteStream.php | 75 + .../lib/classes/Swift/IoException.php | 28 + .../lib/classes/Swift/KeyCache.php | 104 + .../classes/Swift/KeyCache/ArrayKeyCache.php | 197 + .../classes/Swift/KeyCache/DiskKeyCache.php | 294 + .../Swift/KeyCache/KeyCacheInputStream.php | 47 + .../classes/Swift/KeyCache/NullKeyCache.php | 113 + .../KeyCache/SimpleKeyCacheInputStream.php | 123 + .../classes/Swift/LoadBalancedTransport.php | 33 + .../swiftmailer/lib/classes/Swift/Mailer.php | 98 + .../Swift/Mailer/ArrayRecipientIterator.php | 53 + .../Swift/Mailer/RecipientIterator.php | 32 + .../lib/classes/Swift/MemorySpool.php | 110 + .../swiftmailer/lib/classes/Swift/Message.php | 279 + .../lib/classes/Swift/Mime/Attachment.php | 144 + .../classes/Swift/Mime/CharsetObserver.php | 24 + .../lib/classes/Swift/Mime/ContentEncoder.php | 34 + .../ContentEncoder/Base64ContentEncoder.php | 101 + .../ContentEncoder/NativeQpContentEncoder.php | 121 + .../ContentEncoder/NullContentEncoder.php | 79 + .../ContentEncoder/PlainContentEncoder.php | 164 + .../Mime/ContentEncoder/QpContentEncoder.php | 134 + .../ContentEncoder/QpContentEncoderProxy.php | 96 + .../Mime/ContentEncoder/RawContentEncoder.php | 65 + .../lib/classes/Swift/Mime/EmbeddedFile.php | 41 + .../classes/Swift/Mime/EncodingObserver.php | 22 + .../lib/classes/Swift/Mime/Header.php | 93 + .../lib/classes/Swift/Mime/HeaderEncoder.php | 24 + .../HeaderEncoder/Base64HeaderEncoder.php | 55 + .../Mime/HeaderEncoder/QpHeaderEncoder.php | 65 + .../Swift/Mime/Headers/AbstractHeader.php | 486 + .../classes/Swift/Mime/Headers/DateHeader.php | 113 + .../Mime/Headers/IdentificationHeader.php | 189 + .../Swift/Mime/Headers/MailboxHeader.php | 358 + .../Swift/Mime/Headers/OpenDKIMHeader.php | 135 + .../Mime/Headers/ParameterizedHeader.php | 255 + .../classes/Swift/Mime/Headers/PathHeader.php | 153 + .../Swift/Mime/Headers/UnstructuredHeader.php | 109 + .../lib/classes/Swift/Mime/IdGenerator.php | 54 + .../lib/classes/Swift/Mime/MimePart.php | 199 + .../Swift/Mime/SimpleHeaderFactory.php | 195 + .../classes/Swift/Mime/SimpleHeaderSet.php | 399 + .../lib/classes/Swift/Mime/SimpleMessage.php | 642 + .../classes/Swift/Mime/SimpleMimeEntity.php | 826 + .../lib/classes/Swift/MimePart.php | 45 + .../lib/classes/Swift/NullTransport.php | 26 + .../lib/classes/Swift/OutputByteStream.php | 46 + .../classes/Swift/Plugins/AntiFloodPlugin.php | 137 + .../Swift/Plugins/BandwidthMonitorPlugin.php | 154 + .../Swift/Plugins/Decorator/Replacements.php | 31 + .../classes/Swift/Plugins/DecoratorPlugin.php | 200 + .../Swift/Plugins/ImpersonatePlugin.php | 65 + .../lib/classes/Swift/Plugins/Logger.php | 36 + .../classes/Swift/Plugins/LoggerPlugin.php | 126 + .../Swift/Plugins/Loggers/ArrayLogger.php | 72 + .../Swift/Plugins/Loggers/EchoLogger.php | 58 + .../classes/Swift/Plugins/MessageLogger.php | 70 + .../Swift/Plugins/Pop/Pop3Connection.php | 31 + .../Swift/Plugins/Pop/Pop3Exception.php | 27 + .../Swift/Plugins/PopBeforeSmtpPlugin.php | 242 + .../Swift/Plugins/RedirectingPlugin.php | 201 + .../lib/classes/Swift/Plugins/Reporter.php | 31 + .../classes/Swift/Plugins/ReporterPlugin.php | 57 + .../Swift/Plugins/Reporters/HitReporter.php | 58 + .../Swift/Plugins/Reporters/HtmlReporter.php | 38 + .../lib/classes/Swift/Plugins/Sleeper.php | 24 + .../classes/Swift/Plugins/ThrottlerPlugin.php | 196 + .../lib/classes/Swift/Plugins/Timer.php | 24 + .../lib/classes/Swift/Preferences.php | 100 + .../Swift/ReplacementFilterFactory.php | 27 + .../classes/Swift/RfcComplianceException.php | 27 + .../lib/classes/Swift/SendmailTransport.php | 33 + .../swiftmailer/lib/classes/Swift/Signer.php | 19 + .../lib/classes/Swift/Signers/BodySigner.php | 31 + .../lib/classes/Swift/Signers/DKIMSigner.php | 682 + .../classes/Swift/Signers/DomainKeySigner.php | 504 + .../classes/Swift/Signers/HeaderSigner.php | 61 + .../classes/Swift/Signers/OpenDKIMSigner.php | 183 + .../lib/classes/Swift/Signers/SMimeSigner.php | 542 + .../lib/classes/Swift/SmtpTransport.php | 45 + .../swiftmailer/lib/classes/Swift/Spool.php | 53 + .../lib/classes/Swift/SpoolTransport.php | 33 + .../lib/classes/Swift/StreamFilter.php | 35 + .../ByteArrayReplacementFilter.php | 166 + .../StreamFilters/StringReplacementFilter.php | 70 + .../StringReplacementFilterFactory.php | 45 + .../lib/classes/Swift/SwiftException.php | 28 + .../lib/classes/Swift/Transport.php | 76 + .../Swift/Transport/AbstractSmtpTransport.php | 541 + .../Esmtp/Auth/CramMd5Authenticator.php | 75 + .../Esmtp/Auth/LoginAuthenticator.php | 45 + .../Esmtp/Auth/NTLMAuthenticator.php | 681 + .../Esmtp/Auth/PlainAuthenticator.php | 44 + .../Esmtp/Auth/XOAuth2Authenticator.php | 64 + .../Swift/Transport/Esmtp/AuthHandler.php | 268 + .../Swift/Transport/Esmtp/Authenticator.php | 36 + .../Transport/Esmtp/EightBitMimeHandler.php | 113 + .../Swift/Transport/Esmtp/SmtpUtf8Handler.php | 107 + .../classes/Swift/Transport/EsmtpHandler.php | 86 + .../Swift/Transport/EsmtpTransport.php | 446 + .../Swift/Transport/FailoverTransport.php | 103 + .../lib/classes/Swift/Transport/IoBuffer.php | 65 + .../Swift/Transport/LoadBalancedTransport.php | 192 + .../classes/Swift/Transport/NullTransport.php | 98 + .../Swift/Transport/SendmailTransport.php | 158 + .../lib/classes/Swift/Transport/SmtpAgent.php | 36 + .../Swift/Transport/SpoolTransport.php | 120 + .../classes/Swift/Transport/StreamBuffer.php | 319 + .../lib/classes/Swift/TransportException.php | 28 + .../lib/dependency_maps/cache_deps.php | 23 + .../lib/dependency_maps/message_deps.php | 9 + .../lib/dependency_maps/mime_deps.php | 134 + .../lib/dependency_maps/transport_deps.php | 97 + .../swiftmailer/lib/mime_types.php | 1007 + .../swiftmailer/lib/preferences.php | 19 + .../swiftmailer/lib/swift_required.php | 22 + .../lib/swiftmailer_generate_mimes_config.php | 182 + .../vendor/symfony/polyfill-iconv/Iconv.php | 744 + .../vendor/symfony/polyfill-iconv/LICENSE | 19 + .../vendor/symfony/polyfill-iconv/README.md | 14 + .../Resources/charset/from.big5.php | 13719 +++++++++ .../Resources/charset/from.cp037.php | Bin 0 -> 3779 bytes .../Resources/charset/from.cp1006.php | Bin 0 -> 3860 bytes .../Resources/charset/from.cp1026.php | Bin 0 -> 3779 bytes .../Resources/charset/from.cp424.php | Bin 0 -> 3210 bytes .../Resources/charset/from.cp437.php | Bin 0 -> 3841 bytes .../Resources/charset/from.cp500.php | Bin 0 -> 3779 bytes .../Resources/charset/from.cp737.php | Bin 0 -> 3834 bytes .../Resources/charset/from.cp775.php | Bin 0 -> 3815 bytes .../Resources/charset/from.cp850.php | Bin 0 -> 3809 bytes .../Resources/charset/from.cp852.php | Bin 0 -> 3808 bytes .../Resources/charset/from.cp855.php | Bin 0 -> 3809 bytes .../Resources/charset/from.cp856.php | Bin 0 -> 3194 bytes .../Resources/charset/from.cp857.php | Bin 0 -> 3763 bytes .../Resources/charset/from.cp860.php | Bin 0 -> 3840 bytes .../Resources/charset/from.cp861.php | Bin 0 -> 3841 bytes .../Resources/charset/from.cp862.php | Bin 0 -> 3841 bytes .../Resources/charset/from.cp863.php | Bin 0 -> 3841 bytes .../Resources/charset/from.cp864.php | Bin 0 -> 3779 bytes .../Resources/charset/from.cp865.php | Bin 0 -> 3841 bytes .../Resources/charset/from.cp866.php | Bin 0 -> 3831 bytes .../Resources/charset/from.cp869.php | Bin 0 -> 3676 bytes .../Resources/charset/from.cp874.php | Bin 0 -> 3410 bytes .../Resources/charset/from.cp875.php | Bin 0 -> 3776 bytes .../Resources/charset/from.cp932.php | Bin 0 -> 134095 bytes .../Resources/charset/from.cp936.php | Bin 0 -> 372283 bytes .../Resources/charset/from.cp949.php | Bin 0 -> 291504 bytes .../Resources/charset/from.cp950.php | Bin 0 -> 231436 bytes .../Resources/charset/from.iso-8859-1.php | Bin 0 -> 3779 bytes .../Resources/charset/from.iso-8859-10.php | Bin 0 -> 3780 bytes .../Resources/charset/from.iso-8859-11.php | Bin 0 -> 3746 bytes .../Resources/charset/from.iso-8859-13.php | Bin 0 -> 3783 bytes .../Resources/charset/from.iso-8859-14.php | Bin 0 -> 3801 bytes .../Resources/charset/from.iso-8859-15.php | Bin 0 -> 3780 bytes .../Resources/charset/from.iso-8859-16.php | Bin 0 -> 3782 bytes .../Resources/charset/from.iso-8859-2.php | Bin 0 -> 3779 bytes .../Resources/charset/from.iso-8859-3.php | Bin 0 -> 3674 bytes .../Resources/charset/from.iso-8859-4.php | Bin 0 -> 3779 bytes .../Resources/charset/from.iso-8859-5.php | Bin 0 -> 3780 bytes .../Resources/charset/from.iso-8859-6.php | Bin 0 -> 3104 bytes .../Resources/charset/from.iso-8859-7.php | Bin 0 -> 3692 bytes .../Resources/charset/from.iso-8859-8.php | Bin 0 -> 3242 bytes .../Resources/charset/from.iso-8859-9.php | Bin 0 -> 3779 bytes .../Resources/charset/from.koi8-r.php | Bin 0 -> 3835 bytes .../Resources/charset/from.koi8-u.php | Bin 0 -> 3827 bytes .../Resources/charset/from.us-ascii.php | Bin 0 -> 1859 bytes .../Resources/charset/from.windows-1250.php | Bin 0 -> 3721 bytes .../Resources/charset/from.windows-1251.php | Bin 0 -> 3782 bytes .../Resources/charset/from.windows-1252.php | Bin 0 -> 3721 bytes .../Resources/charset/from.windows-1253.php | Bin 0 -> 3542 bytes .../Resources/charset/from.windows-1254.php | Bin 0 -> 3691 bytes .../Resources/charset/from.windows-1255.php | Bin 0 -> 3454 bytes .../Resources/charset/from.windows-1256.php | Bin 0 -> 3800 bytes .../Resources/charset/from.windows-1257.php | Bin 0 -> 3616 bytes .../Resources/charset/from.windows-1258.php | Bin 0 -> 3662 bytes .../Resources/charset/translit.php | 4106 +++ .../symfony/polyfill-iconv/bootstrap.php | 88 + .../symfony/polyfill-iconv/bootstrap80.php | 80 + .../symfony/polyfill-iconv/composer.json | 38 + .../vendor/symfony/polyfill-intl-idn/Idn.php | 925 + .../vendor/symfony/polyfill-intl-idn/Info.php | 23 + .../vendor/symfony/polyfill-intl-idn/LICENSE | 19 + .../symfony/polyfill-intl-idn/README.md | 12 + .../Resources/unidata/DisallowedRanges.php | 375 + .../Resources/unidata/Regex.php | 24 + .../Resources/unidata/deviation.php | 8 + .../Resources/unidata/disallowed.php | 2638 ++ .../unidata/disallowed_STD3_mapped.php | 308 + .../unidata/disallowed_STD3_valid.php | 71 + .../Resources/unidata/ignored.php | 273 + .../Resources/unidata/mapped.php | 5778 ++++ .../Resources/unidata/virama.php | 65 + .../symfony/polyfill-intl-idn/bootstrap.php | 145 + .../symfony/polyfill-intl-idn/bootstrap80.php | 125 + .../symfony/polyfill-intl-idn/composer.json | 44 + .../symfony/polyfill-intl-normalizer/LICENSE | 19 + .../polyfill-intl-normalizer/Normalizer.php | 310 + .../polyfill-intl-normalizer/README.md | 14 + .../Resources/stubs/Normalizer.php | 17 + .../unidata/canonicalComposition.php | 945 + .../unidata/canonicalDecomposition.php | 2065 ++ .../Resources/unidata/combiningClass.php | 876 + .../unidata/compatibilityDecomposition.php | 3695 +++ .../polyfill-intl-normalizer/bootstrap.php | 23 + .../polyfill-intl-normalizer/bootstrap80.php | 19 + .../polyfill-intl-normalizer/composer.json | 39 + .../vendor/symfony/polyfill-mbstring/LICENSE | 19 + .../symfony/polyfill-mbstring/Mbstring.php | 870 + .../symfony/polyfill-mbstring/README.md | 13 + .../Resources/unidata/lowerCase.php | 1397 + .../Resources/unidata/titleCaseRegexp.php | 5 + .../Resources/unidata/upperCase.php | 1489 + .../symfony/polyfill-mbstring/bootstrap.php | 147 + .../symfony/polyfill-mbstring/bootstrap80.php | 143 + .../symfony/polyfill-mbstring/composer.json | 38 + .../vendor/symfony/polyfill-php72/LICENSE | 19 + .../vendor/symfony/polyfill-php72/Php72.php | 217 + .../vendor/symfony/polyfill-php72/README.md | 28 + .../symfony/polyfill-php72/bootstrap.php | 57 + .../symfony/polyfill-php72/composer.json | 35 + dev/plugins/error/CHANGELOG.md | 91 + dev/plugins/error/LICENSE | 21 + dev/plugins/error/README.md | 93 + dev/plugins/error/assets/readme_1.png | Bin 0 -> 41685 bytes dev/plugins/error/blueprints.yaml | 36 + dev/plugins/error/cli/LogCommand.php | 130 + dev/plugins/error/composer.json | 39 + dev/plugins/error/error.php | 117 + dev/plugins/error/error.yaml | 3 + dev/plugins/error/languages.yaml | 55 + dev/plugins/error/templates/error.html.twig | 3 + dev/plugins/error/templates/error.json.twig | 1 + dev/plugins/error/vendor/autoload.php | 7 + .../error/vendor/composer/ClassLoader.php | 445 + dev/plugins/error/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 10 + .../vendor/composer/autoload_namespaces.php | 9 + .../error/vendor/composer/autoload_psr4.php | 10 + .../error/vendor/composer/autoload_real.php | 52 + .../error/vendor/composer/autoload_static.php | 36 + .../error/vendor/composer/installed.json | 1 + dev/plugins/external_links/CHANGELOG.md | 189 + dev/plugins/external_links/LICENSE | 727 + dev/plugins/external_links/README.md | 192 + .../assets/css/external_links.css | 39 + .../external_links/assets/images/link.png | Bin 0 -> 196 bytes .../external_links/assets/images/mail.png | Bin 0 -> 187 bytes dev/plugins/external_links/assets/logo.png | Bin 0 -> 21194 bytes .../external_links/assets/screenshot.png | Bin 0 -> 23677 bytes dev/plugins/external_links/blueprints.yaml | 194 + .../blueprints/external_links.yaml | 80 + .../external_links/classes/ExternalLinks.php | 505 + .../external_links/docs/CONTRIBUTING.md | 125 + dev/plugins/external_links/docs/INSTALL.md | 47 + dev/plugins/external_links/external_links.php | 221 + .../external_links/external_links.yaml | 43 + dev/plugins/external_links/languages.yaml | 215 + dev/plugins/feed/CHANGELOG.md | 143 + dev/plugins/feed/LICENSE | 21 + dev/plugins/feed/README.md | 146 + dev/plugins/feed/assets/readme_1.png | Bin 0 -> 298108 bytes dev/plugins/feed/blueprints.yaml | 78 + dev/plugins/feed/blueprints/feed.yaml | 22 + dev/plugins/feed/composer.json | 36 + dev/plugins/feed/composer.lock | 21 + dev/plugins/feed/feed.php | 162 + dev/plugins/feed/feed.yaml | 7 + dev/plugins/feed/hebe.json | 15 + dev/plugins/feed/templates/feed.atom.twig | 45 + dev/plugins/feed/templates/feed.json.twig | 43 + dev/plugins/feed/templates/feed.rss.twig | 40 + dev/plugins/feed/vendor/autoload.php | 7 + .../feed/vendor/composer/ClassLoader.php | 445 + .../vendor/composer/InstalledVersions.php | 209 + dev/plugins/feed/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 11 + .../vendor/composer/autoload_namespaces.php | 9 + .../feed/vendor/composer/autoload_psr4.php | 9 + .../feed/vendor/composer/autoload_real.php | 55 + .../feed/vendor/composer/autoload_static.php | 21 + .../feed/vendor/composer/installed.json | 5 + .../feed/vendor/composer/installed.php | 24 + dev/plugins/flex-objects/CHANGELOG.md | 504 + dev/plugins/flex-objects/LICENSE | 21 + dev/plugins/flex-objects/README.md | 289 + .../admin/templates/flex-objects.html.twig | 30 + .../admin/templates/flex-objects.json.twig | 1 + .../flex-objects/layouts/404.html.twig | 1 + .../layouts/accounts/partials/top.html.twig | 25 + .../types/default/buttons/add.html.twig | 3 + .../types/default/buttons/back.html.twig | 3 + .../default/buttons/configuration.html.twig | 7 + .../types/default/buttons/delete.html.twig | 3 + .../default/buttons/export-csv.html.twig | 3 + .../types/default/buttons/export.html.twig | 21 + .../types/default/buttons/languages.html.twig | 18 + .../default/buttons/preview-open.html.twig | 5 + .../types/default/buttons/preview.html.twig | 3 + .../types/default/buttons/save.html.twig | 4 + .../types/default/configure.html.twig | 103 + .../flex-objects/types/default/edit.html.twig | 121 + .../flex-objects/types/default/list.html.twig | 98 + .../types/default/list/list.html.twig | 112 + .../types/default/list/list_actions.html.twig | 39 + .../types/default/modals/remove.html.twig | 13 + .../types/default/preview.html.twig | 62 + .../default/titlebar/configure.html.twig | 32 + .../types/default/titlebar/edit.html.twig | 46 + .../types/default/titlebar/list.html.twig | 48 + .../types/default/titlebar/preview.html.twig | 30 + .../types/default/titlebar/types.html.twig | 22 + .../types/default/types.html.twig | 46 + .../types/user-accounts/configure.html.twig | 9 + .../types/user-accounts/edit.html.twig | 9 + .../types/user-accounts/list.html.twig | 7 + .../types/user-groups/configure.html.twig | 9 + .../types/user-groups/list.html.twig | 7 + .../flex-objects/flex-objects.html.twig | 69 + .../save-redirect/save-redirect.html.twig | 37 + .../flex-objects/app/columns/finder.js | 425 + dev/plugins/flex-objects/app/columns/index.js | 102 + dev/plugins/flex-objects/app/filters/index.js | 46 + dev/plugins/flex-objects/app/filters/panel.js | 15 + dev/plugins/flex-objects/app/list/App.vue | 27 + .../app/list/VuetableCssConfig.js | 29 + .../app/list/components/ContentLoader.vue | 48 + .../app/list/components/FilterBar.vue | 66 + .../app/list/components/Table.vue | 94 + dev/plugins/flex-objects/app/list/index.js | 19 + dev/plugins/flex-objects/app/main.js | 3 + dev/plugins/flex-objects/app/utils/finder.js | 393 + .../flex-objects/app/utils/get-filters.js | 34 + .../flex-objects/app/utils/indeterminate.js | 44 + .../assets/flex-objects-directory.png | Bin 0 -> 137785 bytes .../flex-objects/assets/flex-objects-edit.png | Bin 0 -> 159728 bytes .../flex-objects/assets/flex-objects-list.png | Bin 0 -> 239360 bytes .../assets/flex-objects-options.png | Bin 0 -> 256165 bytes .../flex-objects/assets/flex-objects-site.png | Bin 0 -> 253928 bytes dev/plugins/flex-objects/blueprints.yaml | 55 + .../flex-objects/blueprints/flex-objects.yaml | 16 + .../blueprints/flex-objects/contacts.yaml | 158 + .../blueprints/flex-objects/pages.yaml | 22 + .../flex-objects/user-accounts.yaml | 7 + .../blueprints/flex-objects/user-groups.yaml | 7 + .../classes/Admin/AdminController.php | 1916 ++ .../Controllers/AbstractController.php | 359 + .../classes/Controllers/MediaController.php | 541 + .../classes/Controllers/ObjectController.php | 515 + .../classes/Events/FlexTaskEvent.php | 84 + dev/plugins/flex-objects/classes/Flex.php | 444 + .../flex-objects/classes/FlexFormFactory.php | 80 + .../flex-objects/classes/FlexRouter.php | 64 + .../flex-objects/classes/Table/DataTable.php | 410 + .../cli/FlexConvertDataCommand.php | 141 + dev/plugins/flex-objects/composer.json | 32 + dev/plugins/flex-objects/composer.lock | 25 + dev/plugins/flex-objects/css/admin.css | 97 + dev/plugins/flex-objects/css/admin.css.map | 11 + dev/plugins/flex-objects/css/admin.min.css | 1 + dev/plugins/flex-objects/css/site.css | 27 + dev/plugins/flex-objects/css/site.css.map | 11 + dev/plugins/flex-objects/css/site.min.css | 1 + .../data/flex-objects/contacts.json | 6262 ++++ dev/plugins/flex-objects/flex-objects.php | 805 + dev/plugins/flex-objects/flex-objects.yaml | 14 + dev/plugins/flex-objects/js/flex-objects.js | 905 + dev/plugins/flex-objects/js/list.min.js | 2 + dev/plugins/flex-objects/languages/de.yaml | 71 + dev/plugins/flex-objects/languages/en.yaml | 73 + dev/plugins/flex-objects/languages/es.yaml | 73 + dev/plugins/flex-objects/languages/ja.yaml | 73 + dev/plugins/flex-objects/languages/ru.yaml | 12 + dev/plugins/flex-objects/package.json | 51 + dev/plugins/flex-objects/permissions.yaml | 45 + dev/plugins/flex-objects/scss/_preset.scss | 69 + dev/plugins/flex-objects/scss/admin.scss | 3 + .../flex-objects/scss/plugin/_admin.scss | 215 + .../flex-objects/scss/plugin/_site.scss | 68 + dev/plugins/flex-objects/scss/site.scss | 2 + .../templates/flex-edit.html.twig | 42 + .../templates/flex-objects.html.twig | 21 + .../directories/default.html.twig | 30 + .../templates/flex-objects/page.html.twig | 37 + .../flex-objects/views/404.html.twig | 1 + .../flex-objects/views/directories.html.twig | 12 + .../flex-objects/views/directory.html.twig | 24 + .../flex-objects/views/object.html.twig | 23 + .../contacts/collection/default.html.twig | 26 + .../flex/contacts/object/default.html.twig | 15 + .../contacts/object/list-default.html.twig | 15 + .../collection/default.html.twig | 25 + .../user-accounts/object/default.html.twig | 17 + .../object/list-default.html.twig | 27 + .../user-groups/collection/default.html.twig | 25 + .../flex/user-groups/object/default.html.twig | 14 + .../user-groups/object/list-default.html.twig | 16 + .../fields/filepicker/filepicker.html.twig | 17 + .../forms/fields/list/list.html.twig | 177 + .../fields/pagemedia/pagemedia.html.twig | 89 + .../forms/fields/pagemedia/template.html.twig | 33 + dev/plugins/flex-objects/vendor/autoload.php | 7 + .../vendor/composer/ClassLoader.php | 572 + .../vendor/composer/InstalledVersions.php | 350 + .../flex-objects/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 11 + .../vendor/composer/autoload_namespaces.php | 9 + .../vendor/composer/autoload_psr4.php | 10 + .../vendor/composer/autoload_real.php | 57 + .../vendor/composer/autoload_static.php | 37 + .../vendor/composer/installed.json | 5 + .../vendor/composer/installed.php | 23 + .../vendor/composer/platform_check.php | 26 + dev/plugins/flex-objects/watch.sh | 27 + dev/plugins/flex-objects/webpack.conf.js | 75 + dev/plugins/flex-objects/yarn.lock | 3271 +++ dev/plugins/form/CHANGELOG.md | 1194 + dev/plugins/form/LICENSE | 21 + dev/plugins/form/README.md | 41 + dev/plugins/form/app/fields/array.js | 200 + dev/plugins/form/app/fields/file.js | 340 + dev/plugins/form/app/fields/form.js | 94 + dev/plugins/form/app/fields/index.js | 7 + dev/plugins/form/app/fields/media.js | 174 + dev/plugins/form/app/fields/tabs.js | 14 + dev/plugins/form/app/main.js | 4 + dev/plugins/form/app/utils/keep-alive.js | 17 + dev/plugins/form/assets/dropzone.min.css | 1 + dev/plugins/form/assets/form-styles.css | 80 + dev/plugins/form/assets/form-styles.min.css | 1 + dev/plugins/form/assets/form.min.js | 41 + dev/plugins/form/assets/form.vendor.js | 24 + .../form/assets/object.assign.polyfill.js | 29 + dev/plugins/form/assets/signature_pad.js | 617 + dev/plugins/form/blueprints.yaml | 198 + dev/plugins/form/classes/Form.php | 1422 + dev/plugins/form/classes/FormFactory.php | 38 + dev/plugins/form/classes/Forms.php | 129 + dev/plugins/form/classes/TwigExtension.php | 155 + dev/plugins/form/composer.json | 40 + dev/plugins/form/composer.lock | 77 + dev/plugins/form/form.php | 1261 + dev/plugins/form/form.yaml | 20 + dev/plugins/form/gulpfile.js | 84 + dev/plugins/form/hebe.json | 15 + dev/plugins/form/languages.yaml | 897 + dev/plugins/form/package.json | 45 + dev/plugins/form/scss/form-styles.scss | 289 + .../form/templates/form-messages.html.twig | 2 + .../form/templates/form-messages.json.twig | 2 + dev/plugins/form/templates/form.html.twig | 8 + dev/plugins/form/templates/form.json.twig | 1 + dev/plugins/form/templates/formdata.html.twig | 20 + .../form/templates/forms/ajax.json.twig | 5 + .../form/templates/forms/data.html.twig | 1 + .../form/templates/forms/data.txt.twig | 1 + .../templates/forms/default/data.html.twig | 77 + .../templates/forms/default/data.txt.twig | 21 + .../templates/forms/default/field.html.twig | 158 + .../templates/forms/default/fields.html.twig | 17 + .../templates/forms/default/form.html.twig | 208 + .../forms/default/toggleable.html.twig | 9 + .../forms/dropzone/template.html.twig | 39 + .../form/templates/forms/field.html.twig | 9 + .../forms/fields/array/array.html.twig | 99 + .../forms/fields/avatar/avatar.html.twig | 10 + .../forms/fields/captcha/captcha.html.twig | 100 + .../forms/fields/checkbox/checkbox.html.twig | 46 + .../fields/checkboxes/checkboxes.html.twig | 41 + .../forms/fields/color/color.html.twig | 6 + .../forms/fields/column/column.html.twig | 8 + .../forms/fields/columns/columns.html.twig | 7 + .../fields/conditional/conditional.html.twig | 19 + .../forms/fields/date/date.html.twig | 8 + .../forms/fields/date/edit_list.html.twig | 1 + .../forms/fields/datetime/datetime.html.twig | 2 + .../forms/fields/datetime/edit_list.html.twig | 1 + .../forms/fields/display/display.html.twig | 21 + .../forms/fields/email/email.html.twig | 10 + .../forms/fields/fieldset/fieldset.html.twig | 12 + .../forms/fields/file/file.html.twig | 124 + .../forms/fields/formname/formname.html.twig | 5 + .../forms/fields/formtask/formtask.html.twig | 8 + .../forms/fields/hidden/hidden.html.twig | 15 + .../forms/fields/honeypot/honeypot.html.twig | 13 + .../forms/fields/ignore/ignore.html.twig | 0 .../templates/forms/fields/key/key.html.twig | 28 + .../forms/fields/month/month.html.twig | 6 + .../forms/fields/nonce/nonce.html.twig | 1 + .../forms/fields/number/number.html.twig | 9 + .../forms/fields/password/password.html.twig | 8 + .../forms/fields/radio/radio.html.twig | 21 + .../forms/fields/range/range.html.twig | 9 + .../forms/fields/section/section.html.twig | 21 + .../forms/fields/select/select.html.twig | 73 + .../select_optgroup/select_optgroup.html.twig | 2 + .../fields/signature/signature.html.twig | 105 + .../forms/fields/spacer/spacer.html.twig | 19 + .../forms/fields/switch/switch.html.twig | 1 + .../templates/forms/fields/tab/tab.html.twig | 8 + .../forms/fields/tabs/tabs.html.twig | 60 + .../templates/forms/fields/tel/tel.html.twig | 9 + .../forms/fields/text/edit_list.html.twig | 7 + .../forms/fields/text/text.html.twig | 39 + .../forms/fields/textarea/textarea.html.twig | 51 + .../forms/fields/time/edit_list.html.twig | 1 + .../forms/fields/time/time.html.twig | 6 + .../forms/fields/toggle/edit_list.html.twig | 5 + .../forms/fields/toggle/toggle.html.twig | 52 + .../forms/fields/uniqueid/uniqueid.html.twig | 5 + .../forms/fields/url/edit_list.html.twig | 1 + .../templates/forms/fields/url/url.html.twig | 9 + .../forms/fields/value/value.html.twig | 18 + .../forms/fields/week/week.html.twig | 6 + .../form/templates/forms/form.html.twig | 29 + .../templates/forms/layouts/button.html.twig | 4 + .../layouts/button/default-button.html.twig | 12 + .../forms/layouts/field-variables.html.twig | 1 + .../templates/forms/layouts/field.html.twig | 4 + .../layouts/field/default-field.html.twig | 53 + .../templates/forms/layouts/form.html.twig | 4 + .../forms/layouts/form/default-form.html.twig | 8 + .../form/templates/modular/form.html.twig | 4 + .../partials/form-messages.html.twig | 6 + .../partials/form-messages.json.twig | 3 + dev/plugins/form/vendor/autoload.php | 7 + .../form/vendor/composer/ClassLoader.php | 572 + .../vendor/composer/InstalledVersions.php | 350 + dev/plugins/form/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 11 + .../vendor/composer/autoload_namespaces.php | 9 + .../form/vendor/composer/autoload_psr4.php | 11 + .../form/vendor/composer/autoload_real.php | 57 + .../form/vendor/composer/autoload_static.php | 45 + .../form/vendor/composer/installed.json | 61 + .../form/vendor/composer/installed.php | 32 + .../form/vendor/composer/platform_check.php | 26 + .../.github/ISSUE_TEMPLATE/bug_report.md | 28 + .../vendor/google/recaptcha/ARCHITECTURE.md | 64 + .../vendor/google/recaptcha/CONTRIBUTING.md | 49 + .../form/vendor/google/recaptcha/LICENSE | 29 + .../form/vendor/google/recaptcha/README.md | 140 + .../form/vendor/google/recaptcha/app.yaml | 8 + .../vendor/google/recaptcha/composer.json | 39 + .../recaptcha/examples/appengine-https.php | 42 + .../google/recaptcha/examples/config.php.dist | 46 + .../google/recaptcha/examples/examples.css | 37 + .../examples/google0afd8760fd68f119.html | 1 + .../google/recaptcha/examples/index.php | 79 + .../recaptcha-content-security-policy.php | 152 + .../recaptcha-v2-checkbox-explicit.php | 148 + .../examples/recaptcha-v2-checkbox.php | 139 + .../examples/recaptcha-v2-invisible.php | 141 + .../examples/recaptcha-v3-request-scores.php | 120 + .../examples/recaptcha-v3-verify.php | 59 + .../google/recaptcha/examples/robots.txt | 2 + .../vendor/google/recaptcha/phpunit.xml.dist | 20 + .../recaptcha/src/ReCaptcha/ReCaptcha.php | 269 + .../recaptcha/src/ReCaptcha/RequestMethod.php | 50 + .../src/ReCaptcha/RequestMethod/Curl.php | 82 + .../src/ReCaptcha/RequestMethod/CurlPost.php | 104 + .../src/ReCaptcha/RequestMethod/Post.php | 88 + .../src/ReCaptcha/RequestMethod/Socket.php | 112 + .../ReCaptcha/RequestMethod/SocketPost.php | 108 + .../src/ReCaptcha/RequestParameters.php | 111 + .../recaptcha/src/ReCaptcha/Response.php | 218 + .../vendor/google/recaptcha/src/autoload.php | 69 + .../tests/ReCaptcha/ReCaptchaTest.php | 198 + .../ReCaptcha/RequestMethod/CurlPostTest.php | 123 + .../ReCaptcha/RequestMethod/PostTest.php | 149 + .../RequestMethod/SocketPostTest.php | 136 + .../tests/ReCaptcha/RequestParametersTest.php | 70 + .../tests/ReCaptcha/ResponseTest.php | 173 + dev/plugins/form/webpack.conf.js | 65 + dev/plugins/form/yarn.lock | 7407 +++++ dev/plugins/git-sync/CHANGELOG.md | 200 + dev/plugins/git-sync/LICENSE | 201 + dev/plugins/git-sync/README.md | 90 + dev/plugins/git-sync/app/main.js | 1 + dev/plugins/git-sync/app/wizard/index.js | 379 + dev/plugins/git-sync/blueprints.yaml | 289 + .../git-sync/classes/AdminController.php | 177 + dev/plugins/git-sync/classes/GitSync.php | 536 + dev/plugins/git-sync/classes/Helper.php | 158 + dev/plugins/git-sync/cli/InitCommand.php | 45 + dev/plugins/git-sync/cli/PasswdCommand.php | 91 + dev/plugins/git-sync/cli/StatusCommand.php | 149 + dev/plugins/git-sync/cli/SyncCommand.php | 51 + dev/plugins/git-sync/composer.json | 28 + dev/plugins/git-sync/composer.lock | 139 + .../git-sync/css-compiled/git-sync-icon.css | 22 + .../git-sync/css-compiled/git-sync.css | 137 + dev/plugins/git-sync/fonts/gitsync.svg | 12 + dev/plugins/git-sync/fonts/gitsync.ttf | Bin 0 -> 1832 bytes dev/plugins/git-sync/fonts/gitsync.woff | Bin 0 -> 1908 bytes dev/plugins/git-sync/git-sync.php | 490 + dev/plugins/git-sync/git-sync.yaml | 1 + dev/plugins/git-sync/gosass.sh | 2 + dev/plugins/git-sync/images/gitsync-logo.png | Bin 0 -> 6495 bytes .../git-sync/images/repos/bitbucket.svg | 79 + dev/plugins/git-sync/images/repos/github.svg | 15 + dev/plugins/git-sync/images/repos/gitlab.svg | 77 + dev/plugins/git-sync/images/repos/gitlogo.svg | 65 + dev/plugins/git-sync/js/app.js | 196 + dev/plugins/git-sync/js/vendor.js | 61 + dev/plugins/git-sync/package.json | 44 + .../git-sync/scss/configuration/_colors.scss | 8 + dev/plugins/git-sync/scss/git-sync.scss | 7 + dev/plugins/git-sync/scss/plugin/_wizard.scss | 191 + .../bourbon/_bourbon-deprecated-upcoming.scss | 411 + .../scss/vendor/bourbon/_bourbon.scss | 87 + .../vendor/bourbon/addons/_border-color.scss | 26 + .../vendor/bourbon/addons/_border-radius.scss | 48 + .../vendor/bourbon/addons/_border-style.scss | 25 + .../vendor/bourbon/addons/_border-width.scss | 25 + .../scss/vendor/bourbon/addons/_buttons.scss | 64 + .../scss/vendor/bourbon/addons/_clearfix.scss | 25 + .../scss/vendor/bourbon/addons/_ellipsis.scss | 30 + .../vendor/bourbon/addons/_font-stacks.scss | 31 + .../vendor/bourbon/addons/_hide-text.scss | 27 + .../scss/vendor/bourbon/addons/_margin.scss | 26 + .../scss/vendor/bourbon/addons/_padding.scss | 26 + .../scss/vendor/bourbon/addons/_position.scss | 48 + .../scss/vendor/bourbon/addons/_prefixer.scss | 66 + .../vendor/bourbon/addons/_retina-image.scss | 25 + .../scss/vendor/bourbon/addons/_size.scss | 51 + .../vendor/bourbon/addons/_text-inputs.scss | 113 + .../bourbon/addons/_timing-functions.scss | 34 + .../scss/vendor/bourbon/addons/_triangle.scss | 63 + .../vendor/bourbon/addons/_word-wrap.scss | 29 + .../scss/vendor/bourbon/css3/_animation.scss | 43 + .../scss/vendor/bourbon/css3/_appearance.scss | 3 + .../bourbon/css3/_backface-visibility.scss | 3 + .../bourbon/css3/_background-image.scss | 42 + .../scss/vendor/bourbon/css3/_background.scss | 55 + .../vendor/bourbon/css3/_border-image.scss | 59 + .../scss/vendor/bourbon/css3/_calc.scss | 4 + .../scss/vendor/bourbon/css3/_columns.scss | 47 + .../scss/vendor/bourbon/css3/_filter.scss | 4 + .../scss/vendor/bourbon/css3/_flex-box.scss | 287 + .../scss/vendor/bourbon/css3/_font-face.scss | 24 + .../bourbon/css3/_font-feature-settings.scss | 4 + .../bourbon/css3/_hidpi-media-query.scss | 10 + .../scss/vendor/bourbon/css3/_hyphens.scss | 4 + .../vendor/bourbon/css3/_image-rendering.scss | 14 + .../scss/vendor/bourbon/css3/_keyframes.scss | 36 + .../vendor/bourbon/css3/_linear-gradient.scss | 38 + .../vendor/bourbon/css3/_perspective.scss | 8 + .../vendor/bourbon/css3/_placeholder.scss | 8 + .../vendor/bourbon/css3/_radial-gradient.scss | 39 + .../scss/vendor/bourbon/css3/_selection.scss | 42 + .../vendor/bourbon/css3/_text-decoration.scss | 19 + .../scss/vendor/bourbon/css3/_transform.scss | 15 + .../scss/vendor/bourbon/css3/_transition.scss | 71 + .../vendor/bourbon/css3/_user-select.scss | 3 + .../bourbon/functions/_assign-inputs.scss | 11 + .../bourbon/functions/_contains-falsy.scss | 20 + .../vendor/bourbon/functions/_contains.scss | 26 + .../vendor/bourbon/functions/_is-length.scss | 11 + .../vendor/bourbon/functions/_is-light.scss | 21 + .../vendor/bourbon/functions/_is-number.scss | 11 + .../vendor/bourbon/functions/_is-size.scss | 13 + .../bourbon/functions/_modular-scale.scss | 69 + .../vendor/bourbon/functions/_px-to-em.scss | 13 + .../vendor/bourbon/functions/_px-to-rem.scss | 15 + .../scss/vendor/bourbon/functions/_shade.scss | 24 + .../bourbon/functions/_strip-units.scss | 17 + .../scss/vendor/bourbon/functions/_tint.scss | 24 + .../functions/_transition-property-name.scss | 22 + .../vendor/bourbon/functions/_unpack.scss | 27 + .../bourbon/helpers/_convert-units.scss | 21 + .../bourbon/helpers/_directional-values.scss | 96 + .../helpers/_font-source-declaration.scss | 43 + .../helpers/_gradient-positions-parser.scss | 13 + .../bourbon/helpers/_linear-angle-parser.scss | 25 + .../helpers/_linear-gradient-parser.scss | 41 + .../helpers/_linear-positions-parser.scss | 61 + .../helpers/_linear-side-corner-parser.scss | 31 + .../bourbon/helpers/_radial-arg-parser.scss | 69 + .../helpers/_radial-gradient-parser.scss | 50 + .../helpers/_radial-positions-parser.scss | 18 + .../bourbon/helpers/_render-gradients.scss | 26 + .../bourbon/helpers/_shape-size-stripper.scss | 10 + .../vendor/bourbon/helpers/_str-to-num.scss | 50 + .../bourbon/settings/_asset-pipeline.scss | 7 + .../vendor/bourbon/settings/_prefixer.scss | 9 + .../vendor/bourbon/settings/_px-to-em.scss | 1 + .../enc-password/enc-password.html.twig | 12 + .../fields/git-wizard/git-wizard.html.twig | 17 + .../templates/partials/modal-reset.html.twig | 17 + .../templates/partials/modal-wizard.html.twig | 460 + dev/plugins/git-sync/vendor/autoload.php | 7 + .../git-sync/vendor/bin/generate-defuse-key | 1 + .../git-sync/vendor/composer/ClassLoader.php | 477 + .../vendor/composer/InstalledVersions.php | 309 + dev/plugins/git-sync/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 14 + .../vendor/composer/autoload_namespaces.php | 9 + .../vendor/composer/autoload_psr4.php | 12 + .../vendor/composer/autoload_real.php | 57 + .../vendor/composer/autoload_static.php | 53 + .../git-sync/vendor/composer/installed.json | 124 + .../git-sync/vendor/composer/installed.php | 49 + .../vendor/composer/platform_check.php | 26 + .../vendor/defuse/php-encryption/LICENSE | 21 + .../vendor/defuse/php-encryption/README.md | 121 + .../php-encryption/bin/generate-defuse-key | 14 + .../defuse/php-encryption/composer.json | 34 + .../defuse/php-encryption/dist/Makefile | 39 + .../defuse/php-encryption/dist/box.json | 25 + .../php-encryption/dist/signingkey-new.asc | 53 + .../dist/signingkey-new.asc.sig | Bin 0 -> 566 bytes .../defuse/php-encryption/dist/signingkey.asc | 52 + .../php-encryption/docs/CryptoDetails.md | 64 + .../vendor/defuse/php-encryption/docs/FAQ.md | 51 + .../docs/InstallingAndVerifying.md | 53 + .../docs/InternalDeveloperDocs.md | 166 + .../defuse/php-encryption/docs/Tutorial.md | 314 + .../php-encryption/docs/UpgradingFromV1.2.md | 51 + .../php-encryption/docs/classes/Crypto.md | 280 + .../php-encryption/docs/classes/File.md | 486 + .../defuse/php-encryption/docs/classes/Key.md | 117 + .../docs/classes/KeyProtectedByPassword.md | 259 + .../vendor/defuse/php-encryption/src/Core.php | 457 + .../defuse/php-encryption/src/Crypto.php | 445 + .../defuse/php-encryption/src/DerivedKeys.php | 50 + .../defuse/php-encryption/src/Encoding.php | 269 + .../src/Exception/BadFormatException.php | 7 + .../src/Exception/CryptoException.php | 7 + .../EnvironmentIsBrokenException.php | 7 + .../src/Exception/IOException.php | 7 + .../WrongKeyOrModifiedCiphertextException.php | 7 + .../vendor/defuse/php-encryption/src/File.php | 778 + .../vendor/defuse/php-encryption/src/Key.php | 94 + .../php-encryption/src/KeyOrPassword.php | 149 + .../src/KeyProtectedByPassword.php | 145 + .../php-encryption/src/RuntimeTests.php | 228 + .../git-sync/vendor/sebastian/git/LICENSE | 33 + .../git-sync/vendor/sebastian/git/README.md | 14 + .../git-sync/vendor/sebastian/git/build.xml | 30 + .../vendor/sebastian/git/composer.json | 26 + .../sebastian/git/src/Exception/Exception.php | 15 + .../git/src/Exception/RuntimeException.php | 15 + .../git-sync/vendor/sebastian/git/src/Git.php | 145 + dev/plugins/git-sync/watch.sh | 27 + dev/plugins/git-sync/webpack.conf.js | 70 + dev/plugins/git-sync/wizard.png | Bin 0 -> 135495 bytes dev/plugins/git-sync/yarn.lock | 3623 +++ dev/plugins/highlight/CHANGELOG.md | 71 + dev/plugins/highlight/LICENSE | 21 + dev/plugins/highlight/README.md | 181 + dev/plugins/highlight/assets/readme_1.png | Bin 0 -> 167622 bytes dev/plugins/highlight/blueprints.yaml | 145 + dev/plugins/highlight/css/a11y-dark.css | 99 + dev/plugins/highlight/css/a11y-light.css | 99 + dev/plugins/highlight/css/agate.css | 108 + dev/plugins/highlight/css/an-old-hope.css | 89 + dev/plugins/highlight/css/androidstudio.css | 66 + dev/plugins/highlight/css/arduino-light.css | 87 + dev/plugins/highlight/css/arta.css | 73 + dev/plugins/highlight/css/ascetic.css | 45 + .../highlight/css/atelier-cave-dark.css | 83 + .../highlight/css/atelier-cave-light.css | 85 + .../highlight/css/atelier-dune-dark.css | 69 + .../highlight/css/atelier-dune-light.css | 69 + .../highlight/css/atelier-estuary-dark.css | 84 + .../highlight/css/atelier-estuary-light.css | 84 + .../highlight/css/atelier-forest-dark.css | 69 + .../highlight/css/atelier-forest-light.css | 69 + .../highlight/css/atelier-heath-dark.css | 69 + .../highlight/css/atelier-heath-light.css | 69 + .../highlight/css/atelier-lakeside-dark.css | 69 + .../highlight/css/atelier-lakeside-light.css | 69 + .../highlight/css/atelier-plateau-dark.css | 84 + .../highlight/css/atelier-plateau-light.css | 84 + .../highlight/css/atelier-savanna-dark.css | 84 + .../highlight/css/atelier-savanna-light.css | 84 + .../highlight/css/atelier-seaside-dark.css | 69 + .../highlight/css/atelier-seaside-light.css | 69 + .../css/atelier-sulphurpool-dark.css | 69 + .../css/atelier-sulphurpool-light.css | 69 + .../css/atom-one-dark-reasonable.css | 75 + dev/plugins/highlight/css/atom-one-dark.css | 96 + dev/plugins/highlight/css/atom-one-light.css | 96 + dev/plugins/highlight/css/brown-paper.css | 64 + dev/plugins/highlight/css/brown-papersq.png | Bin 0 -> 18198 bytes dev/plugins/highlight/css/codepen-embed.css | 60 + dev/plugins/highlight/css/color-brewer.css | 71 + dev/plugins/highlight/css/darcula.css | 74 + dev/plugins/highlight/css/dark.css | 63 + dev/plugins/highlight/css/default.css | 99 + dev/plugins/highlight/css/docco.css | 97 + dev/plugins/highlight/css/dracula.css | 76 + dev/plugins/highlight/css/far.css | 71 + dev/plugins/highlight/css/foundation.css | 89 + dev/plugins/highlight/css/github-gist.css | 79 + dev/plugins/highlight/css/github.css | 99 + dev/plugins/highlight/css/gml.css | 78 + dev/plugins/highlight/css/googlecode.css | 89 + dev/plugins/highlight/css/gradient-dark.css | 122 + dev/plugins/highlight/css/gradient-light.css | 130 + dev/plugins/highlight/css/grayscale.css | 101 + dev/plugins/highlight/css/gruvbox-dark.css | 108 + dev/plugins/highlight/css/gruvbox-light.css | 108 + .../css/highlightjs-line-numbers.css | 22 + dev/plugins/highlight/css/hopscotch.css | 84 + dev/plugins/highlight/css/hybrid.css | 102 + dev/plugins/highlight/css/idea.css | 97 + dev/plugins/highlight/css/ir-black.css | 73 + .../highlight/css/isbl-editor-dark.css | 112 + .../highlight/css/isbl-editor-light.css | 111 + dev/plugins/highlight/css/kimbie.dark.css | 74 + dev/plugins/highlight/css/kimbie.light.css | 74 + dev/plugins/highlight/css/learn.css | 62 + dev/plugins/highlight/css/lightfair.css | 88 + dev/plugins/highlight/css/lioshi.css | 88 + dev/plugins/highlight/css/magula.css | 70 + dev/plugins/highlight/css/mono-blue.css | 56 + dev/plugins/highlight/css/monokai-sublime.css | 83 + dev/plugins/highlight/css/monokai.css | 71 + dev/plugins/highlight/css/night-owl.css | 182 + dev/plugins/highlight/css/nnfx-dark.css | 106 + dev/plugins/highlight/css/nnfx.css | 106 + dev/plugins/highlight/css/nord.css | 309 + dev/plugins/highlight/css/obsidian.css | 88 + dev/plugins/highlight/css/ocean.css | 74 + dev/plugins/highlight/css/paraiso-dark.css | 72 + dev/plugins/highlight/css/paraiso-light.css | 72 + dev/plugins/highlight/css/pojoaque.css | 83 + dev/plugins/highlight/css/pojoaque.jpg | Bin 0 -> 1186 bytes dev/plugins/highlight/css/purebasic.css | 96 + dev/plugins/highlight/css/qtcreator_dark.css | 83 + dev/plugins/highlight/css/qtcreator_light.css | 83 + dev/plugins/highlight/css/railscasts.css | 106 + dev/plugins/highlight/css/rainbow.css | 85 + dev/plugins/highlight/css/routeros.css | 108 + dev/plugins/highlight/css/school-book.css | 69 + dev/plugins/highlight/css/school-book.png | Bin 0 -> 486 bytes .../highlight/css/shades-of-purple.css | 96 + dev/plugins/highlight/css/solarized-dark.css | 84 + dev/plugins/highlight/css/solarized-light.css | 84 + dev/plugins/highlight/css/srcery.css | 78 + .../highlight/css/stackoverflow-dark.css | 78 + .../highlight/css/stackoverflow-light.css | 78 + dev/plugins/highlight/css/sunburst.css | 102 + .../highlight/css/tomorrow-night-blue.css | 75 + .../highlight/css/tomorrow-night-bright.css | 74 + .../highlight/css/tomorrow-night-eighties.css | 74 + dev/plugins/highlight/css/tomorrow-night.css | 75 + dev/plugins/highlight/css/tomorrow.css | 72 + dev/plugins/highlight/css/vs.css | 68 + dev/plugins/highlight/css/vs2015.css | 115 + dev/plugins/highlight/css/xcode.css | 104 + dev/plugins/highlight/css/xt256.css | 92 + dev/plugins/highlight/css/zenburn.css | 80 + dev/plugins/highlight/hebe.json | 15 + dev/plugins/highlight/highlight.php | 61 + dev/plugins/highlight/highlight.yaml | 3 + dev/plugins/highlight/js/highlight.pack.js | 1269 + .../js/highlightjs-line-numbers.min.js | 1 + dev/plugins/image-captions/CHANGELOG.md | 55 + dev/plugins/image-captions/LICENSE | 21 + dev/plugins/image-captions/README.md | 139 + dev/plugins/image-captions/blueprints.yaml | 76 + dev/plugins/image-captions/composer.json | 5 + dev/plugins/image-captions/composer.lock | 71 + .../image-captions/css/image-captions.css | 27 + dev/plugins/image-captions/image-captions.php | 185 + .../image-captions/image-captions.yaml | 7 + .../image-captions/vendor/autoload.php | 7 + .../vendor/composer/ClassLoader.php | 572 + .../vendor/composer/InstalledVersions.php | 350 + .../image-captions/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 10 + .../vendor/composer/autoload_namespaces.php | 9 + .../vendor/composer/autoload_psr4.php | 10 + .../vendor/composer/autoload_real.php | 57 + .../vendor/composer/autoload_static.php | 36 + .../vendor/composer/installed.json | 61 + .../vendor/composer/installed.php | 32 + .../vendor/composer/platform_check.php | 26 + .../vendor/imangazaliev/didom/CHANGELOG.md | 211 + .../vendor/imangazaliev/didom/LICENSE | 19 + .../vendor/imangazaliev/didom/README-RU.md | 833 + .../vendor/imangazaliev/didom/README.md | 675 + .../vendor/imangazaliev/didom/composer.json | 37 + .../vendor/imangazaliev/didom/composer.lock | 1049 + .../didom/src/DiDom/ClassAttribute.php | 267 + .../imangazaliev/didom/src/DiDom/Document.php | 744 + .../didom/src/DiDom/DocumentFragment.php | 34 + .../imangazaliev/didom/src/DiDom/Element.php | 401 + .../imangazaliev/didom/src/DiDom/Encoder.php | 58 + .../imangazaliev/didom/src/DiDom/Errors.php | 46 + .../Exceptions/InvalidSelectorException.php | 10 + .../imangazaliev/didom/src/DiDom/Node.php | 1185 + .../imangazaliev/didom/src/DiDom/Query.php | 567 + .../didom/src/DiDom/StyleAttribute.php | 322 + dev/plugins/langswitcher/CHANGELOG.md | 78 + dev/plugins/langswitcher/LICENSE | 21 + dev/plugins/langswitcher/README.md | 125 + dev/plugins/langswitcher/assets/readme_1.png | Bin 0 -> 38637 bytes dev/plugins/langswitcher/blueprints.yaml | 61 + dev/plugins/langswitcher/composer.json | 29 + dev/plugins/langswitcher/composer.lock | 24 + dev/plugins/langswitcher/css/langswitcher.css | 22 + dev/plugins/langswitcher/langswitcher.php | 113 + dev/plugins/langswitcher/langswitcher.yaml | 4 + dev/plugins/langswitcher/languages.yaml | 33 + .../partials/langswitcher-long.html.twig | 1 + .../partials/langswitcher-short.html.twig | 1 + .../partials/langswitcher.hreflang.html.twig | 9 + .../templates/partials/langswitcher.html.twig | 31 + dev/plugins/langswitcher/vendor/autoload.php | 7 + .../vendor/composer/ClassLoader.php | 445 + .../langswitcher/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 10 + .../vendor/composer/autoload_namespaces.php | 9 + .../vendor/composer/autoload_psr4.php | 9 + .../vendor/composer/autoload_real.php | 52 + .../vendor/composer/autoload_static.php | 20 + .../vendor/composer/installed.json | 1 + dev/plugins/login/CHANGELOG.md | 853 + dev/plugins/login/LICENSE | 21 + dev/plugins/login/README.md | 556 + dev/plugins/login/blueprints.yaml | 462 + dev/plugins/login/classes/Controller.php | 762 + .../login/classes/Events/UserLoginEvent.php | 397 + .../login/classes/Invitations/Invitation.php | 59 + .../login/classes/Invitations/Invitations.php | 165 + dev/plugins/login/classes/Login.php | 937 + dev/plugins/login/classes/LoginCache.php | 105 + dev/plugins/login/classes/RateLimiter.php | 110 + .../login/classes/RememberMe/RememberMe.php | 43 + .../login/classes/RememberMe/TokenStorage.php | 172 + .../classes/TwoFactorAuth/BaconQrProvider.php | 32 + .../classes/TwoFactorAuth/TwoFactorAuth.php | 118 + .../login/cli/ChangePasswordCommand.php | 177 + .../login/cli/ChangeUserStateCommand.php | 157 + dev/plugins/login/cli/LookupUserCommand.php | 94 + dev/plugins/login/cli/NewUserCommand.php | 324 + dev/plugins/login/composer.json | 49 + dev/plugins/login/composer.lock | 247 + dev/plugins/login/css/login.css | 86 + dev/plugins/login/js/2fa.js | 34 + dev/plugins/login/languages/de.yaml | 139 + dev/plugins/login/languages/en.yaml | 161 + dev/plugins/login/languages/es.yaml | 126 + dev/plugins/login/languages/fr.yaml | 97 + dev/plugins/login/languages/hr.yaml | 54 + dev/plugins/login/languages/hu.yaml | 35 + dev/plugins/login/languages/lt.yaml | 154 + dev/plugins/login/languages/no.yaml | 73 + dev/plugins/login/languages/pt-BR.yaml | 136 + dev/plugins/login/languages/ro.yaml | 97 + dev/plugins/login/languages/ru.yaml | 145 + dev/plugins/login/languages/uk.yaml | 145 + dev/plugins/login/languages/zh.yaml | 136 + dev/plugins/login/login.php | 1245 + dev/plugins/login/login.yaml | 63 + dev/plugins/login/templates/forgot.html.twig | 6 + .../fields/2fa_secret/2fa_secret.html.twig | 31 + dev/plugins/login/templates/login.html.twig | 6 + dev/plugins/login/templates/login.json.twig | 5 + .../templates/partials/forgot-form.html.twig | 29 + .../templates/partials/login-form.html.twig | 74 + .../templates/partials/login-status.html.twig | 5 + .../templates/partials/login-twofa.html.twig | 32 + .../templates/partials/reset-form.html.twig | 30 + dev/plugins/login/templates/profile.html.twig | 9 + dev/plugins/login/templates/profile.json.twig | 1 + .../login/templates/register.html.twig | 1 + dev/plugins/login/templates/reset.html.twig | 8 + .../login/templates/unauthorized.html.twig | 1 + dev/plugins/login/vendor/autoload.php | 7 + .../vendor/bacon/bacon-qr-code/CHANGELOG.md | 37 + .../login/vendor/bacon/bacon-qr-code/LICENSE | 22 + .../vendor/bacon/bacon-qr-code/Module.php | 37 + .../vendor/bacon/bacon-qr-code/README.md | 24 + .../bacon/bacon-qr-code/autoload_classmap.php | 43 + .../bacon/bacon-qr-code/autoload_function.php | 12 + .../bacon/bacon-qr-code/autoload_register.php | 2 + .../vendor/bacon/bacon-qr-code/composer.json | 29 + .../src/BaconQrCode/Common/AbstractEnum.php | 115 + .../src/BaconQrCode/Common/BitArray.php | 435 + .../src/BaconQrCode/Common/BitMatrix.php | 350 + .../src/BaconQrCode/Common/BitUtils.php | 51 + .../BaconQrCode/Common/CharacterSetEci.php | 134 + .../src/BaconQrCode/Common/EcBlock.php | 65 + .../src/BaconQrCode/Common/EcBlocks.php | 101 + .../Common/ErrorCorrectionLevel.php | 62 + .../BaconQrCode/Common/FormatInformation.php | 236 + .../src/BaconQrCode/Common/Mode.php | 70 + .../BaconQrCode/Common/ReedSolomonCodec.php | 476 + .../src/BaconQrCode/Common/Version.php | 687 + .../src/BaconQrCode/Encoder/BlockPair.php | 64 + .../src/BaconQrCode/Encoder/ByteMatrix.php | 158 + .../src/BaconQrCode/Encoder/Encoder.php | 687 + .../src/BaconQrCode/Encoder/MaskUtil.php | 291 + .../src/BaconQrCode/Encoder/MatrixUtil.php | 580 + .../src/BaconQrCode/Encoder/QrCode.php | 201 + .../Exception/ExceptionInterface.php | 14 + .../Exception/InvalidArgumentException.php | 14 + .../Exception/OutOfBoundsException.php | 14 + .../Exception/RuntimeException.php | 14 + .../Exception/UnexpectedValueException.php | 14 + .../BaconQrCode/Exception/WriterException.php | 14 + .../src/BaconQrCode/Renderer/Color/Cmyk.php | 160 + .../Renderer/Color/ColorInterface.php | 37 + .../src/BaconQrCode/Renderer/Color/Gray.php | 84 + .../src/BaconQrCode/Renderer/Color/Rgb.php | 148 + .../Renderer/Image/AbstractRenderer.php | 338 + .../Image/Decorator/DecoratorInterface.php | 63 + .../Image/Decorator/FinderPattern.php | 210 + .../src/BaconQrCode/Renderer/Image/Eps.php | 152 + .../src/BaconQrCode/Renderer/Image/Png.php | 115 + .../Renderer/Image/RendererInterface.php | 61 + .../src/BaconQrCode/Renderer/Image/Svg.php | 146 + .../Renderer/RendererInterface.php | 26 + .../src/BaconQrCode/Renderer/Text/Html.php | 91 + .../src/BaconQrCode/Renderer/Text/Plain.php | 150 + .../bacon-qr-code/src/BaconQrCode/Writer.php | 105 + .../bacon-qr-code/src/Common/BitArray.php | 372 + .../bacon-qr-code/src/Common/BitMatrix.php | 313 + .../bacon-qr-code/src/Common/BitUtils.php | 41 + .../src/Common/CharacterSetEci.php | 180 + .../bacon-qr-code/src/Common/EcBlock.php | 49 + .../bacon-qr-code/src/Common/EcBlocks.php | 74 + .../src/Common/ErrorCorrectionLevel.php | 63 + .../src/Common/FormatInformation.php | 203 + .../bacon/bacon-qr-code/src/Common/Mode.php | 76 + .../src/Common/ReedSolomonCodec.php | 468 + .../bacon-qr-code/src/Common/Version.php | 596 + .../bacon-qr-code/src/Encoder/BlockPair.php | 58 + .../bacon-qr-code/src/Encoder/ByteMatrix.php | 150 + .../bacon-qr-code/src/Encoder/Encoder.php | 652 + .../bacon-qr-code/src/Encoder/MaskUtil.php | 271 + .../bacon-qr-code/src/Encoder/MatrixUtil.php | 513 + .../bacon-qr-code/src/Encoder/QrCode.php | 141 + .../src/Exception/ExceptionInterface.php | 10 + .../Exception/InvalidArgumentException.php | 8 + .../src/Exception/OutOfBoundsException.php | 8 + .../src/Exception/RuntimeException.php | 8 + .../Exception/UnexpectedValueException.php | 8 + .../src/Exception/WriterException.php | 8 + .../src/Renderer/Color/Alpha.php | 57 + .../bacon-qr-code/src/Renderer/Color/Cmyk.php | 103 + .../src/Renderer/Color/ColorInterface.php | 22 + .../bacon-qr-code/src/Renderer/Color/Gray.php | 46 + .../bacon-qr-code/src/Renderer/Color/Rgb.php | 88 + .../src/Renderer/Eye/CompositeEye.php | 38 + .../src/Renderer/Eye/EyeInterface.php | 26 + .../src/Renderer/Eye/ModuleEye.php | 54 + .../src/Renderer/Eye/SimpleCircleEye.php | 54 + .../src/Renderer/Eye/SquareEye.php | 53 + .../src/Renderer/Image/EpsImageBackEnd.php | 376 + .../Renderer/Image/ImageBackEndInterface.php | 87 + .../Renderer/Image/ImagickImageBackEnd.php | 339 + .../src/Renderer/Image/SvgImageBackEnd.php | 369 + .../Renderer/Image/TransformationMatrix.php | 67 + .../src/Renderer/ImageRenderer.php | 152 + .../src/Renderer/Module/DotsModule.php | 63 + .../src/Renderer/Module/EdgeIterator/Edge.php | 100 + .../Module/EdgeIterator/EdgeIterator.php | 169 + .../src/Renderer/Module/ModuleInterface.php | 18 + .../src/Renderer/Module/RoundnessModule.php | 129 + .../src/Renderer/Module/SquareModule.php | 47 + .../bacon-qr-code/src/Renderer/Path/Close.php | 29 + .../bacon-qr-code/src/Renderer/Path/Curve.php | 92 + .../src/Renderer/Path/EllipticArc.php | 278 + .../bacon-qr-code/src/Renderer/Path/Line.php | 41 + .../bacon-qr-code/src/Renderer/Path/Move.php | 41 + .../src/Renderer/Path/OperationInterface.php | 12 + .../bacon-qr-code/src/Renderer/Path/Path.php | 106 + .../src/Renderer/PlainTextRenderer.php | 86 + .../src/Renderer/RendererInterface.php | 11 + .../src/Renderer/RendererStyle/EyeFill.php | 74 + .../src/Renderer/RendererStyle/Fill.php | 168 + .../src/Renderer/RendererStyle/Gradient.php | 46 + .../Renderer/RendererStyle/GradientType.php | 22 + .../Renderer/RendererStyle/RendererStyle.php | 90 + .../vendor/bacon/bacon-qr-code/src/Writer.php | 68 + .../tests/BaconQrCode/Common/BitArrayTest.php | 201 + .../BaconQrCode/Common/BitMatrixTest.php | 119 + .../tests/BaconQrCode/Common/BitUtilsTest.php | 30 + .../Common/ErrorCorrectionLevelTest.php | 40 + .../Common/FormatInformationTest.php | 104 + .../tests/BaconQrCode/Common/ModeTest.php | 42 + .../Common/ReedSolomonCodecTest.php | 111 + .../tests/BaconQrCode/Common/VersionTest.php | 88 + .../tests/BaconQrCode/Encoder/EncoderTest.php | 468 + .../BaconQrCode/Encoder/MaskUtilTest.php | 281 + .../BaconQrCode/Encoder/MatrixUtilTest.php | 336 + .../BaconQrCode/Renderer/Text/HtmlTest.php | 99 + .../BaconQrCode/Renderer/Text/TextTest.php | 149 + .../bacon/bacon-qr-code/tests/bootstrap.php | 10 + .../bacon/bacon-qr-code/tests/phpunit.xml | 11 + .../login/vendor/birke/rememberme/LICENSE | 21 + .../login/vendor/birke/rememberme/README.md | 40 + .../vendor/birke/rememberme/composer.json | 24 + .../birke/rememberme/example/action.php | 119 + .../birke/rememberme/example/css/style.css | 157 + .../vendor/birke/rememberme/example/index.php | 42 + .../example/templates/cookie_was_stolen.php | 4 + .../rememberme/example/templates/login.php | 14 + .../example/templates/user_is_logged_in.php | 31 + .../birke/rememberme/example/tokens/.gitkeep | 0 .../login/vendor/birke/rememberme/phpunit.xml | 7 + .../src/Rememberme/Authenticator.php | 293 + .../rememberme/src/Rememberme/Cookie.php | 104 + .../rememberme/src/Rememberme/Storage/DB.php | 145 + .../src/Rememberme/Storage/File.php | 119 + .../rememberme/src/Rememberme/Storage/PDO.php | 121 + .../Rememberme/Storage/StorageInterface.php | 66 + .../birke/rememberme/test/CookieTest.php | 31 + .../birke/rememberme/test/RemembermeTest.php | 352 + .../birke/rememberme/test/Storage/PDO.php | 98 + .../birke/rememberme/test/Storage/tokens.xml | 8 + .../birke/rememberme/test/bootstrap.php | 3 + .../login/vendor/composer/ClassLoader.php | 445 + .../vendor/composer/InstalledVersions.php | 255 + dev/plugins/login/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 11 + .../login/vendor/composer/autoload_files.php | 10 + .../vendor/composer/autoload_namespaces.php | 10 + .../login/vendor/composer/autoload_psr4.php | 13 + .../login/vendor/composer/autoload_real.php | 75 + .../login/vendor/composer/autoload_static.php | 73 + .../login/vendor/composer/installed.json | 227 + .../login/vendor/composer/installed.php | 60 + .../login/vendor/composer/platform_check.php | 26 + .../login/vendor/dasprid/enum/.coveralls.yml | 2 + .../login/vendor/dasprid/enum/README.md | 164 + .../login/vendor/dasprid/enum/composer.json | 30 + .../login/vendor/dasprid/enum/phpcs.xml | 30 + .../vendor/dasprid/enum/phpunit.xml.dist | 17 + .../vendor/dasprid/enum/src/AbstractEnum.php | 241 + .../login/vendor/dasprid/enum/src/EnumMap.php | 375 + .../Exception/CloneNotSupportedException.php | 10 + .../enum/src/Exception/ExceptionInterface.php | 10 + .../src/Exception/ExpectationException.php | 10 + .../Exception/IllegalArgumentException.php | 10 + .../enum/src/Exception/MismatchException.php | 10 + .../SerializeNotSupportedException.php | 10 + .../UnserializeNotSupportedException.php | 10 + .../vendor/dasprid/enum/src/NullValue.php | 55 + .../dasprid/enum/test/AbstractEnumTest.php | 121 + .../vendor/dasprid/enum/test/EnumMapTest.php | 243 + .../dasprid/enum/test/NullValueTest.php | 31 + .../login/vendor/dasprid/enum/test/Planet.php | 73 + .../vendor/dasprid/enum/test/WeekDay.php | 26 + .../paragonie/random_compat/CHANGELOG.md | 290 + .../vendor/paragonie/random_compat/LICENSE | 22 + .../paragonie/random_compat/RATIONALE.md | 42 + .../vendor/paragonie/random_compat/README.md | 176 + .../paragonie/random_compat/SECURITY.md | 108 + .../paragonie/random_compat/build-phar.sh | 5 + .../paragonie/random_compat/composer.json | 35 + .../dist/random_compat.phar.pubkey | 5 + .../dist/random_compat.phar.pubkey.asc | 11 + .../random_compat/lib/byte_safe_strings.php | 181 + .../random_compat/lib/cast_to_int.php | 74 + .../random_compat/lib/error_polyfill.php | 49 + .../paragonie/random_compat/lib/random.php | 247 + .../lib/random_bytes_com_dotnet.php | 88 + .../lib/random_bytes_dev_urandom.php | 150 + .../lib/random_bytes_libsodium.php | 88 + .../lib/random_bytes_libsodium_legacy.php | 92 + .../random_compat/lib/random_bytes_mcrypt.php | 77 + .../lib/random_bytes_openssl.php | 86 + .../random_compat/lib/random_int.php | 190 + .../random_compat/other/build_phar.php | 57 + .../random_compat/other/ide_stubs/COM.php | 20 + .../random_compat/other/ide_stubs/README.md | 7 + .../other/ide_stubs/com_exception.php | 11 + .../other/ide_stubs/libsodium.php | 90 + .../random_compat/psalm-autoload.php | 9 + .../vendor/paragonie/random_compat/psalm.xml | 15 + .../twofactorauth/.github/FUNDING.yml | 4 + .../vendor/robthree/twofactorauth/LICENSE | 22 + .../vendor/robthree/twofactorauth/README.md | 209 + .../twofactorauth/TwoFactorAuth.phpproj | 70 + .../robthree/twofactorauth/TwoFactorAuth.sln | 22 + .../robthree/twofactorauth/composer.json | 49 + .../robthree/twofactorauth/demo/demo.php | 35 + .../robthree/twofactorauth/demo/loader.php | 50 + .../lib/Providers/Qr/BaconQrCodeProvider.php | 152 + .../Providers/Qr/BaseHTTPQRCodeProvider.php | 33 + .../Providers/Qr/EndroidQrCodeProvider.php | 70 + .../Qr/EndroidQrCodeWithLogoProvider.php | 35 + .../lib/Providers/Qr/IQRCodeProvider.php | 24 + .../Qr/ImageChartsQRCodeProvider.php | 60 + .../lib/Providers/Qr/QRException.php | 7 + .../lib/Providers/Qr/QRServerProvider.php | 108 + .../lib/Providers/Qr/QRicketProvider.php | 76 + .../lib/Providers/Rng/CSRNGProvider.php | 22 + .../lib/Providers/Rng/HashRNGProvider.php | 43 + .../lib/Providers/Rng/IRNGProvider.php | 18 + .../lib/Providers/Rng/MCryptRNGProvider.php | 37 + .../lib/Providers/Rng/OpenSSLRNGProvider.php | 40 + .../lib/Providers/Rng/RNGException.php | 7 + .../lib/Providers/Time/HttpTimeProvider.php | 71 + .../lib/Providers/Time/ITimeProvider.php | 11 + .../Time/LocalMachineTimeProvider.php | 11 + .../lib/Providers/Time/NTPTimeProvider.php | 70 + .../lib/Providers/Time/TimeException.php | 7 + .../twofactorauth/lib/TwoFactorAuth.php | 360 + .../lib/TwoFactorAuthException.php | 7 + .../vendor/robthree/twofactorauth/logo.png | Bin 0 -> 2636 bytes .../multifactorauthforeveryone.png | Bin 0 -> 20735 bytes .../vendor/robthree/twofactorauth/phpunit.xml | 26 + .../tests/MightNotMakeAssertions.php | 26 + .../Providers/Qr/IQRCodeProviderTest.php | 56 + .../tests/Providers/Qr/TestQrProvider.php | 24 + .../tests/Providers/Rng/CSRNGProviderTest.php | 30 + .../Providers/Rng/HashRNGProviderTest.php | 24 + .../tests/Providers/Rng/IRNGProviderTest.php | 61 + .../Providers/Rng/MCryptRNGProviderTest.php | 32 + .../tests/Providers/Rng/NeedsRngLengths.php | 9 + .../Providers/Rng/OpenSSLRNGProviderTest.php | 37 + .../tests/Providers/Rng/TestRNGProvider.php | 41 + .../Providers/Time/ITimeProviderTest.php | 53 + .../tests/Providers/Time/TestTimeProvider.php | 27 + .../twofactorauth/tests/TwoFactorAuthTest.php | 246 + dev/plugins/markdown-notices/CHANGELOG.md | 38 + dev/plugins/markdown-notices/LICENSE | 21 + dev/plugins/markdown-notices/README.md | 62 + .../markdown-notices/assets/notices.css | 32 + .../markdown-notices/assets/screenshot.png | Bin 0 -> 86632 bytes dev/plugins/markdown-notices/blueprints.yaml | 59 + dev/plugins/markdown-notices/composer.json | 27 + dev/plugins/markdown-notices/composer.lock | 22 + dev/plugins/markdown-notices/languages.yaml | 29 + .../markdown-notices/markdown-notices.php | 92 + .../markdown-notices/markdown-notices.yaml | 4 + .../markdown-notices/vendor/autoload.php | 7 + .../vendor/composer/ClassLoader.php | 445 + .../markdown-notices/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 10 + .../vendor/composer/autoload_namespaces.php | 9 + .../vendor/composer/autoload_psr4.php | 9 + .../vendor/composer/autoload_real.php | 52 + .../vendor/composer/autoload_static.php | 20 + .../vendor/composer/installed.json | 1 + dev/plugins/presentation-deckset/CHANGELOG.md | 105 + dev/plugins/presentation-deckset/LICENSE | 21 + dev/plugins/presentation-deckset/README.md | 126 + .../presentation-deckset/blueprints.yaml | 29 + .../classes/DecksetParser.php | 401 + .../presentation-deckset/languages.yaml | 4 + .../presentation-deckset.php | 61 + .../presentation-deckset.yaml | 1 + dev/plugins/presentation/ADVANCED.md | 78 + dev/plugins/presentation/CHANGELOG.md | 649 + dev/plugins/presentation/CONTRIBUTING.md | 62 + dev/plugins/presentation/LICENSE | 21 + dev/plugins/presentation/README.md | 350 + dev/plugins/presentation/blueprints.yaml | 417 + .../presentation/blueprints/presentation.yaml | 248 + .../presentation/blueprints/slide.yaml | 140 + dev/plugins/presentation/classes/Content.php | 380 + .../presentation/classes/ContentInterface.php | 98 + dev/plugins/presentation/classes/Parser.php | 342 + .../presentation/classes/ParserInterface.php | 108 + dev/plugins/presentation/classes/Poll.php | 121 + .../presentation/classes/PollInterface.php | 58 + .../presentation/classes/Transport.php | 288 + .../classes/TransportInterface.php | 103 + .../presentation/classes/Utilities.php | 223 + dev/plugins/presentation/composer.json | 40 + dev/plugins/presentation/composer.lock | 242 + dev/plugins/presentation/css/paper.css | 3 + dev/plugins/presentation/css/presentation.css | 3 + dev/plugins/presentation/css/transition.css | 183 + dev/plugins/presentation/js/broadcast.js | 28 + dev/plugins/presentation/js/modular-scale.js | 101 + .../presentation/js/modular-scale.package.js | 91 + dev/plugins/presentation/js/poll.js | 115 + dev/plugins/presentation/js/presentation.js | 129 + dev/plugins/presentation/js/save.js | 130 + dev/plugins/presentation/languages.yaml | 222 + .../node_modules/axios/dist/axios.js | 1533 + .../node_modules/axios/dist/axios.min.js | 9 + .../node_modules/codemirror/lib/codemirror.js | 9732 +++++++ .../node_modules/js-base64/base64.min.js | 1 + .../node_modules/reveal.js/Gruntfile.js | 192 + .../reveal.js/css/print/paper.css | 203 + .../node_modules/reveal.js/css/print/pdf.css | 164 + .../node_modules/reveal.js/css/reveal.css | 1598 ++ .../reveal.js/css/theme/beige.css | 277 + .../reveal.js/css/theme/black.css | 273 + .../reveal.js/css/theme/blood.css | 296 + .../reveal.js/css/theme/league.css | 279 + .../node_modules/reveal.js/css/theme/moon.css | 277 + .../reveal.js/css/theme/night.css | 271 + .../reveal.js/css/theme/serif.css | 273 + .../reveal.js/css/theme/simple.css | 276 + .../node_modules/reveal.js/css/theme/sky.css | 280 + .../reveal.js/css/theme/solarized.css | 277 + .../reveal.js/css/theme/white.css | 273 + .../node_modules/reveal.js/js/reveal.js | 6028 ++++ .../reveal.js/lib/font/league-gothic/LICENSE | 2 + .../lib/font/league-gothic/league-gothic.css | 10 + .../lib/font/league-gothic/league-gothic.eot | Bin 0 -> 25696 bytes .../lib/font/league-gothic/league-gothic.ttf | Bin 0 -> 64256 bytes .../lib/font/league-gothic/league-gothic.woff | Bin 0 -> 30764 bytes .../lib/font/source-sans-pro/LICENSE | 45 + .../source-sans-pro-italic.eot | Bin 0 -> 75720 bytes .../source-sans-pro-italic.ttf | Bin 0 -> 238084 bytes .../source-sans-pro-italic.woff | Bin 0 -> 98556 bytes .../source-sans-pro-regular.eot | Bin 0 -> 88070 bytes .../source-sans-pro-regular.ttf | Bin 0 -> 288008 bytes .../source-sans-pro-regular.woff | Bin 0 -> 114324 bytes .../source-sans-pro-semibold.eot | Bin 0 -> 89897 bytes .../source-sans-pro-semibold.ttf | Bin 0 -> 284640 bytes .../source-sans-pro-semibold.woff | Bin 0 -> 115648 bytes .../source-sans-pro-semibolditalic.eot | Bin 0 -> 75706 bytes .../source-sans-pro-semibolditalic.ttf | Bin 0 -> 240944 bytes .../source-sans-pro-semibolditalic.woff | Bin 0 -> 98816 bytes .../font/source-sans-pro/source-sans-pro.css | 39 + .../reveal.js/lib/js/html5shiv.js | 7 + .../reveal.js/plugin/highlight/highlight.js | 168 + .../reveal.js/plugin/markdown/markdown.js | 446 + .../reveal.js/plugin/markdown/marked.js | 6 + .../reveal.js/plugin/math/math.js | 92 + .../reveal.js/plugin/multiplex/client.js | 13 + .../reveal.js/plugin/multiplex/index.js | 64 + .../reveal.js/plugin/multiplex/master.js | 34 + .../reveal.js/plugin/notes-server/client.js | 65 + .../reveal.js/plugin/notes-server/index.js | 69 + .../reveal.js/plugin/notes/notes.js | 178 + .../reveal.js/plugin/print-pdf/print-pdf.js | 67 + .../reveal.js/plugin/search/search.js | 206 + .../reveal.js/plugin/zoom-js/zoom.js | 277 + .../reveal.js/test/qunit-2.5.0.js | 5188 ++++ .../test/test-markdown-element-attributes.js | 44 + .../reveal.js/test/test-markdown-external.js | 20 + .../reveal.js/test/test-markdown-options.js | 27 + .../test/test-markdown-slide-attributes.js | 44 + .../reveal.js/test/test-markdown.js | 11 + .../node_modules/reveal.js/test/test-pdf.js | 12 + .../node_modules/reveal.js/test/test.js | 598 + dev/plugins/presentation/package-lock.json | 69 + dev/plugins/presentation/package.json | 22 + dev/plugins/presentation/pnpm-lock.yaml | 12 + dev/plugins/presentation/presentation.php | 596 + dev/plugins/presentation/presentation.yaml | 49 + dev/plugins/presentation/scss/_normalize.scss | 349 + dev/plugins/presentation/scss/paper.scss | 180 + .../presentation/scss/presentation.scss | 411 + .../shortcodes/LinkOverlayShortcode.php | 72 + .../shortcodes/PresentationShortcode.php | 65 + .../presentation_button_bar.html.twig | 30 + .../presentation_dropdown.html.twig | 47 + .../partials/presentation_footer.html.twig | 0 .../partials/presentation_iframe.html.twig | 1 + .../presentation_link_overlay.html.twig | 1 + .../templates/presentation.html.twig | 185 + .../presentation/templates/slide.html.twig | 1 + .../presentation/twig/CallStaticExtension.php | 21 + .../presentation/twig/FileFinderExtension.php | 44 + dev/plugins/presentation/vendor/autoload.php | 7 + .../vendor/composer/ClassLoader.php | 445 + .../presentation/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 9 + .../vendor/composer/autoload_namespaces.php | 10 + .../vendor/composer/autoload_psr4.php | 13 + .../vendor/composer/autoload_real.php | 52 + .../vendor/composer/autoload_static.php | 63 + .../vendor/composer/installed.json | 230 + .../vendor/composer/installers/LICENSE | 19 + .../vendor/composer/installers/composer.json | 105 + .../src/Composer/Installers/AglInstaller.php | 21 + .../Composer/Installers/AimeosInstaller.php | 9 + .../Installers/AnnotateCmsInstaller.php | 11 + .../Composer/Installers/AsgardInstaller.php | 49 + .../Composer/Installers/AttogramInstaller.php | 9 + .../src/Composer/Installers/BaseInstaller.php | 136 + .../Composer/Installers/BitrixInstaller.php | 126 + .../Composer/Installers/BonefishInstaller.php | 9 + .../Composer/Installers/CakePHPInstaller.php | 82 + .../src/Composer/Installers/ChefInstaller.php | 11 + .../Composer/Installers/CiviCrmInstaller.php | 9 + .../Installers/ClanCatsFrameworkInstaller.php | 10 + .../Composer/Installers/CockpitInstaller.php | 34 + .../Installers/CodeIgniterInstaller.php | 11 + .../Installers/Concrete5Installer.php | 13 + .../Composer/Installers/CraftInstaller.php | 35 + .../Composer/Installers/CroogoInstaller.php | 21 + .../Composer/Installers/DecibelInstaller.php | 10 + .../Composer/Installers/DokuWikiInstaller.php | 50 + .../Composer/Installers/DolibarrInstaller.php | 16 + .../Composer/Installers/DrupalInstaller.php | 16 + .../src/Composer/Installers/ElggInstaller.php | 9 + .../Composer/Installers/EliasisInstaller.php | 12 + .../Installers/ExpressionEngineInstaller.php | 29 + .../Installers/EzPlatformInstaller.php | 10 + .../src/Composer/Installers/FuelInstaller.php | 11 + .../Composer/Installers/FuelphpInstaller.php | 9 + .../src/Composer/Installers/GravInstaller.php | 30 + .../Composer/Installers/HuradInstaller.php | 25 + .../Composer/Installers/ImageCMSInstaller.php | 11 + .../src/Composer/Installers/Installer.php | 274 + .../src/Composer/Installers/ItopInstaller.php | 9 + .../Composer/Installers/JoomlaInstaller.php | 15 + .../Composer/Installers/KanboardInstaller.php | 18 + .../Composer/Installers/KirbyInstaller.php | 11 + .../Composer/Installers/KodiCMSInstaller.php | 10 + .../Composer/Installers/KohanaInstaller.php | 9 + .../LanManagementSystemInstaller.php | 27 + .../Composer/Installers/LaravelInstaller.php | 9 + .../Composer/Installers/LavaLiteInstaller.php | 10 + .../Composer/Installers/LithiumInstaller.php | 10 + .../Installers/MODULEWorkInstaller.php | 9 + .../Composer/Installers/MODXEvoInstaller.php | 16 + .../Composer/Installers/MagentoInstaller.php | 11 + .../Composer/Installers/MajimaInstaller.php | 37 + .../src/Composer/Installers/MakoInstaller.php | 9 + .../Composer/Installers/MauticInstaller.php | 25 + .../src/Composer/Installers/MayaInstaller.php | 33 + .../Installers/MediaWikiInstaller.php | 51 + .../Installers/MicroweberInstaller.php | 111 + .../src/Composer/Installers/ModxInstaller.php | 12 + .../Composer/Installers/MoodleInstaller.php | 57 + .../Composer/Installers/OctoberInstaller.php | 47 + .../Composer/Installers/OntoWikiInstaller.php | 24 + .../Composer/Installers/OsclassInstaller.php | 14 + .../src/Composer/Installers/OxidInstaller.php | 59 + .../src/Composer/Installers/PPIInstaller.php | 9 + .../Composer/Installers/PhiftyInstaller.php | 11 + .../Composer/Installers/PhpBBInstaller.php | 11 + .../Composer/Installers/PimcoreInstaller.php | 21 + .../Composer/Installers/PiwikInstaller.php | 32 + .../Installers/PlentymarketsInstaller.php | 29 + .../src/Composer/Installers/Plugin.php | 17 + .../Composer/Installers/PortoInstaller.php | 9 + .../Installers/PrestashopInstaller.php | 10 + .../Composer/Installers/PuppetInstaller.php | 11 + .../Composer/Installers/PxcmsInstaller.php | 63 + .../Composer/Installers/RadPHPInstaller.php | 24 + .../Composer/Installers/ReIndexInstaller.php | 10 + .../Composer/Installers/RedaxoInstaller.php | 10 + .../Installers/RoundcubeInstaller.php | 22 + .../src/Composer/Installers/SMFInstaller.php | 10 + .../Composer/Installers/ShopwareInstaller.php | 60 + .../Installers/SilverStripeInstaller.php | 35 + .../Installers/SiteDirectInstaller.php | 25 + .../Composer/Installers/SyDESInstaller.php | 49 + .../Composer/Installers/Symfony1Installer.php | 26 + .../Composer/Installers/TYPO3CmsInstaller.php | 16 + .../Installers/TYPO3FlowInstaller.php | 38 + .../Composer/Installers/TheliaInstaller.php | 12 + .../src/Composer/Installers/TuskInstaller.php | 14 + .../Installers/UserFrostingInstaller.php | 9 + .../Composer/Installers/VanillaInstaller.php | 10 + .../Composer/Installers/VgmcpInstaller.php | 49 + .../Composer/Installers/WHMCSInstaller.php | 10 + .../Composer/Installers/WolfCMSInstaller.php | 9 + .../Installers/WordPressInstaller.php | 12 + .../Composer/Installers/YawikInstaller.php | 32 + .../src/Composer/Installers/ZendInstaller.php | 11 + .../Composer/Installers/ZikulaInstaller.php | 10 + .../composer/installers/src/bootstrap.php | 13 + .../vendor/michelf/php-smartypants/License.md | 36 + .../Michelf/SmartyPants.inc.php | 9 + .../php-smartypants/Michelf/SmartyPants.php | 560 + .../Michelf/SmartyPantsTypographer.inc.php | 10 + .../Michelf/SmartyPantsTypographer.php | 486 + .../vendor/michelf/php-smartypants/Readme.md | 246 + .../vendor/michelf/php-smartypants/Readme.php | 36 + .../michelf/php-smartypants/composer.json | 26 + .../vendor/thunderer/shortcode/CHANGELOG.md | 139 + .../vendor/thunderer/shortcode/LICENSE | 19 + .../vendor/thunderer/shortcode/Makefile | 13 + .../vendor/thunderer/shortcode/README.md | 398 + .../vendor/thunderer/shortcode/composer.json | 34 + .../thunderer/shortcode/docker-compose.yaml | 19 + .../shortcode/docker/php-5.4/Dockerfile | 3 + .../thunderer/shortcode/phpunit.xml.dist | 30 + .../src/Event/FilterShortcodesEvent.php | 50 + .../src/Event/ReplaceShortcodesEvent.php | 71 + .../src/EventContainer/EventContainer.php | 39 + .../EventContainerInterface.php | 15 + .../EventHandler/FilterRawEventHandler.php | 34 + .../EventHandler/ReplaceJoinEventHandler.php | 36 + .../vendor/thunderer/shortcode/src/Events.php | 16 + .../shortcode/src/Handler/ContentHandler.php | 22 + .../shortcode/src/Handler/DeclareHandler.php | 47 + .../shortcode/src/Handler/EmailHandler.php | 27 + .../shortcode/src/Handler/NameHandler.php | 23 + .../shortcode/src/Handler/NullHandler.php | 22 + .../src/Handler/PlaceholderHandler.php | 34 + .../shortcode/src/Handler/RawHandler.php | 26 + .../src/Handler/SerializerHandler.php | 38 + .../shortcode/src/Handler/UrlHandler.php | 26 + .../shortcode/src/Handler/WrapHandler.php | 37 + .../src/HandlerContainer/HandlerContainer.php | 79 + .../HandlerContainerInterface.php | 18 + .../ImmutableHandlerContainer.php | 20 + .../shortcode/src/Parser/ParserInterface.php | 19 + .../shortcode/src/Parser/RegexParser.php | 93 + .../shortcode/src/Parser/RegularParser.php | 339 + .../shortcode/src/Parser/WordpressParser.php | 115 + .../shortcode/src/Processor/Processor.php | 243 + .../src/Processor/ProcessorContext.php | 29 + .../src/Processor/ProcessorInterface.php | 17 + .../src/Serializer/JsonSerializer.php | 49 + .../src/Serializer/SerializerInterface.php | 28 + .../src/Serializer/TextSerializer.php | 89 + .../src/Serializer/XmlSerializer.php | 117 + .../src/Serializer/YamlSerializer.php | 50 + .../src/Shortcode/AbstractShortcode.php | 60 + .../src/Shortcode/ParsedShortcode.php | 39 + .../Shortcode/ParsedShortcodeInterface.php | 22 + .../src/Shortcode/ProcessedShortcode.php | 135 + .../src/Shortcode/ReplacedShortcode.php | 39 + .../shortcode/src/Shortcode/Shortcode.php | 30 + .../src/Shortcode/ShortcodeInterface.php | 59 + .../shortcode/src/ShortcodeFacade.php | 150 + .../shortcode/src/Syntax/CommonSyntax.php | 33 + .../thunderer/shortcode/src/Syntax/Syntax.php | 53 + .../shortcode/src/Syntax/SyntaxBuilder.php | 64 + .../shortcode/src/Syntax/SyntaxInterface.php | 18 + .../src/Utility/RegexBuilderUtility.php | 85 + .../shortcode/tests/AbstractTestCase.php | 17 + .../thunderer/shortcode/tests/EventsTest.php | 97 + .../thunderer/shortcode/tests/FacadeTest.php | 98 + .../shortcode/tests/Fake/ReverseShortcode.php | 12 + .../shortcode/tests/HandlerContainerTest.php | 100 + .../thunderer/shortcode/tests/ParserTest.php | 321 + .../shortcode/tests/ProcessorTest.php | 367 + .../shortcode/tests/SerializerTest.php | 124 + .../shortcode/tests/ShortcodeTest.php | 137 + .../thunderer/shortcode/tests/SyntaxTest.php | 54 + dev/plugins/problems/CHANGELOG.md | 164 + dev/plugins/problems/LICENSE | 21 + dev/plugins/problems/README.md | 92 + dev/plugins/problems/assets/cli.png | Bin 0 -> 401907 bytes dev/plugins/problems/assets/code-3.svg | 11 + dev/plugins/problems/assets/grav-logo.svg | 1 + dev/plugins/problems/assets/heart.svg | 5 + dev/plugins/problems/assets/readme_1.jpg | Bin 0 -> 368222 bytes dev/plugins/problems/blueprints.yaml | 43 + .../problems/classes/Problems/Apache.php | 61 + .../classes/Problems/Base/Problem.php | 141 + .../classes/Problems/Base/ProblemChecker.php | 159 + .../classes/Problems/EssentialFolders.php | 78 + .../problems/classes/Problems/PHPModules.php | 148 + .../problems/classes/Problems/PHPVersion.php | 43 + .../problems/classes/Problems/Permissions.php | 42 + dev/plugins/problems/cli/CheckCommand.php | 107 + dev/plugins/problems/composer.json | 32 + dev/plugins/problems/composer.lock | 20 + dev/plugins/problems/css/admin.css | 31 + dev/plugins/problems/css/admin.min.css | 1 + dev/plugins/problems/css/spectre-icons.css | 168 + .../problems/css/spectre-icons.min.css | 1 + dev/plugins/problems/css/spectre.css | 1276 + dev/plugins/problems/css/spectre.min.css | 1 + dev/plugins/problems/gulpfile.js | 39 + dev/plugins/problems/languages.yaml | 14 + dev/plugins/problems/package.json | 45 + dev/plugins/problems/problems.php | 185 + dev/plugins/problems/problems.yaml | 2 + dev/plugins/problems/scss/_accordions.scss | 38 + dev/plugins/problems/scss/_animations.scss | 20 + dev/plugins/problems/scss/_asian.scss | 38 + dev/plugins/problems/scss/_autocomplete.scss | 47 + dev/plugins/problems/scss/_avatars.scss | 77 + dev/plugins/problems/scss/_badges.scss | 60 + dev/plugins/problems/scss/_bars.scss | 71 + dev/plugins/problems/scss/_base.scss | 44 + dev/plugins/problems/scss/_breadcrumbs.scss | 29 + dev/plugins/problems/scss/_buttons.scss | 195 + dev/plugins/problems/scss/_calendars.scss | 222 + dev/plugins/problems/scss/_cards.scss | 43 + dev/plugins/problems/scss/_carousels.scss | 126 + dev/plugins/problems/scss/_chips.scss | 30 + dev/plugins/problems/scss/_codes.scss | 31 + .../problems/scss/_comparison-sliders.scss | 115 + dev/plugins/problems/scss/_dropdowns.scss | 36 + dev/plugins/problems/scss/_empty.scss | 21 + dev/plugins/problems/scss/_filters.scss | 37 + dev/plugins/problems/scss/_forms.scss | 545 + dev/plugins/problems/scss/_icons.scss | 5 + dev/plugins/problems/scss/_labels.scss | 34 + dev/plugins/problems/scss/_layout.scss | 424 + dev/plugins/problems/scss/_media.scss | 75 + dev/plugins/problems/scss/_menus.scss | 62 + dev/plugins/problems/scss/_meters.scss | 57 + dev/plugins/problems/scss/_mixins.scss | 11 + dev/plugins/problems/scss/_modals.scss | 87 + dev/plugins/problems/scss/_navbar.scss | 29 + dev/plugins/problems/scss/_navs.scss | 34 + dev/plugins/problems/scss/_normalize.scss | 446 + dev/plugins/problems/scss/_off-canvas.scss | 95 + dev/plugins/problems/scss/_pagination.scss | 61 + dev/plugins/problems/scss/_panels.scss | 23 + dev/plugins/problems/scss/_parallax.scss | 135 + dev/plugins/problems/scss/_popovers.scss | 65 + dev/plugins/problems/scss/_preset.scss | 90 + dev/plugins/problems/scss/_problems.scss | 72 + dev/plugins/problems/scss/_progress.scss | 45 + dev/plugins/problems/scss/_sliders.scss | 99 + dev/plugins/problems/scss/_steps.scss | 70 + dev/plugins/problems/scss/_tables.scss | 57 + dev/plugins/problems/scss/_tabs.scss | 66 + dev/plugins/problems/scss/_tiles.scss | 38 + dev/plugins/problems/scss/_timelines.scss | 54 + dev/plugins/problems/scss/_toasts.scss | 42 + dev/plugins/problems/scss/_tooltips.scss | 79 + dev/plugins/problems/scss/_typography.scss | 128 + dev/plugins/problems/scss/_utilities.scss | 8 + dev/plugins/problems/scss/_variables.scss | 116 + dev/plugins/problems/scss/admin.scss | 92 + .../problems/scss/icons/_icons-action.scss | 316 + .../problems/scss/icons/_icons-core.scss | 53 + .../scss/icons/_icons-navigation.scss | 133 + .../problems/scss/icons/_icons-object.scss | 176 + dev/plugins/problems/scss/mixins/_avatar.scss | 6 + dev/plugins/problems/scss/mixins/_button.scss | 54 + .../problems/scss/mixins/_clearfix.scss | 8 + dev/plugins/problems/scss/mixins/_color.scss | 27 + dev/plugins/problems/scss/mixins/_label.scss | 11 + .../problems/scss/mixins/_position.scss | 65 + dev/plugins/problems/scss/mixins/_shadow.scss | 9 + dev/plugins/problems/scss/mixins/_text.scss | 6 + dev/plugins/problems/scss/mixins/_toast.scss | 5 + .../problems/scss/mixins/_transition.scss | 4 + dev/plugins/problems/scss/spectre-icons.scss | 10 + dev/plugins/problems/scss/spectre.scss | 51 + .../problems/scss/utilities/_colors.scss | 31 + .../problems/scss/utilities/_cursors.scss | 24 + .../problems/scss/utilities/_display.scss | 44 + .../problems/scss/utilities/_divider.scss | 50 + .../problems/scss/utilities/_loading.scss | 34 + .../problems/scss/utilities/_position.scss | 50 + .../problems/scss/utilities/_shapes.scss | 8 + .../problems/scss/utilities/_text.scss | 64 + .../problems/templates/problems.html.twig | 34 + .../reports/problems-report.html.twig | 33 + dev/plugins/problems/vendor/autoload.php | 7 + .../problems/vendor/composer/ClassLoader.php | 445 + .../vendor/composer/InstalledVersions.php | 219 + dev/plugins/problems/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 11 + .../vendor/composer/autoload_namespaces.php | 9 + .../vendor/composer/autoload_psr4.php | 11 + .../vendor/composer/autoload_real.php | 55 + .../vendor/composer/autoload_static.php | 42 + .../problems/vendor/composer/installed.json | 5 + .../problems/vendor/composer/installed.php | 24 + dev/plugins/shortcode-core/CHANGELOG.md | 399 + dev/plugins/shortcode-core/LICENSE | 21 + dev/plugins/shortcode-core/README.md | 567 + .../assets/shortcode-core-1.png | Bin 0 -> 15822 bytes dev/plugins/shortcode-core/blueprints.yaml | 127 + .../shortcode-core/classes/Shortcode.php | 7 + .../classes/ShortcodeManager.php | 15 + .../classes/ShortcodeObject.php | 7 + .../classes/plugin/Shortcode.php | 24 + .../classes/plugin/ShortcodeManager.php | 383 + .../classes/plugin/ShortcodeObject.php | 33 + .../classes/plugin/ShortcodeTwigVar.php | 27 + .../classes/shortcodes/AlignShortcode.php | 26 + .../classes/shortcodes/ColorShortcode.php | 16 + .../classes/shortcodes/ColumnsShortcode.php | 27 + .../classes/shortcodes/DetailsShortcode.php | 26 + .../classes/shortcodes/DivShortcode.php | 22 + .../classes/shortcodes/FigureShortcode.php | 27 + .../shortcodes/FontAwesomeShortcode.php | 53 + .../classes/shortcodes/HShortcode.php | 48 + .../classes/shortcodes/LanguageShortcode.php | 31 + .../classes/shortcodes/LoremShortcode.php | 360 + .../classes/shortcodes/MarkShortcode.php | 27 + .../classes/shortcodes/NoticeShortcode.php | 24 + .../classes/shortcodes/RawShortcode.php | 18 + .../classes/shortcodes/SafeEmailShortcode.php | 51 + .../classes/shortcodes/SectionShortcode.php | 17 + .../classes/shortcodes/Shortcode.php | 91 + .../classes/shortcodes/ShortcodeObject.php | 24 + .../classes/shortcodes/SizeShortcode.php | 19 + .../classes/shortcodes/SpanShortcode.php | 22 + .../classes/shortcodes/UnderlineShortcode.php | 14 + dev/plugins/shortcode-core/composer.json | 32 + dev/plugins/shortcode-core/composer.lock | 80 + .../shortcode-core/css/shortcode-notice.css | 64 + .../shortcode-core/nextgen-editor/README.md | 24 + .../nextgen-editor/babel.config.js | 5 + .../nextgen-editor/dist/css/app.css | 1 + .../nextgen-editor/dist/js/app.js | 2 + .../nextgen-editor/dist/js/app.js.map | 1 + .../nextgen-editor/package.json | 24 + .../nextgen-editor/shortcodes/align/align.js | 55 + .../nextgen-editor/shortcodes/color/color.js | 22 + .../shortcodes/columns/columns.js | 58 + .../shortcodes/details/details.css | 8 + .../shortcodes/details/details.js | 50 + .../nextgen-editor/shortcodes/div/div.js | 47 + .../shortcodes/figure/figure.js | 46 + .../shortcodes/fontawesome/fontawesome.js | 50 + .../shortcodes/headers/headers.css | 32 + .../shortcodes/headers/headers.js | 47 + .../shortcodes/language/language.js | 25 + .../nextgen-editor/shortcodes/lorem/lorem.js | 80 + .../nextgen-editor/shortcodes/mark/mark.css | 7 + .../nextgen-editor/shortcodes/mark/mark.js | 49 + .../shortcodes/notice/notice.css | 63 + .../shortcodes/notice/notice.js | 41 + .../nextgen-editor/shortcodes/raw/raw.js | 13 + .../shortcodes/safe-email/safe-email.js | 48 + .../shortcodes/section/section.js | 26 + .../shortcodes/shortcode-core.js | 10 + .../nextgen-editor/shortcodes/size/size.js | 26 + .../nextgen-editor/shortcodes/span/span.js | 37 + .../nextgen-editor/shortcodes/u/u.js | 13 + .../nextgen-editor/src/collapse.js | 30 + .../nextgen-editor/src/command.js | 153 + .../nextgen-editor/src/converters.js | 150 + .../nextgen-editor/src/events.js | 86 + .../shortcode-core/nextgen-editor/src/init.js | 45 + .../nextgen-editor/src/main.css | 278 + .../shortcode-core/nextgen-editor/src/main.js | 10 + .../nextgen-editor/src/postsave.js | 95 + .../nextgen-editor/src/prerender.js | 100 + .../nextgen-editor/src/remove.js | 55 + .../nextgen-editor/src/render.js | 95 + .../shortcode-core/nextgen-editor/src/save.js | 80 + .../nextgen-editor/src/settings.js | 153 + .../nextgen-editor/src/uncollapse.js | 164 + .../nextgen-editor/vue.config.js | 31 + .../shortcode-core/nextgen-editor/yarn.lock | 9534 +++++++ dev/plugins/shortcode-core/shortcode-core.php | 293 + .../shortcode-core/shortcode-core.yaml | 17 + .../templates/shortcodes/notice.html.twig | 3 + .../shortcode-core/vendor/autoload.php | 7 + .../vendor/composer/ClassLoader.php | 572 + .../vendor/composer/InstalledVersions.php | 350 + .../shortcode-core/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 11 + .../vendor/composer/autoload_namespaces.php | 9 + .../vendor/composer/autoload_psr4.php | 12 + .../vendor/composer/autoload_real.php | 57 + .../vendor/composer/autoload_static.php | 50 + .../vendor/composer/installed.json | 65 + .../vendor/composer/installed.php | 32 + .../vendor/composer/platform_check.php | 26 + .../vendor/thunderer/shortcode/CHANGELOG.md | 139 + .../vendor/thunderer/shortcode/LICENSE | 19 + .../vendor/thunderer/shortcode/Makefile | 13 + .../vendor/thunderer/shortcode/README.md | 398 + .../vendor/thunderer/shortcode/composer.json | 34 + .../thunderer/shortcode/docker-compose.yaml | 20 + .../shortcode/docker/php-5.4/Dockerfile | 3 + .../thunderer/shortcode/phpunit.xml.dist | 30 + .../src/Event/FilterShortcodesEvent.php | 50 + .../src/Event/ReplaceShortcodesEvent.php | 71 + .../src/EventContainer/EventContainer.php | 39 + .../EventContainerInterface.php | 15 + .../EventHandler/FilterRawEventHandler.php | 34 + .../EventHandler/ReplaceJoinEventHandler.php | 36 + .../vendor/thunderer/shortcode/src/Events.php | 16 + .../shortcode/src/Handler/ContentHandler.php | 22 + .../shortcode/src/Handler/DeclareHandler.php | 47 + .../shortcode/src/Handler/EmailHandler.php | 27 + .../shortcode/src/Handler/NameHandler.php | 23 + .../shortcode/src/Handler/NullHandler.php | 22 + .../src/Handler/PlaceholderHandler.php | 34 + .../shortcode/src/Handler/RawHandler.php | 26 + .../src/Handler/SerializerHandler.php | 38 + .../shortcode/src/Handler/UrlHandler.php | 26 + .../shortcode/src/Handler/WrapHandler.php | 37 + .../src/HandlerContainer/HandlerContainer.php | 79 + .../HandlerContainerInterface.php | 18 + .../ImmutableHandlerContainer.php | 20 + .../shortcode/src/Parser/ParserInterface.php | 19 + .../shortcode/src/Parser/RegexParser.php | 93 + .../shortcode/src/Parser/RegularParser.php | 339 + .../shortcode/src/Parser/WordpressParser.php | 115 + .../shortcode/src/Processor/Processor.php | 243 + .../src/Processor/ProcessorContext.php | 29 + .../src/Processor/ProcessorInterface.php | 17 + .../src/Serializer/JsonSerializer.php | 49 + .../src/Serializer/SerializerInterface.php | 28 + .../src/Serializer/TextSerializer.php | 89 + .../src/Serializer/XmlSerializer.php | 117 + .../src/Serializer/YamlSerializer.php | 50 + .../src/Shortcode/AbstractShortcode.php | 60 + .../src/Shortcode/ParsedShortcode.php | 39 + .../Shortcode/ParsedShortcodeInterface.php | 22 + .../src/Shortcode/ProcessedShortcode.php | 135 + .../src/Shortcode/ReplacedShortcode.php | 39 + .../shortcode/src/Shortcode/Shortcode.php | 30 + .../src/Shortcode/ShortcodeInterface.php | 59 + .../shortcode/src/ShortcodeFacade.php | 150 + .../shortcode/src/Syntax/CommonSyntax.php | 33 + .../thunderer/shortcode/src/Syntax/Syntax.php | 53 + .../shortcode/src/Syntax/SyntaxBuilder.php | 64 + .../shortcode/src/Syntax/SyntaxInterface.php | 18 + .../src/Utility/RegexBuilderUtility.php | 85 + .../shortcode/tests/AbstractTestCase.php | 17 + .../thunderer/shortcode/tests/EventsTest.php | 97 + .../thunderer/shortcode/tests/FacadeTest.php | 98 + .../shortcode/tests/Fake/ReverseShortcode.php | 12 + .../shortcode/tests/HandlerContainerTest.php | 100 + .../thunderer/shortcode/tests/ParserTest.php | 321 + .../shortcode/tests/ProcessorTest.php | 367 + .../shortcode/tests/SerializerTest.php | 124 + .../shortcode/tests/ShortcodeTest.php | 137 + .../thunderer/shortcode/tests/SyntaxTest.php | 54 + dev/plugins/tntsearch/CHANGELOG.md | 210 + dev/plugins/tntsearch/LICENSE | 21 + dev/plugins/tntsearch/README.md | 370 + dev/plugins/tntsearch/app/history.js | 3 + dev/plugins/tntsearch/app/main.js | 61 + dev/plugins/tntsearch/app/search.js | 107 + .../tntsearch/assets/admin/tntsearch.css | 34 + .../tntsearch/assets/admin/tntsearch.js | 78 + .../tntsearch/assets/tntsearch-ajax.gif | Bin 0 -> 772833 bytes .../tntsearch/assets/tntsearch-config.png | Bin 0 -> 19802 bytes .../tntsearch/assets/tntsearch-quicktray.png | Bin 0 -> 68282 bytes dev/plugins/tntsearch/assets/tntsearch.css | 71 + dev/plugins/tntsearch/assets/tntsearch.js | 1 + dev/plugins/tntsearch/blueprints.yaml | 288 + .../tntsearch/classes/GravConnector.php | 87 + .../tntsearch/classes/GravResultObject.php | 29 + .../tntsearch/classes/GravTNTSearch.php | 343 + .../tntsearch/cli/TNTSearchIndexerCommand.php | 97 + .../tntsearch/cli/TNTSearchQueryCommand.php | 74 + dev/plugins/tntsearch/composer.json | 34 + dev/plugins/tntsearch/composer.lock | 103 + dev/plugins/tntsearch/languages.yaml | 15 + dev/plugins/tntsearch/package.json | 38 + .../fields/indexstatus/indexstatus.html.twig | 16 + .../templates/partials/tntsearch.html.twig | 30 + .../tntsearch/templates/search.html.twig | 7 + .../templates/tntquery-ajax.html.twig | 19 + .../tntsearch/templates/tntquery.html.twig | 8 + .../tntsearch/templates/tntquery.json.twig | 1 + dev/plugins/tntsearch/tntsearch.php | 523 + dev/plugins/tntsearch/tntsearch.yaml | 28 + dev/plugins/tntsearch/vendor/autoload.php | 7 + .../tntsearch/vendor/composer/ClassLoader.php | 477 + .../vendor/composer/InstalledVersions.php | 293 + dev/plugins/tntsearch/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 11 + .../vendor/composer/autoload_files.php | 10 + .../vendor/composer/autoload_namespaces.php | 9 + .../vendor/composer/autoload_psr4.php | 12 + .../vendor/composer/autoload_real.php | 75 + .../vendor/composer/autoload_static.php | 54 + .../tntsearch/vendor/composer/installed.json | 86 + .../tntsearch/vendor/composer/installed.php | 33 + .../vendor/composer/platform_check.php | 26 + .../teamtnt/tntsearch/.github/FUNDING.yml | 3 + .../vendor/teamtnt/tntsearch/CHANGELOG.md | 22 + .../teamtnt/tntsearch/CODE_OF_CONDUCT.md | 46 + .../vendor/teamtnt/tntsearch/CONDUCT.md | 22 + .../vendor/teamtnt/tntsearch/CONTRIBUTING.md | 32 + .../vendor/teamtnt/tntsearch/LICENSE.md | 21 + .../vendor/teamtnt/tntsearch/PS4Ware.md | 9 + .../vendor/teamtnt/tntsearch/README.md | 374 + .../vendor/teamtnt/tntsearch/composer.json | 41 + .../teamtnt/tntsearch/helper/helpers.php | 25 + .../vendor/teamtnt/tntsearch/phpunit.php | 15 + .../vendor/teamtnt/tntsearch/phpunit.xml | 29 + .../src/Classifier/TNTClassifier.php | 131 + .../tntsearch/src/Connectors/Connector.php | 77 + .../src/Connectors/ConnectorInterface.php | 14 + .../src/Connectors/FileSystemConnector.php | 21 + .../src/Connectors/MySqlConnector.php | 139 + .../src/Connectors/PostgresConnector.php | 121 + .../src/Connectors/SQLiteConnector.php | 40 + .../src/Connectors/SqlServerConnector.php | 71 + .../src/Exceptions/IndexNotFoundException.php | 9 + .../src/FileReaders/FileReaderInterface.php | 16 + .../src/FileReaders/TextFileReader.php | 16 + .../tntsearch/src/Indexer/TNTGeoIndexer.php | 72 + .../tntsearch/src/Indexer/TNTIndexer.php | 695 + .../tntsearch/src/KeywordExtraction/Rake.php | 147 + .../src/Spell/JaroWinklerDistance.php | 114 + .../tntsearch/src/Stemmer/ArabicStemmer.php | 129 + .../tntsearch/src/Stemmer/CroatianStemmer.php | 315 + .../tntsearch/src/Stemmer/GermanStemmer.php | 248 + .../tntsearch/src/Stemmer/ItalianStemmer.php | 451 + .../tntsearch/src/Stemmer/NoStemmer.php | 11 + .../tntsearch/src/Stemmer/PorterStemmer.php | 424 + .../src/Stemmer/PortugueseStemmer.php | 727 + .../tntsearch/src/Stemmer/RussianStemmer.php | 83 + .../teamtnt/tntsearch/src/Stemmer/Stemmer.php | 6 + .../src/Stemmer/UkrainianStemmer.php | 83 + .../tntsearch/src/Stopwords/croatian.json | 1 + .../tntsearch/src/Stopwords/english.json | 1 + .../tntsearch/src/Stopwords/french.json | 1 + .../tntsearch/src/Stopwords/german.json | 1 + .../tntsearch/src/Stopwords/italian.json | 1 + .../tntsearch/src/Stopwords/russian.json | 1 + .../tntsearch/src/Stopwords/spanish.json | 1 + .../tntsearch/src/Stopwords/ukrainian.json | 1 + .../src/Support/AbstractTokenizer.php | 16 + .../tntsearch/src/Support/Collection.php | 163 + .../tntsearch/src/Support/Expression.php | 116 + .../tntsearch/src/Support/Highlighter.php | 206 + .../src/Support/ProductTokenizer.php | 14 + .../tntsearch/src/Support/Tokenizer.php | 14 + .../src/Support/TokenizerInterface.php | 9 + .../teamtnt/tntsearch/src/TNTFuzzyMatch.php | 155 + .../teamtnt/tntsearch/src/TNTGeoSearch.php | 91 + .../teamtnt/tntsearch/src/TNTSearch.php | 513 + .../tntsearch/tests/TNTFuzzyMatchTest.php | 115 + .../tntsearch/tests/TNTGeoSearchTest.php | 41 + .../teamtnt/tntsearch/tests/TNTSearchTest.php | 341 + .../tntsearch/tests/_files/articles.sqlite | Bin 0 -> 4096 bytes .../tntsearch/tests/_files/articles/1.txt | 1 + .../tntsearch/tests/_files/articles/2.txt | 1 + .../tntsearch/tests/_files/articles/3.txt | 1 + .../tntsearch/tests/_files/cities-geo.index | Bin 0 -> 4509696 bytes .../tntsearch/tests/_files/cities.sqlite | Bin 0 -> 3459072 bytes .../tests/_files/english_wordlist_2k.txt | 1510 + .../tntsearch/tests/_files/sms-texts.json | 1 + .../tests/classifier/TNTClassifierTest.php | 59 + .../tests/indexer/TNTGeoIndexerTest.php | 32 + .../tests/indexer/TNTIndexerTest.php | 190 + .../tests/keywordextraction/Rake.php | 107 + .../tests/spell/JaroWinklerDistanceTest.php | 50 + .../tests/stemmer/CroatianStemmerTest.php | 59 + .../tests/stemmer/GermanStemmerTest.php | 14 + .../tests/stemmer/PorterStemmerTest.php | 30 + .../tests/stemmer/PortugueseStemmerTest.php | 15 + .../tntsearch/tests/stemmer/porter/input.txt | 23531 ++++++++++++++++ .../tntsearch/tests/stemmer/porter/output.txt | 23531 ++++++++++++++++ .../tests/support/ExpressionTest.php | 20 + .../tests/support/HighlighterTest.php | 42 + .../tests/support/ProductTokenizerTest.php | 39 + .../tntsearch/tests/support/TokenizerTest.php | 39 + dev/plugins/tntsearch/webpack.conf.js | 45 + dev/plugins/tntsearch/yarn.lock | 4721 ++++ docker-compose.yml | 12 + 2702 files changed, 442090 insertions(+) create mode 100644 Dockerfile create mode 100644 dev/plugins/admin/.gitattributes create mode 100644 dev/plugins/admin/.github/FUNDING.yml create mode 100644 dev/plugins/admin/CHANGELOG.md create mode 100644 dev/plugins/admin/CONTRIBUTING.md create mode 100644 dev/plugins/admin/LICENSE create mode 100644 dev/plugins/admin/README.md create mode 100644 dev/plugins/admin/UPGRADE.md create mode 100644 dev/plugins/admin/admin.php create mode 100644 dev/plugins/admin/admin.yaml create mode 100644 dev/plugins/admin/assets/admin-dashboard.png create mode 100644 dev/plugins/admin/blueprints.yaml create mode 100644 dev/plugins/admin/blueprints/config/media.yaml create mode 100644 dev/plugins/admin/classes/plugin/Admin.php create mode 100644 dev/plugins/admin/classes/plugin/AdminBaseController.php create mode 100644 dev/plugins/admin/classes/plugin/AdminController.php create mode 100644 dev/plugins/admin/classes/plugin/AdminForm.php create mode 100644 dev/plugins/admin/classes/plugin/AdminFormFactory.php create mode 100644 dev/plugins/admin/classes/plugin/Controllers/AbstractController.php create mode 100644 dev/plugins/admin/classes/plugin/Controllers/AdminController.php create mode 100644 dev/plugins/admin/classes/plugin/Controllers/Login/LoginController.php create mode 100644 dev/plugins/admin/classes/plugin/Gpm.php create mode 100644 dev/plugins/admin/classes/plugin/Popularity.php create mode 100644 dev/plugins/admin/classes/plugin/Router.php create mode 100644 dev/plugins/admin/classes/plugin/Routers/LoginRouter.php create mode 100644 dev/plugins/admin/classes/plugin/ScssCompiler.php create mode 100644 dev/plugins/admin/classes/plugin/ScssList.php create mode 100644 dev/plugins/admin/classes/plugin/Themes.php create mode 100644 dev/plugins/admin/classes/plugin/Twig/AdminTwigExtension.php create mode 100644 dev/plugins/admin/classes/plugin/Utils.php create mode 100644 dev/plugins/admin/classes/plugin/WhiteLabel.php create mode 100644 dev/plugins/admin/codeception.yml create mode 100644 dev/plugins/admin/composer.json create mode 100644 dev/plugins/admin/composer.lock create mode 100644 dev/plugins/admin/languages/ar.yaml create mode 100644 dev/plugins/admin/languages/bg.yaml create mode 100644 dev/plugins/admin/languages/bn.yaml create mode 100644 dev/plugins/admin/languages/br.yaml create mode 100644 dev/plugins/admin/languages/ca.yaml create mode 100644 dev/plugins/admin/languages/cs.yaml create mode 100644 dev/plugins/admin/languages/cy.yaml create mode 100644 dev/plugins/admin/languages/da.yaml create mode 100644 dev/plugins/admin/languages/de.yaml create mode 100644 dev/plugins/admin/languages/el.yaml create mode 100644 dev/plugins/admin/languages/en.yaml create mode 100644 dev/plugins/admin/languages/eo.yaml create mode 100644 dev/plugins/admin/languages/es.yaml create mode 100644 dev/plugins/admin/languages/et.yaml create mode 100644 dev/plugins/admin/languages/eu.yaml create mode 100644 dev/plugins/admin/languages/fa.yaml create mode 100644 dev/plugins/admin/languages/fi.yaml create mode 100644 dev/plugins/admin/languages/fr.yaml create mode 100644 dev/plugins/admin/languages/gl.yaml create mode 100644 dev/plugins/admin/languages/he.yaml create mode 100644 dev/plugins/admin/languages/hr.yaml create mode 100644 dev/plugins/admin/languages/hu.yaml create mode 100644 dev/plugins/admin/languages/id.yaml create mode 100644 dev/plugins/admin/languages/it.yaml create mode 100644 dev/plugins/admin/languages/ja.yaml create mode 100644 dev/plugins/admin/languages/ko.yaml create mode 100644 dev/plugins/admin/languages/ku.yaml create mode 100644 dev/plugins/admin/languages/lt.yaml create mode 100644 dev/plugins/admin/languages/mn.yaml create mode 100644 dev/plugins/admin/languages/nl.yaml create mode 100644 dev/plugins/admin/languages/no.yaml create mode 100644 dev/plugins/admin/languages/pl.yaml create mode 100644 dev/plugins/admin/languages/pt.yaml create mode 100644 dev/plugins/admin/languages/ro.yaml create mode 100644 dev/plugins/admin/languages/ru.yaml create mode 100644 dev/plugins/admin/languages/si.yaml create mode 100644 dev/plugins/admin/languages/sk.yaml create mode 100644 dev/plugins/admin/languages/sl.yaml create mode 100644 dev/plugins/admin/languages/sr.yaml create mode 100644 dev/plugins/admin/languages/sv.yaml create mode 100644 dev/plugins/admin/languages/th.yaml create mode 100644 dev/plugins/admin/languages/tlh.yaml create mode 100644 dev/plugins/admin/languages/tr.yaml create mode 100644 dev/plugins/admin/languages/uk.yaml create mode 100644 dev/plugins/admin/languages/vi.yaml create mode 100644 dev/plugins/admin/languages/zh-cn.yaml create mode 100644 dev/plugins/admin/languages/zh-tw.yaml create mode 100644 dev/plugins/admin/languages/zh.yaml create mode 100644 dev/plugins/admin/permissions.yaml create mode 100644 dev/plugins/admin/presets.yaml create mode 100644 dev/plugins/admin/tests/_bootstrap.php create mode 100644 dev/plugins/admin/tests/_support/Helper/Unit.php create mode 100644 dev/plugins/admin/tests/_support/UnitTester.php create mode 100644 dev/plugins/admin/tests/unit.suite.yml create mode 100644 dev/plugins/admin/tests/unit/_bootstrap.php create mode 100644 dev/plugins/admin/tests/unit/classes/controllerTest.php create mode 100644 dev/plugins/admin/twig/AdminTwigExtension.php create mode 100644 dev/plugins/admin/vendor/autoload.php create mode 100644 dev/plugins/admin/vendor/bin/picofeed create mode 100644 dev/plugins/admin/vendor/bin/pscss create mode 100644 dev/plugins/admin/vendor/composer/ClassLoader.php create mode 100644 dev/plugins/admin/vendor/composer/InstalledVersions.php create mode 100644 dev/plugins/admin/vendor/composer/LICENSE create mode 100644 dev/plugins/admin/vendor/composer/autoload_classmap.php create mode 100644 dev/plugins/admin/vendor/composer/autoload_files.php create mode 100644 dev/plugins/admin/vendor/composer/autoload_namespaces.php create mode 100644 dev/plugins/admin/vendor/composer/autoload_psr4.php create mode 100644 dev/plugins/admin/vendor/composer/autoload_real.php create mode 100644 dev/plugins/admin/vendor/composer/autoload_static.php create mode 100644 dev/plugins/admin/vendor/composer/installed.json create mode 100644 dev/plugins/admin/vendor/composer/installed.php create mode 100644 dev/plugins/admin/vendor/composer/platform_check.php create mode 100644 dev/plugins/admin/vendor/laminas/laminas-xml/COPYRIGHT.md create mode 100644 dev/plugins/admin/vendor/laminas/laminas-xml/LICENSE.md create mode 100644 dev/plugins/admin/vendor/laminas/laminas-xml/README.md create mode 100644 dev/plugins/admin/vendor/laminas/laminas-xml/composer.json create mode 100644 dev/plugins/admin/vendor/laminas/laminas-xml/composer.lock create mode 100644 dev/plugins/admin/vendor/laminas/laminas-xml/src/Exception/ExceptionInterface.php create mode 100644 dev/plugins/admin/vendor/laminas/laminas-xml/src/Exception/InvalidArgumentException.php create mode 100644 dev/plugins/admin/vendor/laminas/laminas-xml/src/Exception/RuntimeException.php create mode 100644 dev/plugins/admin/vendor/laminas/laminas-xml/src/Security.php create mode 100644 dev/plugins/admin/vendor/laminas/laminas-zendframework-bridge/.github/FUNDING.yml create mode 100644 dev/plugins/admin/vendor/laminas/laminas-zendframework-bridge/.laminas-ci.json create mode 100644 dev/plugins/admin/vendor/laminas/laminas-zendframework-bridge/COPYRIGHT.md create mode 100644 dev/plugins/admin/vendor/laminas/laminas-zendframework-bridge/LICENSE.md create mode 100644 dev/plugins/admin/vendor/laminas/laminas-zendframework-bridge/README.md create mode 100644 dev/plugins/admin/vendor/laminas/laminas-zendframework-bridge/composer.json create mode 100644 dev/plugins/admin/vendor/laminas/laminas-zendframework-bridge/composer.lock create mode 100644 dev/plugins/admin/vendor/laminas/laminas-zendframework-bridge/config/replacements.php create mode 100644 dev/plugins/admin/vendor/laminas/laminas-zendframework-bridge/psalm-baseline.xml create mode 100644 dev/plugins/admin/vendor/laminas/laminas-zendframework-bridge/psalm.xml.dist create mode 100644 dev/plugins/admin/vendor/laminas/laminas-zendframework-bridge/src/Autoloader.php create mode 100644 dev/plugins/admin/vendor/laminas/laminas-zendframework-bridge/src/ConfigPostProcessor.php create mode 100644 dev/plugins/admin/vendor/laminas/laminas-zendframework-bridge/src/Module.php create mode 100644 dev/plugins/admin/vendor/laminas/laminas-zendframework-bridge/src/Replacements.php create mode 100644 dev/plugins/admin/vendor/laminas/laminas-zendframework-bridge/src/RewriteRules.php create mode 100644 dev/plugins/admin/vendor/laminas/laminas-zendframework-bridge/src/autoload.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/LICENSE create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Base.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/Client.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/ClientException.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/Curl.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/ForbiddenException.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/HttpHeaders.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/InvalidCertificateException.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/InvalidUrlException.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/MaxRedirectException.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/MaxSizeException.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/Stream.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/TimeoutException.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/UnauthorizedException.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/Url.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Config/Config.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Encoding/Encoding.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Filter/Attribute.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Filter/Filter.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Filter/Html.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Filter/Tag.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Generator/ContentGeneratorInterface.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Generator/FileContentGenerator.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Generator/YoutubeContentGenerator.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Logging/Logger.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Atom.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/DateParser.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Feed.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Item.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/MalformedXmlException.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Parser.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/ParserException.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/ParserInterface.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Rss10.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Rss20.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Rss91.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Rss92.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/XmlEntityException.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/XmlParser.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/PicoFeedException.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ContentFilterProcessor.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ContentGeneratorProcessor.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ItemPostProcessor.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ItemProcessorInterface.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ScraperProcessor.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/Favicon.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/Reader.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/ReaderException.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/SubscriptionNotFoundException.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/UnsupportedFeedFormatException.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.blog.lemonde.fr.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.blogs.nytimes.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.igen.fr.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.nytimes.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.over-blog.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.phoronix.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.slate.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.theguardian.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wikipedia.org.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wired.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wsj.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/01net.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/24.hu.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/444.hu.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/888.hu.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/abstrusegoose.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/achgut.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/adventuregamers.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/alainonline.net.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/aljazeera.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/allafrica.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/allgemeine-zeitung.de.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/amazingsuperpowers.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/anythingcomic.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ap.org.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/areadvd.de.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/arstechnica.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/atv.hu.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/awkwardzombie.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/backchannel.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bangkokpost.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bauerwilli.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bgr.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bigfootjustice.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bigpicture.ru.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bizjournals.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/biztimes.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bleepingcomputer.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/blog.fefe.de.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/blog.mapillary.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/brewers.mlb.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/buenosairesherald.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bunicomic.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/buttersafe.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cad-comic.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/chaoslife.findchaos.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/chinafile.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cicero.de.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cliquerefresh.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cnet.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/coinwelt.de.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/consomac.fr.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cowbirdsinlove.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/crash.net.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/csmonitor.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailyjs.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailyreporter.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailytech.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/degroupnews.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/derstandard.at.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dilbert.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/discovermagazine.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/distrowatch.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dozodomo.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/drawingboardcomic.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/e-w-e.ru.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/economist.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/encyclopedie.naheulbeuk.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/endlessorigami.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/engadget.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/escapistmagazine.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/espn.go.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/exocomics.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/explosm.net.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/extrafabulouscomics.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/factroom.ru.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcodesign.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcoexist.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcompany.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ffworld.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/foreignpolicy.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fossbytes.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fototelegraf.ru.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fowllanguagecomics.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gamechannel.hu.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gamestar.hu.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/geek.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/geektimes.ru.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gerbilwithajetpack.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/giantitp.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/github.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gocomics.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/golem.de.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gondola.hu.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gorabbit.ru.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/habrahabr.ru.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/happletea.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hardware.fr.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/heise.de.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hirek.prim.hu.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hotshowlife.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/huffingtonpost.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hvg.hu.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/idokep.hu.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/imogenquest.net.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/index.hu.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/indiehaven.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/inforadio.hu.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ing.dk.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/invisiblebread.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ir.amd.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/japantimes.co.jp.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/japantoday.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/journaldugeek.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/jsonline.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/justcoolidea.ru.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kanpai.fr.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/karriere.jobfinder.dk.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kisalfold.hu.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kiszamolo.hu.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kodi.tv.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/koreaherald.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/koreatimes.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lastplacecomics.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/legorafi.fr.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lejapon.fr.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lesjoiesducode.fr.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lfg.co.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lifehacker.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lifehacker.ru.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux-magazin.de.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux.org.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux.org.ru.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linuxinsider.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lists.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/loadingartist.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/loldwell.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lukesurl.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/macg.co.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/maclife.de.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/magyarkurir.hu.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marc.info.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marriedtothesea.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marycagle.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/maximumble.thebookofbiff.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/medium.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mercworks.net.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/metronieuws.nl.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/milwaukeenns.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mno.hu.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mokepon.smackjeeves.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/monandroid.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/monwindows.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/moya-planeta.ru.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mrlovenstein.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/muckrock.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mynorthshorenow.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nakedCapitalism.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nasa.gov.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nat-geo.ru.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nationaljournal.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nature.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nba.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nedroid.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/networkworld.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/neustadt-ticker.de.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nextinpact.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/niceteethcomic.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nichtlustig.de.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nlcafe.hu.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/novo-argumente.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/oglaf.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/onhax.net.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/onlinekosten.de.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/onmilwaukee.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/openculture.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/opennet.ru.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/openrightsgroup.org.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/opensource.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/optipess.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/origo.hu.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/osnews.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pastebin.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pcgameshardware.de.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/peebleslab.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/penny-arcade.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pixelbeat.org.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/plus.google.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/popstrip.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/portfolio.hu.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pro-linux.de.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/publicpolicyforum.org.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/publy.ru.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/putaindecode.fr.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/recode.net.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/retractionwatch.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/rockpapershotgun.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/rue89.nouvelobs.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/rugbyrama.fr.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/salonkolumnisten.com create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/satwcomic.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/science-skeptical.de.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/scrumalliance.org.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/securityfocus.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/sentfromthemoon.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/sitepoint.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/slashdot.org.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smallhousebliss.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smarthomewelt.de.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smashingmagazine.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smbc-comics.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/snopes.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/soundandvision.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/spiegel.de.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/stereophile.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/stupidfox.net.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/subtraction.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/sz.de.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/takprosto.cc.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/techcrunch.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/the-ebook-reader.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theatlantic.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theawkwardyeti.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thecodinglove.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thedoghousediaries.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thegamercat.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thehindu.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thelocal.se.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/themerepublic.net.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/themoscowtimes.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thenewslens.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theodd1sout.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theonion.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theregister.co.uk.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thestandard.com.hk.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theverge.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/threepanelsoul.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/tichyseinblick.de.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/timesofindia.indiatimes.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/totalcar.hu.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/tozsdeforum.hu.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/travel-dealz.de.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/travelo.hu.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/treehugger.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/treelobsters.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/tutorialzine.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/twogag.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/twokinds.keenspot.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/undeadly.org.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/upi.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/usatoday.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/version2.dk.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/vezess.hu.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/vgcats.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/vuxml.org.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/wausaudailyherald.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/welt.de.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/westfalen-blatt.de.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.bbc.co.uk.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.bdgest.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.bgr.in.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.businessweek.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.cnn.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.developpez.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.egscomics.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.fakingnews.firstpost.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.forbes.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.franceculture.fr.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.futura-sciences.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.geekculture.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.howtogeek.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.lepoint.fr.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.lesnumeriques.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.mac4ever.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.makeuseof.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.monsieur-le-chien.fr.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.npr.org.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.numerama.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.oneindia.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.pseudo-sciences.org.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.sciencemag.org.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.slate.fr.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.universfreebox.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.zeit.de.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/xkcd.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ymatuhin.ru.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/zarojel.hu.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/zdnet.com.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/zoom.hu.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/CandidateParser.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/ParserInterface.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/RuleLoader.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/RuleParser.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/Scraper.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/Subscription.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionList.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionListBuilder.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionListParser.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionParser.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/AtomFeedBuilder.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/AtomHelper.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/AtomItemBuilder.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/FeedBuilder.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/ItemBuilder.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/Rss20FeedBuilder.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/Rss20Helper.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/Rss20ItemBuilder.php create mode 100644 dev/plugins/admin/vendor/p3k/picofeed/picofeed create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/LICENSE.md create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/README.md create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/bin/pscss create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/composer.json create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/phpcs.xml.dist create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/scss.inc.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Base/Range.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Block.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Block/AtRootBlock.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Block/CallableBlock.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Block/ContentBlock.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Block/DirectiveBlock.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Block/EachBlock.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Block/ElseBlock.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Block/ElseifBlock.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Block/ForBlock.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Block/IfBlock.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Block/MediaBlock.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Block/NestedPropertyBlock.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Block/WhileBlock.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Cache.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Colors.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/CompilationResult.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Compiler.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Compiler/CachedResult.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Compiler/Environment.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Exception/CompilerException.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Exception/ParserException.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Exception/RangeException.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Exception/SassException.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Exception/SassScriptException.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Exception/ServerException.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Compact.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Compressed.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Crunched.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Debug.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Expanded.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Nested.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/OutputBlock.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Logger/LoggerInterface.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Logger/QuietLogger.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Logger/StreamLogger.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Node.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Node/Number.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/OutputStyle.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Parser.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/SourceMap/Base64.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/SourceMap/Base64VLQ.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/SourceMap/SourceMapGenerator.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Type.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Util.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Util/Path.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/ValueConverter.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Version.php create mode 100644 dev/plugins/admin/vendor/scssphp/scssphp/src/Warn.php create mode 100644 dev/plugins/anchors/.idea/vcs.xml create mode 100644 dev/plugins/anchors/CHANGELOG.md create mode 100644 dev/plugins/anchors/LICENSE create mode 100644 dev/plugins/anchors/README.md create mode 100644 dev/plugins/anchors/anchors.php create mode 100644 dev/plugins/anchors/anchors.yaml create mode 100644 dev/plugins/anchors/blueprints.yaml create mode 100644 dev/plugins/anchors/hebe.json create mode 100644 dev/plugins/anchors/js/anchor.min.js create mode 100644 dev/plugins/anchors/js/clipboard.min.js create mode 100644 dev/plugins/anchors/twig/AnchorsTwigExtension.php create mode 100644 dev/plugins/breadcrumbs/CHANGELOG.md create mode 100644 dev/plugins/breadcrumbs/LICENSE create mode 100644 dev/plugins/breadcrumbs/README.md create mode 100644 dev/plugins/breadcrumbs/assets/readme_1.png create mode 100644 dev/plugins/breadcrumbs/blueprints.yaml create mode 100644 dev/plugins/breadcrumbs/breadcrumbs.php create mode 100644 dev/plugins/breadcrumbs/breadcrumbs.yaml create mode 100644 dev/plugins/breadcrumbs/classes/plugin/Breadcrumbs.php create mode 100644 dev/plugins/breadcrumbs/composer.json create mode 100644 dev/plugins/breadcrumbs/composer.lock create mode 100644 dev/plugins/breadcrumbs/css/breadcrumbs.css create mode 100644 dev/plugins/breadcrumbs/hebe.json create mode 100644 dev/plugins/breadcrumbs/languages.yaml create mode 100644 dev/plugins/breadcrumbs/templates/partials/breadcrumbs.html.twig create mode 100644 dev/plugins/breadcrumbs/vendor/autoload.php create mode 100644 dev/plugins/breadcrumbs/vendor/composer/ClassLoader.php create mode 100644 dev/plugins/breadcrumbs/vendor/composer/LICENSE create mode 100644 dev/plugins/breadcrumbs/vendor/composer/autoload_classmap.php create mode 100644 dev/plugins/breadcrumbs/vendor/composer/autoload_namespaces.php create mode 100644 dev/plugins/breadcrumbs/vendor/composer/autoload_psr4.php create mode 100644 dev/plugins/breadcrumbs/vendor/composer/autoload_real.php create mode 100644 dev/plugins/breadcrumbs/vendor/composer/autoload_static.php create mode 100644 dev/plugins/breadcrumbs/vendor/composer/installed.json create mode 100644 dev/plugins/email/CHANGELOG.md create mode 100644 dev/plugins/email/LICENSE create mode 100644 dev/plugins/email/README.md create mode 100644 dev/plugins/email/blueprints.yaml create mode 100644 dev/plugins/email/classes/Email.php create mode 100644 dev/plugins/email/classes/Utils.php create mode 100644 dev/plugins/email/cli/ClearQueueFailuresCommand.php create mode 100644 dev/plugins/email/cli/FlushQueueCommand.php create mode 100644 dev/plugins/email/cli/TestEmailCommand.php create mode 100644 dev/plugins/email/composer.json create mode 100644 dev/plugins/email/composer.lock create mode 100644 dev/plugins/email/email.php create mode 100644 dev/plugins/email/email.yaml create mode 100644 dev/plugins/email/languages.yaml create mode 100644 dev/plugins/email/templates/email/base.html.twig create mode 100644 dev/plugins/email/vendor/autoload.php create mode 100644 dev/plugins/email/vendor/composer/ClassLoader.php create mode 100644 dev/plugins/email/vendor/composer/InstalledVersions.php create mode 100644 dev/plugins/email/vendor/composer/LICENSE create mode 100644 dev/plugins/email/vendor/composer/autoload_classmap.php create mode 100644 dev/plugins/email/vendor/composer/autoload_files.php create mode 100644 dev/plugins/email/vendor/composer/autoload_namespaces.php create mode 100644 dev/plugins/email/vendor/composer/autoload_psr4.php create mode 100644 dev/plugins/email/vendor/composer/autoload_real.php create mode 100644 dev/plugins/email/vendor/composer/autoload_static.php create mode 100644 dev/plugins/email/vendor/composer/installed.json create mode 100644 dev/plugins/email/vendor/composer/installed.php create mode 100644 dev/plugins/email/vendor/composer/platform_check.php create mode 100644 dev/plugins/email/vendor/doctrine/lexer/LICENSE create mode 100644 dev/plugins/email/vendor/doctrine/lexer/README.md create mode 100644 dev/plugins/email/vendor/doctrine/lexer/composer.json create mode 100644 dev/plugins/email/vendor/doctrine/lexer/lib/Doctrine/Common/Lexer/AbstractLexer.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/CHANGELOG.md create mode 100644 dev/plugins/email/vendor/egulias/email-validator/CONTRIBUTING.md create mode 100644 dev/plugins/email/vendor/egulias/email-validator/LICENSE create mode 100644 dev/plugins/email/vendor/egulias/email-validator/composer.json create mode 100644 dev/plugins/email/vendor/egulias/email-validator/composer.lock create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/EmailLexer.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/EmailParser.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/EmailValidator.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/MessageIDParser.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Parser.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Parser/Comment.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Parser/CommentStrategy/CommentStrategy.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Parser/CommentStrategy/DomainComment.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Parser/CommentStrategy/LocalComment.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Parser/DomainLiteral.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Parser/DomainPart.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Parser/DoubleQuote.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Parser/FoldingWhiteSpace.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Parser/IDLeftPart.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Parser/IDRightPart.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Parser/LocalPart.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Parser/PartParser.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/InvalidEmail.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/MultipleErrors.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/AtextAfterCFWS.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/CRLFAtTheEnd.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/CRLFX2.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/CRNoLF.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/CharNotAllowed.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/CommaInDomain.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/CommentsInIDRight.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/ConsecutiveAt.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/ConsecutiveDot.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/DetailedReason.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/DomainAcceptsNoMail.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/DomainHyphened.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/DomainTooLong.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/DotAtEnd.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/DotAtStart.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/EmptyReason.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/ExceptionFound.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/ExpectingATEXT.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/ExpectingCTEXT.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/ExpectingDTEXT.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/ExpectingDomainLiteralClose.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/LabelTooLong.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/LocalOrReservedDomain.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/NoDNSRecord.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/NoDomainPart.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/NoLocalPart.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/RFCWarnings.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/Reason.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/SpoofEmail.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/UnOpenedComment.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/UnableToGetDNSRecord.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/UnclosedComment.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/UnclosedQuotedString.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Reason/UnusualElements.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/Result.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/SpoofEmail.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Result/ValidEmail.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Validation/DNSCheckValidation.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Validation/EmailValidation.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Validation/Exception/EmptyValidationList.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Validation/Extra/SpoofCheckValidation.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Validation/MessageIDValidation.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Validation/MultipleValidationWithAnd.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Validation/NoRFCWarningsValidation.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Validation/RFCValidation.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Warning/AddressLiteral.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Warning/CFWSNearAt.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Warning/CFWSWithFWS.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Warning/Comment.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Warning/DeprecatedComment.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Warning/DomainLiteral.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Warning/EmailTooLong.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Warning/IPV6BadChar.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Warning/IPV6ColonEnd.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Warning/IPV6ColonStart.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Warning/IPV6Deprecated.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Warning/IPV6DoubleColon.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Warning/IPV6GroupCount.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Warning/IPV6MaxGroups.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Warning/LocalTooLong.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Warning/NoDNSMXRecord.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Warning/ObsoleteDTEXT.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Warning/QuotedPart.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Warning/QuotedString.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Warning/TLD.php create mode 100644 dev/plugins/email/vendor/egulias/email-validator/src/Warning/Warning.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/.gitattributes create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/.github/ISSUE_TEMPLATE.md create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/.github/PULL_REQUEST_TEMPLATE.md create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/.php_cs.dist create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/CHANGES create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/LICENSE create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/README.md create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/composer.json create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/doc/headers.rst create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/doc/index.rst create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/doc/introduction.rst create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/doc/japanese.rst create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/doc/messages.rst create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/doc/plugins.rst create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/doc/sending.rst create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/AddressEncoder.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/AddressEncoder/IdnAddressEncoder.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/AddressEncoder/Utf8AddressEncoder.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/AddressEncoderException.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Attachment.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/ArrayByteStream.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/FileByteStream.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/TemporaryFileByteStream.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/GenericFixedWidthReader.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/UsAsciiReader.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/Utf8Reader.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReaderFactory.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReaderFactory/SimpleCharacterReaderFactory.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream/ArrayCharacterStream.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream/NgCharacterStream.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ConfigurableSpool.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyContainer.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyException.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/EmbeddedFile.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/Base64Encoder.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/QpEncoder.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/Rfc2231Encoder.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandEvent.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandListener.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/Event.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/EventDispatcher.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/EventListener.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/EventObject.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseEvent.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseListener.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/SendEvent.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/SendListener.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/SimpleEventDispatcher.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeEvent.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeListener.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportExceptionEvent.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportExceptionListener.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FailoverTransport.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileSpool.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileStream.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Filterable.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/IdGenerator.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Image.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/InputByteStream.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/IoException.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/ArrayKeyCache.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/DiskKeyCache.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/KeyCacheInputStream.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/NullKeyCache.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/SimpleKeyCacheInputStream.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/LoadBalancedTransport.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/ArrayRecipientIterator.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/RecipientIterator.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MemorySpool.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Message.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Attachment.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/CharsetObserver.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/Base64ContentEncoder.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/NullContentEncoder.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/PlainContentEncoder.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EmbeddedFile.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EncodingObserver.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Header.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder/Base64HeaderEncoder.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/AbstractHeader.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/DateHeader.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/IdentificationHeader.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/MailboxHeader.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/OpenDKIMHeader.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/ParameterizedHeader.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/PathHeader.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/UnstructuredHeader.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/IdGenerator.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/MimePart.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderFactory.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderSet.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMessage.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMimeEntity.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MimePart.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/NullTransport.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/OutputByteStream.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/AntiFloodPlugin.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/BandwidthMonitorPlugin.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Decorator/Replacements.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/DecoratorPlugin.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/ImpersonatePlugin.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Logger.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/LoggerPlugin.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/ArrayLogger.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/EchoLogger.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/MessageLogger.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Pop/Pop3Connection.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Pop/Pop3Exception.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/PopBeforeSmtpPlugin.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/RedirectingPlugin.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporter.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/ReporterPlugin.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HitReporter.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HtmlReporter.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Sleeper.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/ThrottlerPlugin.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Timer.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Preferences.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ReplacementFilterFactory.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/RfcComplianceException.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SendmailTransport.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signer.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/BodySigner.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DKIMSigner.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DomainKeySigner.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/HeaderSigner.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/OpenDKIMSigner.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/SMimeSigner.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SmtpTransport.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Spool.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SpoolTransport.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilter.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/ByteArrayReplacementFilter.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilter.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilterFactory.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SwiftException.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/AuthHandler.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Authenticator.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/EightBitMimeHandler.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/SmtpUtf8Handler.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpHandler.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/FailoverTransport.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/IoBuffer.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/LoadBalancedTransport.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/NullTransport.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SendmailTransport.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SmtpAgent.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SpoolTransport.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/classes/Swift/TransportException.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/cache_deps.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/message_deps.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/mime_deps.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/dependency_maps/transport_deps.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/mime_types.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/preferences.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/swift_required.php create mode 100644 dev/plugins/email/vendor/swiftmailer/swiftmailer/lib/swiftmailer_generate_mimes_config.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Iconv.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/LICENSE create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/README.md create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.big5.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp037.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp1006.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp1026.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp424.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp437.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp500.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp737.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp775.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp850.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp852.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp855.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp856.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp857.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp860.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp861.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp862.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp863.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp864.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp865.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp866.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp869.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp874.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp875.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp932.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp936.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp949.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.cp950.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-1.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-10.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-11.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-13.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-14.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-15.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-16.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-2.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-3.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-4.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-5.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-6.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-7.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-8.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.iso-8859-9.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.koi8-r.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.koi8-u.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.us-ascii.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.windows-1250.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.windows-1251.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.windows-1252.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.windows-1253.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.windows-1254.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.windows-1255.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.windows-1256.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.windows-1257.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/from.windows-1258.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/Resources/charset/translit.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/bootstrap.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/bootstrap80.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-iconv/composer.json create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-idn/Idn.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-idn/Info.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-idn/LICENSE create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-idn/README.md create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-idn/Resources/unidata/Regex.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-idn/Resources/unidata/deviation.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_mapped.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_valid.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-idn/Resources/unidata/ignored.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-idn/Resources/unidata/mapped.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-idn/Resources/unidata/virama.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-idn/bootstrap.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-idn/bootstrap80.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-idn/composer.json create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-normalizer/LICENSE create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-normalizer/Normalizer.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-normalizer/README.md create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalComposition.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-normalizer/bootstrap.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-normalizer/bootstrap80.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-intl-normalizer/composer.json create mode 100644 dev/plugins/email/vendor/symfony/polyfill-mbstring/LICENSE create mode 100644 dev/plugins/email/vendor/symfony/polyfill-mbstring/Mbstring.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-mbstring/README.md create mode 100644 dev/plugins/email/vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-mbstring/Resources/unidata/upperCase.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-mbstring/bootstrap.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-mbstring/bootstrap80.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-mbstring/composer.json create mode 100644 dev/plugins/email/vendor/symfony/polyfill-php72/LICENSE create mode 100644 dev/plugins/email/vendor/symfony/polyfill-php72/Php72.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-php72/README.md create mode 100644 dev/plugins/email/vendor/symfony/polyfill-php72/bootstrap.php create mode 100644 dev/plugins/email/vendor/symfony/polyfill-php72/composer.json create mode 100644 dev/plugins/error/CHANGELOG.md create mode 100644 dev/plugins/error/LICENSE create mode 100644 dev/plugins/error/README.md create mode 100644 dev/plugins/error/assets/readme_1.png create mode 100644 dev/plugins/error/blueprints.yaml create mode 100644 dev/plugins/error/cli/LogCommand.php create mode 100644 dev/plugins/error/composer.json create mode 100644 dev/plugins/error/error.php create mode 100644 dev/plugins/error/error.yaml create mode 100644 dev/plugins/error/languages.yaml create mode 100644 dev/plugins/error/templates/error.html.twig create mode 100644 dev/plugins/error/templates/error.json.twig create mode 100644 dev/plugins/error/vendor/autoload.php create mode 100644 dev/plugins/error/vendor/composer/ClassLoader.php create mode 100644 dev/plugins/error/vendor/composer/LICENSE create mode 100644 dev/plugins/error/vendor/composer/autoload_classmap.php create mode 100644 dev/plugins/error/vendor/composer/autoload_namespaces.php create mode 100644 dev/plugins/error/vendor/composer/autoload_psr4.php create mode 100644 dev/plugins/error/vendor/composer/autoload_real.php create mode 100644 dev/plugins/error/vendor/composer/autoload_static.php create mode 100644 dev/plugins/error/vendor/composer/installed.json create mode 100644 dev/plugins/external_links/CHANGELOG.md create mode 100644 dev/plugins/external_links/LICENSE create mode 100644 dev/plugins/external_links/README.md create mode 100644 dev/plugins/external_links/assets/css/external_links.css create mode 100644 dev/plugins/external_links/assets/images/link.png create mode 100644 dev/plugins/external_links/assets/images/mail.png create mode 100644 dev/plugins/external_links/assets/logo.png create mode 100644 dev/plugins/external_links/assets/screenshot.png create mode 100644 dev/plugins/external_links/blueprints.yaml create mode 100644 dev/plugins/external_links/blueprints/external_links.yaml create mode 100644 dev/plugins/external_links/classes/ExternalLinks.php create mode 100644 dev/plugins/external_links/docs/CONTRIBUTING.md create mode 100644 dev/plugins/external_links/docs/INSTALL.md create mode 100644 dev/plugins/external_links/external_links.php create mode 100644 dev/plugins/external_links/external_links.yaml create mode 100644 dev/plugins/external_links/languages.yaml create mode 100644 dev/plugins/feed/CHANGELOG.md create mode 100644 dev/plugins/feed/LICENSE create mode 100644 dev/plugins/feed/README.md create mode 100644 dev/plugins/feed/assets/readme_1.png create mode 100644 dev/plugins/feed/blueprints.yaml create mode 100644 dev/plugins/feed/blueprints/feed.yaml create mode 100644 dev/plugins/feed/composer.json create mode 100644 dev/plugins/feed/composer.lock create mode 100644 dev/plugins/feed/feed.php create mode 100644 dev/plugins/feed/feed.yaml create mode 100644 dev/plugins/feed/hebe.json create mode 100644 dev/plugins/feed/templates/feed.atom.twig create mode 100644 dev/plugins/feed/templates/feed.json.twig create mode 100644 dev/plugins/feed/templates/feed.rss.twig create mode 100644 dev/plugins/feed/vendor/autoload.php create mode 100644 dev/plugins/feed/vendor/composer/ClassLoader.php create mode 100644 dev/plugins/feed/vendor/composer/InstalledVersions.php create mode 100644 dev/plugins/feed/vendor/composer/LICENSE create mode 100644 dev/plugins/feed/vendor/composer/autoload_classmap.php create mode 100644 dev/plugins/feed/vendor/composer/autoload_namespaces.php create mode 100644 dev/plugins/feed/vendor/composer/autoload_psr4.php create mode 100644 dev/plugins/feed/vendor/composer/autoload_real.php create mode 100644 dev/plugins/feed/vendor/composer/autoload_static.php create mode 100644 dev/plugins/feed/vendor/composer/installed.json create mode 100644 dev/plugins/feed/vendor/composer/installed.php create mode 100644 dev/plugins/flex-objects/CHANGELOG.md create mode 100644 dev/plugins/flex-objects/LICENSE create mode 100644 dev/plugins/flex-objects/README.md create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects.json.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/layouts/404.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/layouts/accounts/partials/top.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/add.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/back.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/configuration.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/delete.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/export-csv.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/export.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/languages.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/preview-open.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/preview.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/save.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/default/configure.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/default/edit.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/default/list.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/default/list/list.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/default/list/list_actions.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/default/modals/remove.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/default/preview.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/default/titlebar/configure.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/default/titlebar/edit.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/default/titlebar/list.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/default/titlebar/preview.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/default/titlebar/types.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/default/types.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/user-accounts/configure.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/user-accounts/edit.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/user-accounts/list.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/user-groups/configure.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/flex-objects/types/user-groups/list.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/forms/fields/flex-objects/flex-objects.html.twig create mode 100644 dev/plugins/flex-objects/admin/templates/forms/fields/save-redirect/save-redirect.html.twig create mode 100644 dev/plugins/flex-objects/app/columns/finder.js create mode 100644 dev/plugins/flex-objects/app/columns/index.js create mode 100644 dev/plugins/flex-objects/app/filters/index.js create mode 100644 dev/plugins/flex-objects/app/filters/panel.js create mode 100644 dev/plugins/flex-objects/app/list/App.vue create mode 100644 dev/plugins/flex-objects/app/list/VuetableCssConfig.js create mode 100644 dev/plugins/flex-objects/app/list/components/ContentLoader.vue create mode 100644 dev/plugins/flex-objects/app/list/components/FilterBar.vue create mode 100644 dev/plugins/flex-objects/app/list/components/Table.vue create mode 100644 dev/plugins/flex-objects/app/list/index.js create mode 100644 dev/plugins/flex-objects/app/main.js create mode 100644 dev/plugins/flex-objects/app/utils/finder.js create mode 100644 dev/plugins/flex-objects/app/utils/get-filters.js create mode 100644 dev/plugins/flex-objects/app/utils/indeterminate.js create mode 100644 dev/plugins/flex-objects/assets/flex-objects-directory.png create mode 100644 dev/plugins/flex-objects/assets/flex-objects-edit.png create mode 100644 dev/plugins/flex-objects/assets/flex-objects-list.png create mode 100644 dev/plugins/flex-objects/assets/flex-objects-options.png create mode 100644 dev/plugins/flex-objects/assets/flex-objects-site.png create mode 100644 dev/plugins/flex-objects/blueprints.yaml create mode 100644 dev/plugins/flex-objects/blueprints/flex-objects.yaml create mode 100644 dev/plugins/flex-objects/blueprints/flex-objects/contacts.yaml create mode 100644 dev/plugins/flex-objects/blueprints/flex-objects/pages.yaml create mode 100644 dev/plugins/flex-objects/blueprints/flex-objects/user-accounts.yaml create mode 100644 dev/plugins/flex-objects/blueprints/flex-objects/user-groups.yaml create mode 100644 dev/plugins/flex-objects/classes/Admin/AdminController.php create mode 100644 dev/plugins/flex-objects/classes/Controllers/AbstractController.php create mode 100644 dev/plugins/flex-objects/classes/Controllers/MediaController.php create mode 100644 dev/plugins/flex-objects/classes/Controllers/ObjectController.php create mode 100644 dev/plugins/flex-objects/classes/Events/FlexTaskEvent.php create mode 100644 dev/plugins/flex-objects/classes/Flex.php create mode 100644 dev/plugins/flex-objects/classes/FlexFormFactory.php create mode 100644 dev/plugins/flex-objects/classes/FlexRouter.php create mode 100644 dev/plugins/flex-objects/classes/Table/DataTable.php create mode 100644 dev/plugins/flex-objects/cli/FlexConvertDataCommand.php create mode 100644 dev/plugins/flex-objects/composer.json create mode 100644 dev/plugins/flex-objects/composer.lock create mode 100644 dev/plugins/flex-objects/css/admin.css create mode 100644 dev/plugins/flex-objects/css/admin.css.map create mode 100644 dev/plugins/flex-objects/css/admin.min.css create mode 100644 dev/plugins/flex-objects/css/site.css create mode 100644 dev/plugins/flex-objects/css/site.css.map create mode 100644 dev/plugins/flex-objects/css/site.min.css create mode 100644 dev/plugins/flex-objects/data/flex-objects/contacts.json create mode 100644 dev/plugins/flex-objects/flex-objects.php create mode 100644 dev/plugins/flex-objects/flex-objects.yaml create mode 100644 dev/plugins/flex-objects/js/flex-objects.js create mode 100644 dev/plugins/flex-objects/js/list.min.js create mode 100644 dev/plugins/flex-objects/languages/de.yaml create mode 100644 dev/plugins/flex-objects/languages/en.yaml create mode 100644 dev/plugins/flex-objects/languages/es.yaml create mode 100644 dev/plugins/flex-objects/languages/ja.yaml create mode 100644 dev/plugins/flex-objects/languages/ru.yaml create mode 100644 dev/plugins/flex-objects/package.json create mode 100644 dev/plugins/flex-objects/permissions.yaml create mode 100644 dev/plugins/flex-objects/scss/_preset.scss create mode 100644 dev/plugins/flex-objects/scss/admin.scss create mode 100644 dev/plugins/flex-objects/scss/plugin/_admin.scss create mode 100644 dev/plugins/flex-objects/scss/plugin/_site.scss create mode 100644 dev/plugins/flex-objects/scss/site.scss create mode 100644 dev/plugins/flex-objects/templates/flex-edit.html.twig create mode 100644 dev/plugins/flex-objects/templates/flex-objects.html.twig create mode 100644 dev/plugins/flex-objects/templates/flex-objects/directories/default.html.twig create mode 100644 dev/plugins/flex-objects/templates/flex-objects/page.html.twig create mode 100644 dev/plugins/flex-objects/templates/flex-objects/views/404.html.twig create mode 100644 dev/plugins/flex-objects/templates/flex-objects/views/directories.html.twig create mode 100644 dev/plugins/flex-objects/templates/flex-objects/views/directory.html.twig create mode 100644 dev/plugins/flex-objects/templates/flex-objects/views/object.html.twig create mode 100644 dev/plugins/flex-objects/templates/flex/contacts/collection/default.html.twig create mode 100644 dev/plugins/flex-objects/templates/flex/contacts/object/default.html.twig create mode 100644 dev/plugins/flex-objects/templates/flex/contacts/object/list-default.html.twig create mode 100644 dev/plugins/flex-objects/templates/flex/user-accounts/collection/default.html.twig create mode 100644 dev/plugins/flex-objects/templates/flex/user-accounts/object/default.html.twig create mode 100644 dev/plugins/flex-objects/templates/flex/user-accounts/object/list-default.html.twig create mode 100644 dev/plugins/flex-objects/templates/flex/user-groups/collection/default.html.twig create mode 100644 dev/plugins/flex-objects/templates/flex/user-groups/object/default.html.twig create mode 100644 dev/plugins/flex-objects/templates/flex/user-groups/object/list-default.html.twig create mode 100644 dev/plugins/flex-objects/templates/forms/fields/filepicker/filepicker.html.twig create mode 100644 dev/plugins/flex-objects/templates/forms/fields/list/list.html.twig create mode 100644 dev/plugins/flex-objects/templates/forms/fields/pagemedia/pagemedia.html.twig create mode 100644 dev/plugins/flex-objects/templates/forms/fields/pagemedia/template.html.twig create mode 100644 dev/plugins/flex-objects/vendor/autoload.php create mode 100644 dev/plugins/flex-objects/vendor/composer/ClassLoader.php create mode 100644 dev/plugins/flex-objects/vendor/composer/InstalledVersions.php create mode 100644 dev/plugins/flex-objects/vendor/composer/LICENSE create mode 100644 dev/plugins/flex-objects/vendor/composer/autoload_classmap.php create mode 100644 dev/plugins/flex-objects/vendor/composer/autoload_namespaces.php create mode 100644 dev/plugins/flex-objects/vendor/composer/autoload_psr4.php create mode 100644 dev/plugins/flex-objects/vendor/composer/autoload_real.php create mode 100644 dev/plugins/flex-objects/vendor/composer/autoload_static.php create mode 100644 dev/plugins/flex-objects/vendor/composer/installed.json create mode 100644 dev/plugins/flex-objects/vendor/composer/installed.php create mode 100644 dev/plugins/flex-objects/vendor/composer/platform_check.php create mode 100644 dev/plugins/flex-objects/watch.sh create mode 100644 dev/plugins/flex-objects/webpack.conf.js create mode 100644 dev/plugins/flex-objects/yarn.lock create mode 100644 dev/plugins/form/CHANGELOG.md create mode 100644 dev/plugins/form/LICENSE create mode 100644 dev/plugins/form/README.md create mode 100644 dev/plugins/form/app/fields/array.js create mode 100644 dev/plugins/form/app/fields/file.js create mode 100644 dev/plugins/form/app/fields/form.js create mode 100644 dev/plugins/form/app/fields/index.js create mode 100644 dev/plugins/form/app/fields/media.js create mode 100644 dev/plugins/form/app/fields/tabs.js create mode 100644 dev/plugins/form/app/main.js create mode 100644 dev/plugins/form/app/utils/keep-alive.js create mode 100644 dev/plugins/form/assets/dropzone.min.css create mode 100644 dev/plugins/form/assets/form-styles.css create mode 100644 dev/plugins/form/assets/form-styles.min.css create mode 100644 dev/plugins/form/assets/form.min.js create mode 100644 dev/plugins/form/assets/form.vendor.js create mode 100644 dev/plugins/form/assets/object.assign.polyfill.js create mode 100644 dev/plugins/form/assets/signature_pad.js create mode 100644 dev/plugins/form/blueprints.yaml create mode 100644 dev/plugins/form/classes/Form.php create mode 100644 dev/plugins/form/classes/FormFactory.php create mode 100644 dev/plugins/form/classes/Forms.php create mode 100644 dev/plugins/form/classes/TwigExtension.php create mode 100644 dev/plugins/form/composer.json create mode 100644 dev/plugins/form/composer.lock create mode 100644 dev/plugins/form/form.php create mode 100644 dev/plugins/form/form.yaml create mode 100644 dev/plugins/form/gulpfile.js create mode 100644 dev/plugins/form/hebe.json create mode 100644 dev/plugins/form/languages.yaml create mode 100644 dev/plugins/form/package.json create mode 100644 dev/plugins/form/scss/form-styles.scss create mode 100644 dev/plugins/form/templates/form-messages.html.twig create mode 100644 dev/plugins/form/templates/form-messages.json.twig create mode 100644 dev/plugins/form/templates/form.html.twig create mode 100644 dev/plugins/form/templates/form.json.twig create mode 100644 dev/plugins/form/templates/formdata.html.twig create mode 100644 dev/plugins/form/templates/forms/ajax.json.twig create mode 100644 dev/plugins/form/templates/forms/data.html.twig create mode 100644 dev/plugins/form/templates/forms/data.txt.twig create mode 100644 dev/plugins/form/templates/forms/default/data.html.twig create mode 100644 dev/plugins/form/templates/forms/default/data.txt.twig create mode 100644 dev/plugins/form/templates/forms/default/field.html.twig create mode 100644 dev/plugins/form/templates/forms/default/fields.html.twig create mode 100644 dev/plugins/form/templates/forms/default/form.html.twig create mode 100644 dev/plugins/form/templates/forms/default/toggleable.html.twig create mode 100644 dev/plugins/form/templates/forms/dropzone/template.html.twig create mode 100644 dev/plugins/form/templates/forms/field.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/array/array.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/avatar/avatar.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/captcha/captcha.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/checkbox/checkbox.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/checkboxes/checkboxes.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/color/color.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/column/column.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/columns/columns.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/conditional/conditional.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/date/date.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/date/edit_list.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/datetime/datetime.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/datetime/edit_list.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/display/display.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/email/email.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/fieldset/fieldset.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/file/file.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/formname/formname.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/formtask/formtask.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/hidden/hidden.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/honeypot/honeypot.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/ignore/ignore.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/key/key.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/month/month.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/nonce/nonce.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/number/number.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/password/password.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/radio/radio.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/range/range.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/section/section.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/select/select.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/select_optgroup/select_optgroup.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/signature/signature.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/spacer/spacer.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/switch/switch.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/tab/tab.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/tabs/tabs.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/tel/tel.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/text/edit_list.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/text/text.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/textarea/textarea.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/time/edit_list.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/time/time.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/toggle/edit_list.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/toggle/toggle.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/uniqueid/uniqueid.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/url/edit_list.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/url/url.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/value/value.html.twig create mode 100644 dev/plugins/form/templates/forms/fields/week/week.html.twig create mode 100644 dev/plugins/form/templates/forms/form.html.twig create mode 100644 dev/plugins/form/templates/forms/layouts/button.html.twig create mode 100644 dev/plugins/form/templates/forms/layouts/button/default-button.html.twig create mode 100644 dev/plugins/form/templates/forms/layouts/field-variables.html.twig create mode 100644 dev/plugins/form/templates/forms/layouts/field.html.twig create mode 100644 dev/plugins/form/templates/forms/layouts/field/default-field.html.twig create mode 100644 dev/plugins/form/templates/forms/layouts/form.html.twig create mode 100644 dev/plugins/form/templates/forms/layouts/form/default-form.html.twig create mode 100644 dev/plugins/form/templates/modular/form.html.twig create mode 100644 dev/plugins/form/templates/partials/form-messages.html.twig create mode 100644 dev/plugins/form/templates/partials/form-messages.json.twig create mode 100644 dev/plugins/form/vendor/autoload.php create mode 100644 dev/plugins/form/vendor/composer/ClassLoader.php create mode 100644 dev/plugins/form/vendor/composer/InstalledVersions.php create mode 100644 dev/plugins/form/vendor/composer/LICENSE create mode 100644 dev/plugins/form/vendor/composer/autoload_classmap.php create mode 100644 dev/plugins/form/vendor/composer/autoload_namespaces.php create mode 100644 dev/plugins/form/vendor/composer/autoload_psr4.php create mode 100644 dev/plugins/form/vendor/composer/autoload_real.php create mode 100644 dev/plugins/form/vendor/composer/autoload_static.php create mode 100644 dev/plugins/form/vendor/composer/installed.json create mode 100644 dev/plugins/form/vendor/composer/installed.php create mode 100644 dev/plugins/form/vendor/composer/platform_check.php create mode 100644 dev/plugins/form/vendor/google/recaptcha/.github/ISSUE_TEMPLATE/bug_report.md create mode 100644 dev/plugins/form/vendor/google/recaptcha/ARCHITECTURE.md create mode 100644 dev/plugins/form/vendor/google/recaptcha/CONTRIBUTING.md create mode 100644 dev/plugins/form/vendor/google/recaptcha/LICENSE create mode 100644 dev/plugins/form/vendor/google/recaptcha/README.md create mode 100644 dev/plugins/form/vendor/google/recaptcha/app.yaml create mode 100644 dev/plugins/form/vendor/google/recaptcha/composer.json create mode 100644 dev/plugins/form/vendor/google/recaptcha/examples/appengine-https.php create mode 100644 dev/plugins/form/vendor/google/recaptcha/examples/config.php.dist create mode 100644 dev/plugins/form/vendor/google/recaptcha/examples/examples.css create mode 100644 dev/plugins/form/vendor/google/recaptcha/examples/google0afd8760fd68f119.html create mode 100644 dev/plugins/form/vendor/google/recaptcha/examples/index.php create mode 100644 dev/plugins/form/vendor/google/recaptcha/examples/recaptcha-content-security-policy.php create mode 100644 dev/plugins/form/vendor/google/recaptcha/examples/recaptcha-v2-checkbox-explicit.php create mode 100644 dev/plugins/form/vendor/google/recaptcha/examples/recaptcha-v2-checkbox.php create mode 100644 dev/plugins/form/vendor/google/recaptcha/examples/recaptcha-v2-invisible.php create mode 100644 dev/plugins/form/vendor/google/recaptcha/examples/recaptcha-v3-request-scores.php create mode 100644 dev/plugins/form/vendor/google/recaptcha/examples/recaptcha-v3-verify.php create mode 100644 dev/plugins/form/vendor/google/recaptcha/examples/robots.txt create mode 100644 dev/plugins/form/vendor/google/recaptcha/phpunit.xml.dist create mode 100644 dev/plugins/form/vendor/google/recaptcha/src/ReCaptcha/ReCaptcha.php create mode 100644 dev/plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestMethod.php create mode 100644 dev/plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestMethod/Curl.php create mode 100644 dev/plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestMethod/CurlPost.php create mode 100644 dev/plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestMethod/Post.php create mode 100644 dev/plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestMethod/Socket.php create mode 100644 dev/plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestMethod/SocketPost.php create mode 100644 dev/plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestParameters.php create mode 100644 dev/plugins/form/vendor/google/recaptcha/src/ReCaptcha/Response.php create mode 100644 dev/plugins/form/vendor/google/recaptcha/src/autoload.php create mode 100644 dev/plugins/form/vendor/google/recaptcha/tests/ReCaptcha/ReCaptchaTest.php create mode 100644 dev/plugins/form/vendor/google/recaptcha/tests/ReCaptcha/RequestMethod/CurlPostTest.php create mode 100644 dev/plugins/form/vendor/google/recaptcha/tests/ReCaptcha/RequestMethod/PostTest.php create mode 100644 dev/plugins/form/vendor/google/recaptcha/tests/ReCaptcha/RequestMethod/SocketPostTest.php create mode 100644 dev/plugins/form/vendor/google/recaptcha/tests/ReCaptcha/RequestParametersTest.php create mode 100644 dev/plugins/form/vendor/google/recaptcha/tests/ReCaptcha/ResponseTest.php create mode 100644 dev/plugins/form/webpack.conf.js create mode 100644 dev/plugins/form/yarn.lock create mode 100644 dev/plugins/git-sync/CHANGELOG.md create mode 100644 dev/plugins/git-sync/LICENSE create mode 100644 dev/plugins/git-sync/README.md create mode 100644 dev/plugins/git-sync/app/main.js create mode 100644 dev/plugins/git-sync/app/wizard/index.js create mode 100644 dev/plugins/git-sync/blueprints.yaml create mode 100644 dev/plugins/git-sync/classes/AdminController.php create mode 100644 dev/plugins/git-sync/classes/GitSync.php create mode 100644 dev/plugins/git-sync/classes/Helper.php create mode 100644 dev/plugins/git-sync/cli/InitCommand.php create mode 100644 dev/plugins/git-sync/cli/PasswdCommand.php create mode 100644 dev/plugins/git-sync/cli/StatusCommand.php create mode 100644 dev/plugins/git-sync/cli/SyncCommand.php create mode 100644 dev/plugins/git-sync/composer.json create mode 100644 dev/plugins/git-sync/composer.lock create mode 100644 dev/plugins/git-sync/css-compiled/git-sync-icon.css create mode 100644 dev/plugins/git-sync/css-compiled/git-sync.css create mode 100644 dev/plugins/git-sync/fonts/gitsync.svg create mode 100644 dev/plugins/git-sync/fonts/gitsync.ttf create mode 100644 dev/plugins/git-sync/fonts/gitsync.woff create mode 100644 dev/plugins/git-sync/git-sync.php create mode 100644 dev/plugins/git-sync/git-sync.yaml create mode 100644 dev/plugins/git-sync/gosass.sh create mode 100644 dev/plugins/git-sync/images/gitsync-logo.png create mode 100644 dev/plugins/git-sync/images/repos/bitbucket.svg create mode 100644 dev/plugins/git-sync/images/repos/github.svg create mode 100644 dev/plugins/git-sync/images/repos/gitlab.svg create mode 100644 dev/plugins/git-sync/images/repos/gitlogo.svg create mode 100644 dev/plugins/git-sync/js/app.js create mode 100644 dev/plugins/git-sync/js/vendor.js create mode 100644 dev/plugins/git-sync/package.json create mode 100644 dev/plugins/git-sync/scss/configuration/_colors.scss create mode 100644 dev/plugins/git-sync/scss/git-sync.scss create mode 100644 dev/plugins/git-sync/scss/plugin/_wizard.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/_bourbon-deprecated-upcoming.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/_bourbon.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/addons/_border-color.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/addons/_border-radius.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/addons/_border-style.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/addons/_border-width.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/addons/_buttons.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/addons/_clearfix.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/addons/_ellipsis.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/addons/_font-stacks.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/addons/_hide-text.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/addons/_margin.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/addons/_padding.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/addons/_position.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/addons/_prefixer.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/addons/_retina-image.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/addons/_size.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/addons/_text-inputs.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/addons/_timing-functions.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/addons/_triangle.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/addons/_word-wrap.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/css3/_animation.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/css3/_appearance.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/css3/_backface-visibility.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/css3/_background-image.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/css3/_background.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/css3/_border-image.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/css3/_calc.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/css3/_columns.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/css3/_filter.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/css3/_flex-box.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/css3/_font-face.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/css3/_font-feature-settings.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/css3/_hidpi-media-query.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/css3/_hyphens.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/css3/_image-rendering.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/css3/_keyframes.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/css3/_linear-gradient.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/css3/_perspective.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/css3/_placeholder.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/css3/_radial-gradient.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/css3/_selection.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/css3/_text-decoration.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/css3/_transform.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/css3/_transition.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/css3/_user-select.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/functions/_assign-inputs.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/functions/_contains-falsy.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/functions/_contains.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/functions/_is-length.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/functions/_is-light.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/functions/_is-number.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/functions/_is-size.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/functions/_modular-scale.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/functions/_px-to-em.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/functions/_px-to-rem.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/functions/_shade.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/functions/_strip-units.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/functions/_tint.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/functions/_transition-property-name.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/functions/_unpack.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/helpers/_convert-units.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/helpers/_directional-values.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/helpers/_font-source-declaration.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/helpers/_gradient-positions-parser.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/helpers/_linear-angle-parser.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/helpers/_linear-gradient-parser.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/helpers/_linear-positions-parser.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/helpers/_linear-side-corner-parser.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/helpers/_radial-arg-parser.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/helpers/_radial-gradient-parser.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/helpers/_radial-positions-parser.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/helpers/_render-gradients.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/helpers/_shape-size-stripper.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/helpers/_str-to-num.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/settings/_asset-pipeline.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/settings/_prefixer.scss create mode 100644 dev/plugins/git-sync/scss/vendor/bourbon/settings/_px-to-em.scss create mode 100644 dev/plugins/git-sync/templates/forms/fields/enc-password/enc-password.html.twig create mode 100644 dev/plugins/git-sync/templates/forms/fields/git-wizard/git-wizard.html.twig create mode 100644 dev/plugins/git-sync/templates/partials/modal-reset.html.twig create mode 100644 dev/plugins/git-sync/templates/partials/modal-wizard.html.twig create mode 100644 dev/plugins/git-sync/vendor/autoload.php create mode 100644 dev/plugins/git-sync/vendor/bin/generate-defuse-key create mode 100644 dev/plugins/git-sync/vendor/composer/ClassLoader.php create mode 100644 dev/plugins/git-sync/vendor/composer/InstalledVersions.php create mode 100644 dev/plugins/git-sync/vendor/composer/LICENSE create mode 100644 dev/plugins/git-sync/vendor/composer/autoload_classmap.php create mode 100644 dev/plugins/git-sync/vendor/composer/autoload_namespaces.php create mode 100644 dev/plugins/git-sync/vendor/composer/autoload_psr4.php create mode 100644 dev/plugins/git-sync/vendor/composer/autoload_real.php create mode 100644 dev/plugins/git-sync/vendor/composer/autoload_static.php create mode 100644 dev/plugins/git-sync/vendor/composer/installed.json create mode 100644 dev/plugins/git-sync/vendor/composer/installed.php create mode 100644 dev/plugins/git-sync/vendor/composer/platform_check.php create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/LICENSE create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/README.md create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/bin/generate-defuse-key create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/composer.json create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/dist/Makefile create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/dist/box.json create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/dist/signingkey-new.asc create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/dist/signingkey-new.asc.sig create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/dist/signingkey.asc create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/docs/CryptoDetails.md create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/docs/FAQ.md create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/docs/InstallingAndVerifying.md create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/docs/InternalDeveloperDocs.md create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/docs/Tutorial.md create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/docs/UpgradingFromV1.2.md create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/docs/classes/Crypto.md create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/docs/classes/File.md create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/docs/classes/Key.md create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/docs/classes/KeyProtectedByPassword.md create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/src/Core.php create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/src/Crypto.php create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/src/DerivedKeys.php create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/src/Encoding.php create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/src/Exception/BadFormatException.php create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/src/Exception/CryptoException.php create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/src/Exception/EnvironmentIsBrokenException.php create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/src/Exception/IOException.php create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/src/Exception/WrongKeyOrModifiedCiphertextException.php create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/src/File.php create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/src/Key.php create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/src/KeyOrPassword.php create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/src/KeyProtectedByPassword.php create mode 100644 dev/plugins/git-sync/vendor/defuse/php-encryption/src/RuntimeTests.php create mode 100644 dev/plugins/git-sync/vendor/sebastian/git/LICENSE create mode 100644 dev/plugins/git-sync/vendor/sebastian/git/README.md create mode 100644 dev/plugins/git-sync/vendor/sebastian/git/build.xml create mode 100644 dev/plugins/git-sync/vendor/sebastian/git/composer.json create mode 100644 dev/plugins/git-sync/vendor/sebastian/git/src/Exception/Exception.php create mode 100644 dev/plugins/git-sync/vendor/sebastian/git/src/Exception/RuntimeException.php create mode 100644 dev/plugins/git-sync/vendor/sebastian/git/src/Git.php create mode 100644 dev/plugins/git-sync/watch.sh create mode 100644 dev/plugins/git-sync/webpack.conf.js create mode 100644 dev/plugins/git-sync/wizard.png create mode 100644 dev/plugins/git-sync/yarn.lock create mode 100644 dev/plugins/highlight/CHANGELOG.md create mode 100644 dev/plugins/highlight/LICENSE create mode 100644 dev/plugins/highlight/README.md create mode 100644 dev/plugins/highlight/assets/readme_1.png create mode 100644 dev/plugins/highlight/blueprints.yaml create mode 100644 dev/plugins/highlight/css/a11y-dark.css create mode 100644 dev/plugins/highlight/css/a11y-light.css create mode 100644 dev/plugins/highlight/css/agate.css create mode 100644 dev/plugins/highlight/css/an-old-hope.css create mode 100644 dev/plugins/highlight/css/androidstudio.css create mode 100644 dev/plugins/highlight/css/arduino-light.css create mode 100644 dev/plugins/highlight/css/arta.css create mode 100644 dev/plugins/highlight/css/ascetic.css create mode 100644 dev/plugins/highlight/css/atelier-cave-dark.css create mode 100644 dev/plugins/highlight/css/atelier-cave-light.css create mode 100644 dev/plugins/highlight/css/atelier-dune-dark.css create mode 100644 dev/plugins/highlight/css/atelier-dune-light.css create mode 100644 dev/plugins/highlight/css/atelier-estuary-dark.css create mode 100644 dev/plugins/highlight/css/atelier-estuary-light.css create mode 100644 dev/plugins/highlight/css/atelier-forest-dark.css create mode 100644 dev/plugins/highlight/css/atelier-forest-light.css create mode 100644 dev/plugins/highlight/css/atelier-heath-dark.css create mode 100644 dev/plugins/highlight/css/atelier-heath-light.css create mode 100644 dev/plugins/highlight/css/atelier-lakeside-dark.css create mode 100644 dev/plugins/highlight/css/atelier-lakeside-light.css create mode 100644 dev/plugins/highlight/css/atelier-plateau-dark.css create mode 100644 dev/plugins/highlight/css/atelier-plateau-light.css create mode 100644 dev/plugins/highlight/css/atelier-savanna-dark.css create mode 100644 dev/plugins/highlight/css/atelier-savanna-light.css create mode 100644 dev/plugins/highlight/css/atelier-seaside-dark.css create mode 100644 dev/plugins/highlight/css/atelier-seaside-light.css create mode 100644 dev/plugins/highlight/css/atelier-sulphurpool-dark.css create mode 100644 dev/plugins/highlight/css/atelier-sulphurpool-light.css create mode 100644 dev/plugins/highlight/css/atom-one-dark-reasonable.css create mode 100644 dev/plugins/highlight/css/atom-one-dark.css create mode 100644 dev/plugins/highlight/css/atom-one-light.css create mode 100644 dev/plugins/highlight/css/brown-paper.css create mode 100644 dev/plugins/highlight/css/brown-papersq.png create mode 100644 dev/plugins/highlight/css/codepen-embed.css create mode 100644 dev/plugins/highlight/css/color-brewer.css create mode 100644 dev/plugins/highlight/css/darcula.css create mode 100644 dev/plugins/highlight/css/dark.css create mode 100644 dev/plugins/highlight/css/default.css create mode 100644 dev/plugins/highlight/css/docco.css create mode 100644 dev/plugins/highlight/css/dracula.css create mode 100644 dev/plugins/highlight/css/far.css create mode 100644 dev/plugins/highlight/css/foundation.css create mode 100644 dev/plugins/highlight/css/github-gist.css create mode 100644 dev/plugins/highlight/css/github.css create mode 100644 dev/plugins/highlight/css/gml.css create mode 100644 dev/plugins/highlight/css/googlecode.css create mode 100644 dev/plugins/highlight/css/gradient-dark.css create mode 100644 dev/plugins/highlight/css/gradient-light.css create mode 100644 dev/plugins/highlight/css/grayscale.css create mode 100644 dev/plugins/highlight/css/gruvbox-dark.css create mode 100644 dev/plugins/highlight/css/gruvbox-light.css create mode 100644 dev/plugins/highlight/css/highlightjs-line-numbers.css create mode 100644 dev/plugins/highlight/css/hopscotch.css create mode 100644 dev/plugins/highlight/css/hybrid.css create mode 100644 dev/plugins/highlight/css/idea.css create mode 100644 dev/plugins/highlight/css/ir-black.css create mode 100644 dev/plugins/highlight/css/isbl-editor-dark.css create mode 100644 dev/plugins/highlight/css/isbl-editor-light.css create mode 100644 dev/plugins/highlight/css/kimbie.dark.css create mode 100644 dev/plugins/highlight/css/kimbie.light.css create mode 100644 dev/plugins/highlight/css/learn.css create mode 100644 dev/plugins/highlight/css/lightfair.css create mode 100644 dev/plugins/highlight/css/lioshi.css create mode 100644 dev/plugins/highlight/css/magula.css create mode 100644 dev/plugins/highlight/css/mono-blue.css create mode 100644 dev/plugins/highlight/css/monokai-sublime.css create mode 100644 dev/plugins/highlight/css/monokai.css create mode 100644 dev/plugins/highlight/css/night-owl.css create mode 100644 dev/plugins/highlight/css/nnfx-dark.css create mode 100644 dev/plugins/highlight/css/nnfx.css create mode 100644 dev/plugins/highlight/css/nord.css create mode 100644 dev/plugins/highlight/css/obsidian.css create mode 100644 dev/plugins/highlight/css/ocean.css create mode 100644 dev/plugins/highlight/css/paraiso-dark.css create mode 100644 dev/plugins/highlight/css/paraiso-light.css create mode 100644 dev/plugins/highlight/css/pojoaque.css create mode 100644 dev/plugins/highlight/css/pojoaque.jpg create mode 100644 dev/plugins/highlight/css/purebasic.css create mode 100644 dev/plugins/highlight/css/qtcreator_dark.css create mode 100644 dev/plugins/highlight/css/qtcreator_light.css create mode 100644 dev/plugins/highlight/css/railscasts.css create mode 100644 dev/plugins/highlight/css/rainbow.css create mode 100644 dev/plugins/highlight/css/routeros.css create mode 100644 dev/plugins/highlight/css/school-book.css create mode 100644 dev/plugins/highlight/css/school-book.png create mode 100644 dev/plugins/highlight/css/shades-of-purple.css create mode 100644 dev/plugins/highlight/css/solarized-dark.css create mode 100644 dev/plugins/highlight/css/solarized-light.css create mode 100644 dev/plugins/highlight/css/srcery.css create mode 100644 dev/plugins/highlight/css/stackoverflow-dark.css create mode 100644 dev/plugins/highlight/css/stackoverflow-light.css create mode 100644 dev/plugins/highlight/css/sunburst.css create mode 100644 dev/plugins/highlight/css/tomorrow-night-blue.css create mode 100644 dev/plugins/highlight/css/tomorrow-night-bright.css create mode 100644 dev/plugins/highlight/css/tomorrow-night-eighties.css create mode 100644 dev/plugins/highlight/css/tomorrow-night.css create mode 100644 dev/plugins/highlight/css/tomorrow.css create mode 100644 dev/plugins/highlight/css/vs.css create mode 100644 dev/plugins/highlight/css/vs2015.css create mode 100644 dev/plugins/highlight/css/xcode.css create mode 100644 dev/plugins/highlight/css/xt256.css create mode 100644 dev/plugins/highlight/css/zenburn.css create mode 100644 dev/plugins/highlight/hebe.json create mode 100644 dev/plugins/highlight/highlight.php create mode 100644 dev/plugins/highlight/highlight.yaml create mode 100644 dev/plugins/highlight/js/highlight.pack.js create mode 100644 dev/plugins/highlight/js/highlightjs-line-numbers.min.js create mode 100644 dev/plugins/image-captions/CHANGELOG.md create mode 100644 dev/plugins/image-captions/LICENSE create mode 100644 dev/plugins/image-captions/README.md create mode 100644 dev/plugins/image-captions/blueprints.yaml create mode 100644 dev/plugins/image-captions/composer.json create mode 100644 dev/plugins/image-captions/composer.lock create mode 100644 dev/plugins/image-captions/css/image-captions.css create mode 100644 dev/plugins/image-captions/image-captions.php create mode 100644 dev/plugins/image-captions/image-captions.yaml create mode 100644 dev/plugins/image-captions/vendor/autoload.php create mode 100644 dev/plugins/image-captions/vendor/composer/ClassLoader.php create mode 100644 dev/plugins/image-captions/vendor/composer/InstalledVersions.php create mode 100644 dev/plugins/image-captions/vendor/composer/LICENSE create mode 100644 dev/plugins/image-captions/vendor/composer/autoload_classmap.php create mode 100644 dev/plugins/image-captions/vendor/composer/autoload_namespaces.php create mode 100644 dev/plugins/image-captions/vendor/composer/autoload_psr4.php create mode 100644 dev/plugins/image-captions/vendor/composer/autoload_real.php create mode 100644 dev/plugins/image-captions/vendor/composer/autoload_static.php create mode 100644 dev/plugins/image-captions/vendor/composer/installed.json create mode 100644 dev/plugins/image-captions/vendor/composer/installed.php create mode 100644 dev/plugins/image-captions/vendor/composer/platform_check.php create mode 100644 dev/plugins/image-captions/vendor/imangazaliev/didom/CHANGELOG.md create mode 100644 dev/plugins/image-captions/vendor/imangazaliev/didom/LICENSE create mode 100644 dev/plugins/image-captions/vendor/imangazaliev/didom/README-RU.md create mode 100644 dev/plugins/image-captions/vendor/imangazaliev/didom/README.md create mode 100644 dev/plugins/image-captions/vendor/imangazaliev/didom/composer.json create mode 100644 dev/plugins/image-captions/vendor/imangazaliev/didom/composer.lock create mode 100644 dev/plugins/image-captions/vendor/imangazaliev/didom/src/DiDom/ClassAttribute.php create mode 100644 dev/plugins/image-captions/vendor/imangazaliev/didom/src/DiDom/Document.php create mode 100644 dev/plugins/image-captions/vendor/imangazaliev/didom/src/DiDom/DocumentFragment.php create mode 100644 dev/plugins/image-captions/vendor/imangazaliev/didom/src/DiDom/Element.php create mode 100644 dev/plugins/image-captions/vendor/imangazaliev/didom/src/DiDom/Encoder.php create mode 100644 dev/plugins/image-captions/vendor/imangazaliev/didom/src/DiDom/Errors.php create mode 100644 dev/plugins/image-captions/vendor/imangazaliev/didom/src/DiDom/Exceptions/InvalidSelectorException.php create mode 100644 dev/plugins/image-captions/vendor/imangazaliev/didom/src/DiDom/Node.php create mode 100644 dev/plugins/image-captions/vendor/imangazaliev/didom/src/DiDom/Query.php create mode 100644 dev/plugins/image-captions/vendor/imangazaliev/didom/src/DiDom/StyleAttribute.php create mode 100644 dev/plugins/langswitcher/CHANGELOG.md create mode 100644 dev/plugins/langswitcher/LICENSE create mode 100644 dev/plugins/langswitcher/README.md create mode 100644 dev/plugins/langswitcher/assets/readme_1.png create mode 100644 dev/plugins/langswitcher/blueprints.yaml create mode 100644 dev/plugins/langswitcher/composer.json create mode 100644 dev/plugins/langswitcher/composer.lock create mode 100644 dev/plugins/langswitcher/css/langswitcher.css create mode 100644 dev/plugins/langswitcher/langswitcher.php create mode 100644 dev/plugins/langswitcher/langswitcher.yaml create mode 100644 dev/plugins/langswitcher/languages.yaml create mode 100644 dev/plugins/langswitcher/templates/partials/langswitcher-long.html.twig create mode 100644 dev/plugins/langswitcher/templates/partials/langswitcher-short.html.twig create mode 100644 dev/plugins/langswitcher/templates/partials/langswitcher.hreflang.html.twig create mode 100644 dev/plugins/langswitcher/templates/partials/langswitcher.html.twig create mode 100644 dev/plugins/langswitcher/vendor/autoload.php create mode 100644 dev/plugins/langswitcher/vendor/composer/ClassLoader.php create mode 100644 dev/plugins/langswitcher/vendor/composer/LICENSE create mode 100644 dev/plugins/langswitcher/vendor/composer/autoload_classmap.php create mode 100644 dev/plugins/langswitcher/vendor/composer/autoload_namespaces.php create mode 100644 dev/plugins/langswitcher/vendor/composer/autoload_psr4.php create mode 100644 dev/plugins/langswitcher/vendor/composer/autoload_real.php create mode 100644 dev/plugins/langswitcher/vendor/composer/autoload_static.php create mode 100644 dev/plugins/langswitcher/vendor/composer/installed.json create mode 100644 dev/plugins/login/CHANGELOG.md create mode 100644 dev/plugins/login/LICENSE create mode 100644 dev/plugins/login/README.md create mode 100644 dev/plugins/login/blueprints.yaml create mode 100644 dev/plugins/login/classes/Controller.php create mode 100644 dev/plugins/login/classes/Events/UserLoginEvent.php create mode 100644 dev/plugins/login/classes/Invitations/Invitation.php create mode 100644 dev/plugins/login/classes/Invitations/Invitations.php create mode 100644 dev/plugins/login/classes/Login.php create mode 100644 dev/plugins/login/classes/LoginCache.php create mode 100644 dev/plugins/login/classes/RateLimiter.php create mode 100644 dev/plugins/login/classes/RememberMe/RememberMe.php create mode 100644 dev/plugins/login/classes/RememberMe/TokenStorage.php create mode 100644 dev/plugins/login/classes/TwoFactorAuth/BaconQrProvider.php create mode 100644 dev/plugins/login/classes/TwoFactorAuth/TwoFactorAuth.php create mode 100644 dev/plugins/login/cli/ChangePasswordCommand.php create mode 100644 dev/plugins/login/cli/ChangeUserStateCommand.php create mode 100644 dev/plugins/login/cli/LookupUserCommand.php create mode 100644 dev/plugins/login/cli/NewUserCommand.php create mode 100644 dev/plugins/login/composer.json create mode 100644 dev/plugins/login/composer.lock create mode 100644 dev/plugins/login/css/login.css create mode 100644 dev/plugins/login/js/2fa.js create mode 100644 dev/plugins/login/languages/de.yaml create mode 100644 dev/plugins/login/languages/en.yaml create mode 100644 dev/plugins/login/languages/es.yaml create mode 100644 dev/plugins/login/languages/fr.yaml create mode 100644 dev/plugins/login/languages/hr.yaml create mode 100644 dev/plugins/login/languages/hu.yaml create mode 100644 dev/plugins/login/languages/lt.yaml create mode 100644 dev/plugins/login/languages/no.yaml create mode 100644 dev/plugins/login/languages/pt-BR.yaml create mode 100644 dev/plugins/login/languages/ro.yaml create mode 100644 dev/plugins/login/languages/ru.yaml create mode 100644 dev/plugins/login/languages/uk.yaml create mode 100644 dev/plugins/login/languages/zh.yaml create mode 100644 dev/plugins/login/login.php create mode 100644 dev/plugins/login/login.yaml create mode 100644 dev/plugins/login/templates/forgot.html.twig create mode 100644 dev/plugins/login/templates/forms/fields/2fa_secret/2fa_secret.html.twig create mode 100644 dev/plugins/login/templates/login.html.twig create mode 100644 dev/plugins/login/templates/login.json.twig create mode 100644 dev/plugins/login/templates/partials/forgot-form.html.twig create mode 100644 dev/plugins/login/templates/partials/login-form.html.twig create mode 100644 dev/plugins/login/templates/partials/login-status.html.twig create mode 100644 dev/plugins/login/templates/partials/login-twofa.html.twig create mode 100644 dev/plugins/login/templates/partials/reset-form.html.twig create mode 100644 dev/plugins/login/templates/profile.html.twig create mode 100644 dev/plugins/login/templates/profile.json.twig create mode 100644 dev/plugins/login/templates/register.html.twig create mode 100644 dev/plugins/login/templates/reset.html.twig create mode 100644 dev/plugins/login/templates/unauthorized.html.twig create mode 100644 dev/plugins/login/vendor/autoload.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/CHANGELOG.md create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/LICENSE create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/Module.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/README.md create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/autoload_classmap.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/autoload_function.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/autoload_register.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/composer.json create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/AbstractEnum.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitArray.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitMatrix.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitUtils.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/CharacterSetEci.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlock.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlocks.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/ErrorCorrectionLevel.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/FormatInformation.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/Mode.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/ReedSolomonCodec.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/Version.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/BlockPair.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/ByteMatrix.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/Encoder.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MaskUtil.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MatrixUtil.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/QrCode.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/ExceptionInterface.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/InvalidArgumentException.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/OutOfBoundsException.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/RuntimeException.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/UnexpectedValueException.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/WriterException.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Cmyk.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/ColorInterface.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Gray.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Rgb.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/AbstractRenderer.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Decorator/DecoratorInterface.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Decorator/FinderPattern.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Eps.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Png.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/RendererInterface.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Svg.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/RendererInterface.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Text/Html.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Text/Plain.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/BaconQrCode/Writer.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Common/BitArray.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Common/BitMatrix.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Common/BitUtils.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Common/CharacterSetEci.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Common/EcBlock.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Common/EcBlocks.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Common/ErrorCorrectionLevel.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Common/FormatInformation.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Common/Mode.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Common/ReedSolomonCodec.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Common/Version.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/BlockPair.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/ByteMatrix.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/Encoder.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/MaskUtil.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/MatrixUtil.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/QrCode.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Exception/ExceptionInterface.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Exception/InvalidArgumentException.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Exception/OutOfBoundsException.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Exception/RuntimeException.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Exception/UnexpectedValueException.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Exception/WriterException.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Color/Alpha.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Color/Cmyk.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Color/ColorInterface.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Color/Gray.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Color/Rgb.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Eye/CompositeEye.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Eye/EyeInterface.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Eye/ModuleEye.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Eye/SimpleCircleEye.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Eye/SquareEye.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Image/EpsImageBackEnd.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Image/ImageBackEndInterface.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Image/ImagickImageBackEnd.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Image/SvgImageBackEnd.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Image/TransformationMatrix.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/ImageRenderer.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/DotsModule.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/Edge.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/EdgeIterator.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/ModuleInterface.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/RoundnessModule.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/SquareModule.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/Close.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/Curve.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/EllipticArc.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/Line.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/Move.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/OperationInterface.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/Path.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/PlainTextRenderer.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/RendererInterface.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/EyeFill.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Fill.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Gradient.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/GradientType.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/RendererStyle.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/src/Writer.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitArrayTest.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitMatrixTest.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/BitUtilsTest.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ErrorCorrectionLevelTest.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/FormatInformationTest.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ModeTest.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/ReedSolomonCodecTest.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Common/VersionTest.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/EncoderTest.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/MaskUtilTest.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Encoder/MatrixUtilTest.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Renderer/Text/HtmlTest.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/tests/BaconQrCode/Renderer/Text/TextTest.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/tests/bootstrap.php create mode 100644 dev/plugins/login/vendor/bacon/bacon-qr-code/tests/phpunit.xml create mode 100644 dev/plugins/login/vendor/birke/rememberme/LICENSE create mode 100644 dev/plugins/login/vendor/birke/rememberme/README.md create mode 100644 dev/plugins/login/vendor/birke/rememberme/composer.json create mode 100644 dev/plugins/login/vendor/birke/rememberme/example/action.php create mode 100644 dev/plugins/login/vendor/birke/rememberme/example/css/style.css create mode 100644 dev/plugins/login/vendor/birke/rememberme/example/index.php create mode 100644 dev/plugins/login/vendor/birke/rememberme/example/templates/cookie_was_stolen.php create mode 100644 dev/plugins/login/vendor/birke/rememberme/example/templates/login.php create mode 100644 dev/plugins/login/vendor/birke/rememberme/example/templates/user_is_logged_in.php create mode 100644 dev/plugins/login/vendor/birke/rememberme/example/tokens/.gitkeep create mode 100644 dev/plugins/login/vendor/birke/rememberme/phpunit.xml create mode 100644 dev/plugins/login/vendor/birke/rememberme/src/Rememberme/Authenticator.php create mode 100644 dev/plugins/login/vendor/birke/rememberme/src/Rememberme/Cookie.php create mode 100644 dev/plugins/login/vendor/birke/rememberme/src/Rememberme/Storage/DB.php create mode 100644 dev/plugins/login/vendor/birke/rememberme/src/Rememberme/Storage/File.php create mode 100644 dev/plugins/login/vendor/birke/rememberme/src/Rememberme/Storage/PDO.php create mode 100644 dev/plugins/login/vendor/birke/rememberme/src/Rememberme/Storage/StorageInterface.php create mode 100644 dev/plugins/login/vendor/birke/rememberme/test/CookieTest.php create mode 100644 dev/plugins/login/vendor/birke/rememberme/test/RemembermeTest.php create mode 100644 dev/plugins/login/vendor/birke/rememberme/test/Storage/PDO.php create mode 100644 dev/plugins/login/vendor/birke/rememberme/test/Storage/tokens.xml create mode 100644 dev/plugins/login/vendor/birke/rememberme/test/bootstrap.php create mode 100644 dev/plugins/login/vendor/composer/ClassLoader.php create mode 100644 dev/plugins/login/vendor/composer/InstalledVersions.php create mode 100644 dev/plugins/login/vendor/composer/LICENSE create mode 100644 dev/plugins/login/vendor/composer/autoload_classmap.php create mode 100644 dev/plugins/login/vendor/composer/autoload_files.php create mode 100644 dev/plugins/login/vendor/composer/autoload_namespaces.php create mode 100644 dev/plugins/login/vendor/composer/autoload_psr4.php create mode 100644 dev/plugins/login/vendor/composer/autoload_real.php create mode 100644 dev/plugins/login/vendor/composer/autoload_static.php create mode 100644 dev/plugins/login/vendor/composer/installed.json create mode 100644 dev/plugins/login/vendor/composer/installed.php create mode 100644 dev/plugins/login/vendor/composer/platform_check.php create mode 100644 dev/plugins/login/vendor/dasprid/enum/.coveralls.yml create mode 100644 dev/plugins/login/vendor/dasprid/enum/README.md create mode 100644 dev/plugins/login/vendor/dasprid/enum/composer.json create mode 100644 dev/plugins/login/vendor/dasprid/enum/phpcs.xml create mode 100644 dev/plugins/login/vendor/dasprid/enum/phpunit.xml.dist create mode 100644 dev/plugins/login/vendor/dasprid/enum/src/AbstractEnum.php create mode 100644 dev/plugins/login/vendor/dasprid/enum/src/EnumMap.php create mode 100644 dev/plugins/login/vendor/dasprid/enum/src/Exception/CloneNotSupportedException.php create mode 100644 dev/plugins/login/vendor/dasprid/enum/src/Exception/ExceptionInterface.php create mode 100644 dev/plugins/login/vendor/dasprid/enum/src/Exception/ExpectationException.php create mode 100644 dev/plugins/login/vendor/dasprid/enum/src/Exception/IllegalArgumentException.php create mode 100644 dev/plugins/login/vendor/dasprid/enum/src/Exception/MismatchException.php create mode 100644 dev/plugins/login/vendor/dasprid/enum/src/Exception/SerializeNotSupportedException.php create mode 100644 dev/plugins/login/vendor/dasprid/enum/src/Exception/UnserializeNotSupportedException.php create mode 100644 dev/plugins/login/vendor/dasprid/enum/src/NullValue.php create mode 100644 dev/plugins/login/vendor/dasprid/enum/test/AbstractEnumTest.php create mode 100644 dev/plugins/login/vendor/dasprid/enum/test/EnumMapTest.php create mode 100644 dev/plugins/login/vendor/dasprid/enum/test/NullValueTest.php create mode 100644 dev/plugins/login/vendor/dasprid/enum/test/Planet.php create mode 100644 dev/plugins/login/vendor/dasprid/enum/test/WeekDay.php create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/CHANGELOG.md create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/LICENSE create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/RATIONALE.md create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/README.md create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/SECURITY.md create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/build-phar.sh create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/composer.json create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/lib/byte_safe_strings.php create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/lib/cast_to_int.php create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/lib/error_polyfill.php create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/lib/random.php create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/lib/random_bytes_openssl.php create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/lib/random_int.php create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/other/build_phar.php create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/other/ide_stubs/COM.php create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/other/ide_stubs/README.md create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/other/ide_stubs/com_exception.php create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/other/ide_stubs/libsodium.php create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/psalm-autoload.php create mode 100644 dev/plugins/login/vendor/paragonie/random_compat/psalm.xml create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/.github/FUNDING.yml create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/LICENSE create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/README.md create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/TwoFactorAuth.phpproj create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/TwoFactorAuth.sln create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/composer.json create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/demo/demo.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/demo/loader.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/BaconQrCodeProvider.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/BaseHTTPQRCodeProvider.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/EndroidQrCodeProvider.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/EndroidQrCodeWithLogoProvider.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/IQRCodeProvider.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/ImageChartsQRCodeProvider.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/QRException.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/QRServerProvider.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/QRicketProvider.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Rng/CSRNGProvider.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Rng/HashRNGProvider.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Rng/IRNGProvider.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Rng/MCryptRNGProvider.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Rng/OpenSSLRNGProvider.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Rng/RNGException.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Time/HttpTimeProvider.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Time/ITimeProvider.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Time/LocalMachineTimeProvider.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Time/NTPTimeProvider.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/lib/Providers/Time/TimeException.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/lib/TwoFactorAuth.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/lib/TwoFactorAuthException.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/logo.png create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/multifactorauthforeveryone.png create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/phpunit.xml create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/tests/MightNotMakeAssertions.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/tests/Providers/Qr/IQRCodeProviderTest.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/tests/Providers/Qr/TestQrProvider.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/tests/Providers/Rng/CSRNGProviderTest.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/tests/Providers/Rng/HashRNGProviderTest.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/tests/Providers/Rng/IRNGProviderTest.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/tests/Providers/Rng/MCryptRNGProviderTest.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/tests/Providers/Rng/NeedsRngLengths.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/tests/Providers/Rng/OpenSSLRNGProviderTest.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/tests/Providers/Rng/TestRNGProvider.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/tests/Providers/Time/ITimeProviderTest.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/tests/Providers/Time/TestTimeProvider.php create mode 100644 dev/plugins/login/vendor/robthree/twofactorauth/tests/TwoFactorAuthTest.php create mode 100644 dev/plugins/markdown-notices/CHANGELOG.md create mode 100644 dev/plugins/markdown-notices/LICENSE create mode 100644 dev/plugins/markdown-notices/README.md create mode 100644 dev/plugins/markdown-notices/assets/notices.css create mode 100644 dev/plugins/markdown-notices/assets/screenshot.png create mode 100644 dev/plugins/markdown-notices/blueprints.yaml create mode 100644 dev/plugins/markdown-notices/composer.json create mode 100644 dev/plugins/markdown-notices/composer.lock create mode 100644 dev/plugins/markdown-notices/languages.yaml create mode 100644 dev/plugins/markdown-notices/markdown-notices.php create mode 100644 dev/plugins/markdown-notices/markdown-notices.yaml create mode 100644 dev/plugins/markdown-notices/vendor/autoload.php create mode 100644 dev/plugins/markdown-notices/vendor/composer/ClassLoader.php create mode 100644 dev/plugins/markdown-notices/vendor/composer/LICENSE create mode 100644 dev/plugins/markdown-notices/vendor/composer/autoload_classmap.php create mode 100644 dev/plugins/markdown-notices/vendor/composer/autoload_namespaces.php create mode 100644 dev/plugins/markdown-notices/vendor/composer/autoload_psr4.php create mode 100644 dev/plugins/markdown-notices/vendor/composer/autoload_real.php create mode 100644 dev/plugins/markdown-notices/vendor/composer/autoload_static.php create mode 100644 dev/plugins/markdown-notices/vendor/composer/installed.json create mode 100644 dev/plugins/presentation-deckset/CHANGELOG.md create mode 100644 dev/plugins/presentation-deckset/LICENSE create mode 100644 dev/plugins/presentation-deckset/README.md create mode 100644 dev/plugins/presentation-deckset/blueprints.yaml create mode 100644 dev/plugins/presentation-deckset/classes/DecksetParser.php create mode 100644 dev/plugins/presentation-deckset/languages.yaml create mode 100644 dev/plugins/presentation-deckset/presentation-deckset.php create mode 100644 dev/plugins/presentation-deckset/presentation-deckset.yaml create mode 100644 dev/plugins/presentation/ADVANCED.md create mode 100644 dev/plugins/presentation/CHANGELOG.md create mode 100644 dev/plugins/presentation/CONTRIBUTING.md create mode 100644 dev/plugins/presentation/LICENSE create mode 100644 dev/plugins/presentation/README.md create mode 100644 dev/plugins/presentation/blueprints.yaml create mode 100644 dev/plugins/presentation/blueprints/presentation.yaml create mode 100644 dev/plugins/presentation/blueprints/slide.yaml create mode 100644 dev/plugins/presentation/classes/Content.php create mode 100644 dev/plugins/presentation/classes/ContentInterface.php create mode 100644 dev/plugins/presentation/classes/Parser.php create mode 100644 dev/plugins/presentation/classes/ParserInterface.php create mode 100644 dev/plugins/presentation/classes/Poll.php create mode 100644 dev/plugins/presentation/classes/PollInterface.php create mode 100644 dev/plugins/presentation/classes/Transport.php create mode 100644 dev/plugins/presentation/classes/TransportInterface.php create mode 100644 dev/plugins/presentation/classes/Utilities.php create mode 100644 dev/plugins/presentation/composer.json create mode 100644 dev/plugins/presentation/composer.lock create mode 100644 dev/plugins/presentation/css/paper.css create mode 100644 dev/plugins/presentation/css/presentation.css create mode 100644 dev/plugins/presentation/css/transition.css create mode 100644 dev/plugins/presentation/js/broadcast.js create mode 100644 dev/plugins/presentation/js/modular-scale.js create mode 100644 dev/plugins/presentation/js/modular-scale.package.js create mode 100644 dev/plugins/presentation/js/poll.js create mode 100644 dev/plugins/presentation/js/presentation.js create mode 100644 dev/plugins/presentation/js/save.js create mode 100644 dev/plugins/presentation/languages.yaml create mode 100644 dev/plugins/presentation/node_modules/axios/dist/axios.js create mode 100644 dev/plugins/presentation/node_modules/axios/dist/axios.min.js create mode 100644 dev/plugins/presentation/node_modules/codemirror/lib/codemirror.js create mode 100644 dev/plugins/presentation/node_modules/js-base64/base64.min.js create mode 100644 dev/plugins/presentation/node_modules/reveal.js/Gruntfile.js create mode 100644 dev/plugins/presentation/node_modules/reveal.js/css/print/paper.css create mode 100644 dev/plugins/presentation/node_modules/reveal.js/css/print/pdf.css create mode 100644 dev/plugins/presentation/node_modules/reveal.js/css/reveal.css create mode 100644 dev/plugins/presentation/node_modules/reveal.js/css/theme/beige.css create mode 100644 dev/plugins/presentation/node_modules/reveal.js/css/theme/black.css create mode 100644 dev/plugins/presentation/node_modules/reveal.js/css/theme/blood.css create mode 100644 dev/plugins/presentation/node_modules/reveal.js/css/theme/league.css create mode 100644 dev/plugins/presentation/node_modules/reveal.js/css/theme/moon.css create mode 100644 dev/plugins/presentation/node_modules/reveal.js/css/theme/night.css create mode 100644 dev/plugins/presentation/node_modules/reveal.js/css/theme/serif.css create mode 100644 dev/plugins/presentation/node_modules/reveal.js/css/theme/simple.css create mode 100644 dev/plugins/presentation/node_modules/reveal.js/css/theme/sky.css create mode 100644 dev/plugins/presentation/node_modules/reveal.js/css/theme/solarized.css create mode 100644 dev/plugins/presentation/node_modules/reveal.js/css/theme/white.css create mode 100644 dev/plugins/presentation/node_modules/reveal.js/js/reveal.js create mode 100644 dev/plugins/presentation/node_modules/reveal.js/lib/font/league-gothic/LICENSE create mode 100644 dev/plugins/presentation/node_modules/reveal.js/lib/font/league-gothic/league-gothic.css create mode 100644 dev/plugins/presentation/node_modules/reveal.js/lib/font/league-gothic/league-gothic.eot create mode 100644 dev/plugins/presentation/node_modules/reveal.js/lib/font/league-gothic/league-gothic.ttf create mode 100644 dev/plugins/presentation/node_modules/reveal.js/lib/font/league-gothic/league-gothic.woff create mode 100644 dev/plugins/presentation/node_modules/reveal.js/lib/font/source-sans-pro/LICENSE create mode 100644 dev/plugins/presentation/node_modules/reveal.js/lib/font/source-sans-pro/source-sans-pro-italic.eot create mode 100644 dev/plugins/presentation/node_modules/reveal.js/lib/font/source-sans-pro/source-sans-pro-italic.ttf create mode 100644 dev/plugins/presentation/node_modules/reveal.js/lib/font/source-sans-pro/source-sans-pro-italic.woff create mode 100644 dev/plugins/presentation/node_modules/reveal.js/lib/font/source-sans-pro/source-sans-pro-regular.eot create mode 100644 dev/plugins/presentation/node_modules/reveal.js/lib/font/source-sans-pro/source-sans-pro-regular.ttf create mode 100644 dev/plugins/presentation/node_modules/reveal.js/lib/font/source-sans-pro/source-sans-pro-regular.woff create mode 100644 dev/plugins/presentation/node_modules/reveal.js/lib/font/source-sans-pro/source-sans-pro-semibold.eot create mode 100644 dev/plugins/presentation/node_modules/reveal.js/lib/font/source-sans-pro/source-sans-pro-semibold.ttf create mode 100644 dev/plugins/presentation/node_modules/reveal.js/lib/font/source-sans-pro/source-sans-pro-semibold.woff create mode 100644 dev/plugins/presentation/node_modules/reveal.js/lib/font/source-sans-pro/source-sans-pro-semibolditalic.eot create mode 100644 dev/plugins/presentation/node_modules/reveal.js/lib/font/source-sans-pro/source-sans-pro-semibolditalic.ttf create mode 100644 dev/plugins/presentation/node_modules/reveal.js/lib/font/source-sans-pro/source-sans-pro-semibolditalic.woff create mode 100644 dev/plugins/presentation/node_modules/reveal.js/lib/font/source-sans-pro/source-sans-pro.css create mode 100644 dev/plugins/presentation/node_modules/reveal.js/lib/js/html5shiv.js create mode 100644 dev/plugins/presentation/node_modules/reveal.js/plugin/highlight/highlight.js create mode 100644 dev/plugins/presentation/node_modules/reveal.js/plugin/markdown/markdown.js create mode 100644 dev/plugins/presentation/node_modules/reveal.js/plugin/markdown/marked.js create mode 100644 dev/plugins/presentation/node_modules/reveal.js/plugin/math/math.js create mode 100644 dev/plugins/presentation/node_modules/reveal.js/plugin/multiplex/client.js create mode 100644 dev/plugins/presentation/node_modules/reveal.js/plugin/multiplex/index.js create mode 100644 dev/plugins/presentation/node_modules/reveal.js/plugin/multiplex/master.js create mode 100644 dev/plugins/presentation/node_modules/reveal.js/plugin/notes-server/client.js create mode 100644 dev/plugins/presentation/node_modules/reveal.js/plugin/notes-server/index.js create mode 100644 dev/plugins/presentation/node_modules/reveal.js/plugin/notes/notes.js create mode 100644 dev/plugins/presentation/node_modules/reveal.js/plugin/print-pdf/print-pdf.js create mode 100644 dev/plugins/presentation/node_modules/reveal.js/plugin/search/search.js create mode 100644 dev/plugins/presentation/node_modules/reveal.js/plugin/zoom-js/zoom.js create mode 100644 dev/plugins/presentation/node_modules/reveal.js/test/qunit-2.5.0.js create mode 100644 dev/plugins/presentation/node_modules/reveal.js/test/test-markdown-element-attributes.js create mode 100644 dev/plugins/presentation/node_modules/reveal.js/test/test-markdown-external.js create mode 100644 dev/plugins/presentation/node_modules/reveal.js/test/test-markdown-options.js create mode 100644 dev/plugins/presentation/node_modules/reveal.js/test/test-markdown-slide-attributes.js create mode 100644 dev/plugins/presentation/node_modules/reveal.js/test/test-markdown.js create mode 100644 dev/plugins/presentation/node_modules/reveal.js/test/test-pdf.js create mode 100644 dev/plugins/presentation/node_modules/reveal.js/test/test.js create mode 100644 dev/plugins/presentation/package-lock.json create mode 100644 dev/plugins/presentation/package.json create mode 100644 dev/plugins/presentation/pnpm-lock.yaml create mode 100644 dev/plugins/presentation/presentation.php create mode 100644 dev/plugins/presentation/presentation.yaml create mode 100644 dev/plugins/presentation/scss/_normalize.scss create mode 100644 dev/plugins/presentation/scss/paper.scss create mode 100644 dev/plugins/presentation/scss/presentation.scss create mode 100644 dev/plugins/presentation/shortcodes/LinkOverlayShortcode.php create mode 100644 dev/plugins/presentation/shortcodes/PresentationShortcode.php create mode 100644 dev/plugins/presentation/templates/forms/fields/presentation_button_bar/presentation_button_bar.html.twig create mode 100644 dev/plugins/presentation/templates/forms/fields/presentation_dropdown/presentation_dropdown.html.twig create mode 100644 dev/plugins/presentation/templates/partials/presentation_footer.html.twig create mode 100644 dev/plugins/presentation/templates/partials/presentation_iframe.html.twig create mode 100644 dev/plugins/presentation/templates/partials/presentation_link_overlay.html.twig create mode 100644 dev/plugins/presentation/templates/presentation.html.twig create mode 100644 dev/plugins/presentation/templates/slide.html.twig create mode 100644 dev/plugins/presentation/twig/CallStaticExtension.php create mode 100644 dev/plugins/presentation/twig/FileFinderExtension.php create mode 100644 dev/plugins/presentation/vendor/autoload.php create mode 100644 dev/plugins/presentation/vendor/composer/ClassLoader.php create mode 100644 dev/plugins/presentation/vendor/composer/LICENSE create mode 100644 dev/plugins/presentation/vendor/composer/autoload_classmap.php create mode 100644 dev/plugins/presentation/vendor/composer/autoload_namespaces.php create mode 100644 dev/plugins/presentation/vendor/composer/autoload_psr4.php create mode 100644 dev/plugins/presentation/vendor/composer/autoload_real.php create mode 100644 dev/plugins/presentation/vendor/composer/autoload_static.php create mode 100644 dev/plugins/presentation/vendor/composer/installed.json create mode 100644 dev/plugins/presentation/vendor/composer/installers/LICENSE create mode 100644 dev/plugins/presentation/vendor/composer/installers/composer.json create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/AglInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/AimeosInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/AnnotateCmsInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/AsgardInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/AttogramInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/BaseInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/BitrixInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/BonefishInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/CakePHPInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/ChefInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/CiviCrmInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/ClanCatsFrameworkInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/CockpitInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/CodeIgniterInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/Concrete5Installer.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/CraftInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/CroogoInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/DecibelInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/DokuWikiInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/DolibarrInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/DrupalInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/ElggInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/EliasisInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/ExpressionEngineInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/EzPlatformInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/FuelInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/FuelphpInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/GravInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/HuradInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/ImageCMSInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/Installer.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/ItopInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/JoomlaInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/KanboardInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/KirbyInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/KodiCMSInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/KohanaInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/LanManagementSystemInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/LaravelInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/LavaLiteInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/LithiumInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/MODULEWorkInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/MODXEvoInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/MagentoInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/MajimaInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/MakoInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/MauticInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/MayaInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/MediaWikiInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/MicroweberInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/ModxInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/MoodleInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/OctoberInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/OntoWikiInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/OsclassInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/OxidInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/PPIInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/PhiftyInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/PhpBBInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/PimcoreInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/PiwikInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/PlentymarketsInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/Plugin.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/PortoInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/PrestashopInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/PuppetInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/PxcmsInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/RadPHPInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/ReIndexInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/RedaxoInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/RoundcubeInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/SMFInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/ShopwareInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/SilverStripeInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/SiteDirectInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/SyDESInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/Symfony1Installer.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/TYPO3CmsInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/TYPO3FlowInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/TheliaInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/TuskInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/UserFrostingInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/VanillaInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/VgmcpInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/WHMCSInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/WolfCMSInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/WordPressInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/YawikInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/ZendInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/Composer/Installers/ZikulaInstaller.php create mode 100644 dev/plugins/presentation/vendor/composer/installers/src/bootstrap.php create mode 100644 dev/plugins/presentation/vendor/michelf/php-smartypants/License.md create mode 100644 dev/plugins/presentation/vendor/michelf/php-smartypants/Michelf/SmartyPants.inc.php create mode 100644 dev/plugins/presentation/vendor/michelf/php-smartypants/Michelf/SmartyPants.php create mode 100644 dev/plugins/presentation/vendor/michelf/php-smartypants/Michelf/SmartyPantsTypographer.inc.php create mode 100644 dev/plugins/presentation/vendor/michelf/php-smartypants/Michelf/SmartyPantsTypographer.php create mode 100644 dev/plugins/presentation/vendor/michelf/php-smartypants/Readme.md create mode 100644 dev/plugins/presentation/vendor/michelf/php-smartypants/Readme.php create mode 100644 dev/plugins/presentation/vendor/michelf/php-smartypants/composer.json create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/CHANGELOG.md create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/LICENSE create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/Makefile create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/README.md create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/composer.json create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/docker-compose.yaml create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/docker/php-5.4/Dockerfile create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/phpunit.xml.dist create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Event/FilterShortcodesEvent.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Event/ReplaceShortcodesEvent.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/EventContainer/EventContainer.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/EventContainer/EventContainerInterface.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/EventHandler/FilterRawEventHandler.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/EventHandler/ReplaceJoinEventHandler.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Events.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Handler/ContentHandler.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Handler/DeclareHandler.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Handler/EmailHandler.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Handler/NameHandler.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Handler/NullHandler.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Handler/PlaceholderHandler.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Handler/RawHandler.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Handler/SerializerHandler.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Handler/UrlHandler.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Handler/WrapHandler.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/HandlerContainer/HandlerContainer.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/HandlerContainer/HandlerContainerInterface.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/HandlerContainer/ImmutableHandlerContainer.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Parser/ParserInterface.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Parser/RegexParser.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Parser/RegularParser.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Parser/WordpressParser.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Processor/Processor.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Processor/ProcessorContext.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Processor/ProcessorInterface.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Serializer/JsonSerializer.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Serializer/SerializerInterface.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Serializer/TextSerializer.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Serializer/XmlSerializer.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Serializer/YamlSerializer.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Shortcode/AbstractShortcode.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Shortcode/ParsedShortcode.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Shortcode/ParsedShortcodeInterface.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Shortcode/ProcessedShortcode.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Shortcode/ReplacedShortcode.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Shortcode/Shortcode.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Shortcode/ShortcodeInterface.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/ShortcodeFacade.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Syntax/CommonSyntax.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Syntax/Syntax.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Syntax/SyntaxBuilder.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Syntax/SyntaxInterface.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/src/Utility/RegexBuilderUtility.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/tests/AbstractTestCase.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/tests/EventsTest.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/tests/FacadeTest.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/tests/Fake/ReverseShortcode.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/tests/HandlerContainerTest.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/tests/ParserTest.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/tests/ProcessorTest.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/tests/SerializerTest.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/tests/ShortcodeTest.php create mode 100644 dev/plugins/presentation/vendor/thunderer/shortcode/tests/SyntaxTest.php create mode 100644 dev/plugins/problems/CHANGELOG.md create mode 100644 dev/plugins/problems/LICENSE create mode 100644 dev/plugins/problems/README.md create mode 100644 dev/plugins/problems/assets/cli.png create mode 100644 dev/plugins/problems/assets/code-3.svg create mode 100644 dev/plugins/problems/assets/grav-logo.svg create mode 100644 dev/plugins/problems/assets/heart.svg create mode 100644 dev/plugins/problems/assets/readme_1.jpg create mode 100644 dev/plugins/problems/blueprints.yaml create mode 100644 dev/plugins/problems/classes/Problems/Apache.php create mode 100644 dev/plugins/problems/classes/Problems/Base/Problem.php create mode 100644 dev/plugins/problems/classes/Problems/Base/ProblemChecker.php create mode 100644 dev/plugins/problems/classes/Problems/EssentialFolders.php create mode 100644 dev/plugins/problems/classes/Problems/PHPModules.php create mode 100644 dev/plugins/problems/classes/Problems/PHPVersion.php create mode 100644 dev/plugins/problems/classes/Problems/Permissions.php create mode 100644 dev/plugins/problems/cli/CheckCommand.php create mode 100644 dev/plugins/problems/composer.json create mode 100644 dev/plugins/problems/composer.lock create mode 100644 dev/plugins/problems/css/admin.css create mode 100644 dev/plugins/problems/css/admin.min.css create mode 100644 dev/plugins/problems/css/spectre-icons.css create mode 100644 dev/plugins/problems/css/spectre-icons.min.css create mode 100644 dev/plugins/problems/css/spectre.css create mode 100644 dev/plugins/problems/css/spectre.min.css create mode 100644 dev/plugins/problems/gulpfile.js create mode 100644 dev/plugins/problems/languages.yaml create mode 100644 dev/plugins/problems/package.json create mode 100644 dev/plugins/problems/problems.php create mode 100644 dev/plugins/problems/problems.yaml create mode 100644 dev/plugins/problems/scss/_accordions.scss create mode 100644 dev/plugins/problems/scss/_animations.scss create mode 100644 dev/plugins/problems/scss/_asian.scss create mode 100644 dev/plugins/problems/scss/_autocomplete.scss create mode 100644 dev/plugins/problems/scss/_avatars.scss create mode 100644 dev/plugins/problems/scss/_badges.scss create mode 100644 dev/plugins/problems/scss/_bars.scss create mode 100644 dev/plugins/problems/scss/_base.scss create mode 100644 dev/plugins/problems/scss/_breadcrumbs.scss create mode 100644 dev/plugins/problems/scss/_buttons.scss create mode 100644 dev/plugins/problems/scss/_calendars.scss create mode 100644 dev/plugins/problems/scss/_cards.scss create mode 100644 dev/plugins/problems/scss/_carousels.scss create mode 100644 dev/plugins/problems/scss/_chips.scss create mode 100644 dev/plugins/problems/scss/_codes.scss create mode 100644 dev/plugins/problems/scss/_comparison-sliders.scss create mode 100644 dev/plugins/problems/scss/_dropdowns.scss create mode 100644 dev/plugins/problems/scss/_empty.scss create mode 100644 dev/plugins/problems/scss/_filters.scss create mode 100644 dev/plugins/problems/scss/_forms.scss create mode 100644 dev/plugins/problems/scss/_icons.scss create mode 100644 dev/plugins/problems/scss/_labels.scss create mode 100644 dev/plugins/problems/scss/_layout.scss create mode 100644 dev/plugins/problems/scss/_media.scss create mode 100644 dev/plugins/problems/scss/_menus.scss create mode 100644 dev/plugins/problems/scss/_meters.scss create mode 100644 dev/plugins/problems/scss/_mixins.scss create mode 100644 dev/plugins/problems/scss/_modals.scss create mode 100644 dev/plugins/problems/scss/_navbar.scss create mode 100644 dev/plugins/problems/scss/_navs.scss create mode 100644 dev/plugins/problems/scss/_normalize.scss create mode 100644 dev/plugins/problems/scss/_off-canvas.scss create mode 100644 dev/plugins/problems/scss/_pagination.scss create mode 100644 dev/plugins/problems/scss/_panels.scss create mode 100644 dev/plugins/problems/scss/_parallax.scss create mode 100644 dev/plugins/problems/scss/_popovers.scss create mode 100644 dev/plugins/problems/scss/_preset.scss create mode 100644 dev/plugins/problems/scss/_problems.scss create mode 100644 dev/plugins/problems/scss/_progress.scss create mode 100644 dev/plugins/problems/scss/_sliders.scss create mode 100644 dev/plugins/problems/scss/_steps.scss create mode 100644 dev/plugins/problems/scss/_tables.scss create mode 100644 dev/plugins/problems/scss/_tabs.scss create mode 100644 dev/plugins/problems/scss/_tiles.scss create mode 100644 dev/plugins/problems/scss/_timelines.scss create mode 100644 dev/plugins/problems/scss/_toasts.scss create mode 100644 dev/plugins/problems/scss/_tooltips.scss create mode 100644 dev/plugins/problems/scss/_typography.scss create mode 100644 dev/plugins/problems/scss/_utilities.scss create mode 100644 dev/plugins/problems/scss/_variables.scss create mode 100644 dev/plugins/problems/scss/admin.scss create mode 100644 dev/plugins/problems/scss/icons/_icons-action.scss create mode 100644 dev/plugins/problems/scss/icons/_icons-core.scss create mode 100644 dev/plugins/problems/scss/icons/_icons-navigation.scss create mode 100644 dev/plugins/problems/scss/icons/_icons-object.scss create mode 100644 dev/plugins/problems/scss/mixins/_avatar.scss create mode 100644 dev/plugins/problems/scss/mixins/_button.scss create mode 100644 dev/plugins/problems/scss/mixins/_clearfix.scss create mode 100644 dev/plugins/problems/scss/mixins/_color.scss create mode 100644 dev/plugins/problems/scss/mixins/_label.scss create mode 100644 dev/plugins/problems/scss/mixins/_position.scss create mode 100644 dev/plugins/problems/scss/mixins/_shadow.scss create mode 100644 dev/plugins/problems/scss/mixins/_text.scss create mode 100644 dev/plugins/problems/scss/mixins/_toast.scss create mode 100644 dev/plugins/problems/scss/mixins/_transition.scss create mode 100644 dev/plugins/problems/scss/spectre-icons.scss create mode 100644 dev/plugins/problems/scss/spectre.scss create mode 100644 dev/plugins/problems/scss/utilities/_colors.scss create mode 100644 dev/plugins/problems/scss/utilities/_cursors.scss create mode 100644 dev/plugins/problems/scss/utilities/_display.scss create mode 100644 dev/plugins/problems/scss/utilities/_divider.scss create mode 100644 dev/plugins/problems/scss/utilities/_loading.scss create mode 100644 dev/plugins/problems/scss/utilities/_position.scss create mode 100644 dev/plugins/problems/scss/utilities/_shapes.scss create mode 100644 dev/plugins/problems/scss/utilities/_text.scss create mode 100644 dev/plugins/problems/templates/problems.html.twig create mode 100644 dev/plugins/problems/templates/reports/problems-report.html.twig create mode 100644 dev/plugins/problems/vendor/autoload.php create mode 100644 dev/plugins/problems/vendor/composer/ClassLoader.php create mode 100644 dev/plugins/problems/vendor/composer/InstalledVersions.php create mode 100644 dev/plugins/problems/vendor/composer/LICENSE create mode 100644 dev/plugins/problems/vendor/composer/autoload_classmap.php create mode 100644 dev/plugins/problems/vendor/composer/autoload_namespaces.php create mode 100644 dev/plugins/problems/vendor/composer/autoload_psr4.php create mode 100644 dev/plugins/problems/vendor/composer/autoload_real.php create mode 100644 dev/plugins/problems/vendor/composer/autoload_static.php create mode 100644 dev/plugins/problems/vendor/composer/installed.json create mode 100644 dev/plugins/problems/vendor/composer/installed.php create mode 100644 dev/plugins/shortcode-core/CHANGELOG.md create mode 100644 dev/plugins/shortcode-core/LICENSE create mode 100644 dev/plugins/shortcode-core/README.md create mode 100644 dev/plugins/shortcode-core/assets/shortcode-core-1.png create mode 100644 dev/plugins/shortcode-core/blueprints.yaml create mode 100644 dev/plugins/shortcode-core/classes/Shortcode.php create mode 100644 dev/plugins/shortcode-core/classes/ShortcodeManager.php create mode 100644 dev/plugins/shortcode-core/classes/ShortcodeObject.php create mode 100644 dev/plugins/shortcode-core/classes/plugin/Shortcode.php create mode 100644 dev/plugins/shortcode-core/classes/plugin/ShortcodeManager.php create mode 100644 dev/plugins/shortcode-core/classes/plugin/ShortcodeObject.php create mode 100644 dev/plugins/shortcode-core/classes/plugin/ShortcodeTwigVar.php create mode 100644 dev/plugins/shortcode-core/classes/shortcodes/AlignShortcode.php create mode 100644 dev/plugins/shortcode-core/classes/shortcodes/ColorShortcode.php create mode 100644 dev/plugins/shortcode-core/classes/shortcodes/ColumnsShortcode.php create mode 100644 dev/plugins/shortcode-core/classes/shortcodes/DetailsShortcode.php create mode 100644 dev/plugins/shortcode-core/classes/shortcodes/DivShortcode.php create mode 100644 dev/plugins/shortcode-core/classes/shortcodes/FigureShortcode.php create mode 100644 dev/plugins/shortcode-core/classes/shortcodes/FontAwesomeShortcode.php create mode 100644 dev/plugins/shortcode-core/classes/shortcodes/HShortcode.php create mode 100644 dev/plugins/shortcode-core/classes/shortcodes/LanguageShortcode.php create mode 100644 dev/plugins/shortcode-core/classes/shortcodes/LoremShortcode.php create mode 100644 dev/plugins/shortcode-core/classes/shortcodes/MarkShortcode.php create mode 100644 dev/plugins/shortcode-core/classes/shortcodes/NoticeShortcode.php create mode 100644 dev/plugins/shortcode-core/classes/shortcodes/RawShortcode.php create mode 100644 dev/plugins/shortcode-core/classes/shortcodes/SafeEmailShortcode.php create mode 100644 dev/plugins/shortcode-core/classes/shortcodes/SectionShortcode.php create mode 100644 dev/plugins/shortcode-core/classes/shortcodes/Shortcode.php create mode 100644 dev/plugins/shortcode-core/classes/shortcodes/ShortcodeObject.php create mode 100644 dev/plugins/shortcode-core/classes/shortcodes/SizeShortcode.php create mode 100644 dev/plugins/shortcode-core/classes/shortcodes/SpanShortcode.php create mode 100644 dev/plugins/shortcode-core/classes/shortcodes/UnderlineShortcode.php create mode 100644 dev/plugins/shortcode-core/composer.json create mode 100644 dev/plugins/shortcode-core/composer.lock create mode 100644 dev/plugins/shortcode-core/css/shortcode-notice.css create mode 100644 dev/plugins/shortcode-core/nextgen-editor/README.md create mode 100644 dev/plugins/shortcode-core/nextgen-editor/babel.config.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/dist/css/app.css create mode 100644 dev/plugins/shortcode-core/nextgen-editor/dist/js/app.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/dist/js/app.js.map create mode 100644 dev/plugins/shortcode-core/nextgen-editor/package.json create mode 100644 dev/plugins/shortcode-core/nextgen-editor/shortcodes/align/align.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/shortcodes/color/color.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/shortcodes/columns/columns.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/shortcodes/details/details.css create mode 100644 dev/plugins/shortcode-core/nextgen-editor/shortcodes/details/details.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/shortcodes/div/div.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/shortcodes/figure/figure.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/shortcodes/fontawesome/fontawesome.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/shortcodes/headers/headers.css create mode 100644 dev/plugins/shortcode-core/nextgen-editor/shortcodes/headers/headers.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/shortcodes/language/language.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/shortcodes/lorem/lorem.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/shortcodes/mark/mark.css create mode 100644 dev/plugins/shortcode-core/nextgen-editor/shortcodes/mark/mark.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/shortcodes/notice/notice.css create mode 100644 dev/plugins/shortcode-core/nextgen-editor/shortcodes/notice/notice.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/shortcodes/raw/raw.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/shortcodes/safe-email/safe-email.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/shortcodes/section/section.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/shortcodes/shortcode-core.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/shortcodes/size/size.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/shortcodes/span/span.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/shortcodes/u/u.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/src/collapse.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/src/command.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/src/converters.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/src/events.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/src/init.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/src/main.css create mode 100644 dev/plugins/shortcode-core/nextgen-editor/src/main.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/src/postsave.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/src/prerender.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/src/remove.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/src/render.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/src/save.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/src/settings.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/src/uncollapse.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/vue.config.js create mode 100644 dev/plugins/shortcode-core/nextgen-editor/yarn.lock create mode 100644 dev/plugins/shortcode-core/shortcode-core.php create mode 100644 dev/plugins/shortcode-core/shortcode-core.yaml create mode 100644 dev/plugins/shortcode-core/templates/shortcodes/notice.html.twig create mode 100644 dev/plugins/shortcode-core/vendor/autoload.php create mode 100644 dev/plugins/shortcode-core/vendor/composer/ClassLoader.php create mode 100644 dev/plugins/shortcode-core/vendor/composer/InstalledVersions.php create mode 100644 dev/plugins/shortcode-core/vendor/composer/LICENSE create mode 100644 dev/plugins/shortcode-core/vendor/composer/autoload_classmap.php create mode 100644 dev/plugins/shortcode-core/vendor/composer/autoload_namespaces.php create mode 100644 dev/plugins/shortcode-core/vendor/composer/autoload_psr4.php create mode 100644 dev/plugins/shortcode-core/vendor/composer/autoload_real.php create mode 100644 dev/plugins/shortcode-core/vendor/composer/autoload_static.php create mode 100644 dev/plugins/shortcode-core/vendor/composer/installed.json create mode 100644 dev/plugins/shortcode-core/vendor/composer/installed.php create mode 100644 dev/plugins/shortcode-core/vendor/composer/platform_check.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/CHANGELOG.md create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/LICENSE create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/Makefile create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/README.md create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/composer.json create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/docker-compose.yaml create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/docker/php-5.4/Dockerfile create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/phpunit.xml.dist create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Event/FilterShortcodesEvent.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Event/ReplaceShortcodesEvent.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/EventContainer/EventContainer.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/EventContainer/EventContainerInterface.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/EventHandler/FilterRawEventHandler.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/EventHandler/ReplaceJoinEventHandler.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Events.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Handler/ContentHandler.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Handler/DeclareHandler.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Handler/EmailHandler.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Handler/NameHandler.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Handler/NullHandler.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Handler/PlaceholderHandler.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Handler/RawHandler.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Handler/SerializerHandler.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Handler/UrlHandler.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Handler/WrapHandler.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/HandlerContainer/HandlerContainer.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/HandlerContainer/HandlerContainerInterface.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/HandlerContainer/ImmutableHandlerContainer.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Parser/ParserInterface.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Parser/RegexParser.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Parser/RegularParser.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Parser/WordpressParser.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Processor/Processor.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Processor/ProcessorContext.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Processor/ProcessorInterface.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Serializer/JsonSerializer.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Serializer/SerializerInterface.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Serializer/TextSerializer.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Serializer/XmlSerializer.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Serializer/YamlSerializer.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Shortcode/AbstractShortcode.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Shortcode/ParsedShortcode.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Shortcode/ParsedShortcodeInterface.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Shortcode/ProcessedShortcode.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Shortcode/ReplacedShortcode.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Shortcode/Shortcode.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Shortcode/ShortcodeInterface.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/ShortcodeFacade.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Syntax/CommonSyntax.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Syntax/Syntax.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Syntax/SyntaxBuilder.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Syntax/SyntaxInterface.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/src/Utility/RegexBuilderUtility.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/tests/AbstractTestCase.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/tests/EventsTest.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/tests/FacadeTest.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/tests/Fake/ReverseShortcode.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/tests/HandlerContainerTest.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/tests/ParserTest.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/tests/ProcessorTest.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/tests/SerializerTest.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/tests/ShortcodeTest.php create mode 100644 dev/plugins/shortcode-core/vendor/thunderer/shortcode/tests/SyntaxTest.php create mode 100644 dev/plugins/tntsearch/CHANGELOG.md create mode 100644 dev/plugins/tntsearch/LICENSE create mode 100644 dev/plugins/tntsearch/README.md create mode 100644 dev/plugins/tntsearch/app/history.js create mode 100644 dev/plugins/tntsearch/app/main.js create mode 100644 dev/plugins/tntsearch/app/search.js create mode 100644 dev/plugins/tntsearch/assets/admin/tntsearch.css create mode 100644 dev/plugins/tntsearch/assets/admin/tntsearch.js create mode 100644 dev/plugins/tntsearch/assets/tntsearch-ajax.gif create mode 100644 dev/plugins/tntsearch/assets/tntsearch-config.png create mode 100644 dev/plugins/tntsearch/assets/tntsearch-quicktray.png create mode 100644 dev/plugins/tntsearch/assets/tntsearch.css create mode 100644 dev/plugins/tntsearch/assets/tntsearch.js create mode 100644 dev/plugins/tntsearch/blueprints.yaml create mode 100644 dev/plugins/tntsearch/classes/GravConnector.php create mode 100644 dev/plugins/tntsearch/classes/GravResultObject.php create mode 100644 dev/plugins/tntsearch/classes/GravTNTSearch.php create mode 100644 dev/plugins/tntsearch/cli/TNTSearchIndexerCommand.php create mode 100644 dev/plugins/tntsearch/cli/TNTSearchQueryCommand.php create mode 100644 dev/plugins/tntsearch/composer.json create mode 100644 dev/plugins/tntsearch/composer.lock create mode 100644 dev/plugins/tntsearch/languages.yaml create mode 100644 dev/plugins/tntsearch/package.json create mode 100644 dev/plugins/tntsearch/templates/forms/fields/indexstatus/indexstatus.html.twig create mode 100644 dev/plugins/tntsearch/templates/partials/tntsearch.html.twig create mode 100644 dev/plugins/tntsearch/templates/search.html.twig create mode 100644 dev/plugins/tntsearch/templates/tntquery-ajax.html.twig create mode 100644 dev/plugins/tntsearch/templates/tntquery.html.twig create mode 100644 dev/plugins/tntsearch/templates/tntquery.json.twig create mode 100644 dev/plugins/tntsearch/tntsearch.php create mode 100644 dev/plugins/tntsearch/tntsearch.yaml create mode 100644 dev/plugins/tntsearch/vendor/autoload.php create mode 100644 dev/plugins/tntsearch/vendor/composer/ClassLoader.php create mode 100644 dev/plugins/tntsearch/vendor/composer/InstalledVersions.php create mode 100644 dev/plugins/tntsearch/vendor/composer/LICENSE create mode 100644 dev/plugins/tntsearch/vendor/composer/autoload_classmap.php create mode 100644 dev/plugins/tntsearch/vendor/composer/autoload_files.php create mode 100644 dev/plugins/tntsearch/vendor/composer/autoload_namespaces.php create mode 100644 dev/plugins/tntsearch/vendor/composer/autoload_psr4.php create mode 100644 dev/plugins/tntsearch/vendor/composer/autoload_real.php create mode 100644 dev/plugins/tntsearch/vendor/composer/autoload_static.php create mode 100644 dev/plugins/tntsearch/vendor/composer/installed.json create mode 100644 dev/plugins/tntsearch/vendor/composer/installed.php create mode 100644 dev/plugins/tntsearch/vendor/composer/platform_check.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/.github/FUNDING.yml create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/CHANGELOG.md create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/CODE_OF_CONDUCT.md create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/CONDUCT.md create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/CONTRIBUTING.md create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/LICENSE.md create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/PS4Ware.md create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/README.md create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/composer.json create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/helper/helpers.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/phpunit.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/phpunit.xml create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Classifier/TNTClassifier.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Connectors/Connector.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Connectors/ConnectorInterface.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Connectors/FileSystemConnector.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Connectors/MySqlConnector.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Connectors/PostgresConnector.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Connectors/SQLiteConnector.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Connectors/SqlServerConnector.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Exceptions/IndexNotFoundException.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/FileReaders/FileReaderInterface.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/FileReaders/TextFileReader.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Indexer/TNTGeoIndexer.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Indexer/TNTIndexer.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/KeywordExtraction/Rake.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Spell/JaroWinklerDistance.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stemmer/ArabicStemmer.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stemmer/CroatianStemmer.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stemmer/GermanStemmer.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stemmer/ItalianStemmer.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stemmer/NoStemmer.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stemmer/PorterStemmer.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stemmer/PortugueseStemmer.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stemmer/RussianStemmer.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stemmer/Stemmer.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stemmer/UkrainianStemmer.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stopwords/croatian.json create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stopwords/english.json create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stopwords/french.json create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stopwords/german.json create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stopwords/italian.json create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stopwords/russian.json create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stopwords/spanish.json create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stopwords/ukrainian.json create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Support/AbstractTokenizer.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Support/Collection.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Support/Expression.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Support/Highlighter.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Support/ProductTokenizer.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Support/Tokenizer.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/Support/TokenizerInterface.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/TNTFuzzyMatch.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/TNTGeoSearch.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/src/TNTSearch.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/TNTFuzzyMatchTest.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/TNTGeoSearchTest.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/TNTSearchTest.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/_files/articles.sqlite create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/_files/articles/1.txt create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/_files/articles/2.txt create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/_files/articles/3.txt create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/_files/cities-geo.index create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/_files/cities.sqlite create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/_files/english_wordlist_2k.txt create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/_files/sms-texts.json create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/classifier/TNTClassifierTest.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/indexer/TNTGeoIndexerTest.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/indexer/TNTIndexerTest.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/keywordextraction/Rake.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/spell/JaroWinklerDistanceTest.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/stemmer/CroatianStemmerTest.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/stemmer/GermanStemmerTest.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/stemmer/PorterStemmerTest.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/stemmer/PortugueseStemmerTest.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/stemmer/porter/input.txt create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/stemmer/porter/output.txt create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/support/ExpressionTest.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/support/HighlighterTest.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/support/ProductTokenizerTest.php create mode 100644 dev/plugins/tntsearch/vendor/teamtnt/tntsearch/tests/support/TokenizerTest.php create mode 100644 dev/plugins/tntsearch/webpack.conf.js create mode 100644 dev/plugins/tntsearch/yarn.lock create mode 100644 docker-compose.yml diff --git a/.gitignore b/.gitignore index 5101aeaf..82bff889 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,7 @@ !/pages !/images !/themes +!/Dockerfile +!/docker-compose.yml +!/dev/plugins /themes/learn4 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..c6b0b266 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,82 @@ +FROM php:7.4-apache +LABEL maintainer="Andy Miller (@rhukster)" + +RUN usermod --uid 1000 www-data +RUN groupmod --gid 1000 www-data +# Enable Apache Rewrite + Expires Module +RUN a2enmod rewrite expires && \ + sed -i 's/ServerTokens OS/ServerTokens ProductOnly/g' \ + /etc/apache2/conf-available/security.conf + +# Install dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + unzip \ + libfreetype6-dev \ + libjpeg62-turbo-dev \ + libpng-dev \ + libyaml-dev \ + libzip4 \ + libzip-dev \ + zlib1g-dev \ + libicu-dev \ + g++ \ + git \ + cron \ + vim \ + && docker-php-ext-install opcache \ + && docker-php-ext-configure intl \ + && docker-php-ext-install intl \ + && docker-php-ext-configure gd --with-freetype --with-jpeg \ + && docker-php-ext-install -j$(nproc) gd \ + && docker-php-ext-install zip \ + && rm -rf /var/lib/apt/lists/* + +# set recommended PHP.ini settings +# see https://secure.php.net/manual/en/opcache.installation.php +RUN { \ + echo 'opcache.memory_consumption=128'; \ + echo 'opcache.interned_strings_buffer=8'; \ + echo 'opcache.max_accelerated_files=4000'; \ + echo 'opcache.revalidate_freq=2'; \ + echo 'opcache.fast_shutdown=1'; \ + echo 'opcache.enable_cli=1'; \ + echo 'upload_max_filesize=128M'; \ + echo 'post_max_size=128M'; \ + echo 'expose_php=off'; \ + } > /usr/local/etc/php/conf.d/php-recommended.ini + +RUN pecl install apcu \ + && pecl install yaml-2.0.4 \ + && docker-php-ext-enable apcu yaml + +CMD ["sh", "-c", "usermod --uid 1000 www-data"] +CMD ["sh", "-c", "groupmod --gid 1000 www-data"] +# Set user to www-data +RUN chown www-data:www-data /var/www +USER www-data + +# Define Grav specific version of Grav or use latest stable +ARG GRAV_VERSION=latest + +# Install grav +WORKDIR /var/www +RUN curl -o grav-admin.zip -SL https://getgrav.org/download/core/grav-admin/${GRAV_VERSION} && \ + unzip grav-admin.zip && \ + mv -T /var/www/grav-admin /var/www/html && \ + rm grav-admin.zip + +# Create cron job for Grav maintenance scripts +RUN (crontab -l; echo "* * * * * cd /var/www/html;/usr/local/bin/php bin/grav scheduler 1>> /dev/null 2>&1") | crontab - + +# Return to root user +USER root + +# Copy init scripts +# COPY docker-entrypoint.sh /entrypoint.sh + +# provide container inside image for data persistence +VOLUME ["/var/www/html/backup", "/var/www/html/logs", "/var/www/html/user/themes", "/var/www/html/user/pages", "/var/www/html/user/config", "/var/www/html/user/images"] + +# ENTRYPOINT ["/entrypoint.sh"] +# CMD ["apache2-foreground"] +CMD ["sh", "-c", "cron && apache2-foreground"] diff --git a/README.md b/README.md index 31d94298..23d454b6 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,11 @@ Please report [issues on YunoHost bugtracker](https://github.com/YunoHost/issues You can refer to the page on [writing documentation](https://yunohost.org/write_documentation). +If you know docker, you can run: +``` +docker-compose up +``` + ## Regenerate the css We use scss to manage the css. If you want to change it, you must rebuild it. diff --git a/dev/plugins/admin/.gitattributes b/dev/plugins/admin/.gitattributes new file mode 100644 index 00000000..c5ef7313 --- /dev/null +++ b/dev/plugins/admin/.gitattributes @@ -0,0 +1,8 @@ +# Linguist Normalizer +*.yaml linguistic-language=PHP +*.twig linguistic-language=PHP +**/gulpfile.babel.js linguist-vendored +**/webpack.conf.js linguist-vendored +**/js/*.js linguist-vendored +**/js/*.json linguist-vendored +**/css-compiled/*.css linguist-vendored diff --git a/dev/plugins/admin/.github/FUNDING.yml b/dev/plugins/admin/.github/FUNDING.yml new file mode 100644 index 00000000..e84f52bf --- /dev/null +++ b/dev/plugins/admin/.github/FUNDING.yml @@ -0,0 +1,8 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: grav +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +custom: # Replace with a single custom sponsorship URL diff --git a/dev/plugins/admin/CHANGELOG.md b/dev/plugins/admin/CHANGELOG.md new file mode 100644 index 00000000..54bd2066 --- /dev/null +++ b/dev/plugins/admin/CHANGELOG.md @@ -0,0 +1,2510 @@ +# v1.10.31 +## 03/14/2022 + +1. [](#new) + * Added new local Multiavatar (local generation). **This will be default in Grav 1.8** +2. [](#bugfix) + * Patch `collection.js` [#2235](https://github.com/getgrav/grav-plugin-admin/issues/2235) + +# v1.10.30.2 +## 02/09/2022 + +2. [](#bugfix) + * Fixed regression preventing new `elements` field from saving its state + +# v1.10.30.1 +## 02/09/2022 + +1. [](#improved) + * List field items will now require confirmation before getting deleted + +# v1.10.30 +## 02/07/2022 + +1. [](#new) + * Require **Grav 1.7.30** + * Updated SCSS compiler to v1.10 + * PageMedia can now be collapsed and thumbnails previewed smaller, in order to save room on the page. Selection will be remembered. + * DEPRECATED: Admin field `pages_list_display_field` is no longer available as an option [#2191](https://github.com/getgrav/grav-plugin-admin/issues/2191) + * When listing installable themes/plugins, it is now possible to sort them by [Premium](https://getgrav.org/premium) +2. [](#improved) + * Updated JavaScript dependencies + * Cleaned up JavaScript unused dependencies and warnings + * Removed unused style assets + * Plugins list rows now properly highlight on hover, no more guessing when wanting to disable a plugin! +3. [](#bugfix) + * Fixed `elements` field when it's used inside `list` field + * Fixed issue uploading non-images media when Resolution setting enabled in Admin [#2172](https://github.com/getgrav/grav-plugin-admin/issues/2172) + * Prevent fields from being toggled incorrectly by adding originalValue to childs of fieldset. [#2218](https://github.com/getgrav/grav-plugin-admin/pull/2218) + * Fixed persistent focus on Folder field when Adding page (Safari) [#2209](https://github.com/getgrav/grav-plugin-admin/issues/2209) + * Fixed performance of Plugins / Themes sort in the installation table + * Fixed list field with key/value pairs throwing an exception due to bad value [#2199](https://github.com/getgrav/grav-plugin-admin/issues/2199) + * Fixed disabling/enabling plugin from the list breaking the plugin configuration + +# v1.10.29 +## 01/28/2022 + +1. [](#new) + * Require **Grav 1.7.29** +3. [](#improved) + * Made path handling unicode-safe, use new `Utils::basename()` and `Utils::pathinfo()` everywhere + +# v1.10.28 +## 01/24/2022 + +1. [](#bugfix) + * Clean file names before displaying errors/metadata modals + * Recompiled JS for production [#2225](https://github.com/getgrav/grav-plugin-admin/issues/2225) + +# v1.10.27 +## 01/12/2022 + +1. [](#new) + * Support for `YubiKey OTP` 2-Factor authenticator + * New `elements` container field that shows/hides children fields based on boolean trigger value + * Requires Grav `v1.7.27` and Login `v3.6.2` +2. [](#improved) + * Added new asset language strings + +# v1.10.26.1 +## 01/03/2022 + +3. [](#bugfix) + * Fixed an issue with missing files reference by cached autoloader + +# v1.10.26 +## 01/03/2022 + +2. [](#improved) + * Updated SCSS compiler to v1.9 and other vendor libraries + * Fixed various deprecation warnings + * Localized dialog buttons and icons [#2207](https://github.com/getgrav/grav-plugin-admin/pull/2207) + * Updated copyright year + +# v1.10.25 +## 11/16/2021 + +3. [](#bugfix) + * Fixed unescaped messages in JSON responses + +# v1.10.24 +## 10/26/2021 + +1. [](#new) + * Require **Grav 1.7.24** +2. [](#improved) + * Use new `Http\Response` rather than deprecated `GPM\Response` +3. [](#bugfix) + * Fixed an issue with invalid HTML throwing errors on HTML security scanning + * Clear cache when installing plugins + +# v1.10.23 +## 09/29/2021 + +1. [](#new) + * Updated SCSS compiler to v1.8 +2. [](#improved) + * Updated with latest language strings from Crowdin.com +3. [](#bugfix) + * Fixed images from plugins/themes disappearing when saving twice + +# v1.10.22 +## 09/16/2021 + +1. [](#new) + * Updated SCSS compiler to v1.7 + +# v1.10.21 +## 09/14/2021 + +1. [](#new) + * Require **Grav 1.7.21** +2. [](#improved) + * Added a note about UTC times in scheduler AT syntax help + * Now using a monospaced text-based scheduler AT field in scheduler for simplicity + * Improved `Admin:data()` and `Admin::getConfigurationData()` to be more strict +3. [](#bugfix) + * Fixed configuration save location to point to existing config folder [#2176](https://github.com/getgrav/grav-plugin-admin/issues/2176) + +# v1.10.20 +## 09/01/2021 + +1. [](#bugfix) + * Fixed regression `Argument 4 passed to Grav\Plugin\Form\TwigExtension::prepareFormField() must be of the type array` [#2177](https://github.com/getgrav/grav-plugin-admin/issues/2177) + * Fixed `X-Frame-Options` to be `DENY` in all admin pages to prevent a clickjacking attack + +# v1.10.19 +## 08/31/2021 + +1. [](#new) + * Require **Grav 1.7.19** and **Form 5.1.0** and **Login 3.5.0** + * Updated SCSS compiler to v1.6 +2. [](#improved) + * Updated forms and nested fields to use new form logic + * Admin form now use layout `admin`, meaning you can create admin specific field templates by `forms/fields/myfield/admin-field.html.twig` + * Stop using `|tu` filter, Grav already has the same logic in `|t` for admin + * Remove unneeded escapes + * Allow removal of plugin when disabled [#2167](https://github.com/getgrav/grav-plugin-admin/issues/2167) +3. [](#bugfix) + * Fixed missing values in `fieldset` form field + +# v1.10.18 +## 07/19/2021 + +1. [](#improved) + * Add logic to allow fieldset form field inside a list field [#2159](https://github.com/getgrav/grav-plugin-admin/pull/2159) + +# v1.10.17 +## 06/15/2021 + +1. [](#improved) + * Added timestamp as title in logs date [#2141](https://github.com/getgrav/grav-plugin-admin/issues/2141) + * Use `base64_encode` filter rather than function + * Composer update +1. [](#bugfix) + * Fixed missing `Remove Theme` button when the theme is inactive + * Update taskGetChildTypes() to use Flex Pages (works without the plugin) [#2087](https://github.com/getgrav/grav-plugin-admin/issues/2087) + +# v1.10.16 +## 06/02/2021 + +1. [](#bugfix) + * Fixed issue with some elements overflowing closed list items [#2146](https://github.com/getgrav/grav-plugin-admin/issues/2146) + * Fixed configuration not fully updating on save [#2149](https://github.com/getgrav/grav-plugin-admin/issues/2149) + * Fixed display issue with "+ Add Page" and picking a different route [#2136](https://github.com/getgrav/grav-plugin-admin/issues/2136), [#2145](https://github.com/getgrav/grav-plugin-admin/issues/2145) + * Treat WebP as image when inserting / drag & dropping [#2150](https://github.com/getgrav/grav-plugin-admin/issues/2150) + +# v1.10.15 +## 05/19/2021 + +1. [](#new) + * Updated SCSS compiler to v1.5 +1. [](#improved) + * Updated node modules dev dependencies + * Package.json scripts cleanup + * Recompiled JS for production + * Use `base645_encode` filter rather than function + * Editor: Do not assume images URLs are going to be `http://` (wrong assumption plus not SSL) [#2127](https://github.com/getgrav/grav-plugin-admin/issues/2127) + * Improved Theme Activation + Plugin Enabled logic to ensure configuration is not displayed unless activation/enabled state. Fixes [#2140](https://github.com/getgrav/grav-plugin-admin/issues/2140) +1. [](#bugfix) + * Fixed issue with slugify where single curly quotes in titles would translate to straight single quote [#2101](https://github.com/getgrav/grav-plugin-admin/issues/2101) + * Fix z-index issue with fullscreeen editor (and toolips) [#2143](https://github.com/getgrav/grav-plugin-admin/issues/2143) + +# v1.10.14 +## 04/29/2021 + +1. [](#improved) + * Added a `min_height:` option for list field +1. [](#bugfix) + * Fixed z-index issue for tooltips in sidebar + * Fixed custom files being overridden during theme update [#2135](https://github.com/getgrav/grav-plugin-admin/issues/2135) + +# v1.10.13 +## 04/23/2021 + +1. [](#new) + * Added refresh action button for Folder to ease the regeneration of the slug based on the title. Available also as API entry `Grav.default.Forms.Fields.FolderField.Regenerate()` [#1738](https://github.com/getgrav/grav-plugin-admin/issues/1738) +1. [](#improved) + * Removed sourcemaps references from fork-awesome.min.css [#2122](https://github.com/getgrav/grav-plugin-admin/issues/2122) + * Support native spell checkers in CodeMirror editor [#1266](https://github.com/getgrav/grav-plugin-admin/issues/1266) + * Added new 'Content Highlight' color to presets + * Copying Pages now prompts a dedicated modal that allows for picking title, folder name, parent location, page template and visibility [#1738](https://github.com/getgrav/grav-plugin-admin/issues/1738) + * Updated with latest language translations from Crowdin.com +1. [](#bugfix) + * Moved preset CSS compile to earlier in the process to ensure compilation happens in time. + * Prevent Save actions from Flex Objects to trigger the unsaved unload notice [#2125](https://github.com/getgrav/grav-plugin-admin/issues/2125) + * Fixed audit vulnerabilities in module dependencies and house cleanup [#2096](https://github.com/getgrav/grav-plugin-admin/issues/2096) + * Fixed issue preventing Drag & Drop of media files while in Expert Mode [#1927](https://github.com/getgrav/grav-plugin-admin/issues/1927) + * Fixed broken link colors in `preset.css` which was causing issues with tabs and dropdowns + * Fixed permissions for page related tasks and actions + * Fixed permission check for configuration save [#2130](https://github.com/getgrav/grav-plugin-admin/issues/2130) + * Fixed missing/wrong page categories and tags when multi-language support is enabled [#2107](https://github.com/getgrav/grav-plugin-admin/issues/2107) + +# v1.10.12 +## 04/15/2021 + +1. [](#bugfix) + * Regression: Fixed broken plugin/theme installer in admin + * Fixed error reporting for AJAX tasks if user has no permissions + * Fixed missing slash in password reset URL [#2119](https://github.com/getgrav/grav-plugin-admin/issues/2119) + +# v1.10.11 +## 04/13/2021 + +1. [](#bugfix) + * **IMPORTANT** Fixed security vulnerability that allows installation of plugins with minimal admin privileges [GHSA-wg37-cf5x-55hq](https://github.com/getgrav/grav-plugin-admin/security/advisories/GHSA-wg37-cf5x-55hq) + * Fixed `You have been logged out` message when entering to 2FA authentication due to `/admin/task:getNotifications` AJAX call + * Fixed broken 2FA login when site is not configured to use Flex Users [#2109](https://github.com/getgrav/grav-plugin-admin/issues/2109) + * Fixed error message when user clicks logout link after the session has been expired + +# v1.10.10 +## 04/07/2021 + +1. [](#bugfix) + * Fixed missing `admin-preset.css` in multisite environments + * Regression: Fixed broken 2FA form [#2109](https://github.com/getgrav/grav-plugin-admin/issues/2109) + +# v1.10.9 +## 04/06/2021 + +1. [](#new) + * Requires **Grav 1.7.10** +1. [](#improved) + * Better isolate admin to prevent session related vulnerabilities + * Removed support for custom login redirects for improved security + * Shorten forgot password link lifetime from 7 days to 1 hour + * Updated with latest language translations from Crowdin.com +1. [](#bugfix) + * Fixed issue where Adding a new page and canceling from within Editing would alter the Parent location of the edited page [#2067](https://github.com/getgrav/grav-plugin-admin/issues/2067) + * Fixed and enhanced Range field to be Lists compatible [#2062](https://github.com/getgrav/grav-plugin-admin/issues/2062) + * Fixed ERR_TOO_MANY_REDIRECTS with HTTPS = 'On' [#2100](https://github.com/getgrav/grav-plugin-admin/issues/2100) + * Prevent expert editing mode from anyone else than super users [#2094](https://github.com/getgrav/grav-plugin-admin/issues/2094) + * Fixed login related pages being accessible from admin when user has logged in + * Fixed admin user creation and password reset allowing unsafe passwords + * Fixed missing validation when registering the first admin user + * Fixed reset password email not to have session specific token in it + * Fixed admin controller running before setting `$grav['page']` + +# v1.10.8 +## 03/19/2021 + +1. [](#improved) + * Include alt text and title for images added to the editor [#2098](https://github.com/getgrav/grav-plugin-admin/issues/2098) +1. [](#bugfix) + * Fixed issue replacing `wildcard` field names in flex collections [#2092](https://github.com/getgrav/grav-plugin-admin/pull/2092) + * Fixed legacy Pages having old `modular` reference instead of `module` [#2093](https://github.com/getgrav/grav-plugin-admin/issues/2093) + * Fixed issue where Add New modal would close if selecting an item outside of the modal window. It is now necessary go through the Cancel button and clicking the overlay won't trigger the closing of the modal [#2089](https://github.com/getgrav/grav-plugin-admin/issues/2089), [#2065](https://github.com/getgrav/grav-plugin-admin/issues/2065) + +# v1.10.7 +## 03/17/2021 + +1. [](#improved) + * Force height of Flex pages admin to fit available space + * Updated languages from Crowdin.com + * Better field type definitions for file, pagemedia, filepicker and pagemediafield +1. [](#bugfix) + * Fixed error when checking missing log file [#2088](https://github.com/getgrav/grav-plugin-admin/issues/2088) + +# v1.10.6 +## 02/23/2021 + +1. [](#new) + * Vastly improved support for RTL languages [#2078](https://github.com/getgrav/grav-plugin-admin/pull/2078) +1. [](#improved) + * Flex pages admin better uses available space [#2075](https://github.com/getgrav/grav/issues/2075) +1. [](#bugfix) + * Regression: Fixed enabling/disabling plugin or theme corrupting configuration + * Fixed unnecessary closing bracket causing JS error [#2079](https://github.com/getgrav/grav-plugin-admin/issues/2079) + * Fixed wrong language in Admin Tools [#2077](https://github.com/getgrav/grav-plugin-admin/issues/2077) + +# v1.10.5 +## 02/18/2021 + +1. [](#bugfix) + * Regression: Fixed fatal error in admin if POST request has `data` in it [#2074](https://github.com/getgrav/grav-plugin-admin/issues/2074) + * Fixed Admin creating empty `user/config/info.yaml` file (the file can be safely removed, it is not in use) + * Fixed ACL for users with mixed case usernames [#2073](https://github.com/getgrav/grav-plugin-admin/issues/2073) + +# v1.10.4 +## 02/17/2021 + +1. [](#new) + * Added support to include new page creation modals in other pages by using `form_action` twig variable [#2024](https://github.com/getgrav/grav-plugin-admin/pull/2024) + * Updated all languages from [Crowdin](https://crowdin.com/project/grav-admin) - Please update any translations here +1. [](#improved) + * Removed `noscript` template, because 2021... + * List field: added new `placement` property to decide wether to add new items at the top, bottom or based on the *position* of the clicked button [#2055](https://github.com/getgrav/grav-plugin-admin/pull/2055) + * Ensure admin default CSS styles load **first**, and presets loads **last** + * Tweaked handling of uploaded files [#1429](https://github.com/getgrav/grav-plugin-admin/issues/1429) + * Provide media object and filename in `onAdminAfterDelMedia` event [#1905](https://github.com/getgrav/grav-plugin-admin/pull/1905) +1. [](#bugfix) + * Fixed case-sensitive `accept` in `filepicker` field + * Fixed HTML Entities in titles [#2028](https://github.com/getgrav/grav-plugin-admin/issues/2028) + * Fixed deleting list field options completely, didn't save changes [#2056](https://github.com/getgrav/grav-plugin-admin/issues/2056) + * Fixed `onAdminAfterAddMedia` and `onAdminAfterDelMedia` events always pointing to the home page + * Fixed ACL for Configuration tabs [#771](https://github.com/getgrav/grav-plugin-admin/issues/771) + * Fixed changelog button showing up in Info page even if user cannot access it + * Fixed toggleable checkboxes being unchecked in fieldset columns [#2063](https://github.com/getgrav/grav-plugin-admin/issues/2063) + * Fixed issue with max backups of zero [#2070](https://github.com/getgrav/grav-plugin-admin/issues/2070) + +# v1.10.3 +## 02/01/2021 + +1. [](#new) + * Requires **Grav 1.7.4** (SemVer library moved to Grav) + * Added back special fonts (including Gantry) +2. [](#bugfix) + * Fixed field type `range` not taking into account legitimate `0` values + * Fixed `Call to a member function trackHit() on null` [#2049](https://github.com/getgrav/grav-plugin-admin/issues/2049) + +# v1.10.2 +## 01/21/2021 + +2. [](#bugfix) + * Fixed admin style compilation failing to save CSS if assets folder does not exist + +# v1.10.1 +## 01/20/2021 + +1. [](#improved) + * Added `watch.sh` for compiling SCSS with native sass compiler +2. [](#bugfix) + * Fixed issue with overlapping sidebar when using fullscreen editor [#2022](https://github.com/getgrav/grav-plugin-admin/issues/2022) + +# v1.10.0 +## 01/19/2021 + +1. [](#new) + * Requires **Grav 1.7 and PHP 7.3.6** + * Read about this release in the [Grav 1.7 Released](https://getgrav.org/blog/grav-1.7-released) blog post + * Read the full list of changes in the [Changelog on GitHub](https://github.com/getgrav/grav-plugin-admin/blob/1.10.0/CHANGELOG.md) + * Please read [Grav 1.7 Upgrade Guide](https://learn.getgrav.org/17/advanced/grav-development/grav-17-upgrade-guide) before upgrading! +1. [](#improved) + * Various notifications improvements +1. [](#bugfix) + * Fixed missed highlight on the selected page in Parents field + * Fixed notifications that would not be remembered as hidden + * Fixed taxonomy field not listing existing options in Flex Pages + * Fixed taxonomy field not working outside pages + * Fixed fatal error when moving a page using the old implementation [#2019](https://github.com/getgrav/grav-plugin-admin/issues/2019) + * Fixed evaluating default value in `hidden` field (thanks @NicoHood) + +# v1.10.0-rc.20 +## 12/14/2020 + +1. [](#improved) + * Cookies now explicitly set `SameSite` to `Lax` unless otherwise specified [#1998](https://github.com/getgrav/grav-plugin-admin/issues/1998) + * Exposed **Cookies** class (`Grav.default.Utils.Cookies`) for developers that need it in Admin. +1. [](#bugfix) + * Fixed Plugins references in Themes details page. + * Fixed issue preventing purchase of Themes within Admin and redirecting instead. + * Regression: Values inside Fieldset do not display [#1995](https://github.com/getgrav/grav-plugin-admin/issues/1995) + +# v1.10.0-rc.19 +## 12/02/2020 + +1. [](#improved) + * Just keeping sync with Grav rc.19 + +# v1.10.0-rc.18 +## 12/02/2020 + +1. [](#new) + * Retired "Secure Delete" and "Warn on page delete". You are now always warned and asked to confirm a deletion. +1. [](#improved) + * Auto-link a plugin/theme license in details if it starts with `http` + * Allow to fallback to `docs:` instead of `readme:` + * Forward a `sid` to GPM when downloading a premium package + * Better support for array field key/value when either key or value is stored empty [#1972](https://github.com/getgrav/grav-plugin-admin/issues/1972) + * Remember the open state of the sidebar [#1973](https://github.com/getgrav/grav-plugin-admin/issues/1973) + * Upgraded node dependencies to latest version. Improved speed of JS compilation. + * Added modal to confirm updating Grav as well as cool down counter before enabling Update button [#1257](https://github.com/getgrav/grav-plugin-admin/issues/1257) + * Better handling of offline/intranet mode when the repository index is missing. Faster admin. [#1916](https://github.com/getgrav/grav-plugin-admin/issues/1916) + * Statistics is now Page View Statistics [#1885](https://github.com/getgrav/grav-plugin-admin/issues/1885) + * It is now possible to use regex as values for "Hide page types in Admin" and "Hide modular page types in Admin" settings [#1828](https://github.com/getgrav/grav-plugin-admin/issues/1828) + * Default to `disabled` state for all cron-jobs +1. [](#bugfix) + * Fixed Safari issue with new ACL picker field [#1955](https://github.com/getgrav/grav-plugin-admin/issues/1955) + * Stop propagation of ACL add button in ACL picker [flex-objects#83](https://github.com/trilbymedia/grav-plugin-flex-objects/issues/83) + * Fixed missing special groups `authors` and `defaults` for pages + * Fixed Page Move action and selection highlight in Parents selector modal [flex-objects#80](https://github.com/trilbymedia/grav-plugin-flex-objects/issues/80) + * Fixed folder auto-naming in Add Module [#1937](https://github.com/getgrav/grav-plugin-admin/issues/1937) + * Fixed remodal issue triggering close when selecting a dropdown item ending outside of scope [#1682](https://github.com/getgrav/grav-plugin-admin/issues/1682) + * Reworked how collapsed lists work so the tooltip is not cut off [#1928](https://github.com/getgrav/grav-plugin-admin/issues/1928) + * Fixed KeepAlive issue where too large of a session value would fire the keep alive immediately [#1860](https://github.com/getgrav/grav-plugin-admin/issues/1860) + * Fixed stringable objects breaking the inputs + * Fixed filepicker, pagemediaselect fields with `multiple: true` and `array: true` [#1580](https://github.com/getgrav/grav-plugin-admin/issues/1580) + +# v1.10.0-rc.17 +## 10/07/2020 + +1. [](#new) + * Support premium themes +1. [](#improved) + * Improved some error messages for better readability + * Strip tags from browser title +1. [](#bugfix) + * More multi-site routing fixes + * Fixed issue that would force a page reload when failing to install/update a plugin or theme. + * Fixed proxy/browser caching issues in admin pages + +# v1.10.0-rc.16 +## 09/01/2020 + +1. [](#improved) + * Made all the `onAdmin*` CRUD events to pass `object` (and backwards compatible `page`) to make them easier to use + * Updated vendor libraries including `SCSSPHP` to v1.2 +1. [](#bugfix) + * Fixed issue with File field being used in Theme/Plugins + * Fixed bad redirection after successful admin login in subdirectory multisite [#1487](https://github.com/getgrav/grav-plugin-admin/issues/1487) + +# v1.10.0-rc.15 +## 07/22/2020 + +1. [](#bugfix) + * Disabled the EXIF library for Dropzone for fixing the orientation as it was getting applied twice [#1923](https://github.com/getgrav/grav-plugin-admin/issues/1923) + * Forked Dropzone fo fix issue with Resize + Exif orientation [#1923](https://github.com/getgrav/grav-plugin-admin/issues/1923) + * Fixed URI encode for the preview of images names + +# v1.10.0-rc.14 +## 07/09/2020 + +1. [](#improved) + * Completely removed old Google font support for upgrade compatibility +1. [](#bugfix) + * Fixed bad `use` reference to `UserObject` + +# v1.10.0-rc.13 +## 07/01/2020 + +1. [](#improved) + * Improved color picker field + * Trim login route for safety + * Composer update to grab latest vendor libs + +# v1.10.0-rc.12 +## 06/08/2020 + +1. [](#new) + * Added ability to set a preferred markdown editor in user profile + * Added new `onAdminListContentEditors` event to add a custom editor to the list of available +1. [](#bugfix) + * Fixed issue deleting file from a plugin's configuration + * Use `Pages::find()` instead of `Pages::dispatch()` as we do not want to redirect out of admin + * Fixed broken `parent` field when using the old pages + * Fixed broken `file` field preview when using streams in the path + +# v1.10.0-rc.11 +## 05/14/2020 + +1. [](#new) + * Major enhancements to "White Label" functionality including ability to export/import presets + * New horizontal scroller for theme presets + * Codemirror Fontsize / Preset / Font preference options +1. [](#improved) + * Fixed lots of styling issues related to "White Label" presets + * Changed out "One Light" theme for new "Firewatch Light" theme + * New scrolling system based on `SimpleBar` + native CSS scrollbar styling + +# v1.10.0-rc.10 +## 04/30/2020 + +1. [](#new) + * Addd new `taskConvertUrls` method for use with 3rd party editors + +# v1.10.0-rc.9 +## 04/27/2020 + +1. [](#new) + * Added new "White Label" functionality to customize admin colors + logos + * Added badge count for children in the Parents field +1. [](#improved) + * Added markdown support to `text` in `section` field +1. [](#bugfix) + * Prevent loading Pages in Parents field if they don't have children + * Fixed custom folder in `mediapicker` field not working with streams + * Fixed language redirect adding extra language prefix in Flex + * Fixed `Invalid input in "Parent"` when saving page in raw mode [#1869](https://github.com/getgrav/grav-plugin-admin/issues/1869) + +# v1.10.0-rc.8 +## 03/19/2020 + +1. [](#new) + * Added `has-children` flag in parent field data response + * Added `RESET` en lang string +1. [](#bugfix) + * Fixed parent field not working with regular pages + +# v1.10.0-rc.7 +## 03/05/2020 + +1. [](#new) + * Enable admin cache by default (for existing sites, check `Plugins > Admin Panel > Enable Admin Caching`) +1. [](#improved) + * Removed old `scss.sh` and `watch.sh` scripts, use `gulp watch-css` + * Added keysOnly parameter to `AdminPlugin::pagesTypes()` and `AdminPlugin::pagesModularTypes()` methods + * Added ignore parameter to `Admin::types()` and `Admin::modularTypes()` methods + * Improved configuration fields for hiding page types in Admin +1. [](#bugfix) + * Fixed minor UI padding in Flex pages [#1825](https://github.com/getgrav/grav-plugin-admin/issues/1825) + * Fixed `column` and `section` fields loosing user entered value when form submit fails + * Fixed `order` field not working with a new Flex Page + +# v1.10.0-rc.6 +## 02/11/2020 + +1. [](#new) + * Pass phpstan level 1 tests + * Updated semver library to v1.5 + * Require flex-objects plugin +1. [](#improved) + * Added some debugging messages (turned off by default) + +# v1.10.0-rc.5 +## 02/03/2020 + +1. [](#new) + * No changes, just keeping things in sync with Grav RC version + +# v1.10.0-rc.4 +## 02/03/2020 + +1. [](#new) + * Added message to dashboard to install Flex Objects plugin if it is missing + * Updated `permissions` field to use new `$grav['permissions']` + * DEPRECATED `onAdminRegisterPermissions` event, use `PermissionsRegisterEvent::class` event instead + * DEPRECATED `Admin::setPermissions()` and `Admin::addPermissions()`, use `PermissionsRegisterEvent::class` event instead + * DEPRECATED `Admin::getPermissions()`, use `$grav['permissions']->getInstances()` instead +1. [](#improved) + * Added `field.show_label` and `field.label` display logic from frontend forms +1. [](#bugfix) + * Fixed user profile when using `Flex Users` only in admin + * Fixed saving data with empty field, default value (from config, plugin, theme) was used instead + * Fixed JS bug is using empty Grav URI param key + * Fixed bug in toggleable field being disabled with empty value (`''` `0`, `false`, `[]`...) + * Fixed `admin_route()` twig function to work properly with Grav 1.7.0-rc.4, which fixes `Route` base + * Fixed misleading 'Show sensitive data' configuration option wording [#1818](https://github.com/getgrav/grav-plugin-admin/issues/1818) + +# v1.10.0-rc.3 +## 01/02/2020 + +1. [](#new) + * Added ability to display **Changelogs** for `Grav`, `Plugins` and `Themes` + * Added raw root page support for `Flex Pages` + +# v1.10.0-rc.2 +## 12/04/2019 + +1. [](#new) + * Added support for hiding parts of admin by `Deny` permissions (`Flex Users` only) + * Optimized `parent` field for Flex Pages +1. [](#improved) + * Improved `permissions` field to add support for displaying calculated permissions + * Grav 1.7: Updated deprecated `$page->modular()` method calls to `$page->isModule()` + * Output the current process user name in Scheduler instructions + * Translations: rename MODULAR to MODULE everywhere +1. [](#bugfix) + * Fixed `permissions` field with nested permissions + * Fixed Save Shortcut (CTRL + S / CMD + S) not working with new Flex Pages [#1787](https://github.com/getgrav/grav-plugin-admin/issues/1787) + +# v1.10.0-rc.1 +## 11/06/2019 + +1. [](#new) + * Added a new `onAdminLogFiles()` event for 3rd party plugins to register log files for log viewer [#1765](https://github.com/getgrav/grav-plugin-admin/issues/1765) +1. [](#improved) + * Improved delete button UI [#1769](https://github.com/getgrav/grav-plugin-admin/issues/1769) + * Ability to configure display of 3rd party dashboard widgets [#1766](https://github.com/getgrav/grav-plugin-admin/issues/1766) +1. [](#bugfix) + * Fixed administrator user creation when `Flex Users` is enabled + * Fixed minor button alignment in FF [#1760](https://github.com/getgrav/grav-plugin-admin/issues/1760) + +# v1.10.0-beta.10 +## 10/03/2019 + +1. [](#bugfix) + * Regression: Fixed language assignments for the pages without set language + +# v1.10.0-beta.9 +## 09/26/2019 + +1. [](#bugfix) + * Make pages field to work with Flex Pages + +# v1.10.0-beta.8 +## 09/19/2019 + +1. [](#new) + * Add ability to Sanitize SVGs on file upload + * Add ability to Sanitize SVGs in Page media +1. [](#improved) + * YAML linter report now supports multi-language + * Better colors/placement of toolbar buttons in page edit view +1. [](#bugfix) + * Fixed missing language for AJAX requests + * Fixed redirect with absolute language URL + * Fixed issue with user avatar reference not being deleted when image removed + +# v1.10.0-beta.7 +## 08/30/2019 + +1. [](#bugfix) + * Fixed regression: Do not require Flex Objects plugin [grav#2653](https://github.com/getgrav/grav/issues/2653) + +# v1.10.0-beta.6 +## 08/29/2019 + +1. [](#improved) + * Optimized admin for speed (only load frontend pages on demand) + * Updated navigation menu to be fully controlled and overrideable by `onAdminMenu` event + * Lots of Flex Page speed improvements + +# v1.10.0-beta.5 +## 08/11/2019 + +1. [](#new) + * Added `data()` twig function to create data object from an array +1. [](#improved) + * Better support for `array` field into `list` field + * Made RAW blueprints (expert mode) to work properly with Flex Form + * Better support for `clockwork` logs +1. [](#bugfix) + * Fixed issue with nested `list` fields both utilizing the custom `key` functionality + * Regression: Page Preview not working, bad url [#1715](https://github.com/getgrav/grav-plugin-admin/issues/1715) + * Fixed '+New Folder' to work with new parent picker + * Fixed missing XSS check field when editing modular page as raw + * Fixed minor CSS layout issue [#1717](https://github.com/getgrav/grav-plugin-admin/issues/1717) + +# v1.10.0-beta.4 +## 07/01/2019 + +1. [](#new) + * Added `Admin::redirect()` method to allow redirects to be used outside of controllers + * Added `$admin->adminRoute()` method and `admin_route()` twig function to create language aware admin page links + * Renamed `Admin::route()` to `Admin::getCurrentRoute()` and deprecated the old call +1. [](#improved) + * Much improved multi-language support for pages + * Admin redirects should now work better with multiple languages enabled +1. [](#bugfix) + * Fixed default language being renamed to `page.en.md` (English) instead of keeping existing `page.md` filename + * Fixed possibility to override already existing translation by `Save As Language` + * Fixed missing default translation if page used plain `.md` file extension without language code + * Fixed wrong translation showing up as page fallback language + * Integrated Admin 1.9.8 bug fixes + +# v1.10.0-beta.3 +## 06/24/2019 + +1. [](#improved) + * Smarter handling of symlinks in parent field +1. [](#bugfix) + * Fixed issue with windows paths in `parent` field [#1699](https://github.com/getgrav/grav-plugin-admin/issues/1699) + +# v1.10.0-beta.2 +## 06/21/2019 + +1. [](#improved) + * Moved Remodal in-house and added support for stackable modals [#1698](https://github.com/getgrav/grav-plugin-admin/issues/1698), [#1699](https://github.com/getgrav/grav-plugin-admin/issues/1699) +1. [](#bugfix) + * Fixed missing check for maximum allowed files in `files` field + +# v1.10.0-beta.1 +## 06/14/2019 + +1. [](#new) + * New Parent/Move field using Ajax for better performance + * Improvements to cache clearing when admin cache is enabled + * Require Grav v1.7 + * Use PSR-4 for plugin classes + * Added support for Twig 2.11 (compatible with Twig 1.40+) +1. [](#improved) + * Various admin performance improvements +1. [](#bugfix) + * Fixed admin caching issues + +# v1.9.19 +## 12/14/2020 + +1. [](#bugfix) + * Fixed `pages` field escaping issues, needs Grav update, too [#1990](https://github.com/getgrav/grav-plugin-admin/issues/1990) + * Fixed Plugins references in Themes details page. + * Fixed issue preventing purchase of Themes within Admin and redirecting instead. + * Fixed Page Picker not passing admin token + +# v1.9.18 +## 12/02/2020 + +1. [](#new) + * Never allow Admin pages to be rendered in ``, `'); + return true; + } + + return false; + } + + /** + * Generate HTML from item URL + * + * @access public + * @param Item $item + * @return bool + */ + public function generateHtmlFromUrl(Item $item) + { + if (preg_match('/youtube\.com\/watch\?v=(.*)/', $item->getUrl(), $matches)) { + $item->setContent(''); + return true; + } + + return false; + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Logging/Logger.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Logging/Logger.php new file mode 100644 index 00000000..caec463f --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Logging/Logger.php @@ -0,0 +1,114 @@ +format('Y-m-d H:i:s').'] '.$message; + } + } + + /** + * Get all logged messages. + * + * @static + * + * @return array + */ + public static function getMessages() + { + return self::$messages; + } + + /** + * Remove all logged messages. + * + * @static + */ + public static function deleteMessages() + { + self::$messages = array(); + } + + /** + * Set a different timezone. + * + * @static + * + * @see http://php.net/manual/en/timezones.php + * + * @param string $timezone Timezone + */ + public static function setTimeZone($timezone) + { + self::$timezone = $timezone ?: self::$timezone; + } + + /** + * Get all messages serialized into a string. + * + * @static + * + * @return string + */ + public static function toString() + { + return implode(PHP_EOL, self::$messages).PHP_EOL; + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Atom.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Atom.php new file mode 100644 index 00000000..0496869c --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Atom.php @@ -0,0 +1,395 @@ + 'http://www.w3.org/2005/Atom', + ); + + /** + * Get the path to the items XML tree. + * + * @param SimpleXMLElement $xml Feed xml + * @return SimpleXMLElement[] + */ + public function getItemsTree(SimpleXMLElement $xml) + { + return XmlParser::getXPathResult($xml, 'atom:entry', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'entry'); + } + + /** + * Find the feed url. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedUrl(SimpleXMLElement $xml, Feed $feed) + { + $feed->setFeedUrl($this->getUrl($xml, 'self')); + } + + /** + * Find the site url. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findSiteUrl(SimpleXMLElement $xml, Feed $feed) + { + $feed->setSiteUrl($this->getUrl($xml, 'alternate', true)); + } + + /** + * Find the feed description. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedDescription(SimpleXMLElement $xml, Feed $feed) + { + $description = XmlParser::getXPathResult($xml, 'atom:subtitle', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'subtitle'); + + $feed->setDescription(XmlParser::getValue($description)); + } + + /** + * Find the feed logo url. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedLogo(SimpleXMLElement $xml, Feed $feed) + { + $logo = XmlParser::getXPathResult($xml, 'atom:logo', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'logo'); + + $feed->setLogo(XmlParser::getValue($logo)); + } + + /** + * Find the feed icon. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedIcon(SimpleXMLElement $xml, Feed $feed) + { + $icon = XmlParser::getXPathResult($xml, 'atom:icon', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'icon'); + + $feed->setIcon(XmlParser::getValue($icon)); + } + + /** + * Find the feed title. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedTitle(SimpleXMLElement $xml, Feed $feed) + { + $title = XmlParser::getXPathResult($xml, 'atom:title', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'title'); + + $feed->setTitle(Filter::stripWhiteSpace(XmlParser::getValue($title)) ?: $feed->getSiteUrl()); + } + + /** + * Find the feed language. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedLanguage(SimpleXMLElement $xml, Feed $feed) + { + $language = XmlParser::getXPathResult($xml, '*[not(self::atom:entry)]/@xml:lang', $this->namespaces) + ?: XmlParser::getXPathResult($xml, '@xml:lang'); + + $feed->setLanguage(XmlParser::getValue($language)); + } + + /** + * Find the feed id. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedId(SimpleXMLElement $xml, Feed $feed) + { + $id = XmlParser::getXPathResult($xml, 'atom:id', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'id'); + + $feed->setId(XmlParser::getValue($id)); + } + + /** + * Find the feed date. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedDate(SimpleXMLElement $xml, Feed $feed) + { + $updated = XmlParser::getXPathResult($xml, 'atom:updated', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'updated'); + + $feed->setDate($this->getDateParser()->getDateTime(XmlParser::getValue($updated))); + } + + /** + * Find the item published date. + * + * @param SimpleXMLElement $entry Feed item + * @param Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemPublishedDate(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $date = XmlParser::getXPathResult($entry, 'atom:published', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'published'); + + $item->setPublishedDate(!empty($date) ? $this->getDateParser()->getDateTime((string) current($date)) : null); + } + + /** + * Find the item updated date. + * + * @param SimpleXMLElement $entry Feed item + * @param Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemUpdatedDate(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $date = XmlParser::getXPathResult($entry, 'atom:updated', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'updated'); + + $item->setUpdatedDate(!empty($date) ? $this->getDateParser()->getDateTime((string) current($date)) : null); + } + + /** + * Find the item title. + * + * @param SimpleXMLElement $entry Feed item + * @param Item $item Item object + */ + public function findItemTitle(SimpleXMLElement $entry, Item $item) + { + $title = XmlParser::getXPathResult($entry, 'atom:title', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'title'); + + $item->setTitle(Filter::stripWhiteSpace(XmlParser::getValue($title)) ?: $item->getUrl()); + } + + /** + * Find the item author. + * + * @param SimpleXMLElement $xml Feed + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + */ + public function findItemAuthor(SimpleXMLElement $xml, SimpleXMLElement $entry, Item $item) + { + $author = XmlParser::getXPathResult($entry, 'atom:author/atom:name', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'author/name') + ?: XmlParser::getXPathResult($xml, 'atom:author/atom:name', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'author/name'); + + $item->setAuthor(XmlParser::getValue($author)); + } + + /** + * Find the item author URL. + * + * @param SimpleXMLElement $xml Feed + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + */ + public function findItemAuthorUrl(SimpleXMLElement $xml, SimpleXMLElement $entry, Item $item) + { + $authorUrl = XmlParser::getXPathResult($entry, 'atom:author/atom:uri', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'author/uri') + ?: XmlParser::getXPathResult($xml, 'atom:author/atom:uri', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'author/uri'); + + $item->setAuthorUrl(XmlParser::getValue($authorUrl)); + } + + /** + * Find the item content. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + */ + public function findItemContent(SimpleXMLElement $entry, Item $item) + { + $item->setContent($this->getContent($entry)); + } + + /** + * Find the item URL. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + */ + public function findItemUrl(SimpleXMLElement $entry, Item $item) + { + $item->setUrl($this->getUrl($entry, 'alternate', true)); + } + + /** + * Genereate the item id. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemId(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $id = XmlParser::getXPathResult($entry, 'atom:id', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'id'); + + if (!empty($id)) { + $item->setId($this->generateId(XmlParser::getValue($id))); + } else { + $item->setId($this->generateId( + $item->getTitle(), $item->getUrl(), $item->getContent() + )); + } + } + + /** + * Find the item enclosure. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemEnclosure(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $enclosure = $this->findLink($entry, 'enclosure'); + + if ($enclosure) { + $item->setEnclosureUrl(Url::resolve((string) $enclosure['href'], $feed->getSiteUrl())); + $item->setEnclosureType((string) $enclosure['type']); + } + } + + /** + * Find the item language. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemLanguage(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $language = XmlParser::getXPathResult($entry, './/@xml:lang'); + $item->setLanguage(XmlParser::getValue($language) ?: $feed->getLanguage()); + } + + /** + * Find the item categories. + * + * @param SimpleXMLElement $entry Feed item + * @param Item $item Item object + * @param Feed $feed Feed object + */ + public function findItemCategories(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $categories = XmlParser::getXPathResult($entry, 'atom:category/@term', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'category/@term'); + $item->setCategoriesFromXml($categories); + } + + /** + * Get the URL from a link tag. + * + * @param SimpleXMLElement $xml XML tag + * @param string $rel Link relationship: alternate, enclosure, related, self, via + * @return string + */ + private function getUrl(SimpleXMLElement $xml, $rel, $fallback = false) + { + $link = $this->findLink($xml, $rel); + + if ($link) { + return (string) $link['href']; + } + + if ($fallback) { + $link = $this->findLink($xml, ''); + return $link ? (string) $link['href'] : ''; + } + + return ''; + } + + /** + * Get a link tag that match a relationship. + * + * @param SimpleXMLElement $xml XML tag + * @param string $rel Link relationship: alternate, enclosure, related, self, via + * @return SimpleXMLElement|null + */ + private function findLink(SimpleXMLElement $xml, $rel) + { + $links = XmlParser::getXPathResult($xml, 'atom:link', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'link'); + + foreach ($links as $link) { + if ($rel === (string) $link['rel']) { + return $link; + } + } + + return null; + } + + /** + * Get the entry content. + * + * @param SimpleXMLElement $entry XML Entry + * @return string + */ + private function getContent(SimpleXMLElement $entry) + { + $content = current( + XmlParser::getXPathResult($entry, 'atom:content', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'content') + ); + + if (!empty($content) && count($content->children())) { + $xml_string = ''; + + foreach ($content->children() as $child) { + $xml_string .= $child->asXML(); + } + + return $xml_string; + } elseif (trim((string) $content) !== '') { + return (string) $content; + } + + $summary = XmlParser::getXPathResult($entry, 'atom:summary', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'summary'); + + return (string) current($summary); + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/DateParser.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/DateParser.php new file mode 100644 index 00000000..0e5b80e3 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/DateParser.php @@ -0,0 +1,128 @@ + length ]. + * + * @var array + */ + public $formats = array( + DATE_ATOM => null, + DATE_RSS => null, + DATE_COOKIE => null, + DATE_ISO8601 => null, + DATE_RFC822 => null, + DATE_RFC850 => null, + DATE_RFC1036 => null, + DATE_RFC1123 => null, + DATE_RFC2822 => null, + DATE_RFC3339 => null, + 'l, d M Y H:i:s' => null, + 'D, d M Y H:i:s' => 25, + 'D, d M Y h:i:s' => 25, + 'D M d Y H:i:s' => 24, + 'j M Y H:i:s' => 20, + 'Y-m-d H:i:s' => 19, + 'Y-m-d\TH:i:s' => 19, + 'd/m/Y H:i:s' => 19, + 'D, d M Y' => 16, + 'Y-m-d' => 10, + 'd-m-Y' => 10, + 'm-d-Y' => 10, + 'd.m.Y' => 10, + 'm.d.Y' => 10, + 'd/m/Y' => 10, + 'm/d/Y' => 10, + ); + + /** + * Try to parse all date format for broken feeds. + * + * @param string $value Original date format + * + * @return DateTime + */ + public function getDateTime($value) + { + $value = trim($value); + + foreach ($this->formats as $format => $length) { + $truncated_value = $value; + if ($length !== null) { + $truncated_value = substr($truncated_value, 0, $length); + } + + $date = $this->getValidDate($format, $truncated_value); + if ($date !== false) { + return $date; + } + } + + return $this->getCurrentDateTime(); + } + + /** + * Get a valid date from a given format. + * + * @param string $format Date format + * @param string $value Original date value + * + * @return DateTime|bool + */ + public function getValidDate($format, $value) + { + $date = DateTime::createFromFormat($format, $value, $this->getTimeZone()); + + if ($date !== false) { + $errors = DateTime::getLastErrors(); + + if ($errors['error_count'] === 0 && $errors['warning_count'] === 0) { + return $date; + } + } + + return false; + } + + /** + * Get the current datetime. + * + * @return DateTime + */ + public function getCurrentDateTime() + { + return new DateTime('now', $this->getTimeZone()); + } + + /** + * Get DateTimeZone instance + * + * @access public + * @return DateTimeZone + */ + public function getTimeZone() + { + return new DateTimeZone($this->config->getTimezone() ?: $this->timezone); + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Feed.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Feed.php new file mode 100644 index 00000000..a56e71c3 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Feed.php @@ -0,0 +1,315 @@ +$property.PHP_EOL; + } + + $output .= 'Feed::date = '.$this->date->format(DATE_RFC822).PHP_EOL; + $output .= 'Feed::isRTL() = '.($this->isRTL() ? 'true' : 'false').PHP_EOL; + $output .= 'Feed::items = '.count($this->items).' items'.PHP_EOL; + + foreach ($this->items as $item) { + $output .= '----'.PHP_EOL; + $output .= $item; + } + + return $output; + } + + /** + * Get title. + */ + public function getTitle() + { + return $this->title; + } + + /** + * Get description. + */ + public function getDescription() + { + return $this->description; + } + + /** + * Get the logo url. + */ + public function getLogo() + { + return $this->logo; + } + + /** + * Get the icon url. + */ + public function getIcon() + { + return $this->icon; + } + + /** + * Get feed url. + */ + public function getFeedUrl() + { + return $this->feedUrl; + } + + /** + * Get site url. + */ + public function getSiteUrl() + { + return $this->siteUrl; + } + + /** + * Get date. + */ + public function getDate() + { + return $this->date; + } + + /** + * Get language. + */ + public function getLanguage() + { + return $this->language; + } + + /** + * Get id. + */ + public function getId() + { + return $this->id; + } + + /** + * Get feed items. + */ + public function getItems() + { + return $this->items; + } + + /** + * Return true if the feed is "Right to Left". + * + * @return bool + */ + public function isRTL() + { + return Parser::isLanguageRTL($this->language); + } + + /** + * Set feed items. + * + * @param Item[] $items + * @return Feed + */ + public function setItems(array $items) + { + $this->items = $items; + return $this; + } + + /** + * Set feed id. + * + * @param string $id + * @return Feed + */ + public function setId($id) + { + $this->id = $id; + return $this; + } + + /** + * Set feed title. + * + * @param string $title + * @return Feed + */ + public function setTitle($title) + { + $this->title = $title; + return $this; + } + + /** + * Set feed description. + * + * @param string $description + * @return Feed + */ + public function setDescription($description) + { + $this->description = $description; + return $this; + } + + /** + * Set feed url. + * + * @param string $feedUrl + * @return Feed + */ + public function setFeedUrl($feedUrl) + { + $this->feedUrl = $feedUrl; + return $this; + } + + /** + * Set feed website url. + * + * @param string $siteUrl + * @return Feed + */ + public function setSiteUrl($siteUrl) + { + $this->siteUrl = $siteUrl; + return $this; + } + + /** + * Set feed date. + * + * @param \DateTime $date + * @return Feed + */ + public function setDate($date) + { + $this->date = $date; + return $this; + } + + /** + * Set feed language. + * + * @param string $language + * @return Feed + */ + public function setLanguage($language) + { + $this->language = $language; + return $this; + } + + /** + * Set feed logo. + * + * @param string $logo + * @return Feed + */ + public function setLogo($logo) + { + $this->logo = $logo; + return $this; + } + + /** + * Set feed icon. + * + * @param string $icon + * @return Feed + */ + public function setIcon($icon) + { + $this->icon = $icon; + return $this; + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Item.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Item.php new file mode 100644 index 00000000..98214b8e --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Item.php @@ -0,0 +1,562 @@ +namespaces); + } + + /** + * Get specific XML tag or attribute value. + * + * @param string $tag Tag name (examples: guid, media:content) + * @param string $attribute Tag attribute + * + * @return array|false Tag values or error + */ + public function getTag($tag, $attribute = '') + { + if ($attribute !== '') { + $attribute = '/@'.$attribute; + } + + $query = './/'.$tag.$attribute; + $elements = XmlParser::getXPathResult($this->xml, $query, $this->namespaces); + + if ($elements === false) { // xPath error + return false; + } + + return array_map(function ($element) { return (string) $element;}, $elements); + } + + /** + * Return item information. + * + * @return string + */ + public function __toString() + { + $output = ''; + + foreach (array('id', 'title', 'url', 'language', 'author', 'enclosureUrl', 'enclosureType') as $property) { + $output .= 'Item::'.$property.' = '.$this->$property.PHP_EOL; + } + + $publishedDate = $this->publishedDate != null ? $this->publishedDate->format(DATE_RFC822) : null; + $updatedDate = $this->updatedDate != null ? $this->updatedDate->format(DATE_RFC822) : null; + + $categoryString = $this->categories != null ? implode(',', $this->categories) : null; + + $output .= 'Item::date = '.$this->date->format(DATE_RFC822).PHP_EOL; + $output .= 'Item::publishedDate = '.$publishedDate.PHP_EOL; + $output .= 'Item::updatedDate = '.$updatedDate.PHP_EOL; + $output .= 'Item::isRTL() = '.($this->isRTL() ? 'true' : 'false').PHP_EOL; + $output .= 'Item::categories = ['.$categoryString.']'.PHP_EOL; + $output .= 'Item::content = '.strlen($this->content).' bytes'.PHP_EOL; + + return $output; + } + + /** + * Get title. + * + * @return string + */ + public function getTitle() + { + return $this->title; + } + + /** + * Get URL + * + * @access public + * @return string + */ + public function getUrl() + { + return $this->url; + } + + /** + * Set URL + * + * @access public + * @param string $url + * @return Item + */ + public function setUrl($url) + { + $this->url = $url; + return $this; + } + + /** + * Get id. + * + * @return string + */ + public function getId() + { + return $this->id; + } + + /** + * Get date. + * + * @return \DateTime + */ + public function getDate() + { + return $this->date; + } + + /** + * Get published date. + * + * @return \DateTime + */ + public function getPublishedDate() + { + return $this->publishedDate; + } + + /** + * Get updated date. + * + * @return \DateTime + */ + public function getUpdatedDate() + { + return $this->updatedDate; + } + + /** + * Get content. + * + * @return string + */ + public function getContent() + { + return $this->content; + } + + /** + * Set content + * + * @access public + * @param string $value + * @return Item + */ + public function setContent($value) + { + $this->content = $value; + return $this; + } + + /** + * Get enclosure url. + * + * @return string + */ + public function getEnclosureUrl() + { + return $this->enclosureUrl; + } + + /** + * Get enclosure type. + * + * @return string + */ + public function getEnclosureType() + { + return $this->enclosureType; + } + + /** + * Get language. + * + * @return string + */ + public function getLanguage() + { + return $this->language; + } + + /** + * Get categories. + * + * @return array + */ + public function getCategories() + { + return $this->categories; + } + + /** + * Get author. + * + * @return string + */ + public function getAuthor() + { + return $this->author; + } + + /** + * Get author URL. + * + * @return string + */ + public function getAuthorUrl() + { + return $this->authorUrl; + } + + /** + * Return true if the item is "Right to Left". + * + * @return bool + */ + public function isRTL() + { + return Parser::isLanguageRTL($this->language); + } + + /** + * Set item id. + * + * @param string $id + * @return Item + */ + public function setId($id) + { + $this->id = $id; + return $this; + } + + /** + * Set item title. + * + * @param string $title + * @return Item + */ + public function setTitle($title) + { + $this->title = $title; + return $this; + } + + /** + * Set author. + * + * @param string $author + * @return Item + */ + public function setAuthor($author) + { + $this->author = $author; + return $this; + } + + /** + * Set author URL. + * + * @param string $authorUrl + * @return Item + */ + public function setAuthorUrl($authorUrl) + { + $this->authorUrl = $authorUrl; + return $this; + } + + /** + * Set item date. + * + * @param \DateTime $date + * @return Item + */ + public function setDate($date) + { + $this->date = $date; + return $this; + } + + /** + * Set item published date. + * + * @param \DateTime $publishedDate + * @return Item + */ + public function setPublishedDate($publishedDate) + { + $this->publishedDate = $publishedDate; + return $this; + } + + /** + * Set item updated date. + * + * @param \DateTime $updatedDate + * @return Item + */ + public function setUpdatedDate($updatedDate) + { + $this->updatedDate = $updatedDate; + return $this; + } + + /** + * Set enclosure url. + * + * @param string $enclosureUrl + * @return Item + */ + public function setEnclosureUrl($enclosureUrl) + { + $this->enclosureUrl = $enclosureUrl; + return $this; + } + + /** + * Set enclosure type. + * + * @param string $enclosureType + * @return Item + */ + public function setEnclosureType($enclosureType) + { + $this->enclosureType = $enclosureType; + return $this; + } + + /** + * Set item language. + * + * @param string $language + * @return Item + */ + public function setLanguage($language) + { + $this->language = $language; + return $this; + } + + /** + * Set item categories. + * + * @param array $categories + * @return Item + */ + public function setCategories($categories) + { + $this->categories = $categories; + return $this; + } + + /** + * Set item categories from xml. + * + * @param |SimpleXMLElement[] $categories + * @return Item + */ + public function setCategoriesFromXml($categories) + { + if ($categories !== false) { + $this->setCategories( + array_map( + function ($element) { + return trim((string) $element); + }, + $categories + ) + ); + } + + return $this; + } + + /** + * Set raw XML. + * + * @param \SimpleXMLElement $xml + * @return Item + */ + public function setXml($xml) + { + $this->xml = $xml; + return $this; + } + + /** + * Get raw XML. + * + * @return \SimpleXMLElement + */ + public function getXml() + { + return $this->xml; + } + + /** + * Set XML namespaces. + * + * @param array $namespaces + * @return Item + */ + public function setNamespaces($namespaces) + { + $this->namespaces = $namespaces; + return $this; + } + + /** + * Get XML namespaces. + * + * @return array + */ + public function getNamespaces() + { + return $this->namespaces; + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/MalformedXmlException.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/MalformedXmlException.php new file mode 100644 index 00000000..efaf0ff1 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/MalformedXmlException.php @@ -0,0 +1,13 @@ +fallback_url = $fallback_url; + $xml_encoding = XmlParser::getEncodingFromXmlTag($content); + + // Strip XML tag to avoid multiple encoding/decoding in the next XML processing + $this->content = Filter::stripXmlTag($content); + + // Encode everything in UTF-8 + Logger::setMessage(get_called_class().': HTTP Encoding "'.$http_encoding.'" ; XML Encoding "'.$xml_encoding.'"'); + $this->content = Encoding::convert($this->content, $xml_encoding ?: $http_encoding); + + $this->itemPostProcessor = new ItemPostProcessor($this->config); + $this->itemPostProcessor->register(new ContentGeneratorProcessor($this->config)); + $this->itemPostProcessor->register(new ContentFilterProcessor($this->config)); + } + + /** + * Parse the document. + * @return Feed + * @throws MalformedXmlException + */ + public function execute() + { + Logger::setMessage(get_called_class().': begin parsing'); + + $xml = XmlParser::getSimpleXml($this->content); + + if ($xml === false) { + Logger::setMessage(get_called_class().': Applying XML workarounds'); + $this->content = Filter::normalizeData($this->content); + $xml = XmlParser::getSimpleXml($this->content); + + if ($xml === false) { + Logger::setMessage(get_called_class().': XML parsing error'); + Logger::setMessage(XmlParser::getErrors()); + throw new MalformedXmlException('XML parsing error'); + } + } + + $this->used_namespaces = $xml->getNamespaces(true); + $xml = $this->registerSupportedNamespaces($xml); + + $feed = new Feed(); + + $this->findFeedUrl($xml, $feed); + $this->checkFeedUrl($feed); + + $this->findSiteUrl($xml, $feed); + $this->checkSiteUrl($feed); + + $this->findFeedTitle($xml, $feed); + $this->findFeedDescription($xml, $feed); + $this->findFeedLanguage($xml, $feed); + $this->findFeedId($xml, $feed); + $this->findFeedDate($xml, $feed); + $this->findFeedLogo($xml, $feed); + $this->findFeedIcon($xml, $feed); + + foreach ($this->getItemsTree($xml) as $entry) { + $entry = $this->registerSupportedNamespaces($entry); + + $item = new Item(); + $item->xml = $entry; + $item->namespaces = $this->used_namespaces; + + $this->findItemAuthor($xml, $entry, $item); + $this->findItemAuthorUrl($xml, $entry, $item); + + $this->findItemUrl($entry, $item); + $this->checkItemUrl($feed, $item); + + $this->findItemTitle($entry, $item); + $this->findItemContent($entry, $item); + + // Id generation can use the item url/title/content (order is important) + $this->findItemId($entry, $item, $feed); + $this->findItemDate($entry, $item, $feed); + $this->findItemEnclosure($entry, $item, $feed); + $this->findItemLanguage($entry, $item, $feed); + $this->findItemCategories($entry, $item, $feed); + + $this->itemPostProcessor->execute($feed, $item); + $feed->items[] = $item; + } + + Logger::setMessage(get_called_class().PHP_EOL.$feed); + + return $feed; + } + + /** + * Check if the feed url is correct. + * + * @param Feed $feed Feed object + */ + public function checkFeedUrl(Feed $feed) + { + if ($feed->getFeedUrl() === '') { + $feed->feedUrl = $this->fallback_url; + } else { + $feed->feedUrl = Url::resolve($feed->getFeedUrl(), $this->fallback_url); + } + } + + /** + * Check if the site url is correct. + * + * @param Feed $feed Feed object + */ + public function checkSiteUrl(Feed $feed) + { + if ($feed->getSiteUrl() === '') { + $feed->siteUrl = Url::base($feed->getFeedUrl()); + } else { + $feed->siteUrl = Url::resolve($feed->getSiteUrl(), $this->fallback_url); + } + } + + /** + * Check if the item url is correct. + * + * @param Feed $feed Feed object + * @param Item $item Item object + */ + public function checkItemUrl(Feed $feed, Item $item) + { + $item->url = Url::resolve($item->getUrl(), $feed->getSiteUrl()); + } + + /** + * Find the item date. + * + * @param SimpleXMLElement $entry Feed item + * @param Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemDate(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $this->findItemPublishedDate($entry, $item, $feed); + $this->findItemUpdatedDate($entry, $item, $feed); + + if ($item->getPublishedDate() === null) { + // Use the updated date if available, otherwise use the feed date + $item->setPublishedDate($item->getUpdatedDate() ?: $feed->getDate()); + } + + if ($item->getUpdatedDate() === null) { + // Use the published date as fallback + $item->setUpdatedDate($item->getPublishedDate()); + } + + // Use the most recent of published and updated dates + $item->setDate(max($item->getPublishedDate(), $item->getUpdatedDate())); + } + + /** + * Get Item Post Processor instance + * + * @access public + * @return ItemPostProcessor + */ + public function getItemPostProcessor() + { + return $this->itemPostProcessor; + } + + /** + * Get DateParser instance + * + * @access public + * @return DateParser + */ + public function getDateParser() + { + if ($this->dateParser === null) { + $this->dateParser = new DateParser($this->config); + } + + return $this->dateParser; + } + + /** + * Generate a unique id for an entry (hash all arguments). + * + * @return string + */ + public function generateId() + { + return hash($this->hash_algo, implode(func_get_args())); + } + + /** + * Return true if the given language is "Right to Left". + * + * @static + * @param string $language Language: fr-FR, en-US + * @return bool + */ + public static function isLanguageRTL($language) + { + $language = strtolower($language); + + $rtl_languages = array( + 'ar', // Arabic (ar-**) + 'fa', // Farsi (fa-**) + 'ur', // Urdu (ur-**) + 'ps', // Pashtu (ps-**) + 'syr', // Syriac (syr-**) + 'dv', // Divehi (dv-**) + 'he', // Hebrew (he-**) + 'yi', // Yiddish (yi-**) + ); + + foreach ($rtl_languages as $prefix) { + if (strpos($language, $prefix) === 0) { + return true; + } + } + + return false; + } + + /** + * Set Hash algorithm used for id generation. + * + * @param string $algo Algorithm name + * @return \PicoFeed\Parser\Parser + */ + public function setHashAlgo($algo) + { + $this->hash_algo = $algo ?: $this->hash_algo; + return $this; + } + + /** + * Set config object. + * + * @param \PicoFeed\Config\Config $config Config instance + * @return \PicoFeed\Parser\Parser + */ + public function setConfig($config) + { + $this->config = $config; + $this->itemPostProcessor->setConfig($config); + return $this; + } + + /** + * Enable the content grabber. + * + * @return \PicoFeed\Parser\Parser + */ + public function disableContentFiltering() + { + $this->itemPostProcessor->unregister('PicoFeed\Processor\ContentFilterProcessor'); + return $this; + } + + /** + * Enable the content grabber. + * + * @param bool $needsRuleFile true if only pages with rule files should be + * scraped + * @param null|\Closure $scraperCallback Callback function that gets called for each + * scraper execution + * @return \PicoFeed\Parser\Parser + */ + public function enableContentGrabber($needsRuleFile = false, $scraperCallback = null) + { + $processor = new ScraperProcessor($this->config); + + if ($needsRuleFile) { + $processor->getScraper()->disableCandidateParser(); + } + + if ($scraperCallback !== null) { + $processor->setExecutionCallback($scraperCallback); + } + + $this->itemPostProcessor->register($processor); + return $this; + } + + /** + * Set ignored URLs for the content grabber. + * + * @param array $urls URLs + * @return \PicoFeed\Parser\Parser + */ + public function setGrabberIgnoreUrls(array $urls) + { + $this->itemPostProcessor->getProcessor('PicoFeed\Processor\ScraperProcessor')->ignoreUrls($urls); + return $this; + } + + /** + * Register all supported namespaces to be used within an xpath query. + * + * @param SimpleXMLElement $xml Feed xml + * @return SimpleXMLElement + */ + public function registerSupportedNamespaces(SimpleXMLElement $xml) + { + foreach ($this->namespaces as $prefix => $ns) { + $xml->registerXPathNamespace($prefix, $ns); + } + + return $xml; + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/ParserException.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/ParserException.php new file mode 100644 index 00000000..b5fbb699 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/ParserException.php @@ -0,0 +1,15 @@ + 'http://purl.org/rss/1.0/', + 'dc' => 'http://purl.org/dc/elements/1.1/', + 'content' => 'http://purl.org/rss/1.0/modules/content/', + 'feedburner' => 'http://rssnamespace.org/feedburner/ext/1.0', + ); + + /** + * Get the path to the items XML tree. + * + * @param SimpleXMLElement $xml Feed xml + * @return SimpleXMLElement[] + */ + public function getItemsTree(SimpleXMLElement $xml) + { + return XmlParser::getXPathResult($xml, 'rss:item', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'item') + ?: $xml->item; + } + + /** + * Find the feed url. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedUrl(SimpleXMLElement $xml, Feed $feed) + { + $feed->setFeedUrl(''); + } + + /** + * Find the site url. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findSiteUrl(SimpleXMLElement $xml, Feed $feed) + { + $value = XmlParser::getXPathResult($xml, 'rss:channel/rss:link', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'channel/link') + ?: $xml->channel->link; + + $feed->setSiteUrl(XmlParser::getValue($value)); + } + + /** + * Find the feed description. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedDescription(SimpleXMLElement $xml, Feed $feed) + { + $description = XmlParser::getXPathResult($xml, 'rss:channel/rss:description', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'channel/description') + ?: $xml->channel->description; + + $feed->setDescription(XmlParser::getValue($description)); + } + + /** + * Find the feed logo url. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedLogo(SimpleXMLElement $xml, Feed $feed) + { + $logo = XmlParser::getXPathResult($xml, 'rss:image/rss:url', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'image/url'); + + $feed->setLogo(XmlParser::getValue($logo)); + } + + /** + * Find the feed icon. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedIcon(SimpleXMLElement $xml, Feed $feed) + { + $feed->setIcon(''); + } + + /** + * Find the feed title. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedTitle(SimpleXMLElement $xml, Feed $feed) + { + $title = XmlParser::getXPathResult($xml, 'rss:channel/rss:title', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'channel/title') + ?: $xml->channel->title; + + $feed->setTitle(Filter::stripWhiteSpace(XmlParser::getValue($title)) ?: $feed->getSiteUrl()); + } + + /** + * Find the feed language. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedLanguage(SimpleXMLElement $xml, Feed $feed) + { + $language = XmlParser::getXPathResult($xml, 'rss:channel/dc:language', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'channel/dc:language', $this->namespaces); + + $feed->setLanguage(XmlParser::getValue($language)); + } + + /** + * Find the feed id. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedId(SimpleXMLElement $xml, Feed $feed) + { + $feed->setId($feed->getFeedUrl() ?: $feed->getSiteUrl()); + } + + /** + * Find the feed date. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedDate(SimpleXMLElement $xml, Feed $feed) + { + $date = XmlParser::getXPathResult($xml, 'rss:channel/dc:date', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'channel/dc:date', $this->namespaces); + + $feed->setDate($this->getDateParser()->getDateTime(XmlParser::getValue($date))); + } + + /** + * Find the item published date. + * + * @param SimpleXMLElement $entry Feed item + * @param Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemPublishedDate(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $date = XmlParser::getXPathResult($entry, 'dc:date', $this->namespaces); + + $item->setPublishedDate(!empty($date) ? $this->getDateParser()->getDateTime(XmlParser::getValue($date)) : null); + } + + /** + * Find the item updated date. + * + * @param SimpleXMLElement $entry Feed item + * @param Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemUpdatedDate(SimpleXMLElement $entry, Item $item, Feed $feed) + { + if ($item->publishedDate === null) { + $this->findItemPublishedDate($entry, $item, $feed); + } + $item->setUpdatedDate($item->getPublishedDate()); // No updated date in RSS 1.0 specifications + } + + /** + * Find the item title. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + */ + public function findItemTitle(SimpleXMLElement $entry, Item $item) + { + $title = XmlParser::getXPathResult($entry, 'rss:title', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'title') + ?: $entry->title; + + $item->setTitle(Filter::stripWhiteSpace(XmlParser::getValue($title)) ?: $item->getUrl()); + } + + /** + * Find the item author. + * + * @param SimpleXMLElement $xml Feed + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + */ + public function findItemAuthor(SimpleXMLElement $xml, SimpleXMLElement $entry, Item $item) + { + $author = XmlParser::getXPathResult($entry, 'dc:creator', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'rss:channel/dc:creator', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'channel/dc:creator', $this->namespaces); + + $item->setAuthor(XmlParser::getValue($author)); + } + + /** + * Find the item author URL. + * + * @param SimpleXMLElement $xml Feed + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + */ + public function findItemAuthorUrl(SimpleXMLElement $xml, SimpleXMLElement $entry, Item $item) + { + // There appears to be no support for author URL in the dc: terms + $item->setAuthorUrl(''); + } + + /** + * Find the item content. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + */ + public function findItemContent(SimpleXMLElement $entry, Item $item) + { + $content = XmlParser::getXPathResult($entry, 'content:encoded', $this->namespaces); + + if (XmlParser::getValue($content) === '') { + $content = XmlParser::getXPathResult($entry, 'rss:description', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'description') + ?: $entry->description; + } + + $item->setContent(XmlParser::getValue($content)); + } + + /** + * Find the item URL. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + */ + public function findItemUrl(SimpleXMLElement $entry, Item $item) + { + $link = XmlParser::getXPathResult($entry, 'feedburner:origLink', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'rss:link', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'link') + ?: $entry->link; + + $item->setUrl(XmlParser::getValue($link)); + } + + /** + * Genereate the item id. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemId(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $item->setId($this->generateId( + $item->getTitle(), $item->getUrl(), $item->getContent() + )); + } + + /** + * Find the item enclosure. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemEnclosure(SimpleXMLElement $entry, Item $item, Feed $feed) + { + } + + /** + * Find the item language. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemLanguage(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $language = XmlParser::getXPathResult($entry, 'dc:language', $this->namespaces); + + $item->setLanguage(XmlParser::getValue($language) ?: $feed->getLanguage()); + } + + /** + * Find the item categories. + * + * @param SimpleXMLElement $entry Feed item + * @param Item $item Item object + * @param Feed $feed Feed object + */ + public function findItemCategories(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $categories = XmlParser::getXPathResult($entry, 'dc:subject', $this->namespaces); + $item->setCategoriesFromXml($categories); + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Rss20.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Rss20.php new file mode 100644 index 00000000..da9c0d5f --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Rss20.php @@ -0,0 +1,330 @@ + 'http://purl.org/dc/elements/1.1/', + 'content' => 'http://purl.org/rss/1.0/modules/content/', + 'feedburner' => 'http://rssnamespace.org/feedburner/ext/1.0', + 'atom' => 'http://www.w3.org/2005/Atom', + ); + + /** + * Get the path to the items XML tree. + * + * @param SimpleXMLElement $xml Feed xml + * @return SimpleXMLElement[] + */ + public function getItemsTree(SimpleXMLElement $xml) + { + return XmlParser::getXPathResult($xml, 'channel/item'); + } + + /** + * Find the feed url. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedUrl(SimpleXMLElement $xml, Feed $feed) + { + $feed->setFeedUrl(''); + } + + /** + * Find the site url. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findSiteUrl(SimpleXMLElement $xml, Feed $feed) + { + $value = XmlParser::getXPathResult($xml, 'channel/link'); + $feed->setSiteUrl(XmlParser::getValue($value)); + } + + /** + * Find the feed description. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedDescription(SimpleXMLElement $xml, Feed $feed) + { + $value = XmlParser::getXPathResult($xml, 'channel/description'); + $feed->setDescription(XmlParser::getValue($value)); + } + + /** + * Find the feed logo url. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedLogo(SimpleXMLElement $xml, Feed $feed) + { + $value = XmlParser::getXPathResult($xml, 'channel/image/url'); + $feed->setLogo(XmlParser::getValue($value)); + } + + /** + * Find the feed icon. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedIcon(SimpleXMLElement $xml, Feed $feed) + { + $feed->setIcon(''); + } + + /** + * Find the feed title. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedTitle(SimpleXMLElement $xml, Feed $feed) + { + $title = XmlParser::getXPathResult($xml, 'channel/title'); + $feed->setTitle(Filter::stripWhiteSpace(XmlParser::getValue($title)) ?: $feed->getSiteUrl()); + } + + /** + * Find the feed language. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedLanguage(SimpleXMLElement $xml, Feed $feed) + { + $value = XmlParser::getXPathResult($xml, 'channel/language'); + $feed->setLanguage(XmlParser::getValue($value)); + } + + /** + * Find the feed id. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedId(SimpleXMLElement $xml, Feed $feed) + { + $feed->setId($feed->getFeedUrl() ?: $feed->getSiteUrl()); + } + + /** + * Find the feed date. + * + * @param SimpleXMLElement $xml Feed xml + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findFeedDate(SimpleXMLElement $xml, Feed $feed) + { + $publish_date = XmlParser::getXPathResult($xml, 'channel/pubDate'); + $update_date = XmlParser::getXPathResult($xml, 'channel/lastBuildDate'); + + $published = !empty($publish_date) ? $this->getDateParser()->getDateTime(XmlParser::getValue($publish_date)) : null; + $updated = !empty($update_date) ? $this->getDateParser()->getDateTime(XmlParser::getValue($update_date)) : null; + + if ($published === null && $updated === null) { + $feed->setDate($this->getDateParser()->getCurrentDateTime()); // We use the current date if there is no date for the feed + } elseif ($published !== null && $updated !== null) { + $feed->setDate(max($published, $updated)); // We use the most recent date between published and updated + } else { + $feed->setDate($updated ?: $published); + } + } + + /** + * Find the item published date. + * + * @param SimpleXMLElement $entry Feed item + * @param Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemPublishedDate(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $date = XmlParser::getXPathResult($entry, 'pubDate'); + + $item->setPublishedDate(!empty($date) ? $this->getDateParser()->getDateTime(XmlParser::getValue($date)) : null); + } + + /** + * Find the item updated date. + * + * @param SimpleXMLElement $entry Feed item + * @param Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemUpdatedDate(SimpleXMLElement $entry, Item $item, Feed $feed) + { + if ($item->publishedDate === null) { + $this->findItemPublishedDate($entry, $item, $feed); + } + $item->setUpdatedDate($item->getPublishedDate()); // No updated date in RSS 2.0 specifications + } + + /** + * Find the item title. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + */ + public function findItemTitle(SimpleXMLElement $entry, Item $item) + { + $value = XmlParser::getXPathResult($entry, 'title'); + $item->setTitle(Filter::stripWhiteSpace(XmlParser::getValue($value)) ?: $item->getUrl()); + } + + /** + * Find the item author. + * + * @param SimpleXMLElement $xml Feed + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + */ + public function findItemAuthor(SimpleXMLElement $xml, SimpleXMLElement $entry, Item $item) + { + $value = XmlParser::getXPathResult($entry, 'dc:creator', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'author') + ?: XmlParser::getXPathResult($xml, 'channel/dc:creator', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'channel/managingEditor'); + + $item->setAuthor(XmlParser::getValue($value)); + } + + /** + * Find the item author URL. + * + * @param SimpleXMLElement $xml Feed + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + */ + public function findItemAuthorUrl(SimpleXMLElement $xml, SimpleXMLElement $entry, Item $item) + { + // There appears to be no support for author URL in the dc: terms or author element + $item->setAuthorUrl(''); + } + + /** + * Find the item content. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + */ + public function findItemContent(SimpleXMLElement $entry, Item $item) + { + $content = XmlParser::getXPathResult($entry, 'content:encoded', $this->namespaces); + + if (XmlParser::getValue($content) === '') { + $content = XmlParser::getXPathResult($entry, 'description'); + } + + $item->setContent(XmlParser::getValue($content)); + } + + /** + * Find the item URL. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + */ + public function findItemUrl(SimpleXMLElement $entry, Item $item) + { + $link = XmlParser::getXPathResult($entry, 'feedburner:origLink', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'link') + ?: XmlParser::getXPathResult($entry, 'atom:link/@href', $this->namespaces); + + if (!empty($link)) { + $item->setUrl(XmlParser::getValue($link)); + } else { + $link = XmlParser::getXPathResult($entry, 'guid'); + $link = XmlParser::getValue($link); + + if (filter_var($link, FILTER_VALIDATE_URL) !== false) { + $item->setUrl($link); + } + } + } + + /** + * Genereate the item id. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemId(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $id = XmlParser::getValue(XmlParser::getXPathResult($entry, 'guid')); + + if ($id) { + $item->setId($this->generateId($id)); + } else { + $item->setId($this->generateId( + $item->getTitle(), $item->getUrl(), $item->getContent() + )); + } + } + + /** + * Find the item enclosure. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemEnclosure(SimpleXMLElement $entry, Item $item, Feed $feed) + { + if (isset($entry->enclosure)) { + $type = XmlParser::getXPathResult($entry, 'enclosure/@type'); + $url = XmlParser::getXPathResult($entry, 'feedburner:origEnclosureLink', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'enclosure/@url'); + + $item->setEnclosureUrl(Url::resolve(XmlParser::getValue($url), $feed->getSiteUrl())); + $item->setEnclosureType(XmlParser::getValue($type)); + } + } + + /** + * Find the item language. + * + * @param SimpleXMLElement $entry Feed item + * @param \PicoFeed\Parser\Item $item Item object + * @param \PicoFeed\Parser\Feed $feed Feed object + */ + public function findItemLanguage(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $language = XmlParser::getXPathResult($entry, 'dc:language', $this->namespaces); + $item->setLanguage(XmlParser::getValue($language) ?: $feed->getLanguage()); + } + + /** + * Find the item categories. + * + * @param SimpleXMLElement $entry Feed item + * @param Item $item Item object + * @param Feed $feed Feed object + */ + public function findItemCategories(SimpleXMLElement $entry, Item $item, Feed $feed) + { + $categories = XmlParser::getXPathResult($entry, 'category'); + $item->setCategoriesFromXml($categories); + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Rss91.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Rss91.php new file mode 100644 index 00000000..058fca1b --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Rss91.php @@ -0,0 +1,13 @@ +childNodes->length === 0) { + return false; + } + + return $dom; + } + + /** + * Small wrapper around Laminas Xml to turn their exceptions into PicoFeed exceptions + * + * @static + * @access private + * @param string $input + * @param DOMDocument $dom + * @throws XmlEntityException + * @return SimpleXMLElement|DomDocument|boolean + */ + private static function scan($input, $dom = null) + { + try { + return Security::scan($input, $dom); + } catch(RuntimeException $e) { + throw new XmlEntityException($e->getMessage()); + } + } + + /** + * Load HTML document by using a DomDocument instance or return false on failure. + * + * @static + * @access public + * @param string $input XML content + * @return DOMDocument + */ + public static function getHtmlDocument($input) + { + $dom = new DomDocument(); + + if (empty($input)) { + return $dom; + } + + libxml_use_internal_errors(true); + + if (version_compare(PHP_VERSION, '5.4.0', '>=')) { + $dom->loadHTML($input, LIBXML_NONET); + } else { + $dom->loadHTML($input); + } + + self::$errors = []; + foreach (libxml_get_errors() as $error) { + self::$errors[] = sprintf('XML error: %s (Line: %d - Column: %d - Code: %d)', + $error->message, + $error->line, + $error->column, + $error->code + ); + } + + libxml_use_internal_errors(false); + + return $dom; + } + + /** + * Convert a HTML document to XML. + * + * @static + * @access public + * @param string $html HTML document + * @return string + */ + public static function htmlToXml($html) + { + $dom = self::getHtmlDocument(''.$html); + return $dom->saveXML($dom->getElementsByTagName('body')->item(0)); + } + + /** + * Get XML parser errors. + * + * @static + * @access public + * @return string + */ + public static function getErrors() + { + return implode(', ', self::$errors); + } + + /** + * Get the encoding from a xml tag. + * + * @static + * @access public + * @param string $data Input data + * @return string + */ + public static function getEncodingFromXmlTag($data) + { + $encoding = ''; + + if (strpos($data, '')); + $data = str_replace("'", '"', $data); + + $p1 = strpos($data, 'encoding='); + $p2 = strpos($data, '"', $p1 + 10); + + if ($p1 !== false && $p2 !== false) { + $encoding = substr($data, $p1 + 10, $p2 - $p1 - 10); + $encoding = strtolower($encoding); + } + } + + return $encoding; + } + + /** + * Get the charset from a meta tag. + * + * @static + * @access public + * @param string $data Input data + * @return string + */ + public static function getEncodingFromMetaTag($data) + { + $encoding = ''; + + if (preg_match('/;]+)/i', $data, $match) === 1) { + $encoding = strtolower($match[1]); + } + + return $encoding; + } + + /** + * Rewrite XPath query to use namespace-uri and local-name derived from prefix. + * + * @static + * @access public + * @param string $query XPath query + * @param array $ns Prefix to namespace URI mapping + * @return string + */ + public static function replaceXPathPrefixWithNamespaceURI($query, array $ns) + { + return preg_replace_callback('/([A-Z0-9]+):([A-Z0-9]+)/iu', function ($matches) use ($ns) { + // don't try to map the special prefix XML + if (strtolower($matches[1]) === 'xml') { + return $matches[0]; + } + + return '*[namespace-uri()="'.$ns[$matches[1]].'" and local-name()="'.$matches[2].'"]'; + }, + $query); + } + + /** + * Get the result elements of a XPath query. + * + * @static + * @access public + * @param SimpleXMLElement $xml XML element + * @param string $query XPath query + * @param array $ns Prefix to namespace URI mapping + * @return SimpleXMLElement[] + */ + public static function getXPathResult(SimpleXMLElement $xml, $query, array $ns = array()) + { + if (!empty($ns)) { + $query = static::replaceXPathPrefixWithNamespaceURI($query, $ns); + } + + return $xml->xpath($query); + } + + /** + * Get the first Xpath result or SimpleXMLElement value + * + * @static + * @access public + * @param mixed $value + * @return string + */ + public static function getValue($value) + { + $result = ''; + + if (is_array($value) && count($value) > 0) { + $result = (string) $value[0]; + } elseif (is_a($value, 'SimpleXMLElement')) { + return $result = (string) $value; + } + + return trim($result); + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/PicoFeedException.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/PicoFeedException.php new file mode 100644 index 00000000..2de9e4b7 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/PicoFeedException.php @@ -0,0 +1,14 @@ +config->getContentFiltering(true)) { + $filter = Filter::html($item->getContent(), $feed->getSiteUrl()); + $filter->setConfig($this->config); + $item->setContent($filter->execute()); + } else { + Logger::setMessage(get_called_class().': Content filtering disabled'); + } + + return false; + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ContentGeneratorProcessor.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ContentGeneratorProcessor.php new file mode 100644 index 00000000..49adf9cc --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ContentGeneratorProcessor.php @@ -0,0 +1,49 @@ +generators as $generator) { + $className = '\PicoFeed\Generator\\'.ucfirst($generator).'ContentGenerator'; + $object = new $className($this->config); + + if ($object->execute($item)) { + return true; + } + } + + return false; + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ItemPostProcessor.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ItemPostProcessor.php new file mode 100644 index 00000000..7b092b50 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ItemPostProcessor.php @@ -0,0 +1,106 @@ +processors as $processor) { + if ($processor->execute($feed, $item)) { + return true; + } + } + + return false; + } + + /** + * Register a new Item post-processor + * + * @access public + * @param ItemProcessorInterface $processor + * @return ItemPostProcessor + */ + public function register(ItemProcessorInterface $processor) + { + $this->processors[get_class($processor)] = $processor; + return $this; + } + + /** + * Remove Processor instance + * + * @access public + * @param string $class + * @return ItemPostProcessor + */ + public function unregister($class) + { + if (isset($this->processors[$class])) { + unset($this->processors[$class]); + } + + return $this; + } + + /** + * Checks whether a specific processor is registered or not + * + * @access public + * @param string $class + * @return bool + */ + public function hasProcessor($class) + { + return isset($this->processors[$class]); + } + + /** + * Get Processor instance + * + * @access public + * @param string $class + * @return ItemProcessorInterface|null + */ + public function getProcessor($class) + { + return isset($this->processors[$class]) ? $this->processors[$class] : null; + } + + public function setConfig(Config $config) + { + foreach ($this->processors as $processor) { + $processor->setConfig($config); + } + + return false; + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ItemProcessorInterface.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ItemProcessorInterface.php new file mode 100644 index 00000000..5d532262 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ItemProcessorInterface.php @@ -0,0 +1,25 @@ +executionCallback = $executionCallback; + return $this; + } + + /** + * Execute Item Processor + * + * @access public + * @param Feed $feed + * @param Item $item + * @return bool + */ + public function execute(Feed $feed, Item $item) + { + if (!in_array($item->getUrl(), $this->ignoredUrls)) { + $scraper = $this->getScraper(); + $scraper->setUrl($item->getUrl()); + $scraper->execute(); + + if ($this->executionCallback && is_callable($this->executionCallback)) { + call_user_func($this->executionCallback, $feed, $item, $scraper); + } + + if ($scraper->hasRelevantContent()) { + $item->setContent($scraper->getFilteredContent()); + } + } + + return false; + } + + /** + * Ignore list of URLs + * + * @access public + * @param array $urls + * @return $this + */ + public function ignoreUrls(array $urls) + { + $this->ignoredUrls = $urls; + return $this; + } + + /** + * Returns Scraper instance + * + * @access public + * @return Scraper + */ + public function getScraper() + { + if ($this->scraper === null) { + $this->scraper = new Scraper($this->config); + } + + return $this->scraper; + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/Favicon.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/Favicon.php new file mode 100644 index 00000000..d4ca07db --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/Favicon.php @@ -0,0 +1,186 @@ +content; + } + + /** + * Get the icon file type (available only after the download). + * + * @return string + */ + public function getType() + { + foreach ($this->types as $type) { + if (strpos($this->content_type, $type) === 0) { + return $type; + } + } + + return 'image/x-icon'; + } + + /** + * Get data URI (http://en.wikipedia.org/wiki/Data_URI_scheme). + * + * @return string + */ + public function getDataUri() + { + if (empty($this->content)) { + return ''; + } + + return sprintf( + 'data:%s;base64,%s', + $this->getType(), + base64_encode($this->content) + ); + } + + /** + * Download and check if a resource exists. + * + * @param string $url URL + * @return \PicoFeed\Client\Client Client instance + */ + public function download($url) + { + $client = Client::getInstance(); + $client->setConfig($this->config); + + Logger::setMessage(get_called_class().' Download => '.$url); + + try { + $client->execute($url); + } catch (ClientException $e) { + Logger::setMessage(get_called_class().' Download Failed => '.$e->getMessage()); + } + + return $client; + } + + /** + * Check if a remote file exists. + * + * @param string $url URL + * @return bool + */ + public function exists($url) + { + return $this->download($url)->getContent() !== ''; + } + + /** + * Get the icon link for a website. + * + * @param string $website_link URL + * @param string $favicon_link optional URL + * @return string + */ + public function find($website_link, $favicon_link = '') + { + $website = new Url($website_link); + + if ($favicon_link !== '') { + $icons = array($favicon_link); + } else { + $icons = $this->extract($this->download($website->getBaseUrl('/'))->getContent()); + $icons[] = $website->getBaseUrl('/favicon.ico'); + } + + foreach ($icons as $icon_link) { + $icon_link = Url::resolve($icon_link, $website); + $resource = $this->download($icon_link); + $this->content = $resource->getContent(); + $this->content_type = $resource->getContentType(); + + if ($this->content !== '') { + return $icon_link; + } elseif ($favicon_link !== '') { + return $this->find($website_link); + } + } + + return ''; + } + + /** + * Extract the icon links from the HTML. + * + * @param string $html HTML + * @return array + */ + public function extract($html) + { + $icons = array(); + + if (empty($html)) { + return $icons; + } + + $dom = XmlParser::getHtmlDocument($html); + + $xpath = new DOMXpath($dom); + $elements = $xpath->query('//link[@rel="icon" or @rel="shortcut icon" or @rel="Shortcut Icon" or @rel="icon shortcut"]'); + + for ($i = 0; $i < $elements->length; ++$i) { + $icons[] = $elements->item($i)->getAttribute('href'); + } + + return $icons; + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/Reader.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/Reader.php new file mode 100644 index 00000000..596b02dc --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/Reader.php @@ -0,0 +1,189 @@ + '//feed', + 'Rss20' => '//rss[@version="2.0"]', + 'Rss92' => '//rss[@version="0.92"]', + 'Rss91' => '//rss[@version="0.91"]', + 'Rss10' => '//rdf', + ); + + /** + * Download a feed (no discovery). + * + * @param string $url Feed url + * @param string $last_modified Last modified HTTP header + * @param string $etag Etag HTTP header + * @param string $username HTTP basic auth username + * @param string $password HTTP basic auth password + * + * @return \PicoFeed\Client\Client + */ + public function download($url, $last_modified = '', $etag = '', $username = '', $password = '') + { + $url = $this->prependScheme($url); + + return Client::getInstance() + ->setConfig($this->config) + ->setLastModified($last_modified) + ->setEtag($etag) + ->setUsername($username) + ->setPassword($password) + ->execute($url); + } + + /** + * Discover and download a feed. + * + * @param string $url Feed or website url + * @param string $last_modified Last modified HTTP header + * @param string $etag Etag HTTP header + * @param string $username HTTP basic auth username + * @param string $password HTTP basic auth password + * @return Client + * @throws SubscriptionNotFoundException + */ + public function discover($url, $last_modified = '', $etag = '', $username = '', $password = '') + { + $client = $this->download($url, $last_modified, $etag, $username, $password); + + // It's already a feed or the feed was not modified + if (!$client->isModified() || $this->detectFormat($client->getContent())) { + return $client; + } + + // Try to find a subscription + $links = $this->find($client->getUrl(), $client->getContent()); + + if (empty($links)) { + throw new SubscriptionNotFoundException('Unable to find a subscription'); + } + + return $this->download($links[0], $last_modified, $etag, $username, $password); + } + + /** + * Find feed urls inside a HTML document. + * + * @param string $url Website url + * @param string $html HTML content + * + * @return array List of feed links + */ + public function find($url, $html) + { + Logger::setMessage(get_called_class().': Try to discover subscriptions'); + + $dom = XmlParser::getHtmlDocument($html); + $xpath = new DOMXPath($dom); + $links = array(); + + $queries = array( + '//link[@type="application/rss+xml"]', + '//link[@type="application/atom+xml"]', + ); + + foreach ($queries as $query) { + $nodes = $xpath->query($query); + + foreach ($nodes as $node) { + $link = $node->getAttribute('href'); + + if (!empty($link)) { + $feedUrl = new Url($link); + $siteUrl = new Url($url); + + $links[] = $feedUrl->getAbsoluteUrl($feedUrl->isRelativeUrl() ? $siteUrl->getBaseUrl() : ''); + } + } + } + + Logger::setMessage(get_called_class().': '.implode(', ', $links)); + + return $links; + } + + /** + * Get a parser instance. + * + * @param string $url Site url + * @param string $content Feed content + * @param string $encoding HTTP encoding + * @return \PicoFeed\Parser\Parser + * @throws UnsupportedFeedFormatException + */ + public function getParser($url, $content, $encoding) + { + $format = $this->detectFormat($content); + + if (empty($format)) { + throw new UnsupportedFeedFormatException('Unable to detect feed format'); + } + + $className = '\PicoFeed\Parser\\'.$format; + + $parser = new $className($content, $encoding, $url); + $parser->setHashAlgo($this->config->getParserHashAlgo()); + $parser->setConfig($this->config); + + return $parser; + } + + /** + * Detect the feed format. + * + * @param string $content Feed content + * @return string + */ + public function detectFormat($content) + { + $dom = XmlParser::getHtmlDocument($content); + $xpath = new DOMXPath($dom); + + foreach ($this->formats as $parser_name => $query) { + $nodes = $xpath->query($query); + + if ($nodes->length === 1) { + return $parser_name; + } + } + + return ''; + } + + /** + * Add the prefix "http://" if the end-user just enter a domain name. + * + * @param string $url Url + * @return string + */ + public function prependScheme($url) + { + if (!preg_match('%^https?://%', $url)) { + $url = 'http://'.$url; + } + + return $url; + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/ReaderException.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/ReaderException.php new file mode 100644 index 00000000..4f03dbe0 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/ReaderException.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://combat.blog.lemonde.fr/2013/08/31/teddy-riner-le-rookie-devenu-rambo/#xtor=RSS-3208', + 'body' => array( + '//div[@class="entry-content"]', + ), + 'strip' => array( + '//*[contains(@class, "fb-like") or contains(@class, "social")]' + ), + ) + ) +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.blogs.nytimes.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.blogs.nytimes.com.php new file mode 100644 index 00000000..ee641b09 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.blogs.nytimes.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'title' => '//header/h1', + 'test_url' => 'http://bits.blogs.nytimes.com/2012/01/16/wikipedia-plans-to-go-dark-on-wednesday-to-protest-sopa/', + 'body' => array( + '//div[@class="postContent"]', + ), + 'strip' => array( + '//*[@class="shareToolsBox"]', + ), + ) + ) +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.igen.fr.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.igen.fr.php new file mode 100644 index 00000000..f2028f4e --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.igen.fr.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.igen.fr/ailleurs/2014/05/nvidia-va-delaisser-les-smartphones-grand-public-86031', + 'body' => array( + '//div[contains(@class, "field-name-body")]' + ), + 'strip' => array( + ), + ) + ) +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.nytimes.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.nytimes.com.php new file mode 100644 index 00000000..8ff921ce --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.nytimes.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.nytimes.com/2011/05/15/world/middleeast/15prince.html', + 'body' => array( + '//p[contains(@class, "story-content")] | //div[@class="image"]', + ), + ) + ) +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.over-blog.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.over-blog.com.php new file mode 100644 index 00000000..cc5d83c7 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.over-blog.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://eliascarpe.over-blog.com/2015/12/re-upload-projets-d-avenir.html', + 'body' => array( + '//div[contains(concat(" ", normalize-space(@class), " "), " ob-section ")]', + ), + ) + ) +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.phoronix.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.phoronix.com.php new file mode 100644 index 00000000..66713f71 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.phoronix.com.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.phoronix.com/scan.php?page=article&item=amazon_ec2_bare&num=1', + 'body' => array( + '//div[@class="content"]', + ), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.slate.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.slate.com.php new file mode 100644 index 00000000..a795bca3 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.slate.com.php @@ -0,0 +1,20 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.slate.com/articles/business/moneybox/2013/08/microsoft_ceo_steve_ballmer_retires_a_firsthand_account_of_the_company_s.html', + 'body' => array( + '//div[@class="sl-art-body"]', + ), + 'strip' => array( + '//*[contains(@class, "social") or contains(@class, "comments") or contains(@class, "sl-article-floatin-tools") or contains(@class, "sl-art-pag")]', + '//*[@id="mys_slate_logged_in"]', + '//*[@id="sl_article_tools_myslate_bottom"]', + '//*[@id="mys_myslate"]', + '//*[@class="sl-viral-container"]', + '//*[@class="sl-art-creds-cntr"]', + '//*[@class="sl-art-ad-midflex"]', + ) + ) + ) +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.theguardian.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.theguardian.com.php new file mode 100644 index 00000000..e0d6f3fd --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.theguardian.com.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.theguardian.com/sustainable-business/2015/feb/02/2015-hyper-transparency-global-business', + 'body' => array( + '//div[contains(@class, "content__main-column--article")]', + ), + 'strip' => array( + '//div[contains(@class, "meta-container")]', + ), + ) + ) +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wikipedia.org.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wikipedia.org.php new file mode 100644 index 00000000..7b8f76e5 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wikipedia.org.php @@ -0,0 +1,29 @@ + array( + '%.*%' => array( + 'test_url' => 'https://en.wikipedia.org/wiki/Grace_Hopper', + 'body' => array( + '//div[@id="bodyContent"]', + ), + 'strip' => array( + "//div[@id='toc']", + "//div[@id='catlinks']", + "//div[@id='jump-to-nav']", + "//div[@class='thumbcaption']//div[@class='magnify']", + "//table[@class='navbox']", + "//table[contains(@class, 'infobox')]", + "//div[@class='dablink']", + "//div[@id='contentSub']", + "//div[@id='siteSub']", + "//table[@id='persondata']", + "//table[contains(@class, 'metadata')]", + "//*[contains(@class, 'noprint')]", + "//*[contains(@class, 'printfooter')]", + "//*[contains(@class, 'editsection')]", + "//*[contains(@class, 'error')]", + "//span[@title='pronunciation:']", + ), + ) + ) +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wired.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wired.com.php new file mode 100644 index 00000000..952b09ac --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wired.com.php @@ -0,0 +1,44 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.wired.com/gamelife/2013/09/ouya-free-the-games/', + 'body' => array( + '//div[@data-js="gallerySlides"]', + '//div[starts-with(@class,"post")]', + ), + 'strip' => array( + '//h1', + '//nav', + '//button', + '//figure[starts-with(@class,"rad-slide")]', + '//figure[starts-with(@class,"end-slate")]', + '//div[contains(@class,"mobile-")]', + '//div[starts-with(@class,"mob-gallery-launcher")]', + '//div[contains(@id,"mobile-")]', + '//span[contains(@class,"slide-count")]', + '//div[contains(@class,"show-ipad")]', + '//img[contains(@id,"-hero-bg")]', + '//div[@data-js="overlayWrap"]', + '//ul[contains(@class,"metadata")]', + '//div[@class="opening center"]', + '//p[contains(@class="byline-mob"]', + '//div[@id="o-gallery"]', + '//div[starts-with(@class,"sm-col")]', + '//div[contains(@class,"pad-b-huge")]', + '//a[contains(@class,"visually-hidden")]', + '//*[@class="social"]', + '//i', + '//div[@data-js="mobGalleryAd"]', + '//div[contains(@class,"footer")]', + '//div[contains(@data-js,"fader")]', + '//div[@id="sharing"]', + '//div[contains(@id,"related")]', + '//div[@id="most-pop"]', + '//ul[@id="article-tags"]', + '//style', + '//section[contains(@class,"footer")]' + ), + ) + ) +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wsj.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wsj.com.php new file mode 100644 index 00000000..f6e6cc12 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wsj.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://online.wsj.com/article/SB10001424127887324108204579023143974408428.html', + 'body' => array( + '//div[@class="articlePage"]', + ), + 'strip' => array( + '//*[@id="articleThumbnail_2"]', + '//*[@class="socialByline"]', + ) + ) + ) +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/01net.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/01net.com.php new file mode 100644 index 00000000..6d144f05 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/01net.com.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.01net.com/editorial/624550/twitter-rachete-madbits-un-specialiste-francais-de-lanalyse-dimages/', + 'body' => array( + '//div[@class="article_ventre_box"]', + ), + 'strip' => array( + '//link', + '//*[contains(@class, "article_navigation")]', + '//h1', + '//*[contains(@class, "article_toolbarMain")]', + '//*[contains(@class, "article_imagehaute_box")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/24.hu.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/24.hu.php new file mode 100644 index 00000000..6c269db0 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/24.hu.php @@ -0,0 +1,16 @@ + array( + '%.*%' => array( + 'test_url' => 'http://24.hu/belfold/2017/10/20/millios-lehuzasok-miatt-razziaztak-egy-budapesti-barban-videoval/', + 'body' => array( + '//div[@class="post-title-wrapper"]/h1', + '//div[@class="post-header-wrapper has-img"]/img', + '//div[@class="post-body"]' + + ), + 'strip' => array( + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/444.hu.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/444.hu.php new file mode 100644 index 00000000..e65bad18 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/444.hu.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'test_url' => 'https://444.hu/2017/10/20/tulszamlazo-helyen-utottek-rajta-budapest-belvarosaban', + 'body' => array( + '//div[@id="headline"]/h1', + '//article' + ), + 'strip' => array( + '//article/footer', + '//article/div[@class="jeti-roadblock ad"]', + '//figcaption', + '//noscript', + '//ul[@class="widget-stream-items"]' + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/888.hu.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/888.hu.php new file mode 100644 index 00000000..68cfe056 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/888.hu.php @@ -0,0 +1,16 @@ + array( + '%.*%' => array( + 'test_url' => 'https://888.hu/article-a-budapesti-szocik-nem-szeretik-a-videki-szocikat', + 'body' => array( + '//div[@id="cikkholder"]/h1', + '//div[@class="maincontent8"]' + ), + 'strip' => array( + '//div[@class="AdW"]', + '//h1[@class="olvastadmar"]' + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/abstrusegoose.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/abstrusegoose.com.php new file mode 100644 index 00000000..752d0413 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/abstrusegoose.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%alt="(.+)" title="(.+)" */>%' => '/>
$1
$2', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/achgut.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/achgut.com.php new file mode 100644 index 00000000..1e61fe68 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/achgut.com.php @@ -0,0 +1,16 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.achgut.com/artikel/deutscher_herbst_wg_reichsstrasse_106', + 'body' => array( + '//div[@class="headerpict_half"]/div/img', + '//div[@class="beitrag"]/div[@class="teaser_blog_text"]' + ), + 'strip' => array( + '//div[@class="footer_blog_text"]', + '//div[@class="beitrag"]/div[@class="teaser_blog_text"]/h2[1]' + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/adventuregamers.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/adventuregamers.com.php new file mode 100644 index 00000000..98d384e6 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/adventuregamers.com.php @@ -0,0 +1,23 @@ + array( + '%^/news.*%' => array( + 'test_url' => 'http://www.adventuregamers.com/news/view/31079', + 'body' => array( + '//div[@class="bodytext"]', + ) + ), + '%^/videos.*%' => array( + 'test_url' => 'http://www.adventuregamers.com/videos/view/31056', + 'body' => array( + '//iframe', + ) + ), + '%^/articles.*%' => array( + 'test_url' => 'http://www.adventuregamers.com/articles/view/31049', + 'body' => array( + '//div[@class="cleft"]', + ) + ) + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/alainonline.net.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/alainonline.net.php new file mode 100644 index 00000000..f440b234 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/alainonline.net.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.alainonline.net/news_details.php?lang=arabic&sid=18907', + 'body' => array( + '//div[@class="news_details"]', + ), + 'strip' => array( + '//div[@class="news_details"]/div/div[last()]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/aljazeera.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/aljazeera.com.php new file mode 100644 index 00000000..c02eb219 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/aljazeera.com.php @@ -0,0 +1,25 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.aljazeera.com/news/2015/09/xi-jinping-seattle-china-150922230118373.html', + 'body' => array( + '//article[@id="main-story"]', + ), + 'strip' => array( + '//script', + '//header', + '//ul', + '//section[contains(@class,"profile")]', + '//a[@target="_self"]', + '//div[contains(@id,"_2")]', + '//div[contains(@id,"_3")]', + '//img[@class="viewMode"]', + '//table[contains(@class,"in-article-item")]', + '//div[@data-embed-type="Brightcove"]', + '//div[@class="QuoteContainer"]', + '//div[@class="BottomByLine"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/allafrica.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/allafrica.com.php new file mode 100644 index 00000000..e8a506d4 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/allafrica.com.php @@ -0,0 +1,20 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.aljazeera.com/news/2015/09/xi-jinping-seattle-china-150922230118373.html', + 'body' => array( + '//div[@class="story-body"]', + ), + 'strip' => array( + '//p[@class="kindofstory"]', + '//cite[@class="byline"]', + '//div[@class="useful-top"]', + '//div[contains(@class,"related-topics")]', + '//links', + '//sharebar', + '//related-topics', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/allgemeine-zeitung.de.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/allgemeine-zeitung.de.php new file mode 100644 index 00000000..8ede99b1 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/allgemeine-zeitung.de.php @@ -0,0 +1,23 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.allgemeine-zeitung.de/lokales/polizei/mainz-gonsenheim-unbekannte-rauben-esso-tankstelle-in-kurt-schumacher-strasse-aus_14913147.htm', + 'body' => array( + '//div[contains(@class, "article")][1]', + ), + 'strip' => array( + '//read/h1', + '//*[@id="t-map"]', + '//*[contains(@class, "modules")]', + '//*[contains(@class, "adsense")]', + '//*[contains(@class, "linkbox")]', + '//*[contains(@class, "info")]', + '//*[@class="skip"]', + '//*[@class="funcs"]', + '//span[@class="nd address"]', + '//a[contains(@href, "abo-und-services")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/amazingsuperpowers.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/amazingsuperpowers.com.php new file mode 100644 index 00000000..3214c62a --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/amazingsuperpowers.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
$1', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/anythingcomic.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/anythingcomic.com.php new file mode 100644 index 00000000..51247f76 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/anythingcomic.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'body' => array( + '//img[@id="comic_image"]', + '//div[@class="comment-wrapper"][position()=1]', + ), + 'strip' => array(), + 'test_url' => 'http://www.anythingcomic.com/comics/2108929/stress-free/', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ap.org.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ap.org.php new file mode 100644 index 00000000..5bb2bb6c --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ap.org.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://hosted.ap.org/dynamic/stories/A/AS_CHINA_GAO_ZHISHENG?SITE=AP&SECTION=HOME&TEMPLATE=DEFAULT', + 'body' => array( + '//img[@class="ap-smallphoto-img"]', + '//span[@class="entry-content"]', + ), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/areadvd.de.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/areadvd.de.php new file mode 100644 index 00000000..fc569220 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/areadvd.de.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.areadvd.de/news/daily-deals-angebote-bei-lautsprecher-teufel-3/', + 'body' => array('//div[contains(@class,"entry")]'), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/arstechnica.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/arstechnica.com.php new file mode 100644 index 00000000..55e01ce3 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/arstechnica.com.php @@ -0,0 +1,25 @@ + array( + '%.*%' => array( + 'test_url' => 'http://arstechnica.com/tech-policy/2015/09/judge-warners-2m-happy-birthday-copyright-is-bogus/', + 'body' => array( + '//article', + ), + 'strip' => array( + '//h4[@class="post-upperdek"]', + '//h1', + '//ul[@class="lSPager lSGallery"]', + '//div[@class="lSAction"]', + '//section[@class="post-meta"]', + '//figcaption', + '//aside', + '//div[@class="gallery-image-credit"]', + '//section[@class="article-author"]', + '//*[contains(@id,"social-")]', + '//div[contains(@id,"footer")]', + ), + ), + ), +); + diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/atv.hu.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/atv.hu.php new file mode 100644 index 00000000..170ec4db --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/atv.hu.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.atv.hu/belfold/20171020-tobb-millio-forintot-csalt-ki-egy-idos-ferfitol-a-budapesti-no', + 'body' => array( + '//article' + ), + 'strip' => array( + '//span[@class="date"]', + '//div[@class="fb-like db_iframe_widget"]', + '//div[@class="ad-wrapper dashed-border"]', + '//div[@class="footer-meta-wrapper"]', + '//div[@class="image-wrapper "]' + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/awkwardzombie.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/awkwardzombie.com.php new file mode 100644 index 00000000..5ab70514 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/awkwardzombie.com.php @@ -0,0 +1,10 @@ + array( + '%/index.php.*comic=.*%' => array( + 'test_url' => 'http://www.awkwardzombie.com/index.php?comic=041315', + 'body' => array('//*[@id="comic"]/img'), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/backchannel.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/backchannel.com.php new file mode 100644 index 00000000..bc5932a2 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/backchannel.com.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'https://medium.com/lessons-learned/917b8b63ae3e', + 'body' => array( + '//div[contains(@class,"section-inner")]', + ), + 'strip' => array( + '//div[contains(@class,"metabar")]', + '//img[contains(@class,"thumbnail")]', + '//h1', + '//blockquote', + '//p[contains(@class,"graf-after--h4")]' + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bangkokpost.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bangkokpost.com.php new file mode 100644 index 00000000..165515bb --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bangkokpost.com.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.bangkokpost.com/news/politics/704204/new-us-ambassador-arrives-in-bangkok', + 'body' => array( + '//article/div[@class="articleContents"]', + ), + 'strip' => array( + '//h2', + '//h4', + '//div[@class="text-size"]', + '//div[@class="relate-story"]', + '//div[@class="text-ads"]', + '//ul', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bauerwilli.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bauerwilli.com.php new file mode 100644 index 00000000..b191a6ed --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bauerwilli.com.php @@ -0,0 +1,17 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.bauerwilli.com/intuitive-eating/', + 'body' => array( + '//div[@class="entry-thumbnail"]', + '//div[@class="entry-content"]', + ), + 'strip' => array( + '//div[@class="tptn_counter"]', + '//div[contains(@class, "sharedaddy")]' + ), + ), + ), +); + diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bgr.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bgr.com.php new file mode 100644 index 00000000..7507a2f1 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bgr.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://bgr.com/2015/09/27/iphone-6s-waterproof-testing/', + 'body' => array( + '//img[contains(@class,"img")]', + '//div[@class="text-column"]', + ), + 'strip' => array( + '//strong', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bigfootjustice.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bigfootjustice.com.php new file mode 100644 index 00000000..d06ed124 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bigfootjustice.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%-150x150%' => '', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bigpicture.ru.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bigpicture.ru.php new file mode 100644 index 00000000..55c40894 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bigpicture.ru.php @@ -0,0 +1,31 @@ + array( + '%.*%' => array( + 'test_url' => 'http://bigpicture.ru/?p=556658', + 'body' => array( + '//div[@class="article container"]', + ), + 'strip' => array( + '//script', + '//form', + '//style', + '//h1', + '//*[@class="wp-smiley"]', + '//div[@class="ipmd"]', + '//div[@class="tags"]', + '//div[@class="social-button"]', + '//div[@class="bottom-share"]', + '//div[@class="raccoonbox"]', + '//div[@class="yndadvert"]', + '//div[@class="we-recommend"]', + '//div[@class="relap-bigpicture_ru-wrapper"]', + '//div[@id="mmail"]', + '//div[@id="mobile-ads-cut"]', + '//div[@id="liquidstorm-alt-html"]', + '//div[contains(@class, "post-tags")]', + '//*[contains(text(),"Смотрите также")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bizjournals.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bizjournals.com.php new file mode 100644 index 00000000..d1cc3da9 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bizjournals.com.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.bizjournals.com/milwaukee/news/2015/09/30/bucks-will-hike-prices-on-best-seats-at-new-arena.html', + 'body' => array( + '//figure/div/a/img', + '//p[@class="content__segment"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/biztimes.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/biztimes.com.php new file mode 100644 index 00000000..d21aa98c --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/biztimes.com.php @@ -0,0 +1,22 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.biztimes.com/2017/02/10/settlement-would-revive-fowler-lake-condo-project-in-oconomowoc/', + 'body' => array( + '//h2/span[@class="subhead"]', + '//div[contains(@class,"article-content")]', + ), + 'strip' => array( + '//script', + '//div[contains(@class,"mobile-article-content")]', + '//div[contains(@class,"sharedaddy")]', + '//div[contains(@class,"author-details")]', + '//div[@class="row ad"]', + '//div[contains(@class,"relatedposts")]', + '//div[@class="col-lg-12"]', + '//div[contains(@class,"widget")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bleepingcomputer.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bleepingcomputer.com.php new file mode 100644 index 00000000..7b740600 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bleepingcomputer.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.bleepingcomputer.com/news/google/chromes-sandbox-feature-infringes-on-three-patents-so-google-must-now-pay-20m/', + 'body' => array( + '//div[@class="article_section"]', + ), + 'strip' => array( + '//*[@itemprop="headline"]', + '//div[@class="cz-news-story-title-section"]' + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/blog.fefe.de.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/blog.fefe.de.php new file mode 100644 index 00000000..39c88ae4 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/blog.fefe.de.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://blog.fefe.de/?ts=ad706a73', + 'body' => array( + '/html/body/ul', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/blog.mapillary.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/blog.mapillary.com.php new file mode 100644 index 00000000..ce016510 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/blog.mapillary.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://blog.mapillary.com/update/2015/08/26/traffic-sign-updates.html', + 'body' => array( + '//div[contains(@class, "blog-post__content")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/brewers.mlb.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/brewers.mlb.com.php new file mode 100644 index 00000000..be406faf --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/brewers.mlb.com.php @@ -0,0 +1,22 @@ + array( + '%.*%' => array( + 'test_url' => 'http://m.brewers.mlb.com/news/article/161364798', + 'body' => array( + '//article[contains(@class,"article")]', + ), + 'strip' => array( + '//div[contains(@class,"ad-slot")]', + '//h1', + '//span[@class="timestamp"]', + '//div[contains(@class,"contributor-bottom")]', + '//div[contains(@class,"video")]', + '//ul[contains(@class,"social")]', + '//p[@class="tagline"]', + '//div[contains(@class,"social")]', + '//div[@class="button-wrap"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/buenosairesherald.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/buenosairesherald.com.php new file mode 100644 index 00000000..4e73e79f --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/buenosairesherald.com.php @@ -0,0 +1,17 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.buenosairesherald.com/article/199344/manzur-named-next-governor-of-tucum%C3%A1n', + 'body' => array( + '//div[@style="float:none"]', + ), + 'strip' => array( + '//div[contains(@class, "bz_alias_short_desc_container"]', + '//td[@id="bz_show_bug_column_1"]', + '//table[@id="attachment_table"]', + '//table[@class="bz_comment_table"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bunicomic.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bunicomic.com.php new file mode 100644 index 00000000..ad83e436 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bunicomic.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.bunicomic.com/comic/buni-623/', + 'body' => array( + '//div[@class="comic-table"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/buttersafe.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/buttersafe.com.php new file mode 100644 index 00000000..1f313cd0 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/buttersafe.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://buttersafe.com/2015/04/21/the-incredible-flexible-man/', + 'body' => array( + '//div[@id="comic"]', + '//div[@class="post-comic"]', + ), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cad-comic.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cad-comic.com.php new file mode 100644 index 00000000..a631c97f --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cad-comic.com.php @@ -0,0 +1,12 @@ + array( + '%/cad/.+%' => array( + 'test_url' => 'http://www.cad-comic.com/cad/20150417', + 'body' => array( + '//*[@id="content"]/img', + ), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/chaoslife.findchaos.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/chaoslife.findchaos.com.php new file mode 100644 index 00000000..ea6191e8 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/chaoslife.findchaos.com.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://chaoslife.findchaos.com/pets-in-the-wild', + 'body' => array('//div[@id="comic"]'), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/chinafile.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/chinafile.com.php new file mode 100644 index 00000000..450117b3 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/chinafile.com.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.chinafile.com/books/shanghai-faithful?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+chinafile%2FAll+%28ChinaFile%29', + 'body' => array( + '//div[contains(@class,"pane-featured-photo-panel-pane-1")]', + '//div[contains(@class,"video-above-fold")]', + '//div[@class="sc-media"]', + '//div[contains(@class,"field-name-body")]', + ), + 'strip' => array( + '//div[contains(@class,"cboxes")]', + '//div[contains(@class,"l-middle")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cicero.de.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cicero.de.php new file mode 100644 index 00000000..2cd1b709 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cicero.de.php @@ -0,0 +1,17 @@ + array( + '%.*%' => array( + 'test_url' => 'https://cicero.de/innenpolitik/plaene-der-eu-kommission-der-ganz-normale-terror', + 'body' => array( + '//p[@class="lead"]', + '//article/div[2]/div[contains(@class, "field--name-field-cc-image")]', + '//article/div[2]/div[contains(@class, "image-description")]', + '//div[@class="field field-name-field-cc-body"]', + ), + 'strip' => array( + '//*[contains(@class, "urban-ad-sign")]' + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cliquerefresh.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cliquerefresh.com.php new file mode 100644 index 00000000..9dcc7e54 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cliquerefresh.com.php @@ -0,0 +1,10 @@ + array( + '%/comic.*%' => array( + 'test_url' => 'http://cliquerefresh.com/comic/078-stating-the-obvious/', + 'body' => array('//div[@class="comicImg"]/img | //div[@class="comicImg"]/a/img'), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cnet.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cnet.com.php new file mode 100644 index 00000000..60767a53 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cnet.com.php @@ -0,0 +1,37 @@ + array( + '%^/products.*%' => array( + 'test_url' => 'http://www.cnet.com/products/fibaro-flood-sensor/#ftag=CADf328eec', + 'body' => array( + '//li[contains(@class,"slide first"] || //figure[contains(@class,(promoFigure))]', + '//div[@class="quickInfo"]', + '//div[@class="col-6 ratings"]', + '//div[@id="editorReview"]', + ), + 'strip' => array( + '//script', + '//a[@class="clickToEnlarge"]', + '//div[@section="topSharebar"]', + '//div[contains(@class,"related")]', + '//div[contains(@class,"ad-")]', + '//div[@section="shortcodeGallery"]', + ), + ), + '%.*%' => array( + 'test_url' => 'http://cnet.com.feedsportal.com/c/34938/f/645093/s/4a340866/sc/28/l/0L0Scnet0N0Cnews0Cman0Eclaims0Eonline0Epsychic0Emade0Ehim0Ebuy0E10Emillion0Epowerball0Ewinning0Eticket0C0Tftag0FCAD590Aa51e/story01.htm', + 'body' => array( + '//p[@itemprop="description"]', + '//div[@itemprop="articleBody"]', + ), + 'strip' => array( + '//script', + '//a[@class="clickToEnlarge"]', + '//div[@section="topSharebar"]', + '//div[contains(@class,"related")]', + '//div[contains(@class,"ad-")]', + '//div[@section="shortcodeGallery"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/coinwelt.de.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/coinwelt.de.php new file mode 100644 index 00000000..28a8bbab --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/coinwelt.de.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://coinwelt.de/2017/08/bitcache-kreierer-kim-dotcom-bietet-arbeitsplaetze-fuer-blockchain-goetter/', + 'body' => array( + '//div[@class="post-inner"]//div[@class="entry"]', + ), + 'strip' => array( + '//div[contains(@class, "shariff")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/consomac.fr.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/consomac.fr.php new file mode 100644 index 00000000..9209f9cb --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/consomac.fr.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://consomac.fr/news-2430-l-iphone-6-toujours-un-secret-bien-garde.html', + 'body' => array( + '//div[contains(@id, "newscontent")]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cowbirdsinlove.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cowbirdsinlove.com.php new file mode 100644 index 00000000..3214c62a --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cowbirdsinlove.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
$1', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/crash.net.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/crash.net.php new file mode 100644 index 00000000..88cef141 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/crash.net.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.crash.net/motogp/news/885102/1/dovizioso-mugello-win-was-catalyst-for-title-challenge', + 'body' => array( + '//*[@id="block-system-main"]', + ), + 'strip' => array( + '//script', + '//style', + '//*[@class="social-bar"]', + '//*[@id="below-headline-image-ad"]', + '//*[@class="advert-"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/csmonitor.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/csmonitor.com.php new file mode 100644 index 00000000..481e4b09 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/csmonitor.com.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.csmonitor.com/USA/Politics/2015/0925/John-Boehner-steps-down-Self-sacrificing-but-will-it-lead-to-better-government', + 'body' => array( + '//h2[@id="summary"]', + '//div[@class="flex-video youtube"]', + '//div[contains(@class,"eza-body")]', + ), + 'strip' => array( + '//span[@id="breadcrumb"]', + '//div[@id="byline-wrapper"]', + '//div[@class="injection"]', + '//*[contains(@class,"promo_link")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailyjs.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailyjs.com.php new file mode 100644 index 00000000..20eb1d75 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailyjs.com.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'test_url' => 'http://dailyjs.com/2014/08/07/p5js/', + 'body' => array( + '//div[@id="post"]', + ), + 'strip' => array( + '//h2[@class="post"]', + '//div[@class="meta"]', + '//*[contains(@class, "addthis_toolbox")]', + '//*[contains(@class, "addthis_default_style")]', + '//*[@class="navigation small"]', + '//*[@id="related"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailyreporter.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailyreporter.com.php new file mode 100644 index 00000000..db3fc0e1 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailyreporter.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://dailyreporter.com/2016/01/09/us-supreme-court-case-could-weaken-government-workers-unions/', + 'body' => array( + '//div[contains(@class, "entry-content")]', + ), + 'strip' => array( + '//div[@class="dmcss_login_form"]', + '//*[contains(@class, "sharedaddy")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailytech.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailytech.com.php new file mode 100644 index 00000000..5d1df4a9 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailytech.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.dailytech.com/Apples+First+Fixes+to+iOS+9+Land+w+iOS++901+Release/article37495.htm', + 'body' => array( + '//div[@class="NewsBodyImage"]', + '//span[@id="lblSummary"]', + '//span[@id="lblBody"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/degroupnews.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/degroupnews.com.php new file mode 100644 index 00000000..91f5c56e --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/degroupnews.com.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.degroupnews.com/medias/vodsvod/amazon-concurrence-la-chromecast-de-google-avec-fire-tv-stick', + 'body' => array( + '//div[@class="contenu"]', + ), + 'strip' => array( + '//div[contains(@class, "a2a")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/derstandard.at.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/derstandard.at.php new file mode 100644 index 00000000..7e95a51f --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/derstandard.at.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://derstandard.at/2000010267354/The-Witcher-3-Hohe-Hardware-Anforderungen-fuer-PC-Spieler?ref=rss', + 'body' => array( + '//div[@class="copytext"]', + '//ul[@id="media-list"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dilbert.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dilbert.com.php new file mode 100644 index 00000000..b8e9b3d6 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dilbert.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'body' => array( + '//img[@class="img-responsive img-comic"]', + ), + 'test_url' => 'http://dilbert.com/strip/2016-01-28', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/discovermagazine.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/discovermagazine.com.php new file mode 100644 index 00000000..ae0dfe71 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/discovermagazine.com.php @@ -0,0 +1,26 @@ + array( + '%.*%' => array( + 'test_url' => 'http://blogs.discovermagazine.com/neuroskeptic/2017/01/25/publishers-jeffrey-beall/', + 'body' => array( + '//div[@class="contentWell"]', + ), + 'strip' => array( + '//h1', + '//div[@class="breadcrumbs"]', + '//div[@class="mobile"]', + '//div[@class="fromIssue"]', + '//div[contains(@class,"belowDeck")]', + '//div[@class="meta"]', + '//div[@class="shareIcons"]', + '//div[@class="categories"]', + '//div[@class="navigation"]', + '//div[@class="heading"]', + '//div[contains(@id,"-ad")]', + '//div[@class="relatedArticles"]', + '//div[@id="disqus_thread"]' + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/distrowatch.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/distrowatch.com.php new file mode 100644 index 00000000..aefc8f81 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/distrowatch.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://distrowatch.com/?newsid=08355', + 'body' => array( + '//td[@class="NewsText"][1]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dozodomo.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dozodomo.com.php new file mode 100644 index 00000000..e1166957 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dozodomo.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://dozodomo.com/bento/2014/03/04/lart-des-maki-de-takayo-kiyota/', + 'body' => array( + '//div[@class="joke"]', + '//div[@class="story-cover"]', + '//div[@class="story-content"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/drawingboardcomic.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/drawingboardcomic.com.php new file mode 100644 index 00000000..cd30f2e0 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/drawingboardcomic.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'body' => array('//img[@id="comicimage"]'), + 'strip' => array(), + 'test_url' => 'http://drawingboardcomic.com/index.php?comic=208', + ), + ), + 'filter' => array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
$1', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/e-w-e.ru.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/e-w-e.ru.php new file mode 100644 index 00000000..8139cc9a --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/e-w-e.ru.php @@ -0,0 +1,22 @@ + array( + '%.*%' => array( + 'test_url' => 'http://e-w-e.ru/16-prekrasnyx-izobretenij-zhenshhin/', + 'body' => array( + '//div[contains(@class, "post_text")]', + ), + 'strip' => array( + '//script', + '//form', + '//style', + '//*[@class="views_post"]', + '//*[@class="adman_mobile"]', + '//*[@class="adman_desctop"]', + '//*[contains(@rel, "nofollow")]', + '//*[contains(@class, "wp-smiley")]', + '//*[contains(text(),"ИÑточник:")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/economist.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/economist.com.php new file mode 100644 index 00000000..522032fd --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/economist.com.php @@ -0,0 +1,25 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.economist.com/blogs/buttonwood/2017/02/mixed-signals?fsrc=rss', + 'body' => array( + '//article', + ), + 'strip' => array( + '//span[@class="blog-post__siblings-list-header "]', + '//h1', + '//aside', + '//div[@class="blog-post__asideable-wrapper"]', + '//div[@class="share_inline_header"]', + '//div[@id="column-right"]', + '//div[contains(@class,"blog-post__siblings-list-aside")]', + '//div[@class="video-player__wrapper"]', + '//div[@class="blog-post__bottom-panel"]', + '//div[contains(@class,"latest-updates-panel__container")]', + '//div[contains(@class,"blog-post__asideable-content")]', + '//div[@aria-label="Advertisement"]' + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/encyclopedie.naheulbeuk.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/encyclopedie.naheulbeuk.com.php new file mode 100644 index 00000000..19bcbdef --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/encyclopedie.naheulbeuk.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://encyclopedie.naheulbeuk.com/article.php3?id_article=352', + 'body' => array( + '//td//h1[@class="titre-texte"]', + '//td//div[@class="surtitre"]', + '//td//div[@class="texte"]', + ), + ) + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/endlessorigami.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/endlessorigami.com.php new file mode 100644 index 00000000..d06ed124 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/endlessorigami.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%-150x150%' => '', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/engadget.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/engadget.com.php new file mode 100644 index 00000000..cf9e4485 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/engadget.com.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.engadget.com/2015/04/20/dark-matter-discovery/?ncid=rss_truncated', + 'body' => array('//div[@id="page_body"]/div[@class="container@m-"]'), + 'strip' => array('//aside[@role="banner"]'), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/escapistmagazine.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/escapistmagazine.com.php new file mode 100644 index 00000000..e86b59cb --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/escapistmagazine.com.php @@ -0,0 +1,45 @@ + array( + '%/articles/view/comicsandcosplay/comics/critical-miss.*%' => array( + 'body' => array('//*[@class="body"]/span/img | //div[@class="folder_nav_links"]/following::p'), + 'test_url' => 'http://www.escapistmagazine.com/articles/view/comicsandcosplay/comics/critical-miss/13776-Critical-Miss-on-Framerates?utm_source=rss&utm_medium=rss&utm_campaign=articles', + 'strip' => array(), + ), + '%/articles/view/comicsandcosplay/comics/namegame.*%' => array( + 'body' => array('//*[@class="body"]/span/p/img[@height != "120"]'), + 'test_url' => 'http://www.escapistmagazine.com/articles/view/comicsandcosplay/comics/namegame/9759-Leaving-the-Nest?utm_source=rss&utm_medium=rss&utm_campaign=articles', + 'strip' => array(), + ), + '%/articles/view/comicsandcosplay/comics/stolen-pixels.*%' => array( + 'body' => array('//*[@class="body"]/span/p[2]/img'), + 'test_url' => 'http://www.escapistmagazine.com/articles/view/comicsandcosplay/comics/stolen-pixels/8866-Stolen-Pixels-258-Where-the-Boys-Are?utm_source=rss&utm_medium=rss&utm_campaign=articles', + 'strip' => array(), + ), + '%/articles/view/comicsandcosplay/comics/bumhugparade.*%' => array( + 'body' => array('//*[@class="body"]/span/p[2]/img'), + 'test_url' => 'http://www.escapistmagazine.com/articles/view/comicsandcosplay/comics/bumhugparade/8262-Bumhug-Parade-13?utm_source=rss&utm_medium=rss&utm_campaign=articles', + 'strip' => array(), + ), + '%/articles/view/comicsandcosplay.*/comics/escapistradiotheater%' => array( + 'body' => array('//*[@class="body"]/span/p[2]/img'), + 'test_url' => 'http://www.escapistmagazine.com/articles/view/comicsandcosplay/comics/escapistradiotheater/8265-The-Escapist-Radio-Theater-13?utm_source=rss&utm_medium=rss&utm_campaign=articles', + 'strip' => array(), + ), + '%/articles/view/comicsandcosplay/comics/paused.*%' => array( + 'body' => array('//*[@class="body"]/span/p[2]/img | //*[@class="body"]/span/div/img'), + 'test_url' => 'http://www.escapistmagazine.com/articles/view/comicsandcosplay/comics/paused/8263-Paused-16?utm_source=rss&utm_medium=rss&utm_campaign=articles', + 'strip' => array(), + ), + '%/articles/view/comicsandcosplay/comics/fraughtwithperil.*%' => array( + 'body' => array('//*[@class="body"]'), + 'test_url' => 'http://www.escapistmagazine.com/articles/view/comicsandcosplay/comics/fraughtwithperil/12166-The-Escapist-Presents-Escapist-Comics-Critical-Miss-B-lyeh-Fhlop?utm_source=rss&utm_medium=rss&utm_campaign=articles', + 'strip' => array(), + ), + '%/articles/view/video-games/columns/.*%' => array( + 'body' => array('//*[@id="article_content"]'), + 'test_url' => 'http://www.escapistmagazine.com/articles/view/video-games/columns/experienced-points/13971-What-50-Shades-and-Batman-Have-in-Common.2', + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/espn.go.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/espn.go.com.php new file mode 100644 index 00000000..76a20f74 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/espn.go.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://espn.go.com/nfl/story/_/id/13388208/jason-whitlock-chip-kelly-controversy', + 'body' => array( + '//p', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/exocomics.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/exocomics.com.php new file mode 100644 index 00000000..5adc59f8 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/exocomics.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'body' => array('//a[@class="comic"]/img'), + 'strip' => array(), + 'test_url' => 'http://www.exocomics.com/379', + ), + ), + 'filter' => array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
$1', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/explosm.net.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/explosm.net.php new file mode 100644 index 00000000..3fdf02c0 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/explosm.net.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://explosm.net/comics/3803/', + 'body' => array( + '//div[@id="comic-container"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/extrafabulouscomics.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/extrafabulouscomics.com.php new file mode 100644 index 00000000..12697ccb --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/extrafabulouscomics.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%-150x150%' => '', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/factroom.ru.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/factroom.ru.php new file mode 100644 index 00000000..a572061d --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/factroom.ru.php @@ -0,0 +1,27 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.factroom.ru/life/20-facts-about-oil', + 'body' => array( + '//div[@class="post"]', + ), + 'strip' => array( + '//script', + '//form', + '//style', + '//h1', + '//div[@id="yandex_ad2"]', + '//*[@class="jp-relatedposts"]', + '//div[contains(@class, "likely-desktop")]', + '//div[contains(@class, "likely-mobile")]', + '//p[last()]', + '//div[contains(@class, "facebook")]', + '//div[contains(@class, "desktop-underpost-direct")]', + '//div[contains(@class, "source-box")]', + '//div[contains(@class, "under-likely-desktop")]', + '//div[contains(@class, "mobile-down-post")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcodesign.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcodesign.com.php new file mode 100644 index 00000000..74e70a86 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcodesign.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.fastcodesign.com/3026548/exposure/peek-inside-the-worlds-forbidden-subway-tunnels', + 'body' => array( + '//article[contains(@class, "body prose")]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcoexist.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcoexist.com.php new file mode 100644 index 00000000..6916f280 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcoexist.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.fastcoexist.com/3026114/take-a-seat-on-this-gates-funded-future-toilet-that-will-change-how-we-think-about-poop', + 'body' => array( + '//article[contains(@class, "body prose")]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcompany.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcompany.com.php new file mode 100644 index 00000000..e0869a29 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcompany.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.fastcompany.com/3026712/fast-feed/elon-musk-an-apple-tesla-merger-is-very-unlikely', + 'body' => array( + '//article[contains(@class, "body prose")]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ffworld.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ffworld.com.php new file mode 100644 index 00000000..20a47b2d --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ffworld.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.ffworld.com/?rub=news&page=voir&id=2709', + 'body' => array( + '//div[@class="news_body"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/foreignpolicy.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/foreignpolicy.com.php new file mode 100644 index 00000000..3cbcddc4 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/foreignpolicy.com.php @@ -0,0 +1,21 @@ + array( + '%.*%' => array( + 'test_url' => 'http://foreignpolicy.com/2016/01/09/networking-giant-pulls-nsa-linked-code-exploited-by-hackers/', + 'body' => array( + '//article', + ), + 'strip' => array( + '//div[@id="post-category"]', + '//div[@id="desktop-right"]', + '//h1', + '//section[@class="article-meta"]', + '//div[@class="side-panel-wrapper"]', + '//*[contains(@class, "share-")]', + '//*[contains(@id, "taboola-")]', + '//div[@class="comments"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fossbytes.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fossbytes.com.php new file mode 100644 index 00000000..6ce47256 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fossbytes.com.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'http://fossbytes.com/fbi-hacked-1000-computers-to-shut-down-largest-child-pornography-site-on-the-dark-web/', + 'body' => array( + '//div[@class="entry-inner"]', + ), + 'strip' => array( + '//*[@class="at-above-post addthis_default_style addthis_toolbox at-wordpress-hide"]', + '//*[@class="at-below-post addthis_default_style addthis_toolbox at-wordpress-hide"]', + '//*[@class="at-below-post-recommended addthis_default_style addthis_toolbox at-wordpress-hide"]', + '//*[@class="code-block code-block-12 ai-desktop"]', + '//*[@class="code-block code-block-13 ai-tablet-phone"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fototelegraf.ru.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fototelegraf.ru.php new file mode 100644 index 00000000..ca2f85aa --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fototelegraf.ru.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'test_url' => 'http://fototelegraf.ru/?p=348232', + 'body' => array( + '//div[@class="post-content"]', + ), + 'strip' => array( + '//script', + '//form', + '//style', + '//div[@class="imageButtonsBlock"]', + '//div[@class="adOnPostBtwImg"]', + '//div[contains(@class, "post-tags")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fowllanguagecomics.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fowllanguagecomics.com.php new file mode 100644 index 00000000..3f62f071 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fowllanguagecomics.com.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'body' => array('//*[@id="comic"] | //*[@class="post-image"]'), + 'strip' => array(), + 'test_url' => 'http://www.fowllanguagecomics.com/comic/working-out/', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gamechannel.hu.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gamechannel.hu.php new file mode 100644 index 00000000..8ab9c5ca --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gamechannel.hu.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.gamechannel.hu/cikk/hirblock/a-legacy-of-kain-feltamasztasara-keszul-a-crystal-dynamics', + 'body' => array( + '//div[@class="post"]/div[@class="entry"]' + ), + 'strip' => array( + '//div[@class="valaszto"]', + '//center/blockquote' // as we can't grab iframe here + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gamestar.hu.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gamestar.hu.php new file mode 100644 index 00000000..56a4c728 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gamestar.hu.php @@ -0,0 +1,17 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.gamestar.hu/hir/horizon-zero-dawn-the-frozen-wilds-vedjegy-239019.html', + 'body' => array( + '//article/header/h1', + '//div[@class="section section-2-3"]/div[@class="image"]/img', + '//article/p[@class="lead"]', + '//article/div[@class="content"]' + ), + 'strip' => array( + '//div[@class="ad ad-article-inside"]' + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/geek.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/geek.com.php new file mode 100644 index 00000000..d9ccecc2 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/geek.com.php @@ -0,0 +1,17 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.geek.com/news/the-11-best-ways-to-eat-eggs-1634076/', + 'body' => array( + '//div[@class="articleinfo"]/figure', + '//div[@class="articleinfo"]/article', + '//span[@class="by"]', + ), + 'strip' => array( + '//span[@class="red"]', + '//div[@class="on-target"]' + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/geektimes.ru.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/geektimes.ru.php new file mode 100644 index 00000000..19541386 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/geektimes.ru.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'https://geektimes.ru/post/289151/', + 'body' => array( + "//div[contains(concat(' ',normalize-space(@class),' '),' content ')]" + ), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gerbilwithajetpack.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gerbilwithajetpack.com.php new file mode 100644 index 00000000..44013b3b --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gerbilwithajetpack.com.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'body' => array( + '//div[@id="comic-1"]', + '//div[@class="entry"]', + ), + 'test_url' => 'http://gerbilwithajetpack.com/passing-the-digital-buck/', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/giantitp.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/giantitp.com.php new file mode 100644 index 00000000..d9c3ae5d --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/giantitp.com.php @@ -0,0 +1,12 @@ + array( + '%/comics/oots.*%' => array( + 'test_url' => 'http://www.giantitp.com/comics/oots0989.html', + 'body' => array( + '//td[@align="center"]/img', + ), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/github.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/github.com.php new file mode 100644 index 00000000..726634f9 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/github.com.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'https://github.com/audreyr/favicon-cheat-sheet', + 'body' => array( + '//article[contains(@class, "entry-content")]', + ), + 'strip' => array( + '//h1', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gocomics.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gocomics.com.php new file mode 100644 index 00000000..32960f0e --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gocomics.com.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.gocomics.com/pearlsbeforeswine/2015/05/30', + 'body' => array( + '//div[1]/p[1]/a[1]/img', + ), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/golem.de.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/golem.de.php new file mode 100644 index 00000000..87312853 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/golem.de.php @@ -0,0 +1,21 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.golem.de/news/breko-telekom-verzoegert-gezielt-den-vectoring-ausbau-1311-102974.html', + 'body' => array( + '//header[@class="cluster-header"]', + '//header[@class="paged-cluster-header"]', + '//div[@class="formatted"]', + ), + 'next_page' => array( + '//a[@id="atoc_next"]' + ), + 'strip' => array( + '//header[@class="cluster-header"]/a', + '//header[@class="cluster-header"]/h1', + '//div[@id="iqadtile4"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gondola.hu.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gondola.hu.php new file mode 100644 index 00000000..62b1e3c9 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gondola.hu.php @@ -0,0 +1,22 @@ + array( + '%.*%' => array( + 'test_url' => 'https://gondola.hu/hirek/213754-A_budapesti_fejlesztesek_kerdese_mar_nem_zsakbamacska.html', + 'body' => array( + '//div[@id="cikk"]/div[@class="cim"]', + '//br[1]', + '//div[@class="alcim"]', + '//div[@class="lead"]', + '//div[@class="szoveg"]' + ), + 'strip' => array( + '//div[@class="ikonok"]', + '//div[@class="linkekblokk"]', + '//div[@id="billboardbanner"]', + '//div[@class="szerzo"]', + '//div[@class="kulcsszavak"]' + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gorabbit.ru.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gorabbit.ru.php new file mode 100644 index 00000000..4e432481 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gorabbit.ru.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'test_url' => 'http://gorabbit.ru/article/10-oshchushcheniy-za-rulem-kogda-tolko-poluchil-voditelskie-prava', + 'body' => array( + '//div[@class="detail_text"]', + ), + 'strip' => array( + '//script', + '//form', + '//style', + '//div[@class="socials"]', + '//div[@id="cr_1"]', + '//div[@class="related_items"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/habrahabr.ru.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/habrahabr.ru.php new file mode 100644 index 00000000..3f1ec165 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/habrahabr.ru.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'https://habrahabr.ru/company/pentestit/blog/328606/', + 'body' => array( + "//div[contains(concat(' ',normalize-space(@class),' '),' content ')]" + ), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/happletea.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/happletea.com.php new file mode 100644 index 00000000..75b0b83d --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/happletea.com.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'body' => array( + '//div[@id="comic"]', + '//div[@class="entry"]', + ), + 'strip' => array('//div[@class="ssba"]'), + 'test_url' => 'http://www.happletea.com/comic/mans-best-friend/', + ), + ), + 'filter' => array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
$1', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hardware.fr.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hardware.fr.php new file mode 100644 index 00000000..56aec4f4 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hardware.fr.php @@ -0,0 +1,11 @@ + array( + '%^/news.*%' => array( + 'test_url' => 'http://www.hardware.fr/news/14760/intel-lance-nouveaux-ssd-nand-3d.html', + 'body' => array( + '//div[@class="content_actualite"]/div[@class="md"]', + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/heise.de.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/heise.de.php new file mode 100644 index 00000000..0ee69150 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/heise.de.php @@ -0,0 +1,79 @@ + array( + '%^/tp.*%' => array( + 'test_url' => 'https://www.heise.de/tp/features/Macrons-Vermoegenssteuer-Der-Staat-verzichtet-auf-3-2-Milliarden-3863931.html', + 'body' => array( + '//main/article' + ), + 'strip' => array( + '//header', + '//aside', + '//nav[@class="pre-akwa-toc"]', + '//*[@class="seite_zurueck"]', + '//*[@class="pagination"]', + '//a[@class="kommentare_lesen_link"]', + '//div[contains(@class, "shariff")]', + '//a[@class="beitragsfooter_permalink"]', + '//a[@class="beitragsfooter_fehlermelden"]', + '//a[@class="beitragsfooter_printversion"]' + ), + 'next_page' => array( + '//a[@class="seite_weiter"]' + ), + ), + '%^/newsticker/meldung.*%' => array( + 'test_url' => 'https://www.heise.de/newsticker/meldung/DragonFly-BSD-5-0-mit-experimentellem-HAMMER2-veroeffentlicht-3864731.html', + 'body' => array( + '//div[@class="article-content"]', + ), + 'strip' => array( + '//*[contains(@class, "gallery")]', + '//*[contains(@class, "video")]', + ), + ), + '%^/autos/artikel.*%' => array( + 'test_url' => 'https://www.heise.de/autos/artikel/Bericht-Mazda-baut-Range-Extender-mit-Wankelmotor-3864760.html', + 'body' => array( + '//section[@id="artikel_text"]' + ), + 'strip' => array( + '//p[@id="content_foren"]', + '//div[contains(@class, "shariff")]', + '//p[@class="permalink"]', + '//p[@class="printversion"]' + ), + ), + '%^/foto/meldung.*%' => array( + 'test_url' => 'https://www.heise.de/foto/meldung/Wildlife-Fotograf-des-Jahres-Gewinnerbild-zeigt-getoetetes-Nashorn-3864311.html', + 'body' => array( + '//div[@class="article-content"]' + ), + ), + '%^/ct.*%' => array( + 'test_url' => 'https://www.heise.de/ct/artikel/Google-Pixel-2-und-Pixel-2-XL-im-Test-3863842.html', + 'body' => array( + '//main/div[1]/div[1]/section' + ), + 'strip' => array( + '//header' + ) + ), + '%^/developer.*%' => array( + 'test_url' => 'https://www.heise.de/developer/meldung/Container-Docker-unterstuetzt-Kubernetes-3863625.html', + 'body' => array( + '//div[@class="article-content"]' + ) + ), + '%.*%' => array( + 'test_url' => 'https://www.heise.de/mac-and-i/meldung/iOS-App-Nude-findet-mittels-ML-Nacktbilder-und-versteckt-sie-3864217.html', + 'body' => array( + '//article/div[@class="meldung_wrapper"]', + ), + 'strip' => array( + '//*[contains(@class, "gallery")]', + '//*[contains(@class, "video")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hirek.prim.hu.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hirek.prim.hu.php new file mode 100644 index 00000000..1a388094 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hirek.prim.hu.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://hirek.prim.hu/cikk/2017/10/02/atadtak_a_6_fenntarthatosagi_sajtodijat', + 'body' => array( + '//div[@class="boxbody article_box"]/h2', + '//div[@class="text_body"]' + ), + 'strip' => array( + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hotshowlife.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hotshowlife.com.php new file mode 100644 index 00000000..faf01f3d --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hotshowlife.com.php @@ -0,0 +1,23 @@ + array( + '%.*%' => array( + 'test_url' => 'https://hotshowlife.com/top-10-chempionov-produktov-po-szhiganiyu-kalorij/', + 'body' => array( + '//div[@class="entry-content"]', + ), + 'strip' => array( + '//script', + '//form', + '//style', + '//div[@class="ads2"]', + '//div[@class="mistape_caption"]', + '//div[contains(@class, "et_social_media_hidden")]', + '//div[contains(@class, "et_social_inline_bottom")]', + '//div[contains(@class, "avatar")]', + '//ul[contains(@class, "entry-tags")]', + '//div[contains(@class, "entry-meta")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/huffingtonpost.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/huffingtonpost.com.php new file mode 100644 index 00000000..b52b07b5 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/huffingtonpost.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.huffingtonpost.com/2014/02/20/centscere-social-media-syracuse_n_4823848.html', + 'body' => array( + '//article[@class="content")]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hvg.hu.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hvg.hu.php new file mode 100644 index 00000000..efc93713 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hvg.hu.php @@ -0,0 +1,17 @@ + array( + '%.*%' => array( + 'test_url' => 'http://hvg.hu/brandchannel/mastercardbch_20171006_Egyetlen_mobillal_erintettuk_Budapest_legjobb_gasztrohelyeit', + 'body' => array( + '//div[@class="article-title article-title"]', + '//div[@class="article-cover-img"]', + '//div[@class="article-main"]' + ), + 'strip' => array( + '//figcaption', + '//div[@class="article-info byline"]' + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/idokep.hu.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/idokep.hu.php new file mode 100644 index 00000000..06cae09a --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/idokep.hu.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.idokep.hu/hirek/4-es-erossegu-tajfun-tart-japan-fele', + 'body' => array( + '//div[@class="cikk-title"]/h3', + '//div[@class="lead"]', + '//div[@class="atvett_tartalom"]', + '//div[@class="cikk-tartalom"]' + ), + 'strip' => array( + '//div[@class="cimkes-doboz"]', + '//div[@class="komment-wrap"]' + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/imogenquest.net.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/imogenquest.net.php new file mode 100644 index 00000000..3214c62a --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/imogenquest.net.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
$1', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/index.hu.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/index.hu.php new file mode 100644 index 00000000..727d7b7f --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/index.hu.php @@ -0,0 +1,29 @@ + array( + '%.*%' => array( + 'test_url' => 'http://index.hu/mindekozben/poszt/2017/10/20/art_deco_budapest_varosnezo_zsebkonyv_bolla_zoltan/', + 'body' => array( + '//div[@class="mindenkozben_post_content content"]', + '//div[@id="content"]' + ), + 'strip' => array( + '//div[@class="topszponzor_wrapper"]', + '//ul[@class="cikk-cimkek"]', + '//div[@class="author-share-date-container"]', + '//div[@class="pp-list"]', + '//div[@class="social-stripe cikk-bottom-box"]', + '//div[@class="cikk-bottom-text-ad"]', + '//a[@name="hozzaszolasok"]', + '//div[@class="cikk-vegi-ajanlo-reklamok-container"]', + '//div[@id="comments"]', + '//div[@class="comments"]', + '//div[@class="linkpreview-box bekezdes_utan"]', + '//div[@class="lapozo"]', + '//div[@class="szelso-jobb"]', + '//div[@class="social cikk-bottom-box"]', + '//input' + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/indiehaven.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/indiehaven.com.php new file mode 100644 index 00000000..a40ce694 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/indiehaven.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://indiehaven.com/no-mans-sky-is-a-solo-space-adventure-and-im-ok-with-that/', + 'body' => array( + '//section[contains(@class, "entry-content")]', + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/inforadio.hu.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/inforadio.hu.php new file mode 100644 index 00000000..569013d3 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/inforadio.hu.php @@ -0,0 +1,25 @@ + array( + '%.*%' => array( + 'test_url' => 'http://inforadio.hu/belfold/2017/10/20/fontos_valtozas_vegleg_lezarnak_tobb_villamosatjarot_budapesten/', + 'body' => array( + '//div[@class="content-title"]', + '//div[@class="szelso-jobb-lead_container"]', + '//div[@class="cikk-torzs"]' + ), + 'strip' => array( + '//div[@id="microsite_microsite"]', + '//div[@class="cikk-bottom-text-ad"]', + '//div[@class="social-stripe_container"]', + '//div[@class="facebook-like-box"]', + '//div[@class="rovat sargabg rovatdobozcim"]', + '//div[@class="m-okosradio_magazin arenaMagazineItem"]', + '//header[@class="m-okosradio_header"]', + '//div[@class="m-okosradio_elo"]', + '//div[@class="m-okosradio_container"]', + '//form' + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ing.dk.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ing.dk.php new file mode 100644 index 00000000..5a021a08 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ing.dk.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'http://ing.dk/artikel/smart-husisolering-og-styring-skal-mindske-japans-energikrise-164517', + 'body' => array( + '//section[contains(@class, "teaser")]', + '//section[contains(@class, "body")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/invisiblebread.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/invisiblebread.com.php new file mode 100644 index 00000000..90f87597 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/invisiblebread.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%()%' => '$1', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ir.amd.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ir.amd.com.php new file mode 100644 index 00000000..af99fe99 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ir.amd.com.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'body' => array('//span[@class="ccbnTxt"]'), + 'strip' => array(), + 'test_url' => 'http://ir.amd.com/phoenix.zhtml?c=74093&p=RssLanding&cat=news&id=2055819', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/japantimes.co.jp.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/japantimes.co.jp.php new file mode 100644 index 00000000..9959441d --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/japantimes.co.jp.php @@ -0,0 +1,21 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.japantimes.co.jp/news/2015/09/27/world/social-issues-world/pope-meets-sex-abuse-victims-philadelphia-promises-accountability/', + 'body' => array( + '//article[@role="main"]', + ), + 'strip' => array( + '//script', + '//header', + '//div[contains(@class, "meta")]', + '//div[@class="clearfix"]', + '//div[@class="OUTBRAIN"]', + '//ul[@id="content_footer_menu"]', + '//div[@class="article_footer_ad"]', + '//div[@id="disqus_thread"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/japantoday.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/japantoday.com.php new file mode 100644 index 00000000..22485d69 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/japantoday.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.japantoday.com/category/politics/view/japan-u-s-to-sign-new-base-environment-pact', + 'body' => array( + '//div[@id="article_container"]', + ), + 'strip' => array( + '//h2', + '//div[@id="article_info"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/journaldugeek.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/journaldugeek.com.php new file mode 100644 index 00000000..876b2698 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/journaldugeek.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www./2014/05/20/le-playstation-now-arrive-en-beta-fermee-aux-etats-unis/', + 'body' => array( + '//div[@class="post-content"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/jsonline.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/jsonline.com.php new file mode 100644 index 00000000..5895256e --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/jsonline.com.php @@ -0,0 +1,37 @@ + array( + '%.%/picture-gallery/%' => array( + 'test_url' => 'http://www.jsonline.com/picture-gallery/news/local/milwaukee/2017/02/22/photos-aclu-sues-milwaukee-police-over-profiling-stop-and-frisk/98250836/', + 'body' => array( + '//div[@class="priority-asset-gallery galleries standalone hasendslate"]', + ), + 'strip' => array( + '//div[@class="buy-photo-btn"]', + '//div[@class="gallery-thumbs thumbs pag-thumbs")]', + ), + ), + '%.*%' => array( + 'test_url' => 'http://www.jsonline.com/news/usandworld/as-many-as-a-million-expected-for-popes-last-mass-in-us-b99585180z1-329688131.html', + 'body' => array( + '//div[@itemprop="articleBody"]', + ), + 'strip' => array( + '//h1', + '//iframe', + '//span[@class="mycapture-small-btn mycapture-btn-with-text mycapture-expandable-photo-btn-small js-mycapture-btn-small"]', + '//div[@class="close-wrap"]', + '//div[contains(@class,"ui-video-wrapper")]', + '//div[contains(@class,"media-mob")]', + '//div[contains(@class,"left-mob")]', + '//div[contains(@class,"nerdbox")]', + '//p/span', + '//div[contains(@class,"oembed-asset")]', + '//*[contains(@class,"share")]', + '//div[contains(@class,"gallery-asset")]', + '//div[contains(@class,"oembed-asset")]', + '//div[@class="article-print-url"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/justcoolidea.ru.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/justcoolidea.ru.php new file mode 100644 index 00000000..089ff29c --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/justcoolidea.ru.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'test_url' => 'http://justcoolidea.ru/idealnyj-sad-samodelnye-proekty-dlya-berezhlivogo-domovladeltsa/', + 'body' => array( + '//section[@class="entry-content"]', + ), + 'strip' => array( + '//script', + '//form', + '//style', + '//*[contains(@class, "essb_links")]', + '//*[contains(@rel, "nofollow")]', + '//*[contains(@class, "ads")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kanpai.fr.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kanpai.fr.php new file mode 100644 index 00000000..c3a1abc4 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kanpai.fr.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.kanpai.fr/japon/comment-donner-lheure-en-japonais.html', + 'body' => array( + '//div[@class="single-left"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/karriere.jobfinder.dk.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/karriere.jobfinder.dk.php new file mode 100644 index 00000000..25d6dfa3 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/karriere.jobfinder.dk.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'http://karriere.jobfinder.dk/artikel/dansk-professor-skal-lede-smart-grid-forskning-20-millioner-dollars-763', + 'body' => array( + '//section[contains(@class, "teaser")]', + '//section[contains(@class, "body")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kisalfold.hu.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kisalfold.hu.php new file mode 100644 index 00000000..75689014 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kisalfold.hu.php @@ -0,0 +1,17 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.kisalfold.hu/szorakozas/egy_15_eves_srac_szuntetheti_meg_a_wc-parat_budapesten/2536699/', + 'body' => array( + '//header[@class="single-article__header"]/h1', + '//header[@class="single-article__header"]/h2', + '//figure[@class="single-article__image"]/img', + '//div[@class="single-article__content"]/div[@id="single-article__lead"]', + '//div[@id="article_text"]' + ), + 'strip' => array( + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kiszamolo.hu.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kiszamolo.hu.php new file mode 100644 index 00000000..c44a08f4 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kiszamolo.hu.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'https://kiszamolo.hu/30-eve-volt-a-fekete-hetfo/', + 'body' => array( + '//article/h2', + '//article/div[@class="entry clearfix"]/p' + ), + 'strip' => array( + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kodi.tv.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kodi.tv.php new file mode 100644 index 00000000..439fc907 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kodi.tv.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'https://kodi.tv/article/andwere-baaaaack', + 'body' => array( + '//div[@class="l-region--content"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/koreaherald.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/koreaherald.com.php new file mode 100644 index 00000000..96510560 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/koreaherald.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.koreaherald.com/view.php?ud=20150926000018', + 'body' => array( + '//div[@id="articleText"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/koreatimes.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/koreatimes.php new file mode 100644 index 00000000..f274b4a9 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/koreatimes.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.koreatimes.co.kr/www/news/nation/2015/12/116_192409.html', + 'body' => array( + '//div[@id="p"]', + ), + 'strip' => array( + '//div[@id="webtalks_btn_listenDiv"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lastplacecomics.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lastplacecomics.com.php new file mode 100644 index 00000000..12697ccb --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lastplacecomics.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%-150x150%' => '', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/legorafi.fr.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/legorafi.fr.php new file mode 100644 index 00000000..e6aae46b --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/legorafi.fr.php @@ -0,0 +1,22 @@ + array( + '%.*%' => array( + 'test_url' => array( + 'http://www.legorafi.fr/2016/12/16/gorafi-magazine-bravo-vous-avez-bientot-presque-survecu-a-2016/', + 'http://www.legorafi.fr/2016/12/15/manuel-valls-promet-quune-fois-elu-il-debarrassera-la-france-de-manuel-valls/', + ), + 'body' => array( + '//section[@id="banner_magazine"]', + '//figure[@class="main_picture"]', + '//div[@class="content"]', + ), + 'strip' => array( + '//figcaption', + '//div[@class="sharebox"]', + '//div[@class="tags"]', + '//section[@class="taboola_article"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lejapon.fr.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lejapon.fr.php new file mode 100644 index 00000000..8f2b2932 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lejapon.fr.php @@ -0,0 +1,17 @@ + array( + '%.*%' => array( + 'test_url' => 'http://lejapon.fr/guide-voyage-japon/5223/tokyo-sous-la-neige.htm', + 'body' => array( + '//div[@class="entry"]', + ), + 'strip' => array( + '//*[contains(@class, "addthis_toolbox")]', + '//*[contains(@class, "addthis_default_style")]', + '//*[@class="navigation small"]', + '//*[@id="related"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lesjoiesducode.fr.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lesjoiesducode.fr.php new file mode 100644 index 00000000..369206ab --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lesjoiesducode.fr.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://lesjoiesducode.fr/post/75576211207/quand-lappli-ne-fonctionne-plus-sans-aucune-raison', + 'body' => array( + '//div[@class="blog-post-content"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lfg.co.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lfg.co.php new file mode 100644 index 00000000..d978a5fc --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lfg.co.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.lfg.co/page/871/?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+LookingForGroup+%28Looking+For+Group%29&utm_content=FeedBurner', + 'body' => array( + '//*[@id="comic"]/img | //*[@class="content"]', + ), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lifehacker.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lifehacker.com.php new file mode 100644 index 00000000..b9a69338 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lifehacker.com.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'http://lifehacker.com/bring-water-bottle-caps-into-concerts-to-protect-your-d-1269334973', + 'body' => array( + '//div[contains(@class, "row")/img', + '//div[contains(@class, "content-column")]', + ), + 'strip' => array( + '//*[contains(@class, "meta")]', + '//span[contains(@class, "icon")]', + '//h1', + '//aside', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lifehacker.ru.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lifehacker.ru.php new file mode 100644 index 00000000..bc140f67 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lifehacker.ru.php @@ -0,0 +1,22 @@ + array( + '%.*%' => array( + 'test_url' => 'http://lifehacker.ru/2016/03/03/polymail/', + 'body' => array( + '//div[@class="post-content"]', + ), + 'strip' => array( + '//script', + '//form', + '//style', + '//*[@class="wp-thumbnail-caption"]', + '//*[contains(@class, "social-likes")]', + '//*[@class="jp-relatedposts"]', + '//*[contains(@class, "wpappbox")]', + '//*[contains(@class, "icon__image")]', + '//div[@id="hypercomments_widget"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux-magazin.de.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux-magazin.de.php new file mode 100644 index 00000000..f4bc07d0 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux-magazin.de.php @@ -0,0 +1,16 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.linux-magazin.de/Ausgaben/2017/09/AWS-Alternativen', + 'body' => array( + '//div[@class="attribute-content"]/div[@class="attribute-intro"]', + '(//div[@class="attribute-image"])[1]', + '//div[@itemprop="articleBody"]', + ), + 'strip' => array( + '//p[@class="attribute-advice"]', + ) + ) + ) +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux.org.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux.org.php new file mode 100644 index 00000000..2520d0d0 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux.org.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.linux.org/threads/lua-the-scripting-interpreter.8352/', + 'body' => array( + '//div[@class="messageContent"]', + ), + 'strip' => array( + '//aside', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux.org.ru.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux.org.ru.php new file mode 100644 index 00000000..7fa02497 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux.org.ru.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.linux.org/threads/lua-the-scripting-interpreter.8352/', + 'body' => array( + '//div[@itemprop="articleBody"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linuxinsider.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linuxinsider.com.php new file mode 100644 index 00000000..4e0a4cc1 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linuxinsider.com.php @@ -0,0 +1,20 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.linuxinsider.com/story/82526.html?rss=1', + 'body' => array( + '//div[@id="story"]', + ), + 'strip' => array( + '//script', + '//h1', + '//div[@id="story-toolbox1"]', + '//div[@id="story-byline"]', + '//div[@id="story"]/p', + '//div[@class="story-advertisement"]', + '//iframe', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lists.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lists.php new file mode 100644 index 00000000..c7051a20 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lists.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://lists.freebsd.org/pipermail/freebsd-announce/2013-September/001504.html', + 'body' => array( + '//pre', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/loadingartist.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/loadingartist.com.php new file mode 100644 index 00000000..d06ed124 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/loadingartist.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%-150x150%' => '', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/loldwell.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/loldwell.com.php new file mode 100644 index 00000000..d358e156 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/loldwell.com.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://loldwell.com/?comic=food-math-101', + 'body' => array('//*[@id="comic"]'), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lukesurl.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lukesurl.com.php new file mode 100644 index 00000000..816233dd --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lukesurl.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'body' => array('//div[@id="comic"]//img'), + 'strip' => array(), + 'test_url' => 'http://www.lukesurl.com/archives/comic/665-3-of-clubs', + ), + ), + 'filter' => array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
$1', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/macg.co.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/macg.co.php new file mode 100644 index 00000000..bbe6dbcd --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/macg.co.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.macg.co//logiciels/2014/05/feedly-sameliore-un-petit-peu-sur-mac-82205', + 'body' => array( + '//div[contains(@class, "field-name-body")]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/maclife.de.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/maclife.de.php new file mode 100644 index 00000000..bca347ec --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/maclife.de.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.maclife.de/news/neue-farbe-iphone-8-kommt-blush-gold-10094817.html', + 'body' => array( + '//div[contains(@class, "article_wrapper")]/p | //div[contains(@class, "article_wrapper")]/h2 | //div[@class="gallery"]//figure | //div[contains(@class, "gallery_single")]//figure', + ) + ) + ) +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/magyarkurir.hu.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/magyarkurir.hu.php new file mode 100644 index 00000000..32d78bcf --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/magyarkurir.hu.php @@ -0,0 +1,21 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.magyarkurir.hu/hirek/a-vilagszerte-ismert-dicsoito-csapat-hillsong-young-free-lep-fel-budapesten', + 'body' => array( + '//div[@class="behuzas"]' + ), + 'strip' => array( + '//div[@class="ikonsav"]', + '//p[@class="copyright"]', + '//div[@class="cimkek"]', + '//div[@id="footerbanner"]', + '//div[@class="rovat sargabg rovatdobozcim"]', + '//div[@class="rovatdoboz"]', + '//a[contains(., "Own")]', + '//a[@class="fblink"]' + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marc.info.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marc.info.php new file mode 100644 index 00000000..5f582a6d --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marc.info.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://marc.info/?l=openbsd-misc&m=141987113202061&w=2', + 'body' => array( + '//pre', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marriedtothesea.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marriedtothesea.com.php new file mode 100644 index 00000000..469640df --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marriedtothesea.com.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.marriedtothesea.com/index.php?date=052915', + 'body' => array( + '//div[@align]/a/img', + ), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marycagle.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marycagle.com.php new file mode 100644 index 00000000..b8665e35 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marycagle.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'body' => array( + '//img[@id="cc-comic"]', + '//div[@class="cc-newsbody"]', + ), + 'strip' => array(), + 'test_url' => 'http://www.marycagle.com/letsspeakenglish/74-grim-reality/', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/maximumble.thebookofbiff.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/maximumble.thebookofbiff.com.php new file mode 100644 index 00000000..88800546 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/maximumble.thebookofbiff.com.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://maximumble.thebookofbiff.com/2015/04/20/1084-change/', + 'body' => array('//div[@id="comic"]/div/a/img'), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/medium.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/medium.com.php new file mode 100644 index 00000000..e20860e0 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/medium.com.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'test_url' => 'https://medium.com/lessons-learned/917b8b63ae3e', + 'body' => array( + '//div[@class="section-content"]', + ), + 'strip' => array( + '//div[contains(@class,"metabar")]', + '//img[contains(@class,"thumbnail")]', + '//h1', + '//blockquote', + '//div[@class="aspectRatioPlaceholder-fill"]', + '//footer' + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mercworks.net.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mercworks.net.php new file mode 100644 index 00000000..c7a27dea --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mercworks.net.php @@ -0,0 +1,17 @@ + array( + '%.*%' => array( + 'body' => array('//div[@id="comic"]', + '//div[contains(@class,"entry-content")]', + ), + 'strip' => array(), + 'test_url' => 'http://mercworks.net/comicland/healthy-choice/', + ), + ), + 'filter' => array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
$1', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/metronieuws.nl.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/metronieuws.nl.php new file mode 100644 index 00000000..5011169f --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/metronieuws.nl.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.metronieuws.nl/sport/2015/04/broer-fellaini-zorgde-bijna-voor-paniek-bij-mourinho', + 'body' => array('//div[contains(@class,"article-top")]/div[contains(@class,"image-component")] | //div[@class="article-full-width"]/div[1]'), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/milwaukeenns.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/milwaukeenns.php new file mode 100644 index 00000000..ddb29a56 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/milwaukeenns.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://milwaukeenns.org/2016/01/08/united-way-grant-enables-sdc-to-restore-free-tax-assistance-program/', + 'body' => array( + '//div[@class="pf-content"]', + ), + 'strip' => array( + '//div[@class="printfriendly"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mno.hu.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mno.hu.php new file mode 100644 index 00000000..a2799b85 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mno.hu.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'https://mno.hu/kulfold/elnokot-valasztanak-szloveniaban-2422840', + 'body' => array( + '//div[@class="header"]/h1', + '//div[@class="content hircikk clearfix"]/p' + ), + 'strip' => array( + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mokepon.smackjeeves.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mokepon.smackjeeves.com.php new file mode 100644 index 00000000..1ddcd407 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mokepon.smackjeeves.com.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://mokepon.smackjeeves.com/comics/2120096/chapter-9-page-68/', + 'body' => array('//*[@id="comic_area_inner"]/img | //*[@id="comic_area_inner"]/a/img'), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/monandroid.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/monandroid.com.php new file mode 100644 index 00000000..f87560e2 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/monandroid.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.monandroid.com/blog/tutoriel-avance-activer-le-stockage-fusionne-sur-android-6-marshamallow-t12.html', + 'body' => array( + '//div[@class="blog-post-body"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/monwindows.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/monwindows.com.php new file mode 100644 index 00000000..b2b24d74 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/monwindows.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.monwindows.com/tout-savoir-sur-le-centre-d-action-de-windows-phone-8-1-t40574.html', + 'body' => array( + '//div[@class="blog-post-body"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/moya-planeta.ru.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/moya-planeta.ru.php new file mode 100644 index 00000000..dd842844 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/moya-planeta.ru.php @@ -0,0 +1,21 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.moya-planeta.ru/travel/view/chto_yaponcu_horosho_russkomu_ne_ponyat_20432/', + 'body' => array( + '//div[@class="full_object"]', + ), + 'strip' => array( + '//div[@class="full_object_panel object_panel"]', + '//div[@class="full_object_panel_geo object_panel"]', + '//div[@class="full_object_title"]', + '//div[@class="full_object_social_likes"]', + '//div[@class="full_object_planeta_likes"]', + '//div[@class="full_object_go2comments"]', + '//div[@id="yandex_ad_R-163191-3"]', + '//div[@class="full_object_shop_article_recommend"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mrlovenstein.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mrlovenstein.com.php new file mode 100644 index 00000000..b971091f --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mrlovenstein.com.php @@ -0,0 +1,9 @@ + array( + '%.*%' => array( + '%alt="(.+)" */>%' => '/>
$1', + '%\.png%' => '_rollover.png', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/muckrock.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/muckrock.com.php new file mode 100644 index 00000000..9e354a36 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/muckrock.com.php @@ -0,0 +1,20 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.muckrock.com/news/archives/2016/jan/13/5-concerns-private-prisons/', + 'body' => array( + '//div[@class="content"]', + ), + 'strip' => array( + '//div[@class="newsletter-widget"]', + '//div[@class="contributors"]', + '//time', + '//h1', + '//div[@class="secondary"]', + '//aside', + '//div[@class="articles__related"]' + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mynorthshorenow.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mynorthshorenow.com.php new file mode 100644 index 00000000..b6309157 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mynorthshorenow.com.php @@ -0,0 +1,27 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.mynorthshorenow.com/story/news/local/fox-point/2017/04/04/fox-point-building-board-approves-dunwood-commons-project/99875570/', + 'body' => array( + '//div[@itemprop="articleBody"]', + ), + 'strip' => array( + '//h1', + '//iframe', + '//span[@class="mycapture-small-btn mycapture-btn-with-text mycapture-expandable-photo-btn-small js-mycapture-btn-small"]', + '//div[@class="close-wrap"]', + '//div[contains(@class,"ui-video-wrapper")]', + '//div[contains(@class,"media-mob")]', + '//div[contains(@class,"left-mob")]', + '//div[contains(@class,"nerdbox")]', + '//p/span', + '//div[contains(@class,"oembed-asset")]', + '//*[contains(@class,"share")]', + '//div[contains(@class,"gallery-asset")]', + '//div[contains(@class,"oembed-asset")]', + '//div[@class="article-print-url"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nakedCapitalism.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nakedCapitalism.php new file mode 100644 index 00000000..ec2d5fd5 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nakedCapitalism.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://feedproxy.google.com/~r/NakedCapitalism/~3/JOBxEHxN8ZI/mark-blyth-liberalism-undermined-democracy-failure-democratic-party.html', + 'body' => array( + '//div[@class="pf-content"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nasa.gov.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nasa.gov.php new file mode 100644 index 00000000..c6692d07 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nasa.gov.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.nasa.gov/image-feature/jpl/pia20514/coy-dione', + 'body' => array( + '//div[@class="article-body"]', + ), + 'strip' => array( + '//div[@class="title-bar"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nat-geo.ru.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nat-geo.ru.php new file mode 100644 index 00000000..1a42d997 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nat-geo.ru.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.nat-geo.ru/fact/868093-knidos-antichnyy-naukograd/', + 'body' => array( + '//div[@class="article-inner-text"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nationaljournal.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nationaljournal.com.php new file mode 100644 index 00000000..5e612bef --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nationaljournal.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.nationaljournal.com/s/354962/south-carolina-evangelicals-outstrip-establishment?mref=home_top_main', + 'body' => array( + '//div[@class="section-body"]', + ), + 'strip' => array( + '//*[contains(@class, "-related")]', + '//*[contains(@class, "social")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nature.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nature.com.php new file mode 100644 index 00000000..6b9e87f4 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nature.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.nature.com/doifinder/10.1038/nature.2015.18340', + 'body' => array( + '//div[contains(@class,"main-content")]', + ), + 'strip' => array(), + ), + ), +); + diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nba.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nba.com.php new file mode 100644 index 00000000..c8ea926f --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nba.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.nba.com/2015/news/09/25/knicks-jackson-to-spend-more-time-around-coaching-staff.ap/index.html?rss=true', + 'body' => array( + '//div[@class="paragraphs"]', + ), + 'strip' => array( + '//div[@id="nbaArticleSocialWrapper_bot"]', + '//h5', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nedroid.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nedroid.com.php new file mode 100644 index 00000000..3214c62a --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nedroid.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
$1', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/networkworld.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/networkworld.com.php new file mode 100644 index 00000000..18524354 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/networkworld.com.php @@ -0,0 +1,20 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.networkworld.com/article/3020585/security/the-incident-response-fab-five.html', + 'body' => array( + '//figure/img[@class="hero-img"]', + '//section[@class="deck"]', + '//div[@itemprop="articleBody"] | //div[@itemprop="reviewBody"]', + '//div[@class="carousel-inside-crop"]', + ), + 'strip' => array( + '//script', + '//aside', + '//div[@class="credit"]', + '//div[@class="view-large"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/neustadt-ticker.de.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/neustadt-ticker.de.php new file mode 100644 index 00000000..e0c0d19d --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/neustadt-ticker.de.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.neustadt-ticker.de/41302/alltag/kultur/demo-auf-der-boehmischen', + 'body' => array( + '//div[@class="entry-content"]', + ), + 'strip' => array( + '//*[contains(@class, "sharedaddy")]', + '//*[contains(@class, "yarpp-related")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nextinpact.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nextinpact.com.php new file mode 100644 index 00000000..29dd9d6b --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nextinpact.com.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.nextinpact.com/news/101122-3d-nand-intel-lance-six-nouvelles-gammes-ssd-pour-tous-usages.htm', + 'body' => array( + '//div[@class="container_article"]', + ), + 'strip' => array( + '//div[@class="infos_article"]', + '//div[@id="actu_auteur"]', + '//div[@id="soutenir_journaliste"]', + '//section[@id="bandeau_abonnez_vous"]', + '//br' + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/niceteethcomic.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/niceteethcomic.com.php new file mode 100644 index 00000000..f41e4438 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/niceteethcomic.com.php @@ -0,0 +1,10 @@ + array( + '%/archives.*%' => array( + 'test_url' => 'http://niceteethcomic.com/archives/page119/', + 'body' => array('//*[@class="comicpane"]/a/img'), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nichtlustig.de.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nichtlustig.de.php new file mode 100644 index 00000000..4d083f98 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nichtlustig.de.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%.*static.nichtlustig.de/comics/full/(\\d+).*%s' => '', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nlcafe.hu.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nlcafe.hu.php new file mode 100644 index 00000000..b85e6b28 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nlcafe.hu.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.nlcafe.hu/ezvan/20171021/nyugdijas-drogdilert-fogtak-a-ferencvarosi-rendorok/', + 'body' => array( + '//div[@class="single-title"]', + '//div[@class="single-excerpt"]', + '//div[@class="single-post-container-content"]/p', + '//div[@class="single-post-container-content"]/div' + ), + 'strip' => array( + '//div[@class="widget-container related-articles bigdata-widget related-full"]', + '//div[@class="banner-container clear-banner-row clearfix"]' + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/novo-argumente.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/novo-argumente.com.php new file mode 100644 index 00000000..cef35955 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/novo-argumente.com.php @@ -0,0 +1,16 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.novo-argumente.com/artikel/der_kampf_gegen_die_schlafkrankheit', + 'body' => array( + '//main/div/article', + ), + 'strip' => array( + '//*[@class="artikel-datum"]', + '//*[@class="artikel-titel"]', + '//*[@class="artikel-autor"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/oglaf.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/oglaf.com.php new file mode 100644 index 00000000..8b2b5b65 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/oglaf.com.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'body' => array( + '//img[@id="strip"]', + '//a/div[@id="nx"]/..', + ), + 'strip' => array(), + 'test_url' => 'http://oglaf.com/slodging/', + ), + ), + 'filter' => array( + '%.*%' => array( + '%alt="(.+)" title="(.+)" */>%' => '/>
$1
$2
', + '%%' => 'Next page', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/onhax.net.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/onhax.net.php new file mode 100644 index 00000000..213849d8 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/onhax.net.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://onhax.net/process-lasso-8-9-1-4-pro-key-portable-is-here-latest', + 'body' => array( + '//div[@class="postcontent"]', + ), + 'strip' => array( + '//*[@class="sharedaddy sd-sharing-enabled"]', + '//*[@class="yarpp-related"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/onlinekosten.de.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/onlinekosten.de.php new file mode 100644 index 00000000..7382612f --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/onlinekosten.de.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.onlinekosten.de/news/android-8-0-die-neuen-features-im-ueberblick_209619.html?utm_source=rss&utm_medium=feed&utm_campaign=android-8-0-die-neuen-features-im-ueberblick', + 'body' => array( + '//p[@class="cms-widget_article_lead"]', + '//img[@class="bec_img"]', + '//div[@class="cms-widget_article_body"]', + ), + ) + ) +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/onmilwaukee.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/onmilwaukee.php new file mode 100644 index 00000000..f66ac4b8 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/onmilwaukee.php @@ -0,0 +1,24 @@ + array( + '%.*%' => array( + 'test_url' => 'http://onmilwaukee.com/movies/articles/downerspelunking.html', + 'body' => array( + '//article[contains(@class, "show")]', + ), + 'strip' => array( + '//h1', + '//div[contains(@class,"-ad")]', + '//div[contains(@class,"_ad")]', + '//div[@id="pub_wrapper"]', + '//div[contains(@class,"share_tools")]', + '//div[@class="clearfix"]', + '//div[contains(@class,"image_control")]', + '//section[@class="ribboned"]', + '//div[contains(@class,"sidebar")]', + '//aside[@class="article_tag_list"]', + '//section[contains(@id,"more_posts")]' + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/openculture.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/openculture.com.php new file mode 100644 index 00000000..84f2beed --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/openculture.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.openculture.com/2017/03/are-we-living-inside-a-computer-simulation-watch-the-simulation-argument.html', + 'body' => array( + '//div[@class="entry"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/opennet.ru.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/opennet.ru.php new file mode 100644 index 00000000..1fb7722b --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/opennet.ru.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.opennet.ru/opennews/art.shtml?num=46549', + 'body' => array( + '//*[@id="r_memo"]', + ), + 'strip' => array( + ), + ) + ) +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/openrightsgroup.org.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/openrightsgroup.org.php new file mode 100644 index 00000000..94139a72 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/openrightsgroup.org.php @@ -0,0 +1,20 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.openrightsgroup.org/blog/2014/3-days-to-go-till-orgcon2014', + 'body' => array( + '//div[contains(@class, "content")]/div', + ), + 'strip' => array( + '//h2[1]', + '//div[@class="info"]', + '//div[@class="tags"]', + '//div[@class="comments"]', + '//div[@class="breadcrumbs"]', + '//h1[@class="pageTitle"]', + '//p[@class="bookmarkThis"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/opensource.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/opensource.com.php new file mode 100644 index 00000000..60f3577b --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/opensource.com.php @@ -0,0 +1,22 @@ + array( + '%.*%' => array( + 'test_url' => 'http://opensource.com/life/15/10/how-internet-things-will-change-way-we-think', + 'body' => array( + '//div[@id="article-template"]', + ), + 'strip' => array( + '//div[contains(@class,"os-article__sidebar")]', + '//div[@class="panel-pane pane-node-title"]', + '//div[@class="panel-pane pane-os-article-byline"]', + '//ul', + '//div[contains(@class,"-license")]', + '//div[contains(@class,"-tags")]', + '//div[@class="panel-pane pane-os-article-byline"]', + '//div[@class="os-article__content-below"]', + '//div[@id="comments"]' + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/optipess.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/optipess.com.php new file mode 100644 index 00000000..3214c62a --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/optipess.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
$1', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/origo.hu.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/origo.hu.php new file mode 100644 index 00000000..7bd94965 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/origo.hu.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.origo.hu/itthon/20171019-hamisan-tanuskodott-az-ugyved-ezert-nem-praktizalhat.html', + 'body' => array( + '//header[@id="article-head"]/h1', + '//article[@id="article-center"]' + ), + 'strip' => array( + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/osnews.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/osnews.com.php new file mode 100644 index 00000000..1d1396c8 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/osnews.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://osnews.com/story/28863/Google_said_to_be_under_US_antitrust_scrutiny_over_Android', + 'body' => array( + '//div[@class="newscontent1"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pastebin.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pastebin.com.php new file mode 100644 index 00000000..b20bf41c --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pastebin.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://pastebin.com/ed1pP9Ak', + 'body' => array( + '//div[@class="text"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pcgameshardware.de.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pcgameshardware.de.php new file mode 100644 index 00000000..f180aeef --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pcgameshardware.de.php @@ -0,0 +1,16 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.pcgameshardware.de/Dragon-Age-Thema-259929/News/Plaene-fuer-Teil-4-und-5-der-Serie-1235682/', + 'body' => array( + '//p[@class="introText"]', + '//figure[contains(@class, "articleBigTeaser")]', + '//div[@id="articleTextBody"]//p | //div[@id="articleTextBody"]//h2[@class="anchorHeadline"]', + ), + 'strip' => array( + '//p[@class="introText"]//time', + ) + ) + ) +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/peebleslab.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/peebleslab.com.php new file mode 100644 index 00000000..ce4891d1 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/peebleslab.com.php @@ -0,0 +1,9 @@ + array( + '%.*%' => array( + // the extra space is required to strip the title cleanly + '%title="(.+) " */>%' => '/>
$1', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/penny-arcade.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/penny-arcade.com.php new file mode 100644 index 00000000..dd39983b --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/penny-arcade.com.php @@ -0,0 +1,21 @@ + array( + '%/news/.*%' => array( + 'test_url' => 'http://penny-arcade.com/news/post/2015/04/15/101-part-two', + 'body' => array( + '//*[@class="postBody"]/*', + ), + 'strip' => array( + ), + ), + '%/comic/.*%' => array( + 'test_url' => 'http://penny-arcade.com/comic/2015/04/15', + 'body' => array( + '//*[@id="comicFrame"]/a/img', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pixelbeat.org.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pixelbeat.org.php new file mode 100644 index 00000000..fa9052ea --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pixelbeat.org.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.pixelbeat.org/programming/sigpipe_handling.html#1425573246', + 'body' => array( + '//div[@class="contentText"]', + ), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/plus.google.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/plus.google.com.php new file mode 100644 index 00000000..5e48a6cf --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/plus.google.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'https://plus.google.com/+LarryPage/posts/Lh8SKC6sED1', + 'body' => array( + '//div[@role="article"]/div[contains(@class, "eE")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/popstrip.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/popstrip.com.php new file mode 100644 index 00000000..801a2814 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/popstrip.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%( '$1$2$1bonus.png"/>', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/portfolio.hu.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/portfolio.hu.php new file mode 100644 index 00000000..ad01dadc --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/portfolio.hu.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.portfolio.hu/gazdasag/mennybe-vagy-pokolba-megy-ma-a-cseh-trump.265833.html', + 'body' => array( + '//div[@id="cikk"]/h1', + '//div[@class="smscontent"]' + ), + 'strip' => array( + '//div[@class="traderhirdetes ga_viewanalytics"]' + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pro-linux.de.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pro-linux.de.php new file mode 100644 index 00000000..bc76630f --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pro-linux.de.php @@ -0,0 +1,16 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.pro-linux.de/news/1/25252/chrome-62-erschienen.html', + 'body' => array( + '//div[@id="news"]', + ), + 'strip' => array( + '//h3[@class="topic"]', + '//h2[@class="title"]', + '//div[@class="picto"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/publicpolicyforum.org.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/publicpolicyforum.org.php new file mode 100644 index 00000000..5dc8be88 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/publicpolicyforum.org.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'https://publicpolicyforum.org/blog/going-extra-mile', + 'body' => array( + '//div[contains(@class,"field-name-post-date")]', + '//div[contains(@class,"field-name-body")]', + ), + 'strip' => array( + '//img[@src="http://publicpolicyforum.org/sites/default/files/logo3.jpg"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/publy.ru.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/publy.ru.php new file mode 100644 index 00000000..bcfeeb99 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/publy.ru.php @@ -0,0 +1,24 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.publy.ru/post/19988', + 'body' => array( + '//div[@class="singlepost"]', + ), + 'strip' => array( + '//script', + '//form', + '//style', + '//*[@class="featured"]', + '//*[@class="toc_white no_bullets"]', + '//*[@class="toc_title"]', + '//*[@class="pba"]', + '//*[@class="comments"]', + '//*[contains(@class, "g-single")]', + '//*[@class="ts-fab-wrapper"]', + '//*[contains(@class, "wp_rp_wrap")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/putaindecode.fr.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/putaindecode.fr.php new file mode 100644 index 00000000..9fa5568c --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/putaindecode.fr.php @@ -0,0 +1,16 @@ + array( + '%.*%' => array( + 'test_url' => 'http://putaindecode.fr/posts/js/etat-lieux-js-modulaire-front/', + 'body' => array( + '//*[@class="putainde-Post-md"]', + ), + 'strip' => array( + '//*[contains(@class, "inlineimg")]', + '//*[contains(@class, "comment-respond")]', + '//header', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/recode.net.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/recode.net.php new file mode 100644 index 00000000..343cd12f --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/recode.net.php @@ -0,0 +1,20 @@ + array( + '%.*%' => array( + 'test_url' => 'http://recode.net/2015/09/26/big-tech-rolls-out-red-carpet-for-indian-prime-minister-lobbies-behind-closed-doors/', + 'body' => array( + '//img[contains(@class,"attachment-large")]', + '//div[contains(@class,"postarea")]', + '//li[@class,"author"]', + ), + 'strip' => array( + '//script', + '//div[contains(@class,"sharedaddy")]', + '//div[@class="post-send-off"]', + '//div[@class="large-12 columns"]', + '//div[contains(@class,"inner-related-article")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/retractionwatch.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/retractionwatch.com.php new file mode 100644 index 00000000..b97c73ed --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/retractionwatch.com.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'http://retractionwatch.com/2015/11/12/psychologist-jens-forster-settles-case-by-agreeing-to-2-retractions/', + 'body' => array( + '//*[@class="main"]', + '//*[@class="entry-content"]', + ), + 'strip' => array( + '//*[contains(@class, "sharedaddy")]', + '//*[contains(@class, "jp-relatedposts")]', + '//p[@class="p1"]', + ) + ) + ) +); + diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/rockpapershotgun.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/rockpapershotgun.com.php new file mode 100644 index 00000000..71110786 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/rockpapershotgun.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.rockpapershotgun.com/2016/08/26/the-divisions-expansions-delayed-to-improve-the-game/', + 'body' => array( + '//div[@class="entry"]', + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/rue89.nouvelobs.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/rue89.nouvelobs.com.php new file mode 100644 index 00000000..cb9116a3 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/rue89.nouvelobs.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://rue89.feedsportal.com/c/33822/f/608948/s/30999fa0/sc/24/l/0L0Srue890N0C20A130C0A80C30A0Cfaisait0Eboris0Eboillon0Eex0Esarko0Eboy0E350A0E0A0A0A0Eeuros0Egare0Enord0E245315/story01.htm', + 'body' => array( + '//*[@id="article"]/div[contains(@class, "content")]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/rugbyrama.fr.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/rugbyrama.fr.php new file mode 100644 index 00000000..9915c234 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/rugbyrama.fr.php @@ -0,0 +1,20 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.rugbyrama.fr/rugby/top-14/2015-2016/top-14-hayman-coupe-du-monde-finale-2012-lutte.-voici-levan-chilachava-toulon_sto5283863/story.shtml', + 'body' => array( + '//div[@class="storyfull__content"]', + ), + 'strip' => array( + '//script', + '//form', + '//style', + '//*[@class="share-buttons"]', + '//*[@class="ad"]', + '//*[@class="hide-desktop"]', + '//*[@id="tracking_img"]', + ) + ) + ) +); \ No newline at end of file diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/salonkolumnisten.com b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/salonkolumnisten.com new file mode 100644 index 00000000..37f43e9e --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/salonkolumnisten.com @@ -0,0 +1,17 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.salonkolumnisten.com/schulpolitik-niedersachsen/', + 'body' => array( + '//div[@id="main"]/div[contains(@class, "featimg")]', + '//div[@id="main"]/article/div[contains(@class, "entry-content")]', + ), + 'strip' => array( + '//div[@id="main"]/article/div[contains(@class, "entry-content")]/a[1]', + '//div[@id="main"]/article/div[contains(@class, "entry-content")]/a[1]', + ), + ), + ), +); + diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/satwcomic.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/satwcomic.com.php new file mode 100644 index 00000000..d63fc11c --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/satwcomic.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://satwcomic.com/day-at-the-beach', + 'body' => array( + '//div[@class="container"]/center/a/img', + '//span[@itemprop="articleBody"]', + ), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/science-skeptical.de.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/science-skeptical.de.php new file mode 100644 index 00000000..fcf045fb --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/science-skeptical.de.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.science-skeptical.de/politik/diesel-die-lueckenmedien-im-glashaus-6/0016080/', + 'body' => array( + '//div[@class="pf-content"]', + ), + 'strip' => array( + '//div[contains(@class, "printfriendly")]', + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/scrumalliance.org.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/scrumalliance.org.php new file mode 100644 index 00000000..7835fd9e --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/scrumalliance.org.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.scrumalliance.org/community/articles/2015/march/an-introduction-to-agile-project-intake?feed=articles', + 'body' => array( + '//div[@class="article_content"]', + ), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/securityfocus.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/securityfocus.com.php new file mode 100644 index 00000000..01045148 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/securityfocus.com.php @@ -0,0 +1,17 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.securityfocus.com/archive/1/540139', + 'body' => array( + '//div[@id="vulnerability"]', + '//div[@class="comments_reply"]', + ), + 'strip' => array( + '//span[@class="title"]', + '//div[@id="logo_new"]', + '//div[@id="bannerAd"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/sentfromthemoon.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/sentfromthemoon.com.php new file mode 100644 index 00000000..f4354179 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/sentfromthemoon.com.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'body' => array( + '//div[@class="comicpane"]/a/img', + '//div[@class="entry"]', + ), + 'strip' => array(), + 'test_url' => 'http://sentfromthemoon.com/archives/1417', + ), + ), + 'filter' => array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
$1', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/sitepoint.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/sitepoint.com.php new file mode 100644 index 00000000..ab0eb7d4 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/sitepoint.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.sitepoint.com/creating-hello-world-app-swift/', + 'body' => array( + '//section[@class="article_body"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/slashdot.org.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/slashdot.org.php new file mode 100644 index 00000000..89ced8b6 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/slashdot.org.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://science.slashdot.org/story/15/04/20/0528253/pull-top-can-tabs-at-50-reach-historic-archaeological-status', + 'body' => array( + '//article/div[@class="body"] | //article[@class="layout-article"]/div[@class="elips"]', ), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smallhousebliss.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smallhousebliss.com.php new file mode 100644 index 00000000..8c13c44c --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smallhousebliss.com.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'test_url' => 'http://smallhousebliss.com/2013/08/29/house-g-by-lode-architecture/', + 'body' => array( + '//div[@class="post-content"]', + ), + 'strip' => array( + '//*[contains(@class, "gallery")]', + '//*[contains(@class, "share")]', + '//*[contains(@class, "wpcnt")]', + '//*[contains(@class, "meta")]', + '//*[contains(@class, "postitle")]', + '//*[@id="nav-below"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smarthomewelt.de.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smarthomewelt.de.php new file mode 100644 index 00000000..7463abc7 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smarthomewelt.de.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://smarthomewelt.de/apple-tv-amazon-echo-smart-home/', + 'body' => array('//div[@class="entry-inner"]/p | //div[@class="entry-inner"]/div[contains(@class,"wp-caption")]'), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smashingmagazine.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smashingmagazine.com.php new file mode 100644 index 00000000..cbe10726 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smashingmagazine.com.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.smashingmagazine.com/2015/04/17/using-sketch-for-responsive-web-design-case-study/', + 'body' => array('//article[contains(@class,"post")]/p'), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smbc-comics.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smbc-comics.com.php new file mode 100644 index 00000000..42262dc9 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smbc-comics.com.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.smbc-comics.com/comic/the-troll-toll', + 'body' => array( + '//div[@id="cc-comicbody"]', + '//div[@id="aftercomic"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/snopes.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/snopes.com.php new file mode 100644 index 00000000..b0fe6557 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/snopes.com.php @@ -0,0 +1,22 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.snopes.com/bacca-brides-on-tour/', + 'body' => array( + '//article', + ), + 'strip' => array( + '//span[@itemprop="author"]', + '//div[contains(@class,"author-")]', + '//h1', + '//style', + '//div[contains(@class,"socialShares")]', + '//div[contains(@class,"ad-unit")]', + '//aside', + '//div[contains(@class,"boomtrain")]', + '//footer' + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/soundandvision.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/soundandvision.com.php new file mode 100644 index 00000000..6448bb05 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/soundandvision.com.php @@ -0,0 +1,21 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.soundandvision.com/content/james-guthrie-mixing-roger-waters-and-pink-floyd-51', + 'body' => array( + '//div[@id="left"]', + ), + 'strip' => array( + '//div[@class="meta"]', + '//div[@class="ratingsbox"]', + '//h1', + '//h2', + '//addthis', + '//comment-links', + '//div[@class="book-navigation"]', + '//div[@class="comment-links"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/spiegel.de.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/spiegel.de.php new file mode 100644 index 00000000..b42c3aac --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/spiegel.de.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.spiegel.de/politik/ausland/afrika-angola-geht-gegen-islam-vor-und-schliesst-moscheen-a-935788.html', + 'body' => array( + '//div[@class="spArticleContent"]/p | //div[@class="spArticleContent"]//img[@class="spResponsiveImage "]', + ), + 'strip' => array( + '//div[@class="author-details"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/stereophile.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/stereophile.com.php new file mode 100644 index 00000000..8e410be4 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/stereophile.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.stereophile.com/content/2015-rocky-mountain-audio-fest-starts-friday', + 'body' => array( + '//div[@class="content clear-block"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/stupidfox.net.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/stupidfox.net.php new file mode 100644 index 00000000..61182d72 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/stupidfox.net.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://stupidfox.net/134-sleepy-time', + 'body' => array( + '//div[@class="comicmid"]/center/a/img', + '//div[@class="stand_high"]', + ), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/subtraction.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/subtraction.com.php new file mode 100644 index 00000000..6d744277 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/subtraction.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.subtraction.com/2015/06/06/time-lapse-video-of-one-world-trade-center/', + 'body' => array('//article/div[@class="entry-content"]'), + 'strip' => array(), + ), + ), + 'filter' => array( + '%.*%' => array( + '%\+%' => '', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/sz.de.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/sz.de.php new file mode 100644 index 00000000..90bde5a9 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/sz.de.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://sz.de/1.2443161', + 'body' => array('//article[@id="sitecontent"]/section[@class="topenrichment"]//img | //article[@id="sitecontent"]/section[@class="body"]/section[@class="authors"]/preceding-sibling::*[not(contains(@class, "ad"))]'), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/takprosto.cc.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/takprosto.cc.php new file mode 100644 index 00000000..624ef907 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/takprosto.cc.php @@ -0,0 +1,21 @@ + array( + '%.*%' => array( + 'test_url' => 'http://takprosto.cc/kokteyl-dlya-pohudeniya-v-domashnih-usloviyah/', + 'body' => array( + '//div[contains(@class, "entry-contentt")]', + ), + 'strip' => array( + '//script', + '//form', + '//style', + '//*[@class="views_post"]', + '//*[contains(@class, "mailchimp-box")]', + '//*[contains(@class, "essb_links")]', + '//*[contains(@rel, "nofollow")]', + '//*[contains(@class, "ads")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/techcrunch.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/techcrunch.com.php new file mode 100644 index 00000000..230b791a --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/techcrunch.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://techcrunch.com/2013/08/31/indias-visa-maze/', + 'body' => array( + '//div[contains(@class, "media-container")]', + '//div[contains(@class, "article-entry")]', + ), + 'strip' => array( + '//*[contains(@class, "module-crunchbase")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/the-ebook-reader.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/the-ebook-reader.com.php new file mode 100644 index 00000000..3b01eb96 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/the-ebook-reader.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://blog.the-ebook-reader.com/2015/09/25/kobo-glo-hd-and-kobo-touch-2-0-covers-and-cases-roundup/', + 'body' => array( + '//div[@class="entry"]', + ), + 'strip' => array( + '//div[@id="share"]', + '//div[contains(@class,"ItemCenter")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theatlantic.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theatlantic.com.php new file mode 100644 index 00000000..bfad4ab2 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theatlantic.com.php @@ -0,0 +1,23 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.theatlantic.com/politics/archive/2015/09/what-does-it-mean-to-lament-the-poor-inside-panem/407317/', + 'body' => array( + '//picture[@class="img"]', + '//figure/figcaption/span', + '//div/p[@itemprop="description"]', + '//div[@class="article-body"]', + '//ul[@class="photos"]', + ), + 'strip' => array( + '//aside[@class="callout"]', + '//span[@class="credit"]', + '//figcaption[@class="credit"]', + '//aside[contains(@class,"partner-box")]', + '//div[contains(@class,"ad")]', + '//a[contains(@class,"social-icon")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theawkwardyeti.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theawkwardyeti.com.php new file mode 100644 index 00000000..fd4f3d50 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theawkwardyeti.com.php @@ -0,0 +1,12 @@ + array( + '%/comic/.*%' => array( + 'test_url' => 'http://theawkwardyeti.com/comic/things-to-do/', + 'body' => array( + '//div[@id="comic"]' + ), + 'strip' => array() + ) + ) +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thecodinglove.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thecodinglove.com.php new file mode 100644 index 00000000..c6ec5bf5 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thecodinglove.com.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://thecodinglove.com/post/116897934767', + 'body' => array('//div[@class="bodytype"]'), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thedoghousediaries.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thedoghousediaries.com.php new file mode 100644 index 00000000..d2f840d7 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thedoghousediaries.com.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'body' => array( + '//div[@class="comicpane"]/a/img', + '//div[@class="entry"]', + ), + 'strip' => array(), + 'test_url' => 'http://thedoghousediaries.com/6023', + ), + ), + 'filter' => array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
$1', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thegamercat.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thegamercat.com.php new file mode 100644 index 00000000..f9b4637b --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thegamercat.com.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.thegamercat.com/comic/just-no/', + 'body' => array('//div[@id="comic"] | //div[@class="post-content"]/div[@class="entry"]/p'), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thehindu.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thehindu.com.php new file mode 100644 index 00000000..1e6735ba --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thehindu.com.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.thehindu.com/sci-tech/science/why-is-the-shape-of-cells-in-a-honeycomb-always-hexagonal/article7692306.ece?utm_source=RSS_Feed&utm_medium=RSS&utm_campaign=RSS_Syndication', + 'body' => array( + '//div/img[@class="main-image"]', + '//div[@class="photo-caption"]', + '//div[@class="articleLead"]', + '//p', + '//span[@class="upper"]', + ), + 'strip' => array( + '//div[@id="articleKeywords"]', + '//div[@class="photo-source"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thelocal.se.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thelocal.se.php new file mode 100644 index 00000000..c3ec250c --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thelocal.se.php @@ -0,0 +1,17 @@ + array( + '%.*%' => array( + 'test_url' => 'www.thelocal.se/20161219/this-swede-can-memorize-hundreds-of-numbers-in-only-five-minutes', + 'body' => array( + '//div[@id="article-photo"]', + '//div[@id="article-description"]', + '//div[@id="article-body"]', + ), + 'strip' => array( + '//div[@id="article-info-middle"]', + ) + ) + ) +); + diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/themerepublic.net.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/themerepublic.net.php new file mode 100644 index 00000000..bc47b278 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/themerepublic.net.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.themerepublic.net/2015/04/david-lopez-pitoko.html?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+blogspot%2FDngUJ+%28Theme+Republic%29&utm_content=FeedBurner', + 'body' => array('//*[@class="post-body"]'), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/themoscowtimes.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/themoscowtimes.com.php new file mode 100644 index 00000000..0f5bf75e --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/themoscowtimes.com.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.themoscowtimes.com/business/article/535500.html', + 'body' => array( + '//div[@class="article_main_img"]', + '//div[@class="article_text"]', + ), + 'strip' => array( + '//div[@class="articlebottom"]', + '//p/b', + '//p/a[contains(@href, "/article.php?id=")]', + '//div[@class="disqus_wrap"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thenewslens.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thenewslens.com.php new file mode 100644 index 00000000..75381707 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thenewslens.com.php @@ -0,0 +1,21 @@ + array( + '%.*%' => array( + 'test_url' => 'http://international.thenewslens.com/post/255032/', + 'body' => array( + '//div[@class="article-section"]', + ), + 'strip' => array( + '//div[contains(@class,"ad-")]', + '//div[@class="article-title-box"]', + '//div[@class="function-box"]', + '//p/span', + '//aside', + '//footer', + '//div[@class="article-infoBot-box"]', + '//div[contains(@class,"standard-container")]' + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theodd1sout.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theodd1sout.com.php new file mode 100644 index 00000000..d06ed124 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theodd1sout.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%-150x150%' => '', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theonion.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theonion.com.php new file mode 100644 index 00000000..acbfd36b --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theonion.com.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.theonion.com/article/wild-eyed-jim-harbaugh-informs-players-they-must-k-51397?utm_medium=RSS&utm_campaign=feeds', + 'body' => array( + '//div[@class="content-masthead"]/figure/div/noscript/img', + '//div[@class="content-text"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theregister.co.uk.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theregister.co.uk.php new file mode 100644 index 00000000..896365a6 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theregister.co.uk.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.theregister.co.uk/2017/10/21/purism_cleanses_laptops_of_intel_management_engine/', + 'body' => array( + '//div[@id="article"]', + ), + 'strip' => array( + '//div[@class="byline_and_share"]', + '//div[@class="social_btns alt_colour dcl"]', + '//div[@class="promo_article"]', + '//div[@id="article_body_btm"]', + '//p[@class="wptl btm"]' + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thestandard.com.hk.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thestandard.com.hk.php new file mode 100644 index 00000000..1163b345 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thestandard.com.hk.php @@ -0,0 +1,22 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.thestandard.com.hk/breaking_news_detail.asp?id=67156', + 'body' => array( + '//table/tr/td/span[@class="bodyCopy"]', + ), + 'strip' => array( + '//script', + '//br', + '//map[@name="gif_bar"]', + '//img[contains(@usemap,"gif_bar")]', + '//a', + '//span[@class="bodyHeadline"]', + '//i', + '//b', + '//table', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theverge.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theverge.com.php new file mode 100644 index 00000000..09e876de --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theverge.com.php @@ -0,0 +1,16 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.theverge.com/2017/11/11/16624298/mindhunter-netflix-show-david-fincher-review', + 'body' => array( + '//figure[@class="e-image e-image--hero"]/span[@class="e-image__inner"]', + '//div[@class="c-entry-content"]', + ), + 'strip' => array( + '//div[@class="c-related-list"]', + '//div[@class="c-page-title"]', + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/threepanelsoul.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/threepanelsoul.com.php new file mode 100644 index 00000000..4af6196e --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/threepanelsoul.com.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'body' => array( + '//img[@id="cc-comic"]', + ), + 'test_url' => 'http://www.threepanelsoul.com/comic/uncloaking', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/tichyseinblick.de.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/tichyseinblick.de.php new file mode 100644 index 00000000..6fba3df1 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/tichyseinblick.de.php @@ -0,0 +1,22 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.tichyseinblick.de/daili-es-sentials/jamaika-reaktionen-der-enttaeuschten/', + 'body' => array( + '//article' + ), + 'strip' => array( + '//header', + '//footer', + '//div[@class="mod-cad2"]', + '//ul[contains(@class, "social")]', + '//div[@class="rty-pop-up"]', + '//div[@class="pagelink"]', + '//div[@id="reward"]', + '//div[@class="rty-block-plista"]' + ) + ), + ), +); + diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/timesofindia.indiatimes.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/timesofindia.indiatimes.com.php new file mode 100644 index 00000000..19246806 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/timesofindia.indiatimes.com.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://timesofindia.indiatimes.com/city/mangaluru/Adani-UPCL-to-release-CSR-grant-of-Rs-3-74-crore-to-YellurGram-Panchayat/articleshow/50512116.cms', + 'body' => array( + '//div[@class="article_content clearfix"]', + '//section[@class="highlight clearfix"]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/totalcar.hu.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/totalcar.hu.php new file mode 100644 index 00000000..f2e009de --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/totalcar.hu.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'http://totalcar.hu/tesztek/2017/10/21/veteran_fiat-abarth_1000tc_1968/', + 'body' => array( + '//div[@class="content-title"]', + '//div[@class="lead-container"]/div[@class="lead"]', + '//div[@class="cikk-torzs"]' + ), + 'strip' => array( + '//span[@class="gallery_title newline"]', + '//div[@class="social-stripe cikk-bottom-box"]', + '//div[@class="cikk-bottom-text-ad"]' + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/tozsdeforum.hu.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/tozsdeforum.hu.php new file mode 100644 index 00000000..97a0da07 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/tozsdeforum.hu.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.tozsdeforum.hu/szemelyes-penzugyek/napi-penzugyek/ezek-a-legnepszerubb-turistacelpontok-voltal-mar-mindenhol-87181.html', + 'body' => array( + '//header/h1', + '//div[@class="title_img"]', + '//article/div[@class="tf-post"]/div[@class="p"]/p|//article/div[@class="tf-post"]/div[@class="p"]/h3|//article/div[@class="tf-post"]/div[@class="p"]/blockquote' + ), + 'strip' => array( + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/travel-dealz.de.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/travel-dealz.de.php new file mode 100644 index 00000000..4ee4fcdc --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/travel-dealz.de.php @@ -0,0 +1,15 @@ + array( + '%^/blog.*%' => array( + 'test_url' => 'http://travel-dealz.de/blog/venere-gutschein/', + 'body' => array('//div[@class="post-entry"]'), + 'strip' => array( + '//*[@id="jp-relatedposts"]', + '//*[@class="post-meta"]', + '//*[@class="post-data"]', + '//*[@id="author-meta"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/travelo.hu.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/travelo.hu.php new file mode 100644 index 00000000..3ab8ca4f --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/travelo.hu.php @@ -0,0 +1,17 @@ + array( + '%.*%' => array( + 'test_url' => 'http://travelo.hu/csaladbarat/2017/10/20/mar_csak_egy_het_es_kezdodik_az_oszi_szunet/', + 'body' => array( + '//div[@id="content"]/h1', + '//div[@id="kopf"]', + '//div[@id="szoveg"]' + ), + 'strip' => array( + '//div[@class="goAdverticum"]', + '//h1[@class="border"]' + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/treehugger.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/treehugger.com.php new file mode 100644 index 00000000..55eb7e01 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/treehugger.com.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.treehugger.com/uncategorized/top-ten-posts-week-bunnies-2.html', + 'body' => array( + '//div[contains(@class, "promo-image")]', + '//div[contains(@id, "entry-body")]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/treelobsters.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/treelobsters.com.php new file mode 100644 index 00000000..3214c62a --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/treelobsters.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
$1', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/tutorialzine.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/tutorialzine.com.php new file mode 100644 index 00000000..7e391457 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/tutorialzine.com.php @@ -0,0 +1,20 @@ + array( + '%.*%' => array( + 'test_url' => 'https://tutorialzine.com/2017/10/15-interesting-javascript-and-css-libraries-for-october-2017', + 'body' => array( + '//article' + ), + 'strip' => array( + '//div[@class="article__header"]', + '//div[@class="article__share"]', + '//div[@class="article__footer"]', + '//div[@id="article__related-articles"]', + '//div[@class="webappstudio-animation"]', + '//div[@class="ad-container adsbygoogle hidden-xs hidden-sm"]', + '//script' + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/twogag.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/twogag.com.php new file mode 100644 index 00000000..79f4f62e --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/twogag.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%http://www.twogag.com/comics-rss/([^.]+)\\.jpg%' => 'http://www.twogag.com/comics/$1.jpg', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/twokinds.keenspot.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/twokinds.keenspot.com.php new file mode 100644 index 00000000..3428fcb4 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/twokinds.keenspot.com.php @@ -0,0 +1,10 @@ + array( + '%.*%' => array( + 'test_url' => 'http://twokinds.keenspot.com/archive.php?p=0', + 'body' => array('//*[@class="comic"]/div/a/img | //*[@class="comic"]/div/img | //*[@id="cg_img"]/img | //*[@id="cg_img"]/a/img'), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/undeadly.org.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/undeadly.org.php new file mode 100644 index 00000000..8b15900a --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/undeadly.org.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://undeadly.org/cgi?action=article&sid=20141101181155', + 'body' => array( + '/html/body/table[3]/tbody/tr/td[1]/table[2]/tr/td[1]', + ), + 'strip' => array( + '//font', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/upi.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/upi.com.php new file mode 100644 index 00000000..ec8d1a1a --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/upi.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.upi.com/Top_News/US/2015/09/26/Tech-giants-Hollywood-stars-among-guests-at-state-dinner-for-Chinas-Xi-Jinping/4541443281006/', + 'body' => array( + '//div[@class="img"]', + '//div/article[@itemprop="articleBody"]', + ), + 'strip' => array( + '//div[@align="center"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/usatoday.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/usatoday.com.php new file mode 100644 index 00000000..edd6aa44 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/usatoday.com.php @@ -0,0 +1,27 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.usatoday.com/story/life/music/2017/02/13/things-you-should-know-happened-grammy-awards-2017/97833734/', + 'body' => array( + '//div[@itemprop="articleBody"]', + ), + 'strip' => array( + '//script', + '//h1', + '//iframe', + '//span[@class="mycapture-small-btn mycapture-btn-with-text mycapture-expandable-photo-btn-small js-mycapture-btn-small"]', + '//div[@class="close-wrap"]', + '//div[contains(@class,"ui-video-wrapper")]', + '//div[contains(@class,"media-mob")]', + '//div[contains(@class,"left-mob")]', + '//div[contains(@class,"nerdbox")]', + '//div[contains(@class,"oembed-asset")]', + '//*[contains(@class,"share")]', + '//div[contains(@class,"gallery-asset")]', + '//div[contains(@class,"oembed-asset")]', + '//div[@class="article-print-url"]' + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/version2.dk.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/version2.dk.php new file mode 100644 index 00000000..a6d49f2e --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/version2.dk.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.version2.dk/artikel/surface-pro-2-fungerer-bedre-til-arbejde-end-fornoejelse-55195', + 'body' => array( + '//section[contains(@class, "teaser")]', + '//section[contains(@class, "body")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/vezess.hu.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/vezess.hu.php new file mode 100644 index 00000000..acd68c08 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/vezess.hu.php @@ -0,0 +1,20 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.vezess.hu/hirek/2017/10/20/audi-a7-2018-bemutato/', + 'body' => array( + '//article[@id="news"]/h1', + '//article[@id="news"]/h2', + '//article[@id="news"]/p[@class="lead"]', + '//article[@id="news"]/p[@class="main-pic responsive-img-container"]', + '//div[@class="article-body"]' + ), + 'strip' => array( + '//div[@class="info-bar"]', + '//ul[@class="breadcrumb"]', + '//div[@class="embed-link ce_widget"]' + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/vgcats.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/vgcats.com.php new file mode 100644 index 00000000..b2830a37 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/vgcats.com.php @@ -0,0 +1,15 @@ + array( + '%/comics.*%' => array( + 'test_url' => 'http://www.vgcats.com/comics/?strip_id=358', + 'body' => array('//*[@align="center"]/img'), + 'strip' => array(), + ), + '%/super.*%' => array( + 'test_url' => 'http://www.vgcats.com/super/?strip_id=84', + 'body' => array('//*[@align="center"]/p/img'), + 'strip' => array(), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/vuxml.org.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/vuxml.org.php new file mode 100644 index 00000000..b9bef7a4 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/vuxml.org.php @@ -0,0 +1,17 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.vuxml.org/freebsd/a5f160fa-deee-11e4-99f8-080027ef73ec.html', + 'body' => array( + '//body', + ), + 'strip' => array( + '//h1', + '//div[@class="blurb"]', + '//hr', + '//p[@class="copyright"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/wausaudailyherald.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/wausaudailyherald.com.php new file mode 100644 index 00000000..58aceeaf --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/wausaudailyherald.com.php @@ -0,0 +1,27 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.wausaudailyherald.com/story/news/2017/04/01/hundreds-gather-remember-attorney-killed-shooting-spree/99826062/?from=global&sessionKey=&autologin=', + 'body' => array( + '//div[@itemprop="articleBody"]', + ), + 'strip' => array( + '//h1', + '//iframe', + '//span[@class="mycapture-small-btn mycapture-btn-with-text mycapture-expandable-photo-btn-small js-mycapture-btn-small"]', + '//div[@class="close-wrap"]', + '//div[contains(@class,"ui-video-wrapper")]', + '//div[contains(@class,"media-mob")]', + '//div[contains(@class,"left-mob")]', + '//div[contains(@class,"nerdbox")]', + '//p/span', + '//div[contains(@class,"oembed-asset")]', + '//*[contains(@class,"share")]', + '//div[contains(@class,"gallery-asset")]', + '//div[contains(@class,"oembed-asset")]', + '//div[@class="article-print-url"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/welt.de.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/welt.de.php new file mode 100644 index 00000000..83a2ebea --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/welt.de.php @@ -0,0 +1,20 @@ + array( + '%.*%' => array( + 'test_url' => 'https://www.welt.de/debatte/kommentare/article169740590/Bloss-keine-sozialdemokratische-Konsenssause.html', + 'body' => array( + '//main/article/header/div/div[contains(@class, "c-summary")]/div', + '//main/article/header/div[3]/div/figure/div/div/div/picture[1]', + '//main/article/header/div[3]/div/figure/figcaption/child::*', + '//main/article/div[contains(@class, "c-article-text")]' + ), + 'strip' => array( + '//*[contains(@class, "c-inline-element--has-commercials")]', + '//*[contains(@class, "c-inline-teaser")]', + '//figure[contains(@class, "c-video-element")]', + '//main/article/div[contains(@class, "c-article-text")]/div[@class="c-inline-element"]/div[contains(@class, "c-image-element")]' + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/westfalen-blatt.de.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/westfalen-blatt.de.php new file mode 100644 index 00000000..adcf417d --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/westfalen-blatt.de.php @@ -0,0 +1,16 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.westfalen-blatt.de/OWL/Lokales/Kreis-Hoexter/Warburg/3024113-Polizei-in-Warburg-Hier-waren-keine-kriminellen-Profis-am-Werk-Wurstautomat-Sprengung-mit-Polen-Boellern', + 'body' => array( + '//div[contains(@class, "articleimage")]', + '//div[@class="attribute-short"]', + '//div[@class="attribute-long"]', + ), + 'strip' => array( + '//div[@class="fb-post"]' + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.bbc.co.uk.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.bbc.co.uk.php new file mode 100644 index 00000000..98fc368a --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.bbc.co.uk.php @@ -0,0 +1,33 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.bbc.co.uk/news/world-middle-east-23911833', + 'body' => array( + '//div[@class="story-body__inner"] | //div[@class="article"]', + '//div[@class="indPost"]', + ), + 'strip' => array( + '//form', + '//div[@id="headline"]', + '//*[@class="warning"]', + '//span[@class="off-screen"]', + '//span[@class="story-image-copyright"]', + '//ul[@class="story-body__unordered-list"]', + '//div[@class="ad_wrapper"]', + '//div[@id="article-sidebar"]', + '//div[@class="data-table-outer"]', + '//*[@class="story-date"]', + '//*[@class="story-header"]', + '//figure[contains(@class,"has-caption")]', + '//*[@class="story-related"]', + '//*[contains(@class, "byline")]', + '//p[contains(@class, "media-message")]', + '//*[contains(@class, "story-feature")]', + '//*[@id="video-carousel-container"]', + '//*[@id="also-related-links"]', + '//*[contains(@class, "share") or contains(@class, "hidden") or contains(@class, "hyper")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.bdgest.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.bdgest.com.php new file mode 100644 index 00000000..41ef68d4 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.bdgest.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.bdgest.com/chronique-6027-BD-Adrastee-Tome-2.html', + 'body' => array( + '//*[contains(@class, "chronique")]', + ), + 'strip' => array( + '//*[contains(@class, "post-review")]', + '//*[contains(@class, "footer-review")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.bgr.in.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.bgr.in.php new file mode 100644 index 00000000..63ca069e --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.bgr.in.php @@ -0,0 +1,23 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.bgr.in/news/xiaomi-redmi-3-with-13-megapixel-camera-snapdragon-616-launched-price-specifications-and-features/', + 'body' => array( + '//div[@class="article-content"]', + ), + 'strip' => array( + '//*[@class="article-meta"]', + '//*[@class="contentAdsense300"]', + '//*[@class="iwpl-social-hide"]', + '//iframe[@class="iframeads"]', + '//*[@class="disqus_thread"]', + '//*[@class="outb-mobile OUTBRAIN"]', + '//*[@class="wdt_smart_alerts"]', + '//*[@class="footnote"]', + '//*[@id="gadget-widget"]', + '//header[@class="article-title entry-header"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.businessweek.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.businessweek.com.php new file mode 100644 index 00000000..0acc44ec --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.businessweek.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.businessweek.com/articles/2013-09-18/elon-musks-hyperloop-will-work-says-some-very-smart-software', + 'body' => array( + '//div[@id="lead_graphic"]', + '//div[@id="article_body"]', + ), + 'strip' => array( + '//*[contains(@class, "related_item")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.cnn.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.cnn.com.php new file mode 100644 index 00000000..31d03ed9 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.cnn.com.php @@ -0,0 +1,24 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.cnn.com/2013/08/31/world/meast/syria-civil-war/index.html?hpt=hp_t1', + 'body' => array( + '//div[@class="cnn_strycntntlft"]', + ), + 'strip' => array( + '//div[@class="cnn_stryshrwdgtbtm"]', + '//div[@class="cnn_strybtmcntnt"]', + '//div[@class="cnn_strylftcntnt"]', + '//div[contains(@class, "cnnGalleryContainer")]', + '//div[contains(@class, "cnn_strylftcexpbx")]', + '//div[contains(@class, "articleGalleryNavContainer")]', + '//div[contains(@class, "cnnArticleGalleryCaptionControl")]', + '//div[contains(@class, "cnnArticleGalleryNavPrevNextDisabled")]', + '//div[contains(@class, "cnnArticleGalleryNavPrevNext")]', + '//div[contains(@class, "cnn_html_media_title_new")]', + '//div[contains(@id, "disqus")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.developpez.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.developpez.com.php new file mode 100644 index 00000000..1535e437 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.developpez.com.php @@ -0,0 +1,21 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.developpez.com/actu/81757/Mozilla-annonce-la-disponibilite-de-Firefox-36-qui-passe-au-HTTP-2-et-permet-la-synchronisation-de-son-ecran-d-accueil/', + 'body' => array( + '//*[@itemprop="articleBody"]', + ), + 'strip' => array( + '//form', + '//div[@class="content"]/img', + '//a[last()]/following-sibling::*', + '//*[contains(@class,"actuTitle")]', + '//*[contains(@class,"date")]', + '//*[contains(@class,"inlineimg")]', + '//*[@id="signaler"]', + '//*[@id="signalerFrame"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.egscomics.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.egscomics.com.php new file mode 100644 index 00000000..263f0755 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.egscomics.com.php @@ -0,0 +1,12 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.egscomics.com/index.php?id=1690', + 'title' => '/html/head/title', + 'body' => array( + '//img[@id="comic"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.fakingnews.firstpost.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.fakingnews.firstpost.com.php new file mode 100644 index 00000000..c948c77b --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.fakingnews.firstpost.com.php @@ -0,0 +1,17 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.fakingnews.firstpost.com/2016/01/engineering-student-creates-record-in-a-decade-becomes-the-first-to-completely-exhaust-ball-pen-refill/', + 'body' => array( + '//div[@class="entry"]', + ), + 'strip' => array( + '//*[@class="socialshare_bar"]', + '//*[@class="authorbox"]', + '//*[@class="cf5_rps"]', + '//*[@class="60563 fb-comments fb-social-plugin"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.forbes.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.forbes.com.php new file mode 100644 index 00000000..fd16ed57 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.forbes.com.php @@ -0,0 +1,20 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.forbes.com/sites/andygreenberg/2013/09/05/follow-the-bitcoins-how-we-got-busted-buying-drugs-on-silk-roads-black-market/', + 'body' => array( + '//div[@id="leftRail"]/div[contains(@class, body)]', + ), + 'strip' => array( + '//aside', + '//div[contains(@class, "entity_block")]', + '//div[contains(@class, "vestpocket") and not contains(@class, "body")]', + '//div[contains(@style, "display")]', + '//div[contains(@id, "comment")]', + '//div[contains(@class, "widget")]', + '//div[contains(@class, "pagination")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.franceculture.fr.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.franceculture.fr.php new file mode 100644 index 00000000..f7ec0d8d --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.franceculture.fr.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.franceculture.fr/emission-culture-eco-la-finance-aime-toujours-la-france-2016-01-08', + 'body' => array( + '//div[@class="text-zone"]', + ), + 'strip' => array( + '//ul[@class="tags"]', + ), + ) + ) +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.futura-sciences.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.futura-sciences.com.php new file mode 100644 index 00000000..ea94a0fb --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.futura-sciences.com.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.futura-sciences.com/magazines/espace/infos/actu/d/astronautique-curiosity-franchi-succes-dune-dingo-gap-52289/#xtor=RSS-8', + 'body' => array( + '//div[contains(@class, "content fiche-")]', + ), + 'strip' => array( + '//h1', + '//*[contains(@class, "content-date")]', + '//*[contains(@class, "diaporama")]', + '//*[contains(@class, "slider")]', + '//*[contains(@class, "cartouche")]', + '//*[contains(@class, "noprint")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.geekculture.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.geekculture.com.php new file mode 100644 index 00000000..3d0b6c75 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.geekculture.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.geekculture.com/joyoftech/joyarchives/2180.html', + 'body' => array( + '//p[contains(@class,"Maintext")][2]/a/img[contains(@src,"joyimages")]', + ), + 'strip' => array(), + ), + ), +); + diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.howtogeek.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.howtogeek.com.php new file mode 100644 index 00000000..6879e767 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.howtogeek.com.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.howtogeek.com/235283/what-is-a-wireless-hard-drive-and-should-i-get-one/', + 'body' => array( + '//div[@class="thecontent"]', + ), + 'strip' => array( + '//*[@class="relatedside"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.lepoint.fr.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.lepoint.fr.php new file mode 100644 index 00000000..dcb7e484 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.lepoint.fr.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.lepoint.fr/c-est-arrive-aujourd-hui/19-septembre-1783-pour-la-premiere-fois-un-mouton-un-canard-et-un-coq-s-envoient-en-l-air-devant-louis-xvi-18-09-2012-1507704_494.php', + 'body' => array( + '//article', + ), + 'strip' => array( + '//*[contains(@class, "info_article")]', + '//*[contains(@class, "fildariane_titre")]', + '//*[contains(@class, "entete2_article")]', + '//*[contains(@class, "signature_article")]', + '//*[contains(@id, "share")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.lesnumeriques.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.lesnumeriques.com.php new file mode 100644 index 00000000..0137e209 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.lesnumeriques.com.php @@ -0,0 +1,25 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.lesnumeriques.com/blender/kitchenaid-diamond-5ksb1585-p27473/test.html', + 'body' => array( + '//*[@id="product-content"]', + '//*[@id="news-content"]', + '//*[@id="article-content"]', + ), + 'strip' => array( + '//form', + '//div[contains(@class, "price-v4"])', + '//div[contains(@class, "authors-and-date")]', + '//div[contains(@class, "mini-product")]', + '//div[@id="articles-related-authors"]', + '//div[@id="tags-socials"]', + '//div[@id="user-reviews"]', + '//div[@id="product-reviews"]', + '//div[@id="publication-breadcrumbs-and-date"]', + '//div[@id="publication-breadcrumbs-and-date"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.mac4ever.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.mac4ever.com.php new file mode 100644 index 00000000..60bc1bd4 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.mac4ever.com.php @@ -0,0 +1,13 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.mac4ever.com/actu/87392_video-quand-steve-jobs-et-bill-gates-jouaient-au-bachelor-avec-le-mac', + 'body' => array( + '//div[contains(@class, "news-news-content")]', + ), + 'strip' => array( + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.makeuseof.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.makeuseof.com.php new file mode 100644 index 00000000..a274564a --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.makeuseof.com.php @@ -0,0 +1,18 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.makeuseof.com/tag/having-problems-with-audio-in-windows-10-heres-a-likely-fix/', + 'body' => array( + '//div[@class="entry"]', + ), + 'strip' => array( + '//*[@class="new_sharebar"]', + '//*[@class="author"]', + '//*[@class="wdt_grouvi"]', + '//*[@class="wdt_smart_alerts"]', + '//*[@class="modal fade grouvi"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.monsieur-le-chien.fr.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.monsieur-le-chien.fr.php new file mode 100644 index 00000000..5f5e987b --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.monsieur-le-chien.fr.php @@ -0,0 +1,11 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.monsieur-le-chien.fr/index.php?planche=672', + 'body' => array( + '//img[starts-with(@src, "i/planches/")]', + ), + ) + ) +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.npr.org.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.npr.org.php new file mode 100644 index 00000000..ecc0213a --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.npr.org.php @@ -0,0 +1,28 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.npr.org/blogs/thesalt/2013/09/17/223345977/auto-brewery-syndrome-apparently-you-can-make-beer-in-your-gut', + 'body' => array( + '//article[contains(@class,"story")]', + ), + 'strip' => array( + '//div[@class="story-tools"]', + '//h3[@class="slug"]', + '//div[@class="storytitle"]', + '//div[@id="story-meta"]', + '//a[@id="mainContent"]', + '//div[@class="credit-caption"]', + '//div[@class="enlarge_html"]', + '//button', + '//div[contains(@id,"pullquote")]', + '//div[contains(@class,"internallink")]', + '//div[contains(@class,"video")]', + '//div[@class="simplenodate"]', + '//div[contains(@class,"share-")]', + '//div[@class="tags"]', + '//aside' + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.numerama.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.numerama.com.php new file mode 100644 index 00000000..fe4971c5 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.numerama.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.numerama.com/sciences/125959-recherches-ladn-recompensees-nobel-de-chimie.html', + 'body' => array( + '//article', + ), + 'strip' => array( + '//footer', + '//section[@class="related-article"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.oneindia.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.oneindia.com.php new file mode 100644 index 00000000..320c2147 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.oneindia.com.php @@ -0,0 +1,14 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.oneindia.com/india/b-luru-govt-likely-remove-word-eunuch-from-sec-36-a-karnataka-police-act-1981173.html', + 'body' => array( + '//div[@class="ecom-ad-content"]', + ), + 'strip' => array( + '//*[@id="view_cmtns"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.pseudo-sciences.org.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.pseudo-sciences.org.php new file mode 100644 index 00000000..9e467edf --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.pseudo-sciences.org.php @@ -0,0 +1,16 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.pseudo-sciences.org/spip.php?article2275', + 'body' => array( + '//div[@id="art_main"]', + ), + 'strip' => array( + '//div[@id="art_print"]', + '//div[@id="art_chapo"]', + '//img[@class="puce"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.sciencemag.org.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.sciencemag.org.php new file mode 100644 index 00000000..ae7a93ac --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.sciencemag.org.php @@ -0,0 +1,16 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.sciencemag.org/news/2016/01/could-bright-foamy-wak$', + 'body' => array( + '//div[@class="row--hero"]', + '//article[contains(@class,"primary")]', + ), + 'strip' => array( + '//header[@class="article__header"]', + '//footer[@class="article__foot"]', + ), + ), + ) +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.slate.fr.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.slate.fr.php new file mode 100644 index 00000000..8c8dc893 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.slate.fr.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.slate.fr/monde/77034/allemagne-2013-couacs-campagne', + 'body' => array( + '//div[@class="article_content"]', + ), + 'strip' => array( + '//*[@id="slate_associated_bn"]', + '//*[@id="ligatus-article"]', + '//*[@id="article_sidebar"]', + '//div[contains(@id, "reseaux")]', + '//*[contains(@class, "smart") or contains(@class, "article_tags") or contains(@class, "article_reactions")]', + '//*[contains(@class, "OUTBRAIN") or contains(@class, "related_item") or contains(@class, "share")]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.universfreebox.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.universfreebox.com.php new file mode 100644 index 00000000..0747d0fb --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.universfreebox.com.php @@ -0,0 +1,15 @@ + array( + '%.*%' => array( + 'test_url' => 'http://www.universfreebox.com/article/24305/4G-Bouygues-Telecom-lance-une-vente-flash-sur-son-forfait-Sensation-3Go', + 'body' => array( + '//div[@id="corps_corps"]', + ), + 'strip' => array( + '//*[@id="formulaire"]', + '//*[@id="commentaire"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.zeit.de.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.zeit.de.php new file mode 100644 index 00000000..316c2656 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.zeit.de.php @@ -0,0 +1,41 @@ + array( + '%^/zeit-magazin.*%' => array( + 'test_url' => 'http://www.zeit.de/zeit-magazin/2015/15/pegida-kathrin-oertel-lutz-bachmann', + 'body' => array( + '//article[@class="article"]', + ), + 'strip' => array( + '//header/div/h1', + '//header/div/div[@class="article__head__subtitle"]', + '//header/div/div[@class="article__column__author"]', + '//header/div/div[@class="article__column__author"]', + '//header/div/span[@class="article__head__meta-wrap"]', + '//form', + '//style', + '//div[contains(@class, "ad-tile")]', + '//div[@class="iqd-mobile-adplace"]', + '//div[@id="iq-artikelanker"]', + '//div[@id="js-social-services"]', + '//section[@id="js-comments"]', + '//aside', + ), + ), + '%.*%' => array( + 'test_url' => 'http://www.zeit.de/politik/ausland/2015-04/thessaloniki-krise-griechenland-yannis-boutaris/', + 'body' => array( + '//div[@class="article-body"]', + ), + 'strip' => array( + '//*[@class="articleheader"]', + '//*[@class="excerpt"]', + '//div[contains(@class, "ad")]', + '//div[@itemprop="video"]', + '//*[@class="articlemeta"]', + '//*[@class="articlemeta-clear"]', + '//*[@class="zol_inarticletools"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/xkcd.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/xkcd.com.php new file mode 100644 index 00000000..84957268 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/xkcd.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%alt="(.+)" */>%' => '/>
$1', + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ymatuhin.ru.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ymatuhin.ru.php new file mode 100644 index 00000000..9fd83f18 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ymatuhin.ru.php @@ -0,0 +1,21 @@ + array( + '%.*%' => array( + 'test_url' => 'https://ymatuhin.ru/tools/git-default-editor/', + 'body' => array( + '//section', + ), + 'strip' => array( + "//script", + "//style", + "//h1", + "//time", + "//aside", + "/html/body/section/ul", + "//amp-iframe", + "/html/body/section/h4" + ), + ) + ) +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/zarojel.hu.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/zarojel.hu.php new file mode 100644 index 00000000..36d3bdf7 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/zarojel.hu.php @@ -0,0 +1,19 @@ + array( + '%.*%' => array( + 'test_url' => 'https://zarojel.hu/meg-egyszer-a-foldi-ugyrol-is/', + 'body' => array( + '//div[@class="entry-category"]/h1', + '//div[@class="entry-content"]/div[@class="vc_row wpb_row vc_row-fluid"]' + ), + 'strip' => array( + '//ins[@class="adsbygoogle"]', + '//script', + '//figcaption', + '//p[contains(text(),"Kapcsolódó")]', + '//div[@class="wpb_wrapper"]/p[@class="entry-title"]' + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/zdnet.com.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/zdnet.com.php new file mode 100644 index 00000000..79b35ddb --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/zdnet.com.php @@ -0,0 +1,23 @@ + array( + '%.*%' => array( + 'test_url' => 'http://zdnet.com.feedsportal.com/c/35462/f/675637/s/4a33c93e/sc/11/l/0L0Szdnet0N0Carticle0Cchina0Eus0Eagree0Eon0Ecybercrime0Ecooperation0Eamid0Econtinued0Etension0C0Tftag0FRSSbaffb68/story01.htm', + 'body' => array( + '//p[@class="summary"]', + '//div[contains(@class,"storyBody")]', + ), + 'strip' => array( + '//*[contains(@class,"ad-")]', + '//p/span', + '//script', + '//p[@class="summary"]', + '//div[contains(@class,"relatedContent")]', + '//div[contains(@class,"loader")]', + '//p[@class="photoDetails"]', + '//div[@class="thumbnailSlider"]', + '//div[@class="shortcodeGalleryWrapper"]', + ), + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/zoom.hu.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/zoom.hu.php new file mode 100644 index 00000000..3e38781a --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/zoom.hu.php @@ -0,0 +1,17 @@ + array( + '%.*%' => array( + 'test_url' => 'https://zoom.hu/2017/10/20/mar-nem-nyomoznak-a-vegrehajtok-botranyai-miatt', + 'body' => array( + '//div[@class="title-wrapper"]/h1', + '//div[@class="entry-excerpt"]', + '//div[@class="thumbnail-wrapper"]', + '//div[@id="entry-content-id"]' + ), + 'strip' => array( + '//div[@class="place first normal"]' + ) + ), + ), +); diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/CandidateParser.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/CandidateParser.php new file mode 100644 index 00000000..0f74b3dd --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/CandidateParser.php @@ -0,0 +1,281 @@ +dom = XmlParser::getHtmlDocument(''.$html); + $this->xpath = new DOMXPath($this->dom); + } + + /** + * Get the relevant content with the list of potential attributes. + * + * @return string + */ + public function execute() + { + $content = $this->findContentWithCandidates(); + + if (strlen($content) < 200) { + $content = $this->findContentWithArticle(); + } + + if (strlen($content) < 50) { + $content = $this->findContentWithBody(); + } + + return $this->stripGarbage($content); + } + + /** + * Find content based on the list of tag candidates. + * + * @return string + */ + public function findContentWithCandidates() + { + foreach ($this->candidatesAttributes as $candidate) { + Logger::setMessage(get_called_class().': Try this candidate: "'.$candidate.'"'); + + $nodes = $this->xpath->query('//*[(contains(@class, "'.$candidate.'") or @id="'.$candidate.'") and not (contains(@class, "nav") or contains(@class, "page"))]'); + + if ($nodes !== false && $nodes->length > 0) { + Logger::setMessage(get_called_class().': Find candidate "'.$candidate.'"'); + + return $this->dom->saveXML($nodes->item(0)); + } + } + + return ''; + } + + /** + * Find
tag. + * + * @return string + */ + public function findContentWithArticle() + { + $nodes = $this->xpath->query('//article'); + + if ($nodes !== false && $nodes->length > 0) { + Logger::setMessage(get_called_class().': Find
tag'); + + return $this->dom->saveXML($nodes->item(0)); + } + + return ''; + } + + /** + * Find tag. + * + * @return string + */ + public function findContentWithBody() + { + $nodes = $this->xpath->query('//body'); + + if ($nodes !== false && $nodes->length > 0) { + Logger::setMessage(get_called_class().' Find '); + + return $this->dom->saveXML($nodes->item(0)); + } + + return ''; + } + + /** + * Strip useless tags. + * + * @param string $content + * @return string + */ + public function stripGarbage($content) + { + $dom = XmlParser::getDomDocument($content); + + if ($dom !== false) { + $xpath = new DOMXPath($dom); + + $this->stripTags($xpath); + $this->stripAttributes($dom, $xpath); + + $content = $dom->saveXML($dom->documentElement); + } + + return $content; + } + + /** + * Remove blacklisted tags. + * + * @param DOMXPath $xpath + */ + public function stripTags(DOMXPath $xpath) + { + foreach ($this->stripTags as $tag) { + $nodes = $xpath->query('//'.$tag); + + if ($nodes !== false && $nodes->length > 0) { + Logger::setMessage(get_called_class().': Strip tag: "'.$tag.'"'); + + foreach ($nodes as $node) { + $node->parentNode->removeChild($node); + } + } + } + } + + /** + * Remove blacklisted attributes. + * + * @param DomDocument $dom + * @param DOMXPath $xpath + */ + public function stripAttributes(DomDocument $dom, DOMXPath $xpath) + { + foreach ($this->stripAttributes as $attribute) { + $nodes = $xpath->query('//*[contains(@class, "'.$attribute.'") or contains(@id, "'.$attribute.'")]'); + + if ($nodes !== false && $nodes->length > 0) { + Logger::setMessage(get_called_class().': Strip attribute: "'.$attribute.'"'); + + foreach ($nodes as $node) { + if ($this->shouldRemove($dom, $node)) { + $node->parentNode->removeChild($node); + } + } + } + } + } + + /** + * Find link for next page of the article. + * + * @return string + */ + public function findNextLink() + { + return null; + } + + /** + * Return false if the node should not be removed. + * + * @param DomDocument $dom + * @param \DomNode $node + * @return bool + */ + public function shouldRemove(DomDocument $dom, $node) + { + $document_length = strlen($dom->textContent); + $node_length = strlen($node->textContent); + + if ($document_length === 0) { + return true; + } + + $ratio = $node_length * 100 / $document_length; + + if ($ratio >= 90) { + Logger::setMessage(get_called_class().': Should not remove this node ('.$node->nodeName.') ratio: '.$ratio.'%'); + + return false; + } + + return true; + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/ParserInterface.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/ParserInterface.php new file mode 100644 index 00000000..3ded4b1c --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/ParserInterface.php @@ -0,0 +1,20 @@ +getRulesFileList($hostname); + + foreach ($this->getRulesFolders() as $folder) { + $rule = $this->loadRuleFile($folder, $files); + + if (!empty($rule)) { + return $rule; + } + } + } + + return array(); + } + + /** + * Get the list of possible rules file names for a given hostname. + * + * @param string $hostname Hostname + * @return array + */ + public function getRulesFileList($hostname) + { + $files = array($hostname); // subdomain.domain.tld + $parts = explode('.', $hostname); + $len = count($parts); + + if ($len > 2) { + $subdomain = array_shift($parts); + $files[] = implode('.', $parts); // domain.tld + $files[] = '.'.implode('.', $parts); // .domain.tld + $files[] = $subdomain; // subdomain + } elseif ($len === 2) { + $files[] = '.'.implode('.', $parts); // .domain.tld + $files[] = $parts[0]; // domain + } + + return $files; + } + + /** + * Load a rule file from the defined folder. + * + * @param string $folder Rule directory + * @param array $files List of possible file names + * @return array + */ + public function loadRuleFile($folder, array $files) + { + foreach ($files as $file) { + $filename = $folder.'/'.$file.'.php'; + if (file_exists($filename)) { + Logger::setMessage(get_called_class().' Load rule: '.$file); + + return include $filename; + } + } + + return array(); + } + + /** + * Get the list of folders that contains rules. + * + * @return array + */ + public function getRulesFolders() + { + $folders = array(); + + if ($this->config !== null && $this->config->getGrabberRulesFolder() !== null) { + $folders[] = $this->config->getGrabberRulesFolder(); + } + + $folders[] = __DIR__ . '/../Rules'; + + return $folders; + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/RuleParser.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/RuleParser.php new file mode 100644 index 00000000..9beb59c1 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/RuleParser.php @@ -0,0 +1,102 @@ +rules = $rules; + $this->dom = XmlParser::getHtmlDocument(''.$html); + $this->xpath = new DOMXPath($this->dom); + } + + /** + * Get the relevant content with predefined rules. + * + * @return string + */ + public function execute() + { + $this->stripTags(); + + return $this->findContent(); + } + + /** + * Remove HTML tags. + */ + public function stripTags() + { + if (isset($this->rules['strip']) && is_array($this->rules['strip'])) { + foreach ($this->rules['strip'] as $pattern) { + $nodes = $this->xpath->query($pattern); + + if ($nodes !== false && $nodes->length > 0) { + foreach ($nodes as $node) { + $node->parentNode->removeChild($node); + } + } + } + } + } + + /** + * Fetch content based on Xpath rules. + */ + public function findContent() + { + $content = ''; + if (isset($this->rules['body']) && is_array($this->rules['body'])) { + foreach ($this->rules['body'] as $pattern) { + $nodes = $this->xpath->query($pattern); + + if ($nodes !== false && $nodes->length > 0) { + foreach ($nodes as $node) { + $content .= $this->dom->saveXML($node); + } + } + } + } + + return $content; + } + + /** + * Fetch next link based on Xpath rules. + * + * @return string + */ + public function findNextLink() + { + if (isset($this->rules['next_page']) && is_array($this->rules['next_page'])) { + foreach ($this->rules['next_page'] as $pattern) { + $nodes = $this->xpath->query($pattern); + if ($nodes !== false && $nodes->length > 0) { + foreach ($nodes as $node) { + return $node->getAttribute('href'); + } + } + } + } + return null; + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/Scraper.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/Scraper.php new file mode 100644 index 00000000..29383b21 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/Scraper.php @@ -0,0 +1,282 @@ +enableCandidateParser = false; + return $this; + } + + /** + * Get encoding. + * + * @return string + */ + public function getEncoding() + { + return $this->encoding; + } + + /** + * Set encoding. + * + * @param string $encoding + * + * @return Scraper + */ + public function setEncoding($encoding) + { + $this->encoding = $encoding; + + return $this; + } + + /** + * Get URL to download. + * + * @return string + */ + public function getUrl() + { + return $this->url; + } + + /** + * Set URL to download. + * + * @param string $url URL + * + * @return Scraper + */ + public function setUrl($url) + { + $this->url = $url; + + return $this; + } + + /** + * Return true if the scraper found relevant content. + * + * @return bool + */ + public function hasRelevantContent() + { + return !empty($this->content); + } + + /** + * Get relevant content. + * + * @return string + */ + public function getRelevantContent() + { + return $this->content; + } + + /** + * Get raw content (unfiltered). + * + * @return string + */ + public function getRawContent() + { + return $this->html; + } + + /** + * Set raw content (unfiltered). + * + * @param string $html + * + * @return Scraper + */ + public function setRawContent($html) + { + $this->html = $html; + + return $this; + } + + /** + * Get filtered relevant content. + * + * @return string + */ + public function getFilteredContent() + { + $filter = Filter::html($this->content, $this->url); + $filter->setConfig($this->config); + + return $filter->execute(); + } + + /** + * Download the HTML content. + * + * @return bool + */ + public function download() + { + if (!empty($this->url)) { + + // Clear everything + $this->html = ''; + $this->content = ''; + $this->encoding = ''; + + try { + $client = Client::getInstance(); + $client->setConfig($this->config); + $client->setTimeout($this->config->getGrabberTimeout()); + $client->setUserAgent($this->config->getGrabberUserAgent()); + $client->execute($this->url); + + $this->url = $client->getUrl(); + $this->html = $client->getContent(); + $this->encoding = $client->getEncoding(); + + return true; + } catch (ClientException $e) { + Logger::setMessage(get_called_class().': '.$e->getMessage()); + } + } + + return false; + } + + /** + * Execute the scraper. + * + * @param string $pageContent + * @param int $recursionDepth + */ + public function execute($pageContent = '', $recursionDepth = 0) + { + $this->html = ''; + $this->encoding = ''; + $this->content = ''; + $this->download(); + $this->prepareHtml(); + + $parser = $this->getParser(); + + if ($parser !== null) { + $maxRecursions = $this->config->getMaxRecursions(); + if(!isset($maxRecursions)){ + $maxRecursions = 25; + } + $pageContent .= $parser->execute(); + // check if there is a link to next page and recursively get content (max 25 pages) + if((($nextLink = $parser->findNextLink()) !== null) && $recursionDepth < $maxRecursions){ + $nextLink = Url::resolve($nextLink,$this->url); + $this->setUrl($nextLink); + $this->execute($pageContent,$recursionDepth+1); + } + else{ + $this->content = $pageContent; + } + Logger::setMessage(get_called_class().': Content length: '.strlen($this->content).' bytes'); + } + } + + /** + * Get the parser. + * + * @return ParserInterface + */ + public function getParser() + { + $ruleLoader = new RuleLoader($this->config); + $rules = $ruleLoader->getRules($this->url); + + if (!empty($rules['grabber'])) { + Logger::setMessage(get_called_class().': Parse content with rules'); + + foreach ($rules['grabber'] as $pattern => $rule) { + $url = new Url($this->url); + $sub_url = $url->getFullPath(); + + if (preg_match($pattern, $sub_url)) { + Logger::setMessage(get_called_class().': Matched url '.$sub_url); + return new RuleParser($this->html, $rule); + } + } + } elseif ($this->enableCandidateParser) { + Logger::setMessage(get_called_class().': Parse content with candidates'); + } + + return new CandidateParser($this->html); + } + + /** + * Normalize encoding and strip head tag. + */ + public function prepareHtml() + { + $html_encoding = XmlParser::getEncodingFromMetaTag($this->html); + + $this->html = Encoding::convert($this->html, $html_encoding ?: $this->encoding); + $this->html = Filter::stripHeadTags($this->html); + + Logger::setMessage(get_called_class().': HTTP Encoding "'.$this->encoding.'" ; HTML Encoding "'.$html_encoding.'"'); + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/Subscription.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/Subscription.php new file mode 100644 index 00000000..12eccfd5 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/Subscription.php @@ -0,0 +1,175 @@ +title = $title; + return $this; + } + + /** + * Get title + * + * @access public + * @return string + */ + public function getTitle() + { + return $this->title; + } + + /** + * Set feed URL + * + * @access public + * @param string $feedUrl + * @return Subscription + */ + public function setFeedUrl($feedUrl) + { + $this->feedUrl = $feedUrl; + return $this; + } + + /** + * Get feed URL + * + * @access public + * @return string + */ + public function getFeedUrl() + { + return $this->feedUrl; + } + + /** + * Set site URL + * + * @access public + * @param string $siteUrl + * @return Subscription + */ + public function setSiteUrl($siteUrl) + { + $this->siteUrl = $siteUrl; + return $this; + } + + /** + * Get site URL + * + * @access public + * @return string + */ + public function getSiteUrl() + { + return $this->siteUrl; + } + + /** + * Set category + * + * @access public + * @param string $category + * @return Subscription + */ + public function setCategory($category) + { + $this->category = $category; + return $this; + } + + /** + * Get category + * + * @access public + * @return string + */ + public function getCategory() + { + return $this->category; + } + + /** + * Set description + * + * @access public + * @param string $description + * @return Subscription + */ + public function setDescription($description) + { + $this->description = $description; + return $this; + } + + /** + * Get description + * + * @access public + * @return string + */ + public function getDescription() + { + return $this->description; + } + + /** + * Set type + * + * @access public + * @param string $type + * @return Subscription + */ + public function setType($type) + { + $this->type = $type; + return $this; + } + + /** + * Get type + * + * @access public + * @return string + */ + public function getType() + { + return $this->type; + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionList.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionList.php new file mode 100644 index 00000000..b173f89b --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionList.php @@ -0,0 +1,75 @@ +title = $title; + return $this; + } + + /** + * Get title + * + * @access public + * @return string + */ + public function getTitle() + { + return $this->title; + } + + /** + * Add subscription + * + * @access public + * @param Subscription $subscription + * @return SubscriptionList + */ + public function addSubscription(Subscription $subscription) + { + $this->subscriptions[] = $subscription; + return $this; + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionListBuilder.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionListBuilder.php new file mode 100644 index 00000000..838e4cb5 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionListBuilder.php @@ -0,0 +1,204 @@ +subscriptionList = $subscriptionList; + } + + /** + * Get object instance + * + * @static + * @access public + * @param SubscriptionList $subscriptionList + * @return SubscriptionListBuilder + */ + public static function create(SubscriptionList $subscriptionList) + { + return new static($subscriptionList); + } + + /** + * Build OPML feed + * + * @access public + * @param string $filename + * @return string + */ + public function build($filename = '') + { + $this->document = new DomDocument('1.0', 'UTF-8'); + $this->document->formatOutput = true; + + $opmlElement = $this->document->createElement('opml'); + $opmlElement->setAttribute('version', '1.0'); + + $headElement = $this->document->createElement('head'); + + if ($this->subscriptionList->getTitle() !== '') { + $titleElement = $this->document->createElement('title'); + $titleElement->appendChild($this->document->createTextNode($this->subscriptionList->getTitle())); + $headElement->appendChild($titleElement); + } + + $opmlElement->appendChild($headElement); + $opmlElement->appendChild($this->buildBody()); + $this->document->appendChild($opmlElement); + + if ($filename !== '') { + $this->document->save($filename); + return ''; + } + + return $this->document->saveXML(); + } + + /** + * Return true if the list has categories + * + * @access public + * @return bool + */ + public function hasCategories() + { + foreach ($this->subscriptionList->subscriptions as $subscription) { + if ($subscription->getCategory() !== '') { + return true; + } + } + + return false; + } + + /** + * Build OPML body + * + * @access protected + * @return DOMElement + */ + protected function buildBody() + { + $bodyElement = $this->document->createElement('body'); + + if ($this->hasCategories()) { + $this->buildCategories($bodyElement); + return $bodyElement; + } + + foreach ($this->subscriptionList->subscriptions as $subscription) { + $bodyElement->appendChild($this->buildSubscription($subscription)); + } + + return $bodyElement; + } + + /** + * Build categories section + * + * @access protected + * @param DOMElement $bodyElement + */ + protected function buildCategories(DOMElement $bodyElement) + { + $categories = $this->groupByCategories(); + + foreach ($categories as $category => $subscriptions) { + $bodyElement->appendChild($this->buildCategory($category, $subscriptions)); + } + } + + /** + * Build category tag + * + * @access protected + * @param string $category + * @param array $subscriptions + * @return DOMElement + */ + protected function buildCategory($category, array $subscriptions) + { + $outlineElement = $this->document->createElement('outline'); + $outlineElement->setAttribute('text', $category); + + foreach ($subscriptions as $subscription) { + $outlineElement->appendChild($this->buildSubscription($subscription)); + } + + return $outlineElement; + } + + /** + * Build subscription entry + * + * @access public + * @param Subscription $subscription + * @return DOMElement + */ + protected function buildSubscription(Subscription $subscription) + { + $outlineElement = $this->document->createElement('outline'); + $outlineElement->setAttribute('type', $subscription->getType() ?: 'rss'); + $outlineElement->setAttribute('text', $subscription->getTitle() ?: $subscription->getFeedUrl()); + $outlineElement->setAttribute('xmlUrl', $subscription->getFeedUrl()); + + if ($subscription->getTitle() !== '') { + $outlineElement->setAttribute('title', $subscription->getTitle()); + } + + if ($subscription->getDescription() !== '') { + $outlineElement->setAttribute('description', $subscription->getDescription()); + } + + if ($subscription->getSiteUrl() !== '') { + $outlineElement->setAttribute('htmlUrl', $subscription->getSiteUrl()); + } + + return $outlineElement; + } + + /** + * Group subscriptions by category + * + * @access private + * @return array + */ + private function groupByCategories() + { + $categories = array(); + + foreach ($this->subscriptionList->subscriptions as $subscription) { + $categories[$subscription->getCategory()][] = $subscription; + } + + return $categories; + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionListParser.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionListParser.php new file mode 100644 index 00000000..9085588c --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionListParser.php @@ -0,0 +1,100 @@ +subscriptionList = new SubscriptionList(); + $this->data = trim($data); + } + + /** + * Get object instance + * + * @static + * @access public + * @param string $data + * @return SubscriptionListParser + */ + public static function create($data) + { + return new static($data); + } + + /** + * Parse a subscription list entry + * + * @access public + * @throws MalformedXmlException + * @return SubscriptionList + */ + public function parse() + { + $xml = XmlParser::getSimpleXml($this->data); + + if (! $xml || !isset($xml->head) || !isset($xml->body)) { + throw new MalformedXmlException('Unable to parse OPML file: invalid XML'); + } + + $this->parseTitle($xml->head); + $this->parseEntries($xml->body); + + return $this->subscriptionList; + } + + /** + * Parse title + * + * @access protected + * @param SimpleXMLElement $xml + */ + protected function parseTitle(SimpleXMLElement $xml) + { + $this->subscriptionList->setTitle((string) $xml->title); + } + + /** + * Parse entries + * + * @access protected + * @param SimpleXMLElement $body + */ + private function parseEntries(SimpleXMLElement $body) + { + foreach ($body->outline as $outlineElement) { + if (isset($outlineElement->outline)) { + $this->parseEntries($outlineElement); + } else { + $this->subscriptionList->subscriptions[] = SubscriptionParser::create($body, $outlineElement)->parse(); + } + } + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionParser.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionParser.php new file mode 100644 index 00000000..caff07c2 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionParser.php @@ -0,0 +1,142 @@ +parentElement = $parentElement; + $this->outlineElement = $outlineElement; + $this->subscription = new Subscription(); + } + + /** + * Get object instance + * + * @static + * @access public + * @param SimpleXMLElement $parentElement + * @param SimpleXMLElement $outlineElement + * @return SubscriptionParser + */ + public static function create(SimpleXMLElement $parentElement, SimpleXMLElement $outlineElement) + { + return new static($parentElement, $outlineElement); + } + + /** + * Parse subscription entry + * + * @access public + * @return Subscription + */ + public function parse() + { + $this->subscription->setCategory($this->findCategory()); + $this->subscription->setTitle($this->findTitle()); + $this->subscription->setFeedUrl($this->findFeedUrl()); + $this->subscription->setSiteUrl($this->findSiteUrl()); + $this->subscription->setType($this->findType()); + $this->subscription->setDescription($this->findDescription()); + + return $this->subscription; + } + + /** + * Find category. + * + * @access protected + * @return string + */ + protected function findCategory() + { + return isset($this->parentElement['text']) ? (string) $this->parentElement['text'] : ''; + } + + /** + * Find title. + * + * @access protected + * @return string + */ + protected function findTitle() + { + return isset($this->outlineElement['title']) ? (string) $this->outlineElement['title'] : (string) $this->outlineElement['text']; + } + + /** + * Find feed url. + * + * @access protected + * @return string + */ + protected function findFeedUrl() + { + return (string) $this->outlineElement['xmlUrl']; + } + + /** + * Find site url. + * + * @access protected + * @return string + */ + protected function findSiteUrl() + { + return isset($this->outlineElement['htmlUrl']) ? (string) $this->outlineElement['htmlUrl'] : $this->findFeedUrl(); + } + + /** + * Find type. + * + * @access protected + * @return string + */ + protected function findType() + { + return isset($this->outlineElement['version']) ? (string) $this->outlineElement['version'] : + isset($this->outlineElement['type']) ? (string) $this->outlineElement['type'] : 'rss'; + } + + /** + * Find description. + * + * @access protected + * @return string + */ + protected function findDescription() + { + return isset($this->outlineElement['description']) ? (string) $this->outlineElement['description'] : $this->findTitle(); + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/AtomFeedBuilder.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/AtomFeedBuilder.php new file mode 100644 index 00000000..34f37800 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/AtomFeedBuilder.php @@ -0,0 +1,65 @@ +helper = new AtomHelper($this->getDocument()); + + $this->feedElement = $this->getDocument()->createElement('feed'); + $this->feedElement->setAttributeNodeNS(new DomAttr('xmlns', 'http://www.w3.org/2005/Atom')); + + $generator = $this->getDocument()->createElement('generator', 'PicoFeed'); + $generator->setAttribute('uri', 'https://github.com/miniflux/picoFeed'); + $this->feedElement->appendChild($generator); + + $this->helper + ->buildTitle($this->feedElement, $this->feedTitle) + ->buildId($this->feedElement, $this->feedUrl) + ->buildDate($this->feedElement, $this->feedDate) + ->buildLink($this->feedElement, $this->siteUrl) + ->buildLink($this->feedElement, $this->feedUrl, 'self', 'application/atom+xml') + ->buildAuthor($this->feedElement, $this->authorName, $this->authorEmail, $this->authorUrl) + ; + + foreach ($this->items as $item) { + $this->feedElement->appendChild($item->build()); + } + + $this->getDocument()->appendChild($this->feedElement); + + if ($filename !== '') { + $this->getDocument()->save($filename); + } + + return $this->getDocument()->saveXML(); + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/AtomHelper.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/AtomHelper.php new file mode 100644 index 00000000..def6b0b9 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/AtomHelper.php @@ -0,0 +1,139 @@ +document = $document; + } + + /** + * Build node + * + * @access public + * @param DOMElement $element + * @param string $tag + * @param string $value + * @return AtomHelper + */ + public function buildNode(DOMElement $element, $tag, $value) + { + $node = $this->document->createElement($tag); + $node->appendChild($this->document->createTextNode($value)); + $element->appendChild($node); + return $this; + } + + /** + * Build title + * + * @access public + * @param DOMElement $element + * @param string $title + * @return AtomHelper + */ + public function buildTitle(DOMElement $element, $title) + { + return $this->buildNode($element, 'title', $title); + } + + /** + * Build id + * + * @access public + * @param DOMElement $element + * @param string $id + * @return AtomHelper + */ + public function buildId(DOMElement $element, $id) + { + return $this->buildNode($element, 'id', $id); + } + + /** + * Build date element + * + * @access public + * @param DOMElement $element + * @param DateTime $date + * @param string $type + * @return AtomHelper + */ + public function buildDate(DOMElement $element, DateTime $date, $type = 'updated') + { + return $this->buildNode($element, $type, $date->format(DateTime::ATOM)); + } + + /** + * Build link element + * + * @access public + * @param DOMElement $element + * @param string $url + * @param string $rel + * @param string $type + * @return AtomHelper + */ + public function buildLink(DOMElement $element, $url, $rel = 'alternate', $type = 'text/html') + { + $node = $this->document->createElement('link'); + $node->setAttribute('rel', $rel); + $node->setAttribute('type', $type); + $node->setAttribute('href', $url); + $element->appendChild($node); + + return $this; + } + + /** + * Build author element + * + * @access public + * @param DOMElement $element + * @param string $authorName + * @param string $authorEmail + * @param string $authorUrl + * @return AtomHelper + */ + public function buildAuthor(DOMElement $element, $authorName, $authorEmail, $authorUrl) + { + if (!empty($authorName)) { + $author = $this->document->createElement('author'); + $this->buildNode($author, 'name', $authorName); + + if (!empty($authorEmail)) { + $this->buildNode($author, 'email', $authorEmail); + } + + if (!empty($authorUrl)) { + $this->buildNode($author, 'uri', $authorUrl); + } + + $element->appendChild($author); + } + + return $this; + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/AtomItemBuilder.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/AtomItemBuilder.php new file mode 100644 index 00000000..dfdfe68d --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/AtomItemBuilder.php @@ -0,0 +1,63 @@ +itemElement = $this->feedBuilder->getDocument()->createElement('entry'); + $this->helper = new AtomHelper($this->feedBuilder->getDocument()); + + if (!empty($this->itemId)) { + $this->helper->buildId($this->itemElement, $this->itemId); + } else { + $this->helper->buildId($this->itemElement, $this->itemUrl); + } + + $this->helper + ->buildTitle($this->itemElement, $this->itemTitle) + ->buildLink($this->itemElement, $this->itemUrl) + ->buildDate($this->itemElement, $this->itemUpdatedDate, 'updated') + ->buildDate($this->itemElement, $this->itemPublishedDate, 'published') + ->buildAuthor($this->itemElement, $this->authorName, $this->authorEmail, $this->authorUrl) + ; + + if (!empty($this->itemSummary)) { + $this->helper->buildNode($this->itemElement, 'summary', $this->itemSummary); + } + + if (!empty($this->itemContent)) { + $node = $this->feedBuilder->getDocument()->createElement('content'); + $node->setAttribute('type', 'html'); + $node->appendChild($this->feedBuilder->getDocument()->createCDATASection($this->itemContent)); + $this->itemElement->appendChild($node); + } + + return $this->itemElement; + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/FeedBuilder.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/FeedBuilder.php new file mode 100644 index 00000000..cf9d024e --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/FeedBuilder.php @@ -0,0 +1,185 @@ +document = new DomDocument('1.0', 'UTF-8'); + $this->document->formatOutput = true; + } + + /** + * Get new object instance + * + * @access public + * @return static + */ + public static function create() + { + return new static(); + } + + /** + * Add feed title + * + * @access public + * @param string $title + * @return $this + */ + public function withTitle($title) + { + $this->feedTitle = $title; + return $this; + } + + /** + * Add feed url + * + * @access public + * @param string $url + * @return $this + */ + public function withFeedUrl($url) + { + $this->feedUrl = $url; + return $this; + } + + /** + * Add website url + * + * @access public + * @param string $url + * @return $this + */ + public function withSiteUrl($url) + { + $this->siteUrl = $url; + return $this; + } + + /** + * Add feed date + * + * @access public + * @param DateTime $date + * @return $this + */ + public function withDate(DateTime $date) + { + $this->feedDate = $date; + return $this; + } + + /** + * Add feed author + * + * @access public + * @param string $name + * @param string $email + * @param string $url + * @return $this + */ + public function withAuthor($name, $email = '', $url ='') + { + $this->authorName = $name; + $this->authorEmail = $email; + $this->authorUrl = $url; + return $this; + } + + /** + * Add feed item + * + * @access public + * @param ItemBuilder $item + * @return $this + */ + public function withItem(ItemBuilder $item) + { + $this->items[] = $item; + return $this; + } + + /** + * Get DOM document + * + * @access public + * @return DOMDocument + */ + public function getDocument() + { + return $this->document; + } + + /** + * Build feed + * + * @abstract + * @access public + * @param string $filename + * @return string + */ + abstract public function build($filename = ''); +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/ItemBuilder.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/ItemBuilder.php new file mode 100644 index 00000000..86985bc7 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/ItemBuilder.php @@ -0,0 +1,209 @@ +feedBuilder = $feedBuilder; + } + + /** + * Get new object instance + * + * @access public + * @param FeedBuilder $feedBuilder + * @return static + */ + public static function create(FeedBuilder $feedBuilder) + { + return new static($feedBuilder); + } + + /** + * Add item title + * + * @access public + * @param string $title + * @return $this + */ + public function withTitle($title) + { + $this->itemTitle = $title; + return $this; + } + + /** + * Add item id + * + * @access public + * @param string $id + * @return $this + */ + public function withId($id) + { + $this->itemId = $id; + return $this; + } + + /** + * Add item url + * + * @access public + * @param string $url + * @return $this + */ + public function withUrl($url) + { + $this->itemUrl = $url; + return $this; + } + + /** + * Add item summary + * + * @access public + * @param string $summary + * @return $this + */ + public function withSummary($summary) + { + $this->itemSummary = $summary; + return $this; + } + + /** + * Add item content + * + * @access public + * @param string $content + * @return $this + */ + public function withContent($content) + { + $this->itemContent = $content; + return $this; + } + + /** + * Add item updated date + * + * @access public + * @param DateTime $date + * @return $this + */ + public function withUpdatedDate(DateTime $date) + { + $this->itemUpdatedDate = $date; + return $this; + } + + /** + * Add item published date + * + * @access public + * @param DateTime $date + * @return $this + */ + public function withPublishedDate(DateTime $date) + { + $this->itemPublishedDate = $date; + return $this; + } + + /** + * Add item author + * + * @access public + * @param string $name + * @param string $email + * @param string $url + * @return $this + */ + public function withAuthor($name, $email = '', $url ='') + { + $this->authorName = $name; + $this->authorEmail = $email; + $this->authorUrl = $url; + return $this; + } + + /** + * Build item + * + * @abstract + * @access public + * @return DOMElement + */ + abstract public function build(); +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/Rss20FeedBuilder.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/Rss20FeedBuilder.php new file mode 100644 index 00000000..bc3f5135 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/Rss20FeedBuilder.php @@ -0,0 +1,76 @@ +helper = new Rss20Helper($this->getDocument()); + + $this->rssElement = $this->getDocument()->createElement('rss'); + $this->rssElement->setAttribute('version', '2.0'); + $this->rssElement->setAttributeNodeNS(new DomAttr('xmlns:content', 'http://purl.org/rss/1.0/modules/content/')); + $this->rssElement->setAttributeNodeNS(new DomAttr('xmlns:atom', 'http://www.w3.org/2005/Atom')); + + $this->channelElement = $this->getDocument()->createElement('channel'); + $this->helper + ->buildNode($this->channelElement, 'generator', 'PicoFeed (https://github.com/miniflux/picoFeed)') + ->buildTitle($this->channelElement, $this->feedTitle) + ->buildNode($this->channelElement, 'description', $this->feedTitle) + ->buildDate($this->channelElement, $this->feedDate) + ->buildAuthor($this->channelElement, 'webMaster', $this->authorName, $this->authorEmail) + ->buildLink($this->channelElement, $this->siteUrl) + ; + + $link = $this->getDocument()->createElement('atom:link'); + $link->setAttribute('href', $this->feedUrl); + $link->setAttribute('rel', 'self'); + $link->setAttribute('type', 'application/rss+xml'); + $this->channelElement->appendChild($link); + + foreach ($this->items as $item) { + $this->channelElement->appendChild($item->build()); + } + + $this->rssElement->appendChild($this->channelElement); + $this->getDocument()->appendChild($this->rssElement); + + if ($filename !== '') { + $this->getDocument()->save($filename); + } + + return $this->getDocument()->saveXML(); + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/Rss20Helper.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/Rss20Helper.php new file mode 100644 index 00000000..72a19e56 --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/Rss20Helper.php @@ -0,0 +1,115 @@ +document = $document; + } + + /** + * Build node + * + * @access public + * @param DOMElement $element + * @param string $tag + * @param string $value + * @return $this + */ + public function buildNode(DOMElement $element, $tag, $value) + { + $node = $this->document->createElement($tag); + $node->appendChild($this->document->createTextNode($value)); + $element->appendChild($node); + return $this; + } + + /** + * Build title + * + * @access public + * @param DOMElement $element + * @param string $title + * @return $this + */ + public function buildTitle(DOMElement $element, $title) + { + return $this->buildNode($element, 'title', $title); + } + + /** + * Build date element + * + * @access public + * @param DOMElement $element + * @param DateTime $date + * @param string $type + * @return $this + */ + public function buildDate(DOMElement $element, DateTime $date, $type = 'pubDate') + { + return $this->buildNode($element, $type, $date->format(DateTime::RSS)); + } + + /** + * Build link element + * + * @access public + * @param DOMElement $element + * @param string $url + * @return $this + */ + public function buildLink(DOMElement $element, $url) + { + return $this->buildNode($element, 'link', $url); + } + + /** + * Build author element + * + * @access public + * @param DOMElement $element + * @param string $tag + * @param string $authorName + * @param string $authorEmail + * @return $this + */ + public function buildAuthor(DOMElement $element, $tag, $authorName, $authorEmail) + { + if (!empty($authorName)) { + $value = ''; + + if (!empty($authorEmail)) { + $value .= $authorEmail.' ('.$authorName.')'; + } else { + $value = $authorName; + } + + $this->buildNode($element, $tag, $value); + } + + return $this; + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/Rss20ItemBuilder.php b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/Rss20ItemBuilder.php new file mode 100644 index 00000000..125dc6ac --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/Rss20ItemBuilder.php @@ -0,0 +1,67 @@ +itemElement = $this->feedBuilder->getDocument()->createElement('item'); + $this->helper = new Rss20Helper($this->feedBuilder->getDocument()); + + if (!empty($this->itemId)) { + $guid = $this->feedBuilder->getDocument()->createElement('guid'); + $guid->setAttribute('isPermaLink', 'false'); + $guid->appendChild($this->feedBuilder->getDocument()->createTextNode($this->itemId)); + $this->itemElement->appendChild($guid); + } else { + $guid = $this->feedBuilder->getDocument()->createElement('guid'); + $guid->setAttribute('isPermaLink', 'true'); + $guid->appendChild($this->feedBuilder->getDocument()->createTextNode($this->itemUrl)); + $this->itemElement->appendChild($guid); + } + + $this->helper + ->buildTitle($this->itemElement, $this->itemTitle) + ->buildLink($this->itemElement, $this->itemUrl) + ->buildDate($this->itemElement, $this->itemPublishedDate) + ->buildAuthor($this->itemElement, 'author', $this->authorName, $this->authorEmail) + ; + + if (!empty($this->itemSummary)) { + $this->helper->buildNode($this->itemElement, 'description', $this->itemSummary); + } + + if (!empty($this->itemContent)) { + $node = $this->feedBuilder->getDocument()->createElement('content:encoded'); + $node->appendChild($this->feedBuilder->getDocument()->createCDATASection($this->itemContent)); + $this->itemElement->appendChild($node); + } + + return $this->itemElement; + } +} diff --git a/dev/plugins/admin/vendor/p3k/picofeed/picofeed b/dev/plugins/admin/vendor/p3k/picofeed/picofeed new file mode 100644 index 00000000..8f35737a --- /dev/null +++ b/dev/plugins/admin/vendor/p3k/picofeed/picofeed @@ -0,0 +1,135 @@ +#!/usr/bin/env php +discover($url); + + $parser = $reader->getParser( + $resource->getUrl(), + $resource->getContent(), + $resource->getEncoding() + ); + + if ($disable_filtering) { + $parser->disableContentFiltering(); + } + + return $parser->execute(); + } + catch (PicoFeedException $e) { + echo 'Exception thrown ===> "'.$e->getMessage().'"'.PHP_EOL; + return false; + } +} + +function get_item($feed, $item_id) +{ + foreach ($feed->items as $item) { + if ($item->getId() === $item_id) { + echo $item; + echo "============= CONTENT ================\n"; + echo $item->getContent(); + echo "\n============= CONTENT ================\n"; + break; + } + } +} + +function dump_feed($url) +{ + $feed = get_feed($url); + echo $feed; +} + +function debug_feed($url) +{ + get_feed($url); + print_r(Logger::getMessages()); +} + +function dump_item($url, $item_id) +{ + $feed = get_feed($url); + + if ($feed !== false) { + get_item($feed, $item_id); + } +} + +function nofilter_item($url, $item_id) +{ + $feed = get_feed($url, true); + + if ($feed !== false) { + get_item($feed, $item_id); + } +} + +function grabber($url) +{ + $grabber = new Scraper(new Config); + $grabber->setUrl($url); + $grabber->execute(); + + print_r(Logger::getMessages()); + echo "============= CONTENT ================\n"; + echo $grabber->getRelevantContent().PHP_EOL; + echo "============= FILTERED ================\n"; + echo $grabber->getFilteredContent().PHP_EOL; +} + +function fetch_favicon($url) +{ + $favicon = new Favicon(); + echo $favicon->find($url) . PHP_EOL; +} + +// Parse command line arguments +if ($argc === 4) { + switch ($argv[1]) { + case 'item': + dump_item($argv[2], $argv[3]); + die; + case 'nofilter': + nofilter_item($argv[2], $argv[3]); + die; + } +} else if ($argc === 3) { + switch ($argv[1]) { + case 'feed': + dump_feed($argv[2]); + die; + case 'debug': + debug_feed($argv[2]); + die; + case 'grabber': + grabber($argv[2]); + die; + case 'favicon': + fetch_favicon($argv[2]); + die; + } +} + +printf("Usage:\n"); +printf("%s feed \n", $argv[0]); +printf("%s debug \n", $argv[0]); +printf("%s item \n", $argv[0]); +printf("%s nofilter \n", $argv[0]); +printf("%s grabber \n", $argv[0]); +printf("%s favicon \n", $argv[0]); diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/LICENSE.md b/dev/plugins/admin/vendor/scssphp/scssphp/LICENSE.md new file mode 100644 index 00000000..afcfdfb2 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/LICENSE.md @@ -0,0 +1,20 @@ +Copyright (c) 2015 Leaf Corcoran, http://scssphp.github.io/scssphp + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/README.md b/dev/plugins/admin/vendor/scssphp/scssphp/README.md new file mode 100644 index 00000000..65bb93ea --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/README.md @@ -0,0 +1,71 @@ +# scssphp +### + +![Build](https://github.com/scssphp/scssphp/workflows/CI/badge.svg) +[![License](https://poser.pugx.org/scssphp/scssphp/license)](https://packagist.org/packages/scssphp/scssphp) + +`scssphp` is a compiler for SCSS written in PHP. + +Checkout the homepage, , for directions on how to use. + +## Running Tests + +`scssphp` uses [PHPUnit](https://github.com/sebastianbergmann/phpunit) for testing. + +Run the following command from the root directory to run every test: + + vendor/bin/phpunit tests + +There are several tests in the `tests/` directory: + +* `ApiTest.php` contains various unit tests that test the PHP interface. +* `ExceptionTest.php` contains unit tests that test for exceptions thrown by the parser and compiler. +* `FailingTest.php` contains tests reported in Github issues that demonstrate compatibility bugs. +* `InputTest.php` compiles every `.scss` file in the `tests/inputs` directory + then compares to the respective `.css` file in the `tests/outputs` directory. +* `SassSpecTest.php` extracts tests from the `sass/sass-spec` repository. + +When changing any of the tests in `tests/inputs`, the tests will most likely +fail because the output has changed. Once you verify that the output is correct +you can run the following command to rebuild all the tests: + + BUILD=1 vendor/bin/phpunit tests + +This will compile all the tests, and save results into `tests/outputs`. It also +updates the list of excluded specs from sass-spec. + +To enable the full `sass-spec` compatibility tests: + + TEST_SASS_SPEC=1 vendor/bin/phpunit tests + +## Coding Standard + +`scssphp` source conforms to [PSR12](https://www.php-fig.org/psr/psr-12/). + +Run the following command from the root directory to check the code for "sniffs". + + vendor/bin/phpcs --standard=PSR12 --extensions=php bin src tests *.php + +## Static Analysis + +`scssphp` uses [phpstan](https://phpstan.org/) for static analysis. + +Run the following command from the root directory to analyse the codebase: + + make phpstan + +As most of the codebase is composed of legacy code which cannot be type-checked +fully, the setup contains a baseline file with all errors we want to ignore. In +particular, we ignore all errors related to not specifying the types inside arrays +when these arrays correspond to the representation of Sass values and Sass AST nodes +in the parser and compiler. +When contributing, the proper process to deal with static analysis is the following: + +1. Make your change in the codebase +2. Run `make phpstan` +3. Fix errors reported by phpstan when possible +4. Repeat step 2 and 3 until nothing gets fixed anymore at step 3 +5. Run `make phpstan-baseline` to regenerate the phpstan baseline + +Additions to the baseline will be reviewed to avoid ignoring errors that should have +been fixed. diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/bin/pscss b/dev/plugins/admin/vendor/scssphp/scssphp/bin/pscss new file mode 100644 index 00000000..0f009d6b --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/bin/pscss @@ -0,0 +1,244 @@ +#!/usr/bin/env php +parse($data)), true)); + + fwrite(STDERR, 'Warning: the --dump-tree option is deprecated. Use proper debugging tools instead.'); + + exit(); +} + +$scss = new Compiler(); + +if ($loadPaths) { + $scss->setImportPaths($loadPaths); +} + +if ($style) { + if ($style === OutputStyle::COMPRESSED || $style === OutputStyle::EXPANDED) { + $scss->setOutputStyle($style); + } else { + fwrite(STDERR, "WARNING: the $style style is deprecated.\n"); + $scss->setFormatter('ScssPhp\\ScssPhp\\Formatter\\' . ucfirst($style)); + } +} + +$outputFile = isset($arguments[1]) ? $arguments[1] : null; +$sourceMapFile = null; + +if ($sourceMap) { + $sourceMapOptions = array( + 'outputSourceFiles' => $embedSources, + ); + if ($embedSourceMap || $outputFile === null) { + $scss->setSourceMap(Compiler::SOURCE_MAP_INLINE); + } else { + $sourceMapFile = $outputFile . '.map'; + $sourceMapOptions['sourceMapWriteTo'] = $sourceMapFile; + $sourceMapOptions['sourceMapURL'] = basename($sourceMapFile); + $sourceMapOptions['sourceMapBasepath'] = getcwd(); + $sourceMapOptions['sourceMapFilename'] = basename($outputFile); + + $scss->setSourceMap(Compiler::SOURCE_MAP_FILE); + } + + $scss->setSourceMapOptions($sourceMapOptions); +} + +if ($encoding) { + $scss->setEncoding($encoding); +} + +try { + $result = $scss->compileString($data, $inputFile); +} catch (SassException $e) { + fwrite(STDERR, 'Error: '.$e->getMessage()."\n"); + exit(1); +} + +if ($outputFile) { + file_put_contents($outputFile, $result->getCss()); + + if ($sourceMapFile !== null && $result->getSourceMap() !== null) { + file_put_contents($sourceMapFile, $result->getSourceMap()); + } +} else { + echo $result->getCss(); +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/composer.json b/dev/plugins/admin/vendor/scssphp/scssphp/composer.json new file mode 100644 index 00000000..a8cb2d4f --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/composer.json @@ -0,0 +1,111 @@ +{ + "name": "scssphp/scssphp", + "type": "library", + "description": "scssphp is a compiler for SCSS written in PHP.", + "keywords": ["css", "stylesheet", "scss", "sass", "less"], + "homepage": "http://scssphp.github.io/scssphp/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Anthon Pang", + "email": "apang@softwaredevelopment.ca", + "homepage": "https://github.com/robocoder" + }, + { + "name": "Cédric Morin", + "email": "cedric@yterium.com", + "homepage": "https://github.com/Cerdic" + } + ], + "autoload": { + "psr-4": { "ScssPhp\\ScssPhp\\": "src/" } + }, + "autoload-dev": { + "psr-4": { "ScssPhp\\ScssPhp\\Tests\\": "tests/" } + }, + "require": { + "php": ">=5.6.0", + "ext-json": "*", + "ext-ctype": "*" + }, + "suggest": { + "ext-mbstring": "For best performance, mbstring should be installed as it is faster than ext-iconv", + "ext-iconv": "Can be used as fallback when ext-mbstring is not available" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4", + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3 || ^9.4", + "sass/sass-spec": "*", + "squizlabs/php_codesniffer": "~3.5", + "symfony/phpunit-bridge": "^5.1", + "thoughtbot/bourbon": "^7.0", + "twbs/bootstrap": "~5.0", + "twbs/bootstrap4": "4.6.1", + "zurb/foundation": "~6.5" + }, + "repositories": [ + { + "type": "package", + "package": { + "name": "sass/sass-spec", + "version": "2021.11.30", + "source": { + "type": "git", + "url": "https://github.com/sass/sass-spec.git", + "reference": "ee5b460ac84b1ce27b86e22c0252b4296444cf3a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sass/sass-spec/zipball/ee5b460ac84b1ce27b86e22c0252b4296444cf3a", + "reference": "ee5b460ac84b1ce27b86e22c0252b4296444cf3a", + "shasum": "" + } + } + }, + { + "type": "package", + "package": { + "name": "thoughtbot/bourbon", + "version": "v7.0.0", + "source": { + "type": "git", + "url": "https://github.com/thoughtbot/bourbon.git", + "reference": "fbe338ee6807e7f7aa996d82c8a16f248bb149b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thoughtbot/bourbon/zipball/fbe338ee6807e7f7aa996d82c8a16f248bb149b3", + "reference": "fbe338ee6807e7f7aa996d82c8a16f248bb149b3", + "shasum": "" + } + } + }, + { + "type": "package", + "package": { + "name": "twbs/bootstrap4", + "version": "v4.6.1", + "source": { + "type": "git", + "url": "https://github.com/twbs/bootstrap.git", + "reference": "043a03c95a2ad6738f85b65e53b9dbdfb03b8d10" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twbs/bootstrap/zipball/043a03c95a2ad6738f85b65e53b9dbdfb03b8d10", + "reference": "043a03c95a2ad6738f85b65e53b9dbdfb03b8d10", + "shasum": "" + } + } + } + ], + "bin": ["bin/pscss"], + "config": { + "sort-packages": true, + "allow-plugins": { + "bamarni/composer-bin-plugin": true + } + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/phpcs.xml.dist b/dev/plugins/admin/vendor/scssphp/scssphp/phpcs.xml.dist new file mode 100644 index 00000000..b162dbd6 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/phpcs.xml.dist @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/scss.inc.php b/dev/plugins/admin/vendor/scssphp/scssphp/scss.inc.php new file mode 100644 index 00000000..45983780 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/scss.inc.php @@ -0,0 +1,21 @@ + + * + * @internal + */ +class Range +{ + /** + * @var float|int + */ + public $first; + + /** + * @var float|int + */ + public $last; + + /** + * Initialize range + * + * @param int|float $first + * @param int|float $last + */ + public function __construct($first, $last) + { + $this->first = $first; + $this->last = $last; + } + + /** + * Test for inclusion in range + * + * @param int|float $value + * + * @return bool + */ + public function includes($value) + { + return $value >= $this->first && $value <= $this->last; + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Block.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block.php new file mode 100644 index 00000000..96668dc6 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block.php @@ -0,0 +1,73 @@ + + * + * @internal + */ +class Block +{ + /** + * @var string|null + */ + public $type; + + /** + * @var Block|null + */ + public $parent; + + /** + * @var string + */ + public $sourceName; + + /** + * @var int + */ + public $sourceIndex; + + /** + * @var int + */ + public $sourceLine; + + /** + * @var int + */ + public $sourceColumn; + + /** + * @var array|null + */ + public $selectors; + + /** + * @var array + */ + public $comments; + + /** + * @var array + */ + public $children; + + /** + * @var Block|null + */ + public $selfParent; +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/AtRootBlock.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/AtRootBlock.php new file mode 100644 index 00000000..41842c26 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/AtRootBlock.php @@ -0,0 +1,37 @@ +type = Type::T_AT_ROOT; + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/CallableBlock.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/CallableBlock.php new file mode 100644 index 00000000..a18a87c2 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/CallableBlock.php @@ -0,0 +1,45 @@ +type = $type; + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/ContentBlock.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/ContentBlock.php new file mode 100644 index 00000000..87084980 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/ContentBlock.php @@ -0,0 +1,38 @@ +type = Type::T_INCLUDE; + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/DirectiveBlock.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/DirectiveBlock.php new file mode 100644 index 00000000..b1d3d1a8 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/DirectiveBlock.php @@ -0,0 +1,37 @@ +type = Type::T_DIRECTIVE; + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/EachBlock.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/EachBlock.php new file mode 100644 index 00000000..b3289579 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/EachBlock.php @@ -0,0 +1,37 @@ +type = Type::T_EACH; + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/ElseBlock.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/ElseBlock.php new file mode 100644 index 00000000..6abb4d77 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/ElseBlock.php @@ -0,0 +1,27 @@ +type = Type::T_ELSE; + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/ElseifBlock.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/ElseifBlock.php new file mode 100644 index 00000000..4622bca7 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/ElseifBlock.php @@ -0,0 +1,32 @@ +type = Type::T_ELSEIF; + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/ForBlock.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/ForBlock.php new file mode 100644 index 00000000..a9cf6733 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/ForBlock.php @@ -0,0 +1,47 @@ +type = Type::T_FOR; + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/IfBlock.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/IfBlock.php new file mode 100644 index 00000000..9f21bf88 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/IfBlock.php @@ -0,0 +1,37 @@ + + */ + public $cases = []; + + public function __construct() + { + $this->type = Type::T_IF; + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/MediaBlock.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/MediaBlock.php new file mode 100644 index 00000000..c49ee1b2 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/MediaBlock.php @@ -0,0 +1,37 @@ +type = Type::T_MEDIA; + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/NestedPropertyBlock.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/NestedPropertyBlock.php new file mode 100644 index 00000000..1ea4a6c8 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/NestedPropertyBlock.php @@ -0,0 +1,37 @@ +type = Type::T_NESTED_PROPERTY; + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/WhileBlock.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/WhileBlock.php new file mode 100644 index 00000000..ac18d4e0 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Block/WhileBlock.php @@ -0,0 +1,32 @@ +type = Type::T_WHILE; + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Cache.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Cache.php new file mode 100644 index 00000000..9731c60a --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Cache.php @@ -0,0 +1,272 @@ + + * + * @internal + */ +class Cache +{ + const CACHE_VERSION = 1; + + /** + * directory used for storing data + * + * @var string|false + */ + public static $cacheDir = false; + + /** + * prefix for the storing data + * + * @var string + */ + public static $prefix = 'scssphp_'; + + /** + * force a refresh : 'once' for refreshing the first hit on a cache only, true to never use the cache in this hit + * + * @var bool|string + */ + public static $forceRefresh = false; + + /** + * specifies the number of seconds after which data cached will be seen as 'garbage' and potentially cleaned up + * + * @var int + */ + public static $gcLifetime = 604800; + + /** + * array of already refreshed cache if $forceRefresh==='once' + * + * @var array + */ + protected static $refreshed = []; + + /** + * Constructor + * + * @param array $options + * + * @phpstan-param array{cacheDir?: string, prefix?: string, forceRefresh?: string} $options + */ + public function __construct($options) + { + // check $cacheDir + if (isset($options['cacheDir'])) { + self::$cacheDir = $options['cacheDir']; + } + + if (empty(self::$cacheDir)) { + throw new Exception('cacheDir not set'); + } + + if (isset($options['prefix'])) { + self::$prefix = $options['prefix']; + } + + if (empty(self::$prefix)) { + throw new Exception('prefix not set'); + } + + if (isset($options['forceRefresh'])) { + self::$forceRefresh = $options['forceRefresh']; + } + + self::checkCacheDir(); + } + + /** + * Get the cached result of $operation on $what, + * which is known as dependant from the content of $options + * + * @param string $operation parse, compile... + * @param mixed $what content key (e.g., filename to be treated) + * @param array $options any option that affect the operation result on the content + * @param int|null $lastModified last modified timestamp + * + * @return mixed + * + * @throws \Exception + */ + public function getCache($operation, $what, $options = [], $lastModified = null) + { + $fileCache = self::$cacheDir . self::cacheName($operation, $what, $options); + + if ( + ((self::$forceRefresh === false) || (self::$forceRefresh === 'once' && + isset(self::$refreshed[$fileCache]))) && file_exists($fileCache) + ) { + $cacheTime = filemtime($fileCache); + + if ( + (\is_null($lastModified) || $cacheTime > $lastModified) && + $cacheTime + self::$gcLifetime > time() + ) { + $c = file_get_contents($fileCache); + $c = unserialize($c); + + if (\is_array($c) && isset($c['value'])) { + return $c['value']; + } + } + } + + return null; + } + + /** + * Put in cache the result of $operation on $what, + * which is known as dependant from the content of $options + * + * @param string $operation + * @param mixed $what + * @param mixed $value + * @param array $options + * + * @return void + */ + public function setCache($operation, $what, $value, $options = []) + { + $fileCache = self::$cacheDir . self::cacheName($operation, $what, $options); + + $c = ['value' => $value]; + $c = serialize($c); + + file_put_contents($fileCache, $c); + + if (self::$forceRefresh === 'once') { + self::$refreshed[$fileCache] = true; + } + } + + /** + * Get the cache name for the caching of $operation on $what, + * which is known as dependant from the content of $options + * + * @param string $operation + * @param mixed $what + * @param array $options + * + * @return string + */ + private static function cacheName($operation, $what, $options = []) + { + $t = [ + 'version' => self::CACHE_VERSION, + 'scssphpVersion' => Version::VERSION, + 'operation' => $operation, + 'what' => $what, + 'options' => $options + ]; + + $t = self::$prefix + . sha1(json_encode($t)) + . ".$operation" + . ".scsscache"; + + return $t; + } + + /** + * Check that the cache dir exists and is writeable + * + * @return void + * + * @throws \Exception + */ + public static function checkCacheDir() + { + self::$cacheDir = str_replace('\\', '/', self::$cacheDir); + self::$cacheDir = rtrim(self::$cacheDir, '/') . '/'; + + if (! is_dir(self::$cacheDir)) { + throw new Exception('Cache directory doesn\'t exist: ' . self::$cacheDir); + } + + if (! is_writable(self::$cacheDir)) { + throw new Exception('Cache directory isn\'t writable: ' . self::$cacheDir); + } + } + + /** + * Delete unused cached files + * + * @return void + */ + public static function cleanCache() + { + static $clean = false; + + if ($clean || empty(self::$cacheDir)) { + return; + } + + $clean = true; + + // only remove files with extensions created by SCSSPHP Cache + // css files removed based on the list files + $removeTypes = ['scsscache' => 1]; + + $files = scandir(self::$cacheDir); + + if (! $files) { + return; + } + + $checkTime = time() - self::$gcLifetime; + + foreach ($files as $file) { + // don't delete if the file wasn't created with SCSSPHP Cache + if (strpos($file, self::$prefix) !== 0) { + continue; + } + + $parts = explode('.', $file); + $type = array_pop($parts); + + if (! isset($removeTypes[$type])) { + continue; + } + + $fullPath = self::$cacheDir . $file; + $mtime = filemtime($fullPath); + + // don't delete if it's a relatively new file + if ($mtime > $checkTime) { + continue; + } + + unlink($fullPath); + } + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Colors.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Colors.php new file mode 100644 index 00000000..2df39992 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Colors.php @@ -0,0 +1,247 @@ + + * + * @internal + */ +class Colors +{ + /** + * CSS Colors + * + * @see http://www.w3.org/TR/css3-color + * + * @var array + */ + protected static $cssColors = [ + 'aliceblue' => '240,248,255', + 'antiquewhite' => '250,235,215', + 'aqua' => '0,255,255', + 'cyan' => '0,255,255', + 'aquamarine' => '127,255,212', + 'azure' => '240,255,255', + 'beige' => '245,245,220', + 'bisque' => '255,228,196', + 'black' => '0,0,0', + 'blanchedalmond' => '255,235,205', + 'blue' => '0,0,255', + 'blueviolet' => '138,43,226', + 'brown' => '165,42,42', + 'burlywood' => '222,184,135', + 'cadetblue' => '95,158,160', + 'chartreuse' => '127,255,0', + 'chocolate' => '210,105,30', + 'coral' => '255,127,80', + 'cornflowerblue' => '100,149,237', + 'cornsilk' => '255,248,220', + 'crimson' => '220,20,60', + 'darkblue' => '0,0,139', + 'darkcyan' => '0,139,139', + 'darkgoldenrod' => '184,134,11', + 'darkgray' => '169,169,169', + 'darkgrey' => '169,169,169', + 'darkgreen' => '0,100,0', + 'darkkhaki' => '189,183,107', + 'darkmagenta' => '139,0,139', + 'darkolivegreen' => '85,107,47', + 'darkorange' => '255,140,0', + 'darkorchid' => '153,50,204', + 'darkred' => '139,0,0', + 'darksalmon' => '233,150,122', + 'darkseagreen' => '143,188,143', + 'darkslateblue' => '72,61,139', + 'darkslategray' => '47,79,79', + 'darkslategrey' => '47,79,79', + 'darkturquoise' => '0,206,209', + 'darkviolet' => '148,0,211', + 'deeppink' => '255,20,147', + 'deepskyblue' => '0,191,255', + 'dimgray' => '105,105,105', + 'dimgrey' => '105,105,105', + 'dodgerblue' => '30,144,255', + 'firebrick' => '178,34,34', + 'floralwhite' => '255,250,240', + 'forestgreen' => '34,139,34', + 'fuchsia' => '255,0,255', + 'magenta' => '255,0,255', + 'gainsboro' => '220,220,220', + 'ghostwhite' => '248,248,255', + 'gold' => '255,215,0', + 'goldenrod' => '218,165,32', + 'gray' => '128,128,128', + 'grey' => '128,128,128', + 'green' => '0,128,0', + 'greenyellow' => '173,255,47', + 'honeydew' => '240,255,240', + 'hotpink' => '255,105,180', + 'indianred' => '205,92,92', + 'indigo' => '75,0,130', + 'ivory' => '255,255,240', + 'khaki' => '240,230,140', + 'lavender' => '230,230,250', + 'lavenderblush' => '255,240,245', + 'lawngreen' => '124,252,0', + 'lemonchiffon' => '255,250,205', + 'lightblue' => '173,216,230', + 'lightcoral' => '240,128,128', + 'lightcyan' => '224,255,255', + 'lightgoldenrodyellow' => '250,250,210', + 'lightgray' => '211,211,211', + 'lightgrey' => '211,211,211', + 'lightgreen' => '144,238,144', + 'lightpink' => '255,182,193', + 'lightsalmon' => '255,160,122', + 'lightseagreen' => '32,178,170', + 'lightskyblue' => '135,206,250', + 'lightslategray' => '119,136,153', + 'lightslategrey' => '119,136,153', + 'lightsteelblue' => '176,196,222', + 'lightyellow' => '255,255,224', + 'lime' => '0,255,0', + 'limegreen' => '50,205,50', + 'linen' => '250,240,230', + 'maroon' => '128,0,0', + 'mediumaquamarine' => '102,205,170', + 'mediumblue' => '0,0,205', + 'mediumorchid' => '186,85,211', + 'mediumpurple' => '147,112,219', + 'mediumseagreen' => '60,179,113', + 'mediumslateblue' => '123,104,238', + 'mediumspringgreen' => '0,250,154', + 'mediumturquoise' => '72,209,204', + 'mediumvioletred' => '199,21,133', + 'midnightblue' => '25,25,112', + 'mintcream' => '245,255,250', + 'mistyrose' => '255,228,225', + 'moccasin' => '255,228,181', + 'navajowhite' => '255,222,173', + 'navy' => '0,0,128', + 'oldlace' => '253,245,230', + 'olive' => '128,128,0', + 'olivedrab' => '107,142,35', + 'orange' => '255,165,0', + 'orangered' => '255,69,0', + 'orchid' => '218,112,214', + 'palegoldenrod' => '238,232,170', + 'palegreen' => '152,251,152', + 'paleturquoise' => '175,238,238', + 'palevioletred' => '219,112,147', + 'papayawhip' => '255,239,213', + 'peachpuff' => '255,218,185', + 'peru' => '205,133,63', + 'pink' => '255,192,203', + 'plum' => '221,160,221', + 'powderblue' => '176,224,230', + 'purple' => '128,0,128', + 'red' => '255,0,0', + 'rosybrown' => '188,143,143', + 'royalblue' => '65,105,225', + 'saddlebrown' => '139,69,19', + 'salmon' => '250,128,114', + 'sandybrown' => '244,164,96', + 'seagreen' => '46,139,87', + 'seashell' => '255,245,238', + 'sienna' => '160,82,45', + 'silver' => '192,192,192', + 'skyblue' => '135,206,235', + 'slateblue' => '106,90,205', + 'slategray' => '112,128,144', + 'slategrey' => '112,128,144', + 'snow' => '255,250,250', + 'springgreen' => '0,255,127', + 'steelblue' => '70,130,180', + 'tan' => '210,180,140', + 'teal' => '0,128,128', + 'thistle' => '216,191,216', + 'tomato' => '255,99,71', + 'turquoise' => '64,224,208', + 'violet' => '238,130,238', + 'wheat' => '245,222,179', + 'white' => '255,255,255', + 'whitesmoke' => '245,245,245', + 'yellow' => '255,255,0', + 'yellowgreen' => '154,205,50', + 'rebeccapurple' => '102,51,153', + 'transparent' => '0,0,0,0', + ]; + + /** + * Convert named color in a [r,g,b[,a]] array + * + * @param string $colorName + * + * @return int[]|null + */ + public static function colorNameToRGBa($colorName) + { + if (\is_string($colorName) && isset(static::$cssColors[$colorName])) { + $rgba = explode(',', static::$cssColors[$colorName]); + + // only case with opacity is transparent, with opacity=0, so we can intval on opacity also + $rgba = array_map('intval', $rgba); + + return $rgba; + } + + return null; + } + + /** + * Reverse conversion : from RGBA to a color name if possible + * + * @param int $r + * @param int $g + * @param int $b + * @param int|float $a + * + * @return string|null + */ + public static function RGBaToColorName($r, $g, $b, $a = 1) + { + static $reverseColorTable = null; + + if (! is_numeric($r) || ! is_numeric($g) || ! is_numeric($b) || ! is_numeric($a)) { + return null; + } + + if ($a < 1) { + return null; + } + + if (\is_null($reverseColorTable)) { + $reverseColorTable = []; + + foreach (static::$cssColors as $name => $rgb_str) { + $rgb_str = explode(',', $rgb_str); + + if ( + \count($rgb_str) == 3 && + ! isset($reverseColorTable[\intval($rgb_str[0])][\intval($rgb_str[1])][\intval($rgb_str[2])]) + ) { + $reverseColorTable[\intval($rgb_str[0])][\intval($rgb_str[1])][\intval($rgb_str[2])] = $name; + } + } + } + + if (isset($reverseColorTable[\intval($r)][\intval($g)][\intval($b)])) { + return $reverseColorTable[\intval($r)][\intval($g)][\intval($b)]; + } + + return null; + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/CompilationResult.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/CompilationResult.php new file mode 100644 index 00000000..36adb0da --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/CompilationResult.php @@ -0,0 +1,69 @@ +css = $css; + $this->sourceMap = $sourceMap; + $this->includedFiles = $includedFiles; + } + + /** + * @return string + */ + public function getCss() + { + return $this->css; + } + + /** + * @return string[] + */ + public function getIncludedFiles() + { + return $this->includedFiles; + } + + /** + * The sourceMap content, if it was generated + * + * @return null|string + */ + public function getSourceMap() + { + return $this->sourceMap; + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Compiler.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Compiler.php new file mode 100644 index 00000000..b6ef0272 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Compiler.php @@ -0,0 +1,10355 @@ + + * + * @final Extending the Compiler is deprecated + */ +class Compiler +{ + /** + * @deprecated + */ + const LINE_COMMENTS = 1; + /** + * @deprecated + */ + const DEBUG_INFO = 2; + + /** + * @deprecated + */ + const WITH_RULE = 1; + /** + * @deprecated + */ + const WITH_MEDIA = 2; + /** + * @deprecated + */ + const WITH_SUPPORTS = 4; + /** + * @deprecated + */ + const WITH_ALL = 7; + + const SOURCE_MAP_NONE = 0; + const SOURCE_MAP_INLINE = 1; + const SOURCE_MAP_FILE = 2; + + /** + * @var array + */ + protected static $operatorNames = [ + '+' => 'add', + '-' => 'sub', + '*' => 'mul', + '/' => 'div', + '%' => 'mod', + + '==' => 'eq', + '!=' => 'neq', + '<' => 'lt', + '>' => 'gt', + + '<=' => 'lte', + '>=' => 'gte', + ]; + + /** + * @var array + */ + protected static $namespaces = [ + 'special' => '%', + 'mixin' => '@', + 'function' => '^', + ]; + + public static $true = [Type::T_KEYWORD, 'true']; + public static $false = [Type::T_KEYWORD, 'false']; + /** @deprecated */ + public static $NaN = [Type::T_KEYWORD, 'NaN']; + /** @deprecated */ + public static $Infinity = [Type::T_KEYWORD, 'Infinity']; + public static $null = [Type::T_NULL]; + public static $nullString = [Type::T_STRING, '', []]; + public static $defaultValue = [Type::T_KEYWORD, '']; + public static $selfSelector = [Type::T_SELF]; + public static $emptyList = [Type::T_LIST, '', []]; + public static $emptyMap = [Type::T_MAP, [], []]; + public static $emptyString = [Type::T_STRING, '"', []]; + public static $with = [Type::T_KEYWORD, 'with']; + public static $without = [Type::T_KEYWORD, 'without']; + private static $emptyArgumentList = [Type::T_LIST, '', [], []]; + + /** + * @var array + */ + protected $importPaths = []; + /** + * @var array + */ + protected $importCache = []; + + /** + * @var string[] + */ + protected $importedFiles = []; + + /** + * @var array + * @phpstan-var array + */ + protected $userFunctions = []; + /** + * @var array + */ + protected $registeredVars = []; + /** + * @var array + */ + protected $registeredFeatures = [ + 'extend-selector-pseudoclass' => false, + 'at-error' => true, + 'units-level-3' => true, + 'global-variable-shadowing' => false, + ]; + + /** + * @var string|null + */ + protected $encoding = null; + /** + * @var null + * @deprecated + */ + protected $lineNumberStyle = null; + + /** + * @var int|SourceMapGenerator + * @phpstan-var self::SOURCE_MAP_*|SourceMapGenerator + */ + protected $sourceMap = self::SOURCE_MAP_NONE; + + /** + * @var array + * @phpstan-var array{sourceRoot?: string, sourceMapFilename?: string|null, sourceMapURL?: string|null, sourceMapWriteTo?: string|null, outputSourceFiles?: bool, sourceMapRootpath?: string, sourceMapBasepath?: string} + */ + protected $sourceMapOptions = []; + + /** + * @var bool + */ + private $charset = true; + + /** + * @var string|\ScssPhp\ScssPhp\Formatter + */ + protected $formatter = Expanded::class; + + /** + * @var Environment + */ + protected $rootEnv; + /** + * @var OutputBlock|null + */ + protected $rootBlock; + + /** + * @var \ScssPhp\ScssPhp\Compiler\Environment + */ + protected $env; + /** + * @var OutputBlock|null + */ + protected $scope; + /** + * @var Environment|null + */ + protected $storeEnv; + /** + * @var bool|null + * + * @deprecated + */ + protected $charsetSeen; + /** + * @var array + */ + protected $sourceNames; + + /** + * @var Cache|null + */ + protected $cache; + + /** + * @var bool + */ + protected $cacheCheckImportResolutions = false; + + /** + * @var int + */ + protected $indentLevel; + /** + * @var array[] + */ + protected $extends; + /** + * @var array + */ + protected $extendsMap; + + /** + * @var array + */ + protected $parsedFiles = []; + + /** + * @var Parser|null + */ + protected $parser; + /** + * @var int|null + */ + protected $sourceIndex; + /** + * @var int|null + */ + protected $sourceLine; + /** + * @var int|null + */ + protected $sourceColumn; + /** + * @var bool|null + */ + protected $shouldEvaluate; + /** + * @var null + * @deprecated + */ + protected $ignoreErrors; + /** + * @var bool + */ + protected $ignoreCallStackMessage = false; + + /** + * @var array[] + */ + protected $callStack = []; + + /** + * @var array + * @phpstan-var list + */ + private $resolvedImports = []; + + /** + * The directory of the currently processed file + * + * @var string|null + */ + private $currentDirectory; + + /** + * The directory of the input file + * + * @var string + */ + private $rootDirectory; + + /** + * @var bool + */ + private $legacyCwdImportPath = true; + + /** + * @var LoggerInterface + */ + private $logger; + + /** + * @var array + */ + private $warnedChildFunctions = []; + + /** + * Constructor + * + * @param array|null $cacheOptions + * @phpstan-param array{cacheDir?: string, prefix?: string, forceRefresh?: string, checkImportResolutions?: bool}|null $cacheOptions + */ + public function __construct($cacheOptions = null) + { + $this->sourceNames = []; + + if ($cacheOptions) { + $this->cache = new Cache($cacheOptions); + if (!empty($cacheOptions['checkImportResolutions'])) { + $this->cacheCheckImportResolutions = true; + } + } + + $this->logger = new StreamLogger(fopen('php://stderr', 'w'), true); + } + + /** + * Get compiler options + * + * @return array + * + * @internal + */ + public function getCompileOptions() + { + $options = [ + 'importPaths' => $this->importPaths, + 'registeredVars' => $this->registeredVars, + 'registeredFeatures' => $this->registeredFeatures, + 'encoding' => $this->encoding, + 'sourceMap' => serialize($this->sourceMap), + 'sourceMapOptions' => $this->sourceMapOptions, + 'formatter' => $this->formatter, + 'legacyImportPath' => $this->legacyCwdImportPath, + ]; + + return $options; + } + + /** + * Sets an alternative logger. + * + * Changing the logger in the middle of the compilation is not + * supported and will result in an undefined behavior. + * + * @param LoggerInterface $logger + * + * @return void + */ + public function setLogger(LoggerInterface $logger) + { + $this->logger = $logger; + } + + /** + * Set an alternative error output stream, for testing purpose only + * + * @param resource $handle + * + * @return void + * + * @deprecated Use {@see setLogger} instead + */ + public function setErrorOuput($handle) + { + @trigger_error('The method "setErrorOuput" is deprecated. Use "setLogger" instead.', E_USER_DEPRECATED); + + $this->logger = new StreamLogger($handle); + } + + /** + * Compile scss + * + * @param string $code + * @param string|null $path + * + * @return string + * + * @throws SassException when the source fails to compile + * + * @deprecated Use {@see compileString} instead. + */ + public function compile($code, $path = null) + { + @trigger_error(sprintf('The "%s" method is deprecated. Use "compileString" instead.', __METHOD__), E_USER_DEPRECATED); + + $result = $this->compileString($code, $path); + + $sourceMap = $result->getSourceMap(); + + if ($sourceMap !== null) { + if ($this->sourceMap instanceof SourceMapGenerator) { + $this->sourceMap->saveMap($sourceMap); + } elseif ($this->sourceMap === self::SOURCE_MAP_FILE) { + $sourceMapGenerator = new SourceMapGenerator($this->sourceMapOptions); + $sourceMapGenerator->saveMap($sourceMap); + } + } + + return $result->getCss(); + } + + /** + * Compile scss + * + * @param string $source + * @param string|null $path + * + * @return CompilationResult + * + * @throws SassException when the source fails to compile + */ + public function compileString($source, $path = null) + { + if ($this->cache) { + $cacheKey = ($path ? $path : '(stdin)') . ':' . md5($source); + $compileOptions = $this->getCompileOptions(); + $cachedResult = $this->cache->getCache('compile', $cacheKey, $compileOptions); + + if ($cachedResult instanceof CachedResult && $this->isFreshCachedResult($cachedResult)) { + return $cachedResult->getResult(); + } + } + + $this->indentLevel = -1; + $this->extends = []; + $this->extendsMap = []; + $this->sourceIndex = null; + $this->sourceLine = null; + $this->sourceColumn = null; + $this->env = null; + $this->scope = null; + $this->storeEnv = null; + $this->shouldEvaluate = null; + $this->ignoreCallStackMessage = false; + $this->parsedFiles = []; + $this->importedFiles = []; + $this->resolvedImports = []; + + if (!\is_null($path) && is_file($path)) { + $path = realpath($path) ?: $path; + $this->currentDirectory = dirname($path); + $this->rootDirectory = $this->currentDirectory; + } else { + $this->currentDirectory = null; + $this->rootDirectory = getcwd(); + } + + try { + $this->parser = $this->parserFactory($path); + $tree = $this->parser->parse($source); + $this->parser = null; + + $this->formatter = new $this->formatter(); + $this->rootBlock = null; + $this->rootEnv = $this->pushEnv($tree); + + $warnCallback = function ($message, $deprecation) { + $this->logger->warn($message, $deprecation); + }; + $previousWarnCallback = Warn::setCallback($warnCallback); + + try { + $this->injectVariables($this->registeredVars); + $this->compileRoot($tree); + $this->popEnv(); + } finally { + Warn::setCallback($previousWarnCallback); + } + + $sourceMapGenerator = null; + + if ($this->sourceMap) { + if (\is_object($this->sourceMap) && $this->sourceMap instanceof SourceMapGenerator) { + $sourceMapGenerator = $this->sourceMap; + $this->sourceMap = self::SOURCE_MAP_FILE; + } elseif ($this->sourceMap !== self::SOURCE_MAP_NONE) { + $sourceMapGenerator = new SourceMapGenerator($this->sourceMapOptions); + } + } + + $out = $this->formatter->format($this->scope, $sourceMapGenerator); + + $prefix = ''; + + if ($this->charset && strlen($out) !== Util::mbStrlen($out)) { + $prefix = '@charset "UTF-8";' . "\n"; + $out = $prefix . $out; + } + + $sourceMap = null; + + if (! empty($out) && $this->sourceMap && $this->sourceMap !== self::SOURCE_MAP_NONE) { + $sourceMap = $sourceMapGenerator->generateJson($prefix); + $sourceMapUrl = null; + + switch ($this->sourceMap) { + case self::SOURCE_MAP_INLINE: + $sourceMapUrl = sprintf('data:application/json,%s', Util::encodeURIComponent($sourceMap)); + break; + + case self::SOURCE_MAP_FILE: + if (isset($this->sourceMapOptions['sourceMapURL'])) { + $sourceMapUrl = $this->sourceMapOptions['sourceMapURL']; + } + break; + } + + if ($sourceMapUrl !== null) { + $out .= sprintf('/*# sourceMappingURL=%s */', $sourceMapUrl); + } + } + } catch (SassScriptException $e) { + throw new CompilerException($this->addLocationToMessage($e->getMessage()), 0, $e); + } + + $includedFiles = []; + + foreach ($this->resolvedImports as $resolvedImport) { + $includedFiles[$resolvedImport['filePath']] = $resolvedImport['filePath']; + } + + $result = new CompilationResult($out, $sourceMap, array_values($includedFiles)); + + if ($this->cache && isset($cacheKey) && isset($compileOptions)) { + $this->cache->setCache('compile', $cacheKey, new CachedResult($result, $this->parsedFiles, $this->resolvedImports), $compileOptions); + } + + // Reset state to free memory + // TODO in 2.0, reset parsedFiles as well when the getter is removed. + $this->resolvedImports = []; + $this->importedFiles = []; + + return $result; + } + + /** + * @param CachedResult $result + * + * @return bool + */ + private function isFreshCachedResult(CachedResult $result) + { + // check if any dependency file changed since the result was compiled + foreach ($result->getParsedFiles() as $file => $mtime) { + if (! is_file($file) || filemtime($file) !== $mtime) { + return false; + } + } + + if ($this->cacheCheckImportResolutions) { + $resolvedImports = []; + + foreach ($result->getResolvedImports() as $import) { + $currentDir = $import['currentDir']; + $path = $import['path']; + // store the check across all the results in memory to avoid multiple findImport() on the same path + // with same context. + // this is happening in a same hit with multiple compilations (especially with big frameworks) + if (empty($resolvedImports[$currentDir][$path])) { + $resolvedImports[$currentDir][$path] = $this->findImport($path, $currentDir); + } + + if ($resolvedImports[$currentDir][$path] !== $import['filePath']) { + return false; + } + } + } + + return true; + } + + /** + * Instantiate parser + * + * @param string|null $path + * + * @return \ScssPhp\ScssPhp\Parser + */ + protected function parserFactory($path) + { + // https://sass-lang.com/documentation/at-rules/import + // CSS files imported by Sass don’t allow any special Sass features. + // In order to make sure authors don’t accidentally write Sass in their CSS, + // all Sass features that aren’t also valid CSS will produce errors. + // Otherwise, the CSS will be rendered as-is. It can even be extended! + $cssOnly = false; + + if ($path !== null && substr($path, -4) === '.css') { + $cssOnly = true; + } + + $parser = new Parser($path, \count($this->sourceNames), $this->encoding, $this->cache, $cssOnly, $this->logger); + + $this->sourceNames[] = $path; + $this->addParsedFile($path); + + return $parser; + } + + /** + * Is self extend? + * + * @param array $target + * @param array $origin + * + * @return bool + */ + protected function isSelfExtend($target, $origin) + { + foreach ($origin as $sel) { + if (\in_array($target, $sel)) { + return true; + } + } + + return false; + } + + /** + * Push extends + * + * @param array $target + * @param array $origin + * @param array|null $block + * + * @return void + */ + protected function pushExtends($target, $origin, $block) + { + $i = \count($this->extends); + $this->extends[] = [$target, $origin, $block]; + + foreach ($target as $part) { + if (isset($this->extendsMap[$part])) { + $this->extendsMap[$part][] = $i; + } else { + $this->extendsMap[$part] = [$i]; + } + } + } + + /** + * Make output block + * + * @param string|null $type + * @param string[]|null $selectors + * + * @return \ScssPhp\ScssPhp\Formatter\OutputBlock + */ + protected function makeOutputBlock($type, $selectors = null) + { + $out = new OutputBlock(); + $out->type = $type; + $out->lines = []; + $out->children = []; + $out->parent = $this->scope; + $out->selectors = $selectors; + $out->depth = $this->env->depth; + + if ($this->env->block instanceof Block) { + $out->sourceName = $this->env->block->sourceName; + $out->sourceLine = $this->env->block->sourceLine; + $out->sourceColumn = $this->env->block->sourceColumn; + } else { + $out->sourceName = null; + $out->sourceLine = null; + $out->sourceColumn = null; + } + + return $out; + } + + /** + * Compile root + * + * @param \ScssPhp\ScssPhp\Block $rootBlock + * + * @return void + */ + protected function compileRoot(Block $rootBlock) + { + $this->rootBlock = $this->scope = $this->makeOutputBlock(Type::T_ROOT); + + $this->compileChildrenNoReturn($rootBlock->children, $this->scope); + $this->flattenSelectors($this->scope); + $this->missingSelectors(); + } + + /** + * Report missing selectors + * + * @return void + */ + protected function missingSelectors() + { + foreach ($this->extends as $extend) { + if (isset($extend[3])) { + continue; + } + + list($target, $origin, $block) = $extend; + + // ignore if !optional + if ($block[2]) { + continue; + } + + $target = implode(' ', $target); + $origin = $this->collapseSelectors($origin); + + $this->sourceLine = $block[Parser::SOURCE_LINE]; + throw $this->error("\"$origin\" failed to @extend \"$target\". The selector \"$target\" was not found."); + } + } + + /** + * Flatten selectors + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block + * @param string $parentKey + * + * @return void + */ + protected function flattenSelectors(OutputBlock $block, $parentKey = null) + { + if ($block->selectors) { + $selectors = []; + + foreach ($block->selectors as $s) { + $selectors[] = $s; + + if (! \is_array($s)) { + continue; + } + + // check extends + if (! empty($this->extendsMap)) { + $this->matchExtends($s, $selectors); + + // remove duplicates + array_walk($selectors, function (&$value) { + $value = serialize($value); + }); + + $selectors = array_unique($selectors); + + array_walk($selectors, function (&$value) { + $value = unserialize($value); + }); + } + } + + $block->selectors = []; + $placeholderSelector = false; + + foreach ($selectors as $selector) { + if ($this->hasSelectorPlaceholder($selector)) { + $placeholderSelector = true; + continue; + } + + $block->selectors[] = $this->compileSelector($selector); + } + + if ($placeholderSelector && 0 === \count($block->selectors) && null !== $parentKey) { + unset($block->parent->children[$parentKey]); + + return; + } + } + + foreach ($block->children as $key => $child) { + $this->flattenSelectors($child, $key); + } + } + + /** + * Glue parts of :not( or :nth-child( ... that are in general split in selectors parts + * + * @param array $parts + * + * @return array + */ + protected function glueFunctionSelectors($parts) + { + $new = []; + + foreach ($parts as $part) { + if (\is_array($part)) { + $part = $this->glueFunctionSelectors($part); + $new[] = $part; + } else { + // a selector part finishing with a ) is the last part of a :not( or :nth-child( + // and need to be joined to this + if ( + \count($new) && \is_string($new[\count($new) - 1]) && + \strlen($part) && substr($part, -1) === ')' && strpos($part, '(') === false + ) { + while (\count($new) > 1 && substr($new[\count($new) - 1], -1) !== '(') { + $part = array_pop($new) . $part; + } + $new[\count($new) - 1] .= $part; + } else { + $new[] = $part; + } + } + } + + return $new; + } + + /** + * Match extends + * + * @param array $selector + * @param array $out + * @param int $from + * @param bool $initial + * + * @return void + */ + protected function matchExtends($selector, &$out, $from = 0, $initial = true) + { + static $partsPile = []; + $selector = $this->glueFunctionSelectors($selector); + + if (\count($selector) == 1 && \in_array(reset($selector), $partsPile)) { + return; + } + + $outRecurs = []; + + foreach ($selector as $i => $part) { + if ($i < $from) { + continue; + } + + // check that we are not building an infinite loop of extensions + // if the new part is just including a previous part don't try to extend anymore + if (\count($part) > 1) { + foreach ($partsPile as $previousPart) { + if (! \count(array_diff($previousPart, $part))) { + continue 2; + } + } + } + + $partsPile[] = $part; + + if ($this->matchExtendsSingle($part, $origin, $initial)) { + $after = \array_slice($selector, $i + 1); + $before = \array_slice($selector, 0, $i); + list($before, $nonBreakableBefore) = $this->extractRelationshipFromFragment($before); + + foreach ($origin as $new) { + $k = 0; + + // remove shared parts + if (\count($new) > 1) { + while ($k < $i && isset($new[$k]) && $selector[$k] === $new[$k]) { + $k++; + } + } + + if (\count($nonBreakableBefore) && $k === \count($new)) { + $k--; + } + + $replacement = []; + $tempReplacement = $k > 0 ? \array_slice($new, $k) : $new; + + for ($l = \count($tempReplacement) - 1; $l >= 0; $l--) { + $slice = []; + + foreach ($tempReplacement[$l] as $chunk) { + if (! \in_array($chunk, $slice)) { + $slice[] = $chunk; + } + } + + array_unshift($replacement, $slice); + + if (! $this->isImmediateRelationshipCombinator(end($slice))) { + break; + } + } + + $afterBefore = $l != 0 ? \array_slice($tempReplacement, 0, $l) : []; + + // Merge shared direct relationships. + $mergedBefore = $this->mergeDirectRelationships($afterBefore, $nonBreakableBefore); + + $result = array_merge( + $before, + $mergedBefore, + $replacement, + $after + ); + + if ($result === $selector) { + continue; + } + + $this->pushOrMergeExtentedSelector($out, $result); + + // recursively check for more matches + $startRecurseFrom = \count($before) + min(\count($nonBreakableBefore), \count($mergedBefore)); + + if (\count($origin) > 1) { + $this->matchExtends($result, $out, $startRecurseFrom, false); + } else { + $this->matchExtends($result, $outRecurs, $startRecurseFrom, false); + } + + // selector sequence merging + if (! empty($before) && \count($new) > 1) { + $preSharedParts = $k > 0 ? \array_slice($before, 0, $k) : []; + $postSharedParts = $k > 0 ? \array_slice($before, $k) : $before; + + list($betweenSharedParts, $nonBreakabl2) = $this->extractRelationshipFromFragment($afterBefore); + + $result2 = array_merge( + $preSharedParts, + $betweenSharedParts, + $postSharedParts, + $nonBreakabl2, + $nonBreakableBefore, + $replacement, + $after + ); + + $this->pushOrMergeExtentedSelector($out, $result2); + } + } + } + array_pop($partsPile); + } + + while (\count($outRecurs)) { + $result = array_shift($outRecurs); + $this->pushOrMergeExtentedSelector($out, $result); + } + } + + /** + * Test a part for being a pseudo selector + * + * @param string $part + * @param array $matches + * + * @return bool + */ + protected function isPseudoSelector($part, &$matches) + { + if ( + strpos($part, ':') === 0 && + preg_match(",^::?([\w-]+)\((.+)\)$,", $part, $matches) + ) { + return true; + } + + return false; + } + + /** + * Push extended selector except if + * - this is a pseudo selector + * - same as previous + * - in a white list + * in this case we merge the pseudo selector content + * + * @param array $out + * @param array $extended + * + * @return void + */ + protected function pushOrMergeExtentedSelector(&$out, $extended) + { + if (\count($out) && \count($extended) === 1 && \count(reset($extended)) === 1) { + $single = reset($extended); + $part = reset($single); + + if ( + $this->isPseudoSelector($part, $matchesExtended) && + \in_array($matchesExtended[1], [ 'slotted' ]) + ) { + $prev = end($out); + $prev = $this->glueFunctionSelectors($prev); + + if (\count($prev) === 1 && \count(reset($prev)) === 1) { + $single = reset($prev); + $part = reset($single); + + if ( + $this->isPseudoSelector($part, $matchesPrev) && + $matchesPrev[1] === $matchesExtended[1] + ) { + $extended = explode($matchesExtended[1] . '(', $matchesExtended[0], 2); + $extended[1] = $matchesPrev[2] . ', ' . $extended[1]; + $extended = implode($matchesExtended[1] . '(', $extended); + $extended = [ [ $extended ]]; + array_pop($out); + } + } + } + } + $out[] = $extended; + } + + /** + * Match extends single + * + * @param array $rawSingle + * @param array $outOrigin + * @param bool $initial + * + * @return bool + */ + protected function matchExtendsSingle($rawSingle, &$outOrigin, $initial = true) + { + $counts = []; + $single = []; + + // simple usual cases, no need to do the whole trick + if (\in_array($rawSingle, [['>'],['+'],['~']])) { + return false; + } + + foreach ($rawSingle as $part) { + // matches Number + if (! \is_string($part)) { + return false; + } + + if (! preg_match('/^[\[.:#%]/', $part) && \count($single)) { + $single[\count($single) - 1] .= $part; + } else { + $single[] = $part; + } + } + + $extendingDecoratedTag = false; + + if (\count($single) > 1) { + $matches = null; + $extendingDecoratedTag = preg_match('/^[a-z0-9]+$/i', $single[0], $matches) ? $matches[0] : false; + } + + $outOrigin = []; + $found = false; + + foreach ($single as $k => $part) { + if (isset($this->extendsMap[$part])) { + foreach ($this->extendsMap[$part] as $idx) { + $counts[$idx] = isset($counts[$idx]) ? $counts[$idx] + 1 : 1; + } + } + + if ( + $initial && + $this->isPseudoSelector($part, $matches) && + ! \in_array($matches[1], [ 'not' ]) + ) { + $buffer = $matches[2]; + $parser = $this->parserFactory(__METHOD__); + + if ($parser->parseSelector($buffer, $subSelectors, false)) { + foreach ($subSelectors as $ksub => $subSelector) { + $subExtended = []; + $this->matchExtends($subSelector, $subExtended, 0, false); + + if ($subExtended) { + $subSelectorsExtended = $subSelectors; + $subSelectorsExtended[$ksub] = $subExtended; + + foreach ($subSelectorsExtended as $ksse => $sse) { + $subSelectorsExtended[$ksse] = $this->collapseSelectors($sse); + } + + $subSelectorsExtended = implode(', ', $subSelectorsExtended); + $singleExtended = $single; + $singleExtended[$k] = str_replace('(' . $buffer . ')', "($subSelectorsExtended)", $part); + $outOrigin[] = [ $singleExtended ]; + $found = true; + } + } + } + } + } + + foreach ($counts as $idx => $count) { + list($target, $origin, /* $block */) = $this->extends[$idx]; + + $origin = $this->glueFunctionSelectors($origin); + + // check count + if ($count !== \count($target)) { + continue; + } + + $this->extends[$idx][3] = true; + + $rem = array_diff($single, $target); + + foreach ($origin as $j => $new) { + // prevent infinite loop when target extends itself + if ($this->isSelfExtend($single, $origin) && ! $initial) { + return false; + } + + $replacement = end($new); + + // Extending a decorated tag with another tag is not possible. + if ( + $extendingDecoratedTag && $replacement[0] != $extendingDecoratedTag && + preg_match('/^[a-z0-9]+$/i', $replacement[0]) + ) { + unset($origin[$j]); + continue; + } + + $combined = $this->combineSelectorSingle($replacement, $rem); + + if (\count(array_diff($combined, $origin[$j][\count($origin[$j]) - 1]))) { + $origin[$j][\count($origin[$j]) - 1] = $combined; + } + } + + $outOrigin = array_merge($outOrigin, $origin); + + $found = true; + } + + return $found; + } + + /** + * Extract a relationship from the fragment. + * + * When extracting the last portion of a selector we will be left with a + * fragment which may end with a direction relationship combinator. This + * method will extract the relationship fragment and return it along side + * the rest. + * + * @param array $fragment The selector fragment maybe ending with a direction relationship combinator. + * + * @return array The selector without the relationship fragment if any, the relationship fragment. + */ + protected function extractRelationshipFromFragment(array $fragment) + { + $parents = []; + $children = []; + + $j = $i = \count($fragment); + + for (;;) { + $children = $j != $i ? \array_slice($fragment, $j, $i - $j) : []; + $parents = \array_slice($fragment, 0, $j); + $slice = end($parents); + + if (empty($slice) || ! $this->isImmediateRelationshipCombinator($slice[0])) { + break; + } + + $j -= 2; + } + + return [$parents, $children]; + } + + /** + * Combine selector single + * + * @param array $base + * @param array $other + * + * @return array + */ + protected function combineSelectorSingle($base, $other) + { + $tag = []; + $out = []; + $wasTag = false; + $pseudo = []; + + while (\count($other) && strpos(end($other), ':') === 0) { + array_unshift($pseudo, array_pop($other)); + } + + foreach ([array_reverse($base), array_reverse($other)] as $single) { + $rang = count($single); + + foreach ($single as $part) { + if (preg_match('/^[\[:]/', $part)) { + $out[] = $part; + $wasTag = false; + } elseif (preg_match('/^[\.#]/', $part)) { + array_unshift($out, $part); + $wasTag = false; + } elseif (preg_match('/^[^_-]/', $part) && $rang === 1) { + $tag[] = $part; + $wasTag = true; + } elseif ($wasTag) { + $tag[\count($tag) - 1] .= $part; + } else { + array_unshift($out, $part); + } + $rang--; + } + } + + if (\count($tag)) { + array_unshift($out, $tag[0]); + } + + while (\count($pseudo)) { + $out[] = array_shift($pseudo); + } + + return $out; + } + + /** + * Compile media + * + * @param \ScssPhp\ScssPhp\Block $media + * + * @return void + */ + protected function compileMedia(Block $media) + { + assert($media instanceof MediaBlock); + $this->pushEnv($media); + + $mediaQueries = $this->compileMediaQuery($this->multiplyMedia($this->env)); + + if (! empty($mediaQueries)) { + $previousScope = $this->scope; + $parentScope = $this->mediaParent($this->scope); + + foreach ($mediaQueries as $mediaQuery) { + $this->scope = $this->makeOutputBlock(Type::T_MEDIA, [$mediaQuery]); + + $parentScope->children[] = $this->scope; + $parentScope = $this->scope; + } + + // top level properties in a media cause it to be wrapped + $needsWrap = false; + + foreach ($media->children as $child) { + $type = $child[0]; + + if ( + $type !== Type::T_BLOCK && + $type !== Type::T_MEDIA && + $type !== Type::T_DIRECTIVE && + $type !== Type::T_IMPORT + ) { + $needsWrap = true; + break; + } + } + + if ($needsWrap) { + $wrapped = new Block(); + $wrapped->sourceName = $media->sourceName; + $wrapped->sourceIndex = $media->sourceIndex; + $wrapped->sourceLine = $media->sourceLine; + $wrapped->sourceColumn = $media->sourceColumn; + $wrapped->selectors = []; + $wrapped->comments = []; + $wrapped->parent = $media; + $wrapped->children = $media->children; + + $media->children = [[Type::T_BLOCK, $wrapped]]; + } + + $this->compileChildrenNoReturn($media->children, $this->scope); + + $this->scope = $previousScope; + } + + $this->popEnv(); + } + + /** + * Media parent + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $scope + * + * @return \ScssPhp\ScssPhp\Formatter\OutputBlock + */ + protected function mediaParent(OutputBlock $scope) + { + while (! empty($scope->parent)) { + if (! empty($scope->type) && $scope->type !== Type::T_MEDIA) { + break; + } + + $scope = $scope->parent; + } + + return $scope; + } + + /** + * Compile directive + * + * @param DirectiveBlock|array $directive + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * + * @return void + */ + protected function compileDirective($directive, OutputBlock $out) + { + if (\is_array($directive)) { + $directiveName = $this->compileDirectiveName($directive[0]); + $s = '@' . $directiveName; + + if (! empty($directive[1])) { + $s .= ' ' . $this->compileValue($directive[1]); + } + // sass-spec compliance on newline after directives, a bit tricky :/ + $appendNewLine = (! empty($directive[2]) || strpos($s, "\n")) ? "\n" : ""; + if (\is_array($directive[0]) && empty($directive[1])) { + $appendNewLine = "\n"; + } + + if (empty($directive[3])) { + $this->appendRootDirective($s . ';' . $appendNewLine, $out, [Type::T_COMMENT, Type::T_DIRECTIVE]); + } else { + $this->appendOutputLine($out, Type::T_DIRECTIVE, $s . ';'); + } + } else { + $directive->name = $this->compileDirectiveName($directive->name); + $s = '@' . $directive->name; + + if (! empty($directive->value)) { + $s .= ' ' . $this->compileValue($directive->value); + } + + if ($directive->name === 'keyframes' || substr($directive->name, -10) === '-keyframes') { + $this->compileKeyframeBlock($directive, [$s]); + } else { + $this->compileNestedBlock($directive, [$s]); + } + } + } + + /** + * directive names can include some interpolation + * + * @param string|array $directiveName + * @return string + * @throws CompilerException + */ + protected function compileDirectiveName($directiveName) + { + if (is_string($directiveName)) { + return $directiveName; + } + + return $this->compileValue($directiveName); + } + + /** + * Compile at-root + * + * @param \ScssPhp\ScssPhp\Block $block + * + * @return void + */ + protected function compileAtRoot(Block $block) + { + assert($block instanceof AtRootBlock); + $env = $this->pushEnv($block); + $envs = $this->compactEnv($env); + list($with, $without) = $this->compileWith(isset($block->with) ? $block->with : null); + + // wrap inline selector + if ($block->selector) { + $wrapped = new Block(); + $wrapped->sourceName = $block->sourceName; + $wrapped->sourceIndex = $block->sourceIndex; + $wrapped->sourceLine = $block->sourceLine; + $wrapped->sourceColumn = $block->sourceColumn; + $wrapped->selectors = $block->selector; + $wrapped->comments = []; + $wrapped->parent = $block; + $wrapped->children = $block->children; + $wrapped->selfParent = $block->selfParent; + + $block->children = [[Type::T_BLOCK, $wrapped]]; + $block->selector = null; + } + + $selfParent = $block->selfParent; + assert($selfParent !== null, 'at-root blocks must have a selfParent set.'); + + if ( + ! $selfParent->selectors && + isset($block->parent) && $block->parent && + isset($block->parent->selectors) && $block->parent->selectors + ) { + $selfParent = $block->parent; + } + + $this->env = $this->filterWithWithout($envs, $with, $without); + + $saveScope = $this->scope; + $this->scope = $this->filterScopeWithWithout($saveScope, $with, $without); + + // propagate selfParent to the children where they still can be useful + $this->compileChildrenNoReturn($block->children, $this->scope, $selfParent); + + $this->scope = $this->completeScope($this->scope, $saveScope); + $this->scope = $saveScope; + $this->env = $this->extractEnv($envs); + + $this->popEnv(); + } + + /** + * Filter at-root scope depending on with/without option + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $scope + * @param array $with + * @param array $without + * + * @return OutputBlock + */ + protected function filterScopeWithWithout($scope, $with, $without) + { + $filteredScopes = []; + $childStash = []; + + if ($scope->type === Type::T_ROOT) { + return $scope; + } + + // start from the root + while ($scope->parent && $scope->parent->type !== Type::T_ROOT) { + array_unshift($childStash, $scope); + $scope = $scope->parent; + } + + for (;;) { + if (! $scope) { + break; + } + + if ($this->isWith($scope, $with, $without)) { + $s = clone $scope; + $s->children = []; + $s->lines = []; + $s->parent = null; + + if ($s->type !== Type::T_MEDIA && $s->type !== Type::T_DIRECTIVE) { + $s->selectors = []; + } + + $filteredScopes[] = $s; + } + + if (\count($childStash)) { + $scope = array_shift($childStash); + } elseif ($scope->children) { + $scope = end($scope->children); + } else { + $scope = null; + } + } + + if (! \count($filteredScopes)) { + return $this->rootBlock; + } + + $newScope = array_shift($filteredScopes); + $newScope->parent = $this->rootBlock; + + $this->rootBlock->children[] = $newScope; + + $p = &$newScope; + + while (\count($filteredScopes)) { + $s = array_shift($filteredScopes); + $s->parent = $p; + $p->children[] = $s; + $newScope = &$p->children[0]; + $p = &$p->children[0]; + } + + return $newScope; + } + + /** + * found missing selector from a at-root compilation in the previous scope + * (if at-root is just enclosing a property, the selector is in the parent tree) + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $scope + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $previousScope + * + * @return OutputBlock + */ + protected function completeScope($scope, $previousScope) + { + if (! $scope->type && (! $scope->selectors || ! \count($scope->selectors)) && \count($scope->lines)) { + $scope->selectors = $this->findScopeSelectors($previousScope, $scope->depth); + } + + if ($scope->children) { + foreach ($scope->children as $k => $c) { + $scope->children[$k] = $this->completeScope($c, $previousScope); + } + } + + return $scope; + } + + /** + * Find a selector by the depth node in the scope + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $scope + * @param int $depth + * + * @return array + */ + protected function findScopeSelectors($scope, $depth) + { + if ($scope->depth === $depth && $scope->selectors) { + return $scope->selectors; + } + + if ($scope->children) { + foreach (array_reverse($scope->children) as $c) { + if ($s = $this->findScopeSelectors($c, $depth)) { + return $s; + } + } + } + + return []; + } + + /** + * Compile @at-root's with: inclusion / without: exclusion into 2 lists uses to filter scope/env later + * + * @param array|null $withCondition + * + * @return array + * + * @phpstan-return array{array, array} + */ + protected function compileWith($withCondition) + { + // just compile what we have in 2 lists + $with = []; + $without = ['rule' => true]; + + if ($withCondition) { + if ($withCondition[0] === Type::T_INTERPOLATE) { + $w = $this->compileValue($withCondition); + + $buffer = "($w)"; + $parser = $this->parserFactory(__METHOD__); + + if ($parser->parseValue($buffer, $reParsedWith)) { + $withCondition = $reParsedWith; + } + } + + $withConfig = $this->mapGet($withCondition, static::$with); + if ($withConfig !== null) { + $without = []; // cancel the default + $list = $this->coerceList($withConfig); + + foreach ($list[2] as $item) { + $keyword = $this->compileStringContent($this->coerceString($item)); + + $with[$keyword] = true; + } + } + + $withoutConfig = $this->mapGet($withCondition, static::$without); + if ($withoutConfig !== null) { + $without = []; // cancel the default + $list = $this->coerceList($withoutConfig); + + foreach ($list[2] as $item) { + $keyword = $this->compileStringContent($this->coerceString($item)); + + $without[$keyword] = true; + } + } + } + + return [$with, $without]; + } + + /** + * Filter env stack + * + * @param Environment[] $envs + * @param array $with + * @param array $without + * + * @return Environment + * + * @phpstan-param non-empty-array $envs + */ + protected function filterWithWithout($envs, $with, $without) + { + $filtered = []; + + foreach ($envs as $e) { + if ($e->block && ! $this->isWith($e->block, $with, $without)) { + $ec = clone $e; + $ec->block = null; + $ec->selectors = []; + + $filtered[] = $ec; + } else { + $filtered[] = $e; + } + } + + return $this->extractEnv($filtered); + } + + /** + * Filter WITH rules + * + * @param \ScssPhp\ScssPhp\Block|\ScssPhp\ScssPhp\Formatter\OutputBlock $block + * @param array $with + * @param array $without + * + * @return bool + */ + protected function isWith($block, $with, $without) + { + if (isset($block->type)) { + if ($block->type === Type::T_MEDIA) { + return $this->testWithWithout('media', $with, $without); + } + + if ($block->type === Type::T_DIRECTIVE) { + assert($block instanceof DirectiveBlock || $block instanceof OutputBlock); + if (isset($block->name)) { + return $this->testWithWithout($this->compileDirectiveName($block->name), $with, $without); + } elseif (isset($block->selectors) && preg_match(',@(\w+),ims', json_encode($block->selectors), $m)) { + return $this->testWithWithout($m[1], $with, $without); + } else { + return $this->testWithWithout('???', $with, $without); + } + } + } elseif (isset($block->selectors)) { + // a selector starting with number is a keyframe rule + if (\count($block->selectors)) { + $s = reset($block->selectors); + + while (\is_array($s)) { + $s = reset($s); + } + + if (\is_object($s) && $s instanceof Number) { + return $this->testWithWithout('keyframes', $with, $without); + } + } + + return $this->testWithWithout('rule', $with, $without); + } + + return true; + } + + /** + * Test a single type of block against with/without lists + * + * @param string $what + * @param array $with + * @param array $without + * + * @return bool + * true if the block should be kept, false to reject + */ + protected function testWithWithout($what, $with, $without) + { + // if without, reject only if in the list (or 'all' is in the list) + if (\count($without)) { + return (isset($without[$what]) || isset($without['all'])) ? false : true; + } + + // otherwise reject all what is not in the with list + return (isset($with[$what]) || isset($with['all'])) ? true : false; + } + + + /** + * Compile keyframe block + * + * @param \ScssPhp\ScssPhp\Block $block + * @param string[] $selectors + * + * @return void + */ + protected function compileKeyframeBlock(Block $block, $selectors) + { + $env = $this->pushEnv($block); + + $envs = $this->compactEnv($env); + + $this->env = $this->extractEnv(array_filter($envs, function (Environment $e) { + return ! isset($e->block->selectors); + })); + + $this->scope = $this->makeOutputBlock($block->type, $selectors); + $this->scope->depth = 1; + $this->scope->parent->children[] = $this->scope; + + $this->compileChildrenNoReturn($block->children, $this->scope); + + $this->scope = $this->scope->parent; + $this->env = $this->extractEnv($envs); + + $this->popEnv(); + } + + /** + * Compile nested properties lines + * + * @param \ScssPhp\ScssPhp\Block $block + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * + * @return void + */ + protected function compileNestedPropertiesBlock(Block $block, OutputBlock $out) + { + assert($block instanceof NestedPropertyBlock); + $prefix = $this->compileValue($block->prefix) . '-'; + + $nested = $this->makeOutputBlock($block->type); + $nested->parent = $out; + + if ($block->hasValue) { + $nested->depth = $out->depth + 1; + } + + $out->children[] = $nested; + + foreach ($block->children as $child) { + switch ($child[0]) { + case Type::T_ASSIGN: + array_unshift($child[1][2], $prefix); + break; + + case Type::T_NESTED_PROPERTY: + assert($child[1] instanceof NestedPropertyBlock); + array_unshift($child[1]->prefix[2], $prefix); + break; + } + + $this->compileChild($child, $nested); + } + } + + /** + * Compile nested block + * + * @param \ScssPhp\ScssPhp\Block $block + * @param string[] $selectors + * + * @return void + */ + protected function compileNestedBlock(Block $block, $selectors) + { + $this->pushEnv($block); + + $this->scope = $this->makeOutputBlock($block->type, $selectors); + $this->scope->parent->children[] = $this->scope; + + // wrap assign children in a block + // except for @font-face + if (!$block instanceof DirectiveBlock || $this->compileDirectiveName($block->name) !== 'font-face') { + // need wrapping? + $needWrapping = false; + + foreach ($block->children as $child) { + if ($child[0] === Type::T_ASSIGN) { + $needWrapping = true; + break; + } + } + + if ($needWrapping) { + $wrapped = new Block(); + $wrapped->sourceName = $block->sourceName; + $wrapped->sourceIndex = $block->sourceIndex; + $wrapped->sourceLine = $block->sourceLine; + $wrapped->sourceColumn = $block->sourceColumn; + $wrapped->selectors = []; + $wrapped->comments = []; + $wrapped->parent = $block; + $wrapped->children = $block->children; + $wrapped->selfParent = $block->selfParent; + + $block->children = [[Type::T_BLOCK, $wrapped]]; + } + } + + $this->compileChildrenNoReturn($block->children, $this->scope); + + $this->scope = $this->scope->parent; + + $this->popEnv(); + } + + /** + * Recursively compiles a block. + * + * A block is analogous to a CSS block in most cases. A single SCSS document + * is encapsulated in a block when parsed, but it does not have parent tags + * so all of its children appear on the root level when compiled. + * + * Blocks are made up of selectors and children. + * + * The children of a block are just all the blocks that are defined within. + * + * Compiling the block involves pushing a fresh environment on the stack, + * and iterating through the props, compiling each one. + * + * @see Compiler::compileChild() + * + * @param \ScssPhp\ScssPhp\Block $block + * + * @return void + */ + protected function compileBlock(Block $block) + { + $env = $this->pushEnv($block); + $env->selectors = $this->evalSelectors($block->selectors); + + $out = $this->makeOutputBlock(null); + + $this->scope->children[] = $out; + + if (\count($block->children)) { + $out->selectors = $this->multiplySelectors($env, $block->selfParent); + + // propagate selfParent to the children where they still can be useful + $selfParentSelectors = null; + + if (isset($block->selfParent->selectors)) { + $selfParentSelectors = $block->selfParent->selectors; + $block->selfParent->selectors = $out->selectors; + } + + $this->compileChildrenNoReturn($block->children, $out, $block->selfParent); + + // and revert for the following children of the same block + if ($selfParentSelectors) { + $block->selfParent->selectors = $selfParentSelectors; + } + } + + $this->popEnv(); + } + + + /** + * Compile the value of a comment that can have interpolation + * + * @param array $value + * @param bool $pushEnv + * + * @return string + */ + protected function compileCommentValue($value, $pushEnv = false) + { + $c = $value[1]; + + if (isset($value[2])) { + if ($pushEnv) { + $this->pushEnv(); + } + + try { + $c = $this->compileValue($value[2]); + } catch (SassScriptException $e) { + $this->logger->warn('Ignoring interpolation errors in multiline comments is deprecated and will be removed in ScssPhp 2.0. ' . $this->addLocationToMessage($e->getMessage()), true); + // ignore error in comment compilation which are only interpolation + } catch (SassException $e) { + $this->logger->warn('Ignoring interpolation errors in multiline comments is deprecated and will be removed in ScssPhp 2.0. ' . $e->getMessage(), true); + // ignore error in comment compilation which are only interpolation + } + + if ($pushEnv) { + $this->popEnv(); + } + } + + return $c; + } + + /** + * Compile root level comment + * + * @param array $block + * + * @return void + */ + protected function compileComment($block) + { + $out = $this->makeOutputBlock(Type::T_COMMENT); + $out->lines[] = $this->compileCommentValue($block, true); + + $this->scope->children[] = $out; + } + + /** + * Evaluate selectors + * + * @param array $selectors + * + * @return array + */ + protected function evalSelectors($selectors) + { + $this->shouldEvaluate = false; + + $selectors = array_map([$this, 'evalSelector'], $selectors); + + // after evaluating interpolates, we might need a second pass + if ($this->shouldEvaluate) { + $selectors = $this->replaceSelfSelector($selectors, '&'); + $buffer = $this->collapseSelectors($selectors); + $parser = $this->parserFactory(__METHOD__); + + try { + $isValid = $parser->parseSelector($buffer, $newSelectors, true); + } catch (ParserException $e) { + throw $this->error($e->getMessage()); + } + + if ($isValid) { + $selectors = array_map([$this, 'evalSelector'], $newSelectors); + } + } + + return $selectors; + } + + /** + * Evaluate selector + * + * @param array $selector + * + * @return array + */ + protected function evalSelector($selector) + { + return array_map([$this, 'evalSelectorPart'], $selector); + } + + /** + * Evaluate selector part; replaces all the interpolates, stripping quotes + * + * @param array $part + * + * @return array + */ + protected function evalSelectorPart($part) + { + foreach ($part as &$p) { + if (\is_array($p) && ($p[0] === Type::T_INTERPOLATE || $p[0] === Type::T_STRING)) { + $p = $this->compileValue($p); + + // force re-evaluation if self char or non standard char + if (preg_match(',[^\w-],', $p)) { + $this->shouldEvaluate = true; + } + } elseif ( + \is_string($p) && \strlen($p) >= 2 && + ($first = $p[0]) && ($first === '"' || $first === "'") && + substr($p, -1) === $first + ) { + $p = substr($p, 1, -1); + } + } + + return $this->flattenSelectorSingle($part); + } + + /** + * Collapse selectors + * + * @param array $selectors + * + * @return string + */ + protected function collapseSelectors($selectors) + { + $parts = []; + + foreach ($selectors as $selector) { + $output = []; + + foreach ($selector as $node) { + $compound = ''; + + array_walk_recursive( + $node, + function ($value, $key) use (&$compound) { + $compound .= $value; + } + ); + + $output[] = $compound; + } + + $parts[] = implode(' ', $output); + } + + return implode(', ', $parts); + } + + /** + * Collapse selectors + * + * @param array $selectors + * + * @return array + */ + private function collapseSelectorsAsList($selectors) + { + $parts = []; + + foreach ($selectors as $selector) { + $output = []; + $glueNext = false; + + foreach ($selector as $node) { + $compound = ''; + + array_walk_recursive( + $node, + function ($value, $key) use (&$compound) { + $compound .= $value; + } + ); + + if ($this->isImmediateRelationshipCombinator($compound)) { + if (\count($output)) { + $output[\count($output) - 1] .= ' ' . $compound; + } else { + $output[] = $compound; + } + + $glueNext = true; + } elseif ($glueNext) { + $output[\count($output) - 1] .= ' ' . $compound; + $glueNext = false; + } else { + $output[] = $compound; + } + } + + foreach ($output as &$o) { + $o = [Type::T_STRING, '', [$o]]; + } + + $parts[] = [Type::T_LIST, ' ', $output]; + } + + return [Type::T_LIST, ',', $parts]; + } + + /** + * Parse down the selector and revert [self] to "&" before a reparsing + * + * @param array $selectors + * @param string|null $replace + * + * @return array + */ + protected function replaceSelfSelector($selectors, $replace = null) + { + foreach ($selectors as &$part) { + if (\is_array($part)) { + if ($part === [Type::T_SELF]) { + if (\is_null($replace)) { + $replace = $this->reduce([Type::T_SELF]); + $replace = $this->compileValue($replace); + } + $part = $replace; + } else { + $part = $this->replaceSelfSelector($part, $replace); + } + } + } + + return $selectors; + } + + /** + * Flatten selector single; joins together .classes and #ids + * + * @param array $single + * + * @return array + */ + protected function flattenSelectorSingle($single) + { + $joined = []; + + foreach ($single as $part) { + if ( + empty($joined) || + ! \is_string($part) || + preg_match('/[\[.:#%]/', $part) + ) { + $joined[] = $part; + continue; + } + + if (\is_array(end($joined))) { + $joined[] = $part; + } else { + $joined[\count($joined) - 1] .= $part; + } + } + + return $joined; + } + + /** + * Compile selector to string; self(&) should have been replaced by now + * + * @param string|array $selector + * + * @return string + */ + protected function compileSelector($selector) + { + if (! \is_array($selector)) { + return $selector; // media and the like + } + + return implode( + ' ', + array_map( + [$this, 'compileSelectorPart'], + $selector + ) + ); + } + + /** + * Compile selector part + * + * @param array $piece + * + * @return string + */ + protected function compileSelectorPart($piece) + { + foreach ($piece as &$p) { + if (! \is_array($p)) { + continue; + } + + switch ($p[0]) { + case Type::T_SELF: + $p = '&'; + break; + + default: + $p = $this->compileValue($p); + break; + } + } + + return implode($piece); + } + + /** + * Has selector placeholder? + * + * @param array $selector + * + * @return bool + */ + protected function hasSelectorPlaceholder($selector) + { + if (! \is_array($selector)) { + return false; + } + + foreach ($selector as $parts) { + foreach ($parts as $part) { + if (\strlen($part) && '%' === $part[0]) { + return true; + } + } + } + + return false; + } + + /** + * @param string $name + * + * @return void + */ + protected function pushCallStack($name = '') + { + $this->callStack[] = [ + 'n' => $name, + Parser::SOURCE_INDEX => $this->sourceIndex, + Parser::SOURCE_LINE => $this->sourceLine, + Parser::SOURCE_COLUMN => $this->sourceColumn + ]; + + // infinite calling loop + if (\count($this->callStack) > 25000) { + // not displayed but you can var_dump it to deep debug + $msg = $this->callStackMessage(true, 100); + $msg = 'Infinite calling loop'; + + throw $this->error($msg); + } + } + + /** + * @return void + */ + protected function popCallStack() + { + array_pop($this->callStack); + } + + /** + * Compile children and return result + * + * @param array $stms + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * @param string $traceName + * + * @return array|Number|null + */ + protected function compileChildren($stms, OutputBlock $out, $traceName = '') + { + $this->pushCallStack($traceName); + + foreach ($stms as $stm) { + $ret = $this->compileChild($stm, $out); + + if (isset($ret)) { + $this->popCallStack(); + + return $ret; + } + } + + $this->popCallStack(); + + return null; + } + + /** + * Compile children and throw exception if unexpected `@return` + * + * @param array $stms + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * @param \ScssPhp\ScssPhp\Block $selfParent + * @param string $traceName + * + * @return void + * + * @throws \Exception + */ + protected function compileChildrenNoReturn($stms, OutputBlock $out, $selfParent = null, $traceName = '') + { + $this->pushCallStack($traceName); + + foreach ($stms as $stm) { + if ($selfParent && isset($stm[1]) && \is_object($stm[1]) && $stm[1] instanceof Block) { + $stm[1]->selfParent = $selfParent; + $ret = $this->compileChild($stm, $out); + $stm[1]->selfParent = null; + } elseif ($selfParent && \in_array($stm[0], [Type::T_INCLUDE, Type::T_EXTEND])) { + $stm['selfParent'] = $selfParent; + $ret = $this->compileChild($stm, $out); + unset($stm['selfParent']); + } else { + $ret = $this->compileChild($stm, $out); + } + + if (isset($ret)) { + throw $this->error('@return may only be used within a function'); + } + } + + $this->popCallStack(); + } + + + /** + * evaluate media query : compile internal value keeping the structure unchanged + * + * @param array $queryList + * + * @return array + */ + protected function evaluateMediaQuery($queryList) + { + static $parser = null; + + $outQueryList = []; + + foreach ($queryList as $kql => $query) { + $shouldReparse = false; + + foreach ($query as $kq => $q) { + for ($i = 1; $i < \count($q); $i++) { + $value = $this->compileValue($q[$i]); + + // the parser had no mean to know if media type or expression if it was an interpolation + // so you need to reparse if the T_MEDIA_TYPE looks like anything else a media type + if ( + $q[0] == Type::T_MEDIA_TYPE && + (strpos($value, '(') !== false || + strpos($value, ')') !== false || + strpos($value, ':') !== false || + strpos($value, ',') !== false) + ) { + $shouldReparse = true; + } + + $queryList[$kql][$kq][$i] = [Type::T_KEYWORD, $value]; + } + } + + if ($shouldReparse) { + if (\is_null($parser)) { + $parser = $this->parserFactory(__METHOD__); + } + + $queryString = $this->compileMediaQuery([$queryList[$kql]]); + $queryString = reset($queryString); + + if (strpos($queryString, '@media ') === 0) { + $queryString = substr($queryString, 7); + $queries = []; + + if ($parser->parseMediaQueryList($queryString, $queries)) { + $queries = $this->evaluateMediaQuery($queries[2]); + + while (\count($queries)) { + $outQueryList[] = array_shift($queries); + } + + continue; + } + } + } + + $outQueryList[] = $queryList[$kql]; + } + + return $outQueryList; + } + + /** + * Compile media query + * + * @param array $queryList + * + * @return string[] + */ + protected function compileMediaQuery($queryList) + { + $start = '@media '; + $default = trim($start); + $out = []; + $current = ''; + + foreach ($queryList as $query) { + $type = null; + $parts = []; + + $mediaTypeOnly = true; + + foreach ($query as $q) { + if ($q[0] !== Type::T_MEDIA_TYPE) { + $mediaTypeOnly = false; + break; + } + } + + foreach ($query as $q) { + switch ($q[0]) { + case Type::T_MEDIA_TYPE: + $newType = array_map([$this, 'compileValue'], \array_slice($q, 1)); + + // combining not and anything else than media type is too risky and should be avoided + if (! $mediaTypeOnly) { + if (\in_array(Type::T_NOT, $newType) || ($type && \in_array(Type::T_NOT, $type) )) { + if ($type) { + array_unshift($parts, implode(' ', array_filter($type))); + } + + if (! empty($parts)) { + if (\strlen($current)) { + $current .= $this->formatter->tagSeparator; + } + + $current .= implode(' and ', $parts); + } + + if ($current) { + $out[] = $start . $current; + } + + $current = ''; + $type = null; + $parts = []; + } + } + + if ($newType === ['all'] && $default) { + $default = $start . 'all'; + } + + // all can be safely ignored and mixed with whatever else + if ($newType !== ['all']) { + if ($type) { + $type = $this->mergeMediaTypes($type, $newType); + + if (empty($type)) { + // merge failed : ignore this query that is not valid, skip to the next one + $parts = []; + $default = ''; // if everything fail, no @media at all + continue 3; + } + } else { + $type = $newType; + } + } + break; + + case Type::T_MEDIA_EXPRESSION: + if (isset($q[2])) { + $parts[] = '(' + . $this->compileValue($q[1]) + . $this->formatter->assignSeparator + . $this->compileValue($q[2]) + . ')'; + } else { + $parts[] = '(' + . $this->compileValue($q[1]) + . ')'; + } + break; + + case Type::T_MEDIA_VALUE: + $parts[] = $this->compileValue($q[1]); + break; + } + } + + if ($type) { + array_unshift($parts, implode(' ', array_filter($type))); + } + + if (! empty($parts)) { + if (\strlen($current)) { + $current .= $this->formatter->tagSeparator; + } + + $current .= implode(' and ', $parts); + } + } + + if ($current) { + $out[] = $start . $current; + } + + // no @media type except all, and no conflict? + if (! $out && $default) { + $out[] = $default; + } + + return $out; + } + + /** + * Merge direct relationships between selectors + * + * @param array $selectors1 + * @param array $selectors2 + * + * @return array + */ + protected function mergeDirectRelationships($selectors1, $selectors2) + { + if (empty($selectors1) || empty($selectors2)) { + return array_merge($selectors1, $selectors2); + } + + $part1 = end($selectors1); + $part2 = end($selectors2); + + if (! $this->isImmediateRelationshipCombinator($part1[0]) && $part1 !== $part2) { + return array_merge($selectors1, $selectors2); + } + + $merged = []; + + do { + $part1 = array_pop($selectors1); + $part2 = array_pop($selectors2); + + if (! $this->isImmediateRelationshipCombinator($part1[0]) && $part1 !== $part2) { + if ($this->isImmediateRelationshipCombinator(reset($merged)[0])) { + array_unshift($merged, [$part1[0] . $part2[0]]); + $merged = array_merge($selectors1, $selectors2, $merged); + } else { + $merged = array_merge($selectors1, [$part1], $selectors2, [$part2], $merged); + } + + break; + } + + array_unshift($merged, $part1); + } while (! empty($selectors1) && ! empty($selectors2)); + + return $merged; + } + + /** + * Merge media types + * + * @param array $type1 + * @param array $type2 + * + * @return array|null + */ + protected function mergeMediaTypes($type1, $type2) + { + if (empty($type1)) { + return $type2; + } + + if (empty($type2)) { + return $type1; + } + + if (\count($type1) > 1) { + $m1 = strtolower($type1[0]); + $t1 = strtolower($type1[1]); + } else { + $m1 = ''; + $t1 = strtolower($type1[0]); + } + + if (\count($type2) > 1) { + $m2 = strtolower($type2[0]); + $t2 = strtolower($type2[1]); + } else { + $m2 = ''; + $t2 = strtolower($type2[0]); + } + + if (($m1 === Type::T_NOT) ^ ($m2 === Type::T_NOT)) { + if ($t1 === $t2) { + return null; + } + + return [ + $m1 === Type::T_NOT ? $m2 : $m1, + $m1 === Type::T_NOT ? $t2 : $t1, + ]; + } + + if ($m1 === Type::T_NOT && $m2 === Type::T_NOT) { + // CSS has no way of representing "neither screen nor print" + if ($t1 !== $t2) { + return null; + } + + return [Type::T_NOT, $t1]; + } + + if ($t1 !== $t2) { + return null; + } + + // t1 == t2, neither m1 nor m2 are "not" + return [empty($m1) ? $m2 : $m1, $t1]; + } + + /** + * Compile import; returns true if the value was something that could be imported + * + * @param array $rawPath + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * @param bool $once + * + * @return bool + */ + protected function compileImport($rawPath, OutputBlock $out, $once = false) + { + if ($rawPath[0] === Type::T_STRING) { + $path = $this->compileStringContent($rawPath); + + if (strpos($path, 'url(') !== 0 && $filePath = $this->findImport($path, $this->currentDirectory)) { + $this->registerImport($this->currentDirectory, $path, $filePath); + + if (! $once || ! \in_array($filePath, $this->importedFiles)) { + $this->importFile($filePath, $out); + $this->importedFiles[] = $filePath; + } + + return true; + } + + $this->appendRootDirective('@import ' . $this->compileImportPath($rawPath) . ';', $out); + + return false; + } + + if ($rawPath[0] === Type::T_LIST) { + // handle a list of strings + if (\count($rawPath[2]) === 0) { + return false; + } + + foreach ($rawPath[2] as $path) { + if ($path[0] !== Type::T_STRING) { + $this->appendRootDirective('@import ' . $this->compileImportPath($rawPath) . ';', $out); + + return false; + } + } + + foreach ($rawPath[2] as $path) { + $this->compileImport($path, $out, $once); + } + + return true; + } + + $this->appendRootDirective('@import ' . $this->compileImportPath($rawPath) . ';', $out); + + return false; + } + + /** + * @param array $rawPath + * @return string + * @throws CompilerException + */ + protected function compileImportPath($rawPath) + { + $path = $this->compileValue($rawPath); + + // case url() without quotes : suppress \r \n remaining in the path + // if this is a real string there can not be CR or LF char + if (strpos($path, 'url(') === 0) { + $path = str_replace(array("\r", "\n"), array('', ' '), $path); + } else { + // if this is a file name in a string, spaces should be escaped + $path = $this->reduce($rawPath); + $path = $this->escapeImportPathString($path); + $path = $this->compileValue($path); + } + + return $path; + } + + /** + * @param array $path + * @return array + * @throws CompilerException + */ + protected function escapeImportPathString($path) + { + switch ($path[0]) { + case Type::T_LIST: + foreach ($path[2] as $k => $v) { + $path[2][$k] = $this->escapeImportPathString($v); + } + break; + case Type::T_STRING: + if ($path[1]) { + $path = $this->compileValue($path); + $path = str_replace(' ', '\\ ', $path); + $path = [Type::T_KEYWORD, $path]; + } + break; + } + + return $path; + } + + /** + * Append a root directive like @import or @charset as near as the possible from the source code + * (keeping before comments, @import and @charset coming before in the source code) + * + * @param string $line + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * @param array $allowed + * + * @return void + */ + protected function appendRootDirective($line, $out, $allowed = [Type::T_COMMENT]) + { + $root = $out; + + while ($root->parent) { + $root = $root->parent; + } + + $i = 0; + + while ($i < \count($root->children)) { + if (! isset($root->children[$i]->type) || ! \in_array($root->children[$i]->type, $allowed)) { + break; + } + + $i++; + } + + // remove incompatible children from the bottom of the list + $saveChildren = []; + + while ($i < \count($root->children)) { + $saveChildren[] = array_pop($root->children); + } + + // insert the directive as a comment + $child = $this->makeOutputBlock(Type::T_COMMENT); + $child->lines[] = $line; + $child->sourceName = $this->sourceNames[$this->sourceIndex] ?: '(stdin)'; + $child->sourceLine = $this->sourceLine; + $child->sourceColumn = $this->sourceColumn; + + $root->children[] = $child; + + // repush children + while (\count($saveChildren)) { + $root->children[] = array_pop($saveChildren); + } + } + + /** + * Append lines to the current output block: + * directly to the block or through a child if necessary + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * @param string $type + * @param string $line + * + * @return void + */ + protected function appendOutputLine(OutputBlock $out, $type, $line) + { + $outWrite = &$out; + + // check if it's a flat output or not + if (\count($out->children)) { + $lastChild = &$out->children[\count($out->children) - 1]; + + if ( + $lastChild->depth === $out->depth && + \is_null($lastChild->selectors) && + ! \count($lastChild->children) + ) { + $outWrite = $lastChild; + } else { + $nextLines = $this->makeOutputBlock($type); + $nextLines->parent = $out; + $nextLines->depth = $out->depth; + + $out->children[] = $nextLines; + $outWrite = &$nextLines; + } + } + + $outWrite->lines[] = $line; + } + + /** + * Compile child; returns a value to halt execution + * + * @param array $child + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * + * @return array|Number|null + */ + protected function compileChild($child, OutputBlock $out) + { + if (isset($child[Parser::SOURCE_LINE])) { + $this->sourceIndex = isset($child[Parser::SOURCE_INDEX]) ? $child[Parser::SOURCE_INDEX] : null; + $this->sourceLine = isset($child[Parser::SOURCE_LINE]) ? $child[Parser::SOURCE_LINE] : -1; + $this->sourceColumn = isset($child[Parser::SOURCE_COLUMN]) ? $child[Parser::SOURCE_COLUMN] : -1; + } elseif (\is_array($child) && isset($child[1]->sourceLine)) { + $this->sourceIndex = $child[1]->sourceIndex; + $this->sourceLine = $child[1]->sourceLine; + $this->sourceColumn = $child[1]->sourceColumn; + } elseif (! empty($out->sourceLine) && ! empty($out->sourceName)) { + $this->sourceLine = $out->sourceLine; + $sourceIndex = array_search($out->sourceName, $this->sourceNames); + $this->sourceColumn = $out->sourceColumn; + + if ($sourceIndex === false) { + $sourceIndex = null; + } + $this->sourceIndex = $sourceIndex; + } + + switch ($child[0]) { + case Type::T_SCSSPHP_IMPORT_ONCE: + $rawPath = $this->reduce($child[1]); + + $this->compileImport($rawPath, $out, true); + break; + + case Type::T_IMPORT: + $rawPath = $this->reduce($child[1]); + + $this->compileImport($rawPath, $out); + break; + + case Type::T_DIRECTIVE: + $this->compileDirective($child[1], $out); + break; + + case Type::T_AT_ROOT: + $this->compileAtRoot($child[1]); + break; + + case Type::T_MEDIA: + $this->compileMedia($child[1]); + break; + + case Type::T_BLOCK: + $this->compileBlock($child[1]); + break; + + case Type::T_CHARSET: + break; + + case Type::T_CUSTOM_PROPERTY: + list(, $name, $value) = $child; + $compiledName = $this->compileValue($name); + + // if the value reduces to null from something else then + // the property should be discarded + if ($value[0] !== Type::T_NULL) { + $value = $this->reduce($value); + + if ($value[0] === Type::T_NULL || $value === static::$nullString) { + break; + } + } + + $compiledValue = $this->compileValue($value); + + $line = $this->formatter->customProperty( + $compiledName, + $compiledValue + ); + + $this->appendOutputLine($out, Type::T_ASSIGN, $line); + break; + + case Type::T_ASSIGN: + list(, $name, $value) = $child; + + if ($name[0] === Type::T_VARIABLE) { + $flags = isset($child[3]) ? $child[3] : []; + $isDefault = \in_array('!default', $flags); + $isGlobal = \in_array('!global', $flags); + + if ($isGlobal) { + $this->set($name[1], $this->reduce($value), false, $this->rootEnv, $value); + break; + } + + $shouldSet = $isDefault && + (\is_null($result = $this->get($name[1], false)) || + $result === static::$null); + + if (! $isDefault || $shouldSet) { + $this->set($name[1], $this->reduce($value), true, null, $value); + } + break; + } + + $compiledName = $this->compileValue($name); + + // handle shorthand syntaxes : size / line-height... + if (\in_array($compiledName, ['font', 'grid-row', 'grid-column', 'border-radius'])) { + if ($value[0] === Type::T_VARIABLE) { + // if the font value comes from variable, the content is already reduced + // (i.e., formulas were already calculated), so we need the original unreduced value + $value = $this->get($value[1], true, null, true); + } + + $shorthandValue=&$value; + + $shorthandDividerNeedsUnit = false; + $maxListElements = null; + $maxShorthandDividers = 1; + + switch ($compiledName) { + case 'border-radius': + $maxListElements = 4; + $shorthandDividerNeedsUnit = true; + break; + } + + if ($compiledName === 'font' && $value[0] === Type::T_LIST && $value[1] === ',') { + // this is the case if more than one font is given: example: "font: 400 1em/1.3 arial,helvetica" + // we need to handle the first list element + $shorthandValue=&$value[2][0]; + } + + if ($shorthandValue[0] === Type::T_EXPRESSION && $shorthandValue[1] === '/') { + $revert = true; + + if ($shorthandDividerNeedsUnit) { + $divider = $shorthandValue[3]; + + if (\is_array($divider)) { + $divider = $this->reduce($divider, true); + } + + if ($divider instanceof Number && \intval($divider->getDimension()) && $divider->unitless()) { + $revert = false; + } + } + + if ($revert) { + $shorthandValue = $this->expToString($shorthandValue); + } + } elseif ($shorthandValue[0] === Type::T_LIST) { + foreach ($shorthandValue[2] as &$item) { + if ($item[0] === Type::T_EXPRESSION && $item[1] === '/') { + if ($maxShorthandDividers > 0) { + $revert = true; + + // if the list of values is too long, this has to be a shorthand, + // otherwise it could be a real division + if (\is_null($maxListElements) || \count($shorthandValue[2]) <= $maxListElements) { + if ($shorthandDividerNeedsUnit) { + $divider = $item[3]; + + if (\is_array($divider)) { + $divider = $this->reduce($divider, true); + } + + if ($divider instanceof Number && \intval($divider->getDimension()) && $divider->unitless()) { + $revert = false; + } + } + } + + if ($revert) { + $item = $this->expToString($item); + $maxShorthandDividers--; + } + } + } + } + } + } + + // if the value reduces to null from something else then + // the property should be discarded + if ($value[0] !== Type::T_NULL) { + $value = $this->reduce($value); + + if ($value[0] === Type::T_NULL || $value === static::$nullString) { + break; + } + } + + $compiledValue = $this->compileValue($value); + + // ignore empty value + if (\strlen($compiledValue)) { + $line = $this->formatter->property( + $compiledName, + $compiledValue + ); + $this->appendOutputLine($out, Type::T_ASSIGN, $line); + } + break; + + case Type::T_COMMENT: + if ($out->type === Type::T_ROOT) { + $this->compileComment($child); + break; + } + + $line = $this->compileCommentValue($child, true); + $this->appendOutputLine($out, Type::T_COMMENT, $line); + break; + + case Type::T_MIXIN: + case Type::T_FUNCTION: + list(, $block) = $child; + assert($block instanceof CallableBlock); + // the block need to be able to go up to it's parent env to resolve vars + $block->parentEnv = $this->getStoreEnv(); + $this->set(static::$namespaces[$block->type] . $block->name, $block, true); + break; + + case Type::T_EXTEND: + foreach ($child[1] as $sel) { + $replacedSel = $this->replaceSelfSelector($sel); + + if ($replacedSel !== $sel) { + throw $this->error('Parent selectors aren\'t allowed here.'); + } + + $results = $this->evalSelectors([$sel]); + + foreach ($results as $result) { + if (\count($result) !== 1) { + throw $this->error('complex selectors may not be extended.'); + } + + // only use the first one + $result = $result[0]; + $selectors = $out->selectors; + + if (! $selectors && isset($child['selfParent'])) { + $selectors = $this->multiplySelectors($this->env, $child['selfParent']); + } + + if (\count($result) > 1) { + $replacement = implode(', ', $result); + $fname = $this->getPrettyPath($this->sourceNames[$this->sourceIndex]); + $line = $this->sourceLine; + + $message = <<logger->warn($message); + } + + $this->pushExtends($result, $selectors, $child); + } + } + break; + + case Type::T_IF: + list(, $if) = $child; + assert($if instanceof IfBlock); + + if ($this->isTruthy($this->reduce($if->cond, true))) { + return $this->compileChildren($if->children, $out); + } + + foreach ($if->cases as $case) { + if ( + $case instanceof ElseBlock || + $case instanceof ElseifBlock && $this->isTruthy($this->reduce($case->cond)) + ) { + return $this->compileChildren($case->children, $out); + } + } + break; + + case Type::T_EACH: + list(, $each) = $child; + assert($each instanceof EachBlock); + + $list = $this->coerceList($this->reduce($each->list), ',', true); + + $this->pushEnv(); + + foreach ($list[2] as $item) { + if (\count($each->vars) === 1) { + $this->set($each->vars[0], $item, true); + } else { + list(,, $values) = $this->coerceList($item); + + foreach ($each->vars as $i => $var) { + $this->set($var, isset($values[$i]) ? $values[$i] : static::$null, true); + } + } + + $ret = $this->compileChildren($each->children, $out); + + if ($ret) { + $store = $this->env->store; + $this->popEnv(); + $this->backPropagateEnv($store, $each->vars); + + return $ret; + } + } + $store = $this->env->store; + $this->popEnv(); + $this->backPropagateEnv($store, $each->vars); + + break; + + case Type::T_WHILE: + list(, $while) = $child; + assert($while instanceof WhileBlock); + + while ($this->isTruthy($this->reduce($while->cond, true))) { + $ret = $this->compileChildren($while->children, $out); + + if ($ret) { + return $ret; + } + } + break; + + case Type::T_FOR: + list(, $for) = $child; + assert($for instanceof ForBlock); + + $startNumber = $this->assertNumber($this->reduce($for->start, true)); + $endNumber = $this->assertNumber($this->reduce($for->end, true)); + + $start = $this->assertInteger($startNumber); + + $numeratorUnits = $startNumber->getNumeratorUnits(); + $denominatorUnits = $startNumber->getDenominatorUnits(); + + $end = $this->assertInteger($endNumber->coerce($numeratorUnits, $denominatorUnits)); + + $d = $start < $end ? 1 : -1; + + $this->pushEnv(); + + for (;;) { + if ( + (! $for->until && $start - $d == $end) || + ($for->until && $start == $end) + ) { + break; + } + + $this->set($for->var, new Number($start, $numeratorUnits, $denominatorUnits)); + $start += $d; + + $ret = $this->compileChildren($for->children, $out); + + if ($ret) { + $store = $this->env->store; + $this->popEnv(); + $this->backPropagateEnv($store, [$for->var]); + + return $ret; + } + } + + $store = $this->env->store; + $this->popEnv(); + $this->backPropagateEnv($store, [$for->var]); + + break; + + case Type::T_RETURN: + return $this->reduce($child[1], true); + + case Type::T_NESTED_PROPERTY: + $this->compileNestedPropertiesBlock($child[1], $out); + break; + + case Type::T_INCLUDE: + // including a mixin + list(, $name, $argValues, $content, $argUsing) = $child; + + $mixin = $this->get(static::$namespaces['mixin'] . $name, false); + + if (! $mixin) { + throw $this->error("Undefined mixin $name"); + } + + assert($mixin instanceof CallableBlock); + + $callingScope = $this->getStoreEnv(); + + // push scope, apply args + $this->pushEnv(); + $this->env->depth--; + + // Find the parent selectors in the env to be able to know what '&' refers to in the mixin + // and assign this fake parent to childs + $selfParent = null; + + if (isset($child['selfParent']) && isset($child['selfParent']->selectors)) { + $selfParent = $child['selfParent']; + } else { + $parentSelectors = $this->multiplySelectors($this->env); + + if ($parentSelectors) { + $parent = new Block(); + $parent->selectors = $parentSelectors; + + foreach ($mixin->children as $k => $child) { + if (isset($child[1]) && \is_object($child[1]) && $child[1] instanceof Block) { + $mixin->children[$k][1]->parent = $parent; + } + } + } + } + + // clone the stored content to not have its scope spoiled by a further call to the same mixin + // i.e., recursive @include of the same mixin + if (isset($content)) { + $copyContent = clone $content; + $copyContent->scope = clone $callingScope; + + $this->setRaw(static::$namespaces['special'] . 'content', $copyContent, $this->env); + } else { + $this->setRaw(static::$namespaces['special'] . 'content', null, $this->env); + } + + // save the "using" argument list for applying it to when "@content" is invoked + if (isset($argUsing)) { + $this->setRaw(static::$namespaces['special'] . 'using', $argUsing, $this->env); + } else { + $this->setRaw(static::$namespaces['special'] . 'using', null, $this->env); + } + + if (isset($mixin->args)) { + $this->applyArguments($mixin->args, $argValues); + } + + $this->env->marker = 'mixin'; + + if (! empty($mixin->parentEnv)) { + $this->env->declarationScopeParent = $mixin->parentEnv; + } else { + throw $this->error("@mixin $name() without parentEnv"); + } + + $this->compileChildrenNoReturn($mixin->children, $out, $selfParent, $this->env->marker . ' ' . $name); + + $this->popEnv(); + break; + + case Type::T_MIXIN_CONTENT: + $env = isset($this->storeEnv) ? $this->storeEnv : $this->env; + $content = $this->get(static::$namespaces['special'] . 'content', false, $env); + $argUsing = $this->get(static::$namespaces['special'] . 'using', false, $env); + $argContent = $child[1]; + + if (! $content) { + break; + } + + $storeEnv = $this->storeEnv; + $varsUsing = []; + + if (isset($argUsing) && isset($argContent)) { + // Get the arguments provided for the content with the names provided in the "using" argument list + $this->storeEnv = null; + $varsUsing = $this->applyArguments($argUsing, $argContent, false); + } + + // restore the scope from the @content + $this->storeEnv = $content->scope; + + // append the vars from using if any + foreach ($varsUsing as $name => $val) { + $this->set($name, $val, true, $this->storeEnv); + } + + $this->compileChildrenNoReturn($content->children, $out); + + $this->storeEnv = $storeEnv; + break; + + case Type::T_DEBUG: + list(, $value) = $child; + + $fname = $this->getPrettyPath($this->sourceNames[$this->sourceIndex]); + $line = $this->sourceLine; + $value = $this->compileDebugValue($value); + + $this->logger->debug("$fname:$line DEBUG: $value"); + break; + + case Type::T_WARN: + list(, $value) = $child; + + $fname = $this->getPrettyPath($this->sourceNames[$this->sourceIndex]); + $line = $this->sourceLine; + $value = $this->compileDebugValue($value); + + $this->logger->warn("$value\n on line $line of $fname"); + break; + + case Type::T_ERROR: + list(, $value) = $child; + + $fname = $this->getPrettyPath($this->sourceNames[$this->sourceIndex]); + $line = $this->sourceLine; + $value = $this->compileValue($this->reduce($value, true)); + + throw $this->error("File $fname on line $line ERROR: $value\n"); + + default: + throw $this->error("unknown child type: $child[0]"); + } + } + + /** + * Reduce expression to string + * + * @param array $exp + * @param bool $keepParens + * + * @return array + */ + protected function expToString($exp, $keepParens = false) + { + list(, $op, $left, $right, $inParens, $whiteLeft, $whiteRight) = $exp; + + $content = []; + + if ($keepParens && $inParens) { + $content[] = '('; + } + + $content[] = $this->reduce($left); + + if ($whiteLeft) { + $content[] = ' '; + } + + $content[] = $op; + + if ($whiteRight) { + $content[] = ' '; + } + + $content[] = $this->reduce($right); + + if ($keepParens && $inParens) { + $content[] = ')'; + } + + return [Type::T_STRING, '', $content]; + } + + /** + * Is truthy? + * + * @param array|Number $value + * + * @return bool + */ + public function isTruthy($value) + { + return $value !== static::$false && $value !== static::$null; + } + + /** + * Is the value a direct relationship combinator? + * + * @param string $value + * + * @return bool + */ + protected function isImmediateRelationshipCombinator($value) + { + return $value === '>' || $value === '+' || $value === '~'; + } + + /** + * Should $value cause its operand to eval + * + * @param array $value + * + * @return bool + */ + protected function shouldEval($value) + { + switch ($value[0]) { + case Type::T_EXPRESSION: + if ($value[1] === '/') { + return $this->shouldEval($value[2]) || $this->shouldEval($value[3]); + } + + // fall-thru + case Type::T_VARIABLE: + case Type::T_FUNCTION_CALL: + return true; + } + + return false; + } + + /** + * Reduce value + * + * @param array|Number $value + * @param bool $inExp + * + * @return array|Number + */ + protected function reduce($value, $inExp = false) + { + if ($value instanceof Number) { + return $value; + } + + switch ($value[0]) { + case Type::T_EXPRESSION: + list(, $op, $left, $right, $inParens) = $value; + + $opName = isset(static::$operatorNames[$op]) ? static::$operatorNames[$op] : $op; + $inExp = $inExp || $this->shouldEval($left) || $this->shouldEval($right); + + $left = $this->reduce($left, true); + + if ($op !== 'and' && $op !== 'or') { + $right = $this->reduce($right, true); + } + + // special case: looks like css shorthand + if ( + $opName == 'div' && ! $inParens && ! $inExp && + (($right[0] !== Type::T_NUMBER && isset($right[2]) && $right[2] != '') || + ($right[0] === Type::T_NUMBER && ! $right->unitless())) + ) { + return $this->expToString($value); + } + + $left = $this->coerceForExpression($left); + $right = $this->coerceForExpression($right); + $ltype = $left[0]; + $rtype = $right[0]; + + $ucOpName = ucfirst($opName); + $ucLType = ucfirst($ltype); + $ucRType = ucfirst($rtype); + + // this tries: + // 1. op[op name][left type][right type] + // 2. op[left type][right type] (passing the op as first arg + // 3. op[op name] + $fn = "op${ucOpName}${ucLType}${ucRType}"; + + if ( + \is_callable([$this, $fn]) || + (($fn = "op${ucLType}${ucRType}") && + \is_callable([$this, $fn]) && + $passOp = true) || + (($fn = "op${ucOpName}") && + \is_callable([$this, $fn]) && + $genOp = true) + ) { + $shouldEval = $inParens || $inExp; + + if (isset($passOp)) { + $out = $this->$fn($op, $left, $right, $shouldEval); + } else { + $out = $this->$fn($left, $right, $shouldEval); + } + + if (isset($out)) { + return $out; + } + } + + return $this->expToString($value); + + case Type::T_UNARY: + list(, $op, $exp, $inParens) = $value; + + $inExp = $inExp || $this->shouldEval($exp); + $exp = $this->reduce($exp); + + if ($exp instanceof Number) { + switch ($op) { + case '+': + return $exp; + + case '-': + return $exp->unaryMinus(); + } + } + + if ($op === 'not') { + if ($inExp || $inParens) { + if ($exp === static::$false || $exp === static::$null) { + return static::$true; + } + + return static::$false; + } + + $op = $op . ' '; + } + + return [Type::T_STRING, '', [$op, $exp]]; + + case Type::T_VARIABLE: + return $this->reduce($this->get($value[1])); + + case Type::T_LIST: + foreach ($value[2] as &$item) { + $item = $this->reduce($item); + } + unset($item); + + if (isset($value[3]) && \is_array($value[3])) { + foreach ($value[3] as &$item) { + $item = $this->reduce($item); + } + unset($item); + } + + return $value; + + case Type::T_MAP: + foreach ($value[1] as &$item) { + $item = $this->reduce($item); + } + + foreach ($value[2] as &$item) { + $item = $this->reduce($item); + } + + return $value; + + case Type::T_STRING: + foreach ($value[2] as &$item) { + if (\is_array($item) || $item instanceof Number) { + $item = $this->reduce($item); + } + } + + return $value; + + case Type::T_INTERPOLATE: + $value[1] = $this->reduce($value[1]); + + if ($inExp) { + return [Type::T_KEYWORD, $this->compileValue($value, false)]; + } + + return $value; + + case Type::T_FUNCTION_CALL: + return $this->fncall($value[1], $value[2]); + + case Type::T_SELF: + $selfParent = ! empty($this->env->block->selfParent) ? $this->env->block->selfParent : null; + $selfSelector = $this->multiplySelectors($this->env, $selfParent); + $selfSelector = $this->collapseSelectorsAsList($selfSelector); + + return $selfSelector; + + default: + return $value; + } + } + + /** + * Function caller + * + * @param string|array $functionReference + * @param array $argValues + * + * @return array|Number + */ + protected function fncall($functionReference, $argValues) + { + // a string means this is a static hard reference coming from the parsing + if (is_string($functionReference)) { + $name = $functionReference; + + $functionReference = $this->getFunctionReference($name); + if ($functionReference === static::$null || $functionReference[0] !== Type::T_FUNCTION_REFERENCE) { + $functionReference = [Type::T_FUNCTION, $name, [Type::T_LIST, ',', []]]; + } + } + + // a function type means we just want a plain css function call + if ($functionReference[0] === Type::T_FUNCTION) { + // for CSS functions, simply flatten the arguments into a list + $listArgs = []; + + foreach ((array) $argValues as $arg) { + if (empty($arg[0]) || count($argValues) === 1) { + $listArgs[] = $this->reduce($this->stringifyFncallArgs($arg[1])); + } + } + + return [Type::T_FUNCTION, $functionReference[1], [Type::T_LIST, ',', $listArgs]]; + } + + if ($functionReference === static::$null || $functionReference[0] !== Type::T_FUNCTION_REFERENCE) { + return static::$defaultValue; + } + + + switch ($functionReference[1]) { + // SCSS @function + case 'scss': + return $this->callScssFunction($functionReference[3], $argValues); + + // native PHP functions + case 'user': + case 'native': + list(,,$name, $fn, $prototype) = $functionReference; + + // special cases of css valid functions min/max + $name = strtolower($name); + if (\in_array($name, ['min', 'max']) && count($argValues) >= 1) { + $cssFunction = $this->cssValidArg( + [Type::T_FUNCTION_CALL, $name, $argValues], + ['min', 'max', 'calc', 'env', 'var'] + ); + if ($cssFunction !== false) { + return $cssFunction; + } + } + $returnValue = $this->callNativeFunction($name, $fn, $prototype, $argValues); + + if (! isset($returnValue)) { + return $this->fncall([Type::T_FUNCTION, $name, [Type::T_LIST, ',', []]], $argValues); + } + + return $returnValue; + + default: + return static::$defaultValue; + } + } + + /** + * @param array|Number $arg + * @param string[] $allowed_function + * @param bool $inFunction + * + * @return array|Number|false + */ + protected function cssValidArg($arg, $allowed_function = [], $inFunction = false) + { + if ($arg instanceof Number) { + return $this->stringifyFncallArgs($arg); + } + + switch ($arg[0]) { + case Type::T_INTERPOLATE: + return [Type::T_KEYWORD, $this->CompileValue($arg)]; + + case Type::T_FUNCTION: + if (! \in_array($arg[1], $allowed_function)) { + return false; + } + if ($arg[2][0] === Type::T_LIST) { + foreach ($arg[2][2] as $k => $subarg) { + $arg[2][2][$k] = $this->cssValidArg($subarg, $allowed_function, $arg[1]); + if ($arg[2][2][$k] === false) { + return false; + } + } + } + return $arg; + + case Type::T_FUNCTION_CALL: + if (! \in_array($arg[1], $allowed_function)) { + return false; + } + $cssArgs = []; + foreach ($arg[2] as $argValue) { + if ($argValue === static::$null) { + return false; + } + $cssArg = $this->cssValidArg($argValue[1], $allowed_function, $arg[1]); + if (empty($argValue[0]) && $cssArg !== false) { + $cssArgs[] = [$argValue[0], $cssArg]; + } else { + return false; + } + } + + return $this->fncall([Type::T_FUNCTION, $arg[1], [Type::T_LIST, ',', []]], $cssArgs); + + case Type::T_STRING: + case Type::T_KEYWORD: + if (!$inFunction or !\in_array($inFunction, ['calc', 'env', 'var'])) { + return false; + } + return $this->stringifyFncallArgs($arg); + + case Type::T_LIST: + if (!$inFunction) { + return false; + } + if (empty($arg['enclosing']) and $arg[1] === '') { + foreach ($arg[2] as $k => $subarg) { + $arg[2][$k] = $this->cssValidArg($subarg, $allowed_function, $inFunction); + if ($arg[2][$k] === false) { + return false; + } + } + $arg[0] = Type::T_STRING; + return $arg; + } + return false; + + case Type::T_EXPRESSION: + if (! \in_array($arg[1], ['+', '-', '/', '*'])) { + return false; + } + $arg[2] = $this->cssValidArg($arg[2], $allowed_function, $inFunction); + $arg[3] = $this->cssValidArg($arg[3], $allowed_function, $inFunction); + if ($arg[2] === false || $arg[3] === false) { + return false; + } + return $this->expToString($arg, true); + + case Type::T_VARIABLE: + case Type::T_SELF: + default: + return false; + } + } + + + /** + * Reformat fncall arguments to proper css function output + * + * @param array|Number $arg + * + * @return array|Number + */ + protected function stringifyFncallArgs($arg) + { + if ($arg instanceof Number) { + return $arg; + } + + switch ($arg[0]) { + case Type::T_LIST: + foreach ($arg[2] as $k => $v) { + $arg[2][$k] = $this->stringifyFncallArgs($v); + } + break; + + case Type::T_EXPRESSION: + if ($arg[1] === '/') { + $arg[2] = $this->stringifyFncallArgs($arg[2]); + $arg[3] = $this->stringifyFncallArgs($arg[3]); + $arg[5] = $arg[6] = false; // no space around / + $arg = $this->expToString($arg); + } + break; + + case Type::T_FUNCTION_CALL: + $name = strtolower($arg[1]); + + if (in_array($name, ['max', 'min', 'calc'])) { + $args = $arg[2]; + $arg = $this->fncall([Type::T_FUNCTION, $name, [Type::T_LIST, ',', []]], $args); + } + break; + } + + return $arg; + } + + /** + * Find a function reference + * @param string $name + * @param bool $safeCopy + * @return array + */ + protected function getFunctionReference($name, $safeCopy = false) + { + // SCSS @function + if ($func = $this->get(static::$namespaces['function'] . $name, false)) { + if ($safeCopy) { + $func = clone $func; + } + + return [Type::T_FUNCTION_REFERENCE, 'scss', $name, $func]; + } + + // native PHP functions + + // try to find a native lib function + $normalizedName = $this->normalizeName($name); + + if (isset($this->userFunctions[$normalizedName])) { + // see if we can find a user function + list($f, $prototype) = $this->userFunctions[$normalizedName]; + + return [Type::T_FUNCTION_REFERENCE, 'user', $name, $f, $prototype]; + } + + $lowercasedName = strtolower($normalizedName); + + // Special functions overriding a CSS function are case-insensitive. We normalize them as lowercase + // to avoid the deprecation warning about the wrong case being used. + if ($lowercasedName === 'min' || $lowercasedName === 'max') { + $normalizedName = $lowercasedName; + } + + if (($f = $this->getBuiltinFunction($normalizedName)) && \is_callable($f)) { + $libName = $f[1]; + $prototype = isset(static::$$libName) ? static::$$libName : null; + + // All core functions have a prototype defined. Not finding the + // prototype can mean 2 things: + // - the function comes from a child class (deprecated just after) + // - the function was found with a different case, which relates to calling the + // wrong Sass function due to our camelCase usage (`fade-in()` vs `fadein()`), + // because PHP method names are case-insensitive while property names are + // case-sensitive. + if ($prototype === null || strtolower($normalizedName) !== $normalizedName) { + $r = new \ReflectionMethod($this, $libName); + $actualLibName = $r->name; + + if ($actualLibName !== $libName || strtolower($normalizedName) !== $normalizedName) { + $kebabCaseName = preg_replace('~(?<=\\w)([A-Z])~', '-$1', substr($actualLibName, 3)); + assert($kebabCaseName !== null); + $originalName = strtolower($kebabCaseName); + $warning = "Calling built-in functions with a non-standard name is deprecated since Scssphp 1.8.0 and will not work anymore in 2.0 (they will be treated as CSS function calls instead).\nUse \"$originalName\" instead of \"$name\"."; + @trigger_error($warning, E_USER_DEPRECATED); + $fname = $this->getPrettyPath($this->sourceNames[$this->sourceIndex]); + $line = $this->sourceLine; + Warn::deprecation("$warning\n on line $line of $fname"); + + // Use the actual function definition + $prototype = isset(static::$$actualLibName) ? static::$$actualLibName : null; + $f[1] = $libName = $actualLibName; + } + } + + if (\get_class($this) !== __CLASS__ && !isset($this->warnedChildFunctions[$libName])) { + $r = new \ReflectionMethod($this, $libName); + $declaringClass = $r->getDeclaringClass()->name; + + $needsWarning = $this->warnedChildFunctions[$libName] = $declaringClass !== __CLASS__; + + if ($needsWarning) { + if (method_exists(__CLASS__, $libName)) { + @trigger_error(sprintf('Overriding the "%s" core function by extending the Compiler is deprecated and will be unsupported in 2.0. Remove the "%s::%s" method.', $normalizedName, $declaringClass, $libName), E_USER_DEPRECATED); + } else { + @trigger_error(sprintf('Registering custom functions by extending the Compiler and using the lib* discovery mechanism is deprecated and will be removed in 2.0. Replace the "%s::%s" method with registering the "%s" function through "Compiler::registerFunction".', $declaringClass, $libName, $normalizedName), E_USER_DEPRECATED); + } + } + } + + return [Type::T_FUNCTION_REFERENCE, 'native', $name, $f, $prototype]; + } + + return static::$null; + } + + + /** + * Normalize name + * + * @param string $name + * + * @return string + */ + protected function normalizeName($name) + { + return str_replace('-', '_', $name); + } + + /** + * Normalize value + * + * @internal + * + * @param array|Number $value + * + * @return array|Number + */ + public function normalizeValue($value) + { + $value = $this->coerceForExpression($this->reduce($value)); + + if ($value instanceof Number) { + return $value; + } + + switch ($value[0]) { + case Type::T_LIST: + $value = $this->extractInterpolation($value); + + if ($value[0] !== Type::T_LIST) { + return [Type::T_KEYWORD, $this->compileValue($value)]; + } + + foreach ($value[2] as $key => $item) { + $value[2][$key] = $this->normalizeValue($item); + } + + if (! empty($value['enclosing'])) { + unset($value['enclosing']); + } + + if ($value[1] === '' && count($value[2]) > 1) { + $value[1] = ' '; + } + + return $value; + + case Type::T_STRING: + return [$value[0], '"', [$this->compileStringContent($value)]]; + + case Type::T_INTERPOLATE: + return [Type::T_KEYWORD, $this->compileValue($value)]; + + default: + return $value; + } + } + + /** + * Add numbers + * + * @param Number $left + * @param Number $right + * + * @return Number + */ + protected function opAddNumberNumber(Number $left, Number $right) + { + return $left->plus($right); + } + + /** + * Multiply numbers + * + * @param Number $left + * @param Number $right + * + * @return Number + */ + protected function opMulNumberNumber(Number $left, Number $right) + { + return $left->times($right); + } + + /** + * Subtract numbers + * + * @param Number $left + * @param Number $right + * + * @return Number + */ + protected function opSubNumberNumber(Number $left, Number $right) + { + return $left->minus($right); + } + + /** + * Divide numbers + * + * @param Number $left + * @param Number $right + * + * @return Number + */ + protected function opDivNumberNumber(Number $left, Number $right) + { + return $left->dividedBy($right); + } + + /** + * Mod numbers + * + * @param Number $left + * @param Number $right + * + * @return Number + */ + protected function opModNumberNumber(Number $left, Number $right) + { + return $left->modulo($right); + } + + /** + * Add strings + * + * @param array $left + * @param array $right + * + * @return array|null + */ + protected function opAdd($left, $right) + { + if ($strLeft = $this->coerceString($left)) { + if ($right[0] === Type::T_STRING) { + $right[1] = ''; + } + + $strLeft[2][] = $right; + + return $strLeft; + } + + if ($strRight = $this->coerceString($right)) { + if ($left[0] === Type::T_STRING) { + $left[1] = ''; + } + + array_unshift($strRight[2], $left); + + return $strRight; + } + + return null; + } + + /** + * Boolean and + * + * @param array|Number $left + * @param array|Number $right + * @param bool $shouldEval + * + * @return array|Number|null + */ + protected function opAnd($left, $right, $shouldEval) + { + $truthy = ($left === static::$null || $right === static::$null) || + ($left === static::$false || $left === static::$true) && + ($right === static::$false || $right === static::$true); + + if (! $shouldEval) { + if (! $truthy) { + return null; + } + } + + if ($left !== static::$false && $left !== static::$null) { + return $this->reduce($right, true); + } + + return $left; + } + + /** + * Boolean or + * + * @param array|Number $left + * @param array|Number $right + * @param bool $shouldEval + * + * @return array|Number|null + */ + protected function opOr($left, $right, $shouldEval) + { + $truthy = ($left === static::$null || $right === static::$null) || + ($left === static::$false || $left === static::$true) && + ($right === static::$false || $right === static::$true); + + if (! $shouldEval) { + if (! $truthy) { + return null; + } + } + + if ($left !== static::$false && $left !== static::$null) { + return $left; + } + + return $this->reduce($right, true); + } + + /** + * Compare colors + * + * @param string $op + * @param array $left + * @param array $right + * + * @return array + */ + protected function opColorColor($op, $left, $right) + { + if ($op !== '==' && $op !== '!=') { + $warning = "Color arithmetic is deprecated and will be an error in future versions.\n" + . "Consider using Sass's color functions instead."; + $fname = $this->getPrettyPath($this->sourceNames[$this->sourceIndex]); + $line = $this->sourceLine; + + Warn::deprecation("$warning\n on line $line of $fname"); + } + + $out = [Type::T_COLOR]; + + foreach ([1, 2, 3] as $i) { + $lval = isset($left[$i]) ? $left[$i] : 0; + $rval = isset($right[$i]) ? $right[$i] : 0; + + switch ($op) { + case '+': + $out[] = $lval + $rval; + break; + + case '-': + $out[] = $lval - $rval; + break; + + case '*': + $out[] = $lval * $rval; + break; + + case '%': + if ($rval == 0) { + throw $this->error("color: Can't take modulo by zero"); + } + + $out[] = $lval % $rval; + break; + + case '/': + if ($rval == 0) { + throw $this->error("color: Can't divide by zero"); + } + + $out[] = (int) ($lval / $rval); + break; + + case '==': + return $this->opEq($left, $right); + + case '!=': + return $this->opNeq($left, $right); + + default: + throw $this->error("color: unknown op $op"); + } + } + + if (isset($left[4])) { + $out[4] = $left[4]; + } elseif (isset($right[4])) { + $out[4] = $right[4]; + } + + return $this->fixColor($out); + } + + /** + * Compare color and number + * + * @param string $op + * @param array $left + * @param Number $right + * + * @return array + */ + protected function opColorNumber($op, $left, Number $right) + { + if ($op === '==') { + return static::$false; + } + + if ($op === '!=') { + return static::$true; + } + + $value = $right->getDimension(); + + return $this->opColorColor( + $op, + $left, + [Type::T_COLOR, $value, $value, $value] + ); + } + + /** + * Compare number and color + * + * @param string $op + * @param Number $left + * @param array $right + * + * @return array + */ + protected function opNumberColor($op, Number $left, $right) + { + if ($op === '==') { + return static::$false; + } + + if ($op === '!=') { + return static::$true; + } + + $value = $left->getDimension(); + + return $this->opColorColor( + $op, + [Type::T_COLOR, $value, $value, $value], + $right + ); + } + + /** + * Compare number1 == number2 + * + * @param array|Number $left + * @param array|Number $right + * + * @return array + */ + protected function opEq($left, $right) + { + if (($lStr = $this->coerceString($left)) && ($rStr = $this->coerceString($right))) { + $lStr[1] = ''; + $rStr[1] = ''; + + $left = $this->compileValue($lStr); + $right = $this->compileValue($rStr); + } + + return $this->toBool($left === $right); + } + + /** + * Compare number1 != number2 + * + * @param array|Number $left + * @param array|Number $right + * + * @return array + */ + protected function opNeq($left, $right) + { + if (($lStr = $this->coerceString($left)) && ($rStr = $this->coerceString($right))) { + $lStr[1] = ''; + $rStr[1] = ''; + + $left = $this->compileValue($lStr); + $right = $this->compileValue($rStr); + } + + return $this->toBool($left !== $right); + } + + /** + * Compare number1 == number2 + * + * @param Number $left + * @param Number $right + * + * @return array + */ + protected function opEqNumberNumber(Number $left, Number $right) + { + return $this->toBool($left->equals($right)); + } + + /** + * Compare number1 != number2 + * + * @param Number $left + * @param Number $right + * + * @return array + */ + protected function opNeqNumberNumber(Number $left, Number $right) + { + return $this->toBool(!$left->equals($right)); + } + + /** + * Compare number1 >= number2 + * + * @param Number $left + * @param Number $right + * + * @return array + */ + protected function opGteNumberNumber(Number $left, Number $right) + { + return $this->toBool($left->greaterThanOrEqual($right)); + } + + /** + * Compare number1 > number2 + * + * @param Number $left + * @param Number $right + * + * @return array + */ + protected function opGtNumberNumber(Number $left, Number $right) + { + return $this->toBool($left->greaterThan($right)); + } + + /** + * Compare number1 <= number2 + * + * @param Number $left + * @param Number $right + * + * @return array + */ + protected function opLteNumberNumber(Number $left, Number $right) + { + return $this->toBool($left->lessThanOrEqual($right)); + } + + /** + * Compare number1 < number2 + * + * @param Number $left + * @param Number $right + * + * @return array + */ + protected function opLtNumberNumber(Number $left, Number $right) + { + return $this->toBool($left->lessThan($right)); + } + + /** + * Cast to boolean + * + * @api + * + * @param bool $thing + * + * @return array + */ + public function toBool($thing) + { + return $thing ? static::$true : static::$false; + } + + /** + * Escape non printable chars in strings output as in dart-sass + * + * @internal + * + * @param string $string + * @param bool $inKeyword + * + * @return string + */ + public function escapeNonPrintableChars($string, $inKeyword = false) + { + static $replacement = []; + if (empty($replacement[$inKeyword])) { + for ($i = 0; $i < 32; $i++) { + if ($i !== 9 || $inKeyword) { + $replacement[$inKeyword][chr($i)] = '\\' . dechex($i) . ($inKeyword ? ' ' : chr(0)); + } + } + } + $string = str_replace(array_keys($replacement[$inKeyword]), array_values($replacement[$inKeyword]), $string); + // chr(0) is not a possible char from the input, so any chr(0) comes from our escaping replacement + if (strpos($string, chr(0)) !== false) { + if (substr($string, -1) === chr(0)) { + $string = substr($string, 0, -1); + } + $string = str_replace( + [chr(0) . '\\',chr(0) . ' '], + [ '\\', ' '], + $string + ); + if (strpos($string, chr(0)) !== false) { + $parts = explode(chr(0), $string); + $string = array_shift($parts); + while (count($parts)) { + $next = array_shift($parts); + if (strpos("0123456789abcdefABCDEF" . chr(9), $next[0]) !== false) { + $string .= " "; + } + $string .= $next; + } + } + } + + return $string; + } + + /** + * Compiles a primitive value into a CSS property value. + * + * Values in scssphp are typed by being wrapped in arrays, their format is + * typically: + * + * array(type, contents [, additional_contents]*) + * + * The input is expected to be reduced. This function will not work on + * things like expressions and variables. + * + * @api + * + * @param array|Number $value + * @param bool $quote + * + * @return string + */ + public function compileValue($value, $quote = true) + { + $value = $this->reduce($value); + + if ($value instanceof Number) { + return $value->output($this); + } + + switch ($value[0]) { + case Type::T_KEYWORD: + return $this->escapeNonPrintableChars($value[1], true); + + case Type::T_COLOR: + // [1] - red component (either number for a %) + // [2] - green component + // [3] - blue component + // [4] - optional alpha component + list(, $r, $g, $b) = $value; + + $r = $this->compileRGBAValue($r); + $g = $this->compileRGBAValue($g); + $b = $this->compileRGBAValue($b); + + if (\count($value) === 5) { + $alpha = $this->compileRGBAValue($value[4], true); + + if (! is_numeric($alpha) || $alpha < 1) { + $colorName = Colors::RGBaToColorName($r, $g, $b, $alpha); + + if (! \is_null($colorName)) { + return $colorName; + } + + if (is_numeric($alpha)) { + $a = new Number($alpha, ''); + } else { + $a = $alpha; + } + + return 'rgba(' . $r . ', ' . $g . ', ' . $b . ', ' . $a . ')'; + } + } + + if (! is_numeric($r) || ! is_numeric($g) || ! is_numeric($b)) { + return 'rgb(' . $r . ', ' . $g . ', ' . $b . ')'; + } + + $colorName = Colors::RGBaToColorName($r, $g, $b); + + if (! \is_null($colorName)) { + return $colorName; + } + + $h = sprintf('#%02x%02x%02x', $r, $g, $b); + + // Converting hex color to short notation (e.g. #003399 to #039) + if ($h[1] === $h[2] && $h[3] === $h[4] && $h[5] === $h[6]) { + $h = '#' . $h[1] . $h[3] . $h[5]; + } + + return $h; + + case Type::T_STRING: + $content = $this->compileStringContent($value, $quote); + + if ($value[1] && $quote) { + $content = str_replace('\\', '\\\\', $content); + + $content = $this->escapeNonPrintableChars($content); + + // force double quote as string quote for the output in certain cases + if ( + $value[1] === "'" && + (strpos($content, '"') === false or strpos($content, "'") !== false) + ) { + $value[1] = '"'; + } elseif ( + $value[1] === '"' && + (strpos($content, '"') !== false and strpos($content, "'") === false) + ) { + $value[1] = "'"; + } + + $content = str_replace($value[1], '\\' . $value[1], $content); + } + + return $value[1] . $content . $value[1]; + + case Type::T_FUNCTION: + $args = ! empty($value[2]) ? $this->compileValue($value[2], $quote) : ''; + + return "$value[1]($args)"; + + case Type::T_FUNCTION_REFERENCE: + $name = ! empty($value[2]) ? $value[2] : ''; + + return "get-function(\"$name\")"; + + case Type::T_LIST: + $value = $this->extractInterpolation($value); + + if ($value[0] !== Type::T_LIST) { + return $this->compileValue($value, $quote); + } + + list(, $delim, $items) = $value; + $pre = $post = ''; + + if (! empty($value['enclosing'])) { + switch ($value['enclosing']) { + case 'parent': + //$pre = '('; + //$post = ')'; + break; + case 'forced_parent': + $pre = '('; + $post = ')'; + break; + case 'bracket': + case 'forced_bracket': + $pre = '['; + $post = ']'; + break; + } + } + + $separator = $delim === '/' ? ' /' : $delim; + + $prefix_value = ''; + + if ($delim !== ' ') { + $prefix_value = ' '; + } + + $filtered = []; + + $same_string_quote = null; + foreach ($items as $item) { + if (\is_null($same_string_quote)) { + $same_string_quote = false; + if ($item[0] === Type::T_STRING) { + $same_string_quote = $item[1]; + foreach ($items as $ii) { + if ($ii[0] !== Type::T_STRING) { + $same_string_quote = false; + break; + } + } + } + } + if ($item[0] === Type::T_NULL) { + continue; + } + if ($same_string_quote === '"' && $item[0] === Type::T_STRING && $item[1]) { + $item[1] = $same_string_quote; + } + + $compiled = $this->compileValue($item, $quote); + + if ($prefix_value && \strlen($compiled)) { + $compiled = $prefix_value . $compiled; + } + + $filtered[] = $compiled; + } + + return $pre . substr(implode($separator, $filtered), \strlen($prefix_value)) . $post; + + case Type::T_MAP: + $keys = $value[1]; + $values = $value[2]; + $filtered = []; + + for ($i = 0, $s = \count($keys); $i < $s; $i++) { + $filtered[$this->compileValue($keys[$i], $quote)] = $this->compileValue($values[$i], $quote); + } + + array_walk($filtered, function (&$value, $key) { + $value = $key . ': ' . $value; + }); + + return '(' . implode(', ', $filtered) . ')'; + + case Type::T_INTERPOLATED: + // node created by extractInterpolation + list(, $interpolate, $left, $right) = $value; + list(,, $whiteLeft, $whiteRight) = $interpolate; + + $delim = $left[1]; + + if ($delim && $delim !== ' ' && ! $whiteLeft) { + $delim .= ' '; + } + + $left = \count($left[2]) > 0 + ? $this->compileValue($left, $quote) . $delim . $whiteLeft + : ''; + + $delim = $right[1]; + + if ($delim && $delim !== ' ') { + $delim .= ' '; + } + + $right = \count($right[2]) > 0 ? + $whiteRight . $delim . $this->compileValue($right, $quote) : ''; + + return $left . $this->compileValue($interpolate, $quote) . $right; + + case Type::T_INTERPOLATE: + // strip quotes if it's a string + $reduced = $this->reduce($value[1]); + + if ($reduced instanceof Number) { + return $this->compileValue($reduced, $quote); + } + + switch ($reduced[0]) { + case Type::T_LIST: + $reduced = $this->extractInterpolation($reduced); + + if ($reduced[0] !== Type::T_LIST) { + break; + } + + list(, $delim, $items) = $reduced; + + if ($delim !== ' ') { + $delim .= ' '; + } + + $filtered = []; + + foreach ($items as $item) { + if ($item[0] === Type::T_NULL) { + continue; + } + + if ($item[0] === Type::T_STRING) { + $filtered[] = $this->compileStringContent($item, $quote); + } elseif ($item[0] === Type::T_KEYWORD) { + $filtered[] = $item[1]; + } else { + $filtered[] = $this->compileValue($item, $quote); + } + } + + $reduced = [Type::T_KEYWORD, implode("$delim", $filtered)]; + break; + + case Type::T_STRING: + $reduced = [Type::T_STRING, '', [$this->compileStringContent($reduced)]]; + break; + + case Type::T_NULL: + $reduced = [Type::T_KEYWORD, '']; + } + + return $this->compileValue($reduced, $quote); + + case Type::T_NULL: + return 'null'; + + case Type::T_COMMENT: + return $this->compileCommentValue($value); + + default: + throw $this->error('unknown value type: ' . json_encode($value)); + } + } + + /** + * @param array|Number $value + * + * @return string + */ + protected function compileDebugValue($value) + { + $value = $this->reduce($value, true); + + if ($value instanceof Number) { + return $this->compileValue($value); + } + + switch ($value[0]) { + case Type::T_STRING: + return $this->compileStringContent($value); + + default: + return $this->compileValue($value); + } + } + + /** + * Flatten list + * + * @param array $list + * + * @return string + * + * @deprecated + */ + protected function flattenList($list) + { + @trigger_error(sprintf('The "%s" method is deprecated.', __METHOD__), E_USER_DEPRECATED); + + return $this->compileValue($list); + } + + /** + * Gets the text of a Sass string + * + * Calling this method on anything else than a SassString is unsupported. Use {@see assertString} first + * to ensure that the value is indeed a string. + * + * @param array $value + * + * @return string + */ + public function getStringText(array $value) + { + if ($value[0] !== Type::T_STRING) { + throw new \InvalidArgumentException('The argument is not a sass string. Did you forgot to use "assertString"?'); + } + + return $this->compileStringContent($value); + } + + /** + * Compile string content + * + * @param array $string + * @param bool $quote + * + * @return string + */ + protected function compileStringContent($string, $quote = true) + { + $parts = []; + + foreach ($string[2] as $part) { + if (\is_array($part) || $part instanceof Number) { + $parts[] = $this->compileValue($part, $quote); + } else { + $parts[] = $part; + } + } + + return implode($parts); + } + + /** + * Extract interpolation; it doesn't need to be recursive, compileValue will handle that + * + * @param array $list + * + * @return array + */ + protected function extractInterpolation($list) + { + $items = $list[2]; + + foreach ($items as $i => $item) { + if ($item[0] === Type::T_INTERPOLATE) { + $before = [Type::T_LIST, $list[1], \array_slice($items, 0, $i)]; + $after = [Type::T_LIST, $list[1], \array_slice($items, $i + 1)]; + + return [Type::T_INTERPOLATED, $item, $before, $after]; + } + } + + return $list; + } + + /** + * Find the final set of selectors + * + * @param \ScssPhp\ScssPhp\Compiler\Environment $env + * @param \ScssPhp\ScssPhp\Block $selfParent + * + * @return array + */ + protected function multiplySelectors(Environment $env, $selfParent = null) + { + $envs = $this->compactEnv($env); + $selectors = []; + $parentSelectors = [[]]; + + $selfParentSelectors = null; + + if (! \is_null($selfParent) && $selfParent->selectors) { + $selfParentSelectors = $this->evalSelectors($selfParent->selectors); + } + + while ($env = array_pop($envs)) { + if (empty($env->selectors)) { + continue; + } + + $selectors = $env->selectors; + + do { + $stillHasSelf = false; + $prevSelectors = $selectors; + $selectors = []; + + foreach ($parentSelectors as $parent) { + foreach ($prevSelectors as $selector) { + if ($selfParentSelectors) { + foreach ($selfParentSelectors as $selfParent) { + // if no '&' in the selector, each call will give same result, only add once + $s = $this->joinSelectors($parent, $selector, $stillHasSelf, $selfParent); + $selectors[serialize($s)] = $s; + } + } else { + $s = $this->joinSelectors($parent, $selector, $stillHasSelf); + $selectors[serialize($s)] = $s; + } + } + } + } while ($stillHasSelf); + + $parentSelectors = $selectors; + } + + $selectors = array_values($selectors); + + // case we are just starting a at-root : nothing to multiply but parentSelectors + if (! $selectors && $selfParentSelectors) { + $selectors = $selfParentSelectors; + } + + return $selectors; + } + + /** + * Join selectors; looks for & to replace, or append parent before child + * + * @param array $parent + * @param array $child + * @param bool $stillHasSelf + * @param array $selfParentSelectors + + * @return array + */ + protected function joinSelectors($parent, $child, &$stillHasSelf, $selfParentSelectors = null) + { + $setSelf = false; + $out = []; + + foreach ($child as $part) { + $newPart = []; + + foreach ($part as $p) { + // only replace & once and should be recalled to be able to make combinations + if ($p === static::$selfSelector && $setSelf) { + $stillHasSelf = true; + } + + if ($p === static::$selfSelector && ! $setSelf) { + $setSelf = true; + + if (\is_null($selfParentSelectors)) { + $selfParentSelectors = $parent; + } + + foreach ($selfParentSelectors as $i => $parentPart) { + if ($i > 0) { + $out[] = $newPart; + $newPart = []; + } + + foreach ($parentPart as $pp) { + if (\is_array($pp)) { + $flatten = []; + + array_walk_recursive($pp, function ($a) use (&$flatten) { + $flatten[] = $a; + }); + + $pp = implode($flatten); + } + + $newPart[] = $pp; + } + } + } else { + $newPart[] = $p; + } + } + + $out[] = $newPart; + } + + return $setSelf ? $out : array_merge($parent, $child); + } + + /** + * Multiply media + * + * @param \ScssPhp\ScssPhp\Compiler\Environment $env + * @param array $childQueries + * + * @return array + */ + protected function multiplyMedia(Environment $env = null, $childQueries = null) + { + if ( + ! isset($env) || + ! empty($env->block->type) && $env->block->type !== Type::T_MEDIA + ) { + return $childQueries; + } + + // plain old block, skip + if (empty($env->block->type)) { + return $this->multiplyMedia($env->parent, $childQueries); + } + + assert($env->block instanceof MediaBlock); + + $parentQueries = isset($env->block->queryList) + ? $env->block->queryList + : [[[Type::T_MEDIA_VALUE, $env->block->value]]]; + + $store = [$this->env, $this->storeEnv]; + + $this->env = $env; + $this->storeEnv = null; + $parentQueries = $this->evaluateMediaQuery($parentQueries); + + list($this->env, $this->storeEnv) = $store; + + if (\is_null($childQueries)) { + $childQueries = $parentQueries; + } else { + $originalQueries = $childQueries; + $childQueries = []; + + foreach ($parentQueries as $parentQuery) { + foreach ($originalQueries as $childQuery) { + $childQueries[] = array_merge( + $parentQuery, + [[Type::T_MEDIA_TYPE, [Type::T_KEYWORD, 'all']]], + $childQuery + ); + } + } + } + + return $this->multiplyMedia($env->parent, $childQueries); + } + + /** + * Convert env linked list to stack + * + * @param Environment $env + * + * @return Environment[] + * + * @phpstan-return non-empty-array + */ + protected function compactEnv(Environment $env) + { + for ($envs = []; $env; $env = $env->parent) { + $envs[] = $env; + } + + return $envs; + } + + /** + * Convert env stack to singly linked list + * + * @param Environment[] $envs + * + * @return Environment + * + * @phpstan-param non-empty-array $envs + */ + protected function extractEnv($envs) + { + for ($env = null; $e = array_pop($envs);) { + $e->parent = $env; + $env = $e; + } + + return $env; + } + + /** + * Push environment + * + * @param \ScssPhp\ScssPhp\Block $block + * + * @return \ScssPhp\ScssPhp\Compiler\Environment + */ + protected function pushEnv(Block $block = null) + { + $env = new Environment(); + $env->parent = $this->env; + $env->parentStore = $this->storeEnv; + $env->store = []; + $env->block = $block; + $env->depth = isset($this->env->depth) ? $this->env->depth + 1 : 0; + + $this->env = $env; + $this->storeEnv = null; + + return $env; + } + + /** + * Pop environment + * + * @return void + */ + protected function popEnv() + { + $this->storeEnv = $this->env->parentStore; + $this->env = $this->env->parent; + } + + /** + * Propagate vars from a just poped Env (used in @each and @for) + * + * @param array $store + * @param null|string[] $excludedVars + * + * @return void + */ + protected function backPropagateEnv($store, $excludedVars = null) + { + foreach ($store as $key => $value) { + if (empty($excludedVars) || ! \in_array($key, $excludedVars)) { + $this->set($key, $value, true); + } + } + } + + /** + * Get store environment + * + * @return \ScssPhp\ScssPhp\Compiler\Environment + */ + protected function getStoreEnv() + { + return isset($this->storeEnv) ? $this->storeEnv : $this->env; + } + + /** + * Set variable + * + * @param string $name + * @param mixed $value + * @param bool $shadow + * @param \ScssPhp\ScssPhp\Compiler\Environment $env + * @param mixed $valueUnreduced + * + * @return void + */ + protected function set($name, $value, $shadow = false, Environment $env = null, $valueUnreduced = null) + { + $name = $this->normalizeName($name); + + if (! isset($env)) { + $env = $this->getStoreEnv(); + } + + if ($shadow) { + $this->setRaw($name, $value, $env, $valueUnreduced); + } else { + $this->setExisting($name, $value, $env, $valueUnreduced); + } + } + + /** + * Set existing variable + * + * @param string $name + * @param mixed $value + * @param \ScssPhp\ScssPhp\Compiler\Environment $env + * @param mixed $valueUnreduced + * + * @return void + */ + protected function setExisting($name, $value, Environment $env, $valueUnreduced = null) + { + $storeEnv = $env; + $specialContentKey = static::$namespaces['special'] . 'content'; + + $hasNamespace = $name[0] === '^' || $name[0] === '@' || $name[0] === '%'; + + $maxDepth = 10000; + + for (;;) { + if ($maxDepth-- <= 0) { + break; + } + + if (\array_key_exists($name, $env->store)) { + break; + } + + if (! $hasNamespace && isset($env->marker)) { + if (! empty($env->store[$specialContentKey])) { + $env = $env->store[$specialContentKey]->scope; + continue; + } + + if (! empty($env->declarationScopeParent)) { + $env = $env->declarationScopeParent; + continue; + } else { + $env = $storeEnv; + break; + } + } + + if (isset($env->parentStore)) { + $env = $env->parentStore; + } elseif (isset($env->parent)) { + $env = $env->parent; + } else { + $env = $storeEnv; + break; + } + } + + $env->store[$name] = $value; + + if ($valueUnreduced) { + $env->storeUnreduced[$name] = $valueUnreduced; + } + } + + /** + * Set raw variable + * + * @param string $name + * @param mixed $value + * @param \ScssPhp\ScssPhp\Compiler\Environment $env + * @param mixed $valueUnreduced + * + * @return void + */ + protected function setRaw($name, $value, Environment $env, $valueUnreduced = null) + { + $env->store[$name] = $value; + + if ($valueUnreduced) { + $env->storeUnreduced[$name] = $valueUnreduced; + } + } + + /** + * Get variable + * + * @internal + * + * @param string $name + * @param bool $shouldThrow + * @param \ScssPhp\ScssPhp\Compiler\Environment $env + * @param bool $unreduced + * + * @return mixed|null + */ + public function get($name, $shouldThrow = true, Environment $env = null, $unreduced = false) + { + $normalizedName = $this->normalizeName($name); + $specialContentKey = static::$namespaces['special'] . 'content'; + + if (! isset($env)) { + $env = $this->getStoreEnv(); + } + + $hasNamespace = $normalizedName[0] === '^' || $normalizedName[0] === '@' || $normalizedName[0] === '%'; + + $maxDepth = 10000; + + for (;;) { + if ($maxDepth-- <= 0) { + break; + } + + if (\array_key_exists($normalizedName, $env->store)) { + if ($unreduced && isset($env->storeUnreduced[$normalizedName])) { + return $env->storeUnreduced[$normalizedName]; + } + + return $env->store[$normalizedName]; + } + + if (! $hasNamespace && isset($env->marker)) { + if (! empty($env->store[$specialContentKey])) { + $env = $env->store[$specialContentKey]->scope; + continue; + } + + if (! empty($env->declarationScopeParent)) { + $env = $env->declarationScopeParent; + } else { + $env = $this->rootEnv; + } + continue; + } + + if (isset($env->parentStore)) { + $env = $env->parentStore; + } elseif (isset($env->parent)) { + $env = $env->parent; + } else { + break; + } + } + + if ($shouldThrow) { + throw $this->error("Undefined variable \$$name" . ($maxDepth <= 0 ? ' (infinite recursion)' : '')); + } + + // found nothing + return null; + } + + /** + * Has variable? + * + * @param string $name + * @param \ScssPhp\ScssPhp\Compiler\Environment $env + * + * @return bool + */ + protected function has($name, Environment $env = null) + { + return ! \is_null($this->get($name, false, $env)); + } + + /** + * Inject variables + * + * @param array $args + * + * @return void + */ + protected function injectVariables(array $args) + { + if (empty($args)) { + return; + } + + $parser = $this->parserFactory(__METHOD__); + + foreach ($args as $name => $strValue) { + if ($name[0] === '$') { + $name = substr($name, 1); + } + + if (!\is_string($strValue) || ! $parser->parseValue($strValue, $value)) { + $value = $this->coerceValue($strValue); + } + + $this->set($name, $value); + } + } + + /** + * Replaces variables. + * + * @param array $variables + * + * @return void + */ + public function replaceVariables(array $variables) + { + $this->registeredVars = []; + $this->addVariables($variables); + } + + /** + * Replaces variables. + * + * @param array $variables + * + * @return void + */ + public function addVariables(array $variables) + { + $triggerWarning = false; + + foreach ($variables as $name => $value) { + if (!$value instanceof Number && !\is_array($value)) { + $triggerWarning = true; + } + + $this->registeredVars[$name] = $value; + } + + if ($triggerWarning) { + @trigger_error('Passing raw values to as custom variables to the Compiler is deprecated. Use "\ScssPhp\ScssPhp\ValueConverter::parseValue" or "\ScssPhp\ScssPhp\ValueConverter::fromPhp" to convert them instead.', E_USER_DEPRECATED); + } + } + + /** + * Set variables + * + * @api + * + * @param array $variables + * + * @return void + * + * @deprecated Use "addVariables" or "replaceVariables" instead. + */ + public function setVariables(array $variables) + { + @trigger_error('The method "setVariables" of the Compiler is deprecated. Use the "addVariables" method for the equivalent behavior or "replaceVariables" if merging with previous variables was not desired.'); + + $this->addVariables($variables); + } + + /** + * Unset variable + * + * @api + * + * @param string $name + * + * @return void + */ + public function unsetVariable($name) + { + unset($this->registeredVars[$name]); + } + + /** + * Returns list of variables + * + * @api + * + * @return array + */ + public function getVariables() + { + return $this->registeredVars; + } + + /** + * Adds to list of parsed files + * + * @internal + * + * @param string|null $path + * + * @return void + */ + public function addParsedFile($path) + { + if (! \is_null($path) && is_file($path)) { + $this->parsedFiles[realpath($path)] = filemtime($path); + } + } + + /** + * Returns list of parsed files + * + * @deprecated + * @return array + */ + public function getParsedFiles() + { + @trigger_error('The method "getParsedFiles" of the Compiler is deprecated. Use the "getIncludedFiles" method on the CompilationResult instance returned by compileString() instead. Be careful that the signature of the method is different.', E_USER_DEPRECATED); + return $this->parsedFiles; + } + + /** + * Add import path + * + * @api + * + * @param string|callable $path + * + * @return void + */ + public function addImportPath($path) + { + if (! \in_array($path, $this->importPaths)) { + $this->importPaths[] = $path; + } + } + + /** + * Set import paths + * + * @api + * + * @param string|array $path + * + * @return void + */ + public function setImportPaths($path) + { + $paths = (array) $path; + $actualImportPaths = array_filter($paths, function ($path) { + return $path !== ''; + }); + + $this->legacyCwdImportPath = \count($actualImportPaths) !== \count($paths); + + if ($this->legacyCwdImportPath) { + @trigger_error('Passing an empty string in the import paths to refer to the current working directory is deprecated. If that\'s the intended behavior, the value of "getcwd()" should be used directly instead. If this was used for resolving relative imports of the input alongside "chdir" with the source directory, the path of the input file should be passed to "compileString()" instead.', E_USER_DEPRECATED); + } + + $this->importPaths = $actualImportPaths; + } + + /** + * Set number precision + * + * @api + * + * @param int $numberPrecision + * + * @return void + * + * @deprecated The number precision is not configurable anymore. The default is enough for all browsers. + */ + public function setNumberPrecision($numberPrecision) + { + @trigger_error('The number precision is not configurable anymore. ' + . 'The default is enough for all browsers.', E_USER_DEPRECATED); + } + + /** + * Sets the output style. + * + * @api + * + * @param string $style One of the OutputStyle constants + * + * @return void + * + * @phpstan-param OutputStyle::* $style + */ + public function setOutputStyle($style) + { + switch ($style) { + case OutputStyle::EXPANDED: + $this->formatter = Expanded::class; + break; + + case OutputStyle::COMPRESSED: + $this->formatter = Compressed::class; + break; + + default: + throw new \InvalidArgumentException(sprintf('Invalid output style "%s".', $style)); + } + } + + /** + * Set formatter + * + * @api + * + * @param string $formatterName + * + * @return void + * + * @deprecated Use {@see setOutputStyle} instead. + */ + public function setFormatter($formatterName) + { + if (!\in_array($formatterName, [Expanded::class, Compressed::class], true)) { + @trigger_error('Formatters other than Expanded and Compressed are deprecated.', E_USER_DEPRECATED); + } + @trigger_error('The method "setFormatter" is deprecated. Use "setOutputStyle" instead.', E_USER_DEPRECATED); + + $this->formatter = $formatterName; + } + + /** + * Set line number style + * + * @api + * + * @param string $lineNumberStyle + * + * @return void + * + * @deprecated The line number output is not supported anymore. Use source maps instead. + */ + public function setLineNumberStyle($lineNumberStyle) + { + @trigger_error('The line number output is not supported anymore. ' + . 'Use source maps instead.', E_USER_DEPRECATED); + } + + /** + * Configures the handling of non-ASCII outputs. + * + * If $charset is `true`, this will include a `@charset` declaration or a + * UTF-8 [byte-order mark][] if the stylesheet contains any non-ASCII + * characters. Otherwise, it will never include a `@charset` declaration or a + * byte-order mark. + * + * [byte-order mark]: https://en.wikipedia.org/wiki/Byte_order_mark#UTF-8 + * + * @param bool $charset + * + * @return void + */ + public function setCharset($charset) + { + $this->charset = $charset; + } + + /** + * Enable/disable source maps + * + * @api + * + * @param int $sourceMap + * + * @return void + * + * @phpstan-param self::SOURCE_MAP_* $sourceMap + */ + public function setSourceMap($sourceMap) + { + $this->sourceMap = $sourceMap; + } + + /** + * Set source map options + * + * @api + * + * @param array $sourceMapOptions + * + * @phpstan-param array{sourceRoot?: string, sourceMapFilename?: string|null, sourceMapURL?: string|null, sourceMapWriteTo?: string|null, outputSourceFiles?: bool, sourceMapRootpath?: string, sourceMapBasepath?: string} $sourceMapOptions + * + * @return void + */ + public function setSourceMapOptions($sourceMapOptions) + { + $this->sourceMapOptions = $sourceMapOptions; + } + + /** + * Register function + * + * @api + * + * @param string $name + * @param callable $callback + * @param string[]|null $argumentDeclaration + * + * @return void + */ + public function registerFunction($name, $callback, $argumentDeclaration = null) + { + if (self::isNativeFunction($name)) { + @trigger_error(sprintf('The "%s" function is a core sass function. Overriding it with a custom implementation through "%s" is deprecated and won\'t be supported in ScssPhp 2.0 anymore.', $name, __METHOD__), E_USER_DEPRECATED); + } + + if ($argumentDeclaration === null) { + @trigger_error('Omitting the argument declaration when registering custom function is deprecated and won\'t be supported in ScssPhp 2.0 anymore.', E_USER_DEPRECATED); + } + + $this->userFunctions[$this->normalizeName($name)] = [$callback, $argumentDeclaration]; + } + + /** + * Unregister function + * + * @api + * + * @param string $name + * + * @return void + */ + public function unregisterFunction($name) + { + unset($this->userFunctions[$this->normalizeName($name)]); + } + + /** + * Add feature + * + * @api + * + * @param string $name + * + * @return void + * + * @deprecated Registering additional features is deprecated. + */ + public function addFeature($name) + { + @trigger_error('Registering additional features is deprecated.', E_USER_DEPRECATED); + + $this->registeredFeatures[$name] = true; + } + + /** + * Import file + * + * @param string $path + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * + * @return void + */ + protected function importFile($path, OutputBlock $out) + { + $this->pushCallStack('import ' . $this->getPrettyPath($path)); + // see if tree is cached + $realPath = realpath($path); + + if (substr($path, -5) === '.sass') { + $this->sourceIndex = \count($this->sourceNames); + $this->sourceNames[] = $path; + $this->sourceLine = 1; + $this->sourceColumn = 1; + + throw $this->error('The Sass indented syntax is not implemented.'); + } + + if (isset($this->importCache[$realPath])) { + $this->handleImportLoop($realPath); + + $tree = $this->importCache[$realPath]; + } else { + $code = file_get_contents($path); + $parser = $this->parserFactory($path); + $tree = $parser->parse($code); + + $this->importCache[$realPath] = $tree; + } + + $currentDirectory = $this->currentDirectory; + $this->currentDirectory = dirname($path); + + $this->compileChildrenNoReturn($tree->children, $out); + $this->currentDirectory = $currentDirectory; + $this->popCallStack(); + } + + /** + * Save the imported files with their resolving path context + * + * @param string|null $currentDirectory + * @param string $path + * @param string $filePath + * + * @return void + */ + private function registerImport($currentDirectory, $path, $filePath) + { + $this->resolvedImports[] = ['currentDir' => $currentDirectory, 'path' => $path, 'filePath' => $filePath]; + } + + /** + * Detects whether the import is a CSS import. + * + * For legacy reasons, custom importers are called for those, allowing them + * to replace them with an actual Sass import. However this behavior is + * deprecated. Custom importers are expected to return null when they receive + * a CSS import. + * + * @param string $url + * + * @return bool + */ + public static function isCssImport($url) + { + return 1 === preg_match('~\.css$|^https?://|^//~', $url); + } + + /** + * Return the file path for an import url if it exists + * + * @internal + * + * @param string $url + * @param string|null $currentDir + * + * @return string|null + */ + public function findImport($url, $currentDir = null) + { + // Vanilla css and external requests. These are not meant to be Sass imports. + // Callback importers are still called for BC. + if (self::isCssImport($url)) { + foreach ($this->importPaths as $dir) { + if (\is_string($dir)) { + continue; + } + + if (\is_callable($dir)) { + // check custom callback for import path + $file = \call_user_func($dir, $url); + + if (! \is_null($file)) { + if (\is_array($dir)) { + $callableDescription = (\is_object($dir[0]) ? \get_class($dir[0]) : $dir[0]).'::'.$dir[1]; + } elseif ($dir instanceof \Closure) { + $r = new \ReflectionFunction($dir); + if (false !== strpos($r->name, '{closure}')) { + $callableDescription = sprintf('closure{%s:%s}', $r->getFileName(), $r->getStartLine()); + } elseif ($class = $r->getClosureScopeClass()) { + $callableDescription = $class->name.'::'.$r->name; + } else { + $callableDescription = $r->name; + } + } elseif (\is_object($dir)) { + $callableDescription = \get_class($dir) . '::__invoke'; + } else { + $callableDescription = 'callable'; // Fallback if we don't have a dedicated description + } + @trigger_error(sprintf('Returning a file to import for CSS or external references in custom importer callables is deprecated and will not be supported anymore in ScssPhp 2.0. This behavior is not compliant with the Sass specification. Update your "%s" importer.', $callableDescription), E_USER_DEPRECATED); + + return $file; + } + } + } + return null; + } + + if (!\is_null($currentDir)) { + $relativePath = $this->resolveImportPath($url, $currentDir); + + if (!\is_null($relativePath)) { + return $relativePath; + } + } + + foreach ($this->importPaths as $dir) { + if (\is_string($dir)) { + $path = $this->resolveImportPath($url, $dir); + + if (!\is_null($path)) { + return $path; + } + } elseif (\is_callable($dir)) { + // check custom callback for import path + $file = \call_user_func($dir, $url); + + if (! \is_null($file)) { + return $file; + } + } + } + + if ($this->legacyCwdImportPath) { + $path = $this->resolveImportPath($url, getcwd()); + + if (!\is_null($path)) { + @trigger_error('Resolving imports relatively to the current working directory is deprecated. If that\'s the intended behavior, the value of "getcwd()" should be added as an import path explicitly instead. If this was used for resolving relative imports of the input alongside "chdir" with the source directory, the path of the input file should be passed to "compileString()" instead.', E_USER_DEPRECATED); + + return $path; + } + } + + throw $this->error("`$url` file not found for @import"); + } + + /** + * @param string $url + * @param string $baseDir + * + * @return string|null + */ + private function resolveImportPath($url, $baseDir) + { + $path = Path::join($baseDir, $url); + + $hasExtension = preg_match('/.s[ac]ss$/', $url); + + if ($hasExtension) { + return $this->checkImportPathConflicts($this->tryImportPath($path)); + } + + $result = $this->checkImportPathConflicts($this->tryImportPathWithExtensions($path)); + + if (!\is_null($result)) { + return $result; + } + + return $this->tryImportPathAsDirectory($path); + } + + /** + * @param string[] $paths + * + * @return string|null + */ + private function checkImportPathConflicts(array $paths) + { + if (\count($paths) === 0) { + return null; + } + + if (\count($paths) === 1) { + return $paths[0]; + } + + $formattedPrettyPaths = []; + + foreach ($paths as $path) { + $formattedPrettyPaths[] = ' ' . $this->getPrettyPath($path); + } + + throw $this->error("It's not clear which file to import. Found:\n" . implode("\n", $formattedPrettyPaths)); + } + + /** + * @param string $path + * + * @return string[] + */ + private function tryImportPathWithExtensions($path) + { + $result = array_merge( + $this->tryImportPath($path.'.sass'), + $this->tryImportPath($path.'.scss') + ); + + if ($result) { + return $result; + } + + return $this->tryImportPath($path.'.css'); + } + + /** + * @param string $path + * + * @return string[] + */ + private function tryImportPath($path) + { + $partial = dirname($path).'/_'.basename($path); + + $candidates = []; + + if (is_file($partial)) { + $candidates[] = $partial; + } + + if (is_file($path)) { + $candidates[] = $path; + } + + return $candidates; + } + + /** + * @param string $path + * + * @return string|null + */ + private function tryImportPathAsDirectory($path) + { + if (!is_dir($path)) { + return null; + } + + return $this->checkImportPathConflicts($this->tryImportPathWithExtensions($path.'/index')); + } + + /** + * @param string|null $path + * + * @return string + */ + private function getPrettyPath($path) + { + if ($path === null) { + return '(unknown file)'; + } + + $normalizedPath = $path; + $normalizedRootDirectory = $this->rootDirectory.'/'; + + if (\DIRECTORY_SEPARATOR === '\\') { + $normalizedRootDirectory = str_replace('\\', '/', $normalizedRootDirectory); + $normalizedPath = str_replace('\\', '/', $path); + } + + if (0 === strpos($normalizedPath, $normalizedRootDirectory)) { + return substr($path, \strlen($normalizedRootDirectory)); + } + + return $path; + } + + /** + * Set encoding + * + * @api + * + * @param string|null $encoding + * + * @return void + * + * @deprecated Non-compliant support for other encodings than UTF-8 is deprecated. + */ + public function setEncoding($encoding) + { + if (!$encoding || strtolower($encoding) === 'utf-8') { + @trigger_error(sprintf('The "%s" method is deprecated.', __METHOD__), E_USER_DEPRECATED); + } else { + @trigger_error(sprintf('The "%s" method is deprecated. Parsing will only support UTF-8 in ScssPhp 2.0. The non-UTF-8 parsing of ScssPhp 1.x is not spec compliant.', __METHOD__), E_USER_DEPRECATED); + } + + $this->encoding = $encoding; + } + + /** + * Ignore errors? + * + * @api + * + * @param bool $ignoreErrors + * + * @return \ScssPhp\ScssPhp\Compiler + * + * @deprecated Ignoring Sass errors is not longer supported. + */ + public function setIgnoreErrors($ignoreErrors) + { + @trigger_error('Ignoring Sass errors is not longer supported.', E_USER_DEPRECATED); + + return $this; + } + + /** + * Get source position + * + * @api + * + * @return array + * + * @deprecated + */ + public function getSourcePosition() + { + @trigger_error(sprintf('The "%s" method is deprecated.', __METHOD__), E_USER_DEPRECATED); + + $sourceFile = isset($this->sourceNames[$this->sourceIndex]) ? $this->sourceNames[$this->sourceIndex] : ''; + + return [$sourceFile, $this->sourceLine, $this->sourceColumn]; + } + + /** + * Throw error (exception) + * + * @api + * + * @param string $msg Message with optional sprintf()-style vararg parameters + * + * @throws \ScssPhp\ScssPhp\Exception\CompilerException + * + * @deprecated use "error" and throw the exception in the caller instead. + */ + public function throwError($msg) + { + @trigger_error( + 'The method "throwError" is deprecated. Use "error" and throw the exception in the caller instead', + E_USER_DEPRECATED + ); + + throw $this->error(...func_get_args()); + } + + /** + * Build an error (exception) + * + * @internal + * + * @param string $msg Message with optional sprintf()-style vararg parameters + * + * @return CompilerException + */ + public function error($msg, ...$args) + { + if ($args) { + $msg = sprintf($msg, ...$args); + } + + if (! $this->ignoreCallStackMessage) { + $msg = $this->addLocationToMessage($msg); + } + + return new CompilerException($msg); + } + + /** + * @param string $msg + * + * @return string + */ + private function addLocationToMessage($msg) + { + $line = $this->sourceLine; + $column = $this->sourceColumn; + + $loc = isset($this->sourceNames[$this->sourceIndex]) + ? $this->getPrettyPath($this->sourceNames[$this->sourceIndex]) . " on line $line, at column $column" + : "line: $line, column: $column"; + + $msg = "$msg: $loc"; + + $callStackMsg = $this->callStackMessage(); + + if ($callStackMsg) { + $msg .= "\nCall Stack:\n" . $callStackMsg; + } + + return $msg; + } + + /** + * @param string $functionName + * @param array $ExpectedArgs + * @param int $nbActual + * @return CompilerException + * + * @deprecated + */ + public function errorArgsNumber($functionName, $ExpectedArgs, $nbActual) + { + @trigger_error(sprintf('The "%s" method is deprecated.', __METHOD__), E_USER_DEPRECATED); + + $nbExpected = \count($ExpectedArgs); + + if ($nbActual > $nbExpected) { + return $this->error( + 'Error: Only %d arguments allowed in %s(), but %d were passed.', + $nbExpected, + $functionName, + $nbActual + ); + } else { + $missing = []; + + while (count($ExpectedArgs) && count($ExpectedArgs) > $nbActual) { + array_unshift($missing, array_pop($ExpectedArgs)); + } + + return $this->error( + 'Error: %s() argument%s %s missing.', + $functionName, + count($missing) > 1 ? 's' : '', + implode(', ', $missing) + ); + } + } + + /** + * Beautify call stack for output + * + * @param bool $all + * @param int|null $limit + * + * @return string + */ + protected function callStackMessage($all = false, $limit = null) + { + $callStackMsg = []; + $ncall = 0; + + if ($this->callStack) { + foreach (array_reverse($this->callStack) as $call) { + if ($all || (isset($call['n']) && $call['n'])) { + $msg = '#' . $ncall++ . ' ' . $call['n'] . ' '; + $msg .= (isset($this->sourceNames[$call[Parser::SOURCE_INDEX]]) + ? $this->getPrettyPath($this->sourceNames[$call[Parser::SOURCE_INDEX]]) + : '(unknown file)'); + $msg .= ' on line ' . $call[Parser::SOURCE_LINE]; + + $callStackMsg[] = $msg; + + if (! \is_null($limit) && $ncall > $limit) { + break; + } + } + } + } + + return implode("\n", $callStackMsg); + } + + /** + * Handle import loop + * + * @param string $name + * + * @throws \Exception + */ + protected function handleImportLoop($name) + { + for ($env = $this->env; $env; $env = $env->parent) { + if (! $env->block) { + continue; + } + + $file = $this->sourceNames[$env->block->sourceIndex]; + + if ($file === null) { + continue; + } + + if (realpath($file) === $name) { + throw $this->error('An @import loop has been found: %s imports %s', $file, basename($file)); + } + } + } + + /** + * Call SCSS @function + * + * @param CallableBlock|null $func + * @param array $argValues + * + * @return array|Number + */ + protected function callScssFunction($func, $argValues) + { + if (! $func) { + return static::$defaultValue; + } + $name = $func->name; + + $this->pushEnv(); + + // set the args + if (isset($func->args)) { + $this->applyArguments($func->args, $argValues); + } + + // throw away lines and children + $tmp = new OutputBlock(); + $tmp->lines = []; + $tmp->children = []; + + $this->env->marker = 'function'; + + if (! empty($func->parentEnv)) { + $this->env->declarationScopeParent = $func->parentEnv; + } else { + throw $this->error("@function $name() without parentEnv"); + } + + $ret = $this->compileChildren($func->children, $tmp, $this->env->marker . ' ' . $name); + + $this->popEnv(); + + return ! isset($ret) ? static::$defaultValue : $ret; + } + + /** + * Call built-in and registered (PHP) functions + * + * @param string $name + * @param callable $function + * @param array $prototype + * @param array $args + * + * @return array|Number|null + */ + protected function callNativeFunction($name, $function, $prototype, $args) + { + $libName = (is_array($function) ? end($function) : null); + $sorted_kwargs = $this->sortNativeFunctionArgs($libName, $prototype, $args); + + if (\is_null($sorted_kwargs)) { + return null; + } + @list($sorted, $kwargs) = $sorted_kwargs; + + if ($name !== 'if') { + foreach ($sorted as &$val) { + if ($val !== null) { + $val = $this->reduce($val, true); + } + } + } + + $returnValue = \call_user_func($function, $sorted, $kwargs); + + if (! isset($returnValue)) { + return null; + } + + if (\is_array($returnValue) || $returnValue instanceof Number) { + return $returnValue; + } + + @trigger_error(sprintf('Returning a PHP value from the "%s" custom function is deprecated. A sass value must be returned instead.', $name), E_USER_DEPRECATED); + + return $this->coerceValue($returnValue); + } + + /** + * Get built-in function + * + * @param string $name Normalized name + * + * @return array + */ + protected function getBuiltinFunction($name) + { + $libName = self::normalizeNativeFunctionName($name); + return [$this, $libName]; + } + + /** + * Normalize native function name + * + * @internal + * + * @param string $name + * + * @return string + */ + public static function normalizeNativeFunctionName($name) + { + $name = str_replace("-", "_", $name); + $libName = 'lib' . preg_replace_callback( + '/_(.)/', + function ($m) { + return ucfirst($m[1]); + }, + ucfirst($name) + ); + return $libName; + } + + /** + * Check if a function is a native built-in scss function, for css parsing + * + * @internal + * + * @param string $name + * + * @return bool + */ + public static function isNativeFunction($name) + { + return method_exists(Compiler::class, self::normalizeNativeFunctionName($name)); + } + + /** + * Sorts keyword arguments + * + * @param string $functionName + * @param array|null $prototypes + * @param array $args + * + * @return array|null + */ + protected function sortNativeFunctionArgs($functionName, $prototypes, $args) + { + static $parser = null; + + if (! isset($prototypes)) { + $keyArgs = []; + $posArgs = []; + + if (\is_array($args) && \count($args) && \end($args) === static::$null) { + array_pop($args); + } + + // separate positional and keyword arguments + foreach ($args as $arg) { + list($key, $value) = $arg; + + if (empty($key) or empty($key[1])) { + $posArgs[] = empty($arg[2]) ? $value : $arg; + } else { + $keyArgs[$key[1]] = $value; + } + } + + return [$posArgs, $keyArgs]; + } + + // specific cases ? + if (\in_array($functionName, ['libRgb', 'libRgba', 'libHsl', 'libHsla'])) { + // notation 100 127 255 / 0 is in fact a simple list of 4 values + foreach ($args as $k => $arg) { + if ($arg[1][0] === Type::T_LIST && \count($arg[1][2]) === 3) { + $args[$k][1][2] = $this->extractSlashAlphaInColorFunction($arg[1][2]); + } + } + } + + list($positionalArgs, $namedArgs, $names, $separator, $hasSplat) = $this->evaluateArguments($args, false); + + if (! \is_array(reset($prototypes))) { + $prototypes = [$prototypes]; + } + + $parsedPrototypes = array_map([$this, 'parseFunctionPrototype'], $prototypes); + assert(!empty($parsedPrototypes)); + $matchedPrototype = $this->selectFunctionPrototype($parsedPrototypes, \count($positionalArgs), $names); + + $this->verifyPrototype($matchedPrototype, \count($positionalArgs), $names, $hasSplat); + + $vars = $this->applyArgumentsToDeclaration($matchedPrototype, $positionalArgs, $namedArgs, $separator); + + $finalArgs = []; + $keyArgs = []; + + foreach ($matchedPrototype['arguments'] as $argument) { + list($normalizedName, $originalName, $default) = $argument; + + if (isset($vars[$normalizedName])) { + $value = $vars[$normalizedName]; + } else { + $value = $default; + } + + // special null value as default: translate to real null here + if ($value === [Type::T_KEYWORD, 'null']) { + $value = null; + } + + $finalArgs[] = $value; + $keyArgs[$originalName] = $value; + } + + if ($matchedPrototype['rest_argument'] !== null) { + $value = $vars[$matchedPrototype['rest_argument']]; + + $finalArgs[] = $value; + $keyArgs[$matchedPrototype['rest_argument']] = $value; + } + + return [$finalArgs, $keyArgs]; + } + + /** + * Parses a function prototype to the internal representation of arguments. + * + * The input is an array of strings describing each argument, as supported + * in {@see registerFunction}. Argument names don't include the `$`. + * The output contains the list of positional argument, with their normalized + * name (underscores are replaced by dashes), their original name (to be used + * in case of error reporting) and their default value. The output also contains + * the normalized name of the rest argument, or null if the function prototype + * is not variadic. + * + * @param string[] $prototype + * + * @return array + * @phpstan-return array{arguments: list, rest_argument: string|null} + */ + private function parseFunctionPrototype(array $prototype) + { + static $parser = null; + + $arguments = []; + $restArgument = null; + + foreach ($prototype as $p) { + if (null !== $restArgument) { + throw new \InvalidArgumentException('The argument declaration is invalid. The rest argument must be the last one.'); + } + + $default = null; + $p = explode(':', $p, 2); + $name = str_replace('_', '-', $p[0]); + + if (isset($p[1])) { + $defaultSource = trim($p[1]); + + if ($defaultSource === 'null') { + // differentiate this null from the static::$null + $default = [Type::T_KEYWORD, 'null']; + } else { + if (\is_null($parser)) { + $parser = $this->parserFactory(__METHOD__); + } + + $parser->parseValue($defaultSource, $default); + } + } + + if (substr($name, -3) === '...') { + $restArgument = substr($name, 0, -3); + } else { + $arguments[] = [$name, $p[0], $default]; + } + } + + return [ + 'arguments' => $arguments, + 'rest_argument' => $restArgument, + ]; + } + + /** + * Returns the function prototype for the given positional and named arguments. + * + * If no exact match is found, finds the closest approximation. Note that this + * doesn't guarantee that $positional and $names are valid for the returned + * prototype. + * + * @param array[] $prototypes + * @param int $positional + * @param array $names A set of names, as both keys and values + * + * @return array + * + * @phpstan-param non-empty-list, rest_argument: string|null}> $prototypes + * @phpstan-return array{arguments: list, rest_argument: string|null} + */ + private function selectFunctionPrototype(array $prototypes, $positional, array $names) + { + $fuzzyMatch = null; + $minMismatchDistance = null; + + foreach ($prototypes as $prototype) { + // Ideally, find an exact match. + if ($this->checkPrototypeMatches($prototype, $positional, $names)) { + return $prototype; + } + + $mismatchDistance = \count($prototype['arguments']) - $positional; + + if ($minMismatchDistance !== null) { + if (abs($mismatchDistance) > abs($minMismatchDistance)) { + continue; + } + + // If two overloads have the same mismatch distance, favor the overload + // that has more arguments. + if (abs($mismatchDistance) === abs($minMismatchDistance) && $mismatchDistance < 0) { + continue; + } + } + + $minMismatchDistance = $mismatchDistance; + $fuzzyMatch = $prototype; + } + + return $fuzzyMatch; + } + + /** + * Checks whether the argument invocation matches the callable prototype. + * + * The rules are similar to {@see verifyPrototype}. The boolean return value + * avoids the overhead of building and catching exceptions when the reason of + * not matching the prototype does not need to be known. + * + * @param array $prototype + * @param int $positional + * @param array $names + * + * @return bool + * + * @phpstan-param array{arguments: list, rest_argument: string|null} $prototype + */ + private function checkPrototypeMatches(array $prototype, $positional, array $names) + { + $nameUsed = 0; + + foreach ($prototype['arguments'] as $i => $argument) { + list ($name, $originalName, $default) = $argument; + + if ($i < $positional) { + if (isset($names[$name])) { + return false; + } + } elseif (isset($names[$name])) { + $nameUsed++; + } elseif ($default === null) { + return false; + } + } + + if ($prototype['rest_argument'] !== null) { + return true; + } + + if ($positional > \count($prototype['arguments'])) { + return false; + } + + if ($nameUsed < \count($names)) { + return false; + } + + return true; + } + + /** + * Verifies that the argument invocation is valid for the callable prototype. + * + * @param array $prototype + * @param int $positional + * @param array $names + * @param bool $hasSplat + * + * @return void + * + * @throws SassScriptException + * + * @phpstan-param array{arguments: list, rest_argument: string|null} $prototype + */ + private function verifyPrototype(array $prototype, $positional, array $names, $hasSplat) + { + $nameUsed = 0; + + foreach ($prototype['arguments'] as $i => $argument) { + list ($name, $originalName, $default) = $argument; + + if ($i < $positional) { + if (isset($names[$name])) { + throw new SassScriptException(sprintf('Argument $%s was passed both by position and by name.', $originalName)); + } + } elseif (isset($names[$name])) { + $nameUsed++; + } elseif ($default === null) { + throw new SassScriptException(sprintf('Missing argument $%s', $originalName)); + } + } + + if ($prototype['rest_argument'] !== null) { + return; + } + + if ($positional > \count($prototype['arguments'])) { + $message = sprintf( + 'Only %d %sargument%s allowed, but %d %s passed.', + \count($prototype['arguments']), + empty($names) ? '' : 'positional ', + \count($prototype['arguments']) === 1 ? '' : 's', + $positional, + $positional === 1 ? 'was' : 'were' + ); + if (!$hasSplat) { + throw new SassScriptException($message); + } + + $message = $this->addLocationToMessage($message); + $message .= "\nThis will be an error in future versions of Sass."; + $this->logger->warn($message, true); + } + + if ($nameUsed < \count($names)) { + $unknownNames = array_values(array_diff($names, array_column($prototype['arguments'], 0))); + $lastName = array_pop($unknownNames); + $message = sprintf( + 'No argument%s named $%s%s.', + $unknownNames ? 's' : '', + $unknownNames ? implode(', $', $unknownNames) . ' or $' : '', + $lastName + ); + throw new SassScriptException($message); + } + } + + /** + * Evaluates the argument from the invocation. + * + * This returns several things about this invocation: + * - the list of positional arguments + * - the map of named arguments, indexed by normalized names + * - the set of names used in the arguments (that's an array using the normalized names as keys for O(1) access) + * - the separator used by the list using the splat operator, if any + * - a boolean indicator whether any splat argument (list or map) was used, to support the incomplete error reporting. + * + * @param array[] $args + * @param bool $reduce Whether arguments should be reduced to their value + * + * @return array + * + * @throws SassScriptException + * + * @phpstan-return array{0: list, 1: array, 2: array, 3: string|null, 4: bool} + */ + private function evaluateArguments(array $args, $reduce = true) + { + // this represents trailing commas + if (\count($args) && end($args) === static::$null) { + array_pop($args); + } + + $splatSeparator = null; + $keywordArgs = []; + $names = []; + $positionalArgs = []; + $hasKeywordArgument = false; + $hasSplat = false; + + foreach ($args as $arg) { + if (!empty($arg[0])) { + $hasKeywordArgument = true; + + assert(\is_string($arg[0][1])); + $name = str_replace('_', '-', $arg[0][1]); + + if (isset($keywordArgs[$name])) { + throw new SassScriptException(sprintf('Duplicate named argument $%s.', $arg[0][1])); + } + + $keywordArgs[$name] = $this->maybeReduce($reduce, $arg[1]); + $names[$name] = $name; + } elseif (! empty($arg[2])) { + // $arg[2] means a var followed by ... in the arg ($list... ) + $val = $this->reduce($arg[1], true); + $hasSplat = true; + + if ($val[0] === Type::T_LIST) { + foreach ($val[2] as $item) { + if (\is_null($splatSeparator)) { + $splatSeparator = $val[1]; + } + + $positionalArgs[] = $this->maybeReduce($reduce, $item); + } + + if (isset($val[3]) && \is_array($val[3])) { + foreach ($val[3] as $name => $item) { + assert(\is_string($name)); + + $normalizedName = str_replace('_', '-', $name); + + if (isset($keywordArgs[$normalizedName])) { + throw new SassScriptException(sprintf('Duplicate named argument $%s.', $name)); + } + + $keywordArgs[$normalizedName] = $this->maybeReduce($reduce, $item); + $names[$normalizedName] = $normalizedName; + $hasKeywordArgument = true; + } + } + } elseif ($val[0] === Type::T_MAP) { + foreach ($val[1] as $i => $name) { + $name = $this->compileStringContent($this->coerceString($name)); + $item = $val[2][$i]; + + if (! is_numeric($name)) { + $normalizedName = str_replace('_', '-', $name); + + if (isset($keywordArgs[$normalizedName])) { + throw new SassScriptException(sprintf('Duplicate named argument $%s.', $name)); + } + + $keywordArgs[$normalizedName] = $this->maybeReduce($reduce, $item); + $names[$normalizedName] = $normalizedName; + $hasKeywordArgument = true; + } else { + if (\is_null($splatSeparator)) { + $splatSeparator = $val[1]; + } + + $positionalArgs[] = $this->maybeReduce($reduce, $item); + } + } + } elseif ($val[0] !== Type::T_NULL) { // values other than null are treated a single-element lists, while null is the empty list + $positionalArgs[] = $this->maybeReduce($reduce, $val); + } + } elseif ($hasKeywordArgument) { + throw new SassScriptException('Positional arguments must come before keyword arguments.'); + } else { + $positionalArgs[] = $this->maybeReduce($reduce, $arg[1]); + } + } + + return [$positionalArgs, $keywordArgs, $names, $splatSeparator, $hasSplat]; + } + + /** + * @param bool $reduce + * @param array|Number $value + * + * @return array|Number + */ + private function maybeReduce($reduce, $value) + { + if ($reduce) { + return $this->reduce($value, true); + } + + return $value; + } + + /** + * Apply argument values per definition + * + * @param array[] $argDef + * @param array|null $argValues + * @param bool $storeInEnv + * @param bool $reduce only used if $storeInEnv = false + * + * @return array + * + * @phpstan-param list $argDef + * + * @throws \Exception + */ + protected function applyArguments($argDef, $argValues, $storeInEnv = true, $reduce = true) + { + $output = []; + + if (\is_null($argValues)) { + $argValues = []; + } + + if ($storeInEnv) { + $storeEnv = $this->getStoreEnv(); + + $env = new Environment(); + $env->store = $storeEnv->store; + } + + $prototype = ['arguments' => [], 'rest_argument' => null]; + $originalRestArgumentName = null; + + foreach ($argDef as $i => $arg) { + list($name, $default, $isVariable) = $arg; + $normalizedName = str_replace('_', '-', $name); + + if ($isVariable) { + $originalRestArgumentName = $name; + $prototype['rest_argument'] = $normalizedName; + } else { + $prototype['arguments'][] = [$normalizedName, $name, !empty($default) ? $default : null]; + } + } + + list($positionalArgs, $namedArgs, $names, $splatSeparator, $hasSplat) = $this->evaluateArguments($argValues, $reduce); + + $this->verifyPrototype($prototype, \count($positionalArgs), $names, $hasSplat); + + $vars = $this->applyArgumentsToDeclaration($prototype, $positionalArgs, $namedArgs, $splatSeparator); + + foreach ($prototype['arguments'] as $argument) { + list($normalizedName, $name) = $argument; + + if (!isset($vars[$normalizedName])) { + continue; + } + + $val = $vars[$normalizedName]; + + if ($storeInEnv) { + $this->set($name, $this->reduce($val, true), true, $env); + } else { + $output[$name] = ($reduce ? $this->reduce($val, true) : $val); + } + } + + if ($prototype['rest_argument'] !== null) { + assert($originalRestArgumentName !== null); + $name = $originalRestArgumentName; + $val = $vars[$prototype['rest_argument']]; + + if ($storeInEnv) { + $this->set($name, $this->reduce($val, true), true, $env); + } else { + $output[$name] = ($reduce ? $this->reduce($val, true) : $val); + } + } + + if ($storeInEnv) { + $storeEnv->store = $env->store; + } + + foreach ($prototype['arguments'] as $argument) { + list($normalizedName, $name, $default) = $argument; + + if (isset($vars[$normalizedName])) { + continue; + } + assert($default !== null); + + if ($storeInEnv) { + $this->set($name, $this->reduce($default, true), true); + } else { + $output[$name] = ($reduce ? $this->reduce($default, true) : $default); + } + } + + return $output; + } + + /** + * Apply argument values per definition. + * + * This method assumes that the arguments are valid for the provided prototype. + * The validation with {@see verifyPrototype} must have been run before calling + * it. + * Arguments are returned as a map from the normalized argument names to the + * value. Additional arguments are collected in a sass argument list available + * under the name of the rest argument in the result. + * + * Defaults are not applied as they are resolved in a different environment. + * + * @param array $prototype + * @param array $positionalArgs + * @param array $namedArgs + * @param string|null $splatSeparator + * + * @return array + * + * @phpstan-param array{arguments: list, rest_argument: string|null} $prototype + */ + private function applyArgumentsToDeclaration(array $prototype, array $positionalArgs, array $namedArgs, $splatSeparator) + { + $output = []; + $minLength = min(\count($positionalArgs), \count($prototype['arguments'])); + + for ($i = 0; $i < $minLength; $i++) { + list($name) = $prototype['arguments'][$i]; + $val = $positionalArgs[$i]; + + $output[$name] = $val; + } + + $restNamed = $namedArgs; + + for ($i = \count($positionalArgs); $i < \count($prototype['arguments']); $i++) { + $argument = $prototype['arguments'][$i]; + list($name) = $argument; + + if (isset($namedArgs[$name])) { + $val = $namedArgs[$name]; + unset($restNamed[$name]); + } else { + continue; + } + + $output[$name] = $val; + } + + if ($prototype['rest_argument'] !== null) { + $name = $prototype['rest_argument']; + $rest = array_values(array_slice($positionalArgs, \count($prototype['arguments']))); + + $val = [Type::T_LIST, \is_null($splatSeparator) ? ',' : $splatSeparator , $rest, $restNamed]; + + $output[$name] = $val; + } + + return $output; + } + + /** + * Coerce a php value into a scss one + * + * @param mixed $value + * + * @return array|Number + */ + protected function coerceValue($value) + { + if (\is_array($value) || $value instanceof Number) { + return $value; + } + + if (\is_bool($value)) { + return $this->toBool($value); + } + + if (\is_null($value)) { + return static::$null; + } + + if (is_numeric($value)) { + return new Number($value, ''); + } + + if ($value === '') { + return static::$emptyString; + } + + $value = [Type::T_KEYWORD, $value]; + $color = $this->coerceColor($value); + + if ($color) { + return $color; + } + + return $value; + } + + /** + * Tries to convert an item to a Sass map + * + * @param Number|array $item + * + * @return array|null + */ + private function tryMap($item) + { + if ($item instanceof Number) { + return null; + } + + if ($item[0] === Type::T_MAP) { + return $item; + } + + if ( + $item[0] === Type::T_LIST && + $item[2] === [] + ) { + return static::$emptyMap; + } + + return null; + } + + /** + * Coerce something to map + * + * @param array|Number $item + * + * @return array|Number + */ + protected function coerceMap($item) + { + $map = $this->tryMap($item); + + if ($map !== null) { + return $map; + } + + return $item; + } + + /** + * Coerce something to list + * + * @param array|Number $item + * @param string $delim + * @param bool $removeTrailingNull + * + * @return array + */ + protected function coerceList($item, $delim = ',', $removeTrailingNull = false) + { + if ($item instanceof Number) { + return [Type::T_LIST, '', [$item]]; + } + + if ($item[0] === Type::T_LIST) { + // remove trailing null from the list + if ($removeTrailingNull && end($item[2]) === static::$null) { + array_pop($item[2]); + } + + return $item; + } + + if ($item[0] === Type::T_MAP) { + $keys = $item[1]; + $values = $item[2]; + $list = []; + + for ($i = 0, $s = \count($keys); $i < $s; $i++) { + $key = $keys[$i]; + $value = $values[$i]; + + $list[] = [ + Type::T_LIST, + ' ', + [$key, $value] + ]; + } + + return [Type::T_LIST, $list ? ',' : '', $list]; + } + + return [Type::T_LIST, '', [$item]]; + } + + /** + * Coerce color for expression + * + * @param array|Number $value + * + * @return array|Number + */ + protected function coerceForExpression($value) + { + if ($color = $this->coerceColor($value)) { + return $color; + } + + return $value; + } + + /** + * Coerce value to color + * + * @param array|Number $value + * @param bool $inRGBFunction + * + * @return array|null + */ + protected function coerceColor($value, $inRGBFunction = false) + { + if ($value instanceof Number) { + return null; + } + + switch ($value[0]) { + case Type::T_COLOR: + for ($i = 1; $i <= 3; $i++) { + if (! is_numeric($value[$i])) { + $cv = $this->compileRGBAValue($value[$i]); + + if (! is_numeric($cv)) { + return null; + } + + $value[$i] = $cv; + } + + if (isset($value[4])) { + if (! is_numeric($value[4])) { + $cv = $this->compileRGBAValue($value[4], true); + + if (! is_numeric($cv)) { + return null; + } + + $value[4] = $cv; + } + } + } + + return $value; + + case Type::T_LIST: + if ($inRGBFunction) { + if (\count($value[2]) == 3 || \count($value[2]) == 4) { + $color = $value[2]; + array_unshift($color, Type::T_COLOR); + + return $this->coerceColor($color); + } + } + + return null; + + case Type::T_KEYWORD: + if (! \is_string($value[1])) { + return null; + } + + $name = strtolower($value[1]); + + // hexa color? + if (preg_match('/^#([0-9a-f]+)$/i', $name, $m)) { + $nofValues = \strlen($m[1]); + + if (\in_array($nofValues, [3, 4, 6, 8])) { + $nbChannels = 3; + $color = []; + $num = hexdec($m[1]); + + switch ($nofValues) { + case 4: + $nbChannels = 4; + // then continuing with the case 3: + case 3: + for ($i = 0; $i < $nbChannels; $i++) { + $t = $num & 0xf; + array_unshift($color, $t << 4 | $t); + $num >>= 4; + } + + break; + + case 8: + $nbChannels = 4; + // then continuing with the case 6: + case 6: + for ($i = 0; $i < $nbChannels; $i++) { + array_unshift($color, $num & 0xff); + $num >>= 8; + } + + break; + } + + if ($nbChannels === 4) { + if ($color[3] === 255) { + $color[3] = 1; // fully opaque + } else { + $color[3] = round($color[3] / 255, Number::PRECISION); + } + } + + array_unshift($color, Type::T_COLOR); + + return $color; + } + } + + if ($rgba = Colors::colorNameToRGBa($name)) { + return isset($rgba[3]) + ? [Type::T_COLOR, $rgba[0], $rgba[1], $rgba[2], $rgba[3]] + : [Type::T_COLOR, $rgba[0], $rgba[1], $rgba[2]]; + } + + return null; + } + + return null; + } + + /** + * @param int|Number $value + * @param bool $isAlpha + * + * @return int|mixed + */ + protected function compileRGBAValue($value, $isAlpha = false) + { + if ($isAlpha) { + return $this->compileColorPartValue($value, 0, 1, false); + } + + return $this->compileColorPartValue($value, 0, 255, true); + } + + /** + * @param mixed $value + * @param int|float $min + * @param int|float $max + * @param bool $isInt + * + * @return int|mixed + */ + protected function compileColorPartValue($value, $min, $max, $isInt = true) + { + if (! is_numeric($value)) { + if (\is_array($value)) { + $reduced = $this->reduce($value); + + if ($reduced instanceof Number) { + $value = $reduced; + } + } + + if ($value instanceof Number) { + if ($value->unitless()) { + $num = $value->getDimension(); + } elseif ($value->hasUnit('%')) { + $num = $max * $value->getDimension() / 100; + } else { + throw $this->error('Expected %s to have no units or "%%".', $value); + } + + $value = $num; + } elseif (\is_array($value)) { + $value = $this->compileValue($value); + } + } + + if (is_numeric($value)) { + if ($isInt) { + $value = round($value); + } + + $value = min($max, max($min, $value)); + + return $value; + } + + return $value; + } + + /** + * Coerce value to string + * + * @param array|Number $value + * + * @return array + */ + protected function coerceString($value) + { + if ($value[0] === Type::T_STRING) { + return $value; + } + + return [Type::T_STRING, '', [$this->compileValue($value)]]; + } + + /** + * Assert value is a string + * + * This method deals with internal implementation details of the value + * representation where unquoted strings can sometimes be stored under + * other types. + * The returned value is always using the T_STRING type. + * + * @api + * + * @param array|Number $value + * @param string|null $varName + * + * @return array + * + * @throws SassScriptException + */ + public function assertString($value, $varName = null) + { + // case of url(...) parsed a a function + if ($value[0] === Type::T_FUNCTION) { + $value = $this->coerceString($value); + } + + if (! \in_array($value[0], [Type::T_STRING, Type::T_KEYWORD])) { + $value = $this->compileValue($value); + throw SassScriptException::forArgument("$value is not a string.", $varName); + } + + return $this->coerceString($value); + } + + /** + * Coerce value to a percentage + * + * @param array|Number $value + * + * @return int|float + * + * @deprecated + */ + protected function coercePercent($value) + { + @trigger_error(sprintf('"%s" is deprecated since 1.7.0.', __METHOD__), E_USER_DEPRECATED); + + if ($value instanceof Number) { + if ($value->hasUnit('%')) { + return $value->getDimension() / 100; + } + + return $value->getDimension(); + } + + return 0; + } + + /** + * Assert value is a map + * + * @api + * + * @param array|Number $value + * @param string|null $varName + * + * @return array + * + * @throws SassScriptException + */ + public function assertMap($value, $varName = null) + { + $map = $this->tryMap($value); + + if ($map === null) { + $value = $this->compileValue($value); + + throw SassScriptException::forArgument("$value is not a map.", $varName); + } + + return $map; + } + + /** + * Assert value is a list + * + * @api + * + * @param array|Number $value + * + * @return array + * + * @throws \Exception + */ + public function assertList($value) + { + if ($value[0] !== Type::T_LIST) { + throw $this->error('expecting list, %s received', $value[0]); + } + + return $value; + } + + /** + * Gets the keywords of an argument list. + * + * Keys in the returned array are normalized names (underscores are replaced with dashes) + * without the leading `$`. + * Calling this helper with anything that an argument list received for a rest argument + * of the function argument declaration is not supported. + * + * @param array|Number $value + * + * @return array + */ + public function getArgumentListKeywords($value) + { + if ($value[0] !== Type::T_LIST || !isset($value[3]) || !\is_array($value[3])) { + throw new \InvalidArgumentException('The argument is not a sass argument list.'); + } + + return $value[3]; + } + + /** + * Assert value is a color + * + * @api + * + * @param array|Number $value + * @param string|null $varName + * + * @return array + * + * @throws SassScriptException + */ + public function assertColor($value, $varName = null) + { + if ($color = $this->coerceColor($value)) { + return $color; + } + + $value = $this->compileValue($value); + + throw SassScriptException::forArgument("$value is not a color.", $varName); + } + + /** + * Assert value is a number + * + * @api + * + * @param array|Number $value + * @param string|null $varName + * + * @return Number + * + * @throws SassScriptException + */ + public function assertNumber($value, $varName = null) + { + if (!$value instanceof Number) { + $value = $this->compileValue($value); + throw SassScriptException::forArgument("$value is not a number.", $varName); + } + + return $value; + } + + /** + * Assert value is a integer + * + * @api + * + * @param array|Number $value + * @param string|null $varName + * + * @return int + * + * @throws SassScriptException + */ + public function assertInteger($value, $varName = null) + { + $value = $this->assertNumber($value, $varName)->getDimension(); + if (round($value - \intval($value), Number::PRECISION) > 0) { + throw SassScriptException::forArgument("$value is not an integer.", $varName); + } + + return intval($value); + } + + /** + * Extract the ... / alpha on the last argument of channel arg + * in color functions + * + * @param array $args + * @return array + */ + private function extractSlashAlphaInColorFunction($args) + { + $last = end($args); + if (\count($args) === 3 && $last[0] === Type::T_EXPRESSION && $last[1] === '/') { + array_pop($args); + $args[] = $last[2]; + $args[] = $last[3]; + } + return $args; + } + + + /** + * Make sure a color's components don't go out of bounds + * + * @param array $c + * + * @return array + */ + protected function fixColor($c) + { + foreach ([1, 2, 3] as $i) { + if ($c[$i] < 0) { + $c[$i] = 0; + } + + if ($c[$i] > 255) { + $c[$i] = 255; + } + + if (!\is_int($c[$i])) { + $c[$i] = round($c[$i]); + } + } + + return $c; + } + + /** + * Convert RGB to HSL + * + * @internal + * + * @param int $red + * @param int $green + * @param int $blue + * + * @return array + */ + public function toHSL($red, $green, $blue) + { + $min = min($red, $green, $blue); + $max = max($red, $green, $blue); + + $l = $min + $max; + $d = $max - $min; + + if ((int) $d === 0) { + $h = $s = 0; + } else { + if ($l < 255) { + $s = $d / $l; + } else { + $s = $d / (510 - $l); + } + + if ($red == $max) { + $h = 60 * ($green - $blue) / $d; + } elseif ($green == $max) { + $h = 60 * ($blue - $red) / $d + 120; + } elseif ($blue == $max) { + $h = 60 * ($red - $green) / $d + 240; + } + } + + return [Type::T_HSL, fmod($h + 360, 360), $s * 100, $l / 5.1]; + } + + /** + * Hue to RGB helper + * + * @param float $m1 + * @param float $m2 + * @param float $h + * + * @return float + */ + protected function hueToRGB($m1, $m2, $h) + { + if ($h < 0) { + $h += 1; + } elseif ($h > 1) { + $h -= 1; + } + + if ($h * 6 < 1) { + return $m1 + ($m2 - $m1) * $h * 6; + } + + if ($h * 2 < 1) { + return $m2; + } + + if ($h * 3 < 2) { + return $m1 + ($m2 - $m1) * (2 / 3 - $h) * 6; + } + + return $m1; + } + + /** + * Convert HSL to RGB + * + * @internal + * + * @param int|float $hue H from 0 to 360 + * @param int|float $saturation S from 0 to 100 + * @param int|float $lightness L from 0 to 100 + * + * @return array + */ + public function toRGB($hue, $saturation, $lightness) + { + if ($hue < 0) { + $hue += 360; + } + + $h = $hue / 360; + $s = min(100, max(0, $saturation)) / 100; + $l = min(100, max(0, $lightness)) / 100; + + $m2 = $l <= 0.5 ? $l * ($s + 1) : $l + $s - $l * $s; + $m1 = $l * 2 - $m2; + + $r = $this->hueToRGB($m1, $m2, $h + 1 / 3) * 255; + $g = $this->hueToRGB($m1, $m2, $h) * 255; + $b = $this->hueToRGB($m1, $m2, $h - 1 / 3) * 255; + + $out = [Type::T_COLOR, $r, $g, $b]; + + return $out; + } + + /** + * Convert HWB to RGB + * https://www.w3.org/TR/css-color-4/#hwb-to-rgb + * + * @api + * + * @param int $hue H from 0 to 360 + * @param int $whiteness W from 0 to 100 + * @param int $blackness B from 0 to 100 + * + * @return array + */ + private function HWBtoRGB($hue, $whiteness, $blackness) + { + $w = min(100, max(0, $whiteness)) / 100; + $b = min(100, max(0, $blackness)) / 100; + + $sum = $w + $b; + if ($sum > 1.0) { + $w = $w / $sum; + $b = $b / $sum; + } + $b = min(1.0 - $w, $b); + + $rgb = $this->toRGB($hue, 100, 50); + for($i = 1; $i < 4; $i++) { + $rgb[$i] *= (1.0 - $w - $b); + $rgb[$i] = round($rgb[$i] + 255 * $w + 0.0001); + } + + return $rgb; + } + + /** + * Convert RGB to HWB + * + * @api + * + * @param int $red + * @param int $green + * @param int $blue + * + * @return array + */ + private function RGBtoHWB($red, $green, $blue) + { + $min = min($red, $green, $blue); + $max = max($red, $green, $blue); + + $d = $max - $min; + + if ((int) $d === 0) { + $h = 0; + } else { + + if ($red == $max) { + $h = 60 * ($green - $blue) / $d; + } elseif ($green == $max) { + $h = 60 * ($blue - $red) / $d + 120; + } elseif ($blue == $max) { + $h = 60 * ($red - $green) / $d + 240; + } + } + + return [Type::T_HWB, fmod($h, 360), $min / 255 * 100, 100 - $max / 255 *100]; + } + + + // Built in functions + + protected static $libCall = ['function', 'args...']; + protected function libCall($args) + { + $functionReference = $args[0]; + + if (in_array($functionReference[0], [Type::T_STRING, Type::T_KEYWORD])) { + $name = $this->compileStringContent($this->coerceString($functionReference)); + $warning = "Passing a string to call() is deprecated and will be illegal\n" + . "in Sass 4.0. Use call(function-reference($name)) instead."; + Warn::deprecation($warning); + $functionReference = $this->libGetFunction([$this->assertString($functionReference, 'function')]); + } + + if ($functionReference === static::$null) { + return static::$null; + } + + if (! in_array($functionReference[0], [Type::T_FUNCTION_REFERENCE, Type::T_FUNCTION])) { + throw $this->error('Function reference expected, got ' . $functionReference[0]); + } + + $callArgs = [ + [null, $args[1], true] + ]; + + return $this->reduce([Type::T_FUNCTION_CALL, $functionReference, $callArgs]); + } + + + protected static $libGetFunction = [ + ['name'], + ['name', 'css'] + ]; + protected function libGetFunction($args) + { + $name = $this->compileStringContent($this->assertString(array_shift($args), 'name')); + $isCss = false; + + if (count($args)) { + $isCss = array_shift($args); + $isCss = (($isCss === static::$true) ? true : false); + } + + if ($isCss) { + return [Type::T_FUNCTION, $name, [Type::T_LIST, ',', []]]; + } + + return $this->getFunctionReference($name, true); + } + + protected static $libIf = ['condition', 'if-true', 'if-false:']; + protected function libIf($args) + { + list($cond, $t, $f) = $args; + + if (! $this->isTruthy($this->reduce($cond, true))) { + return $this->reduce($f, true); + } + + return $this->reduce($t, true); + } + + protected static $libIndex = ['list', 'value']; + protected function libIndex($args) + { + list($list, $value) = $args; + + if ( + $list[0] === Type::T_MAP || + $list[0] === Type::T_STRING || + $list[0] === Type::T_KEYWORD || + $list[0] === Type::T_INTERPOLATE + ) { + $list = $this->coerceList($list, ' '); + } + + if ($list[0] !== Type::T_LIST) { + return static::$null; + } + + // Numbers are represented with value objects, for which the PHP equality operator does not + // match the Sass rules (and we cannot overload it). As they are the only type of values + // represented with a value object for now, they require a special case. + if ($value instanceof Number) { + $key = 0; + foreach ($list[2] as $item) { + $key++; + $itemValue = $this->normalizeValue($item); + + if ($itemValue instanceof Number && $value->equals($itemValue)) { + return new Number($key, ''); + } + } + return static::$null; + } + + $values = []; + + foreach ($list[2] as $item) { + $values[] = $this->normalizeValue($item); + } + + $key = array_search($this->normalizeValue($value), $values); + + return false === $key ? static::$null : new Number($key + 1, ''); + } + + protected static $libRgb = [ + ['color'], + ['color', 'alpha'], + ['channels'], + ['red', 'green', 'blue'], + ['red', 'green', 'blue', 'alpha'] ]; + protected function libRgb($args, $kwargs, $funcName = 'rgb') + { + switch (\count($args)) { + case 1: + if (! $color = $this->coerceColor($args[0], true)) { + $color = [Type::T_STRING, '', [$funcName . '(', $args[0], ')']]; + } + break; + + case 3: + $color = [Type::T_COLOR, $args[0], $args[1], $args[2]]; + + if (! $color = $this->coerceColor($color)) { + $color = [Type::T_STRING, '', [$funcName . '(', $args[0], ', ', $args[1], ', ', $args[2], ')']]; + } + + return $color; + + case 2: + if ($color = $this->coerceColor($args[0], true)) { + $alpha = $this->compileRGBAValue($args[1], true); + + if (is_numeric($alpha)) { + $color[4] = $alpha; + } else { + $color = [Type::T_STRING, '', + [$funcName . '(', $color[1], ', ', $color[2], ', ', $color[3], ', ', $alpha, ')']]; + } + } else { + $color = [Type::T_STRING, '', [$funcName . '(', $args[0], ', ', $args[1], ')']]; + } + break; + + case 4: + default: + $color = [Type::T_COLOR, $args[0], $args[1], $args[2], $args[3]]; + + if (! $color = $this->coerceColor($color)) { + $color = [Type::T_STRING, '', + [$funcName . '(', $args[0], ', ', $args[1], ', ', $args[2], ', ', $args[3], ')']]; + } + break; + } + + return $color; + } + + protected static $libRgba = [ + ['color'], + ['color', 'alpha'], + ['channels'], + ['red', 'green', 'blue'], + ['red', 'green', 'blue', 'alpha'] ]; + protected function libRgba($args, $kwargs) + { + return $this->libRgb($args, $kwargs, 'rgba'); + } + + /** + * Helper function for adjust_color, change_color, and scale_color + * + * @param array $args + * @param string $operation + * @param callable $fn + * + * @return array + * + * @phpstan-param callable(float|int, float|int|null, float|int): (float|int) $fn + */ + protected function alterColor(array $args, $operation, $fn) + { + $color = $this->assertColor($args[0], 'color'); + + if ($args[1][2]) { + throw new SassScriptException('Only one positional argument is allowed. All other arguments must be passed by name.'); + } + + $kwargs = $this->getArgumentListKeywords($args[1]); + + $scale = $operation === 'scale'; + $change = $operation === 'change'; + + /** + * @param string $name + * @param float|int $max + * @param bool $checkPercent + * @param bool $assertPercent + * + * @return float|int|null + */ + $getParam = function ($name, $max, $checkPercent = false, $assertPercent = false) use (&$kwargs, $scale, $change) { + if (!isset($kwargs[$name])) { + return null; + } + + $number = $this->assertNumber($kwargs[$name], $name); + unset($kwargs[$name]); + + if (!$scale && $checkPercent) { + if (!$number->hasUnit('%')) { + $warning = $this->error("{$name} Passing a number `$number` without unit % is deprecated."); + $this->logger->warn($warning->getMessage(), true); + } + } + + if ($scale || $assertPercent) { + $number->assertUnit('%', $name); + } + + if ($scale) { + $max = 100; + } + + return $number->valueInRange($change ? 0 : -$max, $max, $name); + }; + + $alpha = $getParam('alpha', 1); + $red = $getParam('red', 255); + $green = $getParam('green', 255); + $blue = $getParam('blue', 255); + + if ($scale || !isset($kwargs['hue'])) { + $hue = null; + } else { + $hueNumber = $this->assertNumber($kwargs['hue'], 'hue'); + unset($kwargs['hue']); + $hue = $hueNumber->getDimension(); + } + $saturation = $getParam('saturation', 100, true); + $lightness = $getParam('lightness', 100, true); + $whiteness = $getParam('whiteness', 100, false, true); + $blackness = $getParam('blackness', 100, false, true); + + if (!empty($kwargs)) { + $unknownNames = array_keys($kwargs); + $lastName = array_pop($unknownNames); + $message = sprintf( + 'No argument%s named $%s%s.', + $unknownNames ? 's' : '', + $unknownNames ? implode(', $', $unknownNames) . ' or $' : '', + $lastName + ); + throw new SassScriptException($message); + } + + $hasRgb = $red !== null || $green !== null || $blue !== null; + $hasSL = $saturation !== null || $lightness !== null; + $hasWB = $whiteness !== null || $blackness !== null; + $found = false; + + if ($hasRgb && ($hasSL || $hasWB || $hue !== null)) { + throw new SassScriptException(sprintf('RGB parameters may not be passed along with %s parameters.', $hasWB ? 'HWB' : 'HSL')); + } + + if ($hasWB && $hasSL) { + throw new SassScriptException('HSL parameters may not be passed along with HWB parameters.'); + } + + if ($hasRgb) { + $color[1] = round($fn($color[1], $red, 255)); + $color[2] = round($fn($color[2], $green, 255)); + $color[3] = round($fn($color[3], $blue, 255)); + } elseif ($hasWB) { + $hwb = $this->RGBtoHWB($color[1], $color[2], $color[3]); + if ($hue !== null) { + $hwb[1] = $change ? $hue : $hwb[1] + $hue; + } + $hwb[2] = $fn($hwb[2], $whiteness, 100); + $hwb[3] = $fn($hwb[3], $blackness, 100); + + $rgb = $this->HWBtoRGB($hwb[1], $hwb[2], $hwb[3]); + + if (isset($color[4])) { + $rgb[4] = $color[4]; + } + + $color = $rgb; + } elseif ($hue !== null || $hasSL) { + $hsl = $this->toHSL($color[1], $color[2], $color[3]); + + if ($hue !== null) { + $hsl[1] = $change ? $hue : $hsl[1] + $hue; + } + $hsl[2] = $fn($hsl[2], $saturation, 100); + $hsl[3] = $fn($hsl[3], $lightness, 100); + + $rgb = $this->toRGB($hsl[1], $hsl[2], $hsl[3]); + + if (isset($color[4])) { + $rgb[4] = $color[4]; + } + + $color = $rgb; + } + + if ($alpha !== null) { + $existingAlpha = isset($color[4]) ? $color[4] : 1; + $color[4] = $fn($existingAlpha, $alpha, 1); + } + + return $color; + } + + protected static $libAdjustColor = ['color', 'kwargs...']; + protected function libAdjustColor($args) + { + return $this->alterColor($args, 'adjust', function ($base, $alter, $max) { + if ($alter === null) { + return $base; + } + + $new = $base + $alter; + + if ($new < 0) { + return 0; + } + + if ($new > $max) { + return $max; + } + + return $new; + }); + } + + protected static $libChangeColor = ['color', 'kwargs...']; + protected function libChangeColor($args) + { + return $this->alterColor($args,'change', function ($base, $alter, $max) { + if ($alter === null) { + return $base; + } + + return $alter; + }); + } + + protected static $libScaleColor = ['color', 'kwargs...']; + protected function libScaleColor($args) + { + return $this->alterColor($args, 'scale', function ($base, $scale, $max) { + if ($scale === null) { + return $base; + } + + $scale = $scale / 100; + + if ($scale < 0) { + return $base * $scale + $base; + } + + return ($max - $base) * $scale + $base; + }); + } + + protected static $libIeHexStr = ['color']; + protected function libIeHexStr($args) + { + $color = $this->coerceColor($args[0]); + + if (\is_null($color)) { + throw $this->error('Error: argument `$color` of `ie-hex-str($color)` must be a color'); + } + + $color[4] = isset($color[4]) ? round(255 * $color[4]) : 255; + + return [Type::T_STRING, '', [sprintf('#%02X%02X%02X%02X', $color[4], $color[1], $color[2], $color[3])]]; + } + + protected static $libRed = ['color']; + protected function libRed($args) + { + $color = $this->coerceColor($args[0]); + + if (\is_null($color)) { + throw $this->error('Error: argument `$color` of `red($color)` must be a color'); + } + + return new Number((int) $color[1], ''); + } + + protected static $libGreen = ['color']; + protected function libGreen($args) + { + $color = $this->coerceColor($args[0]); + + if (\is_null($color)) { + throw $this->error('Error: argument `$color` of `green($color)` must be a color'); + } + + return new Number((int) $color[2], ''); + } + + protected static $libBlue = ['color']; + protected function libBlue($args) + { + $color = $this->coerceColor($args[0]); + + if (\is_null($color)) { + throw $this->error('Error: argument `$color` of `blue($color)` must be a color'); + } + + return new Number((int) $color[3], ''); + } + + protected static $libAlpha = ['color']; + protected function libAlpha($args) + { + if ($color = $this->coerceColor($args[0])) { + return new Number(isset($color[4]) ? $color[4] : 1, ''); + } + + // this might be the IE function, so return value unchanged + return null; + } + + protected static $libOpacity = ['color']; + protected function libOpacity($args) + { + $value = $args[0]; + + if ($value instanceof Number) { + return null; + } + + return $this->libAlpha($args); + } + + // mix two colors + protected static $libMix = [ + ['color1', 'color2', 'weight:50%'], + ['color-1', 'color-2', 'weight:50%'] + ]; + protected function libMix($args) + { + list($first, $second, $weight) = $args; + + $first = $this->assertColor($first, 'color1'); + $second = $this->assertColor($second, 'color2'); + $weightScale = $this->assertNumber($weight, 'weight')->valueInRange(0, 100, 'weight') / 100; + + $firstAlpha = isset($first[4]) ? $first[4] : 1; + $secondAlpha = isset($second[4]) ? $second[4] : 1; + + $normalizedWeight = $weightScale * 2 - 1; + $alphaDistance = $firstAlpha - $secondAlpha; + + $combinedWeight = $normalizedWeight * $alphaDistance == -1 ? $normalizedWeight : ($normalizedWeight + $alphaDistance) / (1 + $normalizedWeight * $alphaDistance); + $weight1 = ($combinedWeight + 1) / 2.0; + $weight2 = 1.0 - $weight1; + + $new = [Type::T_COLOR, + $weight1 * $first[1] + $weight2 * $second[1], + $weight1 * $first[2] + $weight2 * $second[2], + $weight1 * $first[3] + $weight2 * $second[3], + ]; + + if ($firstAlpha != 1.0 || $secondAlpha != 1.0) { + $new[] = $firstAlpha * $weightScale + $secondAlpha * (1 - $weightScale); + } + + return $this->fixColor($new); + } + + protected static $libHsl = [ + ['channels'], + ['hue', 'saturation'], + ['hue', 'saturation', 'lightness'], + ['hue', 'saturation', 'lightness', 'alpha'] ]; + protected function libHsl($args, $kwargs, $funcName = 'hsl') + { + $args_to_check = $args; + + if (\count($args) == 1) { + if ($args[0][0] !== Type::T_LIST || \count($args[0][2]) < 3 || \count($args[0][2]) > 4) { + return [Type::T_STRING, '', [$funcName . '(', $args[0], ')']]; + } + + $args = $args[0][2]; + $args_to_check = $kwargs['channels'][2]; + } + + if (\count($args) === 2) { + // if var() is used as an argument, return as a css function + foreach ($args as $arg) { + if ($arg[0] === Type::T_FUNCTION && in_array($arg[1], ['var'])) { + return null; + } + } + + throw new SassScriptException('Missing argument $lightness.'); + } + + foreach ($kwargs as $k => $arg) { + if (in_array($arg[0], [Type::T_FUNCTION_CALL, Type::T_FUNCTION]) && in_array($arg[1], ['min', 'max'])) { + return null; + } + } + + foreach ($args_to_check as $k => $arg) { + if (in_array($arg[0], [Type::T_FUNCTION_CALL, Type::T_FUNCTION]) && in_array($arg[1], ['min', 'max'])) { + if (count($kwargs) > 1 || ($k >= 2 && count($args) === 4)) { + return null; + } + + $args[$k] = $this->stringifyFncallArgs($arg); + } + + if ( + $k >= 2 && count($args) === 4 && + in_array($arg[0], [Type::T_FUNCTION_CALL, Type::T_FUNCTION]) && + in_array($arg[1], ['calc','env']) + ) { + return null; + } + } + + $hue = $this->reduce($args[0]); + $saturation = $this->reduce($args[1]); + $lightness = $this->reduce($args[2]); + $alpha = null; + + if (\count($args) === 4) { + $alpha = $this->compileColorPartValue($args[3], 0, 100, false); + + if (!$hue instanceof Number || !$saturation instanceof Number || ! $lightness instanceof Number || ! is_numeric($alpha)) { + return [Type::T_STRING, '', + [$funcName . '(', $args[0], ', ', $args[1], ', ', $args[2], ', ', $args[3], ')']]; + } + } else { + if (!$hue instanceof Number || !$saturation instanceof Number || ! $lightness instanceof Number) { + return [Type::T_STRING, '', [$funcName . '(', $args[0], ', ', $args[1], ', ', $args[2], ')']]; + } + } + + $hueValue = fmod($hue->getDimension(), 360); + + while ($hueValue < 0) { + $hueValue += 360; + } + + $color = $this->toRGB($hueValue, max(0, min($saturation->getDimension(), 100)), max(0, min($lightness->getDimension(), 100))); + + if (! \is_null($alpha)) { + $color[4] = $alpha; + } + + return $color; + } + + protected static $libHsla = [ + ['channels'], + ['hue', 'saturation'], + ['hue', 'saturation', 'lightness'], + ['hue', 'saturation', 'lightness', 'alpha']]; + protected function libHsla($args, $kwargs) + { + return $this->libHsl($args, $kwargs, 'hsla'); + } + + protected static $libHue = ['color']; + protected function libHue($args) + { + $color = $this->assertColor($args[0], 'color'); + $hsl = $this->toHSL($color[1], $color[2], $color[3]); + + return new Number($hsl[1], 'deg'); + } + + protected static $libSaturation = ['color']; + protected function libSaturation($args) + { + $color = $this->assertColor($args[0], 'color'); + $hsl = $this->toHSL($color[1], $color[2], $color[3]); + + return new Number($hsl[2], '%'); + } + + protected static $libLightness = ['color']; + protected function libLightness($args) + { + $color = $this->assertColor($args[0], 'color'); + $hsl = $this->toHSL($color[1], $color[2], $color[3]); + + return new Number($hsl[3], '%'); + } + + /* + * Todo : a integrer dans le futur module color + protected static $libHwb = [ + ['channels'], + ['hue', 'whiteness', 'blackness'], + ['hue', 'whiteness', 'blackness', 'alpha'] ]; + protected function libHwb($args, $kwargs, $funcName = 'hwb') + { + $args_to_check = $args; + + if (\count($args) == 1) { + if ($args[0][0] !== Type::T_LIST) { + throw $this->error("Missing elements \$whiteness and \$blackness"); + } + + if (\trim($args[0][1])) { + throw $this->error("\$channels must be a space-separated list."); + } + + if (! empty($args[0]['enclosing'])) { + throw $this->error("\$channels must be an unbracketed list."); + } + + $args = $args[0][2]; + if (\count($args) > 3) { + throw $this->error("hwb() : Only 3 elements are allowed but ". \count($args) . "were passed"); + } + + $args_to_check = $this->extractSlashAlphaInColorFunction($kwargs['channels'][2]); + if (\count($args_to_check) !== \count($kwargs['channels'][2])) { + $args = $args_to_check; + } + } + + if (\count($args_to_check) < 2) { + throw $this->error("Missing elements \$whiteness and \$blackness"); + } + if (\count($args_to_check) < 3) { + throw $this->error("Missing element \$blackness"); + } + if (\count($args_to_check) > 4) { + throw $this->error("hwb() : Only 4 elements are allowed but ". \count($args) . "were passed"); + } + + foreach ($kwargs as $k => $arg) { + if (in_array($arg[0], [Type::T_FUNCTION_CALL]) && in_array($arg[1], ['min', 'max'])) { + return null; + } + } + + foreach ($args_to_check as $k => $arg) { + if (in_array($arg[0], [Type::T_FUNCTION_CALL]) && in_array($arg[1], ['min', 'max'])) { + if (count($kwargs) > 1 || ($k >= 2 && count($args) === 4)) { + return null; + } + + $args[$k] = $this->stringifyFncallArgs($arg); + } + + if ( + $k >= 2 && count($args) === 4 && + in_array($arg[0], [Type::T_FUNCTION_CALL, Type::T_FUNCTION]) && + in_array($arg[1], ['calc','env']) + ) { + return null; + } + } + + $hue = $this->reduce($args[0]); + $whiteness = $this->reduce($args[1]); + $blackness = $this->reduce($args[2]); + $alpha = null; + + if (\count($args) === 4) { + $alpha = $this->compileColorPartValue($args[3], 0, 1, false); + + if (! \is_numeric($alpha)) { + $val = $this->compileValue($args[3]); + throw $this->error("\$alpha: $val is not a number"); + } + } + + $this->assertNumber($hue, 'hue'); + $this->assertUnit($whiteness, ['%'], 'whiteness'); + $this->assertUnit($blackness, ['%'], 'blackness'); + + $this->assertRange($whiteness, 0, 100, "0% and 100%", "whiteness"); + $this->assertRange($blackness, 0, 100, "0% and 100%", "blackness"); + + $w = $whiteness->getDimension(); + $b = $blackness->getDimension(); + + $hueValue = $hue->getDimension() % 360; + + while ($hueValue < 0) { + $hueValue += 360; + } + + $color = $this->HWBtoRGB($hueValue, $w, $b); + + if (! \is_null($alpha)) { + $color[4] = $alpha; + } + + return $color; + } + + protected static $libWhiteness = ['color']; + protected function libWhiteness($args, $kwargs, $funcName = 'whiteness') { + + $color = $this->assertColor($args[0]); + $hwb = $this->RGBtoHWB($color[1], $color[2], $color[3]); + + return new Number($hwb[2], '%'); + } + + protected static $libBlackness = ['color']; + protected function libBlackness($args, $kwargs, $funcName = 'blackness') { + + $color = $this->assertColor($args[0]); + $hwb = $this->RGBtoHWB($color[1], $color[2], $color[3]); + + return new Number($hwb[3], '%'); + } + */ + + /** + * @param array $color + * @param int $idx + * @param int|float $amount + * + * @return array + */ + protected function adjustHsl($color, $idx, $amount) + { + $hsl = $this->toHSL($color[1], $color[2], $color[3]); + $hsl[$idx] += $amount; + + if ($idx !== 1) { + // Clamp the saturation and lightness + $hsl[$idx] = min(max(0, $hsl[$idx]), 100); + } + + $out = $this->toRGB($hsl[1], $hsl[2], $hsl[3]); + + if (isset($color[4])) { + $out[4] = $color[4]; + } + + return $out; + } + + protected static $libAdjustHue = ['color', 'degrees']; + protected function libAdjustHue($args) + { + $color = $this->assertColor($args[0], 'color'); + $degrees = $this->assertNumber($args[1], 'degrees')->getDimension(); + + return $this->adjustHsl($color, 1, $degrees); + } + + protected static $libLighten = ['color', 'amount']; + protected function libLighten($args) + { + $color = $this->assertColor($args[0], 'color'); + $amount = Util::checkRange('amount', new Range(0, 100), $args[1], '%'); + + return $this->adjustHsl($color, 3, $amount); + } + + protected static $libDarken = ['color', 'amount']; + protected function libDarken($args) + { + $color = $this->assertColor($args[0], 'color'); + $amount = Util::checkRange('amount', new Range(0, 100), $args[1], '%'); + + return $this->adjustHsl($color, 3, -$amount); + } + + protected static $libSaturate = [['color', 'amount'], ['amount']]; + protected function libSaturate($args) + { + $value = $args[0]; + + if (count($args) === 1) { + $this->assertNumber($args[0], 'amount'); + + return null; + } + + $color = $this->assertColor($args[0], 'color'); + $amount = $this->assertNumber($args[1], 'amount'); + + return $this->adjustHsl($color, 2, $amount->valueInRange(0, 100, 'amount')); + } + + protected static $libDesaturate = ['color', 'amount']; + protected function libDesaturate($args) + { + $color = $this->assertColor($args[0], 'color'); + $amount = $this->assertNumber($args[1], 'amount'); + + return $this->adjustHsl($color, 2, -$amount->valueInRange(0, 100, 'amount')); + } + + protected static $libGrayscale = ['color']; + protected function libGrayscale($args) + { + $value = $args[0]; + + if ($value instanceof Number) { + return null; + } + + return $this->adjustHsl($this->assertColor($value, 'color'), 2, -100); + } + + protected static $libComplement = ['color']; + protected function libComplement($args) + { + return $this->adjustHsl($this->assertColor($args[0], 'color'), 1, 180); + } + + protected static $libInvert = ['color', 'weight:100%']; + protected function libInvert($args) + { + $value = $args[0]; + + $weight = $this->assertNumber($args[1], 'weight'); + + if ($value instanceof Number) { + if ($weight->getDimension() != 100 || !$weight->hasUnit('%')) { + throw new SassScriptException('Only one argument may be passed to the plain-CSS invert() function.'); + } + + return null; + } + + $color = $this->assertColor($value, 'color'); + $inverted = $color; + $inverted[1] = 255 - $inverted[1]; + $inverted[2] = 255 - $inverted[2]; + $inverted[3] = 255 - $inverted[3]; + + return $this->libMix([$inverted, $color, $weight]); + } + + // increases opacity by amount + protected static $libOpacify = ['color', 'amount']; + protected function libOpacify($args) + { + $color = $this->assertColor($args[0], 'color'); + $amount = $this->assertNumber($args[1], 'amount'); + + $color[4] = (isset($color[4]) ? $color[4] : 1) + $amount->valueInRange(0, 1, 'amount'); + $color[4] = min(1, max(0, $color[4])); + + return $color; + } + + protected static $libFadeIn = ['color', 'amount']; + protected function libFadeIn($args) + { + return $this->libOpacify($args); + } + + // decreases opacity by amount + protected static $libTransparentize = ['color', 'amount']; + protected function libTransparentize($args) + { + $color = $this->assertColor($args[0], 'color'); + $amount = $this->assertNumber($args[1], 'amount'); + + $color[4] = (isset($color[4]) ? $color[4] : 1) - $amount->valueInRange(0, 1, 'amount'); + $color[4] = min(1, max(0, $color[4])); + + return $color; + } + + protected static $libFadeOut = ['color', 'amount']; + protected function libFadeOut($args) + { + return $this->libTransparentize($args); + } + + protected static $libUnquote = ['string']; + protected function libUnquote($args) + { + try { + $str = $this->assertString($args[0], 'string'); + } catch (SassScriptException $e) { + $value = $this->compileValue($args[0]); + $fname = $this->getPrettyPath($this->sourceNames[$this->sourceIndex]); + $line = $this->sourceLine; + + $message = "Passing $value, a non-string value, to unquote() +will be an error in future versions of Sass.\n on line $line of $fname"; + + $this->logger->warn($message, true); + + return $args[0]; + } + + $str[1] = ''; + + return $str; + } + + protected static $libQuote = ['string']; + protected function libQuote($args) + { + $value = $this->assertString($args[0], 'string'); + + $value[1] = '"'; + + return $value; + } + + protected static $libPercentage = ['number']; + protected function libPercentage($args) + { + $num = $this->assertNumber($args[0], 'number'); + $num->assertNoUnits('number'); + + return new Number($num->getDimension() * 100, '%'); + } + + protected static $libRound = ['number']; + protected function libRound($args) + { + $num = $this->assertNumber($args[0], 'number'); + + return new Number(round($num->getDimension()), $num->getNumeratorUnits(), $num->getDenominatorUnits()); + } + + protected static $libFloor = ['number']; + protected function libFloor($args) + { + $num = $this->assertNumber($args[0], 'number'); + + return new Number(floor($num->getDimension()), $num->getNumeratorUnits(), $num->getDenominatorUnits()); + } + + protected static $libCeil = ['number']; + protected function libCeil($args) + { + $num = $this->assertNumber($args[0], 'number'); + + return new Number(ceil($num->getDimension()), $num->getNumeratorUnits(), $num->getDenominatorUnits()); + } + + protected static $libAbs = ['number']; + protected function libAbs($args) + { + $num = $this->assertNumber($args[0], 'number'); + + return new Number(abs($num->getDimension()), $num->getNumeratorUnits(), $num->getDenominatorUnits()); + } + + protected static $libMin = ['numbers...']; + protected function libMin($args) + { + /** + * @var Number|null + */ + $min = null; + + foreach ($args[0][2] as $arg) { + $number = $this->assertNumber($arg); + + if (\is_null($min) || $min->greaterThan($number)) { + $min = $number; + } + } + + if (!\is_null($min)) { + return $min; + } + + throw $this->error('At least one argument must be passed.'); + } + + protected static $libMax = ['numbers...']; + protected function libMax($args) + { + /** + * @var Number|null + */ + $max = null; + + foreach ($args[0][2] as $arg) { + $number = $this->assertNumber($arg); + + if (\is_null($max) || $max->lessThan($number)) { + $max = $number; + } + } + + if (!\is_null($max)) { + return $max; + } + + throw $this->error('At least one argument must be passed.'); + } + + protected static $libLength = ['list']; + protected function libLength($args) + { + $list = $this->coerceList($args[0], ',', true); + + return new Number(\count($list[2]), ''); + } + + protected static $libListSeparator = ['list']; + protected function libListSeparator($args) + { + if (! \in_array($args[0][0], [Type::T_LIST, Type::T_MAP])) { + return [Type::T_KEYWORD, 'space']; + } + + $list = $this->coerceList($args[0]); + + if ($list[1] === '' && \count($list[2]) <= 1 && empty($list['enclosing'])) { + return [Type::T_KEYWORD, 'space']; + } + + if ($list[1] === ',') { + return [Type::T_KEYWORD, 'comma']; + } + + if ($list[1] === '/') { + return [Type::T_KEYWORD, 'slash']; + } + + return [Type::T_KEYWORD, 'space']; + } + + protected static $libNth = ['list', 'n']; + protected function libNth($args) + { + $list = $this->coerceList($args[0], ',', false); + $n = $this->assertNumber($args[1])->getDimension(); + + if ($n > 0) { + $n--; + } elseif ($n < 0) { + $n += \count($list[2]); + } + + return isset($list[2][$n]) ? $list[2][$n] : static::$defaultValue; + } + + protected static $libSetNth = ['list', 'n', 'value']; + protected function libSetNth($args) + { + $list = $this->coerceList($args[0]); + $n = $this->assertNumber($args[1])->getDimension(); + + if ($n > 0) { + $n--; + } elseif ($n < 0) { + $n += \count($list[2]); + } + + if (! isset($list[2][$n])) { + throw $this->error('Invalid argument for "n"'); + } + + $list[2][$n] = $args[2]; + + return $list; + } + + protected static $libMapGet = ['map', 'key', 'keys...']; + protected function libMapGet($args) + { + $map = $this->assertMap($args[0], 'map'); + if (!isset($args[2])) { + // BC layer for usages of the function from PHP code rather than from the Sass function + $args[2] = self::$emptyArgumentList; + } + $keys = array_merge([$args[1]], $args[2][2]); + $value = static::$null; + + foreach ($keys as $key) { + if (!\is_array($map) || $map[0] !== Type::T_MAP) { + return static::$null; + } + + $map = $this->mapGet($map, $key); + + if ($map === null) { + return static::$null; + } + + $value = $map; + } + + return $value; + } + + /** + * Gets the value corresponding to that key in the map + * + * @param array $map + * @param Number|array $key + * + * @return Number|array|null + */ + private function mapGet(array $map, $key) + { + $index = $this->mapGetEntryIndex($map, $key); + + if ($index !== null) { + return $map[2][$index]; + } + + return null; + } + + /** + * Gets the index corresponding to that key in the map entries + * + * @param array $map + * @param Number|array $key + * + * @return int|null + */ + private function mapGetEntryIndex(array $map, $key) + { + $key = $this->compileStringContent($this->coerceString($key)); + + for ($i = \count($map[1]) - 1; $i >= 0; $i--) { + if ($key === $this->compileStringContent($this->coerceString($map[1][$i]))) { + return $i; + } + } + + return null; + } + + protected static $libMapKeys = ['map']; + protected function libMapKeys($args) + { + $map = $this->assertMap($args[0], 'map'); + $keys = $map[1]; + + return [Type::T_LIST, ',', $keys]; + } + + protected static $libMapValues = ['map']; + protected function libMapValues($args) + { + $map = $this->assertMap($args[0], 'map'); + $values = $map[2]; + + return [Type::T_LIST, ',', $values]; + } + + protected static $libMapRemove = [ + ['map'], + ['map', 'key', 'keys...'], + ]; + protected function libMapRemove($args) + { + $map = $this->assertMap($args[0], 'map'); + + if (\count($args) === 1) { + return $map; + } + + $keys = []; + $keys[] = $this->compileStringContent($this->coerceString($args[1])); + + foreach ($args[2][2] as $key) { + $keys[] = $this->compileStringContent($this->coerceString($key)); + } + + for ($i = \count($map[1]) - 1; $i >= 0; $i--) { + if (in_array($this->compileStringContent($this->coerceString($map[1][$i])), $keys)) { + array_splice($map[1], $i, 1); + array_splice($map[2], $i, 1); + } + } + + return $map; + } + + protected static $libMapHasKey = ['map', 'key', 'keys...']; + protected function libMapHasKey($args) + { + $map = $this->assertMap($args[0], 'map'); + if (!isset($args[2])) { + // BC layer for usages of the function from PHP code rather than from the Sass function + $args[2] = self::$emptyArgumentList; + } + $keys = array_merge([$args[1]], $args[2][2]); + $lastKey = array_pop($keys); + + foreach ($keys as $key) { + $value = $this->mapGet($map, $key); + + if ($value === null || $value instanceof Number || $value[0] !== Type::T_MAP) { + return self::$false; + } + + $map = $value; + } + + return $this->toBool($this->mapHasKey($map, $lastKey)); + } + + /** + * @param array|Number $keyValue + * + * @return bool + */ + private function mapHasKey(array $map, $keyValue) + { + $key = $this->compileStringContent($this->coerceString($keyValue)); + + for ($i = \count($map[1]) - 1; $i >= 0; $i--) { + if ($key === $this->compileStringContent($this->coerceString($map[1][$i]))) { + return true; + } + } + + return false; + } + + protected static $libMapMerge = [ + ['map1', 'map2'], + ['map-1', 'map-2'], + ['map1', 'args...'] + ]; + protected function libMapMerge($args) + { + $map1 = $this->assertMap($args[0], 'map1'); + $map2 = $args[1]; + $keys = []; + if ($map2[0] === Type::T_LIST && isset($map2[3]) && \is_array($map2[3])) { + // This is an argument list for the variadic signature + if (\count($map2[2]) === 0) { + throw new SassScriptException('Expected $args to contain a key.'); + } + if (\count($map2[2]) === 1) { + throw new SassScriptException('Expected $args to contain a value.'); + } + $keys = $map2[2]; + $map2 = array_pop($keys); + } + $map2 = $this->assertMap($map2, 'map2'); + + return $this->modifyMap($map1, $keys, function ($oldValue) use ($map2) { + $nestedMap = $this->tryMap($oldValue); + + if ($nestedMap === null) { + return $map2; + } + + return $this->mergeMaps($nestedMap, $map2); + }); + } + + /** + * @param array $map + * @param array $keys + * @param callable $modify + * @param bool $addNesting + * + * @return Number|array + * + * @phpstan-param array $keys + * @phpstan-param callable(Number|array): (Number|array) $modify + */ + private function modifyMap(array $map, array $keys, callable $modify, $addNesting = true) + { + if ($keys === []) { + return $modify($map); + } + + return $this->modifyNestedMap($map, $keys, $modify, $addNesting); + } + + /** + * @param array $map + * @param array $keys + * @param callable $modify + * @param bool $addNesting + * + * @return array + * + * @phpstan-param non-empty-array $keys + * @phpstan-param callable(Number|array): (Number|array) $modify + */ + private function modifyNestedMap(array $map, array $keys, callable $modify, $addNesting) + { + $key = array_shift($keys); + + $nestedValueIndex = $this->mapGetEntryIndex($map, $key); + + if ($keys === []) { + if ($nestedValueIndex !== null) { + $map[2][$nestedValueIndex] = $modify($map[2][$nestedValueIndex]); + } else { + $map[1][] = $key; + $map[2][] = $modify(self::$null); + } + + return $map; + } + + $nestedMap = $nestedValueIndex !== null ? $this->tryMap($map[2][$nestedValueIndex]) : null; + + if ($nestedMap === null && !$addNesting) { + return $map; + } + + if ($nestedMap === null) { + $nestedMap = self::$emptyMap; + } + + $newNestedMap = $this->modifyNestedMap($nestedMap, $keys, $modify, $addNesting); + + if ($nestedValueIndex !== null) { + $map[2][$nestedValueIndex] = $newNestedMap; + } else { + $map[1][] = $key; + $map[2][] = $newNestedMap; + } + + return $map; + } + + /** + * Merges 2 Sass maps together + * + * @param array $map1 + * @param array $map2 + * + * @return array + */ + private function mergeMaps(array $map1, array $map2) + { + foreach ($map2[1] as $i2 => $key2) { + $map1EntryIndex = $this->mapGetEntryIndex($map1, $key2); + + if ($map1EntryIndex !== null) { + $map1[2][$map1EntryIndex] = $map2[2][$i2]; + continue; + } + + $map1[1][] = $key2; + $map1[2][] = $map2[2][$i2]; + } + + return $map1; + } + + protected static $libKeywords = ['args']; + protected function libKeywords($args) + { + $value = $args[0]; + + if ($value[0] !== Type::T_LIST || !isset($value[3]) || !\is_array($value[3])) { + $compiledValue = $this->compileValue($value); + + throw SassScriptException::forArgument($compiledValue . ' is not an argument list.', 'args'); + } + + $keys = []; + $values = []; + + foreach ($this->getArgumentListKeywords($value) as $name => $arg) { + $keys[] = [Type::T_KEYWORD, $name]; + $values[] = $arg; + } + + return [Type::T_MAP, $keys, $values]; + } + + protected static $libIsBracketed = ['list']; + protected function libIsBracketed($args) + { + $list = $args[0]; + $this->coerceList($list, ' '); + + if (! empty($list['enclosing']) && $list['enclosing'] === 'bracket') { + return self::$true; + } + + return self::$false; + } + + /** + * @param array $list1 + * @param array|Number|null $sep + * + * @return string + * @throws CompilerException + * + * @deprecated + */ + protected function listSeparatorForJoin($list1, $sep) + { + @trigger_error(sprintf('The "%s" method is deprecated.', __METHOD__), E_USER_DEPRECATED); + + if (! isset($sep)) { + return $list1[1]; + } + + switch ($this->compileValue($sep)) { + case 'comma': + return ','; + + case 'space': + return ' '; + + default: + return $list1[1]; + } + } + + protected static $libJoin = ['list1', 'list2', 'separator:auto', 'bracketed:auto']; + protected function libJoin($args) + { + list($list1, $list2, $sep, $bracketed) = $args; + + $list1 = $this->coerceList($list1, ' ', true); + $list2 = $this->coerceList($list2, ' ', true); + + switch ($this->compileStringContent($this->assertString($sep, 'separator'))) { + case 'comma': + $separator = ','; + break; + + case 'space': + $separator = ' '; + break; + + case 'slash': + $separator = '/'; + break; + + case 'auto': + if ($list1[1] !== '' || count($list1[2]) > 1 || !empty($list1['enclosing']) && $list1['enclosing'] !== 'parent') { + $separator = $list1[1] ?: ' '; + } elseif ($list2[1] !== '' || count($list2[2]) > 1 || !empty($list2['enclosing']) && $list2['enclosing'] !== 'parent') { + $separator = $list2[1] ?: ' '; + } else { + $separator = ' '; + } + break; + + default: + throw SassScriptException::forArgument('Must be "space", "comma", "slash", or "auto".', 'separator'); + } + + if ($bracketed === static::$true) { + $bracketed = true; + } elseif ($bracketed === static::$false) { + $bracketed = false; + } elseif ($bracketed === [Type::T_KEYWORD, 'auto']) { + $bracketed = 'auto'; + } elseif ($bracketed === static::$null) { + $bracketed = false; + } else { + $bracketed = $this->compileValue($bracketed); + $bracketed = ! ! $bracketed; + + if ($bracketed === true) { + $bracketed = true; + } + } + + if ($bracketed === 'auto') { + $bracketed = false; + + if (! empty($list1['enclosing']) && $list1['enclosing'] === 'bracket') { + $bracketed = true; + } + } + + $res = [Type::T_LIST, $separator, array_merge($list1[2], $list2[2])]; + + if ($bracketed) { + $res['enclosing'] = 'bracket'; + } + + return $res; + } + + protected static $libAppend = ['list', 'val', 'separator:auto']; + protected function libAppend($args) + { + list($list1, $value, $sep) = $args; + + $list1 = $this->coerceList($list1, ' ', true); + + switch ($this->compileStringContent($this->assertString($sep, 'separator'))) { + case 'comma': + $separator = ','; + break; + + case 'space': + $separator = ' '; + break; + + case 'slash': + $separator = '/'; + break; + + case 'auto': + $separator = $list1[1] === '' && \count($list1[2]) <= 1 && (empty($list1['enclosing']) || $list1['enclosing'] === 'parent') ? ' ' : $list1[1]; + break; + + default: + throw SassScriptException::forArgument('Must be "space", "comma", "slash", or "auto".', 'separator'); + } + + $res = [Type::T_LIST, $separator, array_merge($list1[2], [$value])]; + + if (isset($list1['enclosing'])) { + $res['enclosing'] = $list1['enclosing']; + } + + return $res; + } + + protected static $libZip = ['lists...']; + protected function libZip($args) + { + $argLists = []; + foreach ($args[0][2] as $arg) { + $argLists[] = $this->coerceList($arg); + } + + $lists = []; + $firstList = array_shift($argLists); + + $result = [Type::T_LIST, ',', $lists]; + if (! \is_null($firstList)) { + foreach ($firstList[2] as $key => $item) { + $list = [Type::T_LIST, ' ', [$item]]; + + foreach ($argLists as $arg) { + if (isset($arg[2][$key])) { + $list[2][] = $arg[2][$key]; + } else { + break 2; + } + } + + $lists[] = $list; + } + + $result[2] = $lists; + } else { + $result['enclosing'] = 'parent'; + } + + return $result; + } + + protected static $libTypeOf = ['value']; + protected function libTypeOf($args) + { + $value = $args[0]; + + return [Type::T_KEYWORD, $this->getTypeOf($value)]; + } + + /** + * @param array|Number $value + * + * @return string + */ + private function getTypeOf($value) + { + switch ($value[0]) { + case Type::T_KEYWORD: + if ($value === static::$true || $value === static::$false) { + return 'bool'; + } + + if ($this->coerceColor($value)) { + return 'color'; + } + + // fall-thru + case Type::T_FUNCTION: + return 'string'; + + case Type::T_FUNCTION_REFERENCE: + return 'function'; + + case Type::T_LIST: + if (isset($value[3]) && \is_array($value[3])) { + return 'arglist'; + } + + // fall-thru + default: + return $value[0]; + } + } + + protected static $libUnit = ['number']; + protected function libUnit($args) + { + $num = $this->assertNumber($args[0], 'number'); + + return [Type::T_STRING, '"', [$num->unitStr()]]; + } + + protected static $libUnitless = ['number']; + protected function libUnitless($args) + { + $value = $this->assertNumber($args[0], 'number'); + + return $this->toBool($value->unitless()); + } + + protected static $libComparable = [ + ['number1', 'number2'], + ['number-1', 'number-2'] + ]; + protected function libComparable($args) + { + list($number1, $number2) = $args; + + if ( + ! $number1 instanceof Number || + ! $number2 instanceof Number + ) { + throw $this->error('Invalid argument(s) for "comparable"'); + } + + return $this->toBool($number1->isComparableTo($number2)); + } + + protected static $libStrIndex = ['string', 'substring']; + protected function libStrIndex($args) + { + $string = $this->assertString($args[0], 'string'); + $stringContent = $this->compileStringContent($string); + + $substring = $this->assertString($args[1], 'substring'); + $substringContent = $this->compileStringContent($substring); + + if (! \strlen($substringContent)) { + $result = 0; + } else { + $result = Util::mbStrpos($stringContent, $substringContent); + } + + return $result === false ? static::$null : new Number($result + 1, ''); + } + + protected static $libStrInsert = ['string', 'insert', 'index']; + protected function libStrInsert($args) + { + $string = $this->assertString($args[0], 'string'); + $stringContent = $this->compileStringContent($string); + + $insert = $this->assertString($args[1], 'insert'); + $insertContent = $this->compileStringContent($insert); + + $index = $this->assertInteger($args[2], 'index'); + if ($index > 0) { + $index = $index - 1; + } + if ($index < 0) { + $index = Util::mbStrlen($stringContent) + 1 + $index; + } + + $string[2] = [ + Util::mbSubstr($stringContent, 0, $index), + $insertContent, + Util::mbSubstr($stringContent, $index) + ]; + + return $string; + } + + protected static $libStrLength = ['string']; + protected function libStrLength($args) + { + $string = $this->assertString($args[0], 'string'); + $stringContent = $this->compileStringContent($string); + + return new Number(Util::mbStrlen($stringContent), ''); + } + + protected static $libStrSlice = ['string', 'start-at', 'end-at:-1']; + protected function libStrSlice($args) + { + $string = $this->assertString($args[0], 'string'); + $stringContent = $this->compileStringContent($string); + + $start = $this->assertNumber($args[1], 'start-at'); + $start->assertNoUnits('start-at'); + $startInt = $this->assertInteger($start, 'start-at'); + $end = $this->assertNumber($args[2], 'end-at'); + $end->assertNoUnits('end-at'); + $endInt = $this->assertInteger($end, 'end-at'); + + if ($endInt === 0) { + return [Type::T_STRING, $string[1], []]; + } + + if ($startInt > 0) { + $startInt--; + } + + if ($endInt < 0) { + $endInt = Util::mbStrlen($stringContent) + $endInt; + } else { + $endInt--; + } + + if ($endInt < $startInt) { + return [Type::T_STRING, $string[1], []]; + } + + $length = $endInt - $startInt + 1; // The end of the slice is inclusive + + $string[2] = [Util::mbSubstr($stringContent, $startInt, $length)]; + + return $string; + } + + protected static $libToLowerCase = ['string']; + protected function libToLowerCase($args) + { + $string = $this->assertString($args[0], 'string'); + $stringContent = $this->compileStringContent($string); + + $string[2] = [$this->stringTransformAsciiOnly($stringContent, 'strtolower')]; + + return $string; + } + + protected static $libToUpperCase = ['string']; + protected function libToUpperCase($args) + { + $string = $this->assertString($args[0], 'string'); + $stringContent = $this->compileStringContent($string); + + $string[2] = [$this->stringTransformAsciiOnly($stringContent, 'strtoupper')]; + + return $string; + } + + /** + * Apply a filter on a string content, only on ascii chars + * let extended chars untouched + * + * @param string $stringContent + * @param callable $filter + * @return string + */ + protected function stringTransformAsciiOnly($stringContent, $filter) + { + $mblength = Util::mbStrlen($stringContent); + if ($mblength === strlen($stringContent)) { + return $filter($stringContent); + } + $filteredString = ""; + for ($i = 0; $i < $mblength; $i++) { + $char = Util::mbSubstr($stringContent, $i, 1); + if (strlen($char) > 1) { + $filteredString .= $char; + } else { + $filteredString .= $filter($char); + } + } + + return $filteredString; + } + + protected static $libFeatureExists = ['feature']; + protected function libFeatureExists($args) + { + $string = $this->assertString($args[0], 'feature'); + $name = $this->compileStringContent($string); + + return $this->toBool( + \array_key_exists($name, $this->registeredFeatures) ? $this->registeredFeatures[$name] : false + ); + } + + protected static $libFunctionExists = ['name']; + protected function libFunctionExists($args) + { + $string = $this->assertString($args[0], 'name'); + $name = $this->compileStringContent($string); + + // user defined functions + if ($this->has(static::$namespaces['function'] . $name)) { + return self::$true; + } + + $name = $this->normalizeName($name); + + if (isset($this->userFunctions[$name])) { + return self::$true; + } + + // built-in functions + $f = $this->getBuiltinFunction($name); + + return $this->toBool(\is_callable($f)); + } + + protected static $libGlobalVariableExists = ['name']; + protected function libGlobalVariableExists($args) + { + $string = $this->assertString($args[0], 'name'); + $name = $this->compileStringContent($string); + + return $this->toBool($this->has($name, $this->rootEnv)); + } + + protected static $libMixinExists = ['name']; + protected function libMixinExists($args) + { + $string = $this->assertString($args[0], 'name'); + $name = $this->compileStringContent($string); + + return $this->toBool($this->has(static::$namespaces['mixin'] . $name)); + } + + protected static $libVariableExists = ['name']; + protected function libVariableExists($args) + { + $string = $this->assertString($args[0], 'name'); + $name = $this->compileStringContent($string); + + return $this->toBool($this->has($name)); + } + + protected static $libCounter = ['args...']; + /** + * Workaround IE7's content counter bug. + * + * @param array $args + * + * @return array + */ + protected function libCounter($args) + { + $list = array_map([$this, 'compileValue'], $args[0][2]); + + return [Type::T_STRING, '', ['counter(' . implode(',', $list) . ')']]; + } + + protected static $libRandom = ['limit:null']; + protected function libRandom($args) + { + if (isset($args[0]) && $args[0] !== static::$null) { + $n = $this->assertInteger($args[0], 'limit'); + + if ($n < 1) { + throw new SassScriptException("\$limit: Must be greater than 0, was $n."); + } + + return new Number(mt_rand(1, $n), ''); + } + + $max = mt_getrandmax(); + return new Number(mt_rand(0, $max - 1) / $max, ''); + } + + protected static $libUniqueId = []; + protected function libUniqueId() + { + static $id; + + if (! isset($id)) { + $id = PHP_INT_SIZE === 4 + ? mt_rand(0, pow(36, 5)) . str_pad(mt_rand(0, pow(36, 5)) % 10000000, 7, '0', STR_PAD_LEFT) + : mt_rand(0, pow(36, 8)); + } + + $id += mt_rand(0, 10) + 1; + + return [Type::T_STRING, '', ['u' . str_pad(base_convert($id, 10, 36), 8, '0', STR_PAD_LEFT)]]; + } + + /** + * @param array|Number $value + * @param bool $force_enclosing_display + * + * @return array + */ + protected function inspectFormatValue($value, $force_enclosing_display = false) + { + if ($value === static::$null) { + $value = [Type::T_KEYWORD, 'null']; + } + + $stringValue = [$value]; + + if ($value instanceof Number) { + return [Type::T_STRING, '', $stringValue]; + } + + if ($value[0] === Type::T_LIST) { + if (end($value[2]) === static::$null) { + array_pop($value[2]); + $value[2][] = [Type::T_STRING, '', ['']]; + $force_enclosing_display = true; + } + + if ( + ! empty($value['enclosing']) && + ($force_enclosing_display || + ($value['enclosing'] === 'bracket') || + ! \count($value[2])) + ) { + $value['enclosing'] = 'forced_' . $value['enclosing']; + $force_enclosing_display = true; + } elseif (! \count($value[2])) { + $value['enclosing'] = 'forced_parent'; + } + + foreach ($value[2] as $k => $listelement) { + $value[2][$k] = $this->inspectFormatValue($listelement, $force_enclosing_display); + } + + $stringValue = [$value]; + } + + return [Type::T_STRING, '', $stringValue]; + } + + protected static $libInspect = ['value']; + protected function libInspect($args) + { + $value = $args[0]; + + return $this->inspectFormatValue($value); + } + + /** + * Preprocess selector args + * + * @param array $arg + * @param string|null $varname + * @param bool $allowParent + * + * @return array + */ + protected function getSelectorArg($arg, $varname = null, $allowParent = false) + { + static $parser = null; + + if (\is_null($parser)) { + $parser = $this->parserFactory(__METHOD__); + } + + if (! $this->checkSelectorArgType($arg)) { + $var_value = $this->compileValue($arg); + throw SassScriptException::forArgument("$var_value is not a valid selector: it must be a string, a list of strings, or a list of lists of strings", $varname); + } + + + if ($arg[0] === Type::T_STRING) { + $arg[1] = ''; + } + $arg = $this->compileValue($arg); + + $parsedSelector = []; + + if ($parser->parseSelector($arg, $parsedSelector, true)) { + $selector = $this->evalSelectors($parsedSelector); + $gluedSelector = $this->glueFunctionSelectors($selector); + + if (! $allowParent) { + foreach ($gluedSelector as $selector) { + foreach ($selector as $s) { + if (in_array(static::$selfSelector, $s)) { + throw SassScriptException::forArgument("Parent selectors aren't allowed here.", $varname); + } + } + } + } + + return $gluedSelector; + } + + throw SassScriptException::forArgument("expected more input, invalid selector.", $varname); + } + + /** + * Check variable type for getSelectorArg() function + * @param array $arg + * @param int $maxDepth + * @return bool + */ + protected function checkSelectorArgType($arg, $maxDepth = 2) + { + if ($arg[0] === Type::T_LIST && $maxDepth > 0) { + foreach ($arg[2] as $elt) { + if (! $this->checkSelectorArgType($elt, $maxDepth - 1)) { + return false; + } + } + return true; + } + if (!in_array($arg[0], [Type::T_STRING, Type::T_KEYWORD])) { + return false; + } + return true; + } + + /** + * Postprocess selector to output in right format + * + * @param array $selectors + * + * @return array + */ + protected function formatOutputSelector($selectors) + { + $selectors = $this->collapseSelectorsAsList($selectors); + + return $selectors; + } + + protected static $libIsSuperselector = ['super', 'sub']; + protected function libIsSuperselector($args) + { + list($super, $sub) = $args; + + $super = $this->getSelectorArg($super, 'super'); + $sub = $this->getSelectorArg($sub, 'sub'); + + return $this->toBool($this->isSuperSelector($super, $sub)); + } + + /** + * Test a $super selector again $sub + * + * @param array $super + * @param array $sub + * + * @return bool + */ + protected function isSuperSelector($super, $sub) + { + // one and only one selector for each arg + if (! $super) { + throw $this->error('Invalid super selector for isSuperSelector()'); + } + + if (! $sub) { + throw $this->error('Invalid sub selector for isSuperSelector()'); + } + + if (count($sub) > 1) { + foreach ($sub as $s) { + if (! $this->isSuperSelector($super, [$s])) { + return false; + } + } + return true; + } + + if (count($super) > 1) { + foreach ($super as $s) { + if ($this->isSuperSelector([$s], $sub)) { + return true; + } + } + return false; + } + + $super = reset($super); + $sub = reset($sub); + + $i = 0; + $nextMustMatch = false; + + foreach ($super as $node) { + $compound = ''; + + array_walk_recursive( + $node, + function ($value, $key) use (&$compound) { + $compound .= $value; + } + ); + + if ($this->isImmediateRelationshipCombinator($compound)) { + if ($node !== $sub[$i]) { + return false; + } + + $nextMustMatch = true; + $i++; + } else { + while ($i < \count($sub) && ! $this->isSuperPart($node, $sub[$i])) { + if ($nextMustMatch) { + return false; + } + + $i++; + } + + if ($i >= \count($sub)) { + return false; + } + + $nextMustMatch = false; + $i++; + } + } + + return true; + } + + /** + * Test a part of super selector again a part of sub selector + * + * @param array $superParts + * @param array $subParts + * + * @return bool + */ + protected function isSuperPart($superParts, $subParts) + { + $i = 0; + + foreach ($superParts as $superPart) { + while ($i < \count($subParts) && $subParts[$i] !== $superPart) { + $i++; + } + + if ($i >= \count($subParts)) { + return false; + } + + $i++; + } + + return true; + } + + protected static $libSelectorAppend = ['selector...']; + protected function libSelectorAppend($args) + { + // get the selector... list + $args = reset($args); + $args = $args[2]; + + if (\count($args) < 1) { + throw $this->error('selector-append() needs at least 1 argument'); + } + + $selectors = []; + foreach ($args as $arg) { + $selectors[] = $this->getSelectorArg($arg, 'selector'); + } + + return $this->formatOutputSelector($this->selectorAppend($selectors)); + } + + /** + * Append parts of the last selector in the list to the previous, recursively + * + * @param array $selectors + * + * @return array + * + * @throws \ScssPhp\ScssPhp\Exception\CompilerException + */ + protected function selectorAppend($selectors) + { + $lastSelectors = array_pop($selectors); + + if (! $lastSelectors) { + throw $this->error('Invalid selector list in selector-append()'); + } + + while (\count($selectors)) { + $previousSelectors = array_pop($selectors); + + if (! $previousSelectors) { + throw $this->error('Invalid selector list in selector-append()'); + } + + // do the trick, happening $lastSelector to $previousSelector + $appended = []; + + foreach ($previousSelectors as $previousSelector) { + foreach ($lastSelectors as $lastSelector) { + $previous = $previousSelector; + foreach ($previousSelector as $j => $previousSelectorParts) { + foreach ($lastSelector as $lastSelectorParts) { + foreach ($lastSelectorParts as $lastSelectorPart) { + $previous[$j][] = $lastSelectorPart; + } + } + } + + $appended[] = $previous; + } + } + + $lastSelectors = $appended; + } + + return $lastSelectors; + } + + protected static $libSelectorExtend = [ + ['selector', 'extendee', 'extender'], + ['selectors', 'extendee', 'extender'] + ]; + protected function libSelectorExtend($args) + { + list($selectors, $extendee, $extender) = $args; + + $selectors = $this->getSelectorArg($selectors, 'selector'); + $extendee = $this->getSelectorArg($extendee, 'extendee'); + $extender = $this->getSelectorArg($extender, 'extender'); + + if (! $selectors || ! $extendee || ! $extender) { + throw $this->error('selector-extend() invalid arguments'); + } + + $extended = $this->extendOrReplaceSelectors($selectors, $extendee, $extender); + + return $this->formatOutputSelector($extended); + } + + protected static $libSelectorReplace = [ + ['selector', 'original', 'replacement'], + ['selectors', 'original', 'replacement'] + ]; + protected function libSelectorReplace($args) + { + list($selectors, $original, $replacement) = $args; + + $selectors = $this->getSelectorArg($selectors, 'selector'); + $original = $this->getSelectorArg($original, 'original'); + $replacement = $this->getSelectorArg($replacement, 'replacement'); + + if (! $selectors || ! $original || ! $replacement) { + throw $this->error('selector-replace() invalid arguments'); + } + + $replaced = $this->extendOrReplaceSelectors($selectors, $original, $replacement, true); + + return $this->formatOutputSelector($replaced); + } + + /** + * Extend/replace in selectors + * used by selector-extend and selector-replace that use the same logic + * + * @param array $selectors + * @param array $extendee + * @param array $extender + * @param bool $replace + * + * @return array + */ + protected function extendOrReplaceSelectors($selectors, $extendee, $extender, $replace = false) + { + $saveExtends = $this->extends; + $saveExtendsMap = $this->extendsMap; + + $this->extends = []; + $this->extendsMap = []; + + foreach ($extendee as $es) { + if (\count($es) !== 1) { + throw $this->error('Can\'t extend complex selector.'); + } + + // only use the first one + $this->pushExtends(reset($es), $extender, null); + } + + $extended = []; + + foreach ($selectors as $selector) { + if (! $replace) { + $extended[] = $selector; + } + + $n = \count($extended); + + $this->matchExtends($selector, $extended); + + // if didnt match, keep the original selector if we are in a replace operation + if ($replace && \count($extended) === $n) { + $extended[] = $selector; + } + } + + $this->extends = $saveExtends; + $this->extendsMap = $saveExtendsMap; + + return $extended; + } + + protected static $libSelectorNest = ['selector...']; + protected function libSelectorNest($args) + { + // get the selector... list + $args = reset($args); + $args = $args[2]; + + if (\count($args) < 1) { + throw $this->error('selector-nest() needs at least 1 argument'); + } + + $selectorsMap = []; + foreach ($args as $arg) { + $selectorsMap[] = $this->getSelectorArg($arg, 'selector', true); + } + + $envs = []; + + foreach ($selectorsMap as $selectors) { + $env = new Environment(); + $env->selectors = $selectors; + + $envs[] = $env; + } + + $envs = array_reverse($envs); + $env = $this->extractEnv($envs); + $outputSelectors = $this->multiplySelectors($env); + + return $this->formatOutputSelector($outputSelectors); + } + + protected static $libSelectorParse = [ + ['selector'], + ['selectors'] + ]; + protected function libSelectorParse($args) + { + $selectors = reset($args); + $selectors = $this->getSelectorArg($selectors, 'selector'); + + return $this->formatOutputSelector($selectors); + } + + protected static $libSelectorUnify = ['selectors1', 'selectors2']; + protected function libSelectorUnify($args) + { + list($selectors1, $selectors2) = $args; + + $selectors1 = $this->getSelectorArg($selectors1, 'selectors1'); + $selectors2 = $this->getSelectorArg($selectors2, 'selectors2'); + + if (! $selectors1 || ! $selectors2) { + throw $this->error('selector-unify() invalid arguments'); + } + + // only consider the first compound of each + $compound1 = reset($selectors1); + $compound2 = reset($selectors2); + + // unify them and that's it + $unified = $this->unifyCompoundSelectors($compound1, $compound2); + + return $this->formatOutputSelector($unified); + } + + /** + * The selector-unify magic as its best + * (at least works as expected on test cases) + * + * @param array $compound1 + * @param array $compound2 + * + * @return array + */ + protected function unifyCompoundSelectors($compound1, $compound2) + { + if (! \count($compound1)) { + return $compound2; + } + + if (! \count($compound2)) { + return $compound1; + } + + // check that last part are compatible + $lastPart1 = array_pop($compound1); + $lastPart2 = array_pop($compound2); + $last = $this->mergeParts($lastPart1, $lastPart2); + + if (! $last) { + return [[]]; + } + + $unifiedCompound = [$last]; + $unifiedSelectors = [$unifiedCompound]; + + // do the rest + while (\count($compound1) || \count($compound2)) { + $part1 = end($compound1); + $part2 = end($compound2); + + if ($part1 && ($match2 = $this->matchPartInCompound($part1, $compound2))) { + list($compound2, $part2, $after2) = $match2; + + if ($after2) { + $unifiedSelectors = $this->prependSelectors($unifiedSelectors, $after2); + } + + $c = $this->mergeParts($part1, $part2); + $unifiedSelectors = $this->prependSelectors($unifiedSelectors, [$c]); + + $part1 = $part2 = null; + + array_pop($compound1); + } + + if ($part2 && ($match1 = $this->matchPartInCompound($part2, $compound1))) { + list($compound1, $part1, $after1) = $match1; + + if ($after1) { + $unifiedSelectors = $this->prependSelectors($unifiedSelectors, $after1); + } + + $c = $this->mergeParts($part2, $part1); + $unifiedSelectors = $this->prependSelectors($unifiedSelectors, [$c]); + + $part1 = $part2 = null; + + array_pop($compound2); + } + + $new = []; + + if ($part1 && $part2) { + array_pop($compound1); + array_pop($compound2); + + $s = $this->prependSelectors($unifiedSelectors, [$part2]); + $new = array_merge($new, $this->prependSelectors($s, [$part1])); + $s = $this->prependSelectors($unifiedSelectors, [$part1]); + $new = array_merge($new, $this->prependSelectors($s, [$part2])); + } elseif ($part1) { + array_pop($compound1); + + $new = array_merge($new, $this->prependSelectors($unifiedSelectors, [$part1])); + } elseif ($part2) { + array_pop($compound2); + + $new = array_merge($new, $this->prependSelectors($unifiedSelectors, [$part2])); + } + + if ($new) { + $unifiedSelectors = $new; + } + } + + return $unifiedSelectors; + } + + /** + * Prepend each selector from $selectors with $parts + * + * @param array $selectors + * @param array $parts + * + * @return array + */ + protected function prependSelectors($selectors, $parts) + { + $new = []; + + foreach ($selectors as $compoundSelector) { + array_unshift($compoundSelector, $parts); + + $new[] = $compoundSelector; + } + + return $new; + } + + /** + * Try to find a matching part in a compound: + * - with same html tag name + * - with some class or id or something in common + * + * @param array $part + * @param array $compound + * + * @return array|false + */ + protected function matchPartInCompound($part, $compound) + { + $partTag = $this->findTagName($part); + $before = $compound; + $after = []; + + // try to find a match by tag name first + while (\count($before)) { + $p = array_pop($before); + + if ($partTag && $partTag !== '*' && $partTag == $this->findTagName($p)) { + return [$before, $p, $after]; + } + + $after[] = $p; + } + + // try again matching a non empty intersection and a compatible tagname + $before = $compound; + $after = []; + + while (\count($before)) { + $p = array_pop($before); + + if ($this->checkCompatibleTags($partTag, $this->findTagName($p))) { + if (\count(array_intersect($part, $p))) { + return [$before, $p, $after]; + } + } + + $after[] = $p; + } + + return false; + } + + /** + * Merge two part list taking care that + * - the html tag is coming first - if any + * - the :something are coming last + * + * @param array $parts1 + * @param array $parts2 + * + * @return array + */ + protected function mergeParts($parts1, $parts2) + { + $tag1 = $this->findTagName($parts1); + $tag2 = $this->findTagName($parts2); + $tag = $this->checkCompatibleTags($tag1, $tag2); + + // not compatible tags + if ($tag === false) { + return []; + } + + if ($tag) { + if ($tag1) { + $parts1 = array_diff($parts1, [$tag1]); + } + + if ($tag2) { + $parts2 = array_diff($parts2, [$tag2]); + } + } + + $mergedParts = array_merge($parts1, $parts2); + $mergedOrderedParts = []; + + foreach ($mergedParts as $part) { + if (strpos($part, ':') === 0) { + $mergedOrderedParts[] = $part; + } + } + + $mergedParts = array_diff($mergedParts, $mergedOrderedParts); + $mergedParts = array_merge($mergedParts, $mergedOrderedParts); + + if ($tag) { + array_unshift($mergedParts, $tag); + } + + return $mergedParts; + } + + /** + * Check the compatibility between two tag names: + * if both are defined they should be identical or one has to be '*' + * + * @param string $tag1 + * @param string $tag2 + * + * @return array|false + */ + protected function checkCompatibleTags($tag1, $tag2) + { + $tags = [$tag1, $tag2]; + $tags = array_unique($tags); + $tags = array_filter($tags); + + if (\count($tags) > 1) { + $tags = array_diff($tags, ['*']); + } + + // not compatible nodes + if (\count($tags) > 1) { + return false; + } + + return $tags; + } + + /** + * Find the html tag name in a selector parts list + * + * @param string[] $parts + * + * @return string + */ + protected function findTagName($parts) + { + foreach ($parts as $part) { + if (! preg_match('/^[\[.:#%_-]/', $part)) { + return $part; + } + } + + return ''; + } + + protected static $libSimpleSelectors = ['selector']; + protected function libSimpleSelectors($args) + { + $selector = reset($args); + $selector = $this->getSelectorArg($selector, 'selector'); + + // remove selectors list layer, keeping the first one + $selector = reset($selector); + + // remove parts list layer, keeping the first part + $part = reset($selector); + + $listParts = []; + + foreach ($part as $p) { + $listParts[] = [Type::T_STRING, '', [$p]]; + } + + return [Type::T_LIST, ',', $listParts]; + } + + protected static $libScssphpGlob = ['pattern']; + protected function libScssphpGlob($args) + { + @trigger_error(sprintf('The "scssphp-glob" function is deprecated an will be removed in ScssPhp 2.0. Register your own alternative through "%s::registerFunction', __CLASS__), E_USER_DEPRECATED); + + $this->logger->warn('The "scssphp-glob" function is deprecated an will be removed in ScssPhp 2.0.', true); + + $string = $this->assertString($args[0], 'pattern'); + $pattern = $this->compileStringContent($string); + $matches = glob($pattern); + $listParts = []; + + foreach ($matches as $match) { + if (! is_file($match)) { + continue; + } + + $listParts[] = [Type::T_STRING, '"', [$match]]; + } + + return [Type::T_LIST, ',', $listParts]; + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Compiler/CachedResult.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Compiler/CachedResult.php new file mode 100644 index 00000000..a6629199 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Compiler/CachedResult.php @@ -0,0 +1,77 @@ + + */ + private $parsedFiles; + + /** + * @var array + * @phpstan-var list + */ + private $resolvedImports; + + /** + * @param CompilationResult $result + * @param array $parsedFiles + * @param array $resolvedImports + * + * @phpstan-param list $resolvedImports + */ + public function __construct(CompilationResult $result, array $parsedFiles, array $resolvedImports) + { + $this->result = $result; + $this->parsedFiles = $parsedFiles; + $this->resolvedImports = $resolvedImports; + } + + /** + * @return CompilationResult + */ + public function getResult() + { + return $this->result; + } + + /** + * @return array + */ + public function getParsedFiles() + { + return $this->parsedFiles; + } + + /** + * @return array + * + * @phpstan-return list + */ + public function getResolvedImports() + { + return $this->resolvedImports; + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Compiler/Environment.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Compiler/Environment.php new file mode 100644 index 00000000..b205a077 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Compiler/Environment.php @@ -0,0 +1,68 @@ + + * + * @internal + */ +class Environment +{ + /** + * @var \ScssPhp\ScssPhp\Block|null + */ + public $block; + + /** + * @var \ScssPhp\ScssPhp\Compiler\Environment|null + */ + public $parent; + + /** + * @var Environment|null + */ + public $declarationScopeParent; + + /** + * @var Environment|null + */ + public $parentStore; + + /** + * @var array|null + */ + public $selectors; + + /** + * @var string|null + */ + public $marker; + + /** + * @var array + */ + public $store; + + /** + * @var array + */ + public $storeUnreduced; + + /** + * @var int + */ + public $depth; +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Exception/CompilerException.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Exception/CompilerException.php new file mode 100644 index 00000000..0b00cf52 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Exception/CompilerException.php @@ -0,0 +1,24 @@ + + * + * @internal + */ +class CompilerException extends \Exception implements SassException +{ +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Exception/ParserException.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Exception/ParserException.php new file mode 100644 index 00000000..00d77ec9 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Exception/ParserException.php @@ -0,0 +1,50 @@ + + * + * @internal + */ +class ParserException extends \Exception implements SassException +{ + /** + * @var array + */ + private $sourcePosition; + + /** + * Get source position + * + * @api + */ + public function getSourcePosition() + { + return $this->sourcePosition; + } + + /** + * Set source position + * + * @api + * + * @param array $sourcePosition + */ + public function setSourcePosition($sourcePosition) + { + $this->sourcePosition = $sourcePosition; + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Exception/RangeException.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Exception/RangeException.php new file mode 100644 index 00000000..4be4dee7 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Exception/RangeException.php @@ -0,0 +1,24 @@ + + * + * @internal + */ +class RangeException extends \Exception implements SassException +{ +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Exception/SassException.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Exception/SassException.php new file mode 100644 index 00000000..9f62b3cd --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Exception/SassException.php @@ -0,0 +1,7 @@ + + * + * @deprecated The Scssphp server should define its own exception instead. + */ +class ServerException extends \Exception implements SassException +{ +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter.php new file mode 100644 index 00000000..c88ddba9 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter.php @@ -0,0 +1,364 @@ + + * + * @internal + */ +abstract class Formatter +{ + /** + * @var int + */ + public $indentLevel; + + /** + * @var string + */ + public $indentChar; + + /** + * @var string + */ + public $break; + + /** + * @var string + */ + public $open; + + /** + * @var string + */ + public $close; + + /** + * @var string + */ + public $tagSeparator; + + /** + * @var string + */ + public $assignSeparator; + + /** + * @var bool + */ + public $keepSemicolons; + + /** + * @var \ScssPhp\ScssPhp\Formatter\OutputBlock + */ + protected $currentBlock; + + /** + * @var int + */ + protected $currentLine; + + /** + * @var int + */ + protected $currentColumn; + + /** + * @var \ScssPhp\ScssPhp\SourceMap\SourceMapGenerator|null + */ + protected $sourceMapGenerator; + + /** + * @var string + */ + protected $strippedSemicolon; + + /** + * Initialize formatter + * + * @api + */ + abstract public function __construct(); + + /** + * Return indentation (whitespace) + * + * @return string + */ + protected function indentStr() + { + return ''; + } + + /** + * Return property assignment + * + * @api + * + * @param string $name + * @param mixed $value + * + * @return string + */ + public function property($name, $value) + { + return rtrim($name) . $this->assignSeparator . $value . ';'; + } + + /** + * Return custom property assignment + * differs in that you have to keep spaces in the value as is + * + * @api + * + * @param string $name + * @param mixed $value + * + * @return string + */ + public function customProperty($name, $value) + { + return rtrim($name) . trim($this->assignSeparator) . $value . ';'; + } + + /** + * Output lines inside a block + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block + * + * @return void + */ + protected function blockLines(OutputBlock $block) + { + $inner = $this->indentStr(); + $glue = $this->break . $inner; + + $this->write($inner . implode($glue, $block->lines)); + + if (! empty($block->children)) { + $this->write($this->break); + } + } + + /** + * Output block selectors + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block + * + * @return void + */ + protected function blockSelectors(OutputBlock $block) + { + assert(! empty($block->selectors)); + + $inner = $this->indentStr(); + + $this->write($inner + . implode($this->tagSeparator, $block->selectors) + . $this->open . $this->break); + } + + /** + * Output block children + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block + * + * @return void + */ + protected function blockChildren(OutputBlock $block) + { + foreach ($block->children as $child) { + $this->block($child); + } + } + + /** + * Output non-empty block + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block + * + * @return void + */ + protected function block(OutputBlock $block) + { + if (empty($block->lines) && empty($block->children)) { + return; + } + + $this->currentBlock = $block; + + $pre = $this->indentStr(); + + if (! empty($block->selectors)) { + $this->blockSelectors($block); + + $this->indentLevel++; + } + + if (! empty($block->lines)) { + $this->blockLines($block); + } + + if (! empty($block->children)) { + $this->blockChildren($block); + } + + if (! empty($block->selectors)) { + $this->indentLevel--; + + if (! $this->keepSemicolons) { + $this->strippedSemicolon = ''; + } + + if (empty($block->children)) { + $this->write($this->break); + } + + $this->write($pre . $this->close . $this->break); + } + } + + /** + * Test and clean safely empty children + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block + * + * @return bool + */ + protected function testEmptyChildren($block) + { + $isEmpty = empty($block->lines); + + if ($block->children) { + foreach ($block->children as $k => &$child) { + if (! $this->testEmptyChildren($child)) { + $isEmpty = false; + continue; + } + + if ($child->type === Type::T_MEDIA || $child->type === Type::T_DIRECTIVE) { + $child->children = []; + $child->selectors = null; + } + } + } + + return $isEmpty; + } + + /** + * Entry point to formatting a block + * + * @api + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block An abstract syntax tree + * @param \ScssPhp\ScssPhp\SourceMap\SourceMapGenerator|null $sourceMapGenerator Optional source map generator + * + * @return string + */ + public function format(OutputBlock $block, SourceMapGenerator $sourceMapGenerator = null) + { + $this->sourceMapGenerator = null; + + if ($sourceMapGenerator) { + $this->currentLine = 1; + $this->currentColumn = 0; + $this->sourceMapGenerator = $sourceMapGenerator; + } + + $this->testEmptyChildren($block); + + ob_start(); + + $this->block($block); + + $out = ob_get_clean(); + + return $out; + } + + /** + * Output content + * + * @param string $str + * + * @return void + */ + protected function write($str) + { + if (! empty($this->strippedSemicolon)) { + echo $this->strippedSemicolon; + + $this->strippedSemicolon = ''; + } + + /* + * Maybe Strip semi-colon appended by property(); it's a separator, not a terminator + * will be striped for real before a closing, otherwise displayed unchanged starting the next write + */ + if ( + ! $this->keepSemicolons && + $str && + (strpos($str, ';') !== false) && + (substr($str, -1) === ';') + ) { + $str = substr($str, 0, -1); + + $this->strippedSemicolon = ';'; + } + + if ($this->sourceMapGenerator) { + $lines = explode("\n", $str); + $lastLine = array_pop($lines); + + foreach ($lines as $line) { + // If the written line starts is empty, adding a mapping would add it for + // a non-existent column as we are at the end of the line + if ($line !== '') { + $this->sourceMapGenerator->addMapping( + $this->currentLine, + $this->currentColumn, + $this->currentBlock->sourceLine, + //columns from parser are off by one + $this->currentBlock->sourceColumn > 0 ? $this->currentBlock->sourceColumn - 1 : 0, + $this->currentBlock->sourceName + ); + } + + $this->currentLine++; + $this->currentColumn = 0; + } + + if ($lastLine !== '') { + $this->sourceMapGenerator->addMapping( + $this->currentLine, + $this->currentColumn, + $this->currentBlock->sourceLine, + //columns from parser are off by one + $this->currentBlock->sourceColumn > 0 ? $this->currentBlock->sourceColumn - 1 : 0, + $this->currentBlock->sourceName + ); + } + + $this->currentColumn += \strlen($lastLine); + } + + echo $str; + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Compact.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Compact.php new file mode 100644 index 00000000..22f22688 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Compact.php @@ -0,0 +1,52 @@ + + * + * @deprecated since 1.4.0. Use the Compressed formatter instead. + * + * @internal + */ +class Compact extends Formatter +{ + /** + * {@inheritdoc} + */ + public function __construct() + { + @trigger_error('The Compact formatter is deprecated since 1.4.0. Use the Compressed formatter instead.', E_USER_DEPRECATED); + + $this->indentLevel = 0; + $this->indentChar = ''; + $this->break = ''; + $this->open = ' {'; + $this->close = "}\n\n"; + $this->tagSeparator = ','; + $this->assignSeparator = ':'; + $this->keepSemicolons = true; + } + + /** + * {@inheritdoc} + */ + public function indentStr() + { + return ' '; + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Compressed.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Compressed.php new file mode 100644 index 00000000..58ebe3f1 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Compressed.php @@ -0,0 +1,83 @@ + + * + * @internal + */ +class Compressed extends Formatter +{ + /** + * {@inheritdoc} + */ + public function __construct() + { + $this->indentLevel = 0; + $this->indentChar = ' '; + $this->break = ''; + $this->open = '{'; + $this->close = '}'; + $this->tagSeparator = ','; + $this->assignSeparator = ':'; + $this->keepSemicolons = false; + } + + /** + * {@inheritdoc} + */ + public function blockLines(OutputBlock $block) + { + $inner = $this->indentStr(); + + $glue = $this->break . $inner; + + foreach ($block->lines as $index => $line) { + if (substr($line, 0, 2) === '/*' && substr($line, 2, 1) !== '!') { + unset($block->lines[$index]); + } + } + + $this->write($inner . implode($glue, $block->lines)); + + if (! empty($block->children)) { + $this->write($this->break); + } + } + + /** + * Output block selectors + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block + */ + protected function blockSelectors(OutputBlock $block) + { + assert(! empty($block->selectors)); + + $inner = $this->indentStr(); + + $this->write( + $inner + . implode( + $this->tagSeparator, + str_replace([' > ', ' + ', ' ~ '], ['>', '+', '~'], $block->selectors) + ) + . $this->open . $this->break + ); + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Crunched.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Crunched.php new file mode 100644 index 00000000..2bc1e929 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Crunched.php @@ -0,0 +1,87 @@ + + * + * @deprecated since 1.4.0. Use the Compressed formatter instead. + * + * @internal + */ +class Crunched extends Formatter +{ + /** + * {@inheritdoc} + */ + public function __construct() + { + @trigger_error('The Crunched formatter is deprecated since 1.4.0. Use the Compressed formatter instead.', E_USER_DEPRECATED); + + $this->indentLevel = 0; + $this->indentChar = ' '; + $this->break = ''; + $this->open = '{'; + $this->close = '}'; + $this->tagSeparator = ','; + $this->assignSeparator = ':'; + $this->keepSemicolons = false; + } + + /** + * {@inheritdoc} + */ + public function blockLines(OutputBlock $block) + { + $inner = $this->indentStr(); + + $glue = $this->break . $inner; + + foreach ($block->lines as $index => $line) { + if (substr($line, 0, 2) === '/*') { + unset($block->lines[$index]); + } + } + + $this->write($inner . implode($glue, $block->lines)); + + if (! empty($block->children)) { + $this->write($this->break); + } + } + + /** + * Output block selectors + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block + */ + protected function blockSelectors(OutputBlock $block) + { + assert(! empty($block->selectors)); + + $inner = $this->indentStr(); + + $this->write( + $inner + . implode( + $this->tagSeparator, + str_replace([' > ', ' + ', ' ~ '], ['>', '+', '~'], $block->selectors) + ) + . $this->open . $this->break + ); + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Debug.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Debug.php new file mode 100644 index 00000000..b3f44225 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Debug.php @@ -0,0 +1,127 @@ + + * + * @deprecated since 1.4.0. + * + * @internal + */ +class Debug extends Formatter +{ + /** + * {@inheritdoc} + */ + public function __construct() + { + @trigger_error('The Debug formatter is deprecated since 1.4.0.', E_USER_DEPRECATED); + + $this->indentLevel = 0; + $this->indentChar = ''; + $this->break = "\n"; + $this->open = ' {'; + $this->close = ' }'; + $this->tagSeparator = ', '; + $this->assignSeparator = ': '; + $this->keepSemicolons = true; + } + + /** + * {@inheritdoc} + */ + protected function indentStr() + { + return str_repeat(' ', $this->indentLevel); + } + + /** + * {@inheritdoc} + */ + protected function blockLines(OutputBlock $block) + { + $indent = $this->indentStr(); + + if (empty($block->lines)) { + $this->write("{$indent}block->lines: []\n"); + + return; + } + + foreach ($block->lines as $index => $line) { + $this->write("{$indent}block->lines[{$index}]: $line\n"); + } + } + + /** + * {@inheritdoc} + */ + protected function blockSelectors(OutputBlock $block) + { + $indent = $this->indentStr(); + + if (empty($block->selectors)) { + $this->write("{$indent}block->selectors: []\n"); + + return; + } + + foreach ($block->selectors as $index => $selector) { + $this->write("{$indent}block->selectors[{$index}]: $selector\n"); + } + } + + /** + * {@inheritdoc} + */ + protected function blockChildren(OutputBlock $block) + { + $indent = $this->indentStr(); + + if (empty($block->children)) { + $this->write("{$indent}block->children: []\n"); + + return; + } + + $this->indentLevel++; + + foreach ($block->children as $i => $child) { + $this->block($child); + } + + $this->indentLevel--; + } + + /** + * {@inheritdoc} + */ + protected function block(OutputBlock $block) + { + $indent = $this->indentStr(); + + $this->write("{$indent}block->type: {$block->type}\n" . + "{$indent}block->depth: {$block->depth}\n"); + + $this->currentBlock = $block; + + $this->blockSelectors($block); + $this->blockLines($block); + $this->blockChildren($block); + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Expanded.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Expanded.php new file mode 100644 index 00000000..a280416d --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Expanded.php @@ -0,0 +1,70 @@ + + * + * @internal + */ +class Expanded extends Formatter +{ + /** + * {@inheritdoc} + */ + public function __construct() + { + $this->indentLevel = 0; + $this->indentChar = ' '; + $this->break = "\n"; + $this->open = ' {'; + $this->close = '}'; + $this->tagSeparator = ', '; + $this->assignSeparator = ': '; + $this->keepSemicolons = true; + } + + /** + * {@inheritdoc} + */ + protected function indentStr() + { + return str_repeat($this->indentChar, $this->indentLevel); + } + + /** + * {@inheritdoc} + */ + protected function blockLines(OutputBlock $block) + { + $inner = $this->indentStr(); + + $glue = $this->break . $inner; + + foreach ($block->lines as $index => $line) { + if (substr($line, 0, 2) === '/*') { + $block->lines[$index] = preg_replace('/\r\n?|\n|\f/', $this->break, $line); + } + } + + $this->write($inner . implode($glue, $block->lines)); + + if (empty($block->selectors) || ! empty($block->children)) { + $this->write($this->break); + } + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Nested.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Nested.php new file mode 100644 index 00000000..c11ea8ad --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Nested.php @@ -0,0 +1,236 @@ + + * + * @deprecated since 1.4.0. Use the Expanded formatter instead. + * + * @internal + */ +class Nested extends Formatter +{ + /** + * @var int + */ + private $depth; + + /** + * {@inheritdoc} + */ + public function __construct() + { + @trigger_error('The Nested formatter is deprecated since 1.4.0. Use the Expanded formatter instead.', E_USER_DEPRECATED); + + $this->indentLevel = 0; + $this->indentChar = ' '; + $this->break = "\n"; + $this->open = ' {'; + $this->close = ' }'; + $this->tagSeparator = ', '; + $this->assignSeparator = ': '; + $this->keepSemicolons = true; + } + + /** + * {@inheritdoc} + */ + protected function indentStr() + { + $n = $this->depth - 1; + + return str_repeat($this->indentChar, max($this->indentLevel + $n, 0)); + } + + /** + * {@inheritdoc} + */ + protected function blockLines(OutputBlock $block) + { + $inner = $this->indentStr(); + $glue = $this->break . $inner; + + foreach ($block->lines as $index => $line) { + if (substr($line, 0, 2) === '/*') { + $block->lines[$index] = preg_replace('/\r\n?|\n|\f/', $this->break, $line); + } + } + + $this->write($inner . implode($glue, $block->lines)); + } + + /** + * {@inheritdoc} + */ + protected function block(OutputBlock $block) + { + static $depths; + static $downLevel; + static $closeBlock; + static $previousEmpty; + static $previousHasSelector; + + if ($block->type === 'root') { + $depths = [ 0 ]; + $downLevel = ''; + $closeBlock = ''; + $this->depth = 0; + $previousEmpty = false; + $previousHasSelector = false; + } + + $isMediaOrDirective = \in_array($block->type, [Type::T_DIRECTIVE, Type::T_MEDIA]); + $isSupport = ($block->type === Type::T_DIRECTIVE + && $block->selectors && strpos(implode('', $block->selectors), '@supports') !== false); + + while ($block->depth < end($depths) || ($block->depth == 1 && end($depths) == 1)) { + array_pop($depths); + $this->depth--; + + if ( + ! $this->depth && ($block->depth <= 1 || (! $this->indentLevel && $block->type === Type::T_COMMENT)) && + (($block->selectors && ! $isMediaOrDirective) || $previousHasSelector) + ) { + $downLevel = $this->break; + } + + if (empty($block->lines) && empty($block->children)) { + $previousEmpty = true; + } + } + + if (empty($block->lines) && empty($block->children)) { + return; + } + + $this->currentBlock = $block; + + if (! empty($block->lines) || (! empty($block->children) && ($this->depth < 1 || $isSupport))) { + if ($block->depth > end($depths)) { + if (! $previousEmpty || $this->depth < 1) { + $this->depth++; + + $depths[] = $block->depth; + } else { + // keep the current depth unchanged but take the block depth as a new reference for following blocks + array_pop($depths); + + $depths[] = $block->depth; + } + } + } + + $previousEmpty = ($block->type === Type::T_COMMENT); + $previousHasSelector = false; + + if (! empty($block->selectors)) { + if ($closeBlock) { + $this->write($closeBlock); + $closeBlock = ''; + } + + if ($downLevel) { + $this->write($downLevel); + $downLevel = ''; + } + + $this->blockSelectors($block); + + $this->indentLevel++; + } + + if (! empty($block->lines)) { + if ($closeBlock) { + $this->write($closeBlock); + $closeBlock = ''; + } + + if ($downLevel) { + $this->write($downLevel); + $downLevel = ''; + } + + $this->blockLines($block); + + $closeBlock = $this->break; + } + + if (! empty($block->children)) { + if ($this->depth > 0 && ($isMediaOrDirective || ! $this->hasFlatChild($block))) { + array_pop($depths); + + $this->depth--; + $this->blockChildren($block); + $this->depth++; + + $depths[] = $block->depth; + } else { + $this->blockChildren($block); + } + } + + // reclear to not be spoiled by children if T_DIRECTIVE + if ($block->type === Type::T_DIRECTIVE) { + $previousHasSelector = false; + } + + if (! empty($block->selectors)) { + $this->indentLevel--; + + if (! $this->keepSemicolons) { + $this->strippedSemicolon = ''; + } + + $this->write($this->close); + + $closeBlock = $this->break; + + if ($this->depth > 1 && ! empty($block->children)) { + array_pop($depths); + $this->depth--; + } + + if (! $isMediaOrDirective) { + $previousHasSelector = true; + } + } + + if ($block->type === 'root') { + $this->write($this->break); + } + } + + /** + * Block has flat child + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block + * + * @return bool + */ + private function hasFlatChild($block) + { + foreach ($block->children as $child) { + if (empty($child->selectors)) { + return true; + } + } + + return false; + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/OutputBlock.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/OutputBlock.php new file mode 100644 index 00000000..5cc91a08 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Formatter/OutputBlock.php @@ -0,0 +1,68 @@ + + * + * @internal + */ +class OutputBlock +{ + /** + * @var string + */ + public $type; + + /** + * @var int + */ + public $depth; + + /** + * @var array|null + */ + public $selectors; + + /** + * @var string[] + */ + public $lines; + + /** + * @var OutputBlock[] + */ + public $children; + + /** + * @var OutputBlock|null + */ + public $parent; + + /** + * @var string|null + */ + public $sourceName; + + /** + * @var int|null + */ + public $sourceLine; + + /** + * @var int|null + */ + public $sourceColumn; +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Logger/LoggerInterface.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Logger/LoggerInterface.php new file mode 100644 index 00000000..7c0a2f76 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Logger/LoggerInterface.php @@ -0,0 +1,48 @@ +stream = $stream; + $this->closeOnDestruct = $closeOnDestruct; + } + + /** + * @internal + */ + public function __destruct() + { + if ($this->closeOnDestruct) { + fclose($this->stream); + } + } + + /** + * @inheritDoc + */ + public function warn($message, $deprecation = false) + { + $prefix = ($deprecation ? 'DEPRECATION ' : '') . 'WARNING: '; + + fwrite($this->stream, $prefix . $message . "\n\n"); + } + + /** + * @inheritDoc + */ + public function debug($message) + { + fwrite($this->stream, $message . "\n"); + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Node.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Node.php new file mode 100644 index 00000000..fcaf8a95 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Node.php @@ -0,0 +1,43 @@ + + * + * @internal + */ +abstract class Node +{ + /** + * @var string + */ + public $type; + + /** + * @var int + */ + public $sourceIndex; + + /** + * @var int|null + */ + public $sourceLine; + + /** + * @var int|null + */ + public $sourceColumn; +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Node/Number.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Node/Number.php new file mode 100644 index 00000000..ca9b5b65 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Node/Number.php @@ -0,0 +1,804 @@ + + * + * @template-implements \ArrayAccess + */ +class Number extends Node implements \ArrayAccess +{ + const PRECISION = 10; + + /** + * @var int + * @deprecated use {Number::PRECISION} instead to read the precision. Configuring it is not supported anymore. + */ + public static $precision = self::PRECISION; + + /** + * @see http://www.w3.org/TR/2012/WD-css3-values-20120308/ + * + * @var array + * @phpstan-var array> + */ + protected static $unitTable = [ + 'in' => [ + 'in' => 1, + 'pc' => 6, + 'pt' => 72, + 'px' => 96, + 'cm' => 2.54, + 'mm' => 25.4, + 'q' => 101.6, + ], + 'turn' => [ + 'deg' => 360, + 'grad' => 400, + 'rad' => 6.28318530717958647692528676, // 2 * M_PI + 'turn' => 1, + ], + 's' => [ + 's' => 1, + 'ms' => 1000, + ], + 'Hz' => [ + 'Hz' => 1, + 'kHz' => 0.001, + ], + 'dpi' => [ + 'dpi' => 1, + 'dpcm' => 1 / 2.54, + 'dppx' => 1 / 96, + ], + ]; + + /** + * @var int|float + */ + private $dimension; + + /** + * @var string[] + * @phpstan-var list + */ + private $numeratorUnits; + + /** + * @var string[] + * @phpstan-var list + */ + private $denominatorUnits; + + /** + * Initialize number + * + * @param int|float $dimension + * @param string[]|string $numeratorUnits + * @param string[] $denominatorUnits + * + * @phpstan-param list|string $numeratorUnits + * @phpstan-param list $denominatorUnits + */ + public function __construct($dimension, $numeratorUnits, array $denominatorUnits = []) + { + if (is_string($numeratorUnits)) { + $numeratorUnits = $numeratorUnits ? [$numeratorUnits] : []; + } elseif (isset($numeratorUnits['numerator_units'], $numeratorUnits['denominator_units'])) { + // TODO get rid of this once `$number[2]` is not used anymore + $denominatorUnits = $numeratorUnits['denominator_units']; + $numeratorUnits = $numeratorUnits['numerator_units']; + } + + $this->dimension = $dimension; + $this->numeratorUnits = $numeratorUnits; + $this->denominatorUnits = $denominatorUnits; + } + + /** + * @return float|int + */ + public function getDimension() + { + return $this->dimension; + } + + /** + * @return string[] + */ + public function getNumeratorUnits() + { + return $this->numeratorUnits; + } + + /** + * @return string[] + */ + public function getDenominatorUnits() + { + return $this->denominatorUnits; + } + + /** + * @return bool + */ + #[\ReturnTypeWillChange] + public function offsetExists($offset) + { + if ($offset === -3) { + return ! \is_null($this->sourceColumn); + } + + if ($offset === -2) { + return ! \is_null($this->sourceLine); + } + + if ( + $offset === -1 || + $offset === 0 || + $offset === 1 || + $offset === 2 + ) { + return true; + } + + return false; + } + + /** + * @return mixed + */ + #[\ReturnTypeWillChange] + public function offsetGet($offset) + { + switch ($offset) { + case -3: + return $this->sourceColumn; + + case -2: + return $this->sourceLine; + + case -1: + return $this->sourceIndex; + + case 0: + return Type::T_NUMBER; + + case 1: + return $this->dimension; + + case 2: + return array('numerator_units' => $this->numeratorUnits, 'denominator_units' => $this->denominatorUnits); + } + } + + /** + * @return void + */ + #[\ReturnTypeWillChange] + public function offsetSet($offset, $value) + { + throw new \BadMethodCallException('Number is immutable'); + } + + /** + * @return void + */ + #[\ReturnTypeWillChange] + public function offsetUnset($offset) + { + throw new \BadMethodCallException('Number is immutable'); + } + + /** + * Returns true if the number is unitless + * + * @return bool + */ + public function unitless() + { + return \count($this->numeratorUnits) === 0 && \count($this->denominatorUnits) === 0; + } + + /** + * Checks whether the number has exactly this unit + * + * @param string $unit + * + * @return bool + */ + public function hasUnit($unit) + { + return \count($this->numeratorUnits) === 1 && \count($this->denominatorUnits) === 0 && $this->numeratorUnits[0] === $unit; + } + + /** + * Returns unit(s) as the product of numerator units divided by the product of denominator units + * + * @return string + */ + public function unitStr() + { + if ($this->unitless()) { + return ''; + } + + return self::getUnitString($this->numeratorUnits, $this->denominatorUnits); + } + + /** + * @param float|int $min + * @param float|int $max + * @param string|null $name + * + * @return float|int + * @throws SassScriptException + */ + public function valueInRange($min, $max, $name = null) + { + try { + return Util::checkRange('', new Range($min, $max), $this); + } catch (RangeException $e) { + throw SassScriptException::forArgument(sprintf('Expected %s to be within %s%s and %s%3$s', $this, $min, $this->unitStr(), $max), $name); + } + } + + /** + * @param string|null $varName + * + * @return void + */ + public function assertNoUnits($varName = null) + { + if ($this->unitless()) { + return; + } + + throw SassScriptException::forArgument(sprintf('Expected %s to have no units.', $this), $varName); + } + + /** + * @param string $unit + * @param string|null $varName + * + * @return void + */ + public function assertUnit($unit, $varName = null) + { + if ($this->hasUnit($unit)) { + return; + } + + throw SassScriptException::forArgument(sprintf('Expected %s to have unit "%s".', $this, $unit), $varName); + } + + /** + * @param Number $other + * + * @return void + */ + public function assertSameUnitOrUnitless(Number $other) + { + if ($other->unitless()) { + return; + } + + if ($this->numeratorUnits === $other->numeratorUnits && $this->denominatorUnits === $other->denominatorUnits) { + return; + } + + throw new SassScriptException(sprintf( + 'Incompatible units %s and %s.', + self::getUnitString($this->numeratorUnits, $this->denominatorUnits), + self::getUnitString($other->numeratorUnits, $other->denominatorUnits) + )); + } + + /** + * Returns a copy of this number, converted to the units represented by $newNumeratorUnits and $newDenominatorUnits. + * + * This does not throw an error if this number is unitless and + * $newNumeratorUnits/$newDenominatorUnits are not empty, or vice versa. Instead, + * it treats all unitless numbers as convertible to and from all units without + * changing the value. + * + * @param string[] $newNumeratorUnits + * @param string[] $newDenominatorUnits + * + * @return Number + * + * @phpstan-param list $newNumeratorUnits + * @phpstan-param list $newDenominatorUnits + * + * @throws SassScriptException if this number's units are not compatible with $newNumeratorUnits and $newDenominatorUnits + */ + public function coerce(array $newNumeratorUnits, array $newDenominatorUnits) + { + return new Number($this->valueInUnits($newNumeratorUnits, $newDenominatorUnits), $newNumeratorUnits, $newDenominatorUnits); + } + + /** + * @param Number $other + * + * @return bool + */ + public function isComparableTo(Number $other) + { + if ($this->unitless() || $other->unitless()) { + return true; + } + + try { + $this->greaterThan($other); + return true; + } catch (SassScriptException $e) { + return false; + } + } + + /** + * @param Number $other + * + * @return bool + */ + public function lessThan(Number $other) + { + return $this->coerceUnits($other, function ($num1, $num2) { + return $num1 < $num2; + }); + } + + /** + * @param Number $other + * + * @return bool + */ + public function lessThanOrEqual(Number $other) + { + return $this->coerceUnits($other, function ($num1, $num2) { + return $num1 <= $num2; + }); + } + + /** + * @param Number $other + * + * @return bool + */ + public function greaterThan(Number $other) + { + return $this->coerceUnits($other, function ($num1, $num2) { + return $num1 > $num2; + }); + } + + /** + * @param Number $other + * + * @return bool + */ + public function greaterThanOrEqual(Number $other) + { + return $this->coerceUnits($other, function ($num1, $num2) { + return $num1 >= $num2; + }); + } + + /** + * @param Number $other + * + * @return Number + */ + public function plus(Number $other) + { + return $this->coerceNumber($other, function ($num1, $num2) { + return $num1 + $num2; + }); + } + + /** + * @param Number $other + * + * @return Number + */ + public function minus(Number $other) + { + return $this->coerceNumber($other, function ($num1, $num2) { + return $num1 - $num2; + }); + } + + /** + * @return Number + */ + public function unaryMinus() + { + return new Number(-$this->dimension, $this->numeratorUnits, $this->denominatorUnits); + } + + /** + * @param Number $other + * + * @return Number + */ + public function modulo(Number $other) + { + return $this->coerceNumber($other, function ($num1, $num2) { + if ($num2 == 0) { + return NAN; + } + + $result = fmod($num1, $num2); + + if ($result == 0) { + return 0; + } + + if ($num2 < 0 xor $num1 < 0) { + $result += $num2; + } + + return $result; + }); + } + + /** + * @param Number $other + * + * @return Number + */ + public function times(Number $other) + { + return $this->multiplyUnits($this->dimension * $other->dimension, $this->numeratorUnits, $this->denominatorUnits, $other->numeratorUnits, $other->denominatorUnits); + } + + /** + * @param Number $other + * + * @return Number + */ + public function dividedBy(Number $other) + { + if ($other->dimension == 0) { + if ($this->dimension == 0) { + $value = NAN; + } elseif ($this->dimension > 0) { + $value = INF; + } else { + $value = -INF; + } + } else { + $value = $this->dimension / $other->dimension; + } + + return $this->multiplyUnits($value, $this->numeratorUnits, $this->denominatorUnits, $other->denominatorUnits, $other->numeratorUnits); + } + + /** + * @param Number $other + * + * @return bool + */ + public function equals(Number $other) + { + // Unitless numbers are convertable to unit numbers, but not equal, so we special-case unitless here. + if ($this->unitless() !== $other->unitless()) { + return false; + } + + // In Sass, neither NaN nor Infinity are equal to themselves, while PHP defines INF==INF + if (is_nan($this->dimension) || is_nan($other->dimension) || !is_finite($this->dimension) || !is_finite($other->dimension)) { + return false; + } + + if ($this->unitless()) { + return round($this->dimension, self::PRECISION) == round($other->dimension, self::PRECISION); + } + + try { + return $this->coerceUnits($other, function ($num1, $num2) { + return round($num1,self::PRECISION) == round($num2, self::PRECISION); + }); + } catch (SassScriptException $e) { + return false; + } + } + + /** + * Output number + * + * @param \ScssPhp\ScssPhp\Compiler $compiler + * + * @return string + */ + public function output(Compiler $compiler = null) + { + $dimension = round($this->dimension, self::PRECISION); + + if (is_nan($dimension)) { + return 'NaN'; + } + + if ($dimension === INF) { + return 'Infinity'; + } + + if ($dimension === -INF) { + return '-Infinity'; + } + + if ($compiler) { + $unit = $this->unitStr(); + } elseif (isset($this->numeratorUnits[0])) { + $unit = $this->numeratorUnits[0]; + } else { + $unit = ''; + } + + $dimension = number_format($dimension, self::PRECISION, '.', ''); + + return rtrim(rtrim($dimension, '0'), '.') . $unit; + } + + /** + * {@inheritdoc} + */ + public function __toString() + { + return $this->output(); + } + + /** + * @param Number $other + * @param callable $operation + * + * @return Number + * + * @phpstan-param callable(int|float, int|float): (int|float) $operation + */ + private function coerceNumber(Number $other, $operation) + { + $result = $this->coerceUnits($other, $operation); + + if (!$this->unitless()) { + return new Number($result, $this->numeratorUnits, $this->denominatorUnits); + } + + return new Number($result, $other->numeratorUnits, $other->denominatorUnits); + } + + /** + * @param Number $other + * @param callable $operation + * + * @return mixed + * + * @phpstan-template T + * @phpstan-param callable(int|float, int|float): T $operation + * @phpstan-return T + */ + private function coerceUnits(Number $other, $operation) + { + if (!$this->unitless()) { + $num1 = $this->dimension; + $num2 = $other->valueInUnits($this->numeratorUnits, $this->denominatorUnits); + } else { + $num1 = $this->valueInUnits($other->numeratorUnits, $other->denominatorUnits); + $num2 = $other->dimension; + } + + return \call_user_func($operation, $num1, $num2); + } + + /** + * @param string[] $numeratorUnits + * @param string[] $denominatorUnits + * + * @return int|float + * + * @phpstan-param list $numeratorUnits + * @phpstan-param list $denominatorUnits + * + * @throws SassScriptException if this number's units are not compatible with $numeratorUnits and $denominatorUnits + */ + private function valueInUnits(array $numeratorUnits, array $denominatorUnits) + { + if ( + $this->unitless() + || (\count($numeratorUnits) === 0 && \count($denominatorUnits) === 0) + || ($this->numeratorUnits === $numeratorUnits && $this->denominatorUnits === $denominatorUnits) + ) { + return $this->dimension; + } + + $value = $this->dimension; + $oldNumerators = $this->numeratorUnits; + + foreach ($numeratorUnits as $newNumerator) { + foreach ($oldNumerators as $key => $oldNumerator) { + $conversionFactor = self::getConversionFactor($newNumerator, $oldNumerator); + + if (\is_null($conversionFactor)) { + continue; + } + + $value *= $conversionFactor; + unset($oldNumerators[$key]); + continue 2; + } + + throw new SassScriptException(sprintf( + 'Incompatible units %s and %s.', + self::getUnitString($this->numeratorUnits, $this->denominatorUnits), + self::getUnitString($numeratorUnits, $denominatorUnits) + )); + } + + $oldDenominators = $this->denominatorUnits; + + foreach ($denominatorUnits as $newDenominator) { + foreach ($oldDenominators as $key => $oldDenominator) { + $conversionFactor = self::getConversionFactor($newDenominator, $oldDenominator); + + if (\is_null($conversionFactor)) { + continue; + } + + $value /= $conversionFactor; + unset($oldDenominators[$key]); + continue 2; + } + + throw new SassScriptException(sprintf( + 'Incompatible units %s and %s.', + self::getUnitString($this->numeratorUnits, $this->denominatorUnits), + self::getUnitString($numeratorUnits, $denominatorUnits) + )); + } + + if (\count($oldNumerators) || \count($oldDenominators)) { + throw new SassScriptException(sprintf( + 'Incompatible units %s and %s.', + self::getUnitString($this->numeratorUnits, $this->denominatorUnits), + self::getUnitString($numeratorUnits, $denominatorUnits) + )); + } + + return $value; + } + + /** + * @param int|float $value + * @param string[] $numerators1 + * @param string[] $denominators1 + * @param string[] $numerators2 + * @param string[] $denominators2 + * + * @return Number + * + * @phpstan-param list $numerators1 + * @phpstan-param list $denominators1 + * @phpstan-param list $numerators2 + * @phpstan-param list $denominators2 + */ + private function multiplyUnits($value, array $numerators1, array $denominators1, array $numerators2, array $denominators2) + { + $newNumerators = array(); + + foreach ($numerators1 as $numerator) { + foreach ($denominators2 as $key => $denominator) { + $conversionFactor = self::getConversionFactor($numerator, $denominator); + + if (\is_null($conversionFactor)) { + continue; + } + + $value /= $conversionFactor; + unset($denominators2[$key]); + continue 2; + } + + $newNumerators[] = $numerator; + } + + foreach ($numerators2 as $numerator) { + foreach ($denominators1 as $key => $denominator) { + $conversionFactor = self::getConversionFactor($numerator, $denominator); + + if (\is_null($conversionFactor)) { + continue; + } + + $value /= $conversionFactor; + unset($denominators1[$key]); + continue 2; + } + + $newNumerators[] = $numerator; + } + + $newDenominators = array_values(array_merge($denominators1, $denominators2)); + + return new Number($value, $newNumerators, $newDenominators); + } + + /** + * Returns the number of [unit1]s per [unit2]. + * + * Equivalently, `1unit1 * conversionFactor(unit1, unit2) = 1unit2`. + * + * @param string $unit1 + * @param string $unit2 + * + * @return float|int|null + */ + private static function getConversionFactor($unit1, $unit2) + { + if ($unit1 === $unit2) { + return 1; + } + + foreach (static::$unitTable as $unitVariants) { + if (isset($unitVariants[$unit1]) && isset($unitVariants[$unit2])) { + return $unitVariants[$unit1] / $unitVariants[$unit2]; + } + } + + return null; + } + + /** + * Returns unit(s) as the product of numerator units divided by the product of denominator units + * + * @param string[] $numerators + * @param string[] $denominators + * + * @phpstan-param list $numerators + * @phpstan-param list $denominators + * + * @return string + */ + private static function getUnitString(array $numerators, array $denominators) + { + if (!\count($numerators)) { + if (\count($denominators) === 0) { + return 'no units'; + } + + if (\count($denominators) === 1) { + return $denominators[0] . '^-1'; + } + + return '(' . implode('*', $denominators) . ')^-1'; + } + + return implode('*', $numerators) . (\count($denominators) ? '/' . implode('*', $denominators) : ''); + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/OutputStyle.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/OutputStyle.php new file mode 100644 index 00000000..c284639c --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/OutputStyle.php @@ -0,0 +1,9 @@ + + * + * @internal + */ +class Parser +{ + const SOURCE_INDEX = -1; + const SOURCE_LINE = -2; + const SOURCE_COLUMN = -3; + + /** + * @var array + */ + protected static $precedence = [ + '=' => 0, + 'or' => 1, + 'and' => 2, + '==' => 3, + '!=' => 3, + '<=' => 4, + '>=' => 4, + '<' => 4, + '>' => 4, + '+' => 5, + '-' => 5, + '*' => 6, + '/' => 6, + '%' => 6, + ]; + + /** + * @var string + */ + protected static $commentPattern; + /** + * @var string + */ + protected static $operatorPattern; + /** + * @var string + */ + protected static $whitePattern; + + /** + * @var Cache|null + */ + protected $cache; + + private $sourceName; + private $sourceIndex; + /** + * @var array + */ + private $sourcePositions; + /** + * @var array|null + */ + private $charset; + /** + * The current offset in the buffer + * + * @var int + */ + private $count; + /** + * @var Block|null + */ + private $env; + /** + * @var bool + */ + private $inParens; + /** + * @var bool + */ + private $eatWhiteDefault; + /** + * @var bool + */ + private $discardComments; + private $allowVars; + /** + * @var string + */ + private $buffer; + private $utf8; + /** + * @var string|null + */ + private $encoding; + private $patternModifiers; + private $commentsSeen; + + private $cssOnly; + + /** + * @var LoggerInterface + */ + private $logger; + + /** + * Constructor + * + * @api + * + * @param string|null $sourceName + * @param int $sourceIndex + * @param string|null $encoding + * @param Cache|null $cache + * @param bool $cssOnly + * @param LoggerInterface|null $logger + */ + public function __construct($sourceName, $sourceIndex = 0, $encoding = 'utf-8', Cache $cache = null, $cssOnly = false, LoggerInterface $logger = null) + { + $this->sourceName = $sourceName ?: '(stdin)'; + $this->sourceIndex = $sourceIndex; + $this->charset = null; + $this->utf8 = ! $encoding || strtolower($encoding) === 'utf-8'; + $this->patternModifiers = $this->utf8 ? 'Aisu' : 'Ais'; + $this->commentsSeen = []; + $this->commentsSeen = []; + $this->allowVars = true; + $this->cssOnly = $cssOnly; + $this->logger = $logger ?: new QuietLogger(); + + if (empty(static::$operatorPattern)) { + static::$operatorPattern = '([*\/%+-]|[!=]\=|\>\=?|\<\=?|and|or)'; + + $commentSingle = '\/\/'; + $commentMultiLeft = '\/\*'; + $commentMultiRight = '\*\/'; + + static::$commentPattern = $commentMultiLeft . '.*?' . $commentMultiRight; + static::$whitePattern = $this->utf8 + ? '/' . $commentSingle . '[^\n]*\s*|(' . static::$commentPattern . ')\s*|\s+/AisuS' + : '/' . $commentSingle . '[^\n]*\s*|(' . static::$commentPattern . ')\s*|\s+/AisS'; + } + + $this->cache = $cache; + } + + /** + * Get source file name + * + * @api + * + * @return string + */ + public function getSourceName() + { + return $this->sourceName; + } + + /** + * Throw parser error + * + * @api + * + * @param string $msg + * + * @phpstan-return never-return + * + * @throws ParserException + * + * @deprecated use "parseError" and throw the exception in the caller instead. + */ + public function throwParseError($msg = 'parse error') + { + @trigger_error( + 'The method "throwParseError" is deprecated. Use "parseError" and throw the exception in the caller instead', + E_USER_DEPRECATED + ); + + throw $this->parseError($msg); + } + + /** + * Creates a parser error + * + * @api + * + * @param string $msg + * + * @return ParserException + */ + public function parseError($msg = 'parse error') + { + list($line, $column) = $this->getSourcePosition($this->count); + + $loc = empty($this->sourceName) + ? "line: $line, column: $column" + : "$this->sourceName on line $line, at column $column"; + + if ($this->peek('(.*?)(\n|$)', $m, $this->count)) { + $this->restoreEncoding(); + + $e = new ParserException("$msg: failed at `$m[1]` $loc"); + $e->setSourcePosition([$this->sourceName, $line, $column]); + + return $e; + } + + $this->restoreEncoding(); + + $e = new ParserException("$msg: $loc"); + $e->setSourcePosition([$this->sourceName, $line, $column]); + + return $e; + } + + /** + * Parser buffer + * + * @api + * + * @param string $buffer + * + * @return Block + */ + public function parse($buffer) + { + if ($this->cache) { + $cacheKey = $this->sourceName . ':' . md5($buffer); + $parseOptions = [ + 'charset' => $this->charset, + 'utf8' => $this->utf8, + ]; + $v = $this->cache->getCache('parse', $cacheKey, $parseOptions); + + if (! \is_null($v)) { + return $v; + } + } + + // strip BOM (byte order marker) + if (substr($buffer, 0, 3) === "\xef\xbb\xbf") { + $buffer = substr($buffer, 3); + } + + $this->buffer = rtrim($buffer, "\x00..\x1f"); + $this->count = 0; + $this->env = null; + $this->inParens = false; + $this->eatWhiteDefault = true; + + $this->saveEncoding(); + $this->extractLineNumbers($buffer); + + $this->pushBlock(null); // root block + $this->whitespace(); + $this->pushBlock(null); + $this->popBlock(); + + while ($this->parseChunk()) { + ; + } + + if ($this->count !== \strlen($this->buffer)) { + throw $this->parseError(); + } + + if (! empty($this->env->parent)) { + throw $this->parseError('unclosed block'); + } + + if ($this->charset) { + array_unshift($this->env->children, $this->charset); + } + + $this->restoreEncoding(); + + if ($this->cache) { + $this->cache->setCache('parse', $cacheKey, $this->env, $parseOptions); + } + + return $this->env; + } + + /** + * Parse a value or value list + * + * @api + * + * @param string $buffer + * @param string|array $out + * + * @return bool + */ + public function parseValue($buffer, &$out) + { + $this->count = 0; + $this->env = null; + $this->inParens = false; + $this->eatWhiteDefault = true; + $this->buffer = (string) $buffer; + + $this->saveEncoding(); + $this->extractLineNumbers($this->buffer); + + $list = $this->valueList($out); + + $this->restoreEncoding(); + + return $list; + } + + /** + * Parse a selector or selector list + * + * @api + * + * @param string $buffer + * @param string|array $out + * @param bool $shouldValidate + * + * @return bool + */ + public function parseSelector($buffer, &$out, $shouldValidate = true) + { + $this->count = 0; + $this->env = null; + $this->inParens = false; + $this->eatWhiteDefault = true; + $this->buffer = (string) $buffer; + + $this->saveEncoding(); + $this->extractLineNumbers($this->buffer); + + // discard space/comments at the start + $this->discardComments = true; + $this->whitespace(); + $this->discardComments = false; + + $selector = $this->selectors($out); + + $this->restoreEncoding(); + + if ($shouldValidate && $this->count !== strlen($buffer)) { + throw $this->parseError("`" . substr($buffer, $this->count) . "` is not a valid Selector in `$buffer`"); + } + + return $selector; + } + + /** + * Parse a media Query + * + * @api + * + * @param string $buffer + * @param string|array $out + * + * @return bool + */ + public function parseMediaQueryList($buffer, &$out) + { + $this->count = 0; + $this->env = null; + $this->inParens = false; + $this->eatWhiteDefault = true; + $this->buffer = (string) $buffer; + + $this->saveEncoding(); + $this->extractLineNumbers($this->buffer); + + $isMediaQuery = $this->mediaQueryList($out); + + $this->restoreEncoding(); + + return $isMediaQuery; + } + + /** + * Parse a single chunk off the head of the buffer and append it to the + * current parse environment. + * + * Returns false when the buffer is empty, or when there is an error. + * + * This function is called repeatedly until the entire document is + * parsed. + * + * This parser is most similar to a recursive descent parser. Single + * functions represent discrete grammatical rules for the language, and + * they are able to capture the text that represents those rules. + * + * Consider the function Compiler::keyword(). (All parse functions are + * structured the same.) + * + * The function takes a single reference argument. When calling the + * function it will attempt to match a keyword on the head of the buffer. + * If it is successful, it will place the keyword in the referenced + * argument, advance the position in the buffer, and return true. If it + * fails then it won't advance the buffer and it will return false. + * + * All of these parse functions are powered by Compiler::match(), which behaves + * the same way, but takes a literal regular expression. Sometimes it is + * more convenient to use match instead of creating a new function. + * + * Because of the format of the functions, to parse an entire string of + * grammatical rules, you can chain them together using &&. + * + * But, if some of the rules in the chain succeed before one fails, then + * the buffer position will be left at an invalid state. In order to + * avoid this, Compiler::seek() is used to remember and set buffer positions. + * + * Before parsing a chain, use $s = $this->count to remember the current + * position into $s. Then if a chain fails, use $this->seek($s) to + * go back where we started. + * + * @return bool + */ + protected function parseChunk() + { + $s = $this->count; + + // the directives + if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] === '@') { + if ( + $this->literal('@at-root', 8) && + ($this->selectors($selector) || true) && + ($this->map($with) || true) && + (($this->matchChar('(') && + $this->interpolation($with) && + $this->matchChar(')')) || true) && + $this->matchChar('{', false) + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + $atRoot = new AtRootBlock(); + $this->registerPushedBlock($atRoot, $s); + $atRoot->selector = $selector; + $atRoot->with = $with; + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@media', 6) && + $this->mediaQueryList($mediaQueryList) && + $this->matchChar('{', false) + ) { + $media = new MediaBlock(); + $this->registerPushedBlock($media, $s); + $media->queryList = $mediaQueryList[2]; + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@mixin', 6) && + $this->keyword($mixinName) && + ($this->argumentDef($args) || true) && + $this->matchChar('{', false) + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + $mixin = new CallableBlock(Type::T_MIXIN); + $this->registerPushedBlock($mixin, $s); + $mixin->name = $mixinName; + $mixin->args = $args; + + return true; + } + + $this->seek($s); + + if ( + ($this->literal('@include', 8) && + $this->keyword($mixinName) && + ($this->matchChar('(') && + ($this->argValues($argValues) || true) && + $this->matchChar(')') || true) && + ($this->end()) || + ($this->literal('using', 5) && + $this->argumentDef($argUsing) && + ($this->end() || $this->matchChar('{') && $hasBlock = true)) || + $this->matchChar('{') && $hasBlock = true) + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + $child = [ + Type::T_INCLUDE, + $mixinName, + isset($argValues) ? $argValues : null, + null, + isset($argUsing) ? $argUsing : null + ]; + + if (! empty($hasBlock)) { + $include = new ContentBlock(); + $this->registerPushedBlock($include, $s); + $include->child = $child; + } else { + $this->append($child, $s); + } + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@scssphp-import-once', 20) && + $this->valueList($importPath) && + $this->end() + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + list($line, $column) = $this->getSourcePosition($s); + $file = $this->sourceName; + $this->logger->warn("The \"@scssphp-import-once\" directive is deprecated and will be removed in ScssPhp 2.0, in \"$file\", line $line, column $column.", true); + + $this->append([Type::T_SCSSPHP_IMPORT_ONCE, $importPath], $s); + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@import', 7) && + $this->valueList($importPath) && + $importPath[0] !== Type::T_FUNCTION_CALL && + $this->end() + ) { + if ($this->cssOnly) { + $this->assertPlainCssValid([Type::T_IMPORT, $importPath], $s); + $this->append([Type::T_COMMENT, rtrim(substr($this->buffer, $s, $this->count - $s))]); + return true; + } + + $this->append([Type::T_IMPORT, $importPath], $s); + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@import', 7) && + $this->url($importPath) && + $this->end() + ) { + if ($this->cssOnly) { + $this->assertPlainCssValid([Type::T_IMPORT, $importPath], $s); + $this->append([Type::T_COMMENT, rtrim(substr($this->buffer, $s, $this->count - $s))]); + return true; + } + + $this->append([Type::T_IMPORT, $importPath], $s); + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@extend', 7) && + $this->selectors($selectors) && + $this->end() + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + // check for '!flag' + $optional = $this->stripOptionalFlag($selectors); + $this->append([Type::T_EXTEND, $selectors, $optional], $s); + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@function', 9) && + $this->keyword($fnName) && + $this->argumentDef($args) && + $this->matchChar('{', false) + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + $func = new CallableBlock(Type::T_FUNCTION); + $this->registerPushedBlock($func, $s); + $func->name = $fnName; + $func->args = $args; + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@return', 7) && + ($this->valueList($retVal) || true) && + $this->end() + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + $this->append([Type::T_RETURN, isset($retVal) ? $retVal : [Type::T_NULL]], $s); + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@each', 5) && + $this->genericList($varNames, 'variable', ',', false) && + $this->literal('in', 2) && + $this->valueList($list) && + $this->matchChar('{', false) + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + $each = new EachBlock(); + $this->registerPushedBlock($each, $s); + + foreach ($varNames[2] as $varName) { + $each->vars[] = $varName[1]; + } + + $each->list = $list; + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@while', 6) && + $this->expression($cond) && + $this->matchChar('{', false) + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + while ( + $cond[0] === Type::T_LIST && + ! empty($cond['enclosing']) && + $cond['enclosing'] === 'parent' && + \count($cond[2]) == 1 + ) { + $cond = reset($cond[2]); + } + + $while = new WhileBlock(); + $this->registerPushedBlock($while, $s); + $while->cond = $cond; + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@for', 4) && + $this->variable($varName) && + $this->literal('from', 4) && + $this->expression($start) && + ($this->literal('through', 7) || + ($forUntil = true && $this->literal('to', 2))) && + $this->expression($end) && + $this->matchChar('{', false) + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + $for = new ForBlock(); + $this->registerPushedBlock($for, $s); + $for->var = $varName[1]; + $for->start = $start; + $for->end = $end; + $for->until = isset($forUntil); + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@if', 3) && + $this->functionCallArgumentsList($cond, false, '{', false) + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + $if = new IfBlock(); + $this->registerPushedBlock($if, $s); + + while ( + $cond[0] === Type::T_LIST && + ! empty($cond['enclosing']) && + $cond['enclosing'] === 'parent' && + \count($cond[2]) == 1 + ) { + $cond = reset($cond[2]); + } + + $if->cond = $cond; + $if->cases = []; + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@debug', 6) && + $this->functionCallArgumentsList($value, false) + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + $this->append([Type::T_DEBUG, $value], $s); + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@warn', 5) && + $this->functionCallArgumentsList($value, false) + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + $this->append([Type::T_WARN, $value], $s); + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@error', 6) && + $this->functionCallArgumentsList($value, false) + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + $this->append([Type::T_ERROR, $value], $s); + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@content', 8) && + ($this->end() || + $this->matchChar('(') && + $this->argValues($argContent) && + $this->matchChar(')') && + $this->end()) + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + $this->append([Type::T_MIXIN_CONTENT, isset($argContent) ? $argContent : null], $s); + + return true; + } + + $this->seek($s); + + $last = $this->last(); + + if (isset($last) && $last[0] === Type::T_IF) { + list(, $if) = $last; + assert($if instanceof IfBlock); + + if ($this->literal('@else', 5)) { + if ($this->matchChar('{', false)) { + $else = new ElseBlock(); + } elseif ( + $this->literal('if', 2) && + $this->functionCallArgumentsList($cond, false, '{', false) + ) { + $else = new ElseifBlock(); + $else->cond = $cond; + } + + if (isset($else)) { + $this->registerPushedBlock($else, $s); + $if->cases[] = $else; + + return true; + } + } + + $this->seek($s); + } + + // only retain the first @charset directive encountered + if ( + $this->literal('@charset', 8) && + $this->valueList($charset) && + $this->end() + ) { + if (! isset($this->charset)) { + $statement = [Type::T_CHARSET, $charset]; + + list($line, $column) = $this->getSourcePosition($s); + + $statement[static::SOURCE_LINE] = $line; + $statement[static::SOURCE_COLUMN] = $column; + $statement[static::SOURCE_INDEX] = $this->sourceIndex; + + $this->charset = $statement; + } + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@supports', 9) && + ($t1 = $this->supportsQuery($supportQuery)) && + ($t2 = $this->matchChar('{', false)) + ) { + $directive = new DirectiveBlock(); + $this->registerPushedBlock($directive, $s); + $directive->name = 'supports'; + $directive->value = $supportQuery; + + return true; + } + + $this->seek($s); + + // doesn't match built in directive, do generic one + if ( + $this->matchChar('@', false) && + $this->mixedKeyword($dirName) && + $this->directiveValue($dirValue, '{') + ) { + if (count($dirName) === 1 && is_string(reset($dirName))) { + $dirName = reset($dirName); + } else { + $dirName = [Type::T_STRING, '', $dirName]; + } + if ($dirName === 'media') { + $directive = new MediaBlock(); + } else { + $directive = new DirectiveBlock(); + $directive->name = $dirName; + } + $this->registerPushedBlock($directive, $s); + + if (isset($dirValue)) { + ! $this->cssOnly || ($dirValue = $this->assertPlainCssValid($dirValue)); + $directive->value = $dirValue; + } + + return true; + } + + $this->seek($s); + + // maybe it's a generic blockless directive + if ( + $this->matchChar('@', false) && + $this->mixedKeyword($dirName) && + ! $this->isKnownGenericDirective($dirName) && + ($this->end(false) || ($this->directiveValue($dirValue, '') && $this->end(false))) + ) { + if (\count($dirName) === 1 && \is_string(\reset($dirName))) { + $dirName = \reset($dirName); + } else { + $dirName = [Type::T_STRING, '', $dirName]; + } + if ( + ! empty($this->env->parent) && + $this->env->type && + ! \in_array($this->env->type, [Type::T_DIRECTIVE, Type::T_MEDIA]) + ) { + $plain = \trim(\substr($this->buffer, $s, $this->count - $s)); + throw $this->parseError( + "Unknown directive `{$plain}` not allowed in `" . $this->env->type . "` block" + ); + } + // blockless directives with a blank line after keeps their blank lines after + // sass-spec compliance purpose + $s = $this->count; + $hasBlankLine = false; + if ($this->match('\s*?\n\s*\n', $out, false)) { + $hasBlankLine = true; + $this->seek($s); + } + $isNotRoot = ! empty($this->env->parent); + $this->append([Type::T_DIRECTIVE, [$dirName, $dirValue, $hasBlankLine, $isNotRoot]], $s); + $this->whitespace(); + + return true; + } + + $this->seek($s); + + return false; + } + + $inCssSelector = null; + if ($this->cssOnly) { + $inCssSelector = (! empty($this->env->parent) && + ! in_array($this->env->type, [Type::T_DIRECTIVE, Type::T_MEDIA])); + } + // custom properties : right part is static + if (($this->customProperty($name) ) && $this->matchChar(':', false)) { + $start = $this->count; + + // but can be complex and finish with ; or } + foreach ([';','}'] as $ending) { + if ( + $this->openString($ending, $stringValue, '(', ')', false) && + $this->end() + ) { + $end = $this->count; + $value = $stringValue; + + // check if we have only a partial value due to nested [] or { } to take in account + $nestingPairs = [['[', ']'], ['{', '}']]; + + foreach ($nestingPairs as $nestingPair) { + $p = strpos($this->buffer, $nestingPair[0], $start); + + if ($p && $p < $end) { + $this->seek($start); + + if ( + $this->openString($ending, $stringValue, $nestingPair[0], $nestingPair[1], false) && + $this->end() && + $this->count > $end + ) { + $end = $this->count; + $value = $stringValue; + } + } + } + + $this->seek($end); + $this->append([Type::T_CUSTOM_PROPERTY, $name, $value], $s); + + return true; + } + } + + // TODO: output an error here if nothing found according to sass spec + } + + $this->seek($s); + + // property shortcut + // captures most properties before having to parse a selector + if ( + $this->keyword($name, false) && + $this->literal(': ', 2) && + $this->valueList($value) && + $this->end() + ) { + $name = [Type::T_STRING, '', [$name]]; + $this->append([Type::T_ASSIGN, $name, $value], $s); + + return true; + } + + $this->seek($s); + + // variable assigns + if ( + $this->variable($name) && + $this->matchChar(':') && + $this->valueList($value) && + $this->end() + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + // check for '!flag' + $assignmentFlags = $this->stripAssignmentFlags($value); + $this->append([Type::T_ASSIGN, $name, $value, $assignmentFlags], $s); + + return true; + } + + $this->seek($s); + + // opening css block + if ( + $this->selectors($selectors) && + $this->matchChar('{', false) + ) { + ! $this->cssOnly || ! $inCssSelector || $this->assertPlainCssValid(false); + + $this->pushBlock($selectors, $s); + + if ($this->eatWhiteDefault) { + $this->whitespace(); + $this->append(null); // collect comments at the beginning if needed + } + + return true; + } + + $this->seek($s); + + // property assign, or nested assign + if ( + $this->propertyName($name) && + $this->matchChar(':') + ) { + $foundSomething = false; + + if ($this->valueList($value)) { + if (empty($this->env->parent)) { + throw $this->parseError('expected "{"'); + } + + $this->append([Type::T_ASSIGN, $name, $value], $s); + $foundSomething = true; + } + + if ($this->matchChar('{', false)) { + ! $this->cssOnly || $this->assertPlainCssValid(false); + + $propBlock = new NestedPropertyBlock(); + $this->registerPushedBlock($propBlock, $s); + $propBlock->prefix = $name; + $propBlock->hasValue = $foundSomething; + + $foundSomething = true; + } elseif ($foundSomething) { + $foundSomething = $this->end(); + } + + if ($foundSomething) { + return true; + } + } + + $this->seek($s); + + // closing a block + if ($this->matchChar('}', false)) { + $block = $this->popBlock(); + + if (! isset($block->type) || $block->type !== Type::T_IF) { + if ($this->env->parent) { + $this->append(null); // collect comments before next statement if needed + } + } + + if ($block instanceof ContentBlock) { + $include = $block->child; + assert(\is_array($include)); + unset($block->child); + $include[3] = $block; + $this->append($include, $s); + } elseif (!$block instanceof ElseBlock && !$block instanceof ElseifBlock) { + $type = isset($block->type) ? $block->type : Type::T_BLOCK; + $this->append([$type, $block], $s); + } + + // collect comments just after the block closing if needed + if ($this->eatWhiteDefault) { + $this->whitespace(); + + if ($this->env->comments) { + $this->append(null); + } + } + + return true; + } + + // extra stuff + if ($this->matchChar(';')) { + return true; + } + + return false; + } + + /** + * Push block onto parse tree + * + * @param array|null $selectors + * @param int $pos + * + * @return Block + */ + protected function pushBlock($selectors, $pos = 0) + { + $b = new Block(); + $b->selectors = $selectors; + + $this->registerPushedBlock($b, $pos); + + return $b; + } + + /** + * @param Block $b + * @param int $pos + * + * @return void + */ + private function registerPushedBlock(Block $b, $pos) + { + list($line, $column) = $this->getSourcePosition($pos); + + $b->sourceName = $this->sourceName; + $b->sourceLine = $line; + $b->sourceColumn = $column; + $b->sourceIndex = $this->sourceIndex; + $b->comments = []; + $b->parent = $this->env; + + if (! $this->env) { + $b->children = []; + } elseif (empty($this->env->children)) { + $this->env->children = $this->env->comments; + $b->children = []; + $this->env->comments = []; + } else { + $b->children = $this->env->comments; + $this->env->comments = []; + } + + $this->env = $b; + + // collect comments at the beginning of a block if needed + if ($this->eatWhiteDefault) { + $this->whitespace(); + + if ($this->env->comments) { + $this->append(null); + } + } + } + + /** + * Push special (named) block onto parse tree + * + * @deprecated + * + * @param string $type + * @param int $pos + * + * @return Block + */ + protected function pushSpecialBlock($type, $pos) + { + $block = $this->pushBlock(null, $pos); + $block->type = $type; + + return $block; + } + + /** + * Pop scope and return last block + * + * @return Block + * + * @throws \Exception + */ + protected function popBlock() + { + + // collect comments ending just before of a block closing + if ($this->env->comments) { + $this->append(null); + } + + // pop the block + $block = $this->env; + + if (empty($block->parent)) { + throw $this->parseError('unexpected }'); + } + + if ($block->type == Type::T_AT_ROOT) { + // keeps the parent in case of self selector & + $block->selfParent = $block->parent; + } + + $this->env = $block->parent; + + unset($block->parent); + + return $block; + } + + /** + * Peek input stream + * + * @param string $regex + * @param array $out + * @param int $from + * + * @return int + */ + protected function peek($regex, &$out, $from = null) + { + if (! isset($from)) { + $from = $this->count; + } + + $r = '/' . $regex . '/' . $this->patternModifiers; + $result = preg_match($r, $this->buffer, $out, 0, $from); + + return $result; + } + + /** + * Seek to position in input stream (or return current position in input stream) + * + * @param int $where + */ + protected function seek($where) + { + $this->count = $where; + } + + /** + * Assert a parsed part is plain CSS Valid + * + * @param array|false $parsed + * @param int $startPos + * + * @throws ParserException + */ + protected function assertPlainCssValid($parsed, $startPos = null) + { + $type = ''; + if ($parsed) { + $type = $parsed[0]; + $parsed = $this->isPlainCssValidElement($parsed); + } + if (! $parsed) { + if (! \is_null($startPos)) { + $plain = rtrim(substr($this->buffer, $startPos, $this->count - $startPos)); + $message = "Error : `{$plain}` isn't allowed in plain CSS"; + } else { + $message = 'Error: SCSS syntax not allowed in CSS file'; + } + if ($type) { + $message .= " ($type)"; + } + throw $this->parseError($message); + } + + return $parsed; + } + + /** + * Check a parsed element is plain CSS Valid + * + * @param array $parsed + * @param bool $allowExpression + * + * @return bool|array + */ + protected function isPlainCssValidElement($parsed, $allowExpression = false) + { + // keep string as is + if (is_string($parsed)) { + return $parsed; + } + + if ( + \in_array($parsed[0], [Type::T_FUNCTION, Type::T_FUNCTION_CALL]) && + !\in_array($parsed[1], [ + 'alpha', + 'attr', + 'calc', + 'cubic-bezier', + 'env', + 'grayscale', + 'hsl', + 'hsla', + 'hwb', + 'invert', + 'linear-gradient', + 'min', + 'max', + 'radial-gradient', + 'repeating-linear-gradient', + 'repeating-radial-gradient', + 'rgb', + 'rgba', + 'rotate', + 'saturate', + 'var', + ]) && + Compiler::isNativeFunction($parsed[1]) + ) { + return false; + } + + switch ($parsed[0]) { + case Type::T_BLOCK: + case Type::T_KEYWORD: + case Type::T_NULL: + case Type::T_NUMBER: + case Type::T_MEDIA: + return $parsed; + + case Type::T_COMMENT: + if (isset($parsed[2])) { + return false; + } + return $parsed; + + case Type::T_DIRECTIVE: + if (\is_array($parsed[1])) { + $parsed[1][1] = $this->isPlainCssValidElement($parsed[1][1]); + if (! $parsed[1][1]) { + return false; + } + } + + return $parsed; + + case Type::T_IMPORT: + if ($parsed[1][0] === Type::T_LIST) { + return false; + } + $parsed[1] = $this->isPlainCssValidElement($parsed[1]); + if ($parsed[1] === false) { + return false; + } + return $parsed; + + case Type::T_STRING: + foreach ($parsed[2] as $k => $substr) { + if (\is_array($substr)) { + $parsed[2][$k] = $this->isPlainCssValidElement($substr); + if (! $parsed[2][$k]) { + return false; + } + } + } + return $parsed; + + case Type::T_LIST: + if (!empty($parsed['enclosing'])) { + return false; + } + foreach ($parsed[2] as $k => $listElement) { + $parsed[2][$k] = $this->isPlainCssValidElement($listElement); + if (! $parsed[2][$k]) { + return false; + } + } + return $parsed; + + case Type::T_ASSIGN: + foreach ([1, 2, 3] as $k) { + if (! empty($parsed[$k])) { + $parsed[$k] = $this->isPlainCssValidElement($parsed[$k]); + if (! $parsed[$k]) { + return false; + } + } + } + return $parsed; + + case Type::T_EXPRESSION: + list( ,$op, $lhs, $rhs, $inParens, $whiteBefore, $whiteAfter) = $parsed; + if (! $allowExpression && ! \in_array($op, ['and', 'or', '/'])) { + return false; + } + $lhs = $this->isPlainCssValidElement($lhs, true); + if (! $lhs) { + return false; + } + $rhs = $this->isPlainCssValidElement($rhs, true); + if (! $rhs) { + return false; + } + + return [ + Type::T_STRING, + '', [ + $this->inParens ? '(' : '', + $lhs, + ($whiteBefore ? ' ' : '') . $op . ($whiteAfter ? ' ' : ''), + $rhs, + $this->inParens ? ')' : '' + ] + ]; + + case Type::T_CUSTOM_PROPERTY: + case Type::T_UNARY: + $parsed[2] = $this->isPlainCssValidElement($parsed[2]); + if (! $parsed[2]) { + return false; + } + return $parsed; + + case Type::T_FUNCTION: + $argsList = $parsed[2]; + foreach ($argsList[2] as $argElement) { + if (! $this->isPlainCssValidElement($argElement)) { + return false; + } + } + return $parsed; + + case Type::T_FUNCTION_CALL: + $parsed[0] = Type::T_FUNCTION; + $argsList = [Type::T_LIST, ',', []]; + foreach ($parsed[2] as $arg) { + if ($arg[0] || ! empty($arg[2])) { + // no named arguments possible in a css function call + // nor ... argument + return false; + } + $arg = $this->isPlainCssValidElement($arg[1], $parsed[1] === 'calc'); + if (! $arg) { + return false; + } + $argsList[2][] = $arg; + } + $parsed[2] = $argsList; + return $parsed; + } + + return false; + } + + /** + * Match string looking for either ending delim, escape, or string interpolation + * + * {@internal This is a workaround for preg_match's 250K string match limit. }} + * + * @param array $m Matches (passed by reference) + * @param string $delim Delimiter + * + * @return bool True if match; false otherwise + */ + protected function matchString(&$m, $delim) + { + $token = null; + + $end = \strlen($this->buffer); + + // look for either ending delim, escape, or string interpolation + foreach (['#{', '\\', "\r", $delim] as $lookahead) { + $pos = strpos($this->buffer, $lookahead, $this->count); + + if ($pos !== false && $pos < $end) { + $end = $pos; + $token = $lookahead; + } + } + + if (! isset($token)) { + return false; + } + + $match = substr($this->buffer, $this->count, $end - $this->count); + $m = [ + $match . $token, + $match, + $token + ]; + $this->count = $end + \strlen($token); + + return true; + } + + /** + * Try to match something on head of buffer + * + * @param string $regex + * @param array $out + * @param bool $eatWhitespace + * + * @return bool + */ + protected function match($regex, &$out, $eatWhitespace = null) + { + $r = '/' . $regex . '/' . $this->patternModifiers; + + if (! preg_match($r, $this->buffer, $out, 0, $this->count)) { + return false; + } + + $this->count += \strlen($out[0]); + + if (! isset($eatWhitespace)) { + $eatWhitespace = $this->eatWhiteDefault; + } + + if ($eatWhitespace) { + $this->whitespace(); + } + + return true; + } + + /** + * Match a single string + * + * @param string $char + * @param bool $eatWhitespace + * + * @return bool + */ + protected function matchChar($char, $eatWhitespace = null) + { + if (! isset($this->buffer[$this->count]) || $this->buffer[$this->count] !== $char) { + return false; + } + + $this->count++; + + if (! isset($eatWhitespace)) { + $eatWhitespace = $this->eatWhiteDefault; + } + + if ($eatWhitespace) { + $this->whitespace(); + } + + return true; + } + + /** + * Match literal string + * + * @param string $what + * @param int $len + * @param bool $eatWhitespace + * + * @return bool + */ + protected function literal($what, $len, $eatWhitespace = null) + { + if (strcasecmp(substr($this->buffer, $this->count, $len), $what) !== 0) { + return false; + } + + $this->count += $len; + + if (! isset($eatWhitespace)) { + $eatWhitespace = $this->eatWhiteDefault; + } + + if ($eatWhitespace) { + $this->whitespace(); + } + + return true; + } + + /** + * Match some whitespace + * + * @return bool + */ + protected function whitespace() + { + $gotWhite = false; + + while (preg_match(static::$whitePattern, $this->buffer, $m, 0, $this->count)) { + if (isset($m[1]) && empty($this->commentsSeen[$this->count])) { + // comment that are kept in the output CSS + $comment = []; + $startCommentCount = $this->count; + $endCommentCount = $this->count + \strlen($m[1]); + + // find interpolations in comment + $p = strpos($this->buffer, '#{', $this->count); + + while ($p !== false && $p < $endCommentCount) { + $c = substr($this->buffer, $this->count, $p - $this->count); + $comment[] = $c; + $this->count = $p; + $out = null; + + if ($this->interpolation($out)) { + // keep right spaces in the following string part + if ($out[3]) { + while ($this->buffer[$this->count - 1] !== '}') { + $this->count--; + } + + $out[3] = ''; + } + + $comment[] = [Type::T_COMMENT, substr($this->buffer, $p, $this->count - $p), $out]; + } else { + list($line, $column) = $this->getSourcePosition($this->count); + $file = $this->sourceName; + if (!$this->discardComments) { + $this->logger->warn("Unterminated interpolations in multiline comments are deprecated and will be removed in ScssPhp 2.0, in \"$file\", line $line, column $column.", true); + } + $comment[] = substr($this->buffer, $this->count, 2); + + $this->count += 2; + } + + $p = strpos($this->buffer, '#{', $this->count); + } + + // remaining part + $c = substr($this->buffer, $this->count, $endCommentCount - $this->count); + + if (! $comment) { + // single part static comment + $this->appendComment([Type::T_COMMENT, $c]); + } else { + $comment[] = $c; + $staticComment = substr($this->buffer, $startCommentCount, $endCommentCount - $startCommentCount); + $commentStatement = [Type::T_COMMENT, $staticComment, [Type::T_STRING, '', $comment]]; + + list($line, $column) = $this->getSourcePosition($startCommentCount); + $commentStatement[self::SOURCE_LINE] = $line; + $commentStatement[self::SOURCE_COLUMN] = $column; + $commentStatement[self::SOURCE_INDEX] = $this->sourceIndex; + + $this->appendComment($commentStatement); + } + + $this->commentsSeen[$startCommentCount] = true; + $this->count = $endCommentCount; + } else { + // comment that are ignored and not kept in the output css + $this->count += \strlen($m[0]); + // silent comments are not allowed in plain CSS files + ! $this->cssOnly + || ! \strlen(trim($m[0])) + || $this->assertPlainCssValid(false, $this->count - \strlen($m[0])); + } + + $gotWhite = true; + } + + return $gotWhite; + } + + /** + * Append comment to current block + * + * @param array $comment + */ + protected function appendComment($comment) + { + if (! $this->discardComments) { + $this->env->comments[] = $comment; + } + } + + /** + * Append statement to current block + * + * @param array|null $statement + * @param int $pos + */ + protected function append($statement, $pos = null) + { + if (! \is_null($statement)) { + ! $this->cssOnly || ($statement = $this->assertPlainCssValid($statement, $pos)); + + if (! \is_null($pos)) { + list($line, $column) = $this->getSourcePosition($pos); + + $statement[static::SOURCE_LINE] = $line; + $statement[static::SOURCE_COLUMN] = $column; + $statement[static::SOURCE_INDEX] = $this->sourceIndex; + } + + $this->env->children[] = $statement; + } + + $comments = $this->env->comments; + + if ($comments) { + $this->env->children = array_merge($this->env->children, $comments); + $this->env->comments = []; + } + } + + /** + * Returns last child was appended + * + * @return array|null + */ + protected function last() + { + $i = \count($this->env->children) - 1; + + if (isset($this->env->children[$i])) { + return $this->env->children[$i]; + } + } + + /** + * Parse media query list + * + * @param array $out + * + * @return bool + */ + protected function mediaQueryList(&$out) + { + return $this->genericList($out, 'mediaQuery', ',', false); + } + + /** + * Parse media query + * + * @param array $out + * + * @return bool + */ + protected function mediaQuery(&$out) + { + $expressions = null; + $parts = []; + + if ( + ($this->literal('only', 4) && ($only = true) || + $this->literal('not', 3) && ($not = true) || true) && + $this->mixedKeyword($mediaType) + ) { + $prop = [Type::T_MEDIA_TYPE]; + + if (isset($only)) { + $prop[] = [Type::T_KEYWORD, 'only']; + } + + if (isset($not)) { + $prop[] = [Type::T_KEYWORD, 'not']; + } + + $media = [Type::T_LIST, '', []]; + + foreach ((array) $mediaType as $type) { + if (\is_array($type)) { + $media[2][] = $type; + } else { + $media[2][] = [Type::T_KEYWORD, $type]; + } + } + + $prop[] = $media; + $parts[] = $prop; + } + + if (empty($parts) || $this->literal('and', 3)) { + $this->genericList($expressions, 'mediaExpression', 'and', false); + + if (\is_array($expressions)) { + $parts = array_merge($parts, $expressions[2]); + } + } + + $out = $parts; + + return true; + } + + /** + * Parse supports query + * + * @param array $out + * + * @return bool + */ + protected function supportsQuery(&$out) + { + $expressions = null; + $parts = []; + + $s = $this->count; + + $not = false; + + if ( + ($this->literal('not', 3) && ($not = true) || true) && + $this->matchChar('(') && + ($this->expression($property)) && + $this->literal(': ', 2) && + $this->valueList($value) && + $this->matchChar(')') + ) { + $support = [Type::T_STRING, '', [[Type::T_KEYWORD, ($not ? 'not ' : '') . '(']]]; + $support[2][] = $property; + $support[2][] = [Type::T_KEYWORD, ': ']; + $support[2][] = $value; + $support[2][] = [Type::T_KEYWORD, ')']; + + $parts[] = $support; + $s = $this->count; + } else { + $this->seek($s); + } + + if ( + $this->matchChar('(') && + $this->supportsQuery($subQuery) && + $this->matchChar(')') + ) { + $parts[] = [Type::T_STRING, '', [[Type::T_KEYWORD, '('], $subQuery, [Type::T_KEYWORD, ')']]]; + $s = $this->count; + } else { + $this->seek($s); + } + + if ( + $this->literal('not', 3) && + $this->supportsQuery($subQuery) + ) { + $parts[] = [Type::T_STRING, '', [[Type::T_KEYWORD, 'not '], $subQuery]]; + $s = $this->count; + } else { + $this->seek($s); + } + + if ( + $this->literal('selector(', 9) && + $this->selector($selector) && + $this->matchChar(')') + ) { + $support = [Type::T_STRING, '', [[Type::T_KEYWORD, 'selector(']]]; + + $selectorList = [Type::T_LIST, '', []]; + + foreach ($selector as $sc) { + $compound = [Type::T_STRING, '', []]; + + foreach ($sc as $scp) { + if (\is_array($scp)) { + $compound[2][] = $scp; + } else { + $compound[2][] = [Type::T_KEYWORD, $scp]; + } + } + + $selectorList[2][] = $compound; + } + + $support[2][] = $selectorList; + $support[2][] = [Type::T_KEYWORD, ')']; + $parts[] = $support; + $s = $this->count; + } else { + $this->seek($s); + } + + if ($this->variable($var) or $this->interpolation($var)) { + $parts[] = $var; + $s = $this->count; + } else { + $this->seek($s); + } + + if ( + $this->literal('and', 3) && + $this->genericList($expressions, 'supportsQuery', ' and', false) + ) { + array_unshift($expressions[2], [Type::T_STRING, '', $parts]); + + $parts = [$expressions]; + $s = $this->count; + } else { + $this->seek($s); + } + + if ( + $this->literal('or', 2) && + $this->genericList($expressions, 'supportsQuery', ' or', false) + ) { + array_unshift($expressions[2], [Type::T_STRING, '', $parts]); + + $parts = [$expressions]; + $s = $this->count; + } else { + $this->seek($s); + } + + if (\count($parts)) { + if ($this->eatWhiteDefault) { + $this->whitespace(); + } + + $out = [Type::T_STRING, '', $parts]; + + return true; + } + + return false; + } + + + /** + * Parse media expression + * + * @param array $out + * + * @return bool + */ + protected function mediaExpression(&$out) + { + $s = $this->count; + $value = null; + + if ( + $this->matchChar('(') && + $this->expression($feature) && + ($this->matchChar(':') && + $this->expression($value) || true) && + $this->matchChar(')') + ) { + $out = [Type::T_MEDIA_EXPRESSION, $feature]; + + if ($value) { + $out[] = $value; + } + + return true; + } + + $this->seek($s); + + return false; + } + + /** + * Parse argument values + * + * @param array $out + * + * @return bool + */ + protected function argValues(&$out) + { + $discardComments = $this->discardComments; + $this->discardComments = true; + + if ($this->genericList($list, 'argValue', ',', false)) { + $out = $list[2]; + + $this->discardComments = $discardComments; + + return true; + } + + $this->discardComments = $discardComments; + + return false; + } + + /** + * Parse argument value + * + * @param array $out + * + * @return bool + */ + protected function argValue(&$out) + { + $s = $this->count; + + $keyword = null; + + if (! $this->variable($keyword) || ! $this->matchChar(':')) { + $this->seek($s); + + $keyword = null; + } + + if ($this->genericList($value, 'expression', '', true)) { + $out = [$keyword, $value, false]; + $s = $this->count; + + if ($this->literal('...', 3)) { + $out[2] = true; + } else { + $this->seek($s); + } + + return true; + } + + return false; + } + + /** + * Check if a generic directive is known to be able to allow almost any syntax or not + * @param mixed $directiveName + * @return bool + */ + protected function isKnownGenericDirective($directiveName) + { + if (\is_array($directiveName) && \is_string(reset($directiveName))) { + $directiveName = reset($directiveName); + } + if (! \is_string($directiveName)) { + return false; + } + if ( + \in_array($directiveName, [ + 'at-root', + 'media', + 'mixin', + 'include', + 'scssphp-import-once', + 'import', + 'extend', + 'function', + 'break', + 'continue', + 'return', + 'each', + 'while', + 'for', + 'if', + 'debug', + 'warn', + 'error', + 'content', + 'else', + 'charset', + 'supports', + // Todo + 'use', + 'forward', + ]) + ) { + return true; + } + return false; + } + + /** + * Parse directive value list that considers $vars as keyword + * + * @param array $out + * @param bool|string $endChar + * + * @return bool + */ + protected function directiveValue(&$out, $endChar = false) + { + $s = $this->count; + + if ($this->variable($out)) { + if ($endChar && $this->matchChar($endChar, false)) { + return true; + } + + if (! $endChar && $this->end()) { + return true; + } + } + + $this->seek($s); + + if (\is_string($endChar) && $this->openString($endChar ? $endChar : ';', $out, null, null, true, ";}{")) { + if ($endChar && $this->matchChar($endChar, false)) { + return true; + } + $ss = $this->count; + if (!$endChar && $this->end()) { + $this->seek($ss); + return true; + } + } + + $this->seek($s); + + $allowVars = $this->allowVars; + $this->allowVars = false; + + $res = $this->genericList($out, 'spaceList', ','); + $this->allowVars = $allowVars; + + if ($res) { + if ($endChar && $this->matchChar($endChar, false)) { + return true; + } + + if (! $endChar && $this->end()) { + return true; + } + } + + $this->seek($s); + + if ($endChar && $this->matchChar($endChar, false)) { + return true; + } + + return false; + } + + /** + * Parse comma separated value list + * + * @param array $out + * + * @return bool + */ + protected function valueList(&$out) + { + $discardComments = $this->discardComments; + $this->discardComments = true; + $res = $this->genericList($out, 'spaceList', ','); + $this->discardComments = $discardComments; + + return $res; + } + + /** + * Parse a function call, where externals () are part of the call + * and not of the value list + * + * @param array $out + * @param bool $mandatoryEnclos + * @param null|string $charAfter + * @param null|bool $eatWhiteSp + * + * @return bool + */ + protected function functionCallArgumentsList(&$out, $mandatoryEnclos = true, $charAfter = null, $eatWhiteSp = null) + { + $s = $this->count; + + if ( + $this->matchChar('(') && + $this->valueList($out) && + $this->matchChar(')') && + ($charAfter ? $this->matchChar($charAfter, $eatWhiteSp) : $this->end()) + ) { + return true; + } + + if (! $mandatoryEnclos) { + $this->seek($s); + + if ( + $this->valueList($out) && + ($charAfter ? $this->matchChar($charAfter, $eatWhiteSp) : $this->end()) + ) { + return true; + } + } + + $this->seek($s); + + return false; + } + + /** + * Parse space separated value list + * + * @param array $out + * + * @return bool + */ + protected function spaceList(&$out) + { + return $this->genericList($out, 'expression'); + } + + /** + * Parse generic list + * + * @param array $out + * @param string $parseItem The name of the method used to parse items + * @param string $delim + * @param bool $flatten + * + * @return bool + */ + protected function genericList(&$out, $parseItem, $delim = '', $flatten = true) + { + $s = $this->count; + $items = []; + $value = null; + + while ($this->$parseItem($value)) { + $trailing_delim = false; + $items[] = $value; + + if ($delim) { + if (! $this->literal($delim, \strlen($delim))) { + break; + } + + $trailing_delim = true; + } else { + // if no delim watch that a keyword didn't eat the single/double quote + // from the following starting string + if ($value[0] === Type::T_KEYWORD) { + $word = $value[1]; + + $last_char = substr($word, -1); + + if ( + strlen($word) > 1 && + in_array($last_char, [ "'", '"']) && + substr($word, -2, 1) !== '\\' + ) { + // if there is a non escaped opening quote in the keyword, this seems unlikely a mistake + $word = str_replace('\\' . $last_char, '\\\\', $word); + if (strpos($word, $last_char) < strlen($word) - 1) { + continue; + } + + $currentCount = $this->count; + + // let's try to rewind to previous char and try a parse + $this->count--; + // in case the keyword also eat spaces + while (substr($this->buffer, $this->count, 1) !== $last_char) { + $this->count--; + } + + $nextValue = null; + if ($this->$parseItem($nextValue)) { + if ($nextValue[0] === Type::T_KEYWORD && $nextValue[1] === $last_char) { + // bad try, forget it + $this->seek($currentCount); + continue; + } + if ($nextValue[0] !== Type::T_STRING) { + // bad try, forget it + $this->seek($currentCount); + continue; + } + + // OK it was a good idea + $value[1] = substr($value[1], 0, -1); + array_pop($items); + $items[] = $value; + $items[] = $nextValue; + } else { + // bad try, forget it + $this->seek($currentCount); + continue; + } + } + } + } + } + + if (! $items) { + $this->seek($s); + + return false; + } + + if ($trailing_delim) { + $items[] = [Type::T_NULL]; + } + + if ($flatten && \count($items) === 1) { + $out = $items[0]; + } else { + $out = [Type::T_LIST, $delim, $items]; + } + + return true; + } + + /** + * Parse expression + * + * @param array $out + * @param bool $listOnly + * @param bool $lookForExp + * + * @return bool + */ + protected function expression(&$out, $listOnly = false, $lookForExp = true) + { + $s = $this->count; + $discard = $this->discardComments; + $this->discardComments = true; + $allowedTypes = ($listOnly ? [Type::T_LIST] : [Type::T_LIST, Type::T_MAP]); + + if ($this->matchChar('(')) { + if ($this->enclosedExpression($lhs, $s, ')', $allowedTypes)) { + if ($lookForExp) { + $out = $this->expHelper($lhs, 0); + } else { + $out = $lhs; + } + + $this->discardComments = $discard; + + return true; + } + + $this->seek($s); + } + + if (\in_array(Type::T_LIST, $allowedTypes) && $this->matchChar('[')) { + if ($this->enclosedExpression($lhs, $s, ']', [Type::T_LIST])) { + if ($lookForExp) { + $out = $this->expHelper($lhs, 0); + } else { + $out = $lhs; + } + + $this->discardComments = $discard; + + return true; + } + + $this->seek($s); + } + + if (! $listOnly && $this->value($lhs)) { + if ($lookForExp) { + $out = $this->expHelper($lhs, 0); + } else { + $out = $lhs; + } + + $this->discardComments = $discard; + + return true; + } + + $this->discardComments = $discard; + + return false; + } + + /** + * Parse expression specifically checking for lists in parenthesis or brackets + * + * @param array $out + * @param int $s + * @param string $closingParen + * @param array $allowedTypes + * + * @return bool + */ + protected function enclosedExpression(&$out, $s, $closingParen = ')', $allowedTypes = [Type::T_LIST, Type::T_MAP]) + { + if ($this->matchChar($closingParen) && \in_array(Type::T_LIST, $allowedTypes)) { + $out = [Type::T_LIST, '', []]; + + switch ($closingParen) { + case ')': + $out['enclosing'] = 'parent'; // parenthesis list + break; + + case ']': + $out['enclosing'] = 'bracket'; // bracketed list + break; + } + + return true; + } + + if ( + $this->valueList($out) && + $this->matchChar($closingParen) && ! ($closingParen === ')' && + \in_array($out[0], [Type::T_EXPRESSION, Type::T_UNARY])) && + \in_array(Type::T_LIST, $allowedTypes) + ) { + if ($out[0] !== Type::T_LIST || ! empty($out['enclosing'])) { + $out = [Type::T_LIST, '', [$out]]; + } + + switch ($closingParen) { + case ')': + $out['enclosing'] = 'parent'; // parenthesis list + break; + + case ']': + $out['enclosing'] = 'bracket'; // bracketed list + break; + } + + return true; + } + + $this->seek($s); + + if (\in_array(Type::T_MAP, $allowedTypes) && $this->map($out)) { + return true; + } + + return false; + } + + /** + * Parse left-hand side of subexpression + * + * @param array $lhs + * @param int $minP + * + * @return array + */ + protected function expHelper($lhs, $minP) + { + $operators = static::$operatorPattern; + + $ss = $this->count; + $whiteBefore = isset($this->buffer[$this->count - 1]) && + ctype_space($this->buffer[$this->count - 1]); + + while ($this->match($operators, $m, false) && static::$precedence[$m[1]] >= $minP) { + $whiteAfter = isset($this->buffer[$this->count]) && + ctype_space($this->buffer[$this->count]); + $varAfter = isset($this->buffer[$this->count]) && + $this->buffer[$this->count] === '$'; + + $this->whitespace(); + + $op = $m[1]; + + // don't turn negative numbers into expressions + if ($op === '-' && $whiteBefore && ! $whiteAfter && ! $varAfter) { + break; + } + + if (! $this->value($rhs) && ! $this->expression($rhs, true, false)) { + break; + } + + if ($op === '-' && ! $whiteAfter && $rhs[0] === Type::T_KEYWORD) { + break; + } + + // consume higher-precedence operators on the right-hand side + $rhs = $this->expHelper($rhs, static::$precedence[$op] + 1); + + $lhs = [Type::T_EXPRESSION, $op, $lhs, $rhs, $this->inParens, $whiteBefore, $whiteAfter]; + + $ss = $this->count; + $whiteBefore = isset($this->buffer[$this->count - 1]) && + ctype_space($this->buffer[$this->count - 1]); + } + + $this->seek($ss); + + return $lhs; + } + + /** + * Parse value + * + * @param array $out + * + * @return bool + */ + protected function value(&$out) + { + if (! isset($this->buffer[$this->count])) { + return false; + } + + $s = $this->count; + $char = $this->buffer[$this->count]; + + if ( + $this->literal('url(', 4) && + $this->match('data:([a-z]+)\/([a-z0-9.+-]+);base64,', $m, false) + ) { + $len = strspn( + $this->buffer, + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwyxz0123456789+/=', + $this->count + ); + + $this->count += $len; + + if ($this->matchChar(')')) { + $content = substr($this->buffer, $s, $this->count - $s); + $out = [Type::T_KEYWORD, $content]; + + return true; + } + } + + $this->seek($s); + + if ( + $this->literal('url(', 4, false) && + $this->match('\s*(\/\/[^\s\)]+)\s*', $m) + ) { + $content = 'url(' . $m[1]; + + if ($this->matchChar(')')) { + $content .= ')'; + $out = [Type::T_KEYWORD, $content]; + + return true; + } + } + + $this->seek($s); + + // not + if ($char === 'n' && $this->literal('not', 3, false)) { + if ( + $this->whitespace() && + $this->value($inner) + ) { + $out = [Type::T_UNARY, 'not', $inner, $this->inParens]; + + return true; + } + + $this->seek($s); + + if ($this->parenValue($inner)) { + $out = [Type::T_UNARY, 'not', $inner, $this->inParens]; + + return true; + } + + $this->seek($s); + } + + // addition + if ($char === '+') { + $this->count++; + + $follow_white = $this->whitespace(); + + if ($this->value($inner)) { + $out = [Type::T_UNARY, '+', $inner, $this->inParens]; + + return true; + } + + if ($follow_white) { + $out = [Type::T_KEYWORD, $char]; + return true; + } + + $this->seek($s); + + return false; + } + + // negation + if ($char === '-') { + if ($this->customProperty($out)) { + return true; + } + + $this->count++; + + $follow_white = $this->whitespace(); + + if ($this->variable($inner) || $this->unit($inner) || $this->parenValue($inner)) { + $out = [Type::T_UNARY, '-', $inner, $this->inParens]; + + return true; + } + + if ( + $this->keyword($inner) && + ! $this->func($inner, $out) + ) { + $out = [Type::T_UNARY, '-', $inner, $this->inParens]; + + return true; + } + + if ($follow_white) { + $out = [Type::T_KEYWORD, $char]; + + return true; + } + + $this->seek($s); + } + + // paren + if ($char === '(' && $this->parenValue($out)) { + return true; + } + + if ($char === '#') { + if ($this->interpolation($out) || $this->color($out)) { + return true; + } + + $this->count++; + + if ($this->keyword($keyword)) { + $out = [Type::T_KEYWORD, '#' . $keyword]; + + return true; + } + + $this->count--; + } + + if ($this->matchChar('&', true)) { + $out = [Type::T_SELF]; + + return true; + } + + if ($char === '$' && $this->variable($out)) { + return true; + } + + if ($char === 'p' && $this->progid($out)) { + return true; + } + + if (($char === '"' || $char === "'") && $this->string($out)) { + return true; + } + + if ($this->unit($out)) { + return true; + } + + // unicode range with wildcards + if ( + $this->literal('U+', 2) && + $this->match('\?+|([0-9A-F]+(\?+|(-[0-9A-F]+))?)', $m, false) + ) { + $unicode = explode('-', $m[0]); + if (strlen(reset($unicode)) <= 6 && strlen(end($unicode)) <= 6) { + $out = [Type::T_KEYWORD, 'U+' . $m[0]]; + + return true; + } + $this->count -= strlen($m[0]) + 2; + } + + if ($this->keyword($keyword, false)) { + if ($this->func($keyword, $out)) { + return true; + } + + $this->whitespace(); + + if ($keyword === 'null') { + $out = [Type::T_NULL]; + } else { + $out = [Type::T_KEYWORD, $keyword]; + } + + return true; + } + + return false; + } + + /** + * Parse parenthesized value + * + * @param array $out + * + * @return bool + */ + protected function parenValue(&$out) + { + $s = $this->count; + + $inParens = $this->inParens; + + if ($this->matchChar('(')) { + if ($this->matchChar(')')) { + $out = [Type::T_LIST, '', []]; + + return true; + } + + $this->inParens = true; + + if ( + $this->expression($exp) && + $this->matchChar(')') + ) { + $out = $exp; + $this->inParens = $inParens; + + return true; + } + } + + $this->inParens = $inParens; + $this->seek($s); + + return false; + } + + /** + * Parse "progid:" + * + * @param array $out + * + * @return bool + */ + protected function progid(&$out) + { + $s = $this->count; + + if ( + $this->literal('progid:', 7, false) && + $this->openString('(', $fn) && + $this->matchChar('(') + ) { + $this->openString(')', $args, '('); + + if ($this->matchChar(')')) { + $out = [Type::T_STRING, '', [ + 'progid:', $fn, '(', $args, ')' + ]]; + + return true; + } + } + + $this->seek($s); + + return false; + } + + /** + * Parse function call + * + * @param string $name + * @param array $func + * + * @return bool + */ + protected function func($name, &$func) + { + $s = $this->count; + + if ($this->matchChar('(')) { + if ($name === 'alpha' && $this->argumentList($args)) { + $func = [Type::T_FUNCTION, $name, [Type::T_STRING, '', $args]]; + + return true; + } + + if ($name !== 'expression' && ! preg_match('/^(-[a-z]+-)?calc$/', $name)) { + $ss = $this->count; + + if ( + $this->argValues($args) && + $this->matchChar(')') + ) { + $func = [Type::T_FUNCTION_CALL, $name, $args]; + + return true; + } + + $this->seek($ss); + } + + if ( + ($this->openString(')', $str, '(') || true) && + $this->matchChar(')') + ) { + $args = []; + + if (! empty($str)) { + $args[] = [null, [Type::T_STRING, '', [$str]]]; + } + + $func = [Type::T_FUNCTION_CALL, $name, $args]; + + return true; + } + } + + $this->seek($s); + + return false; + } + + /** + * Parse function call argument list + * + * @param array $out + * + * @return bool + */ + protected function argumentList(&$out) + { + $s = $this->count; + $this->matchChar('('); + + $args = []; + + while ($this->keyword($var)) { + if ( + $this->matchChar('=') && + $this->expression($exp) + ) { + $args[] = [Type::T_STRING, '', [$var . '=']]; + $arg = $exp; + } else { + break; + } + + $args[] = $arg; + + if (! $this->matchChar(',')) { + break; + } + + $args[] = [Type::T_STRING, '', [', ']]; + } + + if (! $this->matchChar(')') || ! $args) { + $this->seek($s); + + return false; + } + + $out = $args; + + return true; + } + + /** + * Parse mixin/function definition argument list + * + * @param array $out + * + * @return bool + */ + protected function argumentDef(&$out) + { + $s = $this->count; + $this->matchChar('('); + + $args = []; + + while ($this->variable($var)) { + $arg = [$var[1], null, false]; + + $ss = $this->count; + + if ( + $this->matchChar(':') && + $this->genericList($defaultVal, 'expression', '', true) + ) { + $arg[1] = $defaultVal; + } else { + $this->seek($ss); + } + + $ss = $this->count; + + if ($this->literal('...', 3)) { + $sss = $this->count; + + if (! $this->matchChar(')')) { + throw $this->parseError('... has to be after the final argument'); + } + + $arg[2] = true; + + $this->seek($sss); + } else { + $this->seek($ss); + } + + $args[] = $arg; + + if (! $this->matchChar(',')) { + break; + } + } + + if (! $this->matchChar(')')) { + $this->seek($s); + + return false; + } + + $out = $args; + + return true; + } + + /** + * Parse map + * + * @param array $out + * + * @return bool + */ + protected function map(&$out) + { + $s = $this->count; + + if (! $this->matchChar('(')) { + return false; + } + + $keys = []; + $values = []; + + while ( + $this->genericList($key, 'expression', '', true) && + $this->matchChar(':') && + $this->genericList($value, 'expression', '', true) + ) { + $keys[] = $key; + $values[] = $value; + + if (! $this->matchChar(',')) { + break; + } + } + + if (! $keys || ! $this->matchChar(')')) { + $this->seek($s); + + return false; + } + + $out = [Type::T_MAP, $keys, $values]; + + return true; + } + + /** + * Parse color + * + * @param array $out + * + * @return bool + */ + protected function color(&$out) + { + $s = $this->count; + + if ($this->match('(#([0-9a-f]+)\b)', $m)) { + if (\in_array(\strlen($m[2]), [3,4,6,8])) { + $out = [Type::T_KEYWORD, $m[0]]; + + return true; + } + + $this->seek($s); + + return false; + } + + return false; + } + + /** + * Parse number with unit + * + * @param array $unit + * + * @return bool + */ + protected function unit(&$unit) + { + $s = $this->count; + + if ($this->match('([0-9]*(\.)?[0-9]+)([%a-zA-Z]+)?', $m, false)) { + if (\strlen($this->buffer) === $this->count || ! ctype_digit($this->buffer[$this->count])) { + $this->whitespace(); + + $unit = new Node\Number($m[1], empty($m[3]) ? '' : $m[3]); + + return true; + } + + $this->seek($s); + } + + return false; + } + + /** + * Parse string + * + * @param array $out + * @param bool $keepDelimWithInterpolation + * + * @return bool + */ + protected function string(&$out, $keepDelimWithInterpolation = false) + { + $s = $this->count; + + if ($this->matchChar('"', false)) { + $delim = '"'; + } elseif ($this->matchChar("'", false)) { + $delim = "'"; + } else { + return false; + } + + $content = []; + $oldWhite = $this->eatWhiteDefault; + $this->eatWhiteDefault = false; + $hasInterpolation = false; + + while ($this->matchString($m, $delim)) { + if ($m[1] !== '') { + $content[] = $m[1]; + } + + if ($m[2] === '#{') { + $this->count -= \strlen($m[2]); + + if ($this->interpolation($inter, false)) { + $content[] = $inter; + $hasInterpolation = true; + } else { + $this->count += \strlen($m[2]); + $content[] = '#{'; // ignore it + } + } elseif ($m[2] === "\r") { + $content[] = chr(10); + // TODO : warning + # DEPRECATION WARNING on line x, column y of zzz: + # Unescaped multiline strings are deprecated and will be removed in a future version of Sass. + # To include a newline in a string, use "\a" or "\a " as in CSS. + if ($this->matchChar("\n", false)) { + $content[] = ' '; + } + } elseif ($m[2] === '\\') { + if ( + $this->literal("\r\n", 2, false) || + $this->matchChar("\r", false) || + $this->matchChar("\n", false) || + $this->matchChar("\f", false) + ) { + // this is a continuation escaping, to be ignored + } elseif ($this->matchEscapeCharacter($c)) { + $content[] = $c; + } else { + throw $this->parseError('Unterminated escape sequence'); + } + } else { + $this->count -= \strlen($delim); + break; // delim + } + } + + $this->eatWhiteDefault = $oldWhite; + + if ($this->literal($delim, \strlen($delim))) { + if ($hasInterpolation && ! $keepDelimWithInterpolation) { + $delim = '"'; + } + + $out = [Type::T_STRING, $delim, $content]; + + return true; + } + + $this->seek($s); + + return false; + } + + /** + * @param string $out + * @param bool $inKeywords + * + * @return bool + */ + protected function matchEscapeCharacter(&$out, $inKeywords = false) + { + $s = $this->count; + if ($this->match('[a-f0-9]', $m, false)) { + $hex = $m[0]; + + for ($i = 5; $i--;) { + if ($this->match('[a-f0-9]', $m, false)) { + $hex .= $m[0]; + } else { + break; + } + } + + // CSS allows Unicode escape sequences to be followed by a delimiter space + // (necessary in some cases for shorter sequences to disambiguate their end) + $this->matchChar(' ', false); + + $value = hexdec($hex); + + if (!$inKeywords && ($value == 0 || ($value >= 0xD800 && $value <= 0xDFFF) || $value >= 0x10FFFF)) { + $out = "\xEF\xBF\xBD"; // "\u{FFFD}" but with a syntax supported on PHP 5 + } elseif ($value < 0x20) { + $out = Util::mbChr($value); + } else { + $out = Util::mbChr($value); + } + + return true; + } + + if ($this->match('.', $m, false)) { + if ($inKeywords && in_array($m[0], ["'",'"','@','&',' ','\\',':','/','%'])) { + $this->seek($s); + return false; + } + $out = $m[0]; + + return true; + } + + return false; + } + + /** + * Parse keyword or interpolation + * + * @param array $out + * @param bool $restricted + * + * @return bool + */ + protected function mixedKeyword(&$out, $restricted = false) + { + $parts = []; + + $oldWhite = $this->eatWhiteDefault; + $this->eatWhiteDefault = false; + + for (;;) { + if ($restricted ? $this->restrictedKeyword($key) : $this->keyword($key)) { + $parts[] = $key; + continue; + } + + if ($this->interpolation($inter)) { + $parts[] = $inter; + continue; + } + + break; + } + + $this->eatWhiteDefault = $oldWhite; + + if (! $parts) { + return false; + } + + if ($this->eatWhiteDefault) { + $this->whitespace(); + } + + $out = $parts; + + return true; + } + + /** + * Parse an unbounded string stopped by $end + * + * @param string $end + * @param array $out + * @param string $nestOpen + * @param string $nestClose + * @param bool $rtrim + * @param string $disallow + * + * @return bool + */ + protected function openString($end, &$out, $nestOpen = null, $nestClose = null, $rtrim = true, $disallow = null) + { + $oldWhite = $this->eatWhiteDefault; + $this->eatWhiteDefault = false; + + if ($nestOpen && ! $nestClose) { + $nestClose = $end; + } + + $patt = ($disallow ? '[^' . $this->pregQuote($disallow) . ']' : '.'); + $patt = '(' . $patt . '*?)([\'"]|#\{|' + . $this->pregQuote($end) . '|' + . (($nestClose && $nestClose !== $end) ? $this->pregQuote($nestClose) . '|' : '') + . static::$commentPattern . ')'; + + $nestingLevel = 0; + + $content = []; + + while ($this->match($patt, $m, false)) { + if (isset($m[1]) && $m[1] !== '') { + $content[] = $m[1]; + + if ($nestOpen) { + $nestingLevel += substr_count($m[1], $nestOpen); + } + } + + $tok = $m[2]; + + $this->count -= \strlen($tok); + + if ($tok === $end && ! $nestingLevel) { + break; + } + + if ($tok === $nestClose) { + $nestingLevel--; + } + + if (($tok === "'" || $tok === '"') && $this->string($str, true)) { + $content[] = $str; + continue; + } + + if ($tok === '#{' && $this->interpolation($inter)) { + $content[] = $inter; + continue; + } + + $content[] = $tok; + $this->count += \strlen($tok); + } + + $this->eatWhiteDefault = $oldWhite; + + if (! $content || $tok !== $end) { + return false; + } + + // trim the end + if ($rtrim && \is_string(end($content))) { + $content[\count($content) - 1] = rtrim(end($content)); + } + + $out = [Type::T_STRING, '', $content]; + + return true; + } + + /** + * Parser interpolation + * + * @param string|array $out + * @param bool $lookWhite save information about whitespace before and after + * + * @return bool + */ + protected function interpolation(&$out, $lookWhite = true) + { + $oldWhite = $this->eatWhiteDefault; + $allowVars = $this->allowVars; + $this->allowVars = true; + $this->eatWhiteDefault = true; + + $s = $this->count; + + if ( + $this->literal('#{', 2) && + $this->valueList($value) && + $this->matchChar('}', false) + ) { + if ($value === [Type::T_SELF]) { + $out = $value; + } else { + if ($lookWhite) { + $left = ($s > 0 && preg_match('/\s/', $this->buffer[$s - 1])) ? ' ' : ''; + $right = ( + ! empty($this->buffer[$this->count]) && + preg_match('/\s/', $this->buffer[$this->count]) + ) ? ' ' : ''; + } else { + $left = $right = false; + } + + $out = [Type::T_INTERPOLATE, $value, $left, $right]; + } + + $this->eatWhiteDefault = $oldWhite; + $this->allowVars = $allowVars; + + if ($this->eatWhiteDefault) { + $this->whitespace(); + } + + return true; + } + + $this->seek($s); + + $this->eatWhiteDefault = $oldWhite; + $this->allowVars = $allowVars; + + return false; + } + + /** + * Parse property name (as an array of parts or a string) + * + * @param array $out + * + * @return bool + */ + protected function propertyName(&$out) + { + $parts = []; + + $oldWhite = $this->eatWhiteDefault; + $this->eatWhiteDefault = false; + + for (;;) { + if ($this->interpolation($inter)) { + $parts[] = $inter; + continue; + } + + if ($this->keyword($text)) { + $parts[] = $text; + continue; + } + + if (! $parts && $this->match('[:.#]', $m, false)) { + // css hacks + $parts[] = $m[0]; + continue; + } + + break; + } + + $this->eatWhiteDefault = $oldWhite; + + if (! $parts) { + return false; + } + + // match comment hack + if (preg_match(static::$whitePattern, $this->buffer, $m, 0, $this->count)) { + if (! empty($m[0])) { + $parts[] = $m[0]; + $this->count += \strlen($m[0]); + } + } + + $this->whitespace(); // get any extra whitespace + + $out = [Type::T_STRING, '', $parts]; + + return true; + } + + /** + * Parse custom property name (as an array of parts or a string) + * + * @param array $out + * + * @return bool + */ + protected function customProperty(&$out) + { + $s = $this->count; + + if (! $this->literal('--', 2, false)) { + return false; + } + + $parts = ['--']; + + $oldWhite = $this->eatWhiteDefault; + $this->eatWhiteDefault = false; + + for (;;) { + if ($this->interpolation($inter)) { + $parts[] = $inter; + continue; + } + + if ($this->matchChar('&', false)) { + $parts[] = [Type::T_SELF]; + continue; + } + + if ($this->variable($var)) { + $parts[] = $var; + continue; + } + + if ($this->keyword($text)) { + $parts[] = $text; + continue; + } + + break; + } + + $this->eatWhiteDefault = $oldWhite; + + if (\count($parts) == 1) { + $this->seek($s); + + return false; + } + + $this->whitespace(); // get any extra whitespace + + $out = [Type::T_STRING, '', $parts]; + + return true; + } + + /** + * Parse comma separated selector list + * + * @param array $out + * @param string|bool $subSelector + * + * @return bool + */ + protected function selectors(&$out, $subSelector = false) + { + $s = $this->count; + $selectors = []; + + while ($this->selector($sel, $subSelector)) { + $selectors[] = $sel; + + if (! $this->matchChar(',', true)) { + break; + } + + while ($this->matchChar(',', true)) { + ; // ignore extra + } + } + + if (! $selectors) { + $this->seek($s); + + return false; + } + + $out = $selectors; + + return true; + } + + /** + * Parse whitespace separated selector list + * + * @param array $out + * @param string|bool $subSelector + * + * @return bool + */ + protected function selector(&$out, $subSelector = false) + { + $selector = []; + + $discardComments = $this->discardComments; + $this->discardComments = true; + + for (;;) { + $s = $this->count; + + if ($this->match('[>+~]+', $m, true)) { + if ( + $subSelector && \is_string($subSelector) && strpos($subSelector, 'nth-') === 0 && + $m[0] === '+' && $this->match("(\d+|n\b)", $counter) + ) { + $this->seek($s); + } else { + $selector[] = [$m[0]]; + continue; + } + } + + if ($this->selectorSingle($part, $subSelector)) { + $selector[] = $part; + $this->whitespace(); + continue; + } + + break; + } + + $this->discardComments = $discardComments; + + if (! $selector) { + return false; + } + + $out = $selector; + + return true; + } + + /** + * parsing escaped chars in selectors: + * - escaped single chars are kept escaped in the selector but in a normalized form + * (if not in 0-9a-f range as this would be ambigous) + * - other escaped sequences (multibyte chars or 0-9a-f) are kept in their initial escaped form, + * normalized to lowercase + * + * TODO: this is a fallback solution. Ideally escaped chars in selectors should be encoded as the genuine chars, + * and escaping added when printing in the Compiler, where/if it's mandatory + * - but this require a better formal selector representation instead of the array we have now + * + * @param string $out + * @param bool $keepEscapedNumber + * + * @return bool + */ + protected function matchEscapeCharacterInSelector(&$out, $keepEscapedNumber = false) + { + $s_escape = $this->count; + if ($this->match('\\\\', $m)) { + $out = '\\' . $m[0]; + return true; + } + + if ($this->matchEscapeCharacter($escapedout, true)) { + if (strlen($escapedout) === 1) { + if (!preg_match(",\w,", $escapedout)) { + $out = '\\' . $escapedout; + return true; + } elseif (! $keepEscapedNumber || ! \is_numeric($escapedout)) { + $out = $escapedout; + return true; + } + } + $escape_sequence = rtrim(substr($this->buffer, $s_escape, $this->count - $s_escape)); + if (strlen($escape_sequence) < 6) { + $escape_sequence .= ' '; + } + $out = '\\' . strtolower($escape_sequence); + return true; + } + if ($this->match('\\S', $m)) { + $out = '\\' . $m[0]; + return true; + } + + + return false; + } + + /** + * Parse the parts that make up a selector + * + * {@internal + * div[yes=no]#something.hello.world:nth-child(-2n+1)%placeholder + * }} + * + * @param array $out + * @param string|bool $subSelector + * + * @return bool + */ + protected function selectorSingle(&$out, $subSelector = false) + { + $oldWhite = $this->eatWhiteDefault; + $this->eatWhiteDefault = false; + + $parts = []; + + if ($this->matchChar('*', false)) { + $parts[] = '*'; + } + + for (;;) { + if (! isset($this->buffer[$this->count])) { + break; + } + + $s = $this->count; + $char = $this->buffer[$this->count]; + + // see if we can stop early + if ($char === '{' || $char === ',' || $char === ';' || $char === '}' || $char === '@') { + break; + } + + // parsing a sub selector in () stop with the closing ) + if ($subSelector && $char === ')') { + break; + } + + //self + switch ($char) { + case '&': + $parts[] = Compiler::$selfSelector; + $this->count++; + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + continue 2; + + case '.': + $parts[] = '.'; + $this->count++; + continue 2; + + case '|': + $parts[] = '|'; + $this->count++; + continue 2; + } + + // handling of escaping in selectors : get the escaped char + if ($char === '\\') { + $this->count++; + if ($this->matchEscapeCharacterInSelector($escaped, true)) { + $parts[] = $escaped; + continue; + } + $this->count--; + } + + if ($char === '%') { + $this->count++; + + if ($this->placeholder($placeholder)) { + $parts[] = '%'; + $parts[] = $placeholder; + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + continue; + } + + break; + } + + if ($char === '#') { + if ($this->interpolation($inter)) { + $parts[] = $inter; + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + continue; + } + + $parts[] = '#'; + $this->count++; + continue; + } + + // a pseudo selector + if ($char === ':') { + if ($this->buffer[$this->count + 1] === ':') { + $this->count += 2; + $part = '::'; + } else { + $this->count++; + $part = ':'; + } + + if ($this->mixedKeyword($nameParts, true)) { + $parts[] = $part; + + foreach ($nameParts as $sub) { + $parts[] = $sub; + } + + $ss = $this->count; + + if ( + $nameParts === ['not'] || + $nameParts === ['is'] || + $nameParts === ['has'] || + $nameParts === ['where'] || + $nameParts === ['slotted'] || + $nameParts === ['nth-child'] || + $nameParts === ['nth-last-child'] || + $nameParts === ['nth-of-type'] || + $nameParts === ['nth-last-of-type'] + ) { + if ( + $this->matchChar('(', true) && + ($this->selectors($subs, reset($nameParts)) || true) && + $this->matchChar(')') + ) { + $parts[] = '('; + + while ($sub = array_shift($subs)) { + while ($ps = array_shift($sub)) { + foreach ($ps as &$p) { + $parts[] = $p; + } + + if (\count($sub) && reset($sub)) { + $parts[] = ' '; + } + } + + if (\count($subs) && reset($subs)) { + $parts[] = ', '; + } + } + + $parts[] = ')'; + } else { + $this->seek($ss); + } + } elseif ( + $this->matchChar('(', true) && + ($this->openString(')', $str, '(') || true) && + $this->matchChar(')') + ) { + $parts[] = '('; + + if (! empty($str)) { + $parts[] = $str; + } + + $parts[] = ')'; + } else { + $this->seek($ss); + } + + continue; + } + } + + $this->seek($s); + + // 2n+1 + if ($subSelector && \is_string($subSelector) && strpos($subSelector, 'nth-') === 0) { + if ($this->match("(\s*(\+\s*|\-\s*)?(\d+|n|\d+n))+", $counter)) { + $parts[] = $counter[0]; + //$parts[] = str_replace(' ', '', $counter[0]); + continue; + } + } + + $this->seek($s); + + // attribute selector + if ( + $char === '[' && + $this->matchChar('[') && + ($this->openString(']', $str, '[') || true) && + $this->matchChar(']') + ) { + $parts[] = '['; + + if (! empty($str)) { + $parts[] = $str; + } + + $parts[] = ']'; + continue; + } + + $this->seek($s); + + // for keyframes + if ($this->unit($unit)) { + $parts[] = $unit; + continue; + } + + if ($this->restrictedKeyword($name, false, true)) { + $parts[] = $name; + continue; + } + + break; + } + + $this->eatWhiteDefault = $oldWhite; + + if (! $parts) { + return false; + } + + $out = $parts; + + return true; + } + + /** + * Parse a variable + * + * @param array $out + * + * @return bool + */ + protected function variable(&$out) + { + $s = $this->count; + + if ( + $this->matchChar('$', false) && + $this->keyword($name) + ) { + if ($this->allowVars) { + $out = [Type::T_VARIABLE, $name]; + } else { + $out = [Type::T_KEYWORD, '$' . $name]; + } + + return true; + } + + $this->seek($s); + + return false; + } + + /** + * Parse a keyword + * + * @param string $word + * @param bool $eatWhitespace + * @param bool $inSelector + * + * @return bool + */ + protected function keyword(&$word, $eatWhitespace = null, $inSelector = false) + { + $s = $this->count; + $match = $this->match( + $this->utf8 + ? '(([\pL\w\x{00A0}-\x{10FFFF}_\-\*!"\']|\\\\[a-f0-9]{6} ?|\\\\[a-f0-9]{1,5}(?![a-f0-9]) ?|[\\\\].)([\pL\w\x{00A0}-\x{10FFFF}\-_"\']|\\\\[a-f0-9]{6} ?|\\\\[a-f0-9]{1,5}(?![a-f0-9]) ?|[\\\\].)*)' + : '(([\w_\-\*!"\']|\\\\[a-f0-9]{6} ?|\\\\[a-f0-9]{1,5}(?![a-f0-9]) ?|[\\\\].)([\w\-_"\']|\\\\[a-f0-9]{6} ?|\\\\[a-f0-9]{1,5}(?![a-f0-9]) ?|[\\\\].)*)', + $m, + false + ); + + if ($match) { + $word = $m[1]; + + // handling of escaping in keyword : get the escaped char + if (strpos($word, '\\') !== false) { + $send = $this->count; + $escapedWord = []; + $this->seek($s); + $previousEscape = false; + while ($this->count < $send) { + $char = $this->buffer[$this->count]; + $this->count++; + if ( + $this->count < $send + && $char === '\\' + && !$previousEscape + && ( + $inSelector ? + $this->matchEscapeCharacterInSelector($out) + : + $this->matchEscapeCharacter($out, true) + ) + ) { + $escapedWord[] = $out; + } else { + if ($previousEscape) { + $previousEscape = false; + } elseif ($char === '\\') { + $previousEscape = true; + } + $escapedWord[] = $char; + } + } + + $word = implode('', $escapedWord); + } + + if (is_null($eatWhitespace) ? $this->eatWhiteDefault : $eatWhitespace) { + $this->whitespace(); + } + + return true; + } + + return false; + } + + /** + * Parse a keyword that should not start with a number + * + * @param string $word + * @param bool $eatWhitespace + * @param bool $inSelector + * + * @return bool + */ + protected function restrictedKeyword(&$word, $eatWhitespace = null, $inSelector = false) + { + $s = $this->count; + + if ($this->keyword($word, $eatWhitespace, $inSelector) && (\ord($word[0]) > 57 || \ord($word[0]) < 48)) { + return true; + } + + $this->seek($s); + + return false; + } + + /** + * Parse a placeholder + * + * @param string|array $placeholder + * + * @return bool + */ + protected function placeholder(&$placeholder) + { + $match = $this->match( + $this->utf8 + ? '([\pL\w\-_]+)' + : '([\w\-_]+)', + $m + ); + + if ($match) { + $placeholder = $m[1]; + + return true; + } + + if ($this->interpolation($placeholder)) { + return true; + } + + return false; + } + + /** + * Parse a url + * + * @param array $out + * + * @return bool + */ + protected function url(&$out) + { + if ($this->literal('url(', 4)) { + $s = $this->count; + + if ( + ($this->string($out) || $this->spaceList($out)) && + $this->matchChar(')') + ) { + $out = [Type::T_STRING, '', ['url(', $out, ')']]; + + return true; + } + + $this->seek($s); + + if ( + $this->openString(')', $out) && + $this->matchChar(')') + ) { + $out = [Type::T_STRING, '', ['url(', $out, ')']]; + + return true; + } + } + + return false; + } + + /** + * Consume an end of statement delimiter + * @param bool $eatWhitespace + * + * @return bool + */ + protected function end($eatWhitespace = null) + { + if ($this->matchChar(';', $eatWhitespace)) { + return true; + } + + if ($this->count === \strlen($this->buffer) || $this->buffer[$this->count] === '}') { + // if there is end of file or a closing block next then we don't need a ; + return true; + } + + return false; + } + + /** + * Strip assignment flag from the list + * + * @param array $value + * + * @return array + */ + protected function stripAssignmentFlags(&$value) + { + $flags = []; + + for ($token = &$value; $token[0] === Type::T_LIST && ($s = \count($token[2])); $token = &$lastNode) { + $lastNode = &$token[2][$s - 1]; + + while ($lastNode[0] === Type::T_KEYWORD && \in_array($lastNode[1], ['!default', '!global'])) { + array_pop($token[2]); + + $node = end($token[2]); + $token = $this->flattenList($token); + $flags[] = $lastNode[1]; + $lastNode = $node; + } + } + + return $flags; + } + + /** + * Strip optional flag from selector list + * + * @param array $selectors + * + * @return string + */ + protected function stripOptionalFlag(&$selectors) + { + $optional = false; + $selector = end($selectors); + $part = end($selector); + + if ($part === ['!optional']) { + array_pop($selectors[\count($selectors) - 1]); + + $optional = true; + } + + return $optional; + } + + /** + * Turn list of length 1 into value type + * + * @param array $value + * + * @return array + */ + protected function flattenList($value) + { + if ($value[0] === Type::T_LIST && \count($value[2]) === 1) { + return $this->flattenList($value[2][0]); + } + + return $value; + } + + /** + * Quote regular expression + * + * @param string $what + * + * @return string + */ + private function pregQuote($what) + { + return preg_quote($what, '/'); + } + + /** + * Extract line numbers from buffer + * + * @param string $buffer + */ + private function extractLineNumbers($buffer) + { + $this->sourcePositions = [0 => 0]; + $prev = 0; + + while (($pos = strpos($buffer, "\n", $prev)) !== false) { + $this->sourcePositions[] = $pos; + $prev = $pos + 1; + } + + $this->sourcePositions[] = \strlen($buffer); + + if (substr($buffer, -1) !== "\n") { + $this->sourcePositions[] = \strlen($buffer) + 1; + } + } + + /** + * Get source line number and column (given character position in the buffer) + * + * @param int $pos + * + * @return array + */ + private function getSourcePosition($pos) + { + $low = 0; + $high = \count($this->sourcePositions); + + while ($low < $high) { + $mid = (int) (($high + $low) / 2); + + if ($pos < $this->sourcePositions[$mid]) { + $high = $mid - 1; + continue; + } + + if ($pos >= $this->sourcePositions[$mid + 1]) { + $low = $mid + 1; + continue; + } + + return [$mid + 1, $pos - $this->sourcePositions[$mid]]; + } + + return [$low + 1, $pos - $this->sourcePositions[$low]]; + } + + /** + * Save internal encoding of mbstring + * + * When mbstring.func_overload is used to replace the standard PHP string functions, + * this method configures the internal encoding to a single-byte one so that the + * behavior matches the normal behavior of PHP string functions while using the parser. + * The existing internal encoding is saved and will be restored when calling {@see restoreEncoding}. + * + * If mbstring.func_overload is not used (or does not override string functions), this method is a no-op. + * + * @return void + */ + private function saveEncoding() + { + if (\PHP_VERSION_ID < 80000 && \extension_loaded('mbstring') && (2 & (int) ini_get('mbstring.func_overload')) > 0) { + $this->encoding = mb_internal_encoding(); + + mb_internal_encoding('iso-8859-1'); + } + } + + /** + * Restore internal encoding + * + * @return void + */ + private function restoreEncoding() + { + if (\extension_loaded('mbstring') && $this->encoding) { + mb_internal_encoding($this->encoding); + } + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/SourceMap/Base64.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/SourceMap/Base64.php new file mode 100644 index 00000000..00b6b454 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/SourceMap/Base64.php @@ -0,0 +1,187 @@ + + * + * @internal + */ +class Base64 +{ + /** + * @var array + */ + private static $encodingMap = [ + 0 => 'A', + 1 => 'B', + 2 => 'C', + 3 => 'D', + 4 => 'E', + 5 => 'F', + 6 => 'G', + 7 => 'H', + 8 => 'I', + 9 => 'J', + 10 => 'K', + 11 => 'L', + 12 => 'M', + 13 => 'N', + 14 => 'O', + 15 => 'P', + 16 => 'Q', + 17 => 'R', + 18 => 'S', + 19 => 'T', + 20 => 'U', + 21 => 'V', + 22 => 'W', + 23 => 'X', + 24 => 'Y', + 25 => 'Z', + 26 => 'a', + 27 => 'b', + 28 => 'c', + 29 => 'd', + 30 => 'e', + 31 => 'f', + 32 => 'g', + 33 => 'h', + 34 => 'i', + 35 => 'j', + 36 => 'k', + 37 => 'l', + 38 => 'm', + 39 => 'n', + 40 => 'o', + 41 => 'p', + 42 => 'q', + 43 => 'r', + 44 => 's', + 45 => 't', + 46 => 'u', + 47 => 'v', + 48 => 'w', + 49 => 'x', + 50 => 'y', + 51 => 'z', + 52 => '0', + 53 => '1', + 54 => '2', + 55 => '3', + 56 => '4', + 57 => '5', + 58 => '6', + 59 => '7', + 60 => '8', + 61 => '9', + 62 => '+', + 63 => '/', + ]; + + /** + * @var array + */ + private static $decodingMap = [ + 'A' => 0, + 'B' => 1, + 'C' => 2, + 'D' => 3, + 'E' => 4, + 'F' => 5, + 'G' => 6, + 'H' => 7, + 'I' => 8, + 'J' => 9, + 'K' => 10, + 'L' => 11, + 'M' => 12, + 'N' => 13, + 'O' => 14, + 'P' => 15, + 'Q' => 16, + 'R' => 17, + 'S' => 18, + 'T' => 19, + 'U' => 20, + 'V' => 21, + 'W' => 22, + 'X' => 23, + 'Y' => 24, + 'Z' => 25, + 'a' => 26, + 'b' => 27, + 'c' => 28, + 'd' => 29, + 'e' => 30, + 'f' => 31, + 'g' => 32, + 'h' => 33, + 'i' => 34, + 'j' => 35, + 'k' => 36, + 'l' => 37, + 'm' => 38, + 'n' => 39, + 'o' => 40, + 'p' => 41, + 'q' => 42, + 'r' => 43, + 's' => 44, + 't' => 45, + 'u' => 46, + 'v' => 47, + 'w' => 48, + 'x' => 49, + 'y' => 50, + 'z' => 51, + 0 => 52, + 1 => 53, + 2 => 54, + 3 => 55, + 4 => 56, + 5 => 57, + 6 => 58, + 7 => 59, + 8 => 60, + 9 => 61, + '+' => 62, + '/' => 63, + ]; + + /** + * Convert to base64 + * + * @param int $value + * + * @return string + */ + public static function encode($value) + { + return self::$encodingMap[$value]; + } + + /** + * Convert from base64 + * + * @param string $value + * + * @return int + */ + public static function decode($value) + { + return self::$decodingMap[$value]; + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/SourceMap/Base64VLQ.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/SourceMap/Base64VLQ.php new file mode 100644 index 00000000..2a5210c6 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/SourceMap/Base64VLQ.php @@ -0,0 +1,151 @@ + + * @author Anthon Pang + * + * @internal + */ +class Base64VLQ +{ + // A Base64 VLQ digit can represent 5 bits, so it is base-32. + const VLQ_BASE_SHIFT = 5; + + // A mask of bits for a VLQ digit (11111), 31 decimal. + const VLQ_BASE_MASK = 31; + + // The continuation bit is the 6th bit. + const VLQ_CONTINUATION_BIT = 32; + + /** + * Returns the VLQ encoded value. + * + * @param int $value + * + * @return string + */ + public static function encode($value) + { + $encoded = ''; + $vlq = self::toVLQSigned($value); + + do { + $digit = $vlq & self::VLQ_BASE_MASK; + + //$vlq >>>= self::VLQ_BASE_SHIFT; // unsigned right shift + $vlq = (($vlq >> 1) & PHP_INT_MAX) >> (self::VLQ_BASE_SHIFT - 1); + + if ($vlq > 0) { + $digit |= self::VLQ_CONTINUATION_BIT; + } + + $encoded .= Base64::encode($digit); + } while ($vlq > 0); + + return $encoded; + } + + /** + * Decodes VLQValue. + * + * @param string $str + * @param int $index + * + * @return int + */ + public static function decode($str, &$index) + { + $result = 0; + $shift = 0; + + do { + $c = $str[$index++]; + $digit = Base64::decode($c); + $continuation = ($digit & self::VLQ_CONTINUATION_BIT) != 0; + $digit &= self::VLQ_BASE_MASK; + $result = $result + ($digit << $shift); + $shift = $shift + self::VLQ_BASE_SHIFT; + } while ($continuation); + + return self::fromVLQSigned($result); + } + + /** + * Converts from a two-complement value to a value where the sign bit is + * is placed in the least significant bit. For example, as decimals: + * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) + * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) + * + * @param int $value + * + * @return int + */ + private static function toVLQSigned($value) + { + if ($value < 0) { + return ((-$value) << 1) + 1; + } + + return ($value << 1) + 0; + } + + /** + * Converts to a two-complement value from a value where the sign bit is + * is placed in the least significant bit. For example, as decimals: + * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 + * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 + * + * @param int $value + * + * @return int + */ + private static function fromVLQSigned($value) + { + $negate = ($value & 1) === 1; + + //$value >>>= 1; // unsigned right shift + $value = ($value >> 1) & PHP_INT_MAX; + + if (! $negate) { + return $value; + } + + // We need to OR 0x80000000 here to ensure the 32nd bit (the sign bit) is + // always set for negative numbers. If `value` were 1, (meaning `negate` is + // true and all other bits were zeros), `value` would now be 0. -0 is just + // 0, and doesn't flip the 32nd bit as intended. All positive numbers will + // successfully flip the 32nd bit without issue, so it's a noop for them. + return -$value | 0x80000000; + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/SourceMap/SourceMapGenerator.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/SourceMap/SourceMapGenerator.php new file mode 100644 index 00000000..65dc24da --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/SourceMap/SourceMapGenerator.php @@ -0,0 +1,381 @@ + + * @author Nicolas FRANÇOIS + * + * @internal + */ +class SourceMapGenerator +{ + /** + * What version of source map does the generator generate? + */ + const VERSION = 3; + + /** + * Array of default options + * + * @var array + * @phpstan-var array{sourceRoot: string, sourceMapFilename: string|null, sourceMapURL: string|null, sourceMapWriteTo: string|null, outputSourceFiles: bool, sourceMapRootpath: string, sourceMapBasepath: string} + */ + protected $defaultOptions = [ + // an optional source root, useful for relocating source files + // on a server or removing repeated values in the 'sources' entry. + // This value is prepended to the individual entries in the 'source' field. + 'sourceRoot' => '', + + // an optional name of the generated code that this source map is associated with. + 'sourceMapFilename' => null, + + // url of the map + 'sourceMapURL' => null, + + // absolute path to a file to write the map to + 'sourceMapWriteTo' => null, + + // output source contents? + 'outputSourceFiles' => false, + + // base path for filename normalization + 'sourceMapRootpath' => '', + + // base path for filename normalization + 'sourceMapBasepath' => '' + ]; + + /** + * The base64 VLQ encoder + * + * @var \ScssPhp\ScssPhp\SourceMap\Base64VLQ + */ + protected $encoder; + + /** + * Array of mappings + * + * @var array + * @phpstan-var list + */ + protected $mappings = []; + + /** + * Array of contents map + * + * @var array + */ + protected $contentsMap = []; + + /** + * File to content map + * + * @var array + */ + protected $sources = []; + + /** + * @var array + */ + protected $sourceKeys = []; + + /** + * @var array + * @phpstan-var array{sourceRoot: string, sourceMapFilename: string|null, sourceMapURL: string|null, sourceMapWriteTo: string|null, outputSourceFiles: bool, sourceMapRootpath: string, sourceMapBasepath: string} + */ + private $options; + + /** + * @phpstan-param array{sourceRoot?: string, sourceMapFilename?: string|null, sourceMapURL?: string|null, sourceMapWriteTo?: string|null, outputSourceFiles?: bool, sourceMapRootpath?: string, sourceMapBasepath?: string} $options + */ + public function __construct(array $options = []) + { + $this->options = array_merge($this->defaultOptions, $options); + $this->encoder = new Base64VLQ(); + } + + /** + * Adds a mapping + * + * @param int $generatedLine The line number in generated file + * @param int $generatedColumn The column number in generated file + * @param int $originalLine The line number in original file + * @param int $originalColumn The column number in original file + * @param string $sourceFile The original source file + * + * @return void + */ + public function addMapping($generatedLine, $generatedColumn, $originalLine, $originalColumn, $sourceFile) + { + $this->mappings[] = [ + 'generated_line' => $generatedLine, + 'generated_column' => $generatedColumn, + 'original_line' => $originalLine, + 'original_column' => $originalColumn, + 'source_file' => $sourceFile + ]; + + $this->sources[$sourceFile] = $sourceFile; + } + + /** + * Saves the source map to a file + * + * @param string $content The content to write + * + * @return string + * + * @throws \ScssPhp\ScssPhp\Exception\CompilerException If the file could not be saved + * @deprecated + */ + public function saveMap($content) + { + $file = $this->options['sourceMapWriteTo']; + $dir = \dirname($file); + + // directory does not exist + if (! is_dir($dir)) { + // FIXME: create the dir automatically? + throw new CompilerException( + sprintf('The directory "%s" does not exist. Cannot save the source map.', $dir) + ); + } + + // FIXME: proper saving, with dir write check! + if (file_put_contents($file, $content) === false) { + throw new CompilerException(sprintf('Cannot save the source map to "%s"', $file)); + } + + return $this->options['sourceMapURL']; + } + + /** + * Generates the JSON source map + * + * @param string $prefix A prefix added in the output file, which needs to shift mappings + * + * @return string + * + * @see https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit# + */ + public function generateJson($prefix = '') + { + $sourceMap = []; + $mappings = $this->generateMappings($prefix); + + // File version (always the first entry in the object) and must be a positive integer. + $sourceMap['version'] = self::VERSION; + + // An optional name of the generated code that this source map is associated with. + $file = $this->options['sourceMapFilename']; + + if ($file) { + $sourceMap['file'] = $file; + } + + // An optional source root, useful for relocating source files on a server or removing repeated values in the + // 'sources' entry. This value is prepended to the individual entries in the 'source' field. + $root = $this->options['sourceRoot']; + + if ($root) { + $sourceMap['sourceRoot'] = $root; + } + + // A list of original sources used by the 'mappings' entry. + $sourceMap['sources'] = []; + + foreach ($this->sources as $sourceUri => $sourceFilename) { + $sourceMap['sources'][] = $this->normalizeFilename($sourceFilename); + } + + // A list of symbol names used by the 'mappings' entry. + $sourceMap['names'] = []; + + // A string with the encoded mapping data. + $sourceMap['mappings'] = $mappings; + + if ($this->options['outputSourceFiles']) { + // An optional list of source content, useful when the 'source' can't be hosted. + // The contents are listed in the same order as the sources above. + // 'null' may be used if some original sources should be retrieved by name. + $sourceMap['sourcesContent'] = $this->getSourcesContent(); + } + + // less.js compat fixes + if (\count($sourceMap['sources']) && empty($sourceMap['sourceRoot'])) { + unset($sourceMap['sourceRoot']); + } + + return json_encode($sourceMap, JSON_UNESCAPED_SLASHES); + } + + /** + * Returns the sources contents + * + * @return string[]|null + */ + protected function getSourcesContent() + { + if (empty($this->sources)) { + return null; + } + + $content = []; + + foreach ($this->sources as $sourceFile) { + $content[] = file_get_contents($sourceFile); + } + + return $content; + } + + /** + * Generates the mappings string + * + * @param string $prefix A prefix added in the output file, which needs to shift mappings + * + * @return string + */ + public function generateMappings($prefix = '') + { + if (! \count($this->mappings)) { + return ''; + } + + $prefixLines = substr_count($prefix, "\n"); + $lastPrefixNewLine = strrpos($prefix, "\n"); + $lastPrefixLineStart = false === $lastPrefixNewLine ? 0 : $lastPrefixNewLine + 1; + $prefixColumn = strlen($prefix) - $lastPrefixLineStart; + + $this->sourceKeys = array_flip(array_keys($this->sources)); + + // group mappings by generated line number. + $groupedMap = $groupedMapEncoded = []; + + foreach ($this->mappings as $m) { + $groupedMap[$m['generated_line']][] = $m; + } + + ksort($groupedMap); + + $lastGeneratedLine = $lastOriginalIndex = $lastOriginalLine = $lastOriginalColumn = 0; + + foreach ($groupedMap as $lineNumber => $lineMap) { + if ($lineNumber > 1) { + // The prefix only impacts the column for the first line of the original output + $prefixColumn = 0; + } + $lineNumber += $prefixLines; + + while (++$lastGeneratedLine < $lineNumber) { + $groupedMapEncoded[] = ';'; + } + + $lineMapEncoded = []; + $lastGeneratedColumn = 0; + + foreach ($lineMap as $m) { + $generatedColumn = $m['generated_column'] + $prefixColumn; + + $mapEncoded = $this->encoder->encode($generatedColumn - $lastGeneratedColumn); + $lastGeneratedColumn = $generatedColumn; + + // find the index + if ($m['source_file']) { + $index = $this->findFileIndex($m['source_file']); + + if ($index !== false) { + $mapEncoded .= $this->encoder->encode($index - $lastOriginalIndex); + $lastOriginalIndex = $index; + // lines are stored 0-based in SourceMap spec version 3 + $mapEncoded .= $this->encoder->encode($m['original_line'] - 1 - $lastOriginalLine); + $lastOriginalLine = $m['original_line'] - 1; + $mapEncoded .= $this->encoder->encode($m['original_column'] - $lastOriginalColumn); + $lastOriginalColumn = $m['original_column']; + } + } + + $lineMapEncoded[] = $mapEncoded; + } + + $groupedMapEncoded[] = implode(',', $lineMapEncoded) . ';'; + } + + return rtrim(implode($groupedMapEncoded), ';'); + } + + /** + * Finds the index for the filename + * + * @param string $filename + * + * @return int|false + */ + protected function findFileIndex($filename) + { + return $this->sourceKeys[$filename]; + } + + /** + * Normalize filename + * + * @param string $filename + * + * @return string + */ + protected function normalizeFilename($filename) + { + $filename = $this->fixWindowsPath($filename); + $rootpath = $this->options['sourceMapRootpath']; + $basePath = $this->options['sourceMapBasepath']; + + // "Trim" the 'sourceMapBasepath' from the output filename. + if (\strlen($basePath) && strpos($filename, $basePath) === 0) { + $filename = substr($filename, \strlen($basePath)); + } + + // Remove extra leading path separators. + if (strpos($filename, '\\') === 0 || strpos($filename, '/') === 0) { + $filename = substr($filename, 1); + } + + return $rootpath . $filename; + } + + /** + * Fix windows paths + * + * @param string $path + * @param bool $addEndSlash + * + * @return string + */ + public function fixWindowsPath($path, $addEndSlash = false) + { + $slash = ($addEndSlash) ? '/' : ''; + + if (! empty($path)) { + $path = str_replace('\\', '/', $path); + $path = rtrim($path, '/') . $slash; + } + + return $path; + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Type.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Type.php new file mode 100644 index 00000000..d4308878 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Type.php @@ -0,0 +1,208 @@ + + */ +class Type +{ + /** + * @internal + */ + const T_ASSIGN = 'assign'; + /** + * @internal + */ + const T_AT_ROOT = 'at-root'; + /** + * @internal + */ + const T_BLOCK = 'block'; + /** + * @deprecated + * @internal + */ + const T_BREAK = 'break'; + /** + * @internal + */ + const T_CHARSET = 'charset'; + const T_COLOR = 'color'; + /** + * @internal + */ + const T_COMMENT = 'comment'; + /** + * @deprecated + * @internal + */ + const T_CONTINUE = 'continue'; + /** + * @deprecated + * @internal + */ + const T_CONTROL = 'control'; + /** + * @internal + */ + const T_CUSTOM_PROPERTY = 'custom'; + /** + * @internal + */ + const T_DEBUG = 'debug'; + /** + * @internal + */ + const T_DIRECTIVE = 'directive'; + /** + * @internal + */ + const T_EACH = 'each'; + /** + * @internal + */ + const T_ELSE = 'else'; + /** + * @internal + */ + const T_ELSEIF = 'elseif'; + /** + * @internal + */ + const T_ERROR = 'error'; + /** + * @internal + */ + const T_EXPRESSION = 'exp'; + /** + * @internal + */ + const T_EXTEND = 'extend'; + /** + * @internal + */ + const T_FOR = 'for'; + const T_FUNCTION = 'function'; + /** + * @internal + */ + const T_FUNCTION_REFERENCE = 'function-reference'; + /** + * @internal + */ + const T_FUNCTION_CALL = 'fncall'; + /** + * @internal + */ + const T_HSL = 'hsl'; + /** + * @internal + */ + const T_HWB = 'hwb'; + /** + * @internal + */ + const T_IF = 'if'; + /** + * @internal + */ + const T_IMPORT = 'import'; + /** + * @internal + */ + const T_INCLUDE = 'include'; + /** + * @internal + */ + const T_INTERPOLATE = 'interpolate'; + /** + * @internal + */ + const T_INTERPOLATED = 'interpolated'; + /** + * @internal + */ + const T_KEYWORD = 'keyword'; + const T_LIST = 'list'; + const T_MAP = 'map'; + /** + * @internal + */ + const T_MEDIA = 'media'; + /** + * @internal + */ + const T_MEDIA_EXPRESSION = 'mediaExp'; + /** + * @internal + */ + const T_MEDIA_TYPE = 'mediaType'; + /** + * @internal + */ + const T_MEDIA_VALUE = 'mediaValue'; + /** + * @internal + */ + const T_MIXIN = 'mixin'; + /** + * @internal + */ + const T_MIXIN_CONTENT = 'mixin_content'; + /** + * @internal + */ + const T_NESTED_PROPERTY = 'nestedprop'; + /** + * @internal + */ + const T_NOT = 'not'; + const T_NULL = 'null'; + const T_NUMBER = 'number'; + /** + * @internal + */ + const T_RETURN = 'return'; + /** + * @internal + */ + const T_ROOT = 'root'; + /** + * @internal + */ + const T_SCSSPHP_IMPORT_ONCE = 'scssphp-import-once'; + /** + * @internal + */ + const T_SELF = 'self'; + const T_STRING = 'string'; + /** + * @internal + */ + const T_UNARY = 'unary'; + /** + * @internal + */ + const T_VARIABLE = 'var'; + /** + * @internal + */ + const T_WARN = 'warn'; + /** + * @internal + */ + const T_WHILE = 'while'; +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Util.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Util.php new file mode 100644 index 00000000..ad608ceb --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Util.php @@ -0,0 +1,184 @@ + + * + * @internal + */ +class Util +{ + /** + * Asserts that `value` falls within `range` (inclusive), leaving + * room for slight floating-point errors. + * + * @param string $name The name of the value. Used in the error message. + * @param Range $range Range of values. + * @param array|Number $value The value to check. + * @param string $unit The unit of the value. Used in error reporting. + * + * @return mixed `value` adjusted to fall within range, if it was outside by a floating-point margin. + * + * @throws \ScssPhp\ScssPhp\Exception\RangeException + */ + public static function checkRange($name, Range $range, $value, $unit = '') + { + $val = $value[1]; + $grace = new Range(-0.00001, 0.00001); + + if (! \is_numeric($val)) { + throw new RangeException("$name {$val} is not a number."); + } + + if ($range->includes($val)) { + return $val; + } + + if ($grace->includes($val - $range->first)) { + return $range->first; + } + + if ($grace->includes($val - $range->last)) { + return $range->last; + } + + throw new RangeException("$name {$val} must be between {$range->first} and {$range->last}$unit"); + } + + /** + * Encode URI component + * + * @param string $string + * + * @return string + */ + public static function encodeURIComponent($string) + { + $revert = ['%21' => '!', '%2A' => '*', '%27' => "'", '%28' => '(', '%29' => ')']; + + return strtr(rawurlencode($string), $revert); + } + + /** + * mb_chr() wrapper + * + * @param int $code + * + * @return string + */ + public static function mbChr($code) + { + // Use the native implementation if available, but not on PHP 7.2 as mb_chr(0) is buggy there + if (\PHP_VERSION_ID > 70300 && \function_exists('mb_chr')) { + return mb_chr($code, 'UTF-8'); + } + + if (0x80 > $code %= 0x200000) { + $s = \chr($code); + } elseif (0x800 > $code) { + $s = \chr(0xC0 | $code >> 6) . \chr(0x80 | $code & 0x3F); + } elseif (0x10000 > $code) { + $s = \chr(0xE0 | $code >> 12) . \chr(0x80 | $code >> 6 & 0x3F) . \chr(0x80 | $code & 0x3F); + } else { + $s = \chr(0xF0 | $code >> 18) . \chr(0x80 | $code >> 12 & 0x3F) + . \chr(0x80 | $code >> 6 & 0x3F) . \chr(0x80 | $code & 0x3F); + } + + return $s; + } + + /** + * mb_strlen() wrapper + * + * @param string $string + * @return int + */ + public static function mbStrlen($string) + { + // Use the native implementation if available. + if (\function_exists('mb_strlen')) { + return mb_strlen($string, 'UTF-8'); + } + + if (\function_exists('iconv_strlen')) { + return (int) @iconv_strlen($string, 'UTF-8'); + } + + throw new \LogicException('Either mbstring (recommended) or iconv is necessary to use Scssphp.'); + } + + /** + * mb_substr() wrapper + * @param string $string + * @param int $start + * @param null|int $length + * @return string + */ + public static function mbSubstr($string, $start, $length = null) + { + // Use the native implementation if available. + if (\function_exists('mb_substr')) { + return mb_substr($string, $start, $length, 'UTF-8'); + } + + if (\function_exists('iconv_substr')) { + if ($start < 0) { + $start = static::mbStrlen($string) + $start; + if ($start < 0) { + $start = 0; + } + } + + if (null === $length) { + $length = 2147483647; + } elseif ($length < 0) { + $length = static::mbStrlen($string) + $length - $start; + if ($length < 0) { + return ''; + } + } + + return (string)iconv_substr($string, $start, $length, 'UTF-8'); + } + + throw new \LogicException('Either mbstring (recommended) or iconv is necessary to use Scssphp.'); + } + + /** + * mb_strpos wrapper + * @param string $haystack + * @param string $needle + * @param int $offset + * + * @return int|false + */ + public static function mbStrpos($haystack, $needle, $offset = 0) + { + if (\function_exists('mb_strpos')) { + return mb_strpos($haystack, $needle, $offset, 'UTF-8'); + } + + if (\function_exists('iconv_strpos')) { + return iconv_strpos($haystack, $needle, $offset, 'UTF-8'); + } + + throw new \LogicException('Either mbstring (recommended) or iconv is necessary to use Scssphp.'); + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Util/Path.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Util/Path.php new file mode 100644 index 00000000..f399e41a --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Util/Path.php @@ -0,0 +1,77 @@ +parseValue($source, $value)) { + throw new \InvalidArgumentException(sprintf('Invalid value source "%s".', $source)); + } + + return $value; + } + + /** + * Converts a PHP value to a Sass value + * + * The returned value is guaranteed to be supported by the + * Compiler methods for registering custom variables. No other + * guarantee about it is provided. It should be considered + * opaque values by the caller. + * + * @param mixed $value + * + * @return mixed + */ + public static function fromPhp($value) + { + if ($value instanceof Number) { + return $value; + } + + if (is_array($value) && isset($value[0]) && \in_array($value[0], [Type::T_NULL, Type::T_COLOR, Type::T_KEYWORD, Type::T_LIST, Type::T_MAP, Type::T_STRING])) { + return $value; + } + + if ($value === null) { + return Compiler::$null; + } + + if ($value === true) { + return Compiler::$true; + } + + if ($value === false) { + return Compiler::$false; + } + + if ($value === '') { + return Compiler::$emptyString; + } + + if (\is_int($value) || \is_float($value)) { + return new Number($value, ''); + } + + if (\is_string($value)) { + return [Type::T_STRING, '"', [$value]]; + } + + throw new \InvalidArgumentException(sprintf('Cannot convert the value of type "%s" to a Sass value.', gettype($value))); + } +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Version.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Version.php new file mode 100644 index 00000000..f8d72847 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Version.php @@ -0,0 +1,23 @@ + + */ +class Version +{ + const VERSION = '1.10.0'; +} diff --git a/dev/plugins/admin/vendor/scssphp/scssphp/src/Warn.php b/dev/plugins/admin/vendor/scssphp/scssphp/src/Warn.php new file mode 100644 index 00000000..592b44c7 --- /dev/null +++ b/dev/plugins/admin/vendor/scssphp/scssphp/src/Warn.php @@ -0,0 +1,84 @@ + + + + + + \ No newline at end of file diff --git a/dev/plugins/anchors/CHANGELOG.md b/dev/plugins/anchors/CHANGELOG.md new file mode 100644 index 00000000..d5ada54b --- /dev/null +++ b/dev/plugins/anchors/CHANGELOG.md @@ -0,0 +1,65 @@ +# v1.6.0 +## 11/24/2021 + +1. [](#new) + * Added new option `copy_to_clipboard` to automatically copy the link to clipboard +2. [](#improved) + * Removed reliance on `JQuery` for DOM ready check + * Updated `anchors.js` to version 4.3.1 + +# v1.5.4 +## 12/02/2020 + +1. [](#improved) + * Updated `anchors.js` to version 4.3.0 + * Requires Grav 1.6 + +# v1.5.3 +## 03/30/2019 + +1. [](#improved) + * Updated `anchors.js` to version 4.2.0 + * Improved documentation + +# v1.5.2 +## 09/28/2017 + +1. [](#improved) + * Updated `anchors.js` to version 4.1.0 + +# v1.5.1 +## 07/14/2016 + +1. [](#improved) + * Translate some blueprint options + +# v1.5.0 +## 01/06/2016 + +1. [](#improved) + * Disable anchors in Admin + +# v1.4.0 +## 08/25/2015 + +1. [](#improved) + * Added blueprints for Grav Admin plugin + +# v1.3.0 +## 07/20/2015 + +1. [](#new) + * Updated `anchors.js` to version 1.2.1 + * Added new options such as 'placement', 'visible', 'icon' and 'class' + +# v1.2.0 +## 03/01/2015 + +1. [](#new) + * Updated `anchors.js` to version 0.3.0 + +# v1.1.0 +## 11/30/2014 + +1. [](#new) + * ChangeLog started... diff --git a/dev/plugins/anchors/LICENSE b/dev/plugins/anchors/LICENSE new file mode 100644 index 00000000..484793ad --- /dev/null +++ b/dev/plugins/anchors/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Grav + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dev/plugins/anchors/README.md b/dev/plugins/anchors/README.md new file mode 100644 index 00000000..cb615da6 --- /dev/null +++ b/dev/plugins/anchors/README.md @@ -0,0 +1,106 @@ +# Grav Anchors Plugin + + +`anchors` is a [Grav](http://github.com/getgrav/grav) plugin that provides automatic header anchors via the [anchorjs](http://bryanbraun.github.io/anchorjs) Vanilla JS plugin. + +# Installation + +## GPM Installation (Preferred) + +The simplest way to install this plugin is via the [Grav Package Manager (GPM)](http://learn.getgrav.org/advanced/grav-gpm). From the root of your Grav install type: + + bin/gpm install anchors + +## Manual Installation + +If for some reason you can't use GPM you can manually install this plugin. Download the zip version of this repository and unzip it under `/your/site/grav/user/plugins`. Then, rename the folder to `anchors`. + +You should now have all the plugin files under + + /your/site/grav/user/plugins/anchors + +# Usage + +To best understand how Anchors works, you should read through the original [project documentation](https://github.com/bryanbraun/anchorjs). + +## Show Menu of Anchors + +If you want to use the generated links to also generate a menu from these anchors, just put the function below in the template file Twig: + +``` +{{ anchors(content, tag, terms) }} +``` + +The function accepts 3 parameters: + +* **content:** this parameter is the content of the page in which the function will search for all content and separate only the tags and their contents defined by the second parameter. E.g. `page.content` +* **tag:** this parameter will be the string of the tag used to make the menu. E.g. `h2` +* **terms:** this parameter is to exclude terms that you do not wish to include in the menu formation that is between the tag passed in the second parameter. The value passed is a string separated by comma to identify each term. Ex: `title 01, title 02` + +For example: + +``` +{{ anchors(page.content, 'h2') }} +``` + +When rendered the function will return a formed HTML with `