From 4b7c97a02ed5fd9807821819302a770dde9ffa2e Mon Sep 17 00:00:00 2001 From: armansansd Date: Tue, 18 Jul 2023 10:47:46 +0100 Subject: [PATCH] mediatheque --- config/backups.yaml | 0 config/groups.yaml | 17 + config/media.yaml | 263 + config/plugins/admin.yaml | 101 + config/plugins/auto-author.yaml | 2 + config/plugins/autoseo.yaml | 11 + config/plugins/cookieconsent.yaml | 13 + config/plugins/email.yaml | 19 + config/plugins/langswitcher.yaml | 3 + config/plugins/pagination.yaml | 3 + config/plugins/social-seo-metatags.yaml | 33 + config/plugins/taxonomylist.yaml | 2 + config/plugins/tinymce-editor.yaml | 80 + config/plugins/tntsearch.yaml | 28 + config/scheduler.yaml | 0 config/security.yaml | 1 + config/site.yaml | 19 + config/streams.yaml | 0 config/system.yaml | 239 + config/themes/plain.yaml | 3 + config/versions.yaml | 25 + languages/en.yaml | 12 + languages/fr.yaml | 12 + plugins/.gitkeep | 0 plugins/admin-addon-media-metadata/.gitignore | 2 + plugins/admin-addon-media-metadata/.php_cs | 83 + .../admin-addon-media-metadata/CHANGELOG.md | 37 + plugins/admin-addon-media-metadata/LICENSE | 21 + plugins/admin-addon-media-metadata/README.md | 90 + .../admin-addon-media-metadata.css | 40 + .../admin-addon-media-metadata.js | 113 + .../admin-addon-media-metadata.php | 321 + .../admin-addon-media-metadata.yaml | 21 + .../assets/1-open-form.jpg | Bin 0 -> 86765 bytes .../assets/2-form-opened.jpg | Bin 0 -> 45622 bytes .../blueprints.yaml | 30 + .../admin-addon-media-metadata/composer.json | 29 + .../admin-addon-media-metadata/composer.lock | 23 + .../languages/de.yaml | 11 + .../languages/en.yaml | 11 + .../languages/fr.yaml | 11 + .../templates/additionalInlineJS.html.twig | 2 + .../templates/metadata-modal.html.twig | 36 + .../vendor/autoload.php | 7 + .../vendor/composer/ClassLoader.php | 445 + .../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 | 55 + .../vendor/composer/autoload_static.php | 36 + .../vendor/composer/installed.json | 1 + plugins/admin/.editorconfig | 17 + plugins/admin/.gitattributes | 8 + plugins/admin/.github/FUNDING.yml | 8 + plugins/admin/.github/dependabot.yml | 6 + plugins/admin/.gitignore | 17 + plugins/admin/CHANGELOG.md | 2625 + plugins/admin/CONTRIBUTING.md | 1 + plugins/admin/LICENSE | 21 + plugins/admin/README.md | 152 + plugins/admin/UPGRADE.md | 6 + plugins/admin/admin.php | 1350 + plugins/admin/admin.yaml | 84 + plugins/admin/assets/admin-dashboard.png | Bin 0 -> 241372 bytes plugins/admin/blueprints.yaml | 781 + plugins/admin/blueprints/config/media.yaml | 36 + plugins/admin/classes/plugin/Admin.php | 2507 + .../classes/plugin/AdminBaseController.php | 1174 + .../admin/classes/plugin/AdminController.php | 3073 + plugins/admin/classes/plugin/AdminForm.php | 182 + .../admin/classes/plugin/AdminFormFactory.php | 51 + .../plugin/Controllers/AbstractController.php | 414 + .../plugin/Controllers/AdminController.php | 359 + .../Controllers/Login/LoginController.php | 634 + plugins/admin/classes/plugin/Gpm.php | 442 + plugins/admin/classes/plugin/Popularity.php | 310 + plugins/admin/classes/plugin/Router.php | 79 + .../classes/plugin/Routers/LoginRouter.php | 93 + plugins/admin/classes/plugin/ScssCompiler.php | 70 + plugins/admin/classes/plugin/ScssList.php | 59 + plugins/admin/classes/plugin/Themes.php | 29 + .../plugin/Twig/AdminTwigExtension.php | 138 + plugins/admin/classes/plugin/Utils.php | 61 + plugins/admin/classes/plugin/WhiteLabel.php | 100 + plugins/admin/codeception.yml | 18 + plugins/admin/composer.json | 64 + plugins/admin/composer.lock | 3945 + plugins/admin/hebe.json | 15 + plugins/admin/languages/ar.yaml | 307 + plugins/admin/languages/bg.yaml | 356 + plugins/admin/languages/bn.yaml | 4 + plugins/admin/languages/br.yaml | 592 + plugins/admin/languages/ca.yaml | 643 + plugins/admin/languages/cs.yaml | 1112 + plugins/admin/languages/cy.yaml | 89 + plugins/admin/languages/da.yaml | 760 + plugins/admin/languages/de.yaml | 965 + plugins/admin/languages/el.yaml | 710 + plugins/admin/languages/en.yaml | 1154 + plugins/admin/languages/eo.yaml | 766 + plugins/admin/languages/es.yaml | 989 + plugins/admin/languages/et.yaml | 896 + plugins/admin/languages/eu.yaml | 181 + plugins/admin/languages/fa.yaml | 878 + plugins/admin/languages/fi.yaml | 259 + plugins/admin/languages/fr.yaml | 1112 + plugins/admin/languages/gl.yaml | 867 + plugins/admin/languages/he.yaml | 410 + plugins/admin/languages/hr.yaml | 600 + plugins/admin/languages/hu.yaml | 777 + plugins/admin/languages/id.yaml | 708 + plugins/admin/languages/it.yaml | 1112 + plugins/admin/languages/ja.yaml | 759 + plugins/admin/languages/ko.yaml | 107 + plugins/admin/languages/ku.yaml | 121 + plugins/admin/languages/lt.yaml | 359 + plugins/admin/languages/mn.yaml | 1112 + plugins/admin/languages/nl.yaml | 853 + plugins/admin/languages/no.yaml | 730 + plugins/admin/languages/pl.yaml | 795 + plugins/admin/languages/pt.yaml | 620 + plugins/admin/languages/ro.yaml | 1106 + plugins/admin/languages/ru.yaml | 1103 + plugins/admin/languages/si.yaml | 98 + plugins/admin/languages/sk.yaml | 548 + plugins/admin/languages/sl.yaml | 242 + plugins/admin/languages/sr.yaml | 805 + plugins/admin/languages/sv.yaml | 670 + plugins/admin/languages/th.yaml | 688 + plugins/admin/languages/tlh.yaml | 8 + plugins/admin/languages/tr.yaml | 862 + plugins/admin/languages/uk.yaml | 600 + plugins/admin/languages/vi.yaml | 452 + plugins/admin/languages/zh-cn.yaml | 1112 + plugins/admin/languages/zh-tw.yaml | 718 + plugins/admin/languages/zh.yaml | 1112 + plugins/admin/permissions.yaml | 48 + plugins/admin/presets.yaml | 370 + plugins/admin/tests/_bootstrap.php | 11 + plugins/admin/tests/_support/Helper/Unit.php | 80 + plugins/admin/tests/_support/UnitTester.php | 26 + plugins/admin/tests/unit.suite.yml | 9 + plugins/admin/tests/unit/_bootstrap.php | 3 + .../tests/unit/classes/controllerTest.php | 42 + plugins/admin/themes/grav/.babelrc | 3 + plugins/admin/themes/grav/.eslintignore | 1 + plugins/admin/themes/grav/.eslintrc | 165 + .../admin/themes/grav/app/dashboard/backup.js | 42 + .../admin/themes/grav/app/dashboard/cache.js | 49 + .../admin/themes/grav/app/dashboard/chart.js | 138 + .../admin/themes/grav/app/dashboard/index.js | 12 + .../admin/themes/grav/app/dashboard/update.js | 1 + .../grav/app/forms/fields/acl-picker.js | 89 + .../themes/grav/app/forms/fields/array.js | 205 + .../grav/app/forms/fields/collections.js | 311 + .../grav/app/forms/fields/colorpicker.js | 579 + .../themes/grav/app/forms/fields/cron.js | 85 + .../themes/grav/app/forms/fields/datetime.js | 63 + .../themes/grav/app/forms/fields/editor.js | 237 + .../grav/app/forms/fields/editor/buttons.js | 416 + .../themes/grav/app/forms/fields/elements.js | 12 + .../grav/app/forms/fields/filepicker.js | 144 + .../themes/grav/app/forms/fields/files.js | 402 + .../themes/grav/app/forms/fields/folder.js | 20 + .../grav/app/forms/fields/iconpicker.js | 298 + .../grav/app/forms/fields/indeterminate.js | 52 + .../themes/grav/app/forms/fields/index.js | 76 + .../grav/app/forms/fields/mediapicker.js | 51 + .../grav/app/forms/fields/multilevel.js | 281 + .../themes/grav/app/forms/fields/parents.js | 270 + .../grav/app/forms/fields/permissions.js | 46 + .../themes/grav/app/forms/fields/range.js | 10 + .../themes/grav/app/forms/fields/selectize.js | 66 + .../grav/app/forms/fields/selectunique.js | 160 + .../themes/grav/app/forms/fields/text.js | 13 + plugins/admin/themes/grav/app/forms/form.js | 139 + plugins/admin/themes/grav/app/forms/index.js | 16 + plugins/admin/themes/grav/app/forms/state.js | 150 + plugins/admin/themes/grav/app/main.js | 73 + plugins/admin/themes/grav/app/media/index.js | 226 + .../admin/themes/grav/app/plugins/index.js | 92 + plugins/admin/themes/grav/app/themes/index.js | 46 + plugins/admin/themes/grav/app/tools/index.js | 1 + plugins/admin/themes/grav/app/tools/logs.js | 14 + .../grav/app/updates/channel-switcher.js | 24 + .../admin/themes/grav/app/updates/check.js | 26 + plugins/admin/themes/grav/app/updates/feed.js | 68 + .../admin/themes/grav/app/updates/index.js | 196 + .../themes/grav/app/updates/notifications.js | 169 + .../admin/themes/grav/app/updates/update.js | 22 + plugins/admin/themes/grav/app/utils/2fa.js | 32 + .../grav/app/utils/bootstrap-collapse.js | 210 + .../app/utils/bootstrap-datetimepicker.js | 2632 + .../grav/app/utils/bootstrap-dropdown.js | 169 + .../grav/app/utils/bootstrap-transition.js | 52 + .../admin/themes/grav/app/utils/changelog.js | 25 + plugins/admin/themes/grav/app/utils/colors.js | 152 + .../admin/themes/grav/app/utils/cookies.js | 164 + .../admin/themes/grav/app/utils/cron-ui.js | 864 + .../admin/themes/grav/app/utils/finderjs.js | 325 + .../themes/grav/app/utils/formatbytes.js | 11 + plugins/admin/themes/grav/app/utils/gpm.js | 57 + .../themes/grav/app/utils/jquery-utils.js | 50 + .../admin/themes/grav/app/utils/keepalive.js | 34 + .../admin/themes/grav/app/utils/offline.js | 21 + .../admin/themes/grav/app/utils/packages.js | 498 + .../admin/themes/grav/app/utils/remodal.js | 820 + .../admin/themes/grav/app/utils/request.js | 38 + .../admin/themes/grav/app/utils/response.js | 101 + .../grav/app/utils/selectize-option-click.js | 42 + .../grav/app/utils/selectize-required-fix.js | 28 + .../admin/themes/grav/app/utils/sidebar.js | 180 + .../admin/themes/grav/app/utils/storage.js | 41 + .../themes/grav/app/utils/tabs-memory.js | 29 + plugins/admin/themes/grav/app/utils/toastr.js | 6 + .../themes/grav/app/whitelabel/compile.js | 25 + .../admin/themes/grav/app/whitelabel/index.js | 93 + .../themes/grav/app/whitelabel/presets.js | 169 + .../themes/grav/css-compiled/nucleus.css | 625 + .../themes/grav/css-compiled/nucleus.css.map | 93 + .../admin/themes/grav/css-compiled/preset.css | 1520 + .../themes/grav/css-compiled/preset.css.map | 18 + .../themes/grav/css-compiled/simple-fonts.css | 13 + .../grav/css-compiled/simple-fonts.css.map | 10 + .../themes/grav/css-compiled/template.css | 5652 + .../themes/grav/css-compiled/template.css.map | 129 + .../admin/themes/grav/css/chartist.min.css | 1 + .../themes/grav/css/codemirror/codemirror.css | 334 + .../grav/css/codemirror/themes/3024-day.css | 41 + .../grav/css/codemirror/themes/3024-night.css | 39 + .../grav/css/codemirror/themes/abcdef.css | 32 + .../css/codemirror/themes/ambiance-mobile.css | 5 + .../grav/css/codemirror/themes/ambiance.css | 74 + .../grav/css/codemirror/themes/ayu-dark.css | 42 + .../grav/css/codemirror/themes/ayu-mirage.css | 43 + .../css/codemirror/themes/base16-dark.css | 38 + .../css/codemirror/themes/base16-light.css | 38 + .../grav/css/codemirror/themes/bespin.css | 34 + .../grav/css/codemirror/themes/blackboard.css | 32 + .../grav/css/codemirror/themes/cobalt.css | 25 + .../grav/css/codemirror/themes/colorforth.css | 33 + .../grav/css/codemirror/themes/darcula.css | 53 + .../grav/css/codemirror/themes/dracula.css | 40 + .../css/codemirror/themes/duotone-dark.css | 35 + .../css/codemirror/themes/duotone-light.css | 36 + .../grav/css/codemirror/themes/eclipse.css | 23 + .../grav/css/codemirror/themes/elegant.css | 13 + .../css/codemirror/themes/erlang-dark.css | 34 + .../css/codemirror/themes/gruvbox-dark.css | 37 + .../grav/css/codemirror/themes/hopscotch.css | 34 + .../grav/css/codemirror/themes/icecoder.css | 43 + .../grav/css/codemirror/themes/idea.css | 42 + .../grav/css/codemirror/themes/isotope.css | 34 + .../css/codemirror/themes/lesser-dark.css | 47 + .../grav/css/codemirror/themes/liquibyte.css | 95 + .../grav/css/codemirror/themes/lucario.css | 37 + .../css/codemirror/themes/material-darker.css | 135 + .../css/codemirror/themes/material-ocean.css | 135 + .../codemirror/themes/material-palenight.css | 135 + .../grav/css/codemirror/themes/material.css | 135 + .../themes/grav/css/codemirror/themes/mbo.css | 37 + .../grav/css/codemirror/themes/mdn-like.css | 46 + .../grav/css/codemirror/themes/midnight.css | 39 + .../grav/css/codemirror/themes/monokai.css | 41 + .../grav/css/codemirror/themes/moxer.css | 143 + .../grav/css/codemirror/themes/neat.css | 12 + .../themes/grav/css/codemirror/themes/neo.css | 43 + .../grav/css/codemirror/themes/night.css | 27 + .../grav/css/codemirror/themes/nord.css | 42 + .../css/codemirror/themes/oceanic-next.css | 44 + .../css/codemirror/themes/panda-syntax.css | 85 + .../grav/css/codemirror/themes/paper.css | 143 + .../css/codemirror/themes/paraiso-dark.css | 38 + .../css/codemirror/themes/paraiso-light.css | 38 + .../css/codemirror/themes/pastel-on-dark.css | 52 + .../grav/css/codemirror/themes/railscasts.css | 34 + .../grav/css/codemirror/themes/rubyblue.css | 25 + .../grav/css/codemirror/themes/seti.css | 44 + .../grav/css/codemirror/themes/shadowfox.css | 52 + .../grav/css/codemirror/themes/solarized.css | 168 + .../grav/css/codemirror/themes/ssms.css | 16 + .../grav/css/codemirror/themes/the-matrix.css | 30 + .../themes/tomorrow-night-bright.css | 35 + .../themes/tomorrow-night-eighties.css | 38 + .../grav/css/codemirror/themes/ttcn.css | 64 + .../grav/css/codemirror/themes/twilight.css | 32 + .../css/codemirror/themes/vibrant-ink.css | 34 + .../grav/css/codemirror/themes/xq-dark.css | 53 + .../grav/css/codemirror/themes/xq-light.css | 43 + .../grav/css/codemirror/themes/yeti.css | 44 + .../grav/css/codemirror/themes/yonce.css | 59 + .../grav/css/codemirror/themes/zenburn.css | 37 + .../themes/grav/css/fork-awesome.min.css | 12 + .../admin/themes/grav/css/hint.base.min.css | 5 + plugins/admin/themes/grav/css/iconpicker.css | 222 + .../admin/themes/grav/css/nucleus-ie10.css | 24 + plugins/admin/themes/grav/css/nucleus-ie9.css | 62 + plugins/admin/themes/grav/css/prism.css | 121 + .../themes/grav/css/pure-0.5.0/grids-min.css | 15 + plugins/admin/themes/grav/css/rtl.css | 1240 + .../admin/themes/grav/css/selectize.min.css | 1 + .../themes/grav/fonts/forkawesome-webfont.eot | Bin 0 -> 186490 bytes .../themes/grav/fonts/forkawesome-webfont.svg | 2810 + .../themes/grav/fonts/forkawesome-webfont.ttf | Bin 0 -> 186300 bytes .../grav/fonts/forkawesome-webfont.woff | Bin 0 -> 113404 bytes .../grav/fonts/forkawesome-webfont.woff2 | Bin 0 -> 90420 bytes .../rockettheme-apps/rockettheme-apps.eot | Bin 0 -> 4838 bytes .../rockettheme-apps/rockettheme-apps.svg | 16 + .../rockettheme-apps/rockettheme-apps.ttf | Bin 0 -> 4644 bytes .../rockettheme-apps/rockettheme-apps.woff | Bin 0 -> 3348 bytes plugins/admin/themes/grav/images/favicon.png | Bin 0 -> 13203 bytes .../admin/themes/grav/images/grav-regular.svg | 1 + .../admin/themes/grav/images/grav-small.svg | 1 + .../themes/grav/images/icons/book-edit.svg | 10 + .../themes/grav/images/icons/clock-hands.svg | 8 + .../admin/themes/grav/images/icons/crown.svg | 1 + .../admin/themes/grav/images/icons/house.svg | 5 + .../themes/grav/images/icons/module-four.svg | 12 + .../themes/grav/images/icons/superman.svg | 7 + .../themes/grav/images/icons/touchid-lock.svg | 15 + plugins/admin/themes/grav/images/logo.svg | 1 + .../admin/themes/grav/images/transparent.png | Bin 0 -> 5123 bytes plugins/admin/themes/grav/js/admin.min.js | 15273 +++ .../themes/grav/js/form-attr.polyfill.js | 80 + plugins/admin/themes/grav/js/vendor.min.js | 88854 ++++++++++++++++ plugins/admin/themes/grav/package-lock.json | 10249 ++ plugins/admin/themes/grav/package.json | 64 + .../scss/configuration/nucleus/_base.scss | 14 + .../configuration/nucleus/_breakpoints.scss | 16 + .../scss/configuration/nucleus/_core.scss | 2 + .../scss/configuration/nucleus/_layout.scss | 8 + .../grav/scss/configuration/nucleus/_nav.scss | 3 + .../configuration/nucleus/_typography.scss | 14 + .../scss/configuration/template/_base.scss | 5 + .../scss/configuration/template/_colors.scss | 15 + .../configuration/template/_variables.scss | 22 + plugins/admin/themes/grav/scss/nucleus.scss | 27 + .../admin/themes/grav/scss/nucleus/_core.scss | 217 + .../admin/themes/grav/scss/nucleus/_flex.scss | 195 + .../themes/grav/scss/nucleus/_forms.scss | 62 + .../themes/grav/scss/nucleus/_typography.scss | 89 + .../grav/scss/nucleus/functions/_base.scss | 2 + .../scss/nucleus/functions/_direction.scss | 37 + .../grav/scss/nucleus/functions/_range.scss | 13 + .../grav/scss/nucleus/mixins/_base.scss | 2 + .../scss/nucleus/mixins/_breakpoints.scss | 44 + .../grav/scss/nucleus/mixins/_utilities.scss | 30 + .../scss/nucleus/particles/_align-text.scss | 46 + .../scss/nucleus/particles/_visibility.scss | 0 plugins/admin/themes/grav/scss/preset.scss | 2372 + .../admin/themes/grav/scss/simple-fonts.scss | 13 + plugins/admin/themes/grav/scss/template.scss | 109 + .../themes/grav/scss/template/_admin.scss | 1438 + .../themes/grav/scss/template/_buttons.scss | 140 + .../themes/grav/scss/template/_changelog.scss | 117 + .../themes/grav/scss/template/_colors.scss | 93 + .../themes/grav/scss/template/_core.scss | 51 + .../themes/grav/scss/template/_custom.scss | 2 + .../themes/grav/scss/template/_dropzone.scss | 306 + .../themes/grav/scss/template/_editor.scss | 315 + .../themes/grav/scss/template/_errors.scss | 17 + .../grav/scss/template/_extensions.scss | 58 + .../themes/grav/scss/template/_fonts.scss | 40 + .../themes/grav/scss/template/_forms.scss | 997 + .../admin/themes/grav/scss/template/_gpm.scss | 207 + .../themes/grav/scss/template/_header.scss | 3 + .../scss/template/_horizontal-scroll.scss | 54 + .../themes/grav/scss/template/_jqcron.scss | 70 + .../themes/grav/scss/template/_login.scss | 200 + .../themes/grav/scss/template/_media.scss | 331 + .../grav/scss/template/_nav-toggle.scss | 71 + .../grav/scss/template/_notifications.scss | 116 + .../themes/grav/scss/template/_pages.scss | 856 + .../themes/grav/scss/template/_phpinfo.scss | 35 + .../themes/grav/scss/template/_remodal.scss | 329 + .../grav/scss/template/_scrollbars.scss | 210 + .../themes/grav/scss/template/_tables.scss | 190 + .../themes/grav/scss/template/_tabs.scss | 125 + .../themes/grav/scss/template/_toastr.scss | 183 + .../themes/grav/scss/template/_tools.scss | 97 + .../grav/scss/template/_typography.scss | 166 + .../themes/grav/scss/template/_utilities.scss | 9 + .../grav/scss/template/_whitelabel.scss | 268 + .../grav/scss/template/modules/_base.scss | 5 + .../template/modules/_bourbon_essentials.scss | 120 + .../grav/scss/template/modules/_buttons.scss | 91 + .../scss/template/modules/_colorpicker.scss | 253 + .../template/modules/_datetimepicker.scss | 466 + .../grav/scss/template/modules/_finderjs.scss | 161 + .../scss/template/modules/_input-range.scss | 87 + .../scss/template/modules/_scrollbars.scss | 18 + .../scss/template/modules/_toggle-switch.scss | 20 + .../bourbon/_bourbon-deprecated-upcoming.scss | 8 + .../grav/scss/vendor/bourbon/_bourbon.scss | 77 + .../scss/vendor/bourbon/addons/_button.scss | 374 + .../scss/vendor/bourbon/addons/_clearfix.scss | 23 + .../bourbon/addons/_directional-values.scss | 111 + .../scss/vendor/bourbon/addons/_ellipsis.scss | 7 + .../vendor/bourbon/addons/_font-family.scss | 5 + .../vendor/bourbon/addons/_hide-text.scss | 10 + .../bourbon/addons/_html5-input-types.scss | 86 + .../scss/vendor/bourbon/addons/_position.scss | 32 + .../scss/vendor/bourbon/addons/_prefixer.scss | 45 + .../grav/scss/vendor/bourbon/addons/_rem.scss | 33 + .../vendor/bourbon/addons/_retina-image.scss | 31 + .../scss/vendor/bourbon/addons/_size.scss | 16 + .../bourbon/addons/_timing-functions.scss | 32 + .../scss/vendor/bourbon/addons/_triangle.scss | 83 + .../vendor/bourbon/addons/_word-wrap.scss | 8 + .../scss/vendor/bourbon/css3/_animation.scss | 52 + .../scss/vendor/bourbon/css3/_appearance.scss | 3 + .../bourbon/css3/_backface-visibility.scss | 6 + .../bourbon/css3/_background-image.scss | 42 + .../scss/vendor/bourbon/css3/_background.scss | 55 + .../vendor/bourbon/css3/_border-image.scss | 59 + .../vendor/bourbon/css3/_border-radius.scss | 22 + .../scss/vendor/bourbon/css3/_box-sizing.scss | 4 + .../grav/scss/vendor/bourbon/css3/_calc.scss | 4 + .../scss/vendor/bourbon/css3/_columns.scss | 47 + .../scss/vendor/bourbon/css3/_filter.scss | 5 + .../scss/vendor/bourbon/css3/_flex-box.scss | 321 + .../scss/vendor/bourbon/css3/_font-face.scss | 23 + .../bourbon/css3/_font-feature-settings.scss | 10 + .../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 | 35 + .../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/_transform.scss | 15 + .../scss/vendor/bourbon/css3/_transition.scss | 77 + .../vendor/bourbon/css3/_user-select.scss | 3 + .../vendor/bourbon/functions/_assign.scss | 11 + .../bourbon/functions/_color-lightness.scss | 13 + .../vendor/bourbon/functions/_flex-grid.scss | 39 + .../bourbon/functions/_golden-ratio.scss | 3 + .../vendor/bourbon/functions/_grid-width.scss | 13 + .../bourbon/functions/_modular-scale.scss | 66 + .../vendor/bourbon/functions/_px-to-em.scss | 13 + .../vendor/bourbon/functions/_px-to-rem.scss | 15 + .../bourbon/functions/_strip-units.scss | 5 + .../vendor/bourbon/functions/_tint-shade.scss | 9 + .../functions/_transition-property-name.scss | 22 + .../vendor/bourbon/functions/_unpack.scss | 17 + .../bourbon/helpers/_convert-units.scss | 15 + .../helpers/_gradient-positions-parser.scss | 13 + .../scss/vendor/bourbon/helpers/_is-num.scss | 8 + .../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 + .../vendor/bourbon/settings/_prefixer.scss | 6 + .../vendor/bourbon/settings/_px-to-em.scss | 1 + .../vendor/color-schemer/_color-schemer.scss | 31 + .../color-schemer/color-schemer/_cmyk.scss | 14 + .../color-schemer/_color-adjustments.scss | 30 + .../color-schemer/_color-schemer.scss | 208 + .../color-schemer/_colorblind.scss | 29 + .../color-schemer/_comparison.scss | 15 + .../color-schemer/_equalize.scss | 5 + .../color-schemer/_harmonize.scss | 59 + .../color-schemer/_interpolation.scss | 34 + .../color-schemer/color-schemer/_mix.scss | 40 + .../color-schemer/color-schemer/_mixins.scss | 29 + .../color-schemer/color-schemer/_ryb.scss | 76 + .../color-schemer/_tint-shade.scss | 9 + .../themes/grav/templates/changelog.html.twig | 21 + .../themes/grav/templates/config.html.twig | 82 + .../themes/grav/templates/dashboard.html.twig | 73 + .../themes/grav/templates/default.json.twig | 5 + .../themes/grav/templates/denied.html.twig | 18 + .../grav/templates/email/base.html.twig | 194 + .../themes/grav/templates/empty.html.twig | 0 .../themes/grav/templates/error.html.twig | 20 + .../themes/grav/templates/error.json.twig | 1 + .../themes/grav/templates/forgot.html.twig | 14 + .../grav/templates/forms/field.html.twig | 130 + .../fields/acl_picker/acl_picker.html.twig | 134 + .../forms/fields/array/array.html.twig | 96 + .../backupshistory/backupshistory.html.twig | 32 + .../fields/blueprint/blueprint.html.twig | 12 + .../fields/codemirror/codemirror.html.twig | 10 + .../fields/colorpicker/colorpicker.html.twig | 38 + .../colorscheme.color.html.twig | 40 + .../fields/colorscheme/colorscheme.html.twig | 12 + .../forms/fields/column/column.html.twig | 8 + .../forms/fields/columns/columns.html.twig | 8 + .../forms/fields/cron/cron.html.twig | 7 + .../fields/cronstatus/cronstatus.html.twig | 71 + .../fields/dateformat/dateformat.html.twig | 24 + .../forms/fields/datetime/datetime.html.twig | 27 + .../forms/fields/editor/editor.html.twig | 62 + .../forms/fields/element/element.html.twig | 23 + .../forms/fields/elements/elements.html.twig | 20 + .../forms/fields/fieldset/fieldset.html.twig | 81 + .../forms/fields/file/file.html.twig | 118 + .../fields/filepicker/filepicker.html.twig | 27 + .../fields/folder-slug/folder-slug.html.twig | 8 + .../fields/frontmatter/frontmatter.html.twig | 10 + .../fields/iconpicker/iconpicker.html.twig | 44 + .../forms/fields/iconpicker/icons.yaml | 6570 ++ .../forms/fields/list/list.html.twig | 188 + .../forms/fields/markdown/markdown.html.twig | 1 + .../fields/mediapicker/mediapicker.html.twig | 17 + .../fields/multilevel/multilevel.html.twig | 121 + .../forms/fields/order/order.html.twig | 68 + .../fields/pagemedia/pagemedia.html.twig | 65 + .../pagemediaselect/pagemediaselect.html.twig | 1 + .../forms/fields/parents/parents.html.twig | 58 + .../fields/permissions/permissions.html.twig | 161 + .../forms/fields/range/range.html.twig | 28 + .../forms/fields/section/section.html.twig | 24 + .../fields/selectize/selectize.html.twig | 19 + .../selectunique/selectunique.html.twig | 43 + .../forms/fields/taxonomy/taxonomy.html.twig | 39 + .../themepreview/themepreview.html.twig | 106 + .../fields/themeselect/themeselect.html.twig | 31 + .../forms/fields/userinfo/userinfo.html.twig | 19 + .../forms/fields/widgets/widgets.html.twig | 61 + .../templates/forms/fields/xss/xss.html.twig | 6 + .../themes/grav/templates/installer.html.twig | 13 + .../themes/grav/templates/login.html.twig | 11 + .../templates/media-list-content.html.twig | 19 + .../themes/grav/templates/pages.html.twig | 469 + .../partials/backups-button.html.twig | 21 + .../templates/partials/base-root.html.twig | 156 + .../grav/templates/partials/base.html.twig | 1 + .../partials/blueprints-copy.html.twig | 19 + .../partials/blueprints-new-folder.html.twig | 18 + .../partials/blueprints-new.html.twig | 19 + .../partials/blueprints-raw.html.twig | 22 + .../templates/partials/blueprints.html.twig | 34 + .../partials/dashboard-feed.html.twig | 14 + .../partials/dashboard-maintenance.html.twig | 33 + .../dashboard-notifications.html.twig | 13 + .../partials/dashboard-pages.html.twig | 18 + .../partials/dashboard-problems.html.twig | 11 + .../partials/dashboard-statistics.html.twig | 24 + .../templates/partials/feed-block.html.twig | 3 + .../grav/templates/partials/footer.html.twig | 5 + .../grav/templates/partials/header.html.twig | 11 + .../partials/javascript-config.html.twig | 43 + .../templates/partials/javascripts.html.twig | 11 + .../templates/partials/list-sort.html.twig | 13 + .../templates/partials/login-form.html.twig | 25 + .../templates/partials/login-logo.html.twig | 14 + .../templates/partials/login-logout.html.twig | 15 + .../templates/partials/login-twofa.html.twig | 20 + .../grav/templates/partials/login.html.twig | 33 + .../grav/templates/partials/logo.html.twig | 20 + .../partials/media-list-wrapper.html.twig | 32 + .../media-list-wrapper__list.html.twig | 23 + ...edia-list-wrapper__list__filters.html.twig | 28 + .../media-list-wrapper__sidebar.html.twig | 36 + .../templates/partials/messages.html.twig | 14 + .../partials/modal-add-package.html.twig | 89 + .../partials/modal-changelog.html.twig | 1 + .../partials/modal-changes-detected.html.twig | 13 + .../modal-reinstall-package.html.twig | 38 + .../partials/modal-remove-package.html.twig | 44 + .../partials/modal-switch-theme.html.twig | 16 + .../partials/modal-update-packages.html.twig | 89 + .../partials/nav-quick-tray.html.twig | 47 + .../templates/partials/nav-toggle.html.twig | 3 + .../partials/nav-user-avatar.html.twig | 2 + .../partials/nav-user-details.html.twig | 21 + .../grav/templates/partials/nav.html.twig | 47 + .../notification-dashboard-block.html.twig | 6 + .../notification-feed-block.html.twig | 3 + .../notification-plugins-block.html.twig | 6 + .../notification-themes-block.html.twig | 6 + .../partials/notification-top-block.html.twig | 6 + .../partials/page-children.html.twig | 11 + .../templates/partials/page-legend.html.twig | 11 + .../templates/partials/page-move.html.twig | 21 + .../templates/partials/plugin-data.html.twig | 74 + .../partials/plugins-details.html.twig | 76 + .../templates/partials/plugins-list.html.twig | 76 + .../templates/partials/register.html.twig | 24 + .../partials/release-toggle.html.twig | 11 + .../partials/spinning-wheel.html.twig | 3 + .../templates/partials/stylesheets.html.twig | 16 + .../grav/templates/partials/theme.html.twig | 13 + .../partials/themes-details.html.twig | 161 + .../templates/partials/themes-list.html.twig | 81 + .../partials/tools-backups-titlebar.html.twig | 7 + .../partials/tools-backups.html.twig | 81 + .../partials/tools-direct-install.html.twig | 29 + .../templates/partials/tools-logs.html.twig | 80 + .../partials/tools-reports.html.twig | 15 + .../tools-scheduler-titlebar.html.twig | 6 + .../partials/tools-scheduler.html.twig | 36 + .../partials/userinfo-avatar-credit.html.twig | 10 + .../partials/userinfo-avatar.html.twig | 2 + .../themes/grav/templates/plugins.html.twig | 94 + .../templates/plugins/admin-buttons.html.twig | 3 + .../themes/grav/templates/preview.html.twig | 24 + .../themes/grav/templates/register.html.twig | 24 + .../grav/templates/reports/security.html.twig | 20 + .../templates/reports/yamllinter.html.twig | 31 + .../themes/grav/templates/reset.html.twig | 14 + .../grav/templates/statistics.html.twig | 15 + .../themes/grav/templates/themes.html.twig | 87 + .../themes/grav/templates/tools.html.twig | 50 + .../grav/templates/unauthorized.html.twig | 1 + .../themes/grav/templates/user.html.twig | 63 + plugins/admin/themes/grav/theme.yaml | 0 plugins/admin/themes/grav/watch.sh | 27 + plugins/admin/themes/grav/webpack.conf.js | 58 + plugins/admin/themes/grav/yarn.lock | 3201 + plugins/admin/twig/AdminTwigExtension.php | 7 + plugins/admin/vendor/autoload.php | 25 + plugins/admin/vendor/bin/picofeed | 120 + plugins/admin/vendor/bin/pscss | 120 + plugins/admin/vendor/composer/ClassLoader.php | 585 + .../vendor/composer/InstalledVersions.php | 359 + 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 | 50 + .../admin/vendor/composer/autoload_static.php | 73 + plugins/admin/vendor/composer/installed.json | 278 + plugins/admin/vendor/composer/installed.php | 77 + .../admin/vendor/composer/platform_check.php | 26 + .../.github/workflows/auto-close.yml | 22 + .../workflows/continuous-integration.yml | 33 + .../workflows/release-on-milestone-closed.yml | 71 + .../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 + .../workflows/continuous-integration.yml | 32 + .../workflows/release-on-milestone-closed.yml | 61 + .../.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 + 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 + plugins/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 | 117 + .../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 | 10430 ++ .../scssphp/src/Compiler/CachedResult.php | 77 + .../scssphp/src/Compiler/Environment.php | 68 + .../src/Exception/CompilerException.php | 24 + .../scssphp/src/Exception/ParserException.php | 58 + .../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 | 377 + .../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 | 72 + .../scssphp/scssphp/src/Formatter/Nested.php | 238 + .../scssphp/src/Formatter/OutputBlock.php | 68 + .../scssphp/src/Logger/LoggerInterface.php | 48 + .../scssphp/src/Logger/QuietLogger.php | 29 + .../scssphp/src/Logger/StreamLogger.php | 62 + .../admin/vendor/scssphp/scssphp/src/Node.php | 43 + .../scssphp/scssphp/src/Node/Number.php | 834 + .../scssphp/scssphp/src/OutputStyle.php | 9 + .../vendor/scssphp/scssphp/src/Parser.php | 4205 + .../scssphp/scssphp/src/SourceMap/Base64.php | 187 + .../scssphp/src/SourceMap/Base64VLQ.php | 151 + .../src/SourceMap/SourceMapGenerator.php | 390 + .../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 + plugins/auto-author/.gitignore | 6 + plugins/auto-author/CHANGELOG.md | 5 + plugins/auto-author/LICENSE | 21 + plugins/auto-author/README.md | 62 + plugins/auto-author/auto-author.php | 54 + plugins/auto-author/auto-author.yaml | 2 + plugins/auto-author/blueprints.yaml | 39 + plugins/auto-date/CHANGELOG.md | 17 + plugins/auto-date/LICENSE | 21 + plugins/auto-date/README.md | 7 + plugins/auto-date/auto-date.php | 42 + plugins/auto-date/auto-date.yaml | 1 + plugins/auto-date/blueprints.yaml | 30 + plugins/autoseo/.gitignore | 41 + plugins/autoseo/CHANGELOG.md | 134 + plugins/autoseo/CODE_OF_CONDUCT.md | 46 + plugins/autoseo/CONTRIBUTING.md | 113 + plugins/autoseo/LICENSE | 21 + plugins/autoseo/README.md | 114 + plugins/autoseo/autoseo.php | 247 + plugins/autoseo/autoseo.yaml | 11 + plugins/autoseo/blueprints.yaml | 107 + plugins/autoseo/languages.yaml | 49 + plugins/childlist/CHANGELOG.md | 5 + plugins/childlist/LICENSE | 21 + plugins/childlist/README.md | 56 + plugins/childlist/blueprints.yaml | 36 + plugins/childlist/childlist.php | 64 + plugins/childlist/childlist.yaml | 3 + plugins/childlist/composer.json | 29 + plugins/childlist/composer.lock | 23 + plugins/childlist/languages.yaml | 4 + .../form/fields/childlist/childlist.html.twig | 9 + plugins/childlist/vendor/autoload.php | 7 + .../childlist/vendor/composer/ClassLoader.php | 445 + plugins/childlist/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 | 55 + .../vendor/composer/autoload_static.php | 36 + .../childlist/vendor/composer/installed.json | 1 + plugins/cookieconsent/.gitignore | 10 + plugins/cookieconsent/.scrutinizer.yml | 8 + plugins/cookieconsent/.travis.yml | 19 + plugins/cookieconsent/CHANGELOG.md | 35 + plugins/cookieconsent/LICENSE | 21 + plugins/cookieconsent/README.md | 111 + .../assets/cookieconsent.min.css | 6 + .../cookieconsent/assets/cookieconsent.min.js | 1 + plugins/cookieconsent/assets/readme_1.png | Bin 0 -> 276658 bytes plugins/cookieconsent/blueprints.yaml | 152 + plugins/cookieconsent/codeception.yml | 20 + plugins/cookieconsent/composer.json | 15 + plugins/cookieconsent/cookieconsent.php | 72 + plugins/cookieconsent/cookieconsent.yaml | 9 + plugins/cookieconsent/languages.yaml | 39 + .../partials/cookieconsent.html.twig | 27 + plugins/cookieconsent/tests/_bootstrap.php | 2 + .../cookieconsent/tests/_output/.gitignore | 2 + .../tests/_support/Helper/Unit.php | 9 + .../tests/_support/UnitTester.php | 26 + plugins/cookieconsent/tests/unit.suite.yml | 9 + .../tests/unit/CookieconsentPluginTest.php | 158 + .../cookieconsent/tests/unit/_bootstrap.php | 2 + plugins/devtools/CHANGELOG.md | 228 + plugins/devtools/LICENSE | 21 + plugins/devtools/README.md | 79 + plugins/devtools/blueprints.yaml | 41 + plugins/devtools/classes/DevToolsCommand.php | 380 + plugins/devtools/cli/NewBlueprintCommand.php | 88 + plugins/devtools/cli/NewPluginCommand.php | 168 + plugins/devtools/cli/NewThemeCommand.php | 177 + .../blueprint/append/blueprint.yaml.twig | 21 + .../blueprint/newtab/blueprint.yaml.twig | 15 + .../components/plugin/blank/CHANGELOG.md.twig | 5 + .../components/plugin/blank/LICENSE.twig | 21 + .../components/plugin/blank/README.md.twig | 59 + .../plugin/blank/blueprints.yaml.twig | 37 + .../components/plugin/blank/classes/.gitkeep | 0 .../plugin/blank/composer.json.twig | 25 + .../plugin/blank/languages.yaml.twig | 4 + .../components/plugin/blank/plugin.php.twig | 59 + .../components/plugin/blank/plugin.yaml.twig | 2 + .../components/plugin/flex/CHANGELOG.md.twig | 5 + .../components/plugin/flex/LICENSE.twig | 21 + .../components/plugin/flex/README.md.twig | 59 + .../plugin/flex/blueprints.yaml.twig | 37 + .../blueprints/flex-objects/plugin.yaml.twig | 132 + .../components/plugin/flex/classes/.gitkeep | 0 .../Flex/Types/flex_name/Collection.php.twig | 25 + .../Flex/Types/flex_name/Object.php.twig | 25 + .../components/plugin/flex/composer.json.twig | 25 + .../plugin/flex/languages.yaml.twig | 4 + .../components/plugin/flex/plugin.php.twig | 76 + .../components/plugin/flex/plugin.yaml.twig | 2 + .../theme/inheritance/CHANGELOG.md.twig | 5 + .../components/theme/inheritance/LICENSE.twig | 21 + .../theme/inheritance/README.md.twig | 7 + .../theme/inheritance/blueprints.yaml.twig | 19 + .../components/theme/inheritance/css/.gitkeep | 0 .../components/theme/inheritance/js/.gitkeep | 0 .../theme/inheritance/screenshot.jpg | Bin 0 -> 15428 bytes .../theme/inheritance/templates/.gitkeep | 0 .../theme/inheritance/theme.php.twig | 9 + .../theme/inheritance/theme.yaml.twig | 10 + .../theme/inheritance/thumbnail.jpg | Bin 0 -> 3681 bytes .../theme/pure-blank/CHANGELOG.md.twig | 5 + .../components/theme/pure-blank/LICENSE.twig | 21 + .../theme/pure-blank/README.md.twig | 7 + .../theme/pure-blank/blueprints.yaml.twig | 33 + .../theme/pure-blank/css/custom.css | 175 + .../theme/pure-blank/fonts/.gitkeep | 0 .../theme/pure-blank/images/logo.png | Bin 0 -> 8714 bytes .../components/theme/pure-blank/js/.gitkeep | 0 .../theme/pure-blank/screenshot.jpg | Bin 0 -> 15428 bytes .../pure-blank/templates/default.html.twig | 5 + .../pure-blank/templates/error.html.twig | 8 + .../templates/partials/base.html.twig | 70 + .../templates/partials/navigation.html.twig | 47 + .../theme/pure-blank/theme.php.twig | 9 + .../theme/pure-blank/theme.yaml.twig | 3 + .../components/theme/pure-blank/thumbnail.jpg | Bin 0 -> 3681 bytes .../theme/tailwind-mix/CHANGELOG.md.twig | 5 + .../theme/tailwind-mix/LICENSE.twig | 21 + .../theme/tailwind-mix/README.md.twig | 41 + .../theme/tailwind-mix/blueprints.yaml.twig | 43 + .../theme/tailwind-mix/css/site.css | 5 + .../theme/tailwind-mix/fonts/.gitkeep | 0 .../theme/tailwind-mix/images/logo.png | Bin 0 -> 8714 bytes .../components/theme/tailwind-mix/js/.gitkeep | 0 .../components/theme/tailwind-mix/js/main.js | 5 + .../theme/tailwind-mix/languages/en.yaml.twig | 2 + .../theme/tailwind-mix/package.json.twig | 25 + .../theme/tailwind-mix/screenshot.jpg | Bin 0 -> 15428 bytes .../tailwind-mix/tailwind.config.js.twig | 70 + .../tailwind-mix/templates/default.html.twig | 5 + .../tailwind-mix/templates/error.html.twig | 8 + .../templates/partials/base.html.twig | 68 + .../templates/partials/navigation.html.twig | 47 + .../theme/tailwind-mix/theme.php.twig | 9 + .../theme/tailwind-mix/theme.yaml.twig | 4 + .../theme/tailwind-mix/thumbnail.jpg | Bin 0 -> 3681 bytes .../theme/tailwind-mix/webpack.mix.js | 17 + .../theme/tailwind/CHANGELOG.md.twig | 5 + .../components/theme/tailwind/LICENSE.twig | 21 + .../components/theme/tailwind/README.md.twig | 41 + .../theme/tailwind/blueprints.yaml.twig | 43 + .../components/theme/tailwind/css/site.css | 5 + .../components/theme/tailwind/fonts/.gitkeep | 0 .../components/theme/tailwind/images/logo.png | Bin 0 -> 8714 bytes .../components/theme/tailwind/js/.gitkeep | 0 .../components/theme/tailwind/js/main.js | 5 + .../theme/tailwind/languages/en.yaml.twig | 2 + .../theme/tailwind/package-lock.json | 94 + .../theme/tailwind/package.json.twig | 25 + .../theme/tailwind/postcss.config.js | 10 + .../components/theme/tailwind/screenshot.jpg | Bin 0 -> 15428 bytes .../theme/tailwind/tailwind.config.js.twig | 22 + .../tailwind/templates/default.html.twig | 5 + .../theme/tailwind/templates/error.html.twig | 8 + .../templates/partials/base.html.twig | 68 + .../templates/partials/navigation.html.twig | 47 + .../components/theme/tailwind/theme.php.twig | 9 + .../components/theme/tailwind/theme.yaml.twig | 4 + .../components/theme/tailwind/thumbnail.jpg | Bin 0 -> 3681 bytes .../components/theme/tailwind/webpack.mix.js | 17 + plugins/devtools/devtools.php | 13 + plugins/devtools/devtools.yaml | 2 + plugins/devtools/languages.yaml | 7 + plugins/email/CHANGELOG.md | 378 + plugins/email/LICENSE | 21 + plugins/email/README.md | 502 + plugins/email/blueprints.yaml | 172 + plugins/email/classes/Email.php | 512 + plugins/email/classes/Message.php | 97 + plugins/email/classes/Utils.php | 48 + .../email/cli/ClearQueueFailuresCommand.php | 39 + plugins/email/cli/FlushQueueCommand.php | 39 + plugins/email/cli/TestEmailCommand.php | 105 + plugins/email/composer.json | 44 + plugins/email/composer.lock | 1342 + plugins/email/email.php | 187 + plugins/email/email.yaml | 15 + plugins/email/hebe.json | 15 + plugins/email/languages.yaml | 215 + plugins/email/templates/email/base.html.twig | 214 + plugins/email/vendor/autoload.php | 12 + plugins/email/vendor/composer/ClassLoader.php | 572 + .../vendor/composer/InstalledVersions.php | 352 + plugins/email/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 17 + .../email/vendor/composer/autoload_files.php | 13 + .../vendor/composer/autoload_namespaces.php | 9 + .../email/vendor/composer/autoload_psr4.php | 28 + .../email/vendor/composer/autoload_real.php | 57 + .../email/vendor/composer/autoload_static.php | 152 + plugins/email/vendor/composer/installed.json | 1378 + plugins/email/vendor/composer/installed.php | 215 + .../email/vendor/composer/platform_check.php | 26 + plugins/email/vendor/doctrine/lexer/LICENSE | 19 + plugins/email/vendor/doctrine/lexer/README.md | 9 + .../email/vendor/doctrine/lexer/composer.json | 41 + .../Doctrine/Common/Lexer/AbstractLexer.php | 337 + plugins/email/vendor/doctrine/lexer/psalm.xml | 15 + .../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 | 5028 + .../email-validator/src/EmailLexer.php | 339 + .../email-validator/src/EmailParser.php | 91 + .../email-validator/src/EmailValidator.php | 67 + .../email-validator/src/MessageIDParser.php | 92 + .../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 | 211 + .../email-validator/src/Parser/DomainPart.php | 312 + .../src/Parser/DoubleQuote.php | 88 + .../src/Parser/FoldingWhiteSpace.php | 86 + .../email-validator/src/Parser/IDLeftPart.php | 16 + .../src/Parser/IDRightPart.php | 29 + .../email-validator/src/Parser/LocalPart.php | 165 + .../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 | 192 + .../src/Validation/DNSGetRecordWrapper.php | 28 + .../src/Validation/DNSRecords.php | 35 + .../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 + plugins/email/vendor/psr/container/.gitignore | 3 + plugins/email/vendor/psr/container/LICENSE | 21 + plugins/email/vendor/psr/container/README.md | 13 + .../email/vendor/psr/container/composer.json | 22 + .../src/ContainerExceptionInterface.php | 10 + .../psr/container/src/ContainerInterface.php | 36 + .../src/NotFoundExceptionInterface.php | 10 + .../vendor/psr/event-dispatcher/.editorconfig | 15 + .../vendor/psr/event-dispatcher/.gitignore | 2 + .../email/vendor/psr/event-dispatcher/LICENSE | 21 + .../vendor/psr/event-dispatcher/README.md | 6 + .../vendor/psr/event-dispatcher/composer.json | 26 + .../src/EventDispatcherInterface.php | 21 + .../src/ListenerProviderInterface.php | 19 + .../src/StoppableEventInterface.php | 26 + .../symfony/amqp-messenger/CHANGELOG.md | 21 + .../vendor/symfony/amqp-messenger/LICENSE | 19 + .../vendor/symfony/amqp-messenger/README.md | 12 + .../amqp-messenger/Transport/AmqpFactory.php | 39 + .../Transport/AmqpReceivedStamp.php | 43 + .../amqp-messenger/Transport/AmqpReceiver.php | 150 + .../amqp-messenger/Transport/AmqpSender.php | 86 + .../amqp-messenger/Transport/AmqpStamp.php | 94 + .../Transport/AmqpTransport.php | 107 + .../Transport/AmqpTransportFactory.php | 38 + .../amqp-messenger/Transport/Connection.php | 583 + .../symfony/amqp-messenger/composer.json | 36 + .../symfony/deprecation-contracts/.gitignore | 3 + .../deprecation-contracts/CHANGELOG.md | 5 + .../symfony/deprecation-contracts/LICENSE | 19 + .../symfony/deprecation-contracts/README.md | 26 + .../deprecation-contracts/composer.json | 35 + .../deprecation-contracts/function.php | 27 + .../symfony/doctrine-messenger/CHANGELOG.md | 8 + .../vendor/symfony/doctrine-messenger/LICENSE | 19 + .../symfony/doctrine-messenger/README.md | 12 + .../Transport/Connection.php | 508 + .../Transport/DoctrineReceivedStamp.php | 36 + .../Transport/DoctrineReceiver.php | 175 + .../Transport/DoctrineSender.php | 60 + .../Transport/DoctrineTransport.php | 135 + .../Transport/DoctrineTransportFactory.php | 68 + .../Transport/PostgreSqlConnection.php | 150 + .../symfony/doctrine-messenger/composer.json | 40 + .../event-dispatcher-contracts/.gitignore | 3 + .../event-dispatcher-contracts/CHANGELOG.md | 5 + .../event-dispatcher-contracts/Event.php | 54 + .../EventDispatcherInterface.php | 31 + .../event-dispatcher-contracts/LICENSE | 19 + .../event-dispatcher-contracts/README.md | 9 + .../event-dispatcher-contracts/composer.json | 38 + .../Attribute/AsEventListener.php | 29 + .../symfony/event-dispatcher/CHANGELOG.md | 91 + .../Debug/TraceableEventDispatcher.php | 366 + .../Debug/WrappedListener.php | 127 + .../AddEventAliasesPass.php | 46 + .../RegisterListenersPass.php | 238 + .../event-dispatcher/EventDispatcher.php | 280 + .../EventDispatcherInterface.php | 70 + .../EventSubscriberInterface.php | 49 + .../symfony/event-dispatcher/GenericEvent.php | 182 + .../ImmutableEventDispatcher.php | 91 + .../vendor/symfony/event-dispatcher/LICENSE | 19 + .../LegacyEventDispatcherProxy.php | 31 + .../vendor/symfony/event-dispatcher/README.md | 15 + .../symfony/event-dispatcher/composer.json | 52 + .../email/vendor/symfony/mailer/CHANGELOG.md | 61 + .../DataCollector/MessageDataCollector.php | 68 + .../vendor/symfony/mailer/DelayedEnvelope.php | 98 + .../email/vendor/symfony/mailer/Envelope.php | 88 + .../symfony/mailer/Event/MessageEvent.php | 67 + .../symfony/mailer/Event/MessageEvents.php | 67 + .../mailer/EventListener/EnvelopeListener.php | 68 + .../mailer/EventListener/MessageListener.php | 134 + .../EventListener/MessageLoggerListener.php | 57 + .../mailer/Exception/ExceptionInterface.php | 21 + .../Exception/HttpTransportException.php | 40 + .../Exception/IncompleteDsnException.php | 19 + .../Exception/InvalidArgumentException.php | 19 + .../mailer/Exception/LogicException.php | 19 + .../mailer/Exception/RuntimeException.php | 19 + .../mailer/Exception/TransportException.php | 30 + .../Exception/TransportExceptionInterface.php | 22 + .../Exception/UnsupportedSchemeException.php | 81 + .../symfony/mailer/Header/MetadataHeader.php | 34 + .../symfony/mailer/Header/TagHeader.php | 25 + plugins/email/vendor/symfony/mailer/LICENSE | 19 + .../email/vendor/symfony/mailer/Mailer.php | 73 + .../vendor/symfony/mailer/MailerInterface.php | 30 + .../mailer/Messenger/MessageHandler.php | 33 + .../mailer/Messenger/SendEmailMessage.php | 40 + plugins/email/vendor/symfony/mailer/README.md | 74 + .../vendor/symfony/mailer/SentMessage.php | 95 + .../mailer/Test/Constraint/EmailCount.php | 73 + .../mailer/Test/Constraint/EmailIsQueued.php | 46 + .../mailer/Test/TransportFactoryTestCase.php | 117 + .../email/vendor/symfony/mailer/Transport.php | 206 + .../mailer/Transport/AbstractApiTransport.php | 46 + .../Transport/AbstractHttpTransport.php | 79 + .../mailer/Transport/AbstractTransport.php | 110 + .../Transport/AbstractTransportFactory.php | 61 + .../vendor/symfony/mailer/Transport/Dsn.php | 89 + .../mailer/Transport/FailoverTransport.php | 41 + .../Transport/NativeTransportFactory.php | 63 + .../mailer/Transport/NullTransport.php | 31 + .../mailer/Transport/NullTransportFactory.php | 34 + .../mailer/Transport/RoundRobinTransport.php | 121 + .../mailer/Transport/SendmailTransport.php | 123 + .../Transport/SendmailTransportFactory.php | 34 + .../Smtp/Auth/AuthenticatorInterface.php | 35 + .../Smtp/Auth/CramMd5Authenticator.php | 62 + .../Smtp/Auth/LoginAuthenticator.php | 39 + .../Smtp/Auth/PlainAuthenticator.php | 37 + .../Smtp/Auth/XOAuth2Authenticator.php | 39 + .../mailer/Transport/Smtp/EsmtpTransport.php | 200 + .../Transport/Smtp/EsmtpTransportFactory.php | 70 + .../mailer/Transport/Smtp/SmtpTransport.php | 361 + .../Transport/Smtp/Stream/AbstractStream.php | 138 + .../Transport/Smtp/Stream/ProcessStream.php | 65 + .../Transport/Smtp/Stream/SocketStream.php | 193 + .../Transport/TransportFactoryInterface.php | 29 + .../mailer/Transport/TransportInterface.php | 35 + .../symfony/mailer/Transport/Transports.php | 75 + .../email/vendor/symfony/mailer/composer.json | 43 + .../messenger/Attribute/AsMessageHandler.php | 30 + .../vendor/symfony/messenger/CHANGELOG.md | 212 + .../Command/AbstractFailedMessagesCommand.php | 298 + .../Command/ConsumeMessagesCommand.php | 267 + .../messenger/Command/DebugCommand.php | 150 + .../Command/FailedMessagesRemoveCommand.php | 104 + .../Command/FailedMessagesRetryCommand.php | 226 + .../Command/FailedMessagesShowCommand.php | 153 + .../Command/SetupTransportsCommand.php | 95 + .../messenger/Command/StopWorkersCommand.php | 75 + .../DataCollector/MessengerDataCollector.php | 149 + .../DependencyInjection/MessengerPass.php | 402 + .../vendor/symfony/messenger/Envelope.php | 131 + .../Event/AbstractWorkerMessageEvent.php | 45 + .../Event/SendMessageToTransportsEvent.php | 45 + .../Event/WorkerMessageFailedEvent.php | 47 + .../Event/WorkerMessageHandledEvent.php | 21 + .../Event/WorkerMessageReceivedEvent.php | 31 + .../Event/WorkerMessageRetriedEvent.php | 21 + .../messenger/Event/WorkerRunningEvent.php | 44 + .../messenger/Event/WorkerStartedEvent.php | 34 + .../messenger/Event/WorkerStoppedEvent.php | 34 + .../AddErrorDetailsStampListener.php | 38 + .../DispatchPcntlSignalListener.php | 37 + .../EventListener/ResetServicesListener.php | 50 + .../SendFailedMessageForRetryListener.php | 173 + ...ailedMessageToFailureTransportListener.php | 104 + ...topWorkerOnCustomStopExceptionListener.php | 57 + .../StopWorkerOnFailureLimitListener.php | 63 + .../StopWorkerOnMemoryLimitListener.php | 55 + .../StopWorkerOnMessageLimitListener.php | 57 + .../StopWorkerOnRestartSignalListener.php | 71 + .../StopWorkerOnSigtermSignalListener.php | 51 + .../StopWorkerOnTimeLimitListener.php | 58 + .../DelayedMessageHandlingException.php | 48 + .../Exception/ExceptionInterface.php | 21 + .../Exception/HandlerFailedException.php | 67 + .../Exception/InvalidArgumentException.php | 19 + .../messenger/Exception/LogicException.php | 19 + .../MessageDecodingFailedException.php | 19 + .../NoHandlerForMessageException.php | 19 + .../RecoverableExceptionInterface.php | 24 + .../RecoverableMessageHandlingException.php | 21 + .../RejectRedeliveredMessageException.php | 19 + .../messenger/Exception/RuntimeException.php | 19 + .../Exception/StopWorkerException.php | 23 + .../StopWorkerExceptionInterface.php | 19 + .../Exception/TransportException.php | 19 + .../UnrecoverableExceptionInterface.php | 24 + .../UnrecoverableMessageHandlingException.php | 21 + .../Exception/ValidationFailedException.php | 41 + .../vendor/symfony/messenger/HandleTrait.php | 61 + .../messenger/Handler/Acknowledger.php | 83 + .../Handler/BatchHandlerInterface.php | 34 + .../messenger/Handler/BatchHandlerTrait.php | 75 + .../messenger/Handler/HandlerDescriptor.php | 78 + .../messenger/Handler/HandlersLocator.php | 89 + .../Handler/HandlersLocatorInterface.php | 29 + .../Handler/MessageHandlerInterface.php | 21 + .../Handler/MessageSubscriberInterface.php | 49 + .../email/vendor/symfony/messenger/LICENSE | 19 + .../vendor/symfony/messenger/MessageBus.php | 79 + .../symfony/messenger/MessageBusInterface.php | 28 + .../Middleware/ActivationMiddleware.php | 46 + .../Middleware/AddBusNameStampMiddleware.php | 39 + .../DispatchAfterCurrentBusMiddleware.php | 133 + .../FailedMessageProcessingMiddleware.php | 36 + .../Middleware/HandleMessageMiddleware.php | 145 + .../Middleware/MiddlewareInterface.php | 22 + .../RejectRedeliveredMessageMiddleware.php | 50 + .../Middleware/RouterContextMiddleware.php | 88 + .../Middleware/SendMessageMiddleware.php | 79 + .../messenger/Middleware/StackInterface.php | 25 + .../messenger/Middleware/StackMiddleware.php | 92 + .../Middleware/TraceableMiddleware.php | 97 + .../Middleware/ValidationMiddleware.php | 50 + .../email/vendor/symfony/messenger/README.md | 29 + .../Retry/MultiplierRetryStrategy.php | 91 + .../Retry/RetryStrategyInterface.php | 34 + .../symfony/messenger/RoutableMessageBus.php | 68 + .../symfony/messenger/Stamp/AckStamp.php | 35 + .../symfony/messenger/Stamp/BusNameStamp.php | 32 + .../messenger/Stamp/ConsumedByWorkerStamp.php | 19 + .../symfony/messenger/Stamp/DelayStamp.php | 46 + .../Stamp/DispatchAfterCurrentBusStamp.php | 23 + .../messenger/Stamp/ErrorDetailsStamp.php | 96 + .../Stamp/FlushBatchHandlersStamp.php | 30 + .../symfony/messenger/Stamp/HandledStamp.php | 62 + .../messenger/Stamp/NoAutoAckStamp.php | 32 + .../Stamp/NonSendableStampInterface.php | 21 + .../symfony/messenger/Stamp/ReceivedStamp.php | 39 + .../messenger/Stamp/RedeliveryStamp.php | 92 + .../messenger/Stamp/RouterContextStamp.php | 79 + .../symfony/messenger/Stamp/SentStamp.php | 41 + .../Stamp/SentToFailureTransportStamp.php | 32 + .../messenger/Stamp/SerializerStamp.php | 30 + .../messenger/Stamp/StampInterface.php | 23 + .../Stamp/TransportMessageIdStamp.php | 35 + .../messenger/Stamp/ValidationStamp.php | 35 + .../Test/Middleware/MiddlewareTestCase.php | 60 + .../symfony/messenger/TraceableMessageBus.php | 108 + .../Transport/AmqpExt/AmqpFactory.php | 27 + .../Transport/AmqpExt/AmqpReceivedStamp.php | 27 + .../Transport/AmqpExt/AmqpReceiver.php | 27 + .../Transport/AmqpExt/AmqpSender.php | 27 + .../messenger/Transport/AmqpExt/AmqpStamp.php | 27 + .../Transport/AmqpExt/AmqpTransport.php | 27 + .../AmqpExt/AmqpTransportFactory.php | 27 + .../Transport/AmqpExt/Connection.php | 27 + .../Transport/Doctrine/Connection.php | 27 + .../Doctrine/DoctrineReceivedStamp.php | 27 + .../Transport/Doctrine/DoctrineReceiver.php | 27 + .../Transport/Doctrine/DoctrineSender.php | 27 + .../Transport/Doctrine/DoctrineTransport.php | 27 + .../Doctrine/DoctrineTransportFactory.php | 27 + .../messenger/Transport/InMemoryTransport.php | 166 + .../Transport/InMemoryTransportFactory.php | 57 + .../Receiver/ListableReceiverInterface.php | 40 + .../Receiver/MessageCountAwareInterface.php | 26 + .../Receiver/QueueReceiverInterface.php | 31 + .../Transport/Receiver/ReceiverInterface.php | 61 + .../Receiver/SingleMessageReceiver.php | 55 + .../Transport/RedisExt/Connection.php | 27 + .../Transport/RedisExt/RedisReceivedStamp.php | 27 + .../Transport/RedisExt/RedisReceiver.php | 27 + .../Transport/RedisExt/RedisSender.php | 27 + .../Transport/RedisExt/RedisTransport.php | 27 + .../RedisExt/RedisTransportFactory.php | 27 + .../Transport/Sender/SenderInterface.php | 30 + .../Transport/Sender/SendersLocator.php | 60 + .../Sender/SendersLocatorInterface.php | 30 + .../Normalizer/FlattenExceptionNormalizer.php | 100 + .../Transport/Serialization/PhpSerializer.php | 92 + .../Transport/Serialization/Serializer.php | 183 + .../Serialization/SerializerInterface.php | 48 + .../Transport/SetupableTransportInterface.php | 23 + .../Transport/Sync/SyncTransport.php | 65 + .../Transport/Sync/SyncTransportFactory.php | 40 + .../messenger/Transport/TransportFactory.php | 67 + .../Transport/TransportFactoryInterface.php | 26 + .../Transport/TransportInterface.php | 22 + .../email/vendor/symfony/messenger/Worker.php | 268 + .../symfony/messenger/WorkerMetadata.php | 47 + .../vendor/symfony/messenger/composer.json | 57 + plugins/email/vendor/symfony/mime/Address.php | 149 + .../symfony/mime/BodyRendererInterface.php | 20 + .../email/vendor/symfony/mime/CHANGELOG.md | 26 + .../vendor/symfony/mime/CharacterStream.php | 218 + .../symfony/mime/Crypto/DkimOptions.php | 97 + .../vendor/symfony/mime/Crypto/DkimSigner.php | 220 + .../vendor/symfony/mime/Crypto/SMime.php | 111 + .../symfony/mime/Crypto/SMimeEncrypter.php | 63 + .../symfony/mime/Crypto/SMimeSigner.php | 65 + .../AddMimeTypeGuesserPass.php | 50 + plugins/email/vendor/symfony/mime/Email.php | 630 + .../mime/Encoder/AddressEncoderInterface.php | 28 + .../mime/Encoder/Base64ContentEncoder.php | 45 + .../symfony/mime/Encoder/Base64Encoder.php | 41 + .../mime/Encoder/Base64MimeHeaderEncoder.php | 43 + .../mime/Encoder/ContentEncoderInterface.php | 30 + .../mime/Encoder/EightBitContentEncoder.php | 35 + .../symfony/mime/Encoder/EncoderInterface.php | 26 + .../mime/Encoder/IdnAddressEncoder.php | 44 + .../Encoder/MimeHeaderEncoderInterface.php | 23 + .../symfony/mime/Encoder/QpContentEncoder.php | 60 + .../vendor/symfony/mime/Encoder/QpEncoder.php | 195 + .../mime/Encoder/QpMimeHeaderEncoder.php | 40 + .../symfony/mime/Encoder/Rfc2231Encoder.php | 50 + .../Exception/AddressEncoderException.php | 19 + .../mime/Exception/ExceptionInterface.php | 19 + .../Exception/InvalidArgumentException.php | 19 + .../symfony/mime/Exception/LogicException.php | 19 + .../mime/Exception/RfcComplianceException.php | 19 + .../mime/Exception/RuntimeException.php | 19 + .../mime/FileBinaryMimeTypeGuesser.php | 93 + .../symfony/mime/FileinfoMimeTypeGuesser.php | 69 + .../symfony/mime/Header/AbstractHeader.php | 284 + .../vendor/symfony/mime/Header/DateHeader.php | 66 + .../symfony/mime/Header/HeaderInterface.php | 65 + .../vendor/symfony/mime/Header/Headers.php | 307 + .../mime/Header/IdentificationHeader.php | 110 + .../symfony/mime/Header/MailboxHeader.php | 85 + .../symfony/mime/Header/MailboxListHeader.php | 136 + .../mime/Header/ParameterizedHeader.php | 191 + .../vendor/symfony/mime/Header/PathHeader.php | 62 + .../mime/Header/UnstructuredHeader.php | 69 + plugins/email/vendor/symfony/mime/LICENSE | 19 + plugins/email/vendor/symfony/mime/Message.php | 160 + .../vendor/symfony/mime/MessageConverter.php | 125 + .../symfony/mime/MimeTypeGuesserInterface.php | 33 + .../email/vendor/symfony/mime/MimeTypes.php | 3537 + .../symfony/mime/MimeTypesInterface.php | 32 + .../mime/Part/AbstractMultipartPart.php | 99 + .../vendor/symfony/mime/Part/AbstractPart.php | 65 + .../vendor/symfony/mime/Part/DataPart.php | 183 + .../vendor/symfony/mime/Part/MessagePart.php | 62 + .../mime/Part/Multipart/AlternativePart.php | 25 + .../mime/Part/Multipart/DigestPart.php | 31 + .../mime/Part/Multipart/FormDataPart.php | 112 + .../symfony/mime/Part/Multipart/MixedPart.php | 25 + .../mime/Part/Multipart/RelatedPart.php | 55 + .../vendor/symfony/mime/Part/SMimePart.php | 121 + .../vendor/symfony/mime/Part/TextPart.php | 215 + plugins/email/vendor/symfony/mime/README.md | 13 + .../email/vendor/symfony/mime/RawMessage.php | 91 + .../mime/Resources/bin/update_mime_types.php | 161 + .../Test/Constraint/EmailAddressContains.php | 74 + .../Test/Constraint/EmailAttachmentCount.php | 60 + .../mime/Test/Constraint/EmailHasHeader.php | 57 + .../mime/Test/Constraint/EmailHeaderSame.php | 69 + .../Test/Constraint/EmailHtmlBodyContains.php | 58 + .../Test/Constraint/EmailTextBodyContains.php | 58 + .../email/vendor/symfony/mime/composer.json | 46 + .../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-php80/LICENSE | 19 + .../vendor/symfony/polyfill-php80/Php80.php | 115 + .../symfony/polyfill-php80/PhpToken.php | 103 + .../vendor/symfony/polyfill-php80/README.md | 25 + .../Resources/stubs/Attribute.php | 22 + .../Resources/stubs/PhpToken.php | 7 + .../Resources/stubs/Stringable.php | 11 + .../Resources/stubs/UnhandledMatchError.php | 7 + .../Resources/stubs/ValueError.php | 7 + .../symfony/polyfill-php80/bootstrap.php | 42 + .../symfony/polyfill-php80/composer.json | 40 + .../symfony/redis-messenger/CHANGELOG.md | 34 + .../vendor/symfony/redis-messenger/LICENSE | 19 + .../vendor/symfony/redis-messenger/README.md | 12 + .../redis-messenger/Transport/Connection.php | 596 + .../Transport/RedisClusterProxy.php | 42 + .../redis-messenger/Transport/RedisProxy.php | 43 + .../Transport/RedisReceivedStamp.php | 36 + .../Transport/RedisReceiver.php | 102 + .../redis-messenger/Transport/RedisSender.php | 53 + .../Transport/RedisTransport.php | 90 + .../Transport/RedisTransportFactory.php | 39 + .../symfony/redis-messenger/composer.json | 34 + .../symfony/service-contracts/.gitignore | 3 + .../service-contracts/Attribute/Required.php | 25 + .../Attribute/SubscribedService.php | 33 + .../symfony/service-contracts/CHANGELOG.md | 5 + .../vendor/symfony/service-contracts/LICENSE | 19 + .../symfony/service-contracts/README.md | 9 + .../service-contracts/ResetInterface.php | 30 + .../service-contracts/ServiceLocatorTrait.php | 128 + .../ServiceProviderInterface.php | 36 + .../ServiceSubscriberInterface.php | 53 + .../ServiceSubscriberTrait.php | 109 + .../Test/ServiceLocatorTest.php | 95 + .../symfony/service-contracts/composer.json | 42 + plugins/error/.gitignore | 9 + plugins/error/CHANGELOG.md | 91 + plugins/error/LICENSE | 21 + plugins/error/README.md | 93 + plugins/error/assets/readme_1.png | Bin 0 -> 41685 bytes plugins/error/blueprints.yaml | 36 + plugins/error/cli/LogCommand.php | 130 + plugins/error/composer.json | 39 + plugins/error/error.php | 117 + plugins/error/error.yaml | 3 + plugins/error/hebe.json | 15 + plugins/error/languages.yaml | 55 + plugins/error/templates/error.html.twig | 3 + plugins/error/templates/error.json.twig | 1 + plugins/error/vendor/autoload.php | 7 + plugins/error/vendor/composer/ClassLoader.php | 445 + 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 + plugins/error/vendor/composer/installed.json | 1 + plugins/flex-objects/.eslintrc | 170 + plugins/flex-objects/.gitignore | 3 + plugins/flex-objects/CHANGELOG.md | 550 + plugins/flex-objects/LICENSE | 21 + 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 + .../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 | 36 + plugins/flex-objects/app/columns/finder.js | 425 + plugins/flex-objects/app/columns/index.js | 102 + plugins/flex-objects/app/filters/index.js | 46 + plugins/flex-objects/app/filters/panel.js | 15 + 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 + plugins/flex-objects/app/list/index.js | 19 + plugins/flex-objects/app/main.js | 3 + plugins/flex-objects/app/utils/finder.js | 393 + plugins/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 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 | 1911 + .../Controllers/AbstractController.php | 361 + .../classes/Controllers/MediaController.php | 675 + .../classes/Controllers/ObjectController.php | 543 + .../classes/Events/FlexTaskEvent.php | 84 + plugins/flex-objects/classes/Flex.php | 444 + .../flex-objects/classes/FlexFormFactory.php | 80 + plugins/flex-objects/classes/FlexRouter.php | 64 + .../flex-objects/classes/Table/DataTable.php | 410 + .../cli/FlexConvertDataCommand.php | 141 + plugins/flex-objects/composer.json | 32 + plugins/flex-objects/composer.lock | 25 + plugins/flex-objects/css/admin.css | 97 + plugins/flex-objects/css/admin.css.map | 11 + plugins/flex-objects/css/admin.min.css | 1 + plugins/flex-objects/css/site.css | 27 + plugins/flex-objects/css/site.css.map | 11 + plugins/flex-objects/css/site.min.css | 1 + plugins/flex-objects/flex-objects.php | 805 + plugins/flex-objects/flex-objects.yaml | 14 + plugins/flex-objects/js/flex-objects.js | 905 + plugins/flex-objects/js/list.min.js | 2 + plugins/flex-objects/languages/de.yaml | 73 + plugins/flex-objects/languages/en.yaml | 73 + plugins/flex-objects/languages/es.yaml | 73 + plugins/flex-objects/languages/ja.yaml | 73 + plugins/flex-objects/languages/nl.yaml | 71 + plugins/flex-objects/languages/ru.yaml | 12 + plugins/flex-objects/package.json | 51 + plugins/flex-objects/permissions.yaml | 45 + plugins/flex-objects/scss/_preset.scss | 69 + plugins/flex-objects/scss/admin.scss | 3 + plugins/flex-objects/scss/plugin/_admin.scss | 215 + plugins/flex-objects/scss/plugin/_site.scss | 68 + 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 | 95 + .../forms/fields/pagemedia/template.html.twig | 33 + plugins/flex-objects/vendor/autoload.php | 7 + .../vendor/composer/ClassLoader.php | 572 + .../vendor/composer/InstalledVersions.php | 350 + plugins/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 + plugins/flex-objects/watch.sh | 27 + plugins/flex-objects/webpack.conf.js | 75 + plugins/flex-objects/yarn.lock | 3271 + plugins/form/.eslintrc | 165 + plugins/form/.gitignore | 5 + plugins/form/CHANGELOG.md | 1271 + plugins/form/LICENSE | 21 + plugins/form/README.md | 41 + plugins/form/app/fields/array.js | 200 + plugins/form/app/fields/file.js | 340 + plugins/form/app/fields/form.js | 94 + plugins/form/app/fields/index.js | 7 + plugins/form/app/fields/media.js | 174 + plugins/form/app/fields/tabs.js | 14 + plugins/form/app/main.js | 4 + plugins/form/app/utils/keep-alive.js | 17 + plugins/form/assets/dropzone.min.css | 1 + plugins/form/assets/form-styles.css | 1 + plugins/form/assets/form-styles.css.map | 1 + plugins/form/assets/form-styles.min.css | 1 + plugins/form/assets/form.min.js | 41 + plugins/form/assets/form.vendor.js | 24 + plugins/form/assets/object.assign.polyfill.js | 29 + plugins/form/assets/signature_pad.js | 617 + plugins/form/blueprints.yaml | 345 + plugins/form/classes/BasicCaptcha.php | 122 + plugins/form/classes/Form.php | 1422 + plugins/form/classes/FormFactory.php | 38 + plugins/form/classes/Forms.php | 129 + plugins/form/classes/TwigExtension.php | 163 + plugins/form/composer.json | 40 + plugins/form/composer.lock | 77 + plugins/form/fonts/zxx-camo.ttf | Bin 0 -> 32032 bytes plugins/form/fonts/zxx-noise.ttf | Bin 0 -> 23404 bytes plugins/form/fonts/zxx-sans.ttf | Bin 0 -> 13548 bytes plugins/form/fonts/zxx-xed.ttf | Bin 0 -> 21720 bytes plugins/form/form.php | 1311 + plugins/form/form.yaml | 41 + plugins/form/gulpfile.js | 84 + plugins/form/hebe.json | 15 + plugins/form/languages.yaml | 914 + plugins/form/package.json | 45 + plugins/form/scss.sh | 2 + plugins/form/scss/form-styles.scss | 315 + .../form/templates/form-messages.html.twig | 2 + .../form/templates/form-messages.json.twig | 2 + plugins/form/templates/form.html.twig | 8 + plugins/form/templates/form.json.twig | 1 + plugins/form/templates/formdata.html.twig | 20 + plugins/form/templates/forms/ajax.json.twig | 5 + plugins/form/templates/forms/data.html.twig | 1 + plugins/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 + plugins/form/templates/forms/field.html.twig | 9 + .../forms/fields/array/array.html.twig | 99 + .../forms/fields/avatar/avatar.html.twig | 10 + .../basic-captcha/basic-captcha.html.twig | 28 + .../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 | 78 + .../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 + .../fields/turnstile/turnstile.html.twig | 15 + .../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 + plugins/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 + plugins/form/templates/modular/form.html.twig | 4 + .../partials/form-messages.html.twig | 6 + .../partials/form-messages.json.twig | 3 + plugins/form/vendor/autoload.php | 7 + plugins/form/vendor/composer/ClassLoader.php | 572 + .../vendor/composer/InstalledVersions.php | 350 + 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 + plugins/form/vendor/composer/installed.json | 61 + plugins/form/vendor/composer/installed.php | 32 + .../form/vendor/composer/platform_check.php | 26 + .../.github/ISSUE_TEMPLATE/bug_report.md | 28 + .../form/vendor/google/recaptcha/.gitignore | 7 + .../form/vendor/google/recaptcha/.travis.yml | 33 + .../vendor/google/recaptcha/ARCHITECTURE.md | 64 + .../vendor/google/recaptcha/CONTRIBUTING.md | 49 + plugins/form/vendor/google/recaptcha/LICENSE | 29 + .../form/vendor/google/recaptcha/README.md | 140 + plugins/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 + plugins/form/webpack.conf.js | 65 + plugins/form/yarn.lock | 7407 ++ plugins/langswitcher/CHANGELOG.md | 130 + plugins/langswitcher/LICENSE | 21 + plugins/langswitcher/README.md | 128 + plugins/langswitcher/assets/readme_1.png | Bin 0 -> 38637 bytes plugins/langswitcher/blueprints.yaml | 73 + plugins/langswitcher/composer.json | 29 + plugins/langswitcher/composer.lock | 24 + plugins/langswitcher/css/langswitcher.css | 22 + plugins/langswitcher/langswitcher.php | 180 + plugins/langswitcher/langswitcher.yaml | 5 + plugins/langswitcher/languages.yaml | 35 + .../partials/langswitcher-logic.html.twig | 29 + .../partials/langswitcher-long.html.twig | 1 + .../partials/langswitcher-short.html.twig | 1 + .../partials/langswitcher.hreflang.html.twig | 16 + .../templates/partials/langswitcher.html.twig | 15 + plugins/langswitcher/vendor/autoload.php | 7 + .../vendor/composer/ClassLoader.php | 445 + plugins/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 + plugins/login/.gitignore | 2 + plugins/login/CHANGELOG.md | 898 + plugins/login/LICENSE | 21 + plugins/login/README.md | 556 + plugins/login/blueprints.yaml | 462 + plugins/login/classes/Controller.php | 721 + plugins/login/classes/Email.php | 294 + .../classes/Events/PageAuthorizeEvent.php | 136 + .../login/classes/Events/UserLoginEvent.php | 397 + .../login/classes/Invitations/Invitation.php | 59 + .../login/classes/Invitations/Invitations.php | 165 + plugins/login/classes/Login.php | 834 + plugins/login/classes/LoginCache.php | 105 + plugins/login/classes/RateLimiter.php | 110 + .../login/classes/RememberMe/RememberMe.php | 43 + .../login/classes/RememberMe/TokenStorage.php | 172 + .../classes/TwoFactorAuth/BaconQrProvider.php | 36 + .../classes/TwoFactorAuth/TwoFactorAuth.php | 118 + plugins/login/cli/ChangePasswordCommand.php | 177 + plugins/login/cli/ChangeUserStateCommand.php | 157 + plugins/login/cli/LookupUserCommand.php | 94 + plugins/login/cli/NewUserCommand.php | 324 + plugins/login/composer.json | 49 + plugins/login/composer.lock | 301 + plugins/login/css/login.css | 86 + plugins/login/hebe.json | 15 + plugins/login/js/2fa.js | 34 + plugins/login/languages/de.yaml | 136 + plugins/login/languages/en.yaml | 159 + plugins/login/languages/es.yaml | 124 + plugins/login/languages/fr.yaml | 95 + plugins/login/languages/hr.yaml | 54 + plugins/login/languages/hu.yaml | 35 + plugins/login/languages/lt.yaml | 151 + plugins/login/languages/no.yaml | 71 + plugins/login/languages/pt-BR.yaml | 133 + plugins/login/languages/ro.yaml | 97 + plugins/login/languages/ru.yaml | 142 + plugins/login/languages/uk.yaml | 142 + plugins/login/languages/zh.yaml | 133 + plugins/login/login.php | 1341 + plugins/login/login.yaml | 63 + .../templates/emails/login/activate.html.twig | 42 + .../templates/emails/login/invite.html.twig | 46 + .../emails/login/magic-login.html.twig | 46 + .../emails/login/notification.html.twig | 30 + .../emails/login/reset-password.html.twig | 42 + .../templates/emails/login/welcome.html.twig | 41 + plugins/login/templates/forgot.html.twig | 6 + .../fields/2fa_secret/2fa_secret.html.twig | 31 + plugins/login/templates/login.html.twig | 6 + 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 + plugins/login/templates/profile.html.twig | 9 + plugins/login/templates/profile.json.twig | 1 + plugins/login/templates/register.html.twig | 1 + plugins/login/templates/reset.html.twig | 8 + .../login/templates/unauthorized.html.twig | 1 + plugins/login/vendor/autoload.php | 25 + .../login/vendor/bacon/bacon-qr-code/LICENSE | 22 + .../vendor/bacon/bacon-qr-code/README.md | 39 + .../vendor/bacon/bacon-qr-code/composer.json | 44 + .../bacon/bacon-qr-code/phpunit.xml.dist | 13 + .../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 | 183 + .../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 | 79 + .../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 | 668 + .../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 | 336 + .../src/Renderer/Image/SvgImageBackEnd.php | 369 + .../Renderer/Image/TransformationMatrix.php | 68 + .../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 | 71 + .../test/Common/BitArrayTest.php | 222 + .../test/Common/BitMatrixTest.php | 115 + .../test/Common/BitUtilsTest.php | 25 + .../test/Common/ErrorCorrectionLevelTest.php | 25 + .../test/Common/FormatInformationTest.php | 94 + .../bacon-qr-code/test/Common/ModeTest.php | 19 + .../test/Common/ReedSolomonCodecTest.php | 96 + .../bacon-qr-code/test/Common/VersionTest.php | 78 + .../test/Encoder/EncoderTest.php | 487 + .../test/Encoder/MaskUtilTest.php | 251 + .../test/Encoder/MatrixUtilTest.php | 335 + .../test/Integration/ImagickRenderingTest.php | 72 + ...ickRenderingTest__testGenericQrCode__1.png | Bin 0 -> 3111 bytes .../ImagickRenderingTest__testIssue79__1.png | Bin 0 -> 8366 bytes .../login/vendor/birke/rememberme/.gitignore | 4 + plugins/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 + .../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 + plugins/login/vendor/composer/ClassLoader.php | 585 + .../vendor/composer/InstalledVersions.php | 359 + plugins/login/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 11 + .../login/vendor/composer/autoload_files.php | 10 + .../vendor/composer/autoload_namespaces.php | 9 + .../login/vendor/composer/autoload_psr4.php | 15 + .../login/vendor/composer/autoload_real.php | 50 + .../login/vendor/composer/autoload_static.php | 75 + plugins/login/vendor/composer/installed.json | 288 + plugins/login/vendor/composer/installed.php | 68 + .../login/vendor/composer/platform_check.php | 26 + .../dasprid/enum/.github/workflows/tests.yml | 47 + plugins/login/vendor/dasprid/enum/LICENSE | 22 + plugins/login/vendor/dasprid/enum/README.md | 164 + .../login/vendor/dasprid/enum/composer.json | 34 + .../vendor/dasprid/enum/phpunit.xml.dist | 17 + .../vendor/dasprid/enum/src/AbstractEnum.php | 241 + .../login/vendor/dasprid/enum/src/EnumMap.php | 385 + .../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 + .../.github/workflows/test-bacon.yml | 30 + .../.github/workflows/test-endroid.yml | 46 + .../twofactorauth/.github/workflows/test.yml | 28 + .../vendor/robthree/twofactorauth/.gitignore | 192 + .../vendor/robthree/twofactorauth/LICENSE | 22 + .../vendor/robthree/twofactorauth/README.md | 43 + .../twofactorauth/TwoFactorAuth.phpproj | 70 + .../robthree/twofactorauth/TwoFactorAuth.sln | 22 + .../robthree/twofactorauth/composer.json | 49 + .../robthree/twofactorauth/demo/demo.php | 51 + .../robthree/twofactorauth/docs/_config.yml | 3 + .../twofactorauth/docs/_layouts/post.html | 9 + .../twofactorauth/docs/assets/css/style.scss | 54 + .../twofactorauth/docs/getting-started.md | 58 + .../docs/improved-code-verification.md | 32 + .../robthree/twofactorauth/docs/index.md | 18 + .../docs/optional-configuration.md | 56 + .../robthree/twofactorauth/docs/qr-codes.md | 61 + .../twofactorauth/docs/qr-codes/bacon.md | 23 + .../twofactorauth/docs/qr-codes/endroid.md | 37 + .../docs/qr-codes/image-charts.md | 16 + .../twofactorauth/docs/qr-codes/qr-server.md | 20 + .../twofactorauth/docs/qr-codes/qrickit.md | 15 + .../lib/Providers/Qr/BaconQrCodeProvider.php | 159 + .../Providers/Qr/BaseHTTPQRCodeProvider.php | 33 + .../Providers/Qr/EndroidQrCodeProvider.php | 84 + .../Qr/EndroidQrCodeWithLogoProvider.php | 55 + .../Qr/GoogleChartsQrCodeProvider.php | 67 + .../lib/Providers/Qr/HandlesDataUri.php | 24 + .../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 | 27 + .../tests/MightNotMakeAssertions.php | 26 + .../Providers/Qr/IQRCodeProviderTest.php | 60 + .../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 + .../testsDependency/BaconQRCodeTest.php | 61 + .../testsDependency/EndroidQRCodeTest.php | 24 + plugins/markdown-notices/CHANGELOG.md | 38 + plugins/markdown-notices/LICENSE | 21 + plugins/markdown-notices/README.md | 62 + plugins/markdown-notices/assets/notices.css | 32 + .../markdown-notices/assets/screenshot.png | Bin 0 -> 86632 bytes plugins/markdown-notices/blueprints.yaml | 59 + plugins/markdown-notices/composer.json | 27 + plugins/markdown-notices/composer.lock | 22 + plugins/markdown-notices/languages.yaml | 29 + plugins/markdown-notices/markdown-notices.php | 92 + .../markdown-notices/markdown-notices.yaml | 4 + plugins/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 + plugins/pagination/CHANGELOG.md | 104 + plugins/pagination/LICENSE | 21 + plugins/pagination/README.md | 151 + plugins/pagination/blueprints.yaml | 52 + .../classes/plugin/PaginationHelper.php | 130 + .../classes/plugin/PaginationPage.php | 84 + plugins/pagination/composer.json | 32 + plugins/pagination/composer.lock | 24 + plugins/pagination/css/pagination.css | 17 + plugins/pagination/hebe.json | 15 + plugins/pagination/languages.yaml | 20 + plugins/pagination/pagination.php | 165 + plugins/pagination/pagination.yaml | 3 + .../templates/partials/pagination.html.twig | 34 + plugins/pagination/vendor/autoload.php | 7 + .../vendor/composer/ClassLoader.php | 445 + plugins/pagination/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 + .../pagination/vendor/composer/installed.json | 1 + plugins/problems/.gitignore | 2 + plugins/problems/CHANGELOG.md | 164 + plugins/problems/LICENSE | 21 + plugins/problems/README.md | 92 + plugins/problems/assets/cli.png | Bin 0 -> 401907 bytes plugins/problems/assets/code-3.svg | 11 + plugins/problems/assets/grav-logo.svg | 1 + plugins/problems/assets/heart.svg | 5 + plugins/problems/assets/readme_1.jpg | Bin 0 -> 368222 bytes plugins/problems/blueprints.yaml | 43 + plugins/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 + plugins/problems/cli/CheckCommand.php | 107 + plugins/problems/composer.json | 32 + plugins/problems/composer.lock | 20 + plugins/problems/css/admin.css | 31 + plugins/problems/css/admin.min.css | 1 + plugins/problems/css/spectre-icons.css | 168 + plugins/problems/css/spectre-icons.min.css | 1 + plugins/problems/css/spectre.css | 1276 + plugins/problems/css/spectre.min.css | 1 + plugins/problems/gulpfile.js | 39 + plugins/problems/hebe.json | 15 + plugins/problems/languages.yaml | 14 + plugins/problems/package.json | 45 + plugins/problems/problems.php | 185 + plugins/problems/problems.yaml | 2 + plugins/problems/scss/_accordions.scss | 38 + plugins/problems/scss/_animations.scss | 20 + plugins/problems/scss/_asian.scss | 38 + plugins/problems/scss/_autocomplete.scss | 47 + plugins/problems/scss/_avatars.scss | 77 + plugins/problems/scss/_badges.scss | 60 + plugins/problems/scss/_bars.scss | 71 + plugins/problems/scss/_base.scss | 44 + plugins/problems/scss/_breadcrumbs.scss | 29 + plugins/problems/scss/_buttons.scss | 195 + plugins/problems/scss/_calendars.scss | 222 + plugins/problems/scss/_cards.scss | 43 + plugins/problems/scss/_carousels.scss | 126 + plugins/problems/scss/_chips.scss | 30 + plugins/problems/scss/_codes.scss | 31 + .../problems/scss/_comparison-sliders.scss | 115 + plugins/problems/scss/_dropdowns.scss | 36 + plugins/problems/scss/_empty.scss | 21 + plugins/problems/scss/_filters.scss | 37 + plugins/problems/scss/_forms.scss | 545 + plugins/problems/scss/_icons.scss | 5 + plugins/problems/scss/_labels.scss | 34 + plugins/problems/scss/_layout.scss | 424 + plugins/problems/scss/_media.scss | 75 + plugins/problems/scss/_menus.scss | 62 + plugins/problems/scss/_meters.scss | 57 + plugins/problems/scss/_mixins.scss | 11 + plugins/problems/scss/_modals.scss | 87 + plugins/problems/scss/_navbar.scss | 29 + plugins/problems/scss/_navs.scss | 34 + plugins/problems/scss/_normalize.scss | 446 + plugins/problems/scss/_off-canvas.scss | 95 + plugins/problems/scss/_pagination.scss | 61 + plugins/problems/scss/_panels.scss | 23 + plugins/problems/scss/_parallax.scss | 135 + plugins/problems/scss/_popovers.scss | 65 + plugins/problems/scss/_preset.scss | 90 + plugins/problems/scss/_problems.scss | 72 + plugins/problems/scss/_progress.scss | 45 + plugins/problems/scss/_sliders.scss | 99 + plugins/problems/scss/_steps.scss | 70 + plugins/problems/scss/_tables.scss | 57 + plugins/problems/scss/_tabs.scss | 66 + plugins/problems/scss/_tiles.scss | 38 + plugins/problems/scss/_timelines.scss | 54 + plugins/problems/scss/_toasts.scss | 42 + plugins/problems/scss/_tooltips.scss | 79 + plugins/problems/scss/_typography.scss | 128 + plugins/problems/scss/_utilities.scss | 8 + plugins/problems/scss/_variables.scss | 116 + plugins/problems/scss/admin.scss | 92 + .../problems/scss/icons/_icons-action.scss | 316 + plugins/problems/scss/icons/_icons-core.scss | 53 + .../scss/icons/_icons-navigation.scss | 133 + .../problems/scss/icons/_icons-object.scss | 176 + plugins/problems/scss/mixins/_avatar.scss | 6 + plugins/problems/scss/mixins/_button.scss | 54 + plugins/problems/scss/mixins/_clearfix.scss | 8 + plugins/problems/scss/mixins/_color.scss | 27 + plugins/problems/scss/mixins/_label.scss | 11 + plugins/problems/scss/mixins/_position.scss | 65 + plugins/problems/scss/mixins/_shadow.scss | 9 + plugins/problems/scss/mixins/_text.scss | 6 + plugins/problems/scss/mixins/_toast.scss | 5 + plugins/problems/scss/mixins/_transition.scss | 4 + plugins/problems/scss/spectre-icons.scss | 10 + plugins/problems/scss/spectre.scss | 51 + plugins/problems/scss/utilities/_colors.scss | 31 + plugins/problems/scss/utilities/_cursors.scss | 24 + plugins/problems/scss/utilities/_display.scss | 44 + plugins/problems/scss/utilities/_divider.scss | 50 + plugins/problems/scss/utilities/_loading.scss | 34 + .../problems/scss/utilities/_position.scss | 50 + plugins/problems/scss/utilities/_shapes.scss | 8 + plugins/problems/scss/utilities/_text.scss | 64 + plugins/problems/templates/problems.html.twig | 34 + .../reports/problems-report.html.twig | 33 + plugins/problems/vendor/autoload.php | 7 + .../problems/vendor/composer/ClassLoader.php | 445 + .../vendor/composer/InstalledVersions.php | 219 + 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 + plugins/problems/yarn.lock | 3268 + plugins/social-seo-metatags/CHANGELOG.md | 126 + plugins/social-seo-metatags/LICENSE | 21 + plugins/social-seo-metatags/README.md | 254 + plugins/social-seo-metatags/blueprints.yaml | 193 + plugins/social-seo-metatags/languages.yaml | 133 + .../social-seo-metatags.php | 535 + .../social-seo-metatags.yaml | 25 + plugins/taxonomylist/.gitignore | 1 + plugins/taxonomylist/CHANGELOG.md | 93 + plugins/taxonomylist/LICENSE | 21 + plugins/taxonomylist/README.md | 64 + plugins/taxonomylist/assets/readme_1.png | Bin 0 -> 12888 bytes plugins/taxonomylist/blueprints.yaml | 39 + plugins/taxonomylist/classes/taxonomylist.php | 97 + plugins/taxonomylist/composer.json | 36 + plugins/taxonomylist/composer.lock | 22 + plugins/taxonomylist/hebe.json | 15 + plugins/taxonomylist/taxonomylist.php | 75 + plugins/taxonomylist/taxonomylist.yaml | 2 + .../templates/partials/taxonomylist.html.twig | 10 + plugins/taxonomylist/vendor/autoload.php | 7 + .../vendor/composer/ClassLoader.php | 445 + plugins/taxonomylist/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 11 + .../vendor/composer/autoload_namespaces.php | 9 + .../vendor/composer/autoload_psr4.php | 9 + .../vendor/composer/autoload_real.php | 52 + .../vendor/composer/autoload_static.php | 21 + .../vendor/composer/installed.json | 1 + plugins/tinymce-editor/CHANGELOG.md | 160 + plugins/tinymce-editor/CONTRIBUTING.md | 14 + plugins/tinymce-editor/LICENSE | 24 + plugins/tinymce-editor/README.md | 128 + .../tinymce-editor/assets/tinymce-editor.png | Bin 0 -> 94951 bytes plugins/tinymce-editor/blueprints.yaml | 134 + plugins/tinymce-editor/css/editor.css | 1 + .../js/tinymce/jquery.tinymce.min.js | 1 + .../tinymce-editor/js/tinymce/langs/af_ZA.js | 230 + plugins/tinymce-editor/js/tinymce/langs/ar.js | 262 + plugins/tinymce-editor/js/tinymce/langs/az.js | 261 + plugins/tinymce-editor/js/tinymce/langs/be.js | 261 + .../tinymce-editor/js/tinymce/langs/bg_BG.js | 261 + .../tinymce-editor/js/tinymce/langs/bn_BD.js | 261 + plugins/tinymce-editor/js/tinymce/langs/ca.js | 261 + plugins/tinymce-editor/js/tinymce/langs/cs.js | 261 + .../tinymce-editor/js/tinymce/langs/cs_CZ.js | 260 + plugins/tinymce-editor/js/tinymce/langs/cy.js | 230 + plugins/tinymce-editor/js/tinymce/langs/da.js | 261 + plugins/tinymce-editor/js/tinymce/langs/de.js | 261 + .../tinymce-editor/js/tinymce/langs/de_AT.js | 261 + plugins/tinymce-editor/js/tinymce/langs/dv.js | 230 + plugins/tinymce-editor/js/tinymce/langs/el.js | 261 + .../tinymce-editor/js/tinymce/langs/en_CA.js | 261 + .../tinymce-editor/js/tinymce/langs/en_GB.js | 261 + plugins/tinymce-editor/js/tinymce/langs/es.js | 261 + .../tinymce-editor/js/tinymce/langs/es_MX.js | 261 + plugins/tinymce-editor/js/tinymce/langs/et.js | 261 + plugins/tinymce-editor/js/tinymce/langs/eu.js | 261 + .../tinymce-editor/js/tinymce/langs/fa_IR.js | 262 + plugins/tinymce-editor/js/tinymce/langs/fi.js | 261 + .../tinymce-editor/js/tinymce/langs/fr_FR.js | 261 + plugins/tinymce-editor/js/tinymce/langs/ga.js | 261 + plugins/tinymce-editor/js/tinymce/langs/gl.js | 253 + .../tinymce-editor/js/tinymce/langs/he_IL.js | 262 + plugins/tinymce-editor/js/tinymce/langs/hr.js | 253 + .../tinymce-editor/js/tinymce/langs/hu_HU.js | 261 + plugins/tinymce-editor/js/tinymce/langs/id.js | 261 + plugins/tinymce-editor/js/tinymce/langs/it.js | 261 + plugins/tinymce-editor/js/tinymce/langs/ja.js | 261 + .../tinymce-editor/js/tinymce/langs/ka_GE.js | 230 + .../tinymce-editor/js/tinymce/langs/kab.js | 261 + plugins/tinymce-editor/js/tinymce/langs/kk.js | 230 + .../tinymce-editor/js/tinymce/langs/km_KH.js | 253 + .../tinymce-editor/js/tinymce/langs/ko_KR.js | 261 + plugins/tinymce-editor/js/tinymce/langs/lt.js | 261 + plugins/tinymce-editor/js/tinymce/langs/lv.js | 260 + .../tinymce-editor/js/tinymce/langs/nb_NO.js | 261 + plugins/tinymce-editor/js/tinymce/langs/nl.js | 261 + plugins/tinymce-editor/js/tinymce/langs/pl.js | 261 + .../tinymce-editor/js/tinymce/langs/pt_BR.js | 261 + .../tinymce-editor/js/tinymce/langs/pt_PT.js | 261 + .../tinymce-editor/js/tinymce/langs/readme.md | 3 + plugins/tinymce-editor/js/tinymce/langs/ro.js | 230 + plugins/tinymce-editor/js/tinymce/langs/ru.js | 261 + plugins/tinymce-editor/js/tinymce/langs/sk.js | 253 + .../tinymce-editor/js/tinymce/langs/sl_SI.js | 230 + plugins/tinymce-editor/js/tinymce/langs/sr.js | 261 + .../tinymce-editor/js/tinymce/langs/sv_SE.js | 261 + plugins/tinymce-editor/js/tinymce/langs/ta.js | 261 + .../tinymce-editor/js/tinymce/langs/ta_IN.js | 261 + .../tinymce-editor/js/tinymce/langs/th_TH.js | 261 + plugins/tinymce-editor/js/tinymce/langs/tr.js | 261 + .../tinymce-editor/js/tinymce/langs/tr_TR.js | 261 + plugins/tinymce-editor/js/tinymce/langs/ug.js | 260 + plugins/tinymce-editor/js/tinymce/langs/uk.js | 261 + .../tinymce-editor/js/tinymce/langs/uk_UA.js | 261 + plugins/tinymce-editor/js/tinymce/langs/uz.js | 260 + .../tinymce-editor/js/tinymce/langs/vi_VN.js | 260 + .../tinymce-editor/js/tinymce/langs/zh_CN.js | 261 + .../tinymce-editor/js/tinymce/langs/zh_TW.js | 261 + plugins/tinymce-editor/js/tinymce/license.txt | 504 + .../js/tinymce/plugins/advlist/plugin.min.js | 1 + .../js/tinymce/plugins/anchor/plugin.min.js | 1 + .../js/tinymce/plugins/autolink/plugin.min.js | 1 + .../tinymce/plugins/autoresize/plugin.min.js | 1 + .../js/tinymce/plugins/autosave/plugin.min.js | 1 + .../js/tinymce/plugins/bbcode/plugin.min.js | 1 + .../js/tinymce/plugins/charmap/plugin.min.js | 1 + .../js/tinymce/plugins/code/plugin.min.js | 1 + .../tinymce/plugins/codesample/css/prism.css | 138 + .../tinymce/plugins/codesample/plugin.min.js | 1 + .../tinymce/plugins/colorpicker/plugin.min.js | 1 + .../tinymce/plugins/contextmenu/plugin.min.js | 1 + .../plugins/directionality/plugin.min.js | 1 + .../plugins/emoticons/img/smiley-cool.gif | Bin 0 -> 354 bytes .../plugins/emoticons/img/smiley-cry.gif | Bin 0 -> 329 bytes .../emoticons/img/smiley-embarassed.gif | Bin 0 -> 331 bytes .../emoticons/img/smiley-foot-in-mouth.gif | Bin 0 -> 342 bytes .../plugins/emoticons/img/smiley-frown.gif | Bin 0 -> 340 bytes .../plugins/emoticons/img/smiley-innocent.gif | Bin 0 -> 336 bytes .../plugins/emoticons/img/smiley-kiss.gif | Bin 0 -> 338 bytes .../plugins/emoticons/img/smiley-laughing.gif | Bin 0 -> 343 bytes .../emoticons/img/smiley-money-mouth.gif | Bin 0 -> 321 bytes .../plugins/emoticons/img/smiley-sealed.gif | Bin 0 -> 323 bytes .../plugins/emoticons/img/smiley-smile.gif | Bin 0 -> 344 bytes .../emoticons/img/smiley-surprised.gif | Bin 0 -> 338 bytes .../emoticons/img/smiley-tongue-out.gif | Bin 0 -> 328 bytes .../emoticons/img/smiley-undecided.gif | Bin 0 -> 337 bytes .../plugins/emoticons/img/smiley-wink.gif | Bin 0 -> 350 bytes .../plugins/emoticons/img/smiley-yell.gif | Bin 0 -> 336 bytes .../tinymce/plugins/emoticons/plugin.min.js | 1 + .../js/tinymce/plugins/fullpage/plugin.min.js | 1 + .../tinymce/plugins/fullscreen/plugin.min.js | 1 + .../js/tinymce/plugins/help/img/logo.png | Bin 0 -> 13208 bytes .../js/tinymce/plugins/help/plugin.min.js | 1 + .../js/tinymce/plugins/hr/plugin.min.js | 1 + .../js/tinymce/plugins/image/plugin.min.js | 1 + .../tinymce/plugins/imagetools/plugin.min.js | 1 + .../tinymce/plugins/importcss/plugin.min.js | 1 + .../plugins/insertdatetime/plugin.min.js | 1 + .../plugins/legacyoutput/plugin.min.js | 1 + .../js/tinymce/plugins/link/plugin.min.js | 1 + .../js/tinymce/plugins/lists/plugin.min.js | 1 + .../js/tinymce/plugins/media/plugin.min.js | 1 + .../tinymce/plugins/nonbreaking/plugin.min.js | 1 + .../tinymce/plugins/noneditable/plugin.min.js | 1 + .../tinymce/plugins/pagebreak/plugin.min.js | 1 + .../js/tinymce/plugins/paste/plugin.min.js | 1 + .../js/tinymce/plugins/preview/plugin.min.js | 1 + .../js/tinymce/plugins/print/plugin.min.js | 1 + .../js/tinymce/plugins/save/plugin.min.js | 1 + .../plugins/searchreplace/plugin.min.js | 1 + .../plugins/spellchecker/plugin.min.js | 1 + .../js/tinymce/plugins/tabfocus/plugin.min.js | 1 + .../js/tinymce/plugins/table/plugin.min.js | 1 + .../js/tinymce/plugins/template/plugin.min.js | 1 + .../tinymce/plugins/textcolor/plugin.min.js | 1 + .../tinymce/plugins/textpattern/plugin.min.js | 1 + .../js/tinymce/plugins/toc/plugin.min.js | 1 + .../plugins/visualblocks/css/visualblocks.css | 154 + .../plugins/visualblocks/plugin.min.js | 1 + .../tinymce/plugins/visualchars/plugin.min.js | 1 + .../tinymce/plugins/wordcount/plugin.min.js | 1 + .../skins/lightgray/content.inline.min.css | 1 + .../tinymce/skins/lightgray/content.min.css | 1 + .../skins/lightgray/content.mobile.min.css | 1 + .../skins/lightgray/fonts/tinymce-mobile.woff | Bin 0 -> 4624 bytes .../skins/lightgray/fonts/tinymce-small.eot | Bin 0 -> 9492 bytes .../skins/lightgray/fonts/tinymce-small.svg | 63 + .../skins/lightgray/fonts/tinymce-small.ttf | Bin 0 -> 9304 bytes .../skins/lightgray/fonts/tinymce-small.woff | Bin 0 -> 9380 bytes .../tinymce/skins/lightgray/fonts/tinymce.eot | Bin 0 -> 18912 bytes .../tinymce/skins/lightgray/fonts/tinymce.svg | 132 + .../tinymce/skins/lightgray/fonts/tinymce.ttf | Bin 0 -> 18748 bytes .../skins/lightgray/fonts/tinymce.woff | Bin 0 -> 18824 bytes .../js/tinymce/skins/lightgray/img/anchor.gif | Bin 0 -> 53 bytes .../js/tinymce/skins/lightgray/img/loader.gif | Bin 0 -> 2608 bytes .../js/tinymce/skins/lightgray/img/object.gif | Bin 0 -> 152 bytes .../js/tinymce/skins/lightgray/img/trans.gif | Bin 0 -> 43 bytes .../js/tinymce/skins/lightgray/skin.min.css | 1 + .../skins/lightgray/skin.mobile.min.css | 2 + .../js/tinymce/themes/inlite/theme.min.js | 1 + .../js/tinymce/themes/mobile/theme.min.js | 1 + .../js/tinymce/themes/modern/theme.min.js | 1 + .../tinymce-editor/js/tinymce/tinymce.min.js | 2 + plugins/tinymce-editor/languages.yaml | 48 + .../forms/fields/tinymce/tinymce.html.twig | 123 + plugins/tinymce-editor/tinymce-editor.php | 190 + plugins/tinymce-editor/tinymce-editor.yaml | 80 + plugins/tmp-pagecollection/CHANGELOG.md | 5 + plugins/tmp-pagecollection/LICENSE | 21 + plugins/tmp-pagecollection/README.md | 56 + plugins/tmp-pagecollection/blueprints.yaml | 20 + plugins/tmp-pagecollection/composer.json | 29 + plugins/tmp-pagecollection/composer.lock | 23 + plugins/tmp-pagecollection/languages.yaml | 4 + .../tmp-pagecollection/tmp-pagecollection.php | 18 + .../tmp-pagecollection.yaml | 2 + .../tmp-pagecollection/twig/twigDisplay.php | 90 + .../tmp-pagecollection/vendor/autoload.php | 7 + .../vendor/composer/ClassLoader.php | 481 + .../vendor/composer/InstalledVersions.php | 337 + .../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 + plugins/tntsearch/.eslintrc | 15 + plugins/tntsearch/.gitignore | 2 + plugins/tntsearch/CHANGELOG.md | 220 + plugins/tntsearch/LICENSE | 21 + plugins/tntsearch/README.md | 373 + plugins/tntsearch/app/history.js | 3 + plugins/tntsearch/app/main.js | 61 + plugins/tntsearch/app/search.js | 107 + plugins/tntsearch/assets/admin/tntsearch.css | 34 + plugins/tntsearch/assets/admin/tntsearch.js | 78 + plugins/tntsearch/assets/tntsearch-ajax.gif | Bin 0 -> 772833 bytes plugins/tntsearch/assets/tntsearch-config.png | Bin 0 -> 19802 bytes .../tntsearch/assets/tntsearch-quicktray.png | Bin 0 -> 68282 bytes plugins/tntsearch/assets/tntsearch.css | 71 + plugins/tntsearch/assets/tntsearch.js | 1 + plugins/tntsearch/blueprints.yaml | 297 + plugins/tntsearch/classes/GravConnector.php | 87 + .../tntsearch/classes/GravResultObject.php | 29 + plugins/tntsearch/classes/GravTNTSearch.php | 350 + .../tntsearch/cli/TNTSearchIndexerCommand.php | 97 + .../tntsearch/cli/TNTSearchQueryCommand.php | 74 + plugins/tntsearch/composer.json | 34 + plugins/tntsearch/composer.lock | 104 + plugins/tntsearch/languages.yaml | 20 + plugins/tntsearch/package.json | 38 + .../fields/indexstatus/indexstatus.html.twig | 16 + .../templates/partials/tntsearch.html.twig | 30 + plugins/tntsearch/templates/search.html.twig | 7 + .../templates/tntquery-ajax.html.twig | 19 + .../tntsearch/templates/tntquery.html.twig | 8 + .../tntsearch/templates/tntquery.json.twig | 1 + plugins/tntsearch/tntsearch.php | 523 + plugins/tntsearch/tntsearch.yaml | 29 + plugins/tntsearch/vendor/autoload.php | 25 + .../tntsearch/vendor/composer/ClassLoader.php | 585 + .../vendor/composer/InstalledVersions.php | 352 + 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 | 50 + .../vendor/composer/autoload_static.php | 54 + .../tntsearch/vendor/composer/installed.json | 87 + .../tntsearch/vendor/composer/installed.php | 32 + .../vendor/composer/platform_check.php | 26 + .../teamtnt/tntsearch/.github/FUNDING.yml | 3 + .../teamtnt/tntsearch/.github/stale.yml | 18 + .../vendor/teamtnt/tntsearch/.gitignore | 8 + .../vendor/teamtnt/tntsearch/.travis.yml | 22 + .../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 | 380 + .../vendor/teamtnt/tntsearch/composer.json | 42 + .../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/FrenchStemmer.php | 693 + .../tntsearch/src/Stemmer/GermanStemmer.php | 248 + .../tntsearch/src/Stemmer/ItalianStemmer.php | 451 + .../tntsearch/src/Stemmer/NoStemmer.php | 11 + .../tntsearch/src/Stemmer/PolishStemmer.php | 144 + .../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/BigramTokenizer.php | 11 + .../tntsearch/src/Support/Collection.php | 164 + .../src/Support/EdgeNgramTokenizer.php | 23 + .../tntsearch/src/Support/Expression.php | 116 + .../src/Support/FivegramTokenizer.php | 12 + .../src/Support/FourgramTokenizer.php | 12 + .../tntsearch/src/Support/Highlighter.php | 220 + .../tntsearch/src/Support/NGramTokenizer.php | 34 + .../src/Support/ProductTokenizer.php | 14 + .../tntsearch/src/Support/Tokenizer.php | 14 + .../src/Support/TokenizerInterface.php | 9 + .../src/Support/TrigramTokenizer.php | 12 + .../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 | 348 + .../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.sqlite | Bin 0 -> 3459072 bytes .../tests/_files/english_wordlist_2k.txt | 1510 + .../tntsearch/tests/_files/mnist/.gitignore | 2 + .../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/FrenchStemmerTest.php | 13 + .../tests/stemmer/GermanStemmerTest.php | 14 + .../tests/stemmer/PolishStemmerTest.php | 21 + .../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/BigramTokenizerTest.php | 16 + .../tests/support/EdgeNgramTokenizerTest.php | 26 + .../tests/support/ExpressionTest.php | 23 + .../tests/support/FivegramTokenizerTest.php | 16 + .../tests/support/FourgramTokenizerTest.php | 16 + .../tests/support/HighlighterTest.php | 42 + .../tests/support/NGramTokenizerTest.php | 37 + .../tests/support/ProductTokenizerTest.php | 39 + .../tntsearch/tests/support/TokenizerTest.php | 39 + .../tests/support/TrigramTokenizerTest.php | 16 + plugins/tntsearch/webpack.conf.js | 45 + plugins/tntsearch/yarn.lock | 4721 + themes/.gitkeep | 0 themes/plain/CHANGELOG.md | 5 + themes/plain/LICENSE | 21 + themes/plain/README.md | 7 + themes/plain/blueprints.yaml | 27 + themes/plain/blueprints/actualites.yaml | 48 + themes/plain/blueprints/coalitions.yaml | 63 + themes/plain/blueprints/danger.yaml | 146 + themes/plain/blueprints/default.yaml | 16 + themes/plain/blueprints/home.yaml | 76 + themes/plain/blueprints/media.yaml | 86 + themes/plain/blueprints/modules.yaml | 129 + themes/plain/blueprints/pays.yaml | 79 + themes/plain/blueprints/post.yaml | 101 + themes/plain/blueprints/power.yaml | 69 + themes/plain/blueprints/projects.yaml | 14 + themes/plain/blueprints/ressources.yaml | 245 + themes/plain/blueprints/sub_cat.yaml | 2 + themes/plain/css/admin.css | 9 + themes/plain/css/app.css | 5270 + themes/plain/css/slick.css | 119 + themes/plain/fonts/roboto/Roboto_Bold.ttf | Bin 0 -> 170760 bytes themes/plain/fonts/roboto/Roboto_Light.ttf | Bin 0 -> 170420 bytes themes/plain/fonts/roboto/Roboto_Regular.ttf | Bin 0 -> 171676 bytes themes/plain/fonts/trueno/TruenoBd.otf | Bin 0 -> 35816 bytes themes/plain/fonts/trueno/TruenoLt.otf | Bin 0 -> 34316 bytes themes/plain/fonts/trueno/TruenoLtIt.otf | Bin 0 -> 34804 bytes themes/plain/fonts/trueno/TruenoRg.otf | Bin 0 -> 35120 bytes themes/plain/fonts/trueno/TruenoSBd.otf | Bin 0 -> 49528 bytes themes/plain/fonts/trueno/TruenoUltLt.otf | Bin 0 -> 47192 bytes themes/plain/images/BlankMap-Africa.svg | 265 + themes/plain/images/Donation.svg | 60 + themes/plain/images/campagnes.svg | 61 + themes/plain/images/close.png | Bin 0 -> 280 bytes themes/plain/images/com.svg | 71 + themes/plain/images/contact.svg | 101 + themes/plain/images/contact_w.svg | 115 + themes/plain/images/crown.svg | 57 + themes/plain/images/f.svg | 44 + themes/plain/images/f_w.svg | 45 + themes/plain/images/favicon.ico | Bin 0 -> 9662 bytes themes/plain/images/ffr.svg | 93 + themes/plain/images/free.png | Bin 0 -> 14419 bytes themes/plain/images/in.svg | 56 + themes/plain/images/in_w.svg | 58 + themes/plain/images/ligne.svg | 4185 + themes/plain/images/loading.gif | Bin 0 -> 8476 bytes themes/plain/images/logo.svg | 1781 + themes/plain/images/menace.png | Bin 0 -> 14533 bytes themes/plain/images/newsletter.svg | 53 + themes/plain/images/next.png | Bin 0 -> 1350 bytes themes/plain/images/outils.svg | 61 + themes/plain/images/photo_home_membre.jpg | Bin 0 -> 629456 bytes themes/plain/images/photo_home_qui.jpg | Bin 0 -> 732558 bytes themes/plain/images/photo_home_soutenir.jpg | Bin 0 -> 453079 bytes .../plain/images/pictos_pagearrestation.svg | 189 + themes/plain/images/prev.png | Bin 0 -> 1360 bytes themes/plain/images/prison.png | Bin 0 -> 15656 bytes themes/plain/images/t.svg | 44 + themes/plain/images/t_w.svg | 45 + themes/plain/images/trib.svg | 65 + themes/plain/images/you.svg | 249 + themes/plain/images/you_w.svg | 289 + themes/plain/js/admin.js | 67 + themes/plain/js/app.js | 2 + themes/plain/js/app.js.map | 1 + themes/plain/js/datavis.js | 513 + themes/plain/js/jq.js | 2 + themes/plain/js/lib.js | 10371 ++ themes/plain/js/lightbox.js | 554 + themes/plain/modular.yaml | 43 + themes/plain/plain.php | 42 + themes/plain/plain.yaml | 3 + themes/plain/screenshot.jpg | Bin 0 -> 15428 bytes themes/plain/templates/actualites.html.twig | 73 + themes/plain/templates/coalitions.html.twig | 5 + themes/plain/templates/danger.html.twig | 271 + themes/plain/templates/default.html.twig | 52 + themes/plain/templates/error.html.twig | 7 + themes/plain/templates/home.html.twig | 157 + themes/plain/templates/media.html.twig | 70 + themes/plain/templates/modules.html.twig | 123 + themes/plain/templates/old_d3.js | 180 + .../plain/templates/partials/base.html.twig | 199 + .../plain/templates/partials/error.html.twig | 0 .../plain/templates/partials/footer.html.twig | 60 + .../templates/partials/footer_coa.html.twig | 115 + .../plain/templates/partials/head.html.twig | 57 + .../partials/langswitcher.hreflang.html.twig | 9 + .../templates/partials/langswitcher.html.twig | 30 + themes/plain/templates/partials/map.html.twig | 265 + .../templates/partials/navigation.html.twig | 92 + .../templates/partials/pagination.html.twig | 34 + .../templates/partials/sidebar.html.twig | 76 + .../plain/templates/partials/slider.html.twig | 8 + .../templates/partials/tntsearch.html.twig | 31 + themes/plain/templates/pays.html.twig | 69 + themes/plain/templates/post.html.twig | 131 + themes/plain/templates/power.html.twig | 159 + themes/plain/templates/projects.html.twig | 119 + themes/plain/templates/ressources.html.twig | 278 + themes/plain/templates/sub_cat.html.twig | 52 + .../plain/templates/tntquery-ajax.html.twig | 19 + themes/plain/thumbnail.jpg | Bin 0 -> 3681 bytes 3044 files changed, 544089 insertions(+) create mode 100755 config/backups.yaml create mode 100644 config/groups.yaml create mode 100755 config/media.yaml create mode 100755 config/plugins/admin.yaml create mode 100755 config/plugins/auto-author.yaml create mode 100755 config/plugins/autoseo.yaml create mode 100755 config/plugins/cookieconsent.yaml create mode 100644 config/plugins/email.yaml create mode 100755 config/plugins/langswitcher.yaml create mode 100755 config/plugins/pagination.yaml create mode 100755 config/plugins/social-seo-metatags.yaml create mode 100755 config/plugins/taxonomylist.yaml create mode 100644 config/plugins/tinymce-editor.yaml create mode 100755 config/plugins/tntsearch.yaml create mode 100755 config/scheduler.yaml create mode 100755 config/security.yaml create mode 100755 config/site.yaml create mode 100755 config/streams.yaml create mode 100644 config/system.yaml create mode 100755 config/themes/plain.yaml create mode 100755 config/versions.yaml create mode 100644 languages/en.yaml create mode 100644 languages/fr.yaml create mode 100755 plugins/.gitkeep create mode 100755 plugins/admin-addon-media-metadata/.gitignore create mode 100755 plugins/admin-addon-media-metadata/.php_cs create mode 100755 plugins/admin-addon-media-metadata/CHANGELOG.md create mode 100755 plugins/admin-addon-media-metadata/LICENSE create mode 100755 plugins/admin-addon-media-metadata/README.md create mode 100755 plugins/admin-addon-media-metadata/admin-addon-media-metadata.css create mode 100755 plugins/admin-addon-media-metadata/admin-addon-media-metadata.js create mode 100755 plugins/admin-addon-media-metadata/admin-addon-media-metadata.php create mode 100755 plugins/admin-addon-media-metadata/admin-addon-media-metadata.yaml create mode 100755 plugins/admin-addon-media-metadata/assets/1-open-form.jpg create mode 100755 plugins/admin-addon-media-metadata/assets/2-form-opened.jpg create mode 100755 plugins/admin-addon-media-metadata/blueprints.yaml create mode 100755 plugins/admin-addon-media-metadata/composer.json create mode 100755 plugins/admin-addon-media-metadata/composer.lock create mode 100755 plugins/admin-addon-media-metadata/languages/de.yaml create mode 100755 plugins/admin-addon-media-metadata/languages/en.yaml create mode 100755 plugins/admin-addon-media-metadata/languages/fr.yaml create mode 100755 plugins/admin-addon-media-metadata/templates/additionalInlineJS.html.twig create mode 100755 plugins/admin-addon-media-metadata/templates/metadata-modal.html.twig create mode 100755 plugins/admin-addon-media-metadata/vendor/autoload.php create mode 100755 plugins/admin-addon-media-metadata/vendor/composer/ClassLoader.php create mode 100755 plugins/admin-addon-media-metadata/vendor/composer/LICENSE create mode 100755 plugins/admin-addon-media-metadata/vendor/composer/autoload_classmap.php create mode 100755 plugins/admin-addon-media-metadata/vendor/composer/autoload_namespaces.php create mode 100755 plugins/admin-addon-media-metadata/vendor/composer/autoload_psr4.php create mode 100755 plugins/admin-addon-media-metadata/vendor/composer/autoload_real.php create mode 100755 plugins/admin-addon-media-metadata/vendor/composer/autoload_static.php create mode 100755 plugins/admin-addon-media-metadata/vendor/composer/installed.json create mode 100644 plugins/admin/.editorconfig create mode 100644 plugins/admin/.gitattributes create mode 100644 plugins/admin/.github/FUNDING.yml create mode 100644 plugins/admin/.github/dependabot.yml create mode 100644 plugins/admin/.gitignore create mode 100644 plugins/admin/CHANGELOG.md create mode 100644 plugins/admin/CONTRIBUTING.md create mode 100644 plugins/admin/LICENSE create mode 100644 plugins/admin/README.md create mode 100644 plugins/admin/UPGRADE.md create mode 100644 plugins/admin/admin.php create mode 100644 plugins/admin/admin.yaml create mode 100644 plugins/admin/assets/admin-dashboard.png create mode 100644 plugins/admin/blueprints.yaml create mode 100644 plugins/admin/blueprints/config/media.yaml create mode 100644 plugins/admin/classes/plugin/Admin.php create mode 100644 plugins/admin/classes/plugin/AdminBaseController.php create mode 100644 plugins/admin/classes/plugin/AdminController.php create mode 100644 plugins/admin/classes/plugin/AdminForm.php create mode 100644 plugins/admin/classes/plugin/AdminFormFactory.php create mode 100644 plugins/admin/classes/plugin/Controllers/AbstractController.php create mode 100644 plugins/admin/classes/plugin/Controllers/AdminController.php create mode 100644 plugins/admin/classes/plugin/Controllers/Login/LoginController.php create mode 100644 plugins/admin/classes/plugin/Gpm.php create mode 100644 plugins/admin/classes/plugin/Popularity.php create mode 100644 plugins/admin/classes/plugin/Router.php create mode 100644 plugins/admin/classes/plugin/Routers/LoginRouter.php create mode 100644 plugins/admin/classes/plugin/ScssCompiler.php create mode 100644 plugins/admin/classes/plugin/ScssList.php create mode 100644 plugins/admin/classes/plugin/Themes.php create mode 100644 plugins/admin/classes/plugin/Twig/AdminTwigExtension.php create mode 100644 plugins/admin/classes/plugin/Utils.php create mode 100644 plugins/admin/classes/plugin/WhiteLabel.php create mode 100644 plugins/admin/codeception.yml create mode 100644 plugins/admin/composer.json create mode 100644 plugins/admin/composer.lock create mode 100644 plugins/admin/hebe.json create mode 100644 plugins/admin/languages/ar.yaml create mode 100644 plugins/admin/languages/bg.yaml create mode 100644 plugins/admin/languages/bn.yaml create mode 100644 plugins/admin/languages/br.yaml create mode 100644 plugins/admin/languages/ca.yaml create mode 100644 plugins/admin/languages/cs.yaml create mode 100644 plugins/admin/languages/cy.yaml create mode 100644 plugins/admin/languages/da.yaml create mode 100644 plugins/admin/languages/de.yaml create mode 100644 plugins/admin/languages/el.yaml create mode 100644 plugins/admin/languages/en.yaml create mode 100644 plugins/admin/languages/eo.yaml create mode 100644 plugins/admin/languages/es.yaml create mode 100644 plugins/admin/languages/et.yaml create mode 100644 plugins/admin/languages/eu.yaml create mode 100644 plugins/admin/languages/fa.yaml create mode 100644 plugins/admin/languages/fi.yaml create mode 100644 plugins/admin/languages/fr.yaml create mode 100644 plugins/admin/languages/gl.yaml create mode 100644 plugins/admin/languages/he.yaml create mode 100644 plugins/admin/languages/hr.yaml create mode 100644 plugins/admin/languages/hu.yaml create mode 100644 plugins/admin/languages/id.yaml create mode 100644 plugins/admin/languages/it.yaml create mode 100644 plugins/admin/languages/ja.yaml create mode 100644 plugins/admin/languages/ko.yaml create mode 100644 plugins/admin/languages/ku.yaml create mode 100644 plugins/admin/languages/lt.yaml create mode 100644 plugins/admin/languages/mn.yaml create mode 100644 plugins/admin/languages/nl.yaml create mode 100644 plugins/admin/languages/no.yaml create mode 100644 plugins/admin/languages/pl.yaml create mode 100644 plugins/admin/languages/pt.yaml create mode 100644 plugins/admin/languages/ro.yaml create mode 100644 plugins/admin/languages/ru.yaml create mode 100644 plugins/admin/languages/si.yaml create mode 100644 plugins/admin/languages/sk.yaml create mode 100644 plugins/admin/languages/sl.yaml create mode 100644 plugins/admin/languages/sr.yaml create mode 100644 plugins/admin/languages/sv.yaml create mode 100644 plugins/admin/languages/th.yaml create mode 100644 plugins/admin/languages/tlh.yaml create mode 100644 plugins/admin/languages/tr.yaml create mode 100644 plugins/admin/languages/uk.yaml create mode 100644 plugins/admin/languages/vi.yaml create mode 100644 plugins/admin/languages/zh-cn.yaml create mode 100644 plugins/admin/languages/zh-tw.yaml create mode 100644 plugins/admin/languages/zh.yaml create mode 100644 plugins/admin/permissions.yaml create mode 100644 plugins/admin/presets.yaml create mode 100644 plugins/admin/tests/_bootstrap.php create mode 100644 plugins/admin/tests/_support/Helper/Unit.php create mode 100644 plugins/admin/tests/_support/UnitTester.php create mode 100644 plugins/admin/tests/unit.suite.yml create mode 100644 plugins/admin/tests/unit/_bootstrap.php create mode 100644 plugins/admin/tests/unit/classes/controllerTest.php create mode 100644 plugins/admin/themes/grav/.babelrc create mode 100644 plugins/admin/themes/grav/.eslintignore create mode 100644 plugins/admin/themes/grav/.eslintrc create mode 100644 plugins/admin/themes/grav/app/dashboard/backup.js create mode 100644 plugins/admin/themes/grav/app/dashboard/cache.js create mode 100644 plugins/admin/themes/grav/app/dashboard/chart.js create mode 100644 plugins/admin/themes/grav/app/dashboard/index.js create mode 100644 plugins/admin/themes/grav/app/dashboard/update.js create mode 100644 plugins/admin/themes/grav/app/forms/fields/acl-picker.js create mode 100644 plugins/admin/themes/grav/app/forms/fields/array.js create mode 100644 plugins/admin/themes/grav/app/forms/fields/collections.js create mode 100644 plugins/admin/themes/grav/app/forms/fields/colorpicker.js create mode 100644 plugins/admin/themes/grav/app/forms/fields/cron.js create mode 100644 plugins/admin/themes/grav/app/forms/fields/datetime.js create mode 100644 plugins/admin/themes/grav/app/forms/fields/editor.js create mode 100644 plugins/admin/themes/grav/app/forms/fields/editor/buttons.js create mode 100644 plugins/admin/themes/grav/app/forms/fields/elements.js create mode 100644 plugins/admin/themes/grav/app/forms/fields/filepicker.js create mode 100644 plugins/admin/themes/grav/app/forms/fields/files.js create mode 100644 plugins/admin/themes/grav/app/forms/fields/folder.js create mode 100644 plugins/admin/themes/grav/app/forms/fields/iconpicker.js create mode 100644 plugins/admin/themes/grav/app/forms/fields/indeterminate.js create mode 100644 plugins/admin/themes/grav/app/forms/fields/index.js create mode 100644 plugins/admin/themes/grav/app/forms/fields/mediapicker.js create mode 100644 plugins/admin/themes/grav/app/forms/fields/multilevel.js create mode 100644 plugins/admin/themes/grav/app/forms/fields/parents.js create mode 100644 plugins/admin/themes/grav/app/forms/fields/permissions.js create mode 100644 plugins/admin/themes/grav/app/forms/fields/range.js create mode 100644 plugins/admin/themes/grav/app/forms/fields/selectize.js create mode 100644 plugins/admin/themes/grav/app/forms/fields/selectunique.js create mode 100644 plugins/admin/themes/grav/app/forms/fields/text.js create mode 100644 plugins/admin/themes/grav/app/forms/form.js create mode 100644 plugins/admin/themes/grav/app/forms/index.js create mode 100644 plugins/admin/themes/grav/app/forms/state.js create mode 100644 plugins/admin/themes/grav/app/main.js create mode 100644 plugins/admin/themes/grav/app/media/index.js create mode 100644 plugins/admin/themes/grav/app/plugins/index.js create mode 100644 plugins/admin/themes/grav/app/themes/index.js create mode 100644 plugins/admin/themes/grav/app/tools/index.js create mode 100644 plugins/admin/themes/grav/app/tools/logs.js create mode 100644 plugins/admin/themes/grav/app/updates/channel-switcher.js create mode 100644 plugins/admin/themes/grav/app/updates/check.js create mode 100644 plugins/admin/themes/grav/app/updates/feed.js create mode 100644 plugins/admin/themes/grav/app/updates/index.js create mode 100644 plugins/admin/themes/grav/app/updates/notifications.js create mode 100644 plugins/admin/themes/grav/app/updates/update.js create mode 100644 plugins/admin/themes/grav/app/utils/2fa.js create mode 100644 plugins/admin/themes/grav/app/utils/bootstrap-collapse.js create mode 100644 plugins/admin/themes/grav/app/utils/bootstrap-datetimepicker.js create mode 100644 plugins/admin/themes/grav/app/utils/bootstrap-dropdown.js create mode 100644 plugins/admin/themes/grav/app/utils/bootstrap-transition.js create mode 100644 plugins/admin/themes/grav/app/utils/changelog.js create mode 100644 plugins/admin/themes/grav/app/utils/colors.js create mode 100644 plugins/admin/themes/grav/app/utils/cookies.js create mode 100644 plugins/admin/themes/grav/app/utils/cron-ui.js create mode 100644 plugins/admin/themes/grav/app/utils/finderjs.js create mode 100644 plugins/admin/themes/grav/app/utils/formatbytes.js create mode 100644 plugins/admin/themes/grav/app/utils/gpm.js create mode 100644 plugins/admin/themes/grav/app/utils/jquery-utils.js create mode 100644 plugins/admin/themes/grav/app/utils/keepalive.js create mode 100644 plugins/admin/themes/grav/app/utils/offline.js create mode 100644 plugins/admin/themes/grav/app/utils/packages.js create mode 100644 plugins/admin/themes/grav/app/utils/remodal.js create mode 100644 plugins/admin/themes/grav/app/utils/request.js create mode 100644 plugins/admin/themes/grav/app/utils/response.js create mode 100644 plugins/admin/themes/grav/app/utils/selectize-option-click.js create mode 100644 plugins/admin/themes/grav/app/utils/selectize-required-fix.js create mode 100644 plugins/admin/themes/grav/app/utils/sidebar.js create mode 100644 plugins/admin/themes/grav/app/utils/storage.js create mode 100644 plugins/admin/themes/grav/app/utils/tabs-memory.js create mode 100644 plugins/admin/themes/grav/app/utils/toastr.js create mode 100644 plugins/admin/themes/grav/app/whitelabel/compile.js create mode 100644 plugins/admin/themes/grav/app/whitelabel/index.js create mode 100644 plugins/admin/themes/grav/app/whitelabel/presets.js create mode 100644 plugins/admin/themes/grav/css-compiled/nucleus.css create mode 100644 plugins/admin/themes/grav/css-compiled/nucleus.css.map create mode 100644 plugins/admin/themes/grav/css-compiled/preset.css create mode 100644 plugins/admin/themes/grav/css-compiled/preset.css.map create mode 100644 plugins/admin/themes/grav/css-compiled/simple-fonts.css create mode 100644 plugins/admin/themes/grav/css-compiled/simple-fonts.css.map create mode 100644 plugins/admin/themes/grav/css-compiled/template.css create mode 100644 plugins/admin/themes/grav/css-compiled/template.css.map create mode 100644 plugins/admin/themes/grav/css/chartist.min.css create mode 100644 plugins/admin/themes/grav/css/codemirror/codemirror.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/3024-day.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/3024-night.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/abcdef.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/ambiance-mobile.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/ambiance.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/ayu-dark.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/ayu-mirage.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/base16-dark.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/base16-light.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/bespin.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/blackboard.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/cobalt.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/colorforth.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/darcula.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/dracula.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/duotone-dark.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/duotone-light.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/eclipse.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/elegant.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/erlang-dark.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/gruvbox-dark.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/hopscotch.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/icecoder.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/idea.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/isotope.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/lesser-dark.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/liquibyte.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/lucario.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/material-darker.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/material-ocean.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/material-palenight.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/material.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/mbo.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/mdn-like.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/midnight.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/monokai.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/moxer.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/neat.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/neo.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/night.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/nord.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/oceanic-next.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/panda-syntax.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/paper.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/paraiso-dark.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/paraiso-light.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/pastel-on-dark.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/railscasts.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/rubyblue.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/seti.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/shadowfox.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/solarized.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/ssms.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/the-matrix.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/tomorrow-night-bright.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/tomorrow-night-eighties.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/ttcn.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/twilight.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/vibrant-ink.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/xq-dark.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/xq-light.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/yeti.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/yonce.css create mode 100644 plugins/admin/themes/grav/css/codemirror/themes/zenburn.css create mode 100644 plugins/admin/themes/grav/css/fork-awesome.min.css create mode 100644 plugins/admin/themes/grav/css/hint.base.min.css create mode 100644 plugins/admin/themes/grav/css/iconpicker.css create mode 100644 plugins/admin/themes/grav/css/nucleus-ie10.css create mode 100644 plugins/admin/themes/grav/css/nucleus-ie9.css create mode 100644 plugins/admin/themes/grav/css/prism.css create mode 100644 plugins/admin/themes/grav/css/pure-0.5.0/grids-min.css create mode 100644 plugins/admin/themes/grav/css/rtl.css create mode 100644 plugins/admin/themes/grav/css/selectize.min.css create mode 100644 plugins/admin/themes/grav/fonts/forkawesome-webfont.eot create mode 100644 plugins/admin/themes/grav/fonts/forkawesome-webfont.svg create mode 100644 plugins/admin/themes/grav/fonts/forkawesome-webfont.ttf create mode 100644 plugins/admin/themes/grav/fonts/forkawesome-webfont.woff create mode 100644 plugins/admin/themes/grav/fonts/forkawesome-webfont.woff2 create mode 100644 plugins/admin/themes/grav/fonts/rockettheme-apps/rockettheme-apps.eot create mode 100644 plugins/admin/themes/grav/fonts/rockettheme-apps/rockettheme-apps.svg create mode 100644 plugins/admin/themes/grav/fonts/rockettheme-apps/rockettheme-apps.ttf create mode 100644 plugins/admin/themes/grav/fonts/rockettheme-apps/rockettheme-apps.woff create mode 100644 plugins/admin/themes/grav/images/favicon.png create mode 100644 plugins/admin/themes/grav/images/grav-regular.svg create mode 100644 plugins/admin/themes/grav/images/grav-small.svg create mode 100644 plugins/admin/themes/grav/images/icons/book-edit.svg create mode 100644 plugins/admin/themes/grav/images/icons/clock-hands.svg create mode 100644 plugins/admin/themes/grav/images/icons/crown.svg create mode 100644 plugins/admin/themes/grav/images/icons/house.svg create mode 100644 plugins/admin/themes/grav/images/icons/module-four.svg create mode 100644 plugins/admin/themes/grav/images/icons/superman.svg create mode 100644 plugins/admin/themes/grav/images/icons/touchid-lock.svg create mode 100644 plugins/admin/themes/grav/images/logo.svg create mode 100644 plugins/admin/themes/grav/images/transparent.png create mode 100644 plugins/admin/themes/grav/js/admin.min.js create mode 100644 plugins/admin/themes/grav/js/form-attr.polyfill.js create mode 100644 plugins/admin/themes/grav/js/vendor.min.js create mode 100644 plugins/admin/themes/grav/package-lock.json create mode 100644 plugins/admin/themes/grav/package.json create mode 100644 plugins/admin/themes/grav/scss/configuration/nucleus/_base.scss create mode 100644 plugins/admin/themes/grav/scss/configuration/nucleus/_breakpoints.scss create mode 100644 plugins/admin/themes/grav/scss/configuration/nucleus/_core.scss create mode 100644 plugins/admin/themes/grav/scss/configuration/nucleus/_layout.scss create mode 100644 plugins/admin/themes/grav/scss/configuration/nucleus/_nav.scss create mode 100644 plugins/admin/themes/grav/scss/configuration/nucleus/_typography.scss create mode 100644 plugins/admin/themes/grav/scss/configuration/template/_base.scss create mode 100644 plugins/admin/themes/grav/scss/configuration/template/_colors.scss create mode 100644 plugins/admin/themes/grav/scss/configuration/template/_variables.scss create mode 100644 plugins/admin/themes/grav/scss/nucleus.scss create mode 100644 plugins/admin/themes/grav/scss/nucleus/_core.scss create mode 100644 plugins/admin/themes/grav/scss/nucleus/_flex.scss create mode 100644 plugins/admin/themes/grav/scss/nucleus/_forms.scss create mode 100644 plugins/admin/themes/grav/scss/nucleus/_typography.scss create mode 100644 plugins/admin/themes/grav/scss/nucleus/functions/_base.scss create mode 100644 plugins/admin/themes/grav/scss/nucleus/functions/_direction.scss create mode 100644 plugins/admin/themes/grav/scss/nucleus/functions/_range.scss create mode 100644 plugins/admin/themes/grav/scss/nucleus/mixins/_base.scss create mode 100644 plugins/admin/themes/grav/scss/nucleus/mixins/_breakpoints.scss create mode 100644 plugins/admin/themes/grav/scss/nucleus/mixins/_utilities.scss create mode 100644 plugins/admin/themes/grav/scss/nucleus/particles/_align-text.scss create mode 100644 plugins/admin/themes/grav/scss/nucleus/particles/_visibility.scss create mode 100644 plugins/admin/themes/grav/scss/preset.scss create mode 100644 plugins/admin/themes/grav/scss/simple-fonts.scss create mode 100644 plugins/admin/themes/grav/scss/template.scss create mode 100644 plugins/admin/themes/grav/scss/template/_admin.scss create mode 100644 plugins/admin/themes/grav/scss/template/_buttons.scss create mode 100644 plugins/admin/themes/grav/scss/template/_changelog.scss create mode 100644 plugins/admin/themes/grav/scss/template/_colors.scss create mode 100644 plugins/admin/themes/grav/scss/template/_core.scss create mode 100644 plugins/admin/themes/grav/scss/template/_custom.scss create mode 100644 plugins/admin/themes/grav/scss/template/_dropzone.scss create mode 100644 plugins/admin/themes/grav/scss/template/_editor.scss create mode 100644 plugins/admin/themes/grav/scss/template/_errors.scss create mode 100644 plugins/admin/themes/grav/scss/template/_extensions.scss create mode 100644 plugins/admin/themes/grav/scss/template/_fonts.scss create mode 100644 plugins/admin/themes/grav/scss/template/_forms.scss create mode 100644 plugins/admin/themes/grav/scss/template/_gpm.scss create mode 100644 plugins/admin/themes/grav/scss/template/_header.scss create mode 100644 plugins/admin/themes/grav/scss/template/_horizontal-scroll.scss create mode 100644 plugins/admin/themes/grav/scss/template/_jqcron.scss create mode 100644 plugins/admin/themes/grav/scss/template/_login.scss create mode 100644 plugins/admin/themes/grav/scss/template/_media.scss create mode 100644 plugins/admin/themes/grav/scss/template/_nav-toggle.scss create mode 100644 plugins/admin/themes/grav/scss/template/_notifications.scss create mode 100644 plugins/admin/themes/grav/scss/template/_pages.scss create mode 100644 plugins/admin/themes/grav/scss/template/_phpinfo.scss create mode 100644 plugins/admin/themes/grav/scss/template/_remodal.scss create mode 100644 plugins/admin/themes/grav/scss/template/_scrollbars.scss create mode 100644 plugins/admin/themes/grav/scss/template/_tables.scss create mode 100644 plugins/admin/themes/grav/scss/template/_tabs.scss create mode 100644 plugins/admin/themes/grav/scss/template/_toastr.scss create mode 100644 plugins/admin/themes/grav/scss/template/_tools.scss create mode 100644 plugins/admin/themes/grav/scss/template/_typography.scss create mode 100644 plugins/admin/themes/grav/scss/template/_utilities.scss create mode 100644 plugins/admin/themes/grav/scss/template/_whitelabel.scss create mode 100644 plugins/admin/themes/grav/scss/template/modules/_base.scss create mode 100644 plugins/admin/themes/grav/scss/template/modules/_bourbon_essentials.scss create mode 100644 plugins/admin/themes/grav/scss/template/modules/_buttons.scss create mode 100644 plugins/admin/themes/grav/scss/template/modules/_colorpicker.scss create mode 100644 plugins/admin/themes/grav/scss/template/modules/_datetimepicker.scss create mode 100644 plugins/admin/themes/grav/scss/template/modules/_finderjs.scss create mode 100644 plugins/admin/themes/grav/scss/template/modules/_input-range.scss create mode 100644 plugins/admin/themes/grav/scss/template/modules/_scrollbars.scss create mode 100644 plugins/admin/themes/grav/scss/template/modules/_toggle-switch.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/_bourbon-deprecated-upcoming.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/_bourbon.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/addons/_button.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/addons/_clearfix.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/addons/_directional-values.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/addons/_ellipsis.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/addons/_font-family.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/addons/_hide-text.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/addons/_html5-input-types.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/addons/_position.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/addons/_prefixer.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/addons/_rem.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/addons/_retina-image.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/addons/_size.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/addons/_timing-functions.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/addons/_triangle.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/addons/_word-wrap.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/css3/_animation.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/css3/_appearance.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/css3/_backface-visibility.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/css3/_background-image.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/css3/_background.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/css3/_border-image.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/css3/_border-radius.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/css3/_box-sizing.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/css3/_calc.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/css3/_columns.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/css3/_filter.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/css3/_flex-box.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/css3/_font-face.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/css3/_font-feature-settings.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/css3/_hidpi-media-query.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/css3/_hyphens.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/css3/_image-rendering.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/css3/_keyframes.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/css3/_linear-gradient.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/css3/_perspective.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/css3/_placeholder.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/css3/_radial-gradient.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/css3/_transform.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/css3/_transition.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/css3/_user-select.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/functions/_assign.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/functions/_color-lightness.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/functions/_flex-grid.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/functions/_golden-ratio.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/functions/_grid-width.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/functions/_modular-scale.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/functions/_px-to-em.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/functions/_px-to-rem.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/functions/_strip-units.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/functions/_tint-shade.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/functions/_transition-property-name.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/functions/_unpack.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/helpers/_convert-units.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/helpers/_gradient-positions-parser.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/helpers/_is-num.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/helpers/_linear-angle-parser.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/helpers/_linear-gradient-parser.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/helpers/_linear-positions-parser.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/helpers/_linear-side-corner-parser.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/helpers/_radial-arg-parser.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/helpers/_radial-gradient-parser.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/helpers/_radial-positions-parser.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/helpers/_render-gradients.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/helpers/_shape-size-stripper.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/helpers/_str-to-num.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/settings/_prefixer.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/bourbon/settings/_px-to-em.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/color-schemer/_color-schemer.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/color-schemer/color-schemer/_cmyk.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/color-schemer/color-schemer/_color-adjustments.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/color-schemer/color-schemer/_color-schemer.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/color-schemer/color-schemer/_colorblind.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/color-schemer/color-schemer/_comparison.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/color-schemer/color-schemer/_equalize.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/color-schemer/color-schemer/_harmonize.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/color-schemer/color-schemer/_interpolation.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/color-schemer/color-schemer/_mix.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/color-schemer/color-schemer/_mixins.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/color-schemer/color-schemer/_ryb.scss create mode 100644 plugins/admin/themes/grav/scss/vendor/color-schemer/color-schemer/_tint-shade.scss create mode 100644 plugins/admin/themes/grav/templates/changelog.html.twig create mode 100644 plugins/admin/themes/grav/templates/config.html.twig create mode 100644 plugins/admin/themes/grav/templates/dashboard.html.twig create mode 100644 plugins/admin/themes/grav/templates/default.json.twig create mode 100644 plugins/admin/themes/grav/templates/denied.html.twig create mode 100644 plugins/admin/themes/grav/templates/email/base.html.twig create mode 100644 plugins/admin/themes/grav/templates/empty.html.twig create mode 100644 plugins/admin/themes/grav/templates/error.html.twig create mode 100644 plugins/admin/themes/grav/templates/error.json.twig create mode 100644 plugins/admin/themes/grav/templates/forgot.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/field.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/acl_picker/acl_picker.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/array/array.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/backupshistory/backupshistory.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/blueprint/blueprint.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/codemirror/codemirror.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/colorpicker/colorpicker.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/colorscheme.color/colorscheme.color.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/colorscheme/colorscheme.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/column/column.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/columns/columns.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/cron/cron.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/cronstatus/cronstatus.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/dateformat/dateformat.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/datetime/datetime.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/editor/editor.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/element/element.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/elements/elements.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/fieldset/fieldset.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/file/file.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/filepicker/filepicker.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/folder-slug/folder-slug.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/frontmatter/frontmatter.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/iconpicker/iconpicker.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/iconpicker/icons.yaml create mode 100644 plugins/admin/themes/grav/templates/forms/fields/list/list.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/markdown/markdown.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/mediapicker/mediapicker.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/multilevel/multilevel.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/order/order.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/pagemedia/pagemedia.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/pagemediaselect/pagemediaselect.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/parents/parents.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/permissions/permissions.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/range/range.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/section/section.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/selectize/selectize.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/selectunique/selectunique.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/taxonomy/taxonomy.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/themepreview/themepreview.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/themeselect/themeselect.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/userinfo/userinfo.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/widgets/widgets.html.twig create mode 100644 plugins/admin/themes/grav/templates/forms/fields/xss/xss.html.twig create mode 100644 plugins/admin/themes/grav/templates/installer.html.twig create mode 100644 plugins/admin/themes/grav/templates/login.html.twig create mode 100644 plugins/admin/themes/grav/templates/media-list-content.html.twig create mode 100644 plugins/admin/themes/grav/templates/pages.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/backups-button.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/base-root.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/base.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/blueprints-copy.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/blueprints-new-folder.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/blueprints-new.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/blueprints-raw.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/blueprints.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/dashboard-feed.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/dashboard-maintenance.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/dashboard-notifications.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/dashboard-pages.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/dashboard-problems.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/dashboard-statistics.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/feed-block.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/footer.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/header.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/javascript-config.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/javascripts.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/list-sort.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/login-form.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/login-logo.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/login-logout.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/login-twofa.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/login.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/logo.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/media-list-wrapper.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/media-list-wrapper__list.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/media-list-wrapper__list__filters.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/media-list-wrapper__sidebar.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/messages.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/modal-add-package.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/modal-changelog.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/modal-changes-detected.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/modal-reinstall-package.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/modal-remove-package.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/modal-switch-theme.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/modal-update-packages.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/nav-quick-tray.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/nav-toggle.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/nav-user-avatar.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/nav-user-details.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/nav.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/notification-dashboard-block.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/notification-feed-block.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/notification-plugins-block.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/notification-themes-block.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/notification-top-block.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/page-children.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/page-legend.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/page-move.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/plugin-data.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/plugins-details.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/plugins-list.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/register.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/release-toggle.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/spinning-wheel.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/stylesheets.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/theme.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/themes-details.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/themes-list.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/tools-backups-titlebar.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/tools-backups.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/tools-direct-install.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/tools-logs.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/tools-reports.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/tools-scheduler-titlebar.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/tools-scheduler.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/userinfo-avatar-credit.html.twig create mode 100644 plugins/admin/themes/grav/templates/partials/userinfo-avatar.html.twig create mode 100644 plugins/admin/themes/grav/templates/plugins.html.twig create mode 100644 plugins/admin/themes/grav/templates/plugins/admin-buttons.html.twig create mode 100644 plugins/admin/themes/grav/templates/preview.html.twig create mode 100644 plugins/admin/themes/grav/templates/register.html.twig create mode 100644 plugins/admin/themes/grav/templates/reports/security.html.twig create mode 100644 plugins/admin/themes/grav/templates/reports/yamllinter.html.twig create mode 100644 plugins/admin/themes/grav/templates/reset.html.twig create mode 100644 plugins/admin/themes/grav/templates/statistics.html.twig create mode 100644 plugins/admin/themes/grav/templates/themes.html.twig create mode 100644 plugins/admin/themes/grav/templates/tools.html.twig create mode 100644 plugins/admin/themes/grav/templates/unauthorized.html.twig create mode 100644 plugins/admin/themes/grav/templates/user.html.twig create mode 100644 plugins/admin/themes/grav/theme.yaml create mode 100644 plugins/admin/themes/grav/watch.sh create mode 100644 plugins/admin/themes/grav/webpack.conf.js create mode 100644 plugins/admin/themes/grav/yarn.lock create mode 100644 plugins/admin/twig/AdminTwigExtension.php create mode 100644 plugins/admin/vendor/autoload.php create mode 100644 plugins/admin/vendor/bin/picofeed create mode 100644 plugins/admin/vendor/bin/pscss create mode 100644 plugins/admin/vendor/composer/ClassLoader.php create mode 100644 plugins/admin/vendor/composer/InstalledVersions.php create mode 100644 plugins/admin/vendor/composer/LICENSE create mode 100644 plugins/admin/vendor/composer/autoload_classmap.php create mode 100644 plugins/admin/vendor/composer/autoload_files.php create mode 100644 plugins/admin/vendor/composer/autoload_namespaces.php create mode 100644 plugins/admin/vendor/composer/autoload_psr4.php create mode 100644 plugins/admin/vendor/composer/autoload_real.php create mode 100644 plugins/admin/vendor/composer/autoload_static.php create mode 100644 plugins/admin/vendor/composer/installed.json create mode 100644 plugins/admin/vendor/composer/installed.php create mode 100644 plugins/admin/vendor/composer/platform_check.php create mode 100644 plugins/admin/vendor/laminas/laminas-xml/.github/workflows/auto-close.yml create mode 100644 plugins/admin/vendor/laminas/laminas-xml/.github/workflows/continuous-integration.yml create mode 100644 plugins/admin/vendor/laminas/laminas-xml/.github/workflows/release-on-milestone-closed.yml create mode 100644 plugins/admin/vendor/laminas/laminas-xml/COPYRIGHT.md create mode 100644 plugins/admin/vendor/laminas/laminas-xml/LICENSE.md create mode 100644 plugins/admin/vendor/laminas/laminas-xml/README.md create mode 100644 plugins/admin/vendor/laminas/laminas-xml/composer.json create mode 100644 plugins/admin/vendor/laminas/laminas-xml/composer.lock create mode 100644 plugins/admin/vendor/laminas/laminas-xml/src/Exception/ExceptionInterface.php create mode 100644 plugins/admin/vendor/laminas/laminas-xml/src/Exception/InvalidArgumentException.php create mode 100644 plugins/admin/vendor/laminas/laminas-xml/src/Exception/RuntimeException.php create mode 100644 plugins/admin/vendor/laminas/laminas-xml/src/Security.php create mode 100644 plugins/admin/vendor/laminas/laminas-zendframework-bridge/.github/FUNDING.yml create mode 100644 plugins/admin/vendor/laminas/laminas-zendframework-bridge/.github/workflows/continuous-integration.yml create mode 100644 plugins/admin/vendor/laminas/laminas-zendframework-bridge/.github/workflows/release-on-milestone-closed.yml create mode 100644 plugins/admin/vendor/laminas/laminas-zendframework-bridge/.laminas-ci.json create mode 100644 plugins/admin/vendor/laminas/laminas-zendframework-bridge/COPYRIGHT.md create mode 100644 plugins/admin/vendor/laminas/laminas-zendframework-bridge/LICENSE.md create mode 100644 plugins/admin/vendor/laminas/laminas-zendframework-bridge/README.md create mode 100644 plugins/admin/vendor/laminas/laminas-zendframework-bridge/composer.json create mode 100644 plugins/admin/vendor/laminas/laminas-zendframework-bridge/composer.lock create mode 100644 plugins/admin/vendor/laminas/laminas-zendframework-bridge/config/replacements.php create mode 100644 plugins/admin/vendor/laminas/laminas-zendframework-bridge/psalm-baseline.xml create mode 100644 plugins/admin/vendor/laminas/laminas-zendframework-bridge/psalm.xml.dist create mode 100644 plugins/admin/vendor/laminas/laminas-zendframework-bridge/src/Autoloader.php create mode 100644 plugins/admin/vendor/laminas/laminas-zendframework-bridge/src/ConfigPostProcessor.php create mode 100644 plugins/admin/vendor/laminas/laminas-zendframework-bridge/src/Module.php create mode 100644 plugins/admin/vendor/laminas/laminas-zendframework-bridge/src/Replacements.php create mode 100644 plugins/admin/vendor/laminas/laminas-zendframework-bridge/src/RewriteRules.php create mode 100644 plugins/admin/vendor/laminas/laminas-zendframework-bridge/src/autoload.php create mode 100644 plugins/admin/vendor/p3k/picofeed/LICENSE create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Base.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/Client.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/ClientException.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/Curl.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/ForbiddenException.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/HttpHeaders.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/InvalidCertificateException.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/InvalidUrlException.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/MaxRedirectException.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/MaxSizeException.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/Stream.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/TimeoutException.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/UnauthorizedException.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Client/Url.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Config/Config.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Encoding/Encoding.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Filter/Attribute.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Filter/Filter.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Filter/Html.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Filter/Tag.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Generator/ContentGeneratorInterface.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Generator/FileContentGenerator.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Generator/YoutubeContentGenerator.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Logging/Logger.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Atom.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/DateParser.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Feed.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Item.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/MalformedXmlException.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Parser.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/ParserException.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/ParserInterface.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Rss10.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Rss20.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Rss91.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Rss92.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/XmlEntityException.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/XmlParser.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/PicoFeedException.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ContentFilterProcessor.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ContentGeneratorProcessor.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ItemPostProcessor.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ItemProcessorInterface.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ScraperProcessor.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/Favicon.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/Reader.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/ReaderException.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/SubscriptionNotFoundException.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/UnsupportedFeedFormatException.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.blog.lemonde.fr.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.blogs.nytimes.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.igen.fr.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.nytimes.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.over-blog.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.phoronix.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.slate.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.theguardian.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wikipedia.org.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wired.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wsj.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/01net.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/24.hu.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/444.hu.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/888.hu.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/abstrusegoose.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/achgut.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/adventuregamers.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/alainonline.net.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/aljazeera.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/allafrica.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/allgemeine-zeitung.de.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/amazingsuperpowers.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/anythingcomic.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ap.org.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/areadvd.de.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/arstechnica.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/atv.hu.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/awkwardzombie.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/backchannel.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bangkokpost.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bauerwilli.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bgr.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bigfootjustice.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bigpicture.ru.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bizjournals.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/biztimes.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bleepingcomputer.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/blog.fefe.de.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/blog.mapillary.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/brewers.mlb.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/buenosairesherald.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bunicomic.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/buttersafe.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cad-comic.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/chaoslife.findchaos.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/chinafile.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cicero.de.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cliquerefresh.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cnet.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/coinwelt.de.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/consomac.fr.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cowbirdsinlove.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/crash.net.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/csmonitor.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailyjs.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailyreporter.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailytech.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/degroupnews.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/derstandard.at.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dilbert.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/discovermagazine.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/distrowatch.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dozodomo.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/drawingboardcomic.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/e-w-e.ru.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/economist.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/encyclopedie.naheulbeuk.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/endlessorigami.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/engadget.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/escapistmagazine.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/espn.go.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/exocomics.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/explosm.net.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/extrafabulouscomics.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/factroom.ru.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcodesign.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcoexist.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcompany.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ffworld.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/foreignpolicy.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fossbytes.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fototelegraf.ru.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fowllanguagecomics.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gamechannel.hu.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gamestar.hu.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/geek.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/geektimes.ru.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gerbilwithajetpack.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/giantitp.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/github.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gocomics.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/golem.de.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gondola.hu.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gorabbit.ru.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/habrahabr.ru.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/happletea.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hardware.fr.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/heise.de.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hirek.prim.hu.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hotshowlife.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/huffingtonpost.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hvg.hu.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/idokep.hu.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/imogenquest.net.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/index.hu.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/indiehaven.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/inforadio.hu.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ing.dk.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/invisiblebread.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ir.amd.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/japantimes.co.jp.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/japantoday.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/journaldugeek.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/jsonline.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/justcoolidea.ru.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kanpai.fr.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/karriere.jobfinder.dk.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kisalfold.hu.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kiszamolo.hu.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kodi.tv.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/koreaherald.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/koreatimes.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lastplacecomics.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/legorafi.fr.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lejapon.fr.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lesjoiesducode.fr.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lfg.co.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lifehacker.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lifehacker.ru.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux-magazin.de.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux.org.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux.org.ru.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linuxinsider.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lists.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/loadingartist.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/loldwell.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lukesurl.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/macg.co.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/maclife.de.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/magyarkurir.hu.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marc.info.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marriedtothesea.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marycagle.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/maximumble.thebookofbiff.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/medium.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mercworks.net.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/metronieuws.nl.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/milwaukeenns.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mno.hu.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mokepon.smackjeeves.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/monandroid.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/monwindows.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/moya-planeta.ru.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mrlovenstein.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/muckrock.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mynorthshorenow.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nakedCapitalism.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nasa.gov.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nat-geo.ru.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nationaljournal.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nature.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nba.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nedroid.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/networkworld.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/neustadt-ticker.de.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nextinpact.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/niceteethcomic.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nichtlustig.de.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nlcafe.hu.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/novo-argumente.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/oglaf.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/onhax.net.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/onlinekosten.de.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/onmilwaukee.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/openculture.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/opennet.ru.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/openrightsgroup.org.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/opensource.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/optipess.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/origo.hu.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/osnews.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pastebin.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pcgameshardware.de.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/peebleslab.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/penny-arcade.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pixelbeat.org.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/plus.google.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/popstrip.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/portfolio.hu.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pro-linux.de.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/publicpolicyforum.org.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/publy.ru.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/putaindecode.fr.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/recode.net.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/retractionwatch.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/rockpapershotgun.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/rue89.nouvelobs.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/rugbyrama.fr.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/salonkolumnisten.com create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/satwcomic.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/science-skeptical.de.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/scrumalliance.org.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/securityfocus.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/sentfromthemoon.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/sitepoint.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/slashdot.org.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smallhousebliss.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smarthomewelt.de.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smashingmagazine.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smbc-comics.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/snopes.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/soundandvision.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/spiegel.de.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/stereophile.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/stupidfox.net.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/subtraction.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/sz.de.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/takprosto.cc.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/techcrunch.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/the-ebook-reader.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theatlantic.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theawkwardyeti.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thecodinglove.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thedoghousediaries.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thegamercat.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thehindu.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thelocal.se.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/themerepublic.net.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/themoscowtimes.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thenewslens.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theodd1sout.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theonion.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theregister.co.uk.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thestandard.com.hk.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theverge.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/threepanelsoul.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/tichyseinblick.de.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/timesofindia.indiatimes.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/totalcar.hu.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/tozsdeforum.hu.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/travel-dealz.de.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/travelo.hu.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/treehugger.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/treelobsters.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/tutorialzine.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/twogag.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/twokinds.keenspot.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/undeadly.org.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/upi.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/usatoday.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/version2.dk.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/vezess.hu.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/vgcats.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/vuxml.org.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/wausaudailyherald.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/welt.de.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/westfalen-blatt.de.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.bbc.co.uk.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.bdgest.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.bgr.in.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.businessweek.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.cnn.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.developpez.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.egscomics.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.fakingnews.firstpost.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.forbes.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.franceculture.fr.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.futura-sciences.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.geekculture.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.howtogeek.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.lepoint.fr.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.lesnumeriques.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.mac4ever.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.makeuseof.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.monsieur-le-chien.fr.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.npr.org.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.numerama.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.oneindia.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.pseudo-sciences.org.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.sciencemag.org.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.slate.fr.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.universfreebox.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.zeit.de.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/xkcd.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ymatuhin.ru.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/zarojel.hu.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/zdnet.com.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/zoom.hu.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/CandidateParser.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/ParserInterface.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/RuleLoader.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/RuleParser.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/Scraper.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/Subscription.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionList.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionListBuilder.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionListParser.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionParser.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/AtomFeedBuilder.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/AtomHelper.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/AtomItemBuilder.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/FeedBuilder.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/ItemBuilder.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/Rss20FeedBuilder.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/Rss20Helper.php create mode 100644 plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/Rss20ItemBuilder.php create mode 100644 plugins/admin/vendor/p3k/picofeed/picofeed create mode 100644 plugins/admin/vendor/scssphp/scssphp/LICENSE.md create mode 100644 plugins/admin/vendor/scssphp/scssphp/README.md create mode 100644 plugins/admin/vendor/scssphp/scssphp/bin/pscss create mode 100644 plugins/admin/vendor/scssphp/scssphp/composer.json create mode 100644 plugins/admin/vendor/scssphp/scssphp/scss.inc.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Base/Range.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Block.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Block/AtRootBlock.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Block/CallableBlock.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Block/ContentBlock.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Block/DirectiveBlock.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Block/EachBlock.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Block/ElseBlock.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Block/ElseifBlock.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Block/ForBlock.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Block/IfBlock.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Block/MediaBlock.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Block/NestedPropertyBlock.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Block/WhileBlock.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Cache.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Colors.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/CompilationResult.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Compiler.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Compiler/CachedResult.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Compiler/Environment.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Exception/CompilerException.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Exception/ParserException.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Exception/RangeException.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Exception/SassException.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Exception/SassScriptException.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Exception/ServerException.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Formatter.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Formatter/Compact.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Formatter/Compressed.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Formatter/Crunched.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Formatter/Debug.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Formatter/Expanded.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Formatter/Nested.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Formatter/OutputBlock.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Logger/LoggerInterface.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Logger/QuietLogger.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Logger/StreamLogger.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Node.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Node/Number.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/OutputStyle.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Parser.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/SourceMap/Base64.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/SourceMap/Base64VLQ.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/SourceMap/SourceMapGenerator.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Type.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Util.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Util/Path.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/ValueConverter.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Version.php create mode 100644 plugins/admin/vendor/scssphp/scssphp/src/Warn.php create mode 100755 plugins/auto-author/.gitignore create mode 100755 plugins/auto-author/CHANGELOG.md create mode 100755 plugins/auto-author/LICENSE create mode 100755 plugins/auto-author/README.md create mode 100755 plugins/auto-author/auto-author.php create mode 100755 plugins/auto-author/auto-author.yaml create mode 100755 plugins/auto-author/blueprints.yaml create mode 100755 plugins/auto-date/CHANGELOG.md create mode 100755 plugins/auto-date/LICENSE create mode 100755 plugins/auto-date/README.md create mode 100755 plugins/auto-date/auto-date.php create mode 100755 plugins/auto-date/auto-date.yaml create mode 100755 plugins/auto-date/blueprints.yaml create mode 100755 plugins/autoseo/.gitignore create mode 100755 plugins/autoseo/CHANGELOG.md create mode 100755 plugins/autoseo/CODE_OF_CONDUCT.md create mode 100755 plugins/autoseo/CONTRIBUTING.md create mode 100755 plugins/autoseo/LICENSE create mode 100755 plugins/autoseo/README.md create mode 100755 plugins/autoseo/autoseo.php create mode 100755 plugins/autoseo/autoseo.yaml create mode 100755 plugins/autoseo/blueprints.yaml create mode 100755 plugins/autoseo/languages.yaml create mode 100755 plugins/childlist/CHANGELOG.md create mode 100755 plugins/childlist/LICENSE create mode 100755 plugins/childlist/README.md create mode 100755 plugins/childlist/blueprints.yaml create mode 100755 plugins/childlist/childlist.php create mode 100755 plugins/childlist/childlist.yaml create mode 100755 plugins/childlist/composer.json create mode 100755 plugins/childlist/composer.lock create mode 100755 plugins/childlist/languages.yaml create mode 100755 plugins/childlist/template/form/fields/childlist/childlist.html.twig create mode 100755 plugins/childlist/vendor/autoload.php create mode 100755 plugins/childlist/vendor/composer/ClassLoader.php create mode 100755 plugins/childlist/vendor/composer/LICENSE create mode 100755 plugins/childlist/vendor/composer/autoload_classmap.php create mode 100755 plugins/childlist/vendor/composer/autoload_namespaces.php create mode 100755 plugins/childlist/vendor/composer/autoload_psr4.php create mode 100755 plugins/childlist/vendor/composer/autoload_real.php create mode 100755 plugins/childlist/vendor/composer/autoload_static.php create mode 100755 plugins/childlist/vendor/composer/installed.json create mode 100755 plugins/cookieconsent/.gitignore create mode 100755 plugins/cookieconsent/.scrutinizer.yml create mode 100755 plugins/cookieconsent/.travis.yml create mode 100755 plugins/cookieconsent/CHANGELOG.md create mode 100755 plugins/cookieconsent/LICENSE create mode 100755 plugins/cookieconsent/README.md create mode 100755 plugins/cookieconsent/assets/cookieconsent.min.css create mode 100755 plugins/cookieconsent/assets/cookieconsent.min.js create mode 100755 plugins/cookieconsent/assets/readme_1.png create mode 100755 plugins/cookieconsent/blueprints.yaml create mode 100755 plugins/cookieconsent/codeception.yml create mode 100755 plugins/cookieconsent/composer.json create mode 100755 plugins/cookieconsent/cookieconsent.php create mode 100755 plugins/cookieconsent/cookieconsent.yaml create mode 100755 plugins/cookieconsent/languages.yaml create mode 100755 plugins/cookieconsent/templates/partials/cookieconsent.html.twig create mode 100755 plugins/cookieconsent/tests/_bootstrap.php create mode 100755 plugins/cookieconsent/tests/_output/.gitignore create mode 100755 plugins/cookieconsent/tests/_support/Helper/Unit.php create mode 100755 plugins/cookieconsent/tests/_support/UnitTester.php create mode 100755 plugins/cookieconsent/tests/unit.suite.yml create mode 100755 plugins/cookieconsent/tests/unit/CookieconsentPluginTest.php create mode 100755 plugins/cookieconsent/tests/unit/_bootstrap.php create mode 100644 plugins/devtools/CHANGELOG.md create mode 100644 plugins/devtools/LICENSE create mode 100644 plugins/devtools/README.md create mode 100644 plugins/devtools/blueprints.yaml create mode 100644 plugins/devtools/classes/DevToolsCommand.php create mode 100644 plugins/devtools/cli/NewBlueprintCommand.php create mode 100644 plugins/devtools/cli/NewPluginCommand.php create mode 100644 plugins/devtools/cli/NewThemeCommand.php create mode 100644 plugins/devtools/components/blueprint/append/blueprint.yaml.twig create mode 100644 plugins/devtools/components/blueprint/newtab/blueprint.yaml.twig create mode 100644 plugins/devtools/components/plugin/blank/CHANGELOG.md.twig create mode 100644 plugins/devtools/components/plugin/blank/LICENSE.twig create mode 100644 plugins/devtools/components/plugin/blank/README.md.twig create mode 100644 plugins/devtools/components/plugin/blank/blueprints.yaml.twig create mode 100644 plugins/devtools/components/plugin/blank/classes/.gitkeep create mode 100644 plugins/devtools/components/plugin/blank/composer.json.twig create mode 100644 plugins/devtools/components/plugin/blank/languages.yaml.twig create mode 100644 plugins/devtools/components/plugin/blank/plugin.php.twig create mode 100644 plugins/devtools/components/plugin/blank/plugin.yaml.twig create mode 100644 plugins/devtools/components/plugin/flex/CHANGELOG.md.twig create mode 100644 plugins/devtools/components/plugin/flex/LICENSE.twig create mode 100644 plugins/devtools/components/plugin/flex/README.md.twig create mode 100644 plugins/devtools/components/plugin/flex/blueprints.yaml.twig create mode 100644 plugins/devtools/components/plugin/flex/blueprints/flex-objects/plugin.yaml.twig create mode 100644 plugins/devtools/components/plugin/flex/classes/.gitkeep create mode 100644 plugins/devtools/components/plugin/flex/classes/Flex/Types/flex_name/Collection.php.twig create mode 100644 plugins/devtools/components/plugin/flex/classes/Flex/Types/flex_name/Object.php.twig create mode 100644 plugins/devtools/components/plugin/flex/composer.json.twig create mode 100644 plugins/devtools/components/plugin/flex/languages.yaml.twig create mode 100644 plugins/devtools/components/plugin/flex/plugin.php.twig create mode 100644 plugins/devtools/components/plugin/flex/plugin.yaml.twig create mode 100644 plugins/devtools/components/theme/inheritance/CHANGELOG.md.twig create mode 100644 plugins/devtools/components/theme/inheritance/LICENSE.twig create mode 100644 plugins/devtools/components/theme/inheritance/README.md.twig create mode 100644 plugins/devtools/components/theme/inheritance/blueprints.yaml.twig create mode 100644 plugins/devtools/components/theme/inheritance/css/.gitkeep create mode 100644 plugins/devtools/components/theme/inheritance/js/.gitkeep create mode 100644 plugins/devtools/components/theme/inheritance/screenshot.jpg create mode 100644 plugins/devtools/components/theme/inheritance/templates/.gitkeep create mode 100644 plugins/devtools/components/theme/inheritance/theme.php.twig create mode 100644 plugins/devtools/components/theme/inheritance/theme.yaml.twig create mode 100644 plugins/devtools/components/theme/inheritance/thumbnail.jpg create mode 100644 plugins/devtools/components/theme/pure-blank/CHANGELOG.md.twig create mode 100644 plugins/devtools/components/theme/pure-blank/LICENSE.twig create mode 100644 plugins/devtools/components/theme/pure-blank/README.md.twig create mode 100644 plugins/devtools/components/theme/pure-blank/blueprints.yaml.twig create mode 100644 plugins/devtools/components/theme/pure-blank/css/custom.css create mode 100644 plugins/devtools/components/theme/pure-blank/fonts/.gitkeep create mode 100644 plugins/devtools/components/theme/pure-blank/images/logo.png create mode 100644 plugins/devtools/components/theme/pure-blank/js/.gitkeep create mode 100644 plugins/devtools/components/theme/pure-blank/screenshot.jpg create mode 100644 plugins/devtools/components/theme/pure-blank/templates/default.html.twig create mode 100644 plugins/devtools/components/theme/pure-blank/templates/error.html.twig create mode 100644 plugins/devtools/components/theme/pure-blank/templates/partials/base.html.twig create mode 100644 plugins/devtools/components/theme/pure-blank/templates/partials/navigation.html.twig create mode 100644 plugins/devtools/components/theme/pure-blank/theme.php.twig create mode 100644 plugins/devtools/components/theme/pure-blank/theme.yaml.twig create mode 100644 plugins/devtools/components/theme/pure-blank/thumbnail.jpg create mode 100644 plugins/devtools/components/theme/tailwind-mix/CHANGELOG.md.twig create mode 100644 plugins/devtools/components/theme/tailwind-mix/LICENSE.twig create mode 100644 plugins/devtools/components/theme/tailwind-mix/README.md.twig create mode 100644 plugins/devtools/components/theme/tailwind-mix/blueprints.yaml.twig create mode 100644 plugins/devtools/components/theme/tailwind-mix/css/site.css create mode 100644 plugins/devtools/components/theme/tailwind-mix/fonts/.gitkeep create mode 100644 plugins/devtools/components/theme/tailwind-mix/images/logo.png create mode 100644 plugins/devtools/components/theme/tailwind-mix/js/.gitkeep create mode 100644 plugins/devtools/components/theme/tailwind-mix/js/main.js create mode 100644 plugins/devtools/components/theme/tailwind-mix/languages/en.yaml.twig create mode 100644 plugins/devtools/components/theme/tailwind-mix/package.json.twig create mode 100644 plugins/devtools/components/theme/tailwind-mix/screenshot.jpg create mode 100644 plugins/devtools/components/theme/tailwind-mix/tailwind.config.js.twig create mode 100644 plugins/devtools/components/theme/tailwind-mix/templates/default.html.twig create mode 100644 plugins/devtools/components/theme/tailwind-mix/templates/error.html.twig create mode 100644 plugins/devtools/components/theme/tailwind-mix/templates/partials/base.html.twig create mode 100644 plugins/devtools/components/theme/tailwind-mix/templates/partials/navigation.html.twig create mode 100644 plugins/devtools/components/theme/tailwind-mix/theme.php.twig create mode 100644 plugins/devtools/components/theme/tailwind-mix/theme.yaml.twig create mode 100644 plugins/devtools/components/theme/tailwind-mix/thumbnail.jpg create mode 100644 plugins/devtools/components/theme/tailwind-mix/webpack.mix.js create mode 100644 plugins/devtools/components/theme/tailwind/CHANGELOG.md.twig create mode 100644 plugins/devtools/components/theme/tailwind/LICENSE.twig create mode 100644 plugins/devtools/components/theme/tailwind/README.md.twig create mode 100644 plugins/devtools/components/theme/tailwind/blueprints.yaml.twig create mode 100644 plugins/devtools/components/theme/tailwind/css/site.css create mode 100644 plugins/devtools/components/theme/tailwind/fonts/.gitkeep create mode 100644 plugins/devtools/components/theme/tailwind/images/logo.png create mode 100644 plugins/devtools/components/theme/tailwind/js/.gitkeep create mode 100644 plugins/devtools/components/theme/tailwind/js/main.js create mode 100644 plugins/devtools/components/theme/tailwind/languages/en.yaml.twig create mode 100644 plugins/devtools/components/theme/tailwind/package-lock.json create mode 100644 plugins/devtools/components/theme/tailwind/package.json.twig create mode 100644 plugins/devtools/components/theme/tailwind/postcss.config.js create mode 100644 plugins/devtools/components/theme/tailwind/screenshot.jpg create mode 100644 plugins/devtools/components/theme/tailwind/tailwind.config.js.twig create mode 100644 plugins/devtools/components/theme/tailwind/templates/default.html.twig create mode 100644 plugins/devtools/components/theme/tailwind/templates/error.html.twig create mode 100644 plugins/devtools/components/theme/tailwind/templates/partials/base.html.twig create mode 100644 plugins/devtools/components/theme/tailwind/templates/partials/navigation.html.twig create mode 100644 plugins/devtools/components/theme/tailwind/theme.php.twig create mode 100644 plugins/devtools/components/theme/tailwind/theme.yaml.twig create mode 100644 plugins/devtools/components/theme/tailwind/thumbnail.jpg create mode 100644 plugins/devtools/components/theme/tailwind/webpack.mix.js create mode 100644 plugins/devtools/devtools.php create mode 100644 plugins/devtools/devtools.yaml create mode 100644 plugins/devtools/languages.yaml create mode 100644 plugins/email/CHANGELOG.md create mode 100644 plugins/email/LICENSE create mode 100644 plugins/email/README.md create mode 100644 plugins/email/blueprints.yaml create mode 100644 plugins/email/classes/Email.php create mode 100644 plugins/email/classes/Message.php create mode 100644 plugins/email/classes/Utils.php create mode 100644 plugins/email/cli/ClearQueueFailuresCommand.php create mode 100644 plugins/email/cli/FlushQueueCommand.php create mode 100644 plugins/email/cli/TestEmailCommand.php create mode 100644 plugins/email/composer.json create mode 100644 plugins/email/composer.lock create mode 100644 plugins/email/email.php create mode 100644 plugins/email/email.yaml create mode 100644 plugins/email/hebe.json create mode 100644 plugins/email/languages.yaml create mode 100644 plugins/email/templates/email/base.html.twig create mode 100644 plugins/email/vendor/autoload.php create mode 100644 plugins/email/vendor/composer/ClassLoader.php create mode 100644 plugins/email/vendor/composer/InstalledVersions.php create mode 100644 plugins/email/vendor/composer/LICENSE create mode 100644 plugins/email/vendor/composer/autoload_classmap.php create mode 100644 plugins/email/vendor/composer/autoload_files.php create mode 100644 plugins/email/vendor/composer/autoload_namespaces.php create mode 100644 plugins/email/vendor/composer/autoload_psr4.php create mode 100644 plugins/email/vendor/composer/autoload_real.php create mode 100644 plugins/email/vendor/composer/autoload_static.php create mode 100644 plugins/email/vendor/composer/installed.json create mode 100644 plugins/email/vendor/composer/installed.php create mode 100644 plugins/email/vendor/composer/platform_check.php create mode 100644 plugins/email/vendor/doctrine/lexer/LICENSE create mode 100644 plugins/email/vendor/doctrine/lexer/README.md create mode 100644 plugins/email/vendor/doctrine/lexer/composer.json create mode 100644 plugins/email/vendor/doctrine/lexer/lib/Doctrine/Common/Lexer/AbstractLexer.php create mode 100644 plugins/email/vendor/doctrine/lexer/psalm.xml create mode 100644 plugins/email/vendor/egulias/email-validator/CHANGELOG.md create mode 100644 plugins/email/vendor/egulias/email-validator/CONTRIBUTING.md create mode 100644 plugins/email/vendor/egulias/email-validator/LICENSE create mode 100644 plugins/email/vendor/egulias/email-validator/composer.json create mode 100644 plugins/email/vendor/egulias/email-validator/composer.lock create mode 100644 plugins/email/vendor/egulias/email-validator/src/EmailLexer.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/EmailParser.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/EmailValidator.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/MessageIDParser.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Parser.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Parser/Comment.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Parser/CommentStrategy/CommentStrategy.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Parser/CommentStrategy/DomainComment.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Parser/CommentStrategy/LocalComment.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Parser/DomainLiteral.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Parser/DomainPart.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Parser/DoubleQuote.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Parser/FoldingWhiteSpace.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Parser/IDLeftPart.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Parser/IDRightPart.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Parser/LocalPart.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Parser/PartParser.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/InvalidEmail.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/MultipleErrors.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/AtextAfterCFWS.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/CRLFAtTheEnd.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/CRLFX2.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/CRNoLF.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/CharNotAllowed.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/CommaInDomain.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/CommentsInIDRight.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/ConsecutiveAt.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/ConsecutiveDot.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/DetailedReason.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/DomainAcceptsNoMail.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/DomainHyphened.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/DomainTooLong.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/DotAtEnd.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/DotAtStart.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/EmptyReason.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/ExceptionFound.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/ExpectingATEXT.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/ExpectingCTEXT.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/ExpectingDTEXT.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/ExpectingDomainLiteralClose.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/LabelTooLong.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/LocalOrReservedDomain.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/NoDNSRecord.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/NoDomainPart.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/NoLocalPart.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/RFCWarnings.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/Reason.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/SpoofEmail.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/UnOpenedComment.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/UnableToGetDNSRecord.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/UnclosedComment.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/UnclosedQuotedString.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Reason/UnusualElements.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/Result.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/SpoofEmail.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Result/ValidEmail.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Validation/DNSCheckValidation.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Validation/DNSGetRecordWrapper.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Validation/DNSRecords.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Validation/EmailValidation.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Validation/Exception/EmptyValidationList.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Validation/Extra/SpoofCheckValidation.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Validation/MessageIDValidation.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Validation/MultipleValidationWithAnd.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Validation/NoRFCWarningsValidation.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Validation/RFCValidation.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Warning/AddressLiteral.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Warning/CFWSNearAt.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Warning/CFWSWithFWS.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Warning/Comment.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Warning/DeprecatedComment.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Warning/DomainLiteral.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Warning/EmailTooLong.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Warning/IPV6BadChar.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Warning/IPV6ColonEnd.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Warning/IPV6ColonStart.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Warning/IPV6Deprecated.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Warning/IPV6DoubleColon.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Warning/IPV6GroupCount.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Warning/IPV6MaxGroups.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Warning/LocalTooLong.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Warning/NoDNSMXRecord.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Warning/ObsoleteDTEXT.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Warning/QuotedPart.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Warning/QuotedString.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Warning/TLD.php create mode 100644 plugins/email/vendor/egulias/email-validator/src/Warning/Warning.php create mode 100644 plugins/email/vendor/psr/container/.gitignore create mode 100644 plugins/email/vendor/psr/container/LICENSE create mode 100644 plugins/email/vendor/psr/container/README.md create mode 100644 plugins/email/vendor/psr/container/composer.json create mode 100644 plugins/email/vendor/psr/container/src/ContainerExceptionInterface.php create mode 100644 plugins/email/vendor/psr/container/src/ContainerInterface.php create mode 100644 plugins/email/vendor/psr/container/src/NotFoundExceptionInterface.php create mode 100644 plugins/email/vendor/psr/event-dispatcher/.editorconfig create mode 100644 plugins/email/vendor/psr/event-dispatcher/.gitignore create mode 100644 plugins/email/vendor/psr/event-dispatcher/LICENSE create mode 100644 plugins/email/vendor/psr/event-dispatcher/README.md create mode 100644 plugins/email/vendor/psr/event-dispatcher/composer.json create mode 100644 plugins/email/vendor/psr/event-dispatcher/src/EventDispatcherInterface.php create mode 100644 plugins/email/vendor/psr/event-dispatcher/src/ListenerProviderInterface.php create mode 100644 plugins/email/vendor/psr/event-dispatcher/src/StoppableEventInterface.php create mode 100644 plugins/email/vendor/symfony/amqp-messenger/CHANGELOG.md create mode 100644 plugins/email/vendor/symfony/amqp-messenger/LICENSE create mode 100644 plugins/email/vendor/symfony/amqp-messenger/README.md create mode 100644 plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpFactory.php create mode 100644 plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpReceivedStamp.php create mode 100644 plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpReceiver.php create mode 100644 plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpSender.php create mode 100644 plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpStamp.php create mode 100644 plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpTransport.php create mode 100644 plugins/email/vendor/symfony/amqp-messenger/Transport/AmqpTransportFactory.php create mode 100644 plugins/email/vendor/symfony/amqp-messenger/Transport/Connection.php create mode 100644 plugins/email/vendor/symfony/amqp-messenger/composer.json create mode 100644 plugins/email/vendor/symfony/deprecation-contracts/.gitignore create mode 100644 plugins/email/vendor/symfony/deprecation-contracts/CHANGELOG.md create mode 100644 plugins/email/vendor/symfony/deprecation-contracts/LICENSE create mode 100644 plugins/email/vendor/symfony/deprecation-contracts/README.md create mode 100644 plugins/email/vendor/symfony/deprecation-contracts/composer.json create mode 100644 plugins/email/vendor/symfony/deprecation-contracts/function.php create mode 100644 plugins/email/vendor/symfony/doctrine-messenger/CHANGELOG.md create mode 100644 plugins/email/vendor/symfony/doctrine-messenger/LICENSE create mode 100644 plugins/email/vendor/symfony/doctrine-messenger/README.md create mode 100644 plugins/email/vendor/symfony/doctrine-messenger/Transport/Connection.php create mode 100644 plugins/email/vendor/symfony/doctrine-messenger/Transport/DoctrineReceivedStamp.php create mode 100644 plugins/email/vendor/symfony/doctrine-messenger/Transport/DoctrineReceiver.php create mode 100644 plugins/email/vendor/symfony/doctrine-messenger/Transport/DoctrineSender.php create mode 100644 plugins/email/vendor/symfony/doctrine-messenger/Transport/DoctrineTransport.php create mode 100644 plugins/email/vendor/symfony/doctrine-messenger/Transport/DoctrineTransportFactory.php create mode 100644 plugins/email/vendor/symfony/doctrine-messenger/Transport/PostgreSqlConnection.php create mode 100644 plugins/email/vendor/symfony/doctrine-messenger/composer.json create mode 100644 plugins/email/vendor/symfony/event-dispatcher-contracts/.gitignore create mode 100644 plugins/email/vendor/symfony/event-dispatcher-contracts/CHANGELOG.md create mode 100644 plugins/email/vendor/symfony/event-dispatcher-contracts/Event.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher-contracts/EventDispatcherInterface.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher-contracts/LICENSE create mode 100644 plugins/email/vendor/symfony/event-dispatcher-contracts/README.md create mode 100644 plugins/email/vendor/symfony/event-dispatcher-contracts/composer.json create mode 100644 plugins/email/vendor/symfony/event-dispatcher/Attribute/AsEventListener.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher/CHANGELOG.md create mode 100644 plugins/email/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher/Debug/WrappedListener.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher/EventDispatcher.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher/EventDispatcherInterface.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher/EventSubscriberInterface.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher/GenericEvent.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher/LICENSE create mode 100644 plugins/email/vendor/symfony/event-dispatcher/LegacyEventDispatcherProxy.php create mode 100644 plugins/email/vendor/symfony/event-dispatcher/README.md create mode 100644 plugins/email/vendor/symfony/event-dispatcher/composer.json create mode 100644 plugins/email/vendor/symfony/mailer/CHANGELOG.md create mode 100644 plugins/email/vendor/symfony/mailer/DataCollector/MessageDataCollector.php create mode 100644 plugins/email/vendor/symfony/mailer/DelayedEnvelope.php create mode 100644 plugins/email/vendor/symfony/mailer/Envelope.php create mode 100644 plugins/email/vendor/symfony/mailer/Event/MessageEvent.php create mode 100644 plugins/email/vendor/symfony/mailer/Event/MessageEvents.php create mode 100644 plugins/email/vendor/symfony/mailer/EventListener/EnvelopeListener.php create mode 100644 plugins/email/vendor/symfony/mailer/EventListener/MessageListener.php create mode 100644 plugins/email/vendor/symfony/mailer/EventListener/MessageLoggerListener.php create mode 100644 plugins/email/vendor/symfony/mailer/Exception/ExceptionInterface.php create mode 100644 plugins/email/vendor/symfony/mailer/Exception/HttpTransportException.php create mode 100644 plugins/email/vendor/symfony/mailer/Exception/IncompleteDsnException.php create mode 100644 plugins/email/vendor/symfony/mailer/Exception/InvalidArgumentException.php create mode 100644 plugins/email/vendor/symfony/mailer/Exception/LogicException.php create mode 100644 plugins/email/vendor/symfony/mailer/Exception/RuntimeException.php create mode 100644 plugins/email/vendor/symfony/mailer/Exception/TransportException.php create mode 100644 plugins/email/vendor/symfony/mailer/Exception/TransportExceptionInterface.php create mode 100644 plugins/email/vendor/symfony/mailer/Exception/UnsupportedSchemeException.php create mode 100644 plugins/email/vendor/symfony/mailer/Header/MetadataHeader.php create mode 100644 plugins/email/vendor/symfony/mailer/Header/TagHeader.php create mode 100644 plugins/email/vendor/symfony/mailer/LICENSE create mode 100644 plugins/email/vendor/symfony/mailer/Mailer.php create mode 100644 plugins/email/vendor/symfony/mailer/MailerInterface.php create mode 100644 plugins/email/vendor/symfony/mailer/Messenger/MessageHandler.php create mode 100644 plugins/email/vendor/symfony/mailer/Messenger/SendEmailMessage.php create mode 100644 plugins/email/vendor/symfony/mailer/README.md create mode 100644 plugins/email/vendor/symfony/mailer/SentMessage.php create mode 100644 plugins/email/vendor/symfony/mailer/Test/Constraint/EmailCount.php create mode 100644 plugins/email/vendor/symfony/mailer/Test/Constraint/EmailIsQueued.php create mode 100644 plugins/email/vendor/symfony/mailer/Test/TransportFactoryTestCase.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/AbstractApiTransport.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/AbstractHttpTransport.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/AbstractTransport.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/AbstractTransportFactory.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Dsn.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/FailoverTransport.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/NativeTransportFactory.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/NullTransport.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/NullTransportFactory.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/RoundRobinTransport.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/SendmailTransport.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/SendmailTransportFactory.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Smtp/Auth/AuthenticatorInterface.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Smtp/Auth/CramMd5Authenticator.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Smtp/Auth/LoginAuthenticator.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Smtp/Auth/PlainAuthenticator.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Smtp/Auth/XOAuth2Authenticator.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Smtp/EsmtpTransport.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Smtp/EsmtpTransportFactory.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Smtp/SmtpTransport.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Smtp/Stream/AbstractStream.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Smtp/Stream/ProcessStream.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Smtp/Stream/SocketStream.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/TransportFactoryInterface.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/TransportInterface.php create mode 100644 plugins/email/vendor/symfony/mailer/Transport/Transports.php create mode 100644 plugins/email/vendor/symfony/mailer/composer.json create mode 100644 plugins/email/vendor/symfony/messenger/Attribute/AsMessageHandler.php create mode 100644 plugins/email/vendor/symfony/messenger/CHANGELOG.md create mode 100644 plugins/email/vendor/symfony/messenger/Command/AbstractFailedMessagesCommand.php create mode 100644 plugins/email/vendor/symfony/messenger/Command/ConsumeMessagesCommand.php create mode 100644 plugins/email/vendor/symfony/messenger/Command/DebugCommand.php create mode 100644 plugins/email/vendor/symfony/messenger/Command/FailedMessagesRemoveCommand.php create mode 100644 plugins/email/vendor/symfony/messenger/Command/FailedMessagesRetryCommand.php create mode 100644 plugins/email/vendor/symfony/messenger/Command/FailedMessagesShowCommand.php create mode 100644 plugins/email/vendor/symfony/messenger/Command/SetupTransportsCommand.php create mode 100644 plugins/email/vendor/symfony/messenger/Command/StopWorkersCommand.php create mode 100644 plugins/email/vendor/symfony/messenger/DataCollector/MessengerDataCollector.php create mode 100644 plugins/email/vendor/symfony/messenger/DependencyInjection/MessengerPass.php create mode 100644 plugins/email/vendor/symfony/messenger/Envelope.php create mode 100644 plugins/email/vendor/symfony/messenger/Event/AbstractWorkerMessageEvent.php create mode 100644 plugins/email/vendor/symfony/messenger/Event/SendMessageToTransportsEvent.php create mode 100644 plugins/email/vendor/symfony/messenger/Event/WorkerMessageFailedEvent.php create mode 100644 plugins/email/vendor/symfony/messenger/Event/WorkerMessageHandledEvent.php create mode 100644 plugins/email/vendor/symfony/messenger/Event/WorkerMessageReceivedEvent.php create mode 100644 plugins/email/vendor/symfony/messenger/Event/WorkerMessageRetriedEvent.php create mode 100644 plugins/email/vendor/symfony/messenger/Event/WorkerRunningEvent.php create mode 100644 plugins/email/vendor/symfony/messenger/Event/WorkerStartedEvent.php create mode 100644 plugins/email/vendor/symfony/messenger/Event/WorkerStoppedEvent.php create mode 100644 plugins/email/vendor/symfony/messenger/EventListener/AddErrorDetailsStampListener.php create mode 100644 plugins/email/vendor/symfony/messenger/EventListener/DispatchPcntlSignalListener.php create mode 100644 plugins/email/vendor/symfony/messenger/EventListener/ResetServicesListener.php create mode 100644 plugins/email/vendor/symfony/messenger/EventListener/SendFailedMessageForRetryListener.php create mode 100644 plugins/email/vendor/symfony/messenger/EventListener/SendFailedMessageToFailureTransportListener.php create mode 100644 plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnCustomStopExceptionListener.php create mode 100644 plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnFailureLimitListener.php create mode 100644 plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnMemoryLimitListener.php create mode 100644 plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnMessageLimitListener.php create mode 100644 plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnRestartSignalListener.php create mode 100644 plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnSigtermSignalListener.php create mode 100644 plugins/email/vendor/symfony/messenger/EventListener/StopWorkerOnTimeLimitListener.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/DelayedMessageHandlingException.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/ExceptionInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/HandlerFailedException.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/InvalidArgumentException.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/LogicException.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/MessageDecodingFailedException.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/NoHandlerForMessageException.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/RecoverableExceptionInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/RecoverableMessageHandlingException.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/RejectRedeliveredMessageException.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/RuntimeException.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/StopWorkerException.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/StopWorkerExceptionInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/TransportException.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/UnrecoverableExceptionInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/UnrecoverableMessageHandlingException.php create mode 100644 plugins/email/vendor/symfony/messenger/Exception/ValidationFailedException.php create mode 100644 plugins/email/vendor/symfony/messenger/HandleTrait.php create mode 100644 plugins/email/vendor/symfony/messenger/Handler/Acknowledger.php create mode 100644 plugins/email/vendor/symfony/messenger/Handler/BatchHandlerInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Handler/BatchHandlerTrait.php create mode 100644 plugins/email/vendor/symfony/messenger/Handler/HandlerDescriptor.php create mode 100644 plugins/email/vendor/symfony/messenger/Handler/HandlersLocator.php create mode 100644 plugins/email/vendor/symfony/messenger/Handler/HandlersLocatorInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Handler/MessageHandlerInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Handler/MessageSubscriberInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/LICENSE create mode 100644 plugins/email/vendor/symfony/messenger/MessageBus.php create mode 100644 plugins/email/vendor/symfony/messenger/MessageBusInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/ActivationMiddleware.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/AddBusNameStampMiddleware.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/DispatchAfterCurrentBusMiddleware.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/FailedMessageProcessingMiddleware.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/HandleMessageMiddleware.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/MiddlewareInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/RejectRedeliveredMessageMiddleware.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/RouterContextMiddleware.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/SendMessageMiddleware.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/StackInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/StackMiddleware.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/TraceableMiddleware.php create mode 100644 plugins/email/vendor/symfony/messenger/Middleware/ValidationMiddleware.php create mode 100644 plugins/email/vendor/symfony/messenger/README.md create mode 100644 plugins/email/vendor/symfony/messenger/Retry/MultiplierRetryStrategy.php create mode 100644 plugins/email/vendor/symfony/messenger/Retry/RetryStrategyInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/RoutableMessageBus.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/AckStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/BusNameStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/ConsumedByWorkerStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/DelayStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/DispatchAfterCurrentBusStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/ErrorDetailsStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/FlushBatchHandlersStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/HandledStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/NoAutoAckStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/NonSendableStampInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/ReceivedStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/RedeliveryStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/RouterContextStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/SentStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/SentToFailureTransportStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/SerializerStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/StampInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/TransportMessageIdStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Stamp/ValidationStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Test/Middleware/MiddlewareTestCase.php create mode 100644 plugins/email/vendor/symfony/messenger/TraceableMessageBus.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpFactory.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpReceivedStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpReceiver.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpSender.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpTransport.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/AmqpExt/AmqpTransportFactory.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/AmqpExt/Connection.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Doctrine/Connection.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Doctrine/DoctrineReceivedStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Doctrine/DoctrineReceiver.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Doctrine/DoctrineSender.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Doctrine/DoctrineTransport.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Doctrine/DoctrineTransportFactory.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/InMemoryTransport.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/InMemoryTransportFactory.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Receiver/ListableReceiverInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Receiver/MessageCountAwareInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Receiver/QueueReceiverInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Receiver/ReceiverInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Receiver/SingleMessageReceiver.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/RedisExt/Connection.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/RedisExt/RedisReceivedStamp.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/RedisExt/RedisReceiver.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/RedisExt/RedisSender.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/RedisExt/RedisTransport.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/RedisExt/RedisTransportFactory.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Sender/SenderInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Sender/SendersLocator.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Sender/SendersLocatorInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Serialization/Normalizer/FlattenExceptionNormalizer.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Serialization/PhpSerializer.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Serialization/Serializer.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Serialization/SerializerInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/SetupableTransportInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Sync/SyncTransport.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/Sync/SyncTransportFactory.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/TransportFactory.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/TransportFactoryInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Transport/TransportInterface.php create mode 100644 plugins/email/vendor/symfony/messenger/Worker.php create mode 100644 plugins/email/vendor/symfony/messenger/WorkerMetadata.php create mode 100644 plugins/email/vendor/symfony/messenger/composer.json create mode 100644 plugins/email/vendor/symfony/mime/Address.php create mode 100644 plugins/email/vendor/symfony/mime/BodyRendererInterface.php create mode 100644 plugins/email/vendor/symfony/mime/CHANGELOG.md create mode 100644 plugins/email/vendor/symfony/mime/CharacterStream.php create mode 100644 plugins/email/vendor/symfony/mime/Crypto/DkimOptions.php create mode 100644 plugins/email/vendor/symfony/mime/Crypto/DkimSigner.php create mode 100644 plugins/email/vendor/symfony/mime/Crypto/SMime.php create mode 100644 plugins/email/vendor/symfony/mime/Crypto/SMimeEncrypter.php create mode 100644 plugins/email/vendor/symfony/mime/Crypto/SMimeSigner.php create mode 100644 plugins/email/vendor/symfony/mime/DependencyInjection/AddMimeTypeGuesserPass.php create mode 100644 plugins/email/vendor/symfony/mime/Email.php create mode 100644 plugins/email/vendor/symfony/mime/Encoder/AddressEncoderInterface.php create mode 100644 plugins/email/vendor/symfony/mime/Encoder/Base64ContentEncoder.php create mode 100644 plugins/email/vendor/symfony/mime/Encoder/Base64Encoder.php create mode 100644 plugins/email/vendor/symfony/mime/Encoder/Base64MimeHeaderEncoder.php create mode 100644 plugins/email/vendor/symfony/mime/Encoder/ContentEncoderInterface.php create mode 100644 plugins/email/vendor/symfony/mime/Encoder/EightBitContentEncoder.php create mode 100644 plugins/email/vendor/symfony/mime/Encoder/EncoderInterface.php create mode 100644 plugins/email/vendor/symfony/mime/Encoder/IdnAddressEncoder.php create mode 100644 plugins/email/vendor/symfony/mime/Encoder/MimeHeaderEncoderInterface.php create mode 100644 plugins/email/vendor/symfony/mime/Encoder/QpContentEncoder.php create mode 100644 plugins/email/vendor/symfony/mime/Encoder/QpEncoder.php create mode 100644 plugins/email/vendor/symfony/mime/Encoder/QpMimeHeaderEncoder.php create mode 100644 plugins/email/vendor/symfony/mime/Encoder/Rfc2231Encoder.php create mode 100644 plugins/email/vendor/symfony/mime/Exception/AddressEncoderException.php create mode 100644 plugins/email/vendor/symfony/mime/Exception/ExceptionInterface.php create mode 100644 plugins/email/vendor/symfony/mime/Exception/InvalidArgumentException.php create mode 100644 plugins/email/vendor/symfony/mime/Exception/LogicException.php create mode 100644 plugins/email/vendor/symfony/mime/Exception/RfcComplianceException.php create mode 100644 plugins/email/vendor/symfony/mime/Exception/RuntimeException.php create mode 100644 plugins/email/vendor/symfony/mime/FileBinaryMimeTypeGuesser.php create mode 100644 plugins/email/vendor/symfony/mime/FileinfoMimeTypeGuesser.php create mode 100644 plugins/email/vendor/symfony/mime/Header/AbstractHeader.php create mode 100644 plugins/email/vendor/symfony/mime/Header/DateHeader.php create mode 100644 plugins/email/vendor/symfony/mime/Header/HeaderInterface.php create mode 100644 plugins/email/vendor/symfony/mime/Header/Headers.php create mode 100644 plugins/email/vendor/symfony/mime/Header/IdentificationHeader.php create mode 100644 plugins/email/vendor/symfony/mime/Header/MailboxHeader.php create mode 100644 plugins/email/vendor/symfony/mime/Header/MailboxListHeader.php create mode 100644 plugins/email/vendor/symfony/mime/Header/ParameterizedHeader.php create mode 100644 plugins/email/vendor/symfony/mime/Header/PathHeader.php create mode 100644 plugins/email/vendor/symfony/mime/Header/UnstructuredHeader.php create mode 100644 plugins/email/vendor/symfony/mime/LICENSE create mode 100644 plugins/email/vendor/symfony/mime/Message.php create mode 100644 plugins/email/vendor/symfony/mime/MessageConverter.php create mode 100644 plugins/email/vendor/symfony/mime/MimeTypeGuesserInterface.php create mode 100644 plugins/email/vendor/symfony/mime/MimeTypes.php create mode 100644 plugins/email/vendor/symfony/mime/MimeTypesInterface.php create mode 100644 plugins/email/vendor/symfony/mime/Part/AbstractMultipartPart.php create mode 100644 plugins/email/vendor/symfony/mime/Part/AbstractPart.php create mode 100644 plugins/email/vendor/symfony/mime/Part/DataPart.php create mode 100644 plugins/email/vendor/symfony/mime/Part/MessagePart.php create mode 100644 plugins/email/vendor/symfony/mime/Part/Multipart/AlternativePart.php create mode 100644 plugins/email/vendor/symfony/mime/Part/Multipart/DigestPart.php create mode 100644 plugins/email/vendor/symfony/mime/Part/Multipart/FormDataPart.php create mode 100644 plugins/email/vendor/symfony/mime/Part/Multipart/MixedPart.php create mode 100644 plugins/email/vendor/symfony/mime/Part/Multipart/RelatedPart.php create mode 100644 plugins/email/vendor/symfony/mime/Part/SMimePart.php create mode 100644 plugins/email/vendor/symfony/mime/Part/TextPart.php create mode 100644 plugins/email/vendor/symfony/mime/README.md create mode 100644 plugins/email/vendor/symfony/mime/RawMessage.php create mode 100644 plugins/email/vendor/symfony/mime/Resources/bin/update_mime_types.php create mode 100644 plugins/email/vendor/symfony/mime/Test/Constraint/EmailAddressContains.php create mode 100644 plugins/email/vendor/symfony/mime/Test/Constraint/EmailAttachmentCount.php create mode 100644 plugins/email/vendor/symfony/mime/Test/Constraint/EmailHasHeader.php create mode 100644 plugins/email/vendor/symfony/mime/Test/Constraint/EmailHeaderSame.php create mode 100644 plugins/email/vendor/symfony/mime/Test/Constraint/EmailHtmlBodyContains.php create mode 100644 plugins/email/vendor/symfony/mime/Test/Constraint/EmailTextBodyContains.php create mode 100644 plugins/email/vendor/symfony/mime/composer.json create mode 100644 plugins/email/vendor/symfony/polyfill-intl-idn/Idn.php create mode 100644 plugins/email/vendor/symfony/polyfill-intl-idn/Info.php create mode 100644 plugins/email/vendor/symfony/polyfill-intl-idn/LICENSE create mode 100644 plugins/email/vendor/symfony/polyfill-intl-idn/README.md create mode 100644 plugins/email/vendor/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php create mode 100644 plugins/email/vendor/symfony/polyfill-intl-idn/Resources/unidata/Regex.php create mode 100644 plugins/email/vendor/symfony/polyfill-intl-idn/Resources/unidata/deviation.php create mode 100644 plugins/email/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed.php create mode 100644 plugins/email/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_mapped.php create mode 100644 plugins/email/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_valid.php create mode 100644 plugins/email/vendor/symfony/polyfill-intl-idn/Resources/unidata/ignored.php create mode 100644 plugins/email/vendor/symfony/polyfill-intl-idn/Resources/unidata/mapped.php create mode 100644 plugins/email/vendor/symfony/polyfill-intl-idn/Resources/unidata/virama.php create mode 100644 plugins/email/vendor/symfony/polyfill-intl-idn/bootstrap.php create mode 100644 plugins/email/vendor/symfony/polyfill-intl-idn/bootstrap80.php create mode 100644 plugins/email/vendor/symfony/polyfill-intl-idn/composer.json create mode 100644 plugins/email/vendor/symfony/polyfill-intl-normalizer/LICENSE create mode 100644 plugins/email/vendor/symfony/polyfill-intl-normalizer/Normalizer.php create mode 100644 plugins/email/vendor/symfony/polyfill-intl-normalizer/README.md create mode 100644 plugins/email/vendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php create mode 100644 plugins/email/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalComposition.php create mode 100644 plugins/email/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php create mode 100644 plugins/email/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php create mode 100644 plugins/email/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php create mode 100644 plugins/email/vendor/symfony/polyfill-intl-normalizer/bootstrap.php create mode 100644 plugins/email/vendor/symfony/polyfill-intl-normalizer/bootstrap80.php create mode 100644 plugins/email/vendor/symfony/polyfill-intl-normalizer/composer.json create mode 100644 plugins/email/vendor/symfony/polyfill-php80/LICENSE create mode 100644 plugins/email/vendor/symfony/polyfill-php80/Php80.php create mode 100644 plugins/email/vendor/symfony/polyfill-php80/PhpToken.php create mode 100644 plugins/email/vendor/symfony/polyfill-php80/README.md create mode 100644 plugins/email/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php create mode 100644 plugins/email/vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php create mode 100644 plugins/email/vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php create mode 100644 plugins/email/vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php create mode 100644 plugins/email/vendor/symfony/polyfill-php80/Resources/stubs/ValueError.php create mode 100644 plugins/email/vendor/symfony/polyfill-php80/bootstrap.php create mode 100644 plugins/email/vendor/symfony/polyfill-php80/composer.json create mode 100644 plugins/email/vendor/symfony/redis-messenger/CHANGELOG.md create mode 100644 plugins/email/vendor/symfony/redis-messenger/LICENSE create mode 100644 plugins/email/vendor/symfony/redis-messenger/README.md create mode 100644 plugins/email/vendor/symfony/redis-messenger/Transport/Connection.php create mode 100644 plugins/email/vendor/symfony/redis-messenger/Transport/RedisClusterProxy.php create mode 100644 plugins/email/vendor/symfony/redis-messenger/Transport/RedisProxy.php create mode 100644 plugins/email/vendor/symfony/redis-messenger/Transport/RedisReceivedStamp.php create mode 100644 plugins/email/vendor/symfony/redis-messenger/Transport/RedisReceiver.php create mode 100644 plugins/email/vendor/symfony/redis-messenger/Transport/RedisSender.php create mode 100644 plugins/email/vendor/symfony/redis-messenger/Transport/RedisTransport.php create mode 100644 plugins/email/vendor/symfony/redis-messenger/Transport/RedisTransportFactory.php create mode 100644 plugins/email/vendor/symfony/redis-messenger/composer.json create mode 100644 plugins/email/vendor/symfony/service-contracts/.gitignore create mode 100644 plugins/email/vendor/symfony/service-contracts/Attribute/Required.php create mode 100644 plugins/email/vendor/symfony/service-contracts/Attribute/SubscribedService.php create mode 100644 plugins/email/vendor/symfony/service-contracts/CHANGELOG.md create mode 100644 plugins/email/vendor/symfony/service-contracts/LICENSE create mode 100644 plugins/email/vendor/symfony/service-contracts/README.md create mode 100644 plugins/email/vendor/symfony/service-contracts/ResetInterface.php create mode 100644 plugins/email/vendor/symfony/service-contracts/ServiceLocatorTrait.php create mode 100644 plugins/email/vendor/symfony/service-contracts/ServiceProviderInterface.php create mode 100644 plugins/email/vendor/symfony/service-contracts/ServiceSubscriberInterface.php create mode 100644 plugins/email/vendor/symfony/service-contracts/ServiceSubscriberTrait.php create mode 100644 plugins/email/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php create mode 100644 plugins/email/vendor/symfony/service-contracts/composer.json create mode 100755 plugins/error/.gitignore create mode 100755 plugins/error/CHANGELOG.md create mode 100755 plugins/error/LICENSE create mode 100755 plugins/error/README.md create mode 100755 plugins/error/assets/readme_1.png create mode 100755 plugins/error/blueprints.yaml create mode 100755 plugins/error/cli/LogCommand.php create mode 100755 plugins/error/composer.json create mode 100755 plugins/error/error.php create mode 100755 plugins/error/error.yaml create mode 100755 plugins/error/hebe.json create mode 100755 plugins/error/languages.yaml create mode 100755 plugins/error/templates/error.html.twig create mode 100755 plugins/error/templates/error.json.twig create mode 100755 plugins/error/vendor/autoload.php create mode 100755 plugins/error/vendor/composer/ClassLoader.php create mode 100755 plugins/error/vendor/composer/LICENSE create mode 100755 plugins/error/vendor/composer/autoload_classmap.php create mode 100755 plugins/error/vendor/composer/autoload_namespaces.php create mode 100755 plugins/error/vendor/composer/autoload_psr4.php create mode 100755 plugins/error/vendor/composer/autoload_real.php create mode 100755 plugins/error/vendor/composer/autoload_static.php create mode 100755 plugins/error/vendor/composer/installed.json create mode 100644 plugins/flex-objects/.eslintrc create mode 100644 plugins/flex-objects/.gitignore create mode 100644 plugins/flex-objects/CHANGELOG.md create mode 100644 plugins/flex-objects/LICENSE create mode 100644 plugins/flex-objects/README.md create mode 100644 plugins/flex-objects/admin/templates/flex-objects.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects.json.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/layouts/404.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/add.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/back.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/configuration.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/delete.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/export-csv.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/export.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/languages.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/preview-open.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/preview.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/default/buttons/save.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/default/configure.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/default/edit.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/default/list.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/default/list/list.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/default/list/list_actions.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/default/modals/remove.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/default/preview.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/default/titlebar/configure.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/default/titlebar/edit.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/default/titlebar/list.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/default/titlebar/preview.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/default/titlebar/types.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/default/types.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/user-accounts/configure.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/user-accounts/edit.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/user-accounts/list.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/user-groups/configure.html.twig create mode 100644 plugins/flex-objects/admin/templates/flex-objects/types/user-groups/list.html.twig create mode 100644 plugins/flex-objects/admin/templates/forms/fields/flex-objects/flex-objects.html.twig create mode 100644 plugins/flex-objects/admin/templates/forms/fields/save-redirect/save-redirect.html.twig create mode 100644 plugins/flex-objects/app/columns/finder.js create mode 100644 plugins/flex-objects/app/columns/index.js create mode 100644 plugins/flex-objects/app/filters/index.js create mode 100644 plugins/flex-objects/app/filters/panel.js create mode 100644 plugins/flex-objects/app/list/App.vue create mode 100644 plugins/flex-objects/app/list/VuetableCssConfig.js create mode 100644 plugins/flex-objects/app/list/components/ContentLoader.vue create mode 100644 plugins/flex-objects/app/list/components/FilterBar.vue create mode 100644 plugins/flex-objects/app/list/components/Table.vue create mode 100644 plugins/flex-objects/app/list/index.js create mode 100644 plugins/flex-objects/app/main.js create mode 100644 plugins/flex-objects/app/utils/finder.js create mode 100644 plugins/flex-objects/app/utils/get-filters.js create mode 100644 plugins/flex-objects/app/utils/indeterminate.js create mode 100644 plugins/flex-objects/assets/flex-objects-directory.png create mode 100644 plugins/flex-objects/assets/flex-objects-edit.png create mode 100644 plugins/flex-objects/assets/flex-objects-list.png create mode 100644 plugins/flex-objects/assets/flex-objects-options.png create mode 100644 plugins/flex-objects/assets/flex-objects-site.png create mode 100644 plugins/flex-objects/blueprints.yaml create mode 100644 plugins/flex-objects/blueprints/flex-objects.yaml create mode 100644 plugins/flex-objects/blueprints/flex-objects/contacts.yaml create mode 100644 plugins/flex-objects/blueprints/flex-objects/pages.yaml create mode 100644 plugins/flex-objects/blueprints/flex-objects/user-accounts.yaml create mode 100644 plugins/flex-objects/blueprints/flex-objects/user-groups.yaml create mode 100644 plugins/flex-objects/classes/Admin/AdminController.php create mode 100644 plugins/flex-objects/classes/Controllers/AbstractController.php create mode 100644 plugins/flex-objects/classes/Controllers/MediaController.php create mode 100644 plugins/flex-objects/classes/Controllers/ObjectController.php create mode 100644 plugins/flex-objects/classes/Events/FlexTaskEvent.php create mode 100644 plugins/flex-objects/classes/Flex.php create mode 100644 plugins/flex-objects/classes/FlexFormFactory.php create mode 100644 plugins/flex-objects/classes/FlexRouter.php create mode 100644 plugins/flex-objects/classes/Table/DataTable.php create mode 100644 plugins/flex-objects/cli/FlexConvertDataCommand.php create mode 100644 plugins/flex-objects/composer.json create mode 100644 plugins/flex-objects/composer.lock create mode 100644 plugins/flex-objects/css/admin.css create mode 100644 plugins/flex-objects/css/admin.css.map create mode 100644 plugins/flex-objects/css/admin.min.css create mode 100644 plugins/flex-objects/css/site.css create mode 100644 plugins/flex-objects/css/site.css.map create mode 100644 plugins/flex-objects/css/site.min.css create mode 100644 plugins/flex-objects/flex-objects.php create mode 100644 plugins/flex-objects/flex-objects.yaml create mode 100644 plugins/flex-objects/js/flex-objects.js create mode 100644 plugins/flex-objects/js/list.min.js create mode 100644 plugins/flex-objects/languages/de.yaml create mode 100644 plugins/flex-objects/languages/en.yaml create mode 100644 plugins/flex-objects/languages/es.yaml create mode 100644 plugins/flex-objects/languages/ja.yaml create mode 100644 plugins/flex-objects/languages/nl.yaml create mode 100644 plugins/flex-objects/languages/ru.yaml create mode 100644 plugins/flex-objects/package.json create mode 100644 plugins/flex-objects/permissions.yaml create mode 100644 plugins/flex-objects/scss/_preset.scss create mode 100644 plugins/flex-objects/scss/admin.scss create mode 100644 plugins/flex-objects/scss/plugin/_admin.scss create mode 100644 plugins/flex-objects/scss/plugin/_site.scss create mode 100644 plugins/flex-objects/scss/site.scss create mode 100644 plugins/flex-objects/templates/flex-edit.html.twig create mode 100644 plugins/flex-objects/templates/flex-objects.html.twig create mode 100644 plugins/flex-objects/templates/flex-objects/directories/default.html.twig create mode 100644 plugins/flex-objects/templates/flex-objects/page.html.twig create mode 100644 plugins/flex-objects/templates/flex-objects/views/404.html.twig create mode 100644 plugins/flex-objects/templates/flex-objects/views/directories.html.twig create mode 100644 plugins/flex-objects/templates/flex-objects/views/directory.html.twig create mode 100644 plugins/flex-objects/templates/flex-objects/views/object.html.twig create mode 100644 plugins/flex-objects/templates/flex/contacts/collection/default.html.twig create mode 100644 plugins/flex-objects/templates/flex/contacts/object/default.html.twig create mode 100644 plugins/flex-objects/templates/flex/contacts/object/list-default.html.twig create mode 100644 plugins/flex-objects/templates/flex/user-accounts/collection/default.html.twig create mode 100644 plugins/flex-objects/templates/flex/user-accounts/object/default.html.twig create mode 100644 plugins/flex-objects/templates/flex/user-accounts/object/list-default.html.twig create mode 100644 plugins/flex-objects/templates/flex/user-groups/collection/default.html.twig create mode 100644 plugins/flex-objects/templates/flex/user-groups/object/default.html.twig create mode 100644 plugins/flex-objects/templates/flex/user-groups/object/list-default.html.twig create mode 100644 plugins/flex-objects/templates/forms/fields/filepicker/filepicker.html.twig create mode 100644 plugins/flex-objects/templates/forms/fields/list/list.html.twig create mode 100644 plugins/flex-objects/templates/forms/fields/pagemedia/pagemedia.html.twig create mode 100644 plugins/flex-objects/templates/forms/fields/pagemedia/template.html.twig create mode 100644 plugins/flex-objects/vendor/autoload.php create mode 100644 plugins/flex-objects/vendor/composer/ClassLoader.php create mode 100644 plugins/flex-objects/vendor/composer/InstalledVersions.php create mode 100644 plugins/flex-objects/vendor/composer/LICENSE create mode 100644 plugins/flex-objects/vendor/composer/autoload_classmap.php create mode 100644 plugins/flex-objects/vendor/composer/autoload_namespaces.php create mode 100644 plugins/flex-objects/vendor/composer/autoload_psr4.php create mode 100644 plugins/flex-objects/vendor/composer/autoload_real.php create mode 100644 plugins/flex-objects/vendor/composer/autoload_static.php create mode 100644 plugins/flex-objects/vendor/composer/installed.json create mode 100644 plugins/flex-objects/vendor/composer/installed.php create mode 100644 plugins/flex-objects/vendor/composer/platform_check.php create mode 100644 plugins/flex-objects/watch.sh create mode 100644 plugins/flex-objects/webpack.conf.js create mode 100644 plugins/flex-objects/yarn.lock create mode 100644 plugins/form/.eslintrc create mode 100644 plugins/form/.gitignore create mode 100644 plugins/form/CHANGELOG.md create mode 100644 plugins/form/LICENSE create mode 100644 plugins/form/README.md create mode 100644 plugins/form/app/fields/array.js create mode 100644 plugins/form/app/fields/file.js create mode 100644 plugins/form/app/fields/form.js create mode 100644 plugins/form/app/fields/index.js create mode 100644 plugins/form/app/fields/media.js create mode 100644 plugins/form/app/fields/tabs.js create mode 100644 plugins/form/app/main.js create mode 100644 plugins/form/app/utils/keep-alive.js create mode 100644 plugins/form/assets/dropzone.min.css create mode 100644 plugins/form/assets/form-styles.css create mode 100644 plugins/form/assets/form-styles.css.map create mode 100644 plugins/form/assets/form-styles.min.css create mode 100644 plugins/form/assets/form.min.js create mode 100644 plugins/form/assets/form.vendor.js create mode 100644 plugins/form/assets/object.assign.polyfill.js create mode 100644 plugins/form/assets/signature_pad.js create mode 100644 plugins/form/blueprints.yaml create mode 100644 plugins/form/classes/BasicCaptcha.php create mode 100644 plugins/form/classes/Form.php create mode 100644 plugins/form/classes/FormFactory.php create mode 100644 plugins/form/classes/Forms.php create mode 100644 plugins/form/classes/TwigExtension.php create mode 100644 plugins/form/composer.json create mode 100644 plugins/form/composer.lock create mode 100644 plugins/form/fonts/zxx-camo.ttf create mode 100644 plugins/form/fonts/zxx-noise.ttf create mode 100644 plugins/form/fonts/zxx-sans.ttf create mode 100644 plugins/form/fonts/zxx-xed.ttf create mode 100644 plugins/form/form.php create mode 100644 plugins/form/form.yaml create mode 100644 plugins/form/gulpfile.js create mode 100644 plugins/form/hebe.json create mode 100644 plugins/form/languages.yaml create mode 100644 plugins/form/package.json create mode 100644 plugins/form/scss.sh create mode 100644 plugins/form/scss/form-styles.scss create mode 100644 plugins/form/templates/form-messages.html.twig create mode 100644 plugins/form/templates/form-messages.json.twig create mode 100644 plugins/form/templates/form.html.twig create mode 100644 plugins/form/templates/form.json.twig create mode 100644 plugins/form/templates/formdata.html.twig create mode 100644 plugins/form/templates/forms/ajax.json.twig create mode 100644 plugins/form/templates/forms/data.html.twig create mode 100644 plugins/form/templates/forms/data.txt.twig create mode 100644 plugins/form/templates/forms/default/data.html.twig create mode 100644 plugins/form/templates/forms/default/data.txt.twig create mode 100644 plugins/form/templates/forms/default/field.html.twig create mode 100644 plugins/form/templates/forms/default/fields.html.twig create mode 100644 plugins/form/templates/forms/default/form.html.twig create mode 100644 plugins/form/templates/forms/default/toggleable.html.twig create mode 100644 plugins/form/templates/forms/dropzone/template.html.twig create mode 100644 plugins/form/templates/forms/field.html.twig create mode 100644 plugins/form/templates/forms/fields/array/array.html.twig create mode 100644 plugins/form/templates/forms/fields/avatar/avatar.html.twig create mode 100644 plugins/form/templates/forms/fields/basic-captcha/basic-captcha.html.twig create mode 100644 plugins/form/templates/forms/fields/captcha/captcha.html.twig create mode 100644 plugins/form/templates/forms/fields/checkbox/checkbox.html.twig create mode 100644 plugins/form/templates/forms/fields/checkboxes/checkboxes.html.twig create mode 100644 plugins/form/templates/forms/fields/color/color.html.twig create mode 100644 plugins/form/templates/forms/fields/column/column.html.twig create mode 100644 plugins/form/templates/forms/fields/columns/columns.html.twig create mode 100644 plugins/form/templates/forms/fields/conditional/conditional.html.twig create mode 100644 plugins/form/templates/forms/fields/date/date.html.twig create mode 100644 plugins/form/templates/forms/fields/date/edit_list.html.twig create mode 100644 plugins/form/templates/forms/fields/datetime/datetime.html.twig create mode 100644 plugins/form/templates/forms/fields/datetime/edit_list.html.twig create mode 100644 plugins/form/templates/forms/fields/display/display.html.twig create mode 100644 plugins/form/templates/forms/fields/email/email.html.twig create mode 100644 plugins/form/templates/forms/fields/fieldset/fieldset.html.twig create mode 100644 plugins/form/templates/forms/fields/file/file.html.twig create mode 100644 plugins/form/templates/forms/fields/formname/formname.html.twig create mode 100644 plugins/form/templates/forms/fields/formtask/formtask.html.twig create mode 100644 plugins/form/templates/forms/fields/hidden/hidden.html.twig create mode 100644 plugins/form/templates/forms/fields/honeypot/honeypot.html.twig create mode 100644 plugins/form/templates/forms/fields/ignore/ignore.html.twig create mode 100644 plugins/form/templates/forms/fields/key/key.html.twig create mode 100644 plugins/form/templates/forms/fields/month/month.html.twig create mode 100644 plugins/form/templates/forms/fields/nonce/nonce.html.twig create mode 100644 plugins/form/templates/forms/fields/number/number.html.twig create mode 100644 plugins/form/templates/forms/fields/password/password.html.twig create mode 100644 plugins/form/templates/forms/fields/radio/radio.html.twig create mode 100644 plugins/form/templates/forms/fields/range/range.html.twig create mode 100644 plugins/form/templates/forms/fields/section/section.html.twig create mode 100644 plugins/form/templates/forms/fields/select/select.html.twig create mode 100644 plugins/form/templates/forms/fields/select_optgroup/select_optgroup.html.twig create mode 100644 plugins/form/templates/forms/fields/signature/signature.html.twig create mode 100644 plugins/form/templates/forms/fields/spacer/spacer.html.twig create mode 100644 plugins/form/templates/forms/fields/switch/switch.html.twig create mode 100644 plugins/form/templates/forms/fields/tab/tab.html.twig create mode 100644 plugins/form/templates/forms/fields/tabs/tabs.html.twig create mode 100644 plugins/form/templates/forms/fields/tel/tel.html.twig create mode 100644 plugins/form/templates/forms/fields/text/edit_list.html.twig create mode 100644 plugins/form/templates/forms/fields/text/text.html.twig create mode 100644 plugins/form/templates/forms/fields/textarea/textarea.html.twig create mode 100644 plugins/form/templates/forms/fields/time/edit_list.html.twig create mode 100644 plugins/form/templates/forms/fields/time/time.html.twig create mode 100644 plugins/form/templates/forms/fields/toggle/edit_list.html.twig create mode 100644 plugins/form/templates/forms/fields/toggle/toggle.html.twig create mode 100644 plugins/form/templates/forms/fields/turnstile/turnstile.html.twig create mode 100644 plugins/form/templates/forms/fields/uniqueid/uniqueid.html.twig create mode 100644 plugins/form/templates/forms/fields/url/edit_list.html.twig create mode 100644 plugins/form/templates/forms/fields/url/url.html.twig create mode 100644 plugins/form/templates/forms/fields/value/value.html.twig create mode 100644 plugins/form/templates/forms/fields/week/week.html.twig create mode 100644 plugins/form/templates/forms/form.html.twig create mode 100644 plugins/form/templates/forms/layouts/button.html.twig create mode 100644 plugins/form/templates/forms/layouts/button/default-button.html.twig create mode 100644 plugins/form/templates/forms/layouts/field-variables.html.twig create mode 100644 plugins/form/templates/forms/layouts/field.html.twig create mode 100644 plugins/form/templates/forms/layouts/field/default-field.html.twig create mode 100644 plugins/form/templates/forms/layouts/form.html.twig create mode 100644 plugins/form/templates/forms/layouts/form/default-form.html.twig create mode 100644 plugins/form/templates/modular/form.html.twig create mode 100644 plugins/form/templates/partials/form-messages.html.twig create mode 100644 plugins/form/templates/partials/form-messages.json.twig create mode 100644 plugins/form/vendor/autoload.php create mode 100644 plugins/form/vendor/composer/ClassLoader.php create mode 100644 plugins/form/vendor/composer/InstalledVersions.php create mode 100644 plugins/form/vendor/composer/LICENSE create mode 100644 plugins/form/vendor/composer/autoload_classmap.php create mode 100644 plugins/form/vendor/composer/autoload_namespaces.php create mode 100644 plugins/form/vendor/composer/autoload_psr4.php create mode 100644 plugins/form/vendor/composer/autoload_real.php create mode 100644 plugins/form/vendor/composer/autoload_static.php create mode 100644 plugins/form/vendor/composer/installed.json create mode 100644 plugins/form/vendor/composer/installed.php create mode 100644 plugins/form/vendor/composer/platform_check.php create mode 100644 plugins/form/vendor/google/recaptcha/.github/ISSUE_TEMPLATE/bug_report.md create mode 100644 plugins/form/vendor/google/recaptcha/.gitignore create mode 100644 plugins/form/vendor/google/recaptcha/.travis.yml create mode 100644 plugins/form/vendor/google/recaptcha/ARCHITECTURE.md create mode 100644 plugins/form/vendor/google/recaptcha/CONTRIBUTING.md create mode 100644 plugins/form/vendor/google/recaptcha/LICENSE create mode 100644 plugins/form/vendor/google/recaptcha/README.md create mode 100644 plugins/form/vendor/google/recaptcha/app.yaml create mode 100644 plugins/form/vendor/google/recaptcha/composer.json create mode 100644 plugins/form/vendor/google/recaptcha/examples/appengine-https.php create mode 100644 plugins/form/vendor/google/recaptcha/examples/config.php.dist create mode 100644 plugins/form/vendor/google/recaptcha/examples/examples.css create mode 100644 plugins/form/vendor/google/recaptcha/examples/google0afd8760fd68f119.html create mode 100644 plugins/form/vendor/google/recaptcha/examples/index.php create mode 100644 plugins/form/vendor/google/recaptcha/examples/recaptcha-content-security-policy.php create mode 100644 plugins/form/vendor/google/recaptcha/examples/recaptcha-v2-checkbox-explicit.php create mode 100644 plugins/form/vendor/google/recaptcha/examples/recaptcha-v2-checkbox.php create mode 100644 plugins/form/vendor/google/recaptcha/examples/recaptcha-v2-invisible.php create mode 100644 plugins/form/vendor/google/recaptcha/examples/recaptcha-v3-request-scores.php create mode 100644 plugins/form/vendor/google/recaptcha/examples/recaptcha-v3-verify.php create mode 100644 plugins/form/vendor/google/recaptcha/examples/robots.txt create mode 100644 plugins/form/vendor/google/recaptcha/phpunit.xml.dist create mode 100644 plugins/form/vendor/google/recaptcha/src/ReCaptcha/ReCaptcha.php create mode 100644 plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestMethod.php create mode 100644 plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestMethod/Curl.php create mode 100644 plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestMethod/CurlPost.php create mode 100644 plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestMethod/Post.php create mode 100644 plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestMethod/Socket.php create mode 100644 plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestMethod/SocketPost.php create mode 100644 plugins/form/vendor/google/recaptcha/src/ReCaptcha/RequestParameters.php create mode 100644 plugins/form/vendor/google/recaptcha/src/ReCaptcha/Response.php create mode 100644 plugins/form/vendor/google/recaptcha/src/autoload.php create mode 100644 plugins/form/vendor/google/recaptcha/tests/ReCaptcha/ReCaptchaTest.php create mode 100644 plugins/form/vendor/google/recaptcha/tests/ReCaptcha/RequestMethod/CurlPostTest.php create mode 100644 plugins/form/vendor/google/recaptcha/tests/ReCaptcha/RequestMethod/PostTest.php create mode 100644 plugins/form/vendor/google/recaptcha/tests/ReCaptcha/RequestMethod/SocketPostTest.php create mode 100644 plugins/form/vendor/google/recaptcha/tests/ReCaptcha/RequestParametersTest.php create mode 100644 plugins/form/vendor/google/recaptcha/tests/ReCaptcha/ResponseTest.php create mode 100644 plugins/form/webpack.conf.js create mode 100644 plugins/form/yarn.lock create mode 100644 plugins/langswitcher/CHANGELOG.md create mode 100644 plugins/langswitcher/LICENSE create mode 100644 plugins/langswitcher/README.md create mode 100644 plugins/langswitcher/assets/readme_1.png create mode 100644 plugins/langswitcher/blueprints.yaml create mode 100644 plugins/langswitcher/composer.json create mode 100644 plugins/langswitcher/composer.lock create mode 100644 plugins/langswitcher/css/langswitcher.css create mode 100644 plugins/langswitcher/langswitcher.php create mode 100644 plugins/langswitcher/langswitcher.yaml create mode 100644 plugins/langswitcher/languages.yaml create mode 100644 plugins/langswitcher/templates/partials/langswitcher-logic.html.twig create mode 100644 plugins/langswitcher/templates/partials/langswitcher-long.html.twig create mode 100644 plugins/langswitcher/templates/partials/langswitcher-short.html.twig create mode 100644 plugins/langswitcher/templates/partials/langswitcher.hreflang.html.twig create mode 100644 plugins/langswitcher/templates/partials/langswitcher.html.twig create mode 100644 plugins/langswitcher/vendor/autoload.php create mode 100644 plugins/langswitcher/vendor/composer/ClassLoader.php create mode 100644 plugins/langswitcher/vendor/composer/LICENSE create mode 100644 plugins/langswitcher/vendor/composer/autoload_classmap.php create mode 100644 plugins/langswitcher/vendor/composer/autoload_namespaces.php create mode 100644 plugins/langswitcher/vendor/composer/autoload_psr4.php create mode 100644 plugins/langswitcher/vendor/composer/autoload_real.php create mode 100644 plugins/langswitcher/vendor/composer/autoload_static.php create mode 100644 plugins/langswitcher/vendor/composer/installed.json create mode 100644 plugins/login/.gitignore create mode 100644 plugins/login/CHANGELOG.md create mode 100644 plugins/login/LICENSE create mode 100644 plugins/login/README.md create mode 100644 plugins/login/blueprints.yaml create mode 100644 plugins/login/classes/Controller.php create mode 100644 plugins/login/classes/Email.php create mode 100644 plugins/login/classes/Events/PageAuthorizeEvent.php create mode 100644 plugins/login/classes/Events/UserLoginEvent.php create mode 100644 plugins/login/classes/Invitations/Invitation.php create mode 100644 plugins/login/classes/Invitations/Invitations.php create mode 100644 plugins/login/classes/Login.php create mode 100644 plugins/login/classes/LoginCache.php create mode 100644 plugins/login/classes/RateLimiter.php create mode 100644 plugins/login/classes/RememberMe/RememberMe.php create mode 100644 plugins/login/classes/RememberMe/TokenStorage.php create mode 100644 plugins/login/classes/TwoFactorAuth/BaconQrProvider.php create mode 100644 plugins/login/classes/TwoFactorAuth/TwoFactorAuth.php create mode 100644 plugins/login/cli/ChangePasswordCommand.php create mode 100644 plugins/login/cli/ChangeUserStateCommand.php create mode 100644 plugins/login/cli/LookupUserCommand.php create mode 100644 plugins/login/cli/NewUserCommand.php create mode 100644 plugins/login/composer.json create mode 100644 plugins/login/composer.lock create mode 100644 plugins/login/css/login.css create mode 100644 plugins/login/hebe.json create mode 100644 plugins/login/js/2fa.js create mode 100644 plugins/login/languages/de.yaml create mode 100644 plugins/login/languages/en.yaml create mode 100644 plugins/login/languages/es.yaml create mode 100644 plugins/login/languages/fr.yaml create mode 100644 plugins/login/languages/hr.yaml create mode 100644 plugins/login/languages/hu.yaml create mode 100644 plugins/login/languages/lt.yaml create mode 100644 plugins/login/languages/no.yaml create mode 100644 plugins/login/languages/pt-BR.yaml create mode 100644 plugins/login/languages/ro.yaml create mode 100644 plugins/login/languages/ru.yaml create mode 100644 plugins/login/languages/uk.yaml create mode 100644 plugins/login/languages/zh.yaml create mode 100644 plugins/login/login.php create mode 100644 plugins/login/login.yaml create mode 100644 plugins/login/templates/emails/login/activate.html.twig create mode 100644 plugins/login/templates/emails/login/invite.html.twig create mode 100644 plugins/login/templates/emails/login/magic-login.html.twig create mode 100644 plugins/login/templates/emails/login/notification.html.twig create mode 100644 plugins/login/templates/emails/login/reset-password.html.twig create mode 100644 plugins/login/templates/emails/login/welcome.html.twig create mode 100644 plugins/login/templates/forgot.html.twig create mode 100644 plugins/login/templates/forms/fields/2fa_secret/2fa_secret.html.twig create mode 100644 plugins/login/templates/login.html.twig create mode 100644 plugins/login/templates/login.json.twig create mode 100644 plugins/login/templates/partials/forgot-form.html.twig create mode 100644 plugins/login/templates/partials/login-form.html.twig create mode 100644 plugins/login/templates/partials/login-status.html.twig create mode 100644 plugins/login/templates/partials/login-twofa.html.twig create mode 100644 plugins/login/templates/partials/reset-form.html.twig create mode 100644 plugins/login/templates/profile.html.twig create mode 100644 plugins/login/templates/profile.json.twig create mode 100644 plugins/login/templates/register.html.twig create mode 100644 plugins/login/templates/reset.html.twig create mode 100644 plugins/login/templates/unauthorized.html.twig create mode 100644 plugins/login/vendor/autoload.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/LICENSE create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/README.md create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/composer.json create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/phpunit.xml.dist create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Common/BitArray.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Common/BitMatrix.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Common/BitUtils.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Common/CharacterSetEci.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Common/EcBlock.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Common/EcBlocks.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Common/ErrorCorrectionLevel.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Common/FormatInformation.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Common/Mode.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Common/ReedSolomonCodec.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Common/Version.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/BlockPair.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/ByteMatrix.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/Encoder.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/MaskUtil.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/MatrixUtil.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Encoder/QrCode.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Exception/ExceptionInterface.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Exception/InvalidArgumentException.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Exception/OutOfBoundsException.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Exception/RuntimeException.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Exception/UnexpectedValueException.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Exception/WriterException.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Color/Alpha.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Color/Cmyk.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Color/ColorInterface.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Color/Gray.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Color/Rgb.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Eye/CompositeEye.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Eye/EyeInterface.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Eye/ModuleEye.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Eye/SimpleCircleEye.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Eye/SquareEye.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Image/EpsImageBackEnd.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Image/ImageBackEndInterface.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Image/ImagickImageBackEnd.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Image/SvgImageBackEnd.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Image/TransformationMatrix.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/ImageRenderer.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/DotsModule.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/Edge.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/EdgeIterator/EdgeIterator.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/ModuleInterface.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/RoundnessModule.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Module/SquareModule.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/Close.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/Curve.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/EllipticArc.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/Line.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/Move.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/OperationInterface.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/Path/Path.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/PlainTextRenderer.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/RendererInterface.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/EyeFill.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Fill.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/Gradient.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/GradientType.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Renderer/RendererStyle/RendererStyle.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/src/Writer.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Common/BitArrayTest.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Common/BitMatrixTest.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Common/BitUtilsTest.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Common/ErrorCorrectionLevelTest.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Common/FormatInformationTest.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Common/ModeTest.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Common/ReedSolomonCodecTest.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Common/VersionTest.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Encoder/EncoderTest.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Encoder/MaskUtilTest.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Encoder/MatrixUtilTest.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Integration/ImagickRenderingTest.php create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Integration/__snapshots__/files/ImagickRenderingTest__testGenericQrCode__1.png create mode 100644 plugins/login/vendor/bacon/bacon-qr-code/test/Integration/__snapshots__/files/ImagickRenderingTest__testIssue79__1.png create mode 100644 plugins/login/vendor/birke/rememberme/.gitignore create mode 100644 plugins/login/vendor/birke/rememberme/LICENSE create mode 100644 plugins/login/vendor/birke/rememberme/README.md create mode 100644 plugins/login/vendor/birke/rememberme/composer.json create mode 100644 plugins/login/vendor/birke/rememberme/example/action.php create mode 100644 plugins/login/vendor/birke/rememberme/example/css/style.css create mode 100644 plugins/login/vendor/birke/rememberme/example/index.php create mode 100644 plugins/login/vendor/birke/rememberme/example/templates/cookie_was_stolen.php create mode 100644 plugins/login/vendor/birke/rememberme/example/templates/login.php create mode 100644 plugins/login/vendor/birke/rememberme/example/templates/user_is_logged_in.php create mode 100644 plugins/login/vendor/birke/rememberme/phpunit.xml create mode 100644 plugins/login/vendor/birke/rememberme/src/Rememberme/Authenticator.php create mode 100644 plugins/login/vendor/birke/rememberme/src/Rememberme/Cookie.php create mode 100644 plugins/login/vendor/birke/rememberme/src/Rememberme/Storage/DB.php create mode 100644 plugins/login/vendor/birke/rememberme/src/Rememberme/Storage/File.php create mode 100644 plugins/login/vendor/birke/rememberme/src/Rememberme/Storage/PDO.php create mode 100644 plugins/login/vendor/birke/rememberme/src/Rememberme/Storage/StorageInterface.php create mode 100644 plugins/login/vendor/birke/rememberme/test/CookieTest.php create mode 100644 plugins/login/vendor/birke/rememberme/test/RemembermeTest.php create mode 100644 plugins/login/vendor/birke/rememberme/test/Storage/PDO.php create mode 100644 plugins/login/vendor/birke/rememberme/test/Storage/tokens.xml create mode 100644 plugins/login/vendor/birke/rememberme/test/bootstrap.php create mode 100644 plugins/login/vendor/composer/ClassLoader.php create mode 100644 plugins/login/vendor/composer/InstalledVersions.php create mode 100644 plugins/login/vendor/composer/LICENSE create mode 100644 plugins/login/vendor/composer/autoload_classmap.php create mode 100644 plugins/login/vendor/composer/autoload_files.php create mode 100644 plugins/login/vendor/composer/autoload_namespaces.php create mode 100644 plugins/login/vendor/composer/autoload_psr4.php create mode 100644 plugins/login/vendor/composer/autoload_real.php create mode 100644 plugins/login/vendor/composer/autoload_static.php create mode 100644 plugins/login/vendor/composer/installed.json create mode 100644 plugins/login/vendor/composer/installed.php create mode 100644 plugins/login/vendor/composer/platform_check.php create mode 100644 plugins/login/vendor/dasprid/enum/.github/workflows/tests.yml create mode 100644 plugins/login/vendor/dasprid/enum/LICENSE create mode 100644 plugins/login/vendor/dasprid/enum/README.md create mode 100644 plugins/login/vendor/dasprid/enum/composer.json create mode 100644 plugins/login/vendor/dasprid/enum/phpunit.xml.dist create mode 100644 plugins/login/vendor/dasprid/enum/src/AbstractEnum.php create mode 100644 plugins/login/vendor/dasprid/enum/src/EnumMap.php create mode 100644 plugins/login/vendor/dasprid/enum/src/Exception/CloneNotSupportedException.php create mode 100644 plugins/login/vendor/dasprid/enum/src/Exception/ExceptionInterface.php create mode 100644 plugins/login/vendor/dasprid/enum/src/Exception/ExpectationException.php create mode 100644 plugins/login/vendor/dasprid/enum/src/Exception/IllegalArgumentException.php create mode 100644 plugins/login/vendor/dasprid/enum/src/Exception/MismatchException.php create mode 100644 plugins/login/vendor/dasprid/enum/src/Exception/SerializeNotSupportedException.php create mode 100644 plugins/login/vendor/dasprid/enum/src/Exception/UnserializeNotSupportedException.php create mode 100644 plugins/login/vendor/dasprid/enum/src/NullValue.php create mode 100644 plugins/login/vendor/dasprid/enum/test/AbstractEnumTest.php create mode 100644 plugins/login/vendor/dasprid/enum/test/EnumMapTest.php create mode 100644 plugins/login/vendor/dasprid/enum/test/NullValueTest.php create mode 100644 plugins/login/vendor/dasprid/enum/test/Planet.php create mode 100644 plugins/login/vendor/dasprid/enum/test/WeekDay.php create mode 100644 plugins/login/vendor/paragonie/random_compat/CHANGELOG.md create mode 100644 plugins/login/vendor/paragonie/random_compat/LICENSE create mode 100644 plugins/login/vendor/paragonie/random_compat/RATIONALE.md create mode 100644 plugins/login/vendor/paragonie/random_compat/README.md create mode 100644 plugins/login/vendor/paragonie/random_compat/SECURITY.md create mode 100644 plugins/login/vendor/paragonie/random_compat/build-phar.sh create mode 100644 plugins/login/vendor/paragonie/random_compat/composer.json create mode 100644 plugins/login/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey create mode 100644 plugins/login/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc create mode 100644 plugins/login/vendor/paragonie/random_compat/lib/byte_safe_strings.php create mode 100644 plugins/login/vendor/paragonie/random_compat/lib/cast_to_int.php create mode 100644 plugins/login/vendor/paragonie/random_compat/lib/error_polyfill.php create mode 100644 plugins/login/vendor/paragonie/random_compat/lib/random.php create mode 100644 plugins/login/vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php create mode 100644 plugins/login/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php create mode 100644 plugins/login/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php create mode 100644 plugins/login/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php create mode 100644 plugins/login/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php create mode 100644 plugins/login/vendor/paragonie/random_compat/lib/random_bytes_openssl.php create mode 100644 plugins/login/vendor/paragonie/random_compat/lib/random_int.php create mode 100644 plugins/login/vendor/paragonie/random_compat/other/build_phar.php create mode 100644 plugins/login/vendor/paragonie/random_compat/other/ide_stubs/COM.php create mode 100644 plugins/login/vendor/paragonie/random_compat/other/ide_stubs/README.md create mode 100644 plugins/login/vendor/paragonie/random_compat/other/ide_stubs/com_exception.php create mode 100644 plugins/login/vendor/paragonie/random_compat/other/ide_stubs/libsodium.php create mode 100644 plugins/login/vendor/paragonie/random_compat/psalm-autoload.php create mode 100644 plugins/login/vendor/paragonie/random_compat/psalm.xml create mode 100644 plugins/login/vendor/robthree/twofactorauth/.github/FUNDING.yml create mode 100644 plugins/login/vendor/robthree/twofactorauth/.github/workflows/test-bacon.yml create mode 100644 plugins/login/vendor/robthree/twofactorauth/.github/workflows/test-endroid.yml create mode 100644 plugins/login/vendor/robthree/twofactorauth/.github/workflows/test.yml create mode 100644 plugins/login/vendor/robthree/twofactorauth/.gitignore create mode 100644 plugins/login/vendor/robthree/twofactorauth/LICENSE create mode 100644 plugins/login/vendor/robthree/twofactorauth/README.md create mode 100644 plugins/login/vendor/robthree/twofactorauth/TwoFactorAuth.phpproj create mode 100644 plugins/login/vendor/robthree/twofactorauth/TwoFactorAuth.sln create mode 100644 plugins/login/vendor/robthree/twofactorauth/composer.json create mode 100644 plugins/login/vendor/robthree/twofactorauth/demo/demo.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/docs/_config.yml create mode 100644 plugins/login/vendor/robthree/twofactorauth/docs/_layouts/post.html create mode 100644 plugins/login/vendor/robthree/twofactorauth/docs/assets/css/style.scss create mode 100644 plugins/login/vendor/robthree/twofactorauth/docs/getting-started.md create mode 100644 plugins/login/vendor/robthree/twofactorauth/docs/improved-code-verification.md create mode 100644 plugins/login/vendor/robthree/twofactorauth/docs/index.md create mode 100644 plugins/login/vendor/robthree/twofactorauth/docs/optional-configuration.md create mode 100644 plugins/login/vendor/robthree/twofactorauth/docs/qr-codes.md create mode 100644 plugins/login/vendor/robthree/twofactorauth/docs/qr-codes/bacon.md create mode 100644 plugins/login/vendor/robthree/twofactorauth/docs/qr-codes/endroid.md create mode 100644 plugins/login/vendor/robthree/twofactorauth/docs/qr-codes/image-charts.md create mode 100644 plugins/login/vendor/robthree/twofactorauth/docs/qr-codes/qr-server.md create mode 100644 plugins/login/vendor/robthree/twofactorauth/docs/qr-codes/qrickit.md create mode 100644 plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/BaconQrCodeProvider.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/BaseHTTPQRCodeProvider.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/EndroidQrCodeProvider.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/EndroidQrCodeWithLogoProvider.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/GoogleChartsQrCodeProvider.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/HandlesDataUri.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/IQRCodeProvider.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/ImageChartsQRCodeProvider.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/QRException.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/QRServerProvider.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/lib/Providers/Qr/QRicketProvider.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/lib/Providers/Rng/CSRNGProvider.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/lib/Providers/Rng/HashRNGProvider.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/lib/Providers/Rng/IRNGProvider.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/lib/Providers/Rng/MCryptRNGProvider.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/lib/Providers/Rng/OpenSSLRNGProvider.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/lib/Providers/Rng/RNGException.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/lib/Providers/Time/HttpTimeProvider.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/lib/Providers/Time/ITimeProvider.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/lib/Providers/Time/LocalMachineTimeProvider.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/lib/Providers/Time/NTPTimeProvider.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/lib/Providers/Time/TimeException.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/lib/TwoFactorAuth.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/lib/TwoFactorAuthException.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/logo.png create mode 100644 plugins/login/vendor/robthree/twofactorauth/multifactorauthforeveryone.png create mode 100644 plugins/login/vendor/robthree/twofactorauth/phpunit.xml create mode 100644 plugins/login/vendor/robthree/twofactorauth/tests/MightNotMakeAssertions.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/tests/Providers/Qr/IQRCodeProviderTest.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/tests/Providers/Qr/TestQrProvider.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/tests/Providers/Rng/CSRNGProviderTest.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/tests/Providers/Rng/HashRNGProviderTest.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/tests/Providers/Rng/IRNGProviderTest.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/tests/Providers/Rng/MCryptRNGProviderTest.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/tests/Providers/Rng/NeedsRngLengths.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/tests/Providers/Rng/OpenSSLRNGProviderTest.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/tests/Providers/Rng/TestRNGProvider.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/tests/Providers/Time/ITimeProviderTest.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/tests/Providers/Time/TestTimeProvider.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/tests/TwoFactorAuthTest.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/testsDependency/BaconQRCodeTest.php create mode 100644 plugins/login/vendor/robthree/twofactorauth/testsDependency/EndroidQRCodeTest.php create mode 100755 plugins/markdown-notices/CHANGELOG.md create mode 100755 plugins/markdown-notices/LICENSE create mode 100755 plugins/markdown-notices/README.md create mode 100755 plugins/markdown-notices/assets/notices.css create mode 100755 plugins/markdown-notices/assets/screenshot.png create mode 100755 plugins/markdown-notices/blueprints.yaml create mode 100755 plugins/markdown-notices/composer.json create mode 100755 plugins/markdown-notices/composer.lock create mode 100755 plugins/markdown-notices/languages.yaml create mode 100755 plugins/markdown-notices/markdown-notices.php create mode 100755 plugins/markdown-notices/markdown-notices.yaml create mode 100755 plugins/markdown-notices/vendor/autoload.php create mode 100755 plugins/markdown-notices/vendor/composer/ClassLoader.php create mode 100755 plugins/markdown-notices/vendor/composer/LICENSE create mode 100755 plugins/markdown-notices/vendor/composer/autoload_classmap.php create mode 100755 plugins/markdown-notices/vendor/composer/autoload_namespaces.php create mode 100755 plugins/markdown-notices/vendor/composer/autoload_psr4.php create mode 100755 plugins/markdown-notices/vendor/composer/autoload_real.php create mode 100755 plugins/markdown-notices/vendor/composer/autoload_static.php create mode 100755 plugins/markdown-notices/vendor/composer/installed.json create mode 100644 plugins/pagination/CHANGELOG.md create mode 100644 plugins/pagination/LICENSE create mode 100644 plugins/pagination/README.md create mode 100644 plugins/pagination/blueprints.yaml create mode 100644 plugins/pagination/classes/plugin/PaginationHelper.php create mode 100644 plugins/pagination/classes/plugin/PaginationPage.php create mode 100644 plugins/pagination/composer.json create mode 100644 plugins/pagination/composer.lock create mode 100644 plugins/pagination/css/pagination.css create mode 100644 plugins/pagination/hebe.json create mode 100644 plugins/pagination/languages.yaml create mode 100644 plugins/pagination/pagination.php create mode 100644 plugins/pagination/pagination.yaml create mode 100644 plugins/pagination/templates/partials/pagination.html.twig create mode 100644 plugins/pagination/vendor/autoload.php create mode 100644 plugins/pagination/vendor/composer/ClassLoader.php create mode 100644 plugins/pagination/vendor/composer/LICENSE create mode 100644 plugins/pagination/vendor/composer/autoload_classmap.php create mode 100644 plugins/pagination/vendor/composer/autoload_namespaces.php create mode 100644 plugins/pagination/vendor/composer/autoload_psr4.php create mode 100644 plugins/pagination/vendor/composer/autoload_real.php create mode 100644 plugins/pagination/vendor/composer/autoload_static.php create mode 100644 plugins/pagination/vendor/composer/installed.json create mode 100755 plugins/problems/.gitignore create mode 100755 plugins/problems/CHANGELOG.md create mode 100755 plugins/problems/LICENSE create mode 100755 plugins/problems/README.md create mode 100755 plugins/problems/assets/cli.png create mode 100755 plugins/problems/assets/code-3.svg create mode 100755 plugins/problems/assets/grav-logo.svg create mode 100755 plugins/problems/assets/heart.svg create mode 100755 plugins/problems/assets/readme_1.jpg create mode 100755 plugins/problems/blueprints.yaml create mode 100755 plugins/problems/classes/Problems/Apache.php create mode 100755 plugins/problems/classes/Problems/Base/Problem.php create mode 100755 plugins/problems/classes/Problems/Base/ProblemChecker.php create mode 100755 plugins/problems/classes/Problems/EssentialFolders.php create mode 100755 plugins/problems/classes/Problems/PHPModules.php create mode 100755 plugins/problems/classes/Problems/PHPVersion.php create mode 100755 plugins/problems/classes/Problems/Permissions.php create mode 100755 plugins/problems/cli/CheckCommand.php create mode 100755 plugins/problems/composer.json create mode 100755 plugins/problems/composer.lock create mode 100755 plugins/problems/css/admin.css create mode 100755 plugins/problems/css/admin.min.css create mode 100755 plugins/problems/css/spectre-icons.css create mode 100755 plugins/problems/css/spectre-icons.min.css create mode 100755 plugins/problems/css/spectre.css create mode 100755 plugins/problems/css/spectre.min.css create mode 100755 plugins/problems/gulpfile.js create mode 100755 plugins/problems/hebe.json create mode 100755 plugins/problems/languages.yaml create mode 100755 plugins/problems/package.json create mode 100755 plugins/problems/problems.php create mode 100755 plugins/problems/problems.yaml create mode 100755 plugins/problems/scss/_accordions.scss create mode 100755 plugins/problems/scss/_animations.scss create mode 100755 plugins/problems/scss/_asian.scss create mode 100755 plugins/problems/scss/_autocomplete.scss create mode 100755 plugins/problems/scss/_avatars.scss create mode 100755 plugins/problems/scss/_badges.scss create mode 100755 plugins/problems/scss/_bars.scss create mode 100755 plugins/problems/scss/_base.scss create mode 100755 plugins/problems/scss/_breadcrumbs.scss create mode 100755 plugins/problems/scss/_buttons.scss create mode 100755 plugins/problems/scss/_calendars.scss create mode 100755 plugins/problems/scss/_cards.scss create mode 100755 plugins/problems/scss/_carousels.scss create mode 100755 plugins/problems/scss/_chips.scss create mode 100755 plugins/problems/scss/_codes.scss create mode 100755 plugins/problems/scss/_comparison-sliders.scss create mode 100755 plugins/problems/scss/_dropdowns.scss create mode 100755 plugins/problems/scss/_empty.scss create mode 100755 plugins/problems/scss/_filters.scss create mode 100755 plugins/problems/scss/_forms.scss create mode 100755 plugins/problems/scss/_icons.scss create mode 100755 plugins/problems/scss/_labels.scss create mode 100755 plugins/problems/scss/_layout.scss create mode 100755 plugins/problems/scss/_media.scss create mode 100755 plugins/problems/scss/_menus.scss create mode 100755 plugins/problems/scss/_meters.scss create mode 100755 plugins/problems/scss/_mixins.scss create mode 100755 plugins/problems/scss/_modals.scss create mode 100755 plugins/problems/scss/_navbar.scss create mode 100755 plugins/problems/scss/_navs.scss create mode 100755 plugins/problems/scss/_normalize.scss create mode 100755 plugins/problems/scss/_off-canvas.scss create mode 100755 plugins/problems/scss/_pagination.scss create mode 100755 plugins/problems/scss/_panels.scss create mode 100755 plugins/problems/scss/_parallax.scss create mode 100755 plugins/problems/scss/_popovers.scss create mode 100755 plugins/problems/scss/_preset.scss create mode 100755 plugins/problems/scss/_problems.scss create mode 100755 plugins/problems/scss/_progress.scss create mode 100755 plugins/problems/scss/_sliders.scss create mode 100755 plugins/problems/scss/_steps.scss create mode 100755 plugins/problems/scss/_tables.scss create mode 100755 plugins/problems/scss/_tabs.scss create mode 100755 plugins/problems/scss/_tiles.scss create mode 100755 plugins/problems/scss/_timelines.scss create mode 100755 plugins/problems/scss/_toasts.scss create mode 100755 plugins/problems/scss/_tooltips.scss create mode 100755 plugins/problems/scss/_typography.scss create mode 100755 plugins/problems/scss/_utilities.scss create mode 100755 plugins/problems/scss/_variables.scss create mode 100755 plugins/problems/scss/admin.scss create mode 100755 plugins/problems/scss/icons/_icons-action.scss create mode 100755 plugins/problems/scss/icons/_icons-core.scss create mode 100755 plugins/problems/scss/icons/_icons-navigation.scss create mode 100755 plugins/problems/scss/icons/_icons-object.scss create mode 100755 plugins/problems/scss/mixins/_avatar.scss create mode 100755 plugins/problems/scss/mixins/_button.scss create mode 100755 plugins/problems/scss/mixins/_clearfix.scss create mode 100755 plugins/problems/scss/mixins/_color.scss create mode 100755 plugins/problems/scss/mixins/_label.scss create mode 100755 plugins/problems/scss/mixins/_position.scss create mode 100755 plugins/problems/scss/mixins/_shadow.scss create mode 100755 plugins/problems/scss/mixins/_text.scss create mode 100755 plugins/problems/scss/mixins/_toast.scss create mode 100755 plugins/problems/scss/mixins/_transition.scss create mode 100755 plugins/problems/scss/spectre-icons.scss create mode 100755 plugins/problems/scss/spectre.scss create mode 100755 plugins/problems/scss/utilities/_colors.scss create mode 100755 plugins/problems/scss/utilities/_cursors.scss create mode 100755 plugins/problems/scss/utilities/_display.scss create mode 100755 plugins/problems/scss/utilities/_divider.scss create mode 100755 plugins/problems/scss/utilities/_loading.scss create mode 100755 plugins/problems/scss/utilities/_position.scss create mode 100755 plugins/problems/scss/utilities/_shapes.scss create mode 100755 plugins/problems/scss/utilities/_text.scss create mode 100755 plugins/problems/templates/problems.html.twig create mode 100755 plugins/problems/templates/reports/problems-report.html.twig create mode 100755 plugins/problems/vendor/autoload.php create mode 100755 plugins/problems/vendor/composer/ClassLoader.php create mode 100755 plugins/problems/vendor/composer/InstalledVersions.php create mode 100755 plugins/problems/vendor/composer/LICENSE create mode 100755 plugins/problems/vendor/composer/autoload_classmap.php create mode 100755 plugins/problems/vendor/composer/autoload_namespaces.php create mode 100755 plugins/problems/vendor/composer/autoload_psr4.php create mode 100755 plugins/problems/vendor/composer/autoload_real.php create mode 100755 plugins/problems/vendor/composer/autoload_static.php create mode 100755 plugins/problems/vendor/composer/installed.json create mode 100755 plugins/problems/vendor/composer/installed.php create mode 100755 plugins/problems/yarn.lock create mode 100755 plugins/social-seo-metatags/CHANGELOG.md create mode 100755 plugins/social-seo-metatags/LICENSE create mode 100755 plugins/social-seo-metatags/README.md create mode 100755 plugins/social-seo-metatags/blueprints.yaml create mode 100755 plugins/social-seo-metatags/languages.yaml create mode 100755 plugins/social-seo-metatags/social-seo-metatags.php create mode 100755 plugins/social-seo-metatags/social-seo-metatags.yaml create mode 100755 plugins/taxonomylist/.gitignore create mode 100755 plugins/taxonomylist/CHANGELOG.md create mode 100755 plugins/taxonomylist/LICENSE create mode 100755 plugins/taxonomylist/README.md create mode 100755 plugins/taxonomylist/assets/readme_1.png create mode 100755 plugins/taxonomylist/blueprints.yaml create mode 100755 plugins/taxonomylist/classes/taxonomylist.php create mode 100755 plugins/taxonomylist/composer.json create mode 100755 plugins/taxonomylist/composer.lock create mode 100755 plugins/taxonomylist/hebe.json create mode 100755 plugins/taxonomylist/taxonomylist.php create mode 100755 plugins/taxonomylist/taxonomylist.yaml create mode 100755 plugins/taxonomylist/templates/partials/taxonomylist.html.twig create mode 100755 plugins/taxonomylist/vendor/autoload.php create mode 100755 plugins/taxonomylist/vendor/composer/ClassLoader.php create mode 100755 plugins/taxonomylist/vendor/composer/LICENSE create mode 100755 plugins/taxonomylist/vendor/composer/autoload_classmap.php create mode 100755 plugins/taxonomylist/vendor/composer/autoload_namespaces.php create mode 100755 plugins/taxonomylist/vendor/composer/autoload_psr4.php create mode 100755 plugins/taxonomylist/vendor/composer/autoload_real.php create mode 100755 plugins/taxonomylist/vendor/composer/autoload_static.php create mode 100755 plugins/taxonomylist/vendor/composer/installed.json create mode 100755 plugins/tinymce-editor/CHANGELOG.md create mode 100755 plugins/tinymce-editor/CONTRIBUTING.md create mode 100755 plugins/tinymce-editor/LICENSE create mode 100755 plugins/tinymce-editor/README.md create mode 100755 plugins/tinymce-editor/assets/tinymce-editor.png create mode 100755 plugins/tinymce-editor/blueprints.yaml create mode 100755 plugins/tinymce-editor/css/editor.css create mode 100755 plugins/tinymce-editor/js/tinymce/jquery.tinymce.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/af_ZA.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/ar.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/az.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/be.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/bg_BG.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/bn_BD.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/ca.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/cs.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/cs_CZ.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/cy.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/da.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/de.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/de_AT.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/dv.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/el.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/en_CA.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/en_GB.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/es.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/es_MX.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/et.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/eu.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/fa_IR.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/fi.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/fr_FR.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/ga.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/gl.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/he_IL.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/hr.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/hu_HU.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/id.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/it.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/ja.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/ka_GE.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/kab.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/kk.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/km_KH.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/ko_KR.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/lt.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/lv.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/nb_NO.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/nl.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/pl.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/pt_BR.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/pt_PT.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/readme.md create mode 100755 plugins/tinymce-editor/js/tinymce/langs/ro.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/ru.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/sk.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/sl_SI.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/sr.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/sv_SE.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/ta.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/ta_IN.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/th_TH.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/tr.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/tr_TR.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/ug.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/uk.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/uk_UA.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/uz.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/vi_VN.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/zh_CN.js create mode 100755 plugins/tinymce-editor/js/tinymce/langs/zh_TW.js create mode 100755 plugins/tinymce-editor/js/tinymce/license.txt create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/advlist/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/anchor/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/autolink/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/autoresize/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/autosave/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/bbcode/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/charmap/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/code/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/codesample/css/prism.css create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/codesample/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/colorpicker/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/contextmenu/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/directionality/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/emoticons/img/smiley-cool.gif create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/emoticons/img/smiley-cry.gif create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/emoticons/img/smiley-embarassed.gif create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/emoticons/img/smiley-foot-in-mouth.gif create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/emoticons/img/smiley-frown.gif create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/emoticons/img/smiley-innocent.gif create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/emoticons/img/smiley-kiss.gif create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/emoticons/img/smiley-laughing.gif create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/emoticons/img/smiley-money-mouth.gif create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/emoticons/img/smiley-sealed.gif create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/emoticons/img/smiley-smile.gif create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/emoticons/img/smiley-surprised.gif create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/emoticons/img/smiley-tongue-out.gif create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/emoticons/img/smiley-undecided.gif create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/emoticons/img/smiley-wink.gif create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/emoticons/img/smiley-yell.gif create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/emoticons/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/fullpage/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/fullscreen/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/help/img/logo.png create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/help/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/hr/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/image/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/imagetools/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/importcss/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/insertdatetime/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/legacyoutput/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/link/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/lists/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/media/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/nonbreaking/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/noneditable/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/pagebreak/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/paste/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/preview/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/print/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/save/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/searchreplace/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/spellchecker/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/tabfocus/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/table/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/template/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/textcolor/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/textpattern/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/toc/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/visualblocks/css/visualblocks.css create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/visualblocks/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/visualchars/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/plugins/wordcount/plugin.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/skins/lightgray/content.inline.min.css create mode 100755 plugins/tinymce-editor/js/tinymce/skins/lightgray/content.min.css create mode 100755 plugins/tinymce-editor/js/tinymce/skins/lightgray/content.mobile.min.css create mode 100755 plugins/tinymce-editor/js/tinymce/skins/lightgray/fonts/tinymce-mobile.woff create mode 100755 plugins/tinymce-editor/js/tinymce/skins/lightgray/fonts/tinymce-small.eot create mode 100755 plugins/tinymce-editor/js/tinymce/skins/lightgray/fonts/tinymce-small.svg create mode 100755 plugins/tinymce-editor/js/tinymce/skins/lightgray/fonts/tinymce-small.ttf create mode 100755 plugins/tinymce-editor/js/tinymce/skins/lightgray/fonts/tinymce-small.woff create mode 100755 plugins/tinymce-editor/js/tinymce/skins/lightgray/fonts/tinymce.eot create mode 100755 plugins/tinymce-editor/js/tinymce/skins/lightgray/fonts/tinymce.svg create mode 100755 plugins/tinymce-editor/js/tinymce/skins/lightgray/fonts/tinymce.ttf create mode 100755 plugins/tinymce-editor/js/tinymce/skins/lightgray/fonts/tinymce.woff create mode 100755 plugins/tinymce-editor/js/tinymce/skins/lightgray/img/anchor.gif create mode 100755 plugins/tinymce-editor/js/tinymce/skins/lightgray/img/loader.gif create mode 100755 plugins/tinymce-editor/js/tinymce/skins/lightgray/img/object.gif create mode 100755 plugins/tinymce-editor/js/tinymce/skins/lightgray/img/trans.gif create mode 100755 plugins/tinymce-editor/js/tinymce/skins/lightgray/skin.min.css create mode 100755 plugins/tinymce-editor/js/tinymce/skins/lightgray/skin.mobile.min.css create mode 100755 plugins/tinymce-editor/js/tinymce/themes/inlite/theme.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/themes/mobile/theme.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/themes/modern/theme.min.js create mode 100755 plugins/tinymce-editor/js/tinymce/tinymce.min.js create mode 100755 plugins/tinymce-editor/languages.yaml create mode 100755 plugins/tinymce-editor/templates/forms/fields/tinymce/tinymce.html.twig create mode 100755 plugins/tinymce-editor/tinymce-editor.php create mode 100755 plugins/tinymce-editor/tinymce-editor.yaml create mode 100755 plugins/tmp-pagecollection/CHANGELOG.md create mode 100755 plugins/tmp-pagecollection/LICENSE create mode 100755 plugins/tmp-pagecollection/README.md create mode 100755 plugins/tmp-pagecollection/blueprints.yaml create mode 100755 plugins/tmp-pagecollection/composer.json create mode 100755 plugins/tmp-pagecollection/composer.lock create mode 100755 plugins/tmp-pagecollection/languages.yaml create mode 100755 plugins/tmp-pagecollection/tmp-pagecollection.php create mode 100755 plugins/tmp-pagecollection/tmp-pagecollection.yaml create mode 100755 plugins/tmp-pagecollection/twig/twigDisplay.php create mode 100755 plugins/tmp-pagecollection/vendor/autoload.php create mode 100755 plugins/tmp-pagecollection/vendor/composer/ClassLoader.php create mode 100755 plugins/tmp-pagecollection/vendor/composer/InstalledVersions.php create mode 100755 plugins/tmp-pagecollection/vendor/composer/LICENSE create mode 100755 plugins/tmp-pagecollection/vendor/composer/autoload_classmap.php create mode 100755 plugins/tmp-pagecollection/vendor/composer/autoload_namespaces.php create mode 100755 plugins/tmp-pagecollection/vendor/composer/autoload_psr4.php create mode 100755 plugins/tmp-pagecollection/vendor/composer/autoload_real.php create mode 100755 plugins/tmp-pagecollection/vendor/composer/autoload_static.php create mode 100755 plugins/tmp-pagecollection/vendor/composer/installed.json create mode 100755 plugins/tmp-pagecollection/vendor/composer/installed.php create mode 100755 plugins/tmp-pagecollection/vendor/composer/platform_check.php create mode 100644 plugins/tntsearch/.eslintrc create mode 100644 plugins/tntsearch/.gitignore create mode 100644 plugins/tntsearch/CHANGELOG.md create mode 100644 plugins/tntsearch/LICENSE create mode 100644 plugins/tntsearch/README.md create mode 100644 plugins/tntsearch/app/history.js create mode 100644 plugins/tntsearch/app/main.js create mode 100644 plugins/tntsearch/app/search.js create mode 100644 plugins/tntsearch/assets/admin/tntsearch.css create mode 100644 plugins/tntsearch/assets/admin/tntsearch.js create mode 100644 plugins/tntsearch/assets/tntsearch-ajax.gif create mode 100644 plugins/tntsearch/assets/tntsearch-config.png create mode 100644 plugins/tntsearch/assets/tntsearch-quicktray.png create mode 100644 plugins/tntsearch/assets/tntsearch.css create mode 100644 plugins/tntsearch/assets/tntsearch.js create mode 100644 plugins/tntsearch/blueprints.yaml create mode 100644 plugins/tntsearch/classes/GravConnector.php create mode 100644 plugins/tntsearch/classes/GravResultObject.php create mode 100644 plugins/tntsearch/classes/GravTNTSearch.php create mode 100644 plugins/tntsearch/cli/TNTSearchIndexerCommand.php create mode 100644 plugins/tntsearch/cli/TNTSearchQueryCommand.php create mode 100644 plugins/tntsearch/composer.json create mode 100644 plugins/tntsearch/composer.lock create mode 100644 plugins/tntsearch/languages.yaml create mode 100644 plugins/tntsearch/package.json create mode 100644 plugins/tntsearch/templates/forms/fields/indexstatus/indexstatus.html.twig create mode 100644 plugins/tntsearch/templates/partials/tntsearch.html.twig create mode 100644 plugins/tntsearch/templates/search.html.twig create mode 100644 plugins/tntsearch/templates/tntquery-ajax.html.twig create mode 100644 plugins/tntsearch/templates/tntquery.html.twig create mode 100644 plugins/tntsearch/templates/tntquery.json.twig create mode 100644 plugins/tntsearch/tntsearch.php create mode 100644 plugins/tntsearch/tntsearch.yaml create mode 100644 plugins/tntsearch/vendor/autoload.php create mode 100644 plugins/tntsearch/vendor/composer/ClassLoader.php create mode 100644 plugins/tntsearch/vendor/composer/InstalledVersions.php create mode 100644 plugins/tntsearch/vendor/composer/LICENSE create mode 100644 plugins/tntsearch/vendor/composer/autoload_classmap.php create mode 100644 plugins/tntsearch/vendor/composer/autoload_files.php create mode 100644 plugins/tntsearch/vendor/composer/autoload_namespaces.php create mode 100644 plugins/tntsearch/vendor/composer/autoload_psr4.php create mode 100644 plugins/tntsearch/vendor/composer/autoload_real.php create mode 100644 plugins/tntsearch/vendor/composer/autoload_static.php create mode 100644 plugins/tntsearch/vendor/composer/installed.json create mode 100644 plugins/tntsearch/vendor/composer/installed.php create mode 100644 plugins/tntsearch/vendor/composer/platform_check.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/.github/FUNDING.yml create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/.github/stale.yml create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/.gitignore create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/.travis.yml create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/CHANGELOG.md create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/CODE_OF_CONDUCT.md create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/CONDUCT.md create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/CONTRIBUTING.md create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/LICENSE.md create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/PS4Ware.md create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/README.md create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/composer.json create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/helper/helpers.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/phpunit.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/phpunit.xml create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Classifier/TNTClassifier.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Connectors/Connector.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Connectors/ConnectorInterface.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Connectors/FileSystemConnector.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Connectors/MySqlConnector.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Connectors/PostgresConnector.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Connectors/SQLiteConnector.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Connectors/SqlServerConnector.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Exceptions/IndexNotFoundException.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/FileReaders/FileReaderInterface.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/FileReaders/TextFileReader.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Indexer/TNTGeoIndexer.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Indexer/TNTIndexer.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/KeywordExtraction/Rake.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Spell/JaroWinklerDistance.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stemmer/ArabicStemmer.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stemmer/CroatianStemmer.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stemmer/FrenchStemmer.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stemmer/GermanStemmer.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stemmer/ItalianStemmer.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stemmer/NoStemmer.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stemmer/PolishStemmer.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stemmer/PorterStemmer.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stemmer/PortugueseStemmer.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stemmer/RussianStemmer.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stemmer/Stemmer.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stemmer/UkrainianStemmer.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stopwords/croatian.json create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stopwords/english.json create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stopwords/french.json create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stopwords/german.json create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stopwords/italian.json create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stopwords/russian.json create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stopwords/spanish.json create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Stopwords/ukrainian.json create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Support/AbstractTokenizer.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Support/BigramTokenizer.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Support/Collection.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Support/EdgeNgramTokenizer.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Support/Expression.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Support/FivegramTokenizer.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Support/FourgramTokenizer.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Support/Highlighter.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Support/NGramTokenizer.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Support/ProductTokenizer.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Support/Tokenizer.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Support/TokenizerInterface.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/Support/TrigramTokenizer.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/TNTFuzzyMatch.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/TNTGeoSearch.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/src/TNTSearch.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/TNTFuzzyMatchTest.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/TNTGeoSearchTest.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/TNTSearchTest.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/_files/articles.sqlite create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/_files/articles/1.txt create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/_files/articles/2.txt create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/_files/articles/3.txt create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/_files/cities.sqlite create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/_files/english_wordlist_2k.txt create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/_files/mnist/.gitignore create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/_files/sms-texts.json create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/classifier/TNTClassifierTest.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/indexer/TNTGeoIndexerTest.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/indexer/TNTIndexerTest.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/keywordextraction/Rake.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/spell/JaroWinklerDistanceTest.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/stemmer/CroatianStemmerTest.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/stemmer/FrenchStemmerTest.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/stemmer/GermanStemmerTest.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/stemmer/PolishStemmerTest.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/stemmer/PorterStemmerTest.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/stemmer/PortugueseStemmerTest.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/stemmer/porter/input.txt create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/stemmer/porter/output.txt create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/support/BigramTokenizerTest.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/support/EdgeNgramTokenizerTest.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/support/ExpressionTest.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/support/FivegramTokenizerTest.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/support/FourgramTokenizerTest.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/support/HighlighterTest.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/support/NGramTokenizerTest.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/support/ProductTokenizerTest.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/support/TokenizerTest.php create mode 100644 plugins/tntsearch/vendor/teamtnt/tntsearch/tests/support/TrigramTokenizerTest.php create mode 100644 plugins/tntsearch/webpack.conf.js create mode 100644 plugins/tntsearch/yarn.lock create mode 100755 themes/.gitkeep create mode 100755 themes/plain/CHANGELOG.md create mode 100755 themes/plain/LICENSE create mode 100755 themes/plain/README.md create mode 100755 themes/plain/blueprints.yaml create mode 100755 themes/plain/blueprints/actualites.yaml create mode 100755 themes/plain/blueprints/coalitions.yaml create mode 100755 themes/plain/blueprints/danger.yaml create mode 100755 themes/plain/blueprints/default.yaml create mode 100755 themes/plain/blueprints/home.yaml create mode 100755 themes/plain/blueprints/media.yaml create mode 100755 themes/plain/blueprints/modules.yaml create mode 100755 themes/plain/blueprints/pays.yaml create mode 100755 themes/plain/blueprints/post.yaml create mode 100755 themes/plain/blueprints/power.yaml create mode 100755 themes/plain/blueprints/projects.yaml create mode 100755 themes/plain/blueprints/ressources.yaml create mode 100755 themes/plain/blueprints/sub_cat.yaml create mode 100755 themes/plain/css/admin.css create mode 100755 themes/plain/css/app.css create mode 100755 themes/plain/css/slick.css create mode 100755 themes/plain/fonts/roboto/Roboto_Bold.ttf create mode 100755 themes/plain/fonts/roboto/Roboto_Light.ttf create mode 100755 themes/plain/fonts/roboto/Roboto_Regular.ttf create mode 100755 themes/plain/fonts/trueno/TruenoBd.otf create mode 100755 themes/plain/fonts/trueno/TruenoLt.otf create mode 100755 themes/plain/fonts/trueno/TruenoLtIt.otf create mode 100755 themes/plain/fonts/trueno/TruenoRg.otf create mode 100755 themes/plain/fonts/trueno/TruenoSBd.otf create mode 100755 themes/plain/fonts/trueno/TruenoUltLt.otf create mode 100755 themes/plain/images/BlankMap-Africa.svg create mode 100644 themes/plain/images/Donation.svg create mode 100755 themes/plain/images/campagnes.svg create mode 100755 themes/plain/images/close.png create mode 100755 themes/plain/images/com.svg create mode 100755 themes/plain/images/contact.svg create mode 100755 themes/plain/images/contact_w.svg create mode 100755 themes/plain/images/crown.svg create mode 100755 themes/plain/images/f.svg create mode 100755 themes/plain/images/f_w.svg create mode 100755 themes/plain/images/favicon.ico create mode 100755 themes/plain/images/ffr.svg create mode 100755 themes/plain/images/free.png create mode 100755 themes/plain/images/in.svg create mode 100755 themes/plain/images/in_w.svg create mode 100755 themes/plain/images/ligne.svg create mode 100755 themes/plain/images/loading.gif create mode 100755 themes/plain/images/logo.svg create mode 100755 themes/plain/images/menace.png create mode 100644 themes/plain/images/newsletter.svg create mode 100755 themes/plain/images/next.png create mode 100755 themes/plain/images/outils.svg create mode 100644 themes/plain/images/photo_home_membre.jpg create mode 100644 themes/plain/images/photo_home_qui.jpg create mode 100644 themes/plain/images/photo_home_soutenir.jpg create mode 100755 themes/plain/images/pictos_pagearrestation.svg create mode 100755 themes/plain/images/prev.png create mode 100755 themes/plain/images/prison.png create mode 100755 themes/plain/images/t.svg create mode 100755 themes/plain/images/t_w.svg create mode 100755 themes/plain/images/trib.svg create mode 100755 themes/plain/images/you.svg create mode 100755 themes/plain/images/you_w.svg create mode 100755 themes/plain/js/admin.js create mode 100755 themes/plain/js/app.js create mode 100755 themes/plain/js/app.js.map create mode 100755 themes/plain/js/datavis.js create mode 100755 themes/plain/js/jq.js create mode 100755 themes/plain/js/lib.js create mode 100755 themes/plain/js/lightbox.js create mode 100755 themes/plain/modular.yaml create mode 100755 themes/plain/plain.php create mode 100755 themes/plain/plain.yaml create mode 100755 themes/plain/screenshot.jpg create mode 100755 themes/plain/templates/actualites.html.twig create mode 100755 themes/plain/templates/coalitions.html.twig create mode 100755 themes/plain/templates/danger.html.twig create mode 100755 themes/plain/templates/default.html.twig create mode 100755 themes/plain/templates/error.html.twig create mode 100755 themes/plain/templates/home.html.twig create mode 100755 themes/plain/templates/media.html.twig create mode 100755 themes/plain/templates/modules.html.twig create mode 100755 themes/plain/templates/old_d3.js create mode 100755 themes/plain/templates/partials/base.html.twig create mode 100755 themes/plain/templates/partials/error.html.twig create mode 100755 themes/plain/templates/partials/footer.html.twig create mode 100755 themes/plain/templates/partials/footer_coa.html.twig create mode 100755 themes/plain/templates/partials/head.html.twig create mode 100755 themes/plain/templates/partials/langswitcher.hreflang.html.twig create mode 100755 themes/plain/templates/partials/langswitcher.html.twig create mode 100755 themes/plain/templates/partials/map.html.twig create mode 100755 themes/plain/templates/partials/navigation.html.twig create mode 100755 themes/plain/templates/partials/pagination.html.twig create mode 100755 themes/plain/templates/partials/sidebar.html.twig create mode 100755 themes/plain/templates/partials/slider.html.twig create mode 100755 themes/plain/templates/partials/tntsearch.html.twig create mode 100755 themes/plain/templates/pays.html.twig create mode 100755 themes/plain/templates/post.html.twig create mode 100755 themes/plain/templates/power.html.twig create mode 100755 themes/plain/templates/projects.html.twig create mode 100755 themes/plain/templates/ressources.html.twig create mode 100755 themes/plain/templates/sub_cat.html.twig create mode 100755 themes/plain/templates/tntquery-ajax.html.twig create mode 100755 themes/plain/thumbnail.jpg diff --git a/config/backups.yaml b/config/backups.yaml new file mode 100755 index 0000000..e69de29 diff --git a/config/groups.yaml b/config/groups.yaml new file mode 100644 index 0000000..75f2f1b --- /dev/null +++ b/config/groups.yaml @@ -0,0 +1,17 @@ +lecteur: + access: + admin: + login: false + super: false + cache: false + configuration: false + pages: false + maintenance: false + statistics: false + plugins: false + themes: false + tools: false + users: false + flex-objects: false + readableName: Lecteur + enabled: true diff --git a/config/media.yaml b/config/media.yaml new file mode 100755 index 0000000..23fbce9 --- /dev/null +++ b/config/media.yaml @@ -0,0 +1,263 @@ +types: + defaults: + type: file + thumb: media/thumb.png + mime: application/octet-stream + image: + filters: + default: [enableProgressive] + jpg: + type: image + thumb: media/thumb-jpg.png + mime: image/jpeg + image: null + jpe: + type: image + thumb: media/thumb-jpg.png + mime: image/jpeg + image: null + jpeg: + type: image + thumb: media/thumb-jpg.png + mime: image/jpeg + image: null + png: + type: image + thumb: media/thumb-png.png + mime: image/png + image: null + gif: + type: animated + thumb: media/thumb-gif.png + mime: image/gif + image: null + svg: + type: vector + thumb: media/thumb-svg.png + mime: image/svg+xml + image: null + mp4: + type: video + thumb: media/thumb-mp4.png + mime: video/mp4 + image: null + mov: + type: video + thumb: media/thumb-mov.png + mime: video/quicktime + image: null + m4v: + type: video + thumb: media/thumb-m4v.png + mime: video/x-m4v + image: null + swf: + type: video + thumb: media/thumb-swf.png + mime: video/x-flv + image: null + flv: + type: video + thumb: media/thumb-flv.png + mime: video/x-flv + image: null + webm: + type: video + thumb: media/thumb-webm.png + mime: video/webm + image: null + ogv: + type: video + thumb: media/thumb-ogg.png + mime: video/ogg + image: null + mp3: + type: audio + thumb: media/thumb-mp3.png + mime: audio/mp3 + image: null + ogg: + type: audio + thumb: media/thumb-ogg.png + mime: audio/ogg + image: null + wma: + type: audio + thumb: media/thumb-wma.png + mime: audio/wma + image: null + m4a: + type: audio + thumb: media/thumb-m4a.png + mime: audio/m4a + image: null + wav: + type: audio + thumb: media/thumb-wav.png + mime: audio/wav + image: null + aiff: + type: audio + thumb: media/thumb-aif.png + mime: audio/aiff + image: null + aif: + type: audio + thumb: media/thumb-aif.png + mime: audio/aif + image: null + txt: + type: file + thumb: media/thumb-txt.png + mime: text/plain + image: null + xml: + type: file + thumb: media/thumb-xml.png + mime: application/xml + image: null + doc: + type: file + thumb: media/thumb-doc.png + mime: application/msword + image: null + docx: + type: file + thumb: media/thumb-docx.png + mime: application/msword + image: null + xls: + type: file + thumb: media/thumb-xls.png + mime: application/vnd.ms-excel + image: null + xlsx: + type: file + thumb: media/thumb-xlsx.png + mime: application/vnd.ms-excel + image: null + ppt: + type: file + thumb: media/thumb-ppt.png + mime: application/vnd.ms-powerpoint + image: null + pptx: + type: file + thumb: media/thumb-pptx.png + mime: application/vnd.ms-powerpoint + image: null + pps: + type: file + thumb: media/thumb-pps.png + mime: application/vnd.ms-powerpoint + image: null + rtf: + type: file + thumb: media/thumb-rtf.png + mime: application/rtf + image: null + bmp: + type: file + thumb: media/thumb-bmp.png + mime: image/bmp + image: null + tiff: + type: file + thumb: media/thumb-tiff.png + mime: image/tiff + image: null + mpeg: + type: file + thumb: media/thumb-mpg.png + mime: video/mpeg + image: null + mpg: + type: file + thumb: media/thumb-mpg.png + mime: video/mpeg + image: null + mpe: + type: file + thumb: media/thumb-mpe.png + mime: video/mpeg + image: null + avi: + type: file + thumb: media/thumb-avi.png + mime: video/msvideo + image: null + wmv: + type: file + thumb: media/thumb-wmv.png + mime: video/x-ms-wmv + image: null + html: + type: file + thumb: media/thumb-html.png + mime: text/html + image: null + htm: + type: file + thumb: media/thumb-html.png + mime: text/html + image: null + ics: + type: iCal + thumb: media/thumb-ics.png + mime: text/calendar + image: null + pdf: + type: file + thumb: media/thumb-pdf.png + mime: application/pdf + image: null + ai: + type: file + thumb: media/thumb-ai.png + mime: image/ai + image: null + psd: + type: file + thumb: media/thumb-psd.png + mime: image/psd + image: null + zip: + type: file + thumb: media/thumb-zip.png + mime: application/zip + image: null + 7z: + type: file + thumb: media/thumb-7z.png + mime: application/x-7z-compressed + image: null + gz: + type: file + thumb: media/thumb-gz.png + mime: application/gzip + image: null + tar: + type: file + thumb: media/thumb-tar.png + mime: application/x-tar + image: null + css: + type: file + thumb: media/thumb-css.png + mime: text/css + image: null + js: + type: file + thumb: media/thumb-js.png + mime: application/javascript + image: null + json: + type: file + thumb: media/thumb-json.png + mime: application/json + image: null + odt: + type: file + thumb: null + mime: null + image: null diff --git a/config/plugins/admin.yaml b/config/plugins/admin.yaml new file mode 100755 index 0000000..c28bff6 --- /dev/null +++ b/config/plugins/admin.yaml @@ -0,0 +1,101 @@ +enabled: true +route: /admin +cache_enabled: true +theme: grav +logo_text: null +body_classes: null +content_padding: true +twofa_enabled: true +sidebar: + activate: tab + hover_delay: 100 + size: auto +dashboard: + days_of_stats: 7 +widgets_display: + dashboard-maintenance: 'true' + dashboard-statistics: 'true' + dashboard-notifications: 'false' + dashboard-feed: 'false' + dashboard-pages: 'true' +pages: + show_parents: both + show_modular: true + parents_levels: null +session: + timeout: 6000 +edit_mode: normal +frontend_preview_target: inline +show_github_msg: true +admin_icons: line-awesome +enable_auto_updates_check: false +notifications: + feed: false + dashboard: false + plugins: false + themes: false +popularity: + enabled: true + ignore: + - '/test*' + - /modular + history: + daily: '30' + monthly: '12' + visitors: '20' +whitelabel: + quicktray_recompile: false + codemirror_theme: paper + codemirror_fontsize: md + codemirror_md_font: sans + logo_custom: { } + logo_login: { } + color_scheme: + accents: + primary-accent: button + secondary-accent: notice + tertiary-accent: critical + colors: + logo-bg: '#323640' + logo-link: '#FFFFFF' + nav-bg: '#3D424E' + nav-text: '#B7B9BD' + nav-link: '#ffffff' + nav-selected-bg: '#323640' + nav-selected-link: '#ffffff' + nav-hover-bg: '#434753' + nav-hover-link: '#ffffff' + toolbar-bg: '#ffffff' + toolbar-text: '#3D424E' + page-bg: '#F6F6F6' + page-text: '#6f7b8a' + page-link: '#0090D9' + content-bg: '#ffffff' + content-text: '#6f7b8a' + content-link: '#0090D9' + content-link2: '#da4b46' + content-header: '#414147' + content-tabs-bg: '#e6e6e6' + content-tabs-text: '#808080' + button-bg: '#0090D9' + button-text: '#ffffff' + notice-bg: '#06A599' + notice-text: '#ffffff' + update-bg: '#77559D' + update-text: '#ffffff' + critical-bg: '#F45857' + critical-text: '#ffffff' + content-highlight: '#ffffd7' + name: null + custom_footer: null + custom_css: null + custom_presets: null +show_beta_msg: null +pagemedia: + resize_width: 0 + resize_height: 0 + res_min_width: 0 + res_min_height: 0 + res_max_width: 0 + res_max_height: 0 + resize_quality: 0.8 diff --git a/config/plugins/auto-author.yaml b/config/plugins/auto-author.yaml new file mode 100755 index 0000000..364d495 --- /dev/null +++ b/config/plugins/auto-author.yaml @@ -0,0 +1,2 @@ +enabled: true +user: true diff --git a/config/plugins/autoseo.yaml b/config/plugins/autoseo.yaml new file mode 100755 index 0000000..d4bbfea --- /dev/null +++ b/config/plugins/autoseo.yaml @@ -0,0 +1,11 @@ +enabled: true +description: + enabled: true + length: 30 +keywords: + enabled: true + length: 20 +facebook: + enabled: true +twitter: + enabled: true diff --git a/config/plugins/cookieconsent.yaml b/config/plugins/cookieconsent.yaml new file mode 100755 index 0000000..3be049a --- /dev/null +++ b/config/plugins/cookieconsent.yaml @@ -0,0 +1,13 @@ +enabled: true +cdn: true +popup_background_color: '#000000' +popup_text_color: '#ffffff' +button_background_color: '#e94d1a' +button_text_color: '#000000' +button_border_color: '#e94d1a' +position: bottom +theme: block +content_message: 'Ce site contient des cookies déposés via des services de partage de vidéos, ils sont destinés à permettre à l''utilisateur de visualiser le contenu multimédia directement sur le site.' +content_dismiss: 'J''accepte' +content_link: 'En savoir plus' +content_href: 'https://policies.google.com/privacy?hl=fr&gl=fr' diff --git a/config/plugins/email.yaml b/config/plugins/email.yaml new file mode 100644 index 0000000..5afc30e --- /dev/null +++ b/config/plugins/email.yaml @@ -0,0 +1,19 @@ +enabled: true +from: contact@armansansd.net +to: contact@armansansd.net +mailer: + engine: sendmail + smtp: + server: localhost + port: 25 + encryption: none + user: null + password: null + sendmail: + bin: '/usr/sbin/sendmail -bs' +content_type: text/html +debug: false +cc: null +bcc: null +reply_to: null +body: null diff --git a/config/plugins/langswitcher.yaml b/config/plugins/langswitcher.yaml new file mode 100755 index 0000000..3066a1a --- /dev/null +++ b/config/plugins/langswitcher.yaml @@ -0,0 +1,3 @@ +enabled: true +built_in_css: true +untranslated_pages_behavior: none diff --git a/config/plugins/pagination.yaml b/config/plugins/pagination.yaml new file mode 100755 index 0000000..c83c903 --- /dev/null +++ b/config/plugins/pagination.yaml @@ -0,0 +1,3 @@ +enabled: true +built_in_css: true +delta: 0 diff --git a/config/plugins/social-seo-metatags.yaml b/config/plugins/social-seo-metatags.yaml new file mode 100755 index 0000000..2da01be --- /dev/null +++ b/config/plugins/social-seo-metatags.yaml @@ -0,0 +1,33 @@ +enabled: true +seo: + robots: without + length: 20 + taxonomy: + enabled: true + page_content: + enabled: false + breadcrumb: false + keywords: + taxonomy: + enabled: true + page_content: + enabled: true + length: 20 +quote: + convert_simple: true +image: + use_cache: true +social_pages: + pages: + twitter: + enabled: true + type: summary_large_image + username: null + facebook: + opengraph: + enabled: false + insights: + enabled: false + appid: '1234567890' +default: + image: { } diff --git a/config/plugins/taxonomylist.yaml b/config/plugins/taxonomylist.yaml new file mode 100755 index 0000000..ca43908 --- /dev/null +++ b/config/plugins/taxonomylist.yaml @@ -0,0 +1,2 @@ +enabled: true +route: /actualites diff --git a/config/plugins/tinymce-editor.yaml b/config/plugins/tinymce-editor.yaml new file mode 100644 index 0000000..0b727c1 --- /dev/null +++ b/config/plugins/tinymce-editor.yaml @@ -0,0 +1,80 @@ +enabled: true +restrictions: + whitelist: false + blacklist: false +whitelist: + items: + - '@root.descendants' + filter: + published: true + non-published: true +blacklist: + items: + - '@none' + filter: + published: true + non-published: true +apikey: r2duxdbywfre1kmk3ft7z998eyt5mnsmkyqcp41hthzk5jcc +plugins: + - advlist + - anchor + - autoresize + - charmap + - code + - colorpicker + - emoticons + - fullscreen + - hr + - image + - insertdatetime + - link + - lists + - media + - nonbreaking + - pagebreak + - paste + - print + - searchreplace + - table + - textcolor + - toc + - visualchars + - wordcount +parameters: + - + name: paste_data_images + value: '1' + - + name: paste_data_images + value: '1' +evals: '' +menubar: false +menu: + - + title: File + items: 'newdocument print' + - + title: Edit + items: 'undo redo | cut copy paste pastetext | selectall | searchreplace' + - + title: Insert + items: 'media link image | pagebreak charmap anchor hr insertdatetime nonbreaking toc' + - + title: View + items: 'visualchars visualaid | fullscreen' + - + title: Format + items: 'bold italic underline strikethrough superscript subscript | formats | removeformat' + - + title: Table + items: 'inserttable tableprops deletetable | cell row column' + - + title: Tools + items: code +toolbar: + - + row: 'formatselect | undo redo | visualchars | image media | link unlink | blockquote | nonbreaking | | bold italic underline | bullist numlist | superscript subscript | removeformat table' + - + row: null +branding: false +statusbar: false diff --git a/config/plugins/tntsearch.yaml b/config/plugins/tntsearch.yaml new file mode 100755 index 0000000..b9a8883 --- /dev/null +++ b/config/plugins/tntsearch.yaml @@ -0,0 +1,28 @@ +enabled: true +search_route: /search +query_route: /s +built_in_css: true +built_in_js: true +built_in_search_page: true +enable_admin_page_events: true +search_type: auto +fuzzy: true +phrases: true +stemmer: default +display_route: true +display_hits: true +display_time: true +live_uri_update: true +limit: '20' +min: '3' +snippet: '300' +index_page_by_default: true +scheduled_index: + enabled: true + at: '0 0 * * 1' + logs: logs/tntsearch-index.out +filter: + items: + - root@.descendants +powered_by: true +search_object_type: Grav diff --git a/config/scheduler.yaml b/config/scheduler.yaml new file mode 100755 index 0000000..e69de29 diff --git a/config/security.yaml b/config/security.yaml new file mode 100755 index 0000000..a89515d --- /dev/null +++ b/config/security.yaml @@ -0,0 +1 @@ +salt: w2FWPbaOYk5Sxg diff --git a/config/site.yaml b/config/site.yaml new file mode 100755 index 0000000..59260cf --- /dev/null +++ b/config/site.yaml @@ -0,0 +1,19 @@ +title: 'Tournons la Page' +default_lang: fr +author: + name: 'tournons la page' + email: contact@tournonslapage.org +taxonomies: + - category + - tag +metadata: + description: 'Tournons La Page est un mouvement citoyen qui entend rassembler le plus largement possible autour d''une vision et des valeurs communes de respect des droits humains fondamentaux et des principes démocratiques.' +summary: + enabled: true + format: short + size: 300 + delimiter: '===' +redirects: null +routes: null +blog: + route: /blog diff --git a/config/streams.yaml b/config/streams.yaml new file mode 100755 index 0000000..e69de29 diff --git a/config/system.yaml b/config/system.yaml new file mode 100644 index 0000000..9dcc868 --- /dev/null +++ b/config/system.yaml @@ -0,0 +1,239 @@ +absolute_urls: false +timezone: null +param_sep: ':' +wrapped_site: false +reverse_proxy_setup: false +force_ssl: false +force_lowercase_urls: true +custom_base_url: null +username_regex: '^[a-z0-9_-]{3,16}$' +pwd_regex: '(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}' +intl_enabled: true +http_x_forwarded: + protocol: true + host: false + port: true + ip: true +languages: + supported: + - fr + - en + default_lang: fr + include_default_lang: true + include_default_lang_file_extension: true + translations: true + translations_fallback: true + session_store_active: false + http_accept_language: false + override_locale: false + pages_fallback_only: false + debug: false +home: + alias: /home + hide_in_urls: false +pages: + type: regular + dirs: + - 'page://' + theme: plain + order: + by: default + dir: asc + list: + count: 20 + dateformat: + default: null + short: 'jS M Y' + long: 'F jS \a\t g:ia' + publish_dates: true + process: + markdown: true + twig: false + twig_first: false + never_cache_twig: false + events: + page: true + twig: true + markdown: + extra: false + auto_line_breaks: false + auto_url_links: false + escape_markup: false + special_chars: + '>': gt + '<': lt + valid_link_attributes: + - rel + - target + - id + - class + - classes + types: + - html + - htm + - xml + - txt + - json + - rss + - atom + append_url_extension: null + expires: 604800 + cache_control: null + last_modified: false + etag: false + vary_accept_encoding: false + redirect_default_code: '302' + redirect_trailing_slash: 1 + redirect_default_route: 0 + ignore_files: + - .DS_Store + ignore_folders: + - .git + - .idea + ignore_hidden: true + hide_empty_folders: false + url_taxonomy_filters: true + frontmatter: + process_twig: false + ignore_fields: + - form + - forms +cache: + enabled: false + check: + method: file + driver: auto + prefix: g + purge_at: '0 4 * * *' + clear_at: '0 3 * * *' + clear_job_type: all + clear_images_by_default: true + cli_compatibility: false + lifetime: 604800 + gzip: true + allow_webserver_gzip: true + redis: + socket: null + password: null + database: null + server: null + port: null + memcache: + server: null + port: null + memcached: + server: null + port: null +twig: + cache: true + debug: false + auto_reload: true + autoescape: false + undefined_functions: true + undefined_filters: true + safe_functions: { } + safe_filters: { } + umask_fix: false +assets: + css_pipeline: true + css_pipeline_include_externals: true + css_pipeline_before_excludes: true + css_minify: true + css_minify_windows: false + css_rewrite: true + js_pipeline: true + js_pipeline_include_externals: true + js_pipeline_before_excludes: true + js_module_pipeline: false + js_module_pipeline_include_externals: true + js_module_pipeline_before_excludes: true + js_minify: true + enable_asset_timestamp: false + enable_asset_sri: false + collections: + jquery: 'system://assets/jquery/jquery-2.x.min.js' +errors: + display: 1 + log: false +log: + handler: file + syslog: + facility: local6 + tag: grav +debugger: + enabled: true + provider: debugbar + censored: false + shutdown: + close_connection: true + twig: true +images: + default_image_quality: 85 + cache_all: false + cache_perms: '0755' + debug: false + auto_fix_orientation: false + seofriendly: false + cls: + auto_sizes: false + aspect_ratio: false + retina_scale: '1' + defaults: + loading: auto + watermark: + image: 'system://images/watermark.png' + position_y: center + position_x: center + scale: 33 + watermark_all: false +media: + enable_media_timestamp: false + unsupported_inline_types: null + allowed_fallback_types: null + auto_metadata_exif: false + upload_limit: 8388608 +session: + enabled: true + initialize: true + timeout: 3000 + name: grav-site + uniqueness: path + secure: false + secure_https: true + httponly: true + samesite: Lax + split: true + domain: null + path: null +gpm: + releases: stable + official_gpm_only: true + method: auto + verify_peer: false +http: + method: auto + enable_proxy: true + proxy_url: null + proxy_cert_path: null + concurrent_connections: 5 + verify_peer: true + verify_host: true +accounts: + type: regular + storage: file + avatar: gravatar +flex: + cache: + index: + enabled: true + lifetime: 60 + object: + enabled: true + lifetime: 600 + render: + enabled: true + lifetime: 600 +strict_mode: + yaml_compat: true + twig_compat: true + blueprint_compat: true diff --git a/config/themes/plain.yaml b/config/themes/plain.yaml new file mode 100755 index 0000000..fdcf423 --- /dev/null +++ b/config/themes/plain.yaml @@ -0,0 +1,3 @@ +enabled: true +dropdown: + enabled: true diff --git a/config/versions.yaml b/config/versions.yaml new file mode 100755 index 0000000..a49eb06 --- /dev/null +++ b/config/versions.yaml @@ -0,0 +1,25 @@ +core: + grav: + version: 1.7.42.1 + history: + version: 1.6.31 + date: '2021-01-15 14:11:30' + 0: { version: 1.7.5, date: '2021-02-08 13:39:58' } + 1: { version: 1.7.7, date: '2021-03-04 13:20:41' } + 2: { version: 1.7.9, date: '2021-03-22 17:05:54' } + 3: { version: 1.7.10, date: '2021-04-07 08:19:14' } + 4: { version: 1.7.15, date: '2021-05-20 08:16:55' } + 5: { version: 1.7.16, date: '2021-06-04 13:32:43' } + 6: { version: 1.7.17, date: '2021-06-21 07:55:11' } + 7: { version: 1.7.18, date: '2021-08-19 07:46:49' } + 8: { version: 1.7.23, date: '2021-10-26 12:14:15' } + 9: { version: 1.7.25, date: '2021-12-11 13:23:27' } + 10: { version: 1.7.26.1, date: '2022-01-13 15:56:19' } + 11: { version: 1.7.27.1, date: '2022-01-13 15:58:17' } + 12: { version: 1.7.30, date: '2022-02-28 13:58:46' } + 13: { version: 1.7.31, date: '2022-03-15 10:23:00' } + 14: { version: 1.7.32, date: '2022-04-22 09:52:03' } + 15: { version: 1.7.33, date: '2022-05-26 10:42:44' } + 16: { version: 1.7.35, date: '2022-08-10 12:01:48' } + 17: { version: 1.7.42.1, date: '2023-06-27 13:17:25' } + schema: 1.7.0_2020-11-20_1 diff --git a/languages/en.yaml b/languages/en.yaml new file mode 100644 index 0000000..d7768ab --- /dev/null +++ b/languages/en.yaml @@ -0,0 +1,12 @@ +DANGER: + ARREST: Arrested since + PRISON: In prison since + FREE: Free since + MENACE: Menaced since +COALITION: Coalitions +MEMBER: Members under threat supported by our emergency fund +ORGA: Organisations +MEDIA: + DOWNLOAD: Download + CONNECTION: Login to access the media + LOGOUT: Log out \ No newline at end of file diff --git a/languages/fr.yaml b/languages/fr.yaml new file mode 100644 index 0000000..b39193a --- /dev/null +++ b/languages/fr.yaml @@ -0,0 +1,12 @@ +DANGER: + ARREST: Arrêté·e le + PRISON: En prison depuis + FREE: Libéré·e le + MENACE: Menacé·e depuis le +COALITION: Coalitions +MEMBER: Membres en danger appuyés par notre fonds d’urgence +ORGA: Organisations +MEDIA: + DOWNLOAD: Télécharger + CONNECTION: Connectez-vous pour accéder au média + LOGOUT: Déconnection \ No newline at end of file diff --git a/plugins/.gitkeep b/plugins/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/plugins/admin-addon-media-metadata/.gitignore b/plugins/admin-addon-media-metadata/.gitignore new file mode 100755 index 0000000..4cc3c5b --- /dev/null +++ b/plugins/admin-addon-media-metadata/.gitignore @@ -0,0 +1,2 @@ +.DS_Store +.php_cs.cache diff --git a/plugins/admin-addon-media-metadata/.php_cs b/plugins/admin-addon-media-metadata/.php_cs new file mode 100755 index 0000000..1f79713 --- /dev/null +++ b/plugins/admin-addon-media-metadata/.php_cs @@ -0,0 +1,83 @@ +exclude('vendor/') + ->in(__DIR__); + +// Return a Code Sniffing configuration using +// all sniffers needed for PSR-2 +// and additionally: +// - Remove leading slashes in use clauses. +// - PHP single-line arrays should not have trailing comma. +// - Single-line whitespace before closing semicolon are prohibited. +// - Remove unused use statements in the PHP source code +// - Ensure Concatenation to have at least one whitespace around +// - Remove trailing whitespace at the end of blank lines. +return PhpCsFixer\Config::create() + ->setRiskyAllowed(true) + ->setRules([ + '@PSR2' => true, + 'align_multiline_comment' => [ + 'comment_type' => 'all_multiline', + ], + 'array_syntax' => [ + 'syntax' => 'short' + ], + 'binary_operator_spaces' => [ + 'default' => 'single_space' + ], + 'concat_space' => [ + 'spacing' => 'one' + ], + 'function_typehint_space' => true, + 'hash_to_slash_comment' => true, + 'lowercase_cast' => true, + 'native_function_casing' => true, + 'no_alias_functions' => true, + 'no_blank_lines_after_phpdoc' => true, + 'no_empty_statement' => true, + 'no_extra_consecutive_blank_lines' => true, + 'no_leading_import_slash' => true, + 'no_leading_namespace_whitespace' => true, + 'no_trailing_comma_in_singleline_array' => true, + 'no_short_bool_cast' => true, + 'no_singleline_whitespace_before_semicolons' => true, + 'no_unused_imports' => true, + 'no_unneeded_control_parentheses' => true, + 'no_whitespace_in_blank_line' => true, + 'ordered_imports' => true, + 'phpdoc_no_empty_return' => true, + 'phpdoc_no_package' => false, + 'phpdoc_scalar' => true, + 'phpdoc_trim' => true, + 'return_type_declaration' => [ + 'space_before' => 'none' + ], + 'self_accessor' => true, + 'single_quote' => true, + 'standardize_not_equals' => true, + 'whitespace_after_comma_in_array' => true, + ]) + ->setFinder($finder); diff --git a/plugins/admin-addon-media-metadata/CHANGELOG.md b/plugins/admin-addon-media-metadata/CHANGELOG.md new file mode 100755 index 0000000..b3b46e7 --- /dev/null +++ b/plugins/admin-addon-media-metadata/CHANGELOG.md @@ -0,0 +1,37 @@ +# v.1.1.0 +## 05-06-2020 + +1. [](#new) + * Page specific media metadata fields can be added to a page’s frontmatter (see README --> Configuration) +2. [](#improved) + * meta.yaml file will not be created upon upload anymore: this allows the creation of the file with the setting media.auto_metadata_exif turned on (in Admin Plugin 1.9); in Admin Plugin 1.10 it did not work anyway – **NOTE: in Admin Plugin 1.10 with setting media.auto_metadata_exif turned on, make sure to save the page with a newly uploaded image before adding other metadata using this plugin** + +# v1.0.2 +## 16-04-2020 + +1. [](#improved) + * The button next to a media file will now also be translated. It was hard-coded to English before. + +# v1.0.1 +## 10-04-2020 + +1. [](#bugfix) + * meta.yaml file will now be created for an already uploaded media file that did not have an associated meta.yaml file before + +# v1.0.0 +## 20-03-2020 + +1. [](#improved) + * using core technology (Grav\Common\Yaml) for parsing and writing the meta.yaml files – kudos to https://github.com/renards for adding crucial parts to the code + +# v0.9.1 +## 16-03-2020 + +1. [](#bugfix) + * adding /vendor/ and composer.lock, needed for composer autoload functionality + +# v0.9.0 +## 15-03-2020 + +1. [](#new) + * Initial release \ No newline at end of file diff --git a/plugins/admin-addon-media-metadata/LICENSE b/plugins/admin-addon-media-metadata/LICENSE new file mode 100755 index 0000000..3287767 --- /dev/null +++ b/plugins/admin-addon-media-metadata/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2020 Clive Beckett + +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/plugins/admin-addon-media-metadata/README.md b/plugins/admin-addon-media-metadata/README.md new file mode 100755 index 0000000..0838884 --- /dev/null +++ b/plugins/admin-addon-media-metadata/README.md @@ -0,0 +1,90 @@ +# Admin Addon Media Metadata Plugin + +The **Admin Addon Media Metadata** Plugin is an extension for the [Grav CMS](http://github.com/getgrav/grav) [Admin plugin](https://github.com/getgrav/grav-plugin-admin). It lets you add and **edit metadata for media files** in the Page Media browser. + +The Admin plugin has not been offering a feature like this yet. In order to add/edit metadata e.g. for an image you had to create a [image.filename].meta.yaml for the image in your file browser and edit it in a text editor. + +## Usage and Features + +- the plugin will create and edit [mediafile].meta.yaml files in your page folder via a simple form in the Admin plugin +- by default you can add/edit a **title,** **alt** text, and a **caption** – see *Configuration* section below on how to adapt this for your Grav installation +- multiline text can be added (e.g. for caption) +- in case you are storing additional, manually added data in your [mediafile].meta.yaml file, it will not be overwritten even if the form does not let you change it + +### How to use it + +*(see also screenshots below)* + +1. hover any file in your Page Media section +2. hit the small «i» button to open the metadata form *(the regular «i» button which just showed the metadata will be overwritten by the plugin)* + +### NOTE on setting “Auto metadata from Exif” + +If your system is set to automatically write EXIF metadata +`(system.yaml → media.auto_metadata_exif: true)` + +- On **Admin Plugin 1.10:** +Please **save the page** after uploading an image and **before** you write additional metadata using this plugin. On saving the page, the Admin Plugin will create the meta.yaml file including the EXIF data – but it won’t do so if a meta.yaml file already exists. +- On **Admin Plugin 1.9** and **admin-addon-media-metadata >= 1.1.0:** +There’s no problem here: the EXIF data will be written immediately upon upload whereas this plugin now only writes or edits meta.yaml files when needed. + +## Installation + +### Grav Package Manager (GPM) + +If you can access your Grav installation via the command line, install the plugin by typing the following from your Grav root: + +``` +bin/gpm install admin-addon-media-metadata +``` + +### Admin Tool Web Interface + +In the **Plugins** section, hit the **[+ Add]** button, search for Admin Addon Media Metadata and install. + +### Manual Installation + +To install the plugin manually, download the ZIP version of the latest release of this repository and unzip it under `/your/site/grav/user/plugins`. Then rename the folder to `admin-addon-media-metadata`. You can find these files on [GitHub](https://github.com/clivebeckett/grav-plugin-admin-addon-media-metadata/releases). + +## Configuration + +The default fields in the metadata form are alt, title, and caption. If you want to add more data to your meta.yaml files, please copy +`user/plugins/admin-addon-media-metadata/admin-addon-media-metadata.yaml` to +`user/config/plugins/admin-addon-media-metadata.yaml` +and add more form fields to the form by updating the copy. E.g. if you want to add a field for a web link, you might add the following lines: + +``` + - type: text + label: Web link + name: weblink + placeholder: https://domain.tld/ +``` + +The URL field will be available in your metadata form and you’ll be able edit the information. + +### Additional Page Specific Metadata Fields (v1.1 and later) + +You may also add page specific fields to a page’s frontmatter. *Note: The fields will be added to the form, not override the ones from the above mentioned config files:* + +``` +admin-addon-media-metadata: + metadata_form: + fields: + - + type: text + label: 'Yet another field' + name: yetAnotherField + placeholder: 'yet yet yet' +``` + +## Credits + +I have based the plugin on Dávid Szabó’s [Admin Addon Media Rename plugin](https://github.com/david-szabo97/grav-plugin-admin-addon-media-rename). Much of the code would not have been possible for me without Dávid’s work. + +[@renards](https://github.com/renards) helped a lot in replacing my original self-written Yaml parsing and writing code with Grav core technology and thus made version 1.0.0 possible. + +## Screenshots + +![](assets/1-open-form.jpg) + +![](assets/2-form-opened.jpg) diff --git a/plugins/admin-addon-media-metadata/admin-addon-media-metadata.css b/plugins/admin-addon-media-metadata/admin-addon-media-metadata.css new file mode 100755 index 0000000..ba13c87 --- /dev/null +++ b/plugins/admin-addon-media-metadata/admin-addon-media-metadata.css @@ -0,0 +1,40 @@ +span[data-dz-name] { + cursor: text; +} + +.dz-metadata-edit { + display: none; + position: absolute; + width: 25px; + height: 25px; + right: -26px; + font-size: 0; + cursor: pointer; + background: #ededed; +/* bottom: 25px; */ + top: 49px; +} + +.dz-metadata-edit:after { + text-align: center; + display: block; + font-family: FontAwesome; + font-size: 18px; + line-height: 25px; +/* content: "\f044"; */ + content: "\f05a"; + color: #737c81; +} + +.dz-metadata-edit:hover:after { + color: #0082ba; +} + +.dropzone .dz-preview:hover .dz-metadata-edit { + display: block; +} + +div.form-label { padding-right: 1rem; } +[data-remodal-id=modal-admin-addon-media-metadata] h1 { line-height: 1; } +form h1 span.header { } +form h1 span.filename { font-size: 1rem; } diff --git a/plugins/admin-addon-media-metadata/admin-addon-media-metadata.js b/plugins/admin-addon-media-metadata/admin-addon-media-metadata.js new file mode 100755 index 0000000..e366125 --- /dev/null +++ b/plugins/admin-addon-media-metadata/admin-addon-media-metadata.js @@ -0,0 +1,113 @@ +/** + * some of the code is based on the Admin Addon Media Rename by Dávid Szabó + * see https://github.com/david-szabo97/grav-plugin-admin-addon-media-rename + */ +$(function() { + + adminAddonMediaMetadata.metadata = {}; + + var clickedElement; + var fileName; + var $elementName; + var modal; + var $modal; + var isPageMedia = false; + + // Append modal + $('body').append(adminAddonMediaMetadata.MODAL); + + $(document).off('click', '[data-dz-name], .dz-metadata-edit'); + $(document).on('click', '[data-dz-name], .dz-metadata-edit', function(e) { + clickedElement = $(this); + modal = $.remodal.lookup[$('[data-remodal-id=modal-admin-addon-media-metadata]').data('remodal')]; + $modal = modal.$modal; + modal.open(); + + // Populate fields + elementName = clickedElement.closest('.dz-preview').find('[data-dz-name]') + fileName = elementName.text(); + $('[name=filename]', $modal).val(fileName); + if (mediaListOnLoad[fileName] !== undefined) { + for (var i = 0; i < metadataFormFields.length; i++) { + $('[name=' + metadataFormFields[i] + ']', $modal).val(mediaListOnLoad[fileName][metadataFormFields[i]]); + } + } else { + for (var i = 0; i < metadataFormFields.length; i++) { + $('[name=' + metadataFormFields[i] + ']', $modal).val(''); + } + } + $modal.find('form span.filename').text(fileName); + + // Reset loading state + $('.loading', $modal).addClass('hidden'); +// $('.button', $modal).removeClass('hidden').css('visibility', 'hidden'); + $('.button', $modal).removeClass('hidden'); + + isPageMedia = !clickedElement.closest('.dz-preview').hasClass('dz-no-editor'); + $modal.find('.block-toggle').toggleClass('hidden', !isPageMedia); + $modal.find('.page-media-info').toggleClass('hidden', !isPageMedia); + $modal.find('.non-page-media-info').toggleClass('hidden', isPageMedia); + }); + + /** + * add the new data dynamically to mediaListOnLoad JSON object + * for newly uploaded media files as well as for “older” files, overwriting the data already in that JSON object + * and save it in the YAML file + * Variables from above ($(document).on), like fileName and $modal are still available + */ + $(document).on('click', '[data-remodal-id=modal-admin-addon-media-metadata] .button', function(e) { + // hiding the button and showing the loading icon + $('.loading', $modal).removeClass('hidden'); + $('.button', $modal).addClass('hidden'); + + // create the file object for newly uploaded files + if (mediaListOnLoad[fileName] === undefined) { + mediaListOnLoad[fileName] = new Object(); + mediaListOnLoad[fileName]['filename'] = fileName; + } + + // Do request with JS Fetch API: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch + var data = new FormData(); + data.append('filename', fileName); + data.append('admin-nonce', GravAdmin.config.admin_nonce); + + // add the new values to mediaListOnLoad (for later updates before page reload) + // append the new values to the FormData (data.append) + for (var i = 0; i < metadataFormFields.length; i++) { + var newVal = $('[name=' + metadataFormFields[i] + ']', $modal).val(); + mediaListOnLoad[fileName][metadataFormFields[i]] = newVal; + data.append(metadataFormFields[i], newVal); + } + + fetch(adminAddonMediaMetadata.PATH, { method: 'POST', body: data, credentials: 'same-origin' }) + //.then(res => res.json()) + .then(result => { + if (result.error) { + var alertModal = $.remodal.lookup[$('[data-remodal-id=modal-admin-addon-media-metadata-alert]').data('remodal')]; + alertModal.open(); + $('p', alertModal.$modal).html(result.error.msg); + return; + } + + modal.close(); + }); + }); + + // adding the “edit metadata” button next to all media files + setInterval(function addMetadataButton() { + $('.dz-preview').each(function(i, dz) { + if ($(this).find('.dz-metadata-edit').length == 0) { + var editButton = document.createElement('a'); + //editButton.href = 'javascript:undefined;'; + editButton.title = adminAddonMediaMetadataButton; + editButton.className = 'dz-metadata-edit'; + editButton.innerText = adminAddonMediaMetadataButton; + var fileName = $(this).find('[data-dz-name]').text(); + editButton.setAttribute('data-filename', fileName); + $(this).append(editButton); + } + $(this).find('.dz-metadata').remove(); + }); + }, 1000); +}); + diff --git a/plugins/admin-addon-media-metadata/admin-addon-media-metadata.php b/plugins/admin-addon-media-metadata/admin-addon-media-metadata.php new file mode 100755 index 0000000..3ab5a45 --- /dev/null +++ b/plugins/admin-addon-media-metadata/admin-addon-media-metadata.php @@ -0,0 +1,321 @@ +=1.7 + 'onPluginsInitialized' => ['onPluginsInitialized', 0] + ]; + } + + /** + * Composer autoload. + * is + * @return ClassLoader + */ + public function autoload(): ClassLoader + { + return require __DIR__ . '/vendor/autoload.php'; + } + + public function getPath() + { + return '/' . trim($this->grav['admin']->base, '/') . '/' . trim(self::ROUTE, '/'); + } + + public function buildBaseUrl() + { + return rtrim($this->grav['uri']->rootUrl(true), '/') . '/' . trim($this->getPath(), '/'); + } + + /** + * Initialize the plugin + */ + public function onPluginsInitialized() + { + if (!$this->isAdmin() || !$this->grav['user']->authenticated) { + return; + } + + if ($this->grav['uri']->path() == $this->getPath()) { + $this->enable([ + 'onPagesInitialized' => ['processRenameRequest', 0] + ]); + return; + } + + $this->enable([ + 'onTwigTemplatePaths' => ['onTwigTemplatePaths', 0], + 'onPagesInitialized' => ['onTwigExtensions', 0], + //'onAdminAfterAddMedia' => ['createMetaYaml', 0], // removing the call of this method: see method below + 'onAdminTaskExecute' => ['editMetaDataFile', 0], + ]); + } + + public function onTwigTemplatePaths() + { + $this->grav['twig']->twig_paths[] = __DIR__ . '/templates'; + } + + public function onTwigExtensions() + { + $page = $this->grav['admin']->page(true); + if (!$page) { + return; + } + + /** + * get metadata form field config from plugin admin-addon-media-metadata.yaml file + * or local override in user/config/plugins/admin-addon-media-metadata.yaml + * or from page frontmatter + */ + //$formFields = $this->config->get('plugins.admin-addon-media-metadata.metadata_form'); + $config = $this->mergeConfig($page, true); + $formFields = $config->get('metadata_form'); + + /** + * list all needed data keys from the fields configuration + */ + $arrMetaKeys = $this->editableFields($formFields['fields']); + + $path = $page->path(); + $media = new Media($path); + $allMedia = $media->all(); + $arrFiles = []; + $i = 0; + foreach ($allMedia as $filename => $file) { + $metadata = $file->meta(); + $arrFiles[$filename] = [ + 'filename' => $filename, + ]; + /** + * for each file: write stored metadata for each editable field into an array + * this will be output as inline JS variable adminAddonMediaMetadata + */ + foreach ($arrMetaKeys as $metaKey => $info) { + $arrFiles[$filename][$metaKey] = $metadata->$metaKey; + } + $i++; + } + + $jsArrFormFields = ''; + $i = 0; + foreach ($arrMetaKeys as $metaKey => $info) { + $jsArrFormFields .= ($i > 0) ? ",'" . $metaKey . "'" : "'" . $metaKey . "'"; + $i++; + } + + $inlineJs = 'var metadataFormFields = [' . $jsArrFormFields . '];'; + $inlineJs .= PHP_EOL . 'var mediaListOnLoad = ' . json_encode($arrFiles) . ';'; + $modal = $this->grav['twig']->twig()->render('metadata-modal.html.twig', $formFields); + $jsConfig = [ + 'PATH' => $this->buildBaseUrl() . '/' . $page->route() . '/task:' . self::TASK_METADATA, + 'MODAL' => $modal + ]; + $inlineJs .= PHP_EOL . 'var adminAddonMediaMetadata = ' . json_encode($jsConfig) . ';'; + $inlineJs .= PHP_EOL . $this->grav['twig']->twig()->render('additionalInlineJS.html.twig'); + $this->grav['assets']->addInlineJs($inlineJs, -1000); + $this->grav['assets']->addCss('plugin://admin-addon-media-metadata/admin-addon-media-metadata.css', -1000); + $this->grav['assets']->addJs('plugin://admin-addon-media-metadata/admin-addon-media-metadata.js', -1000); + } + + public function editTest() + { + $this->outputError('blob'); + } + + /** + * writes metadata into the [mediafile].meta.yaml file + * creates the .meta.yaml file if it does not yet exist + */ + public function editMetaDataFile($e) + { + $method = $e['method']; + if ($method === 'task' . self::TASK_METADATA) { + $fileName = $_POST['filename']; + + $pageObj = $this->grav['admin']->page(); + $basePath = $pageObj->path() . DS; + + $filePath = $basePath . $fileName; + +/** + * temporarily removing the condition that checks for the media file to exist + * as in Admin plugin 1.10 a media file will be uploaded to a tmp folder first + * and moved to the page folder on saving the page + * + * there needs to be a better solution for this + * + * also: take care of system.yaml → media.auto_metadata_exif + * if set to TRUE, a meta.yaml with EXIF data will be written, but only if the meta.yaml does not yet exist + * in Admin 1.10 you need to save a page in order to have the meta.yaml file with EXIF data created + * in Admin 1.9 this is not a problem since this plugin now (>=1.1.0) writes metadata only when needed + */ +// if (!file_exists($filePath)) { +// $this->outputError($this->grav['language']->translate(['PLUGIN_ADMIN_ADDON_MEDIA_METADATA.ERRORS.MEDIA_FILE_NOT_FOUND', $filePath])); +// } else { + $metaDataFilePath = $filePath . '.meta.yaml'; + + /** + * get the list of form data from the fields configuration + */ + $arrMetaKeys = $this->editableFields(); + + if (file_exists($metaDataFilePath)) { + /** + * get array of all current metadata for the file + * this is to avoid overwriting data that has been added to the meta.yaml file in the file browser + */ + $storedMetaData = Yaml::parse(file_get_contents($metaDataFilePath)); + + /** + * overwrite the currently stored data for each field in the form + */ + foreach ($arrMetaKeys as $metaKey => $info) { + if (isset($_POST[$metaKey])) { + $storedMetaData[$metaKey] = $_POST[$metaKey]; + } + } + + } else { + /** + * create metaData in case the meta data file does not yet exist + */ + $storedMetaData = []; + foreach ($arrMetaKeys as $metaKey => $info) { + if (isset($_POST[$metaKey])) { + $storedMetaData[$metaKey] = $_POST[$metaKey]; + } else { + $storedMetaData[$metaKey] = ''; + } + } + } + + /** + * Get an instance of the meta file and write the data to it + * @see \Grav\Common\Page\Media + */ + $metaDataFile = File::instance($metaDataFilePath); + $metaDataFile->save(Yaml::dump($storedMetaData)); + + //$this->outputError($newYamlText); +// } + } + } + +/** + * this method will not be called in Admin Plugin v1.10 (up until rc.11 anyway) + * additionally, writing the YAML file on upload will meddle with the system functionality + * that writes exif data + * in Admin Plugin v1.9 this functionality writes the meta.yaml file + * on upload, this plugin will then just add the other metadata + * when writing the meta.yaml file upon upload the system functionality will be overwritten + * in Admin Plugin v1.10 you need to save the page before using this plugin on a file + * if you want the exif data to be stored + */ + /** + * creates an image.meta.yaml file + * this file will be deleted by the core when deleting an image + * will be called after a media file has been added (see onPluginsInitialized()) + */ +// public function createMetaYaml() +// { +// $fileName = $_FILES['file']['name']; +// +// $pageObj = $this->grav['admin']->page(); +// $basePath = $pageObj->path() . DS; +// +// $filePath = $basePath . $fileName; +// if (!file_exists($filePath)) { +// $this->outputError($this->grav['language']->translate(['PLUGIN_ADMIN_ADDON_MEDIA_METADATA.ERRORS.MEDIA_FILE_NOT_FOUND', $filePath])); +// } else { +// // TODO: do that only for image files? +// $metaDataFileName = $fileName . '.meta.yaml'; +// $metaDataFilePath = $basePath . $metaDataFileName; +// if (!file_exists($metaDataFilePath)) { +// /** +// * get the list of form data from the fields configuration +// */ +// $arrMetaKeys = $this->editableFields(); +// +// $newMetaData = []; +// foreach ($arrMetaKeys as $metaKey => $info) { +// $newMetaData[$metaKey] = ''; +// } +// +// /** +// * Get an instance of the meta file and write the data to it +// * @see \Grav\Common\Page\Media +// */ +// $metaDataFile = File::instance($metaDataFilePath); +// $metaDataFile->save(Yaml::dump($newMetaData)); +// } +// } +// } + + /** + * return all editable fields from form configuration + */ + private function editableFields($fieldsConf = null) + { + if ($fieldsConf === null) { + $page = $this->grav['admin']->page(true); + if (!$page) { + return; + } + /** + * get metadata form field config from plugin admin-addon-media-metadata.yaml file + * or local override in user/config/plugins/admin-addon-media-metadata.yaml + * or from page frontmatter + */ + //$formFields = $this->config->get('plugins.admin-addon-media-metadata.metadata_form'); + $config = $this->mergeConfig($page, true); + $formFields = $config->get('metadata_form'); + $fieldsConf = $formFields['fields']; + } + $arrMetaKeys = []; + foreach ($fieldsConf as $singleFieldConf) { + if (isset($singleFieldConf['name'], $singleFieldConf['type']) && $singleFieldConf['name'] !== 'filename') { + $arrMetaKeys[$singleFieldConf['name']] = [ + 'name' => $singleFieldConf['name'], + 'type' => $singleFieldConf['type'] + ]; + } + } + return $arrMetaKeys; + } + + public function outputError($msg) + { + header('HTTP/1.1 400 Bad Request'); + die(json_encode(['error' => ['msg' => $msg]])); + } +} diff --git a/plugins/admin-addon-media-metadata/admin-addon-media-metadata.yaml b/plugins/admin-addon-media-metadata/admin-addon-media-metadata.yaml new file mode 100755 index 0000000..ae296fe --- /dev/null +++ b/plugins/admin-addon-media-metadata/admin-addon-media-metadata.yaml @@ -0,0 +1,21 @@ +enabled: true + +metadata_form: + fields: + - type: hidden + title: PLUGIN_ADMIN_ADDON_MEDIA_METADATA.FILENAME + name: filename + readonly: true + + - type: text + label: PLUGIN_ADMIN_ADDON_MEDIA_METADATA.TITLE + name: title + + - type: text + label: PLUGIN_ADMIN_ADDON_MEDIA_METADATA.ALT + name: alt + + - type: textarea + label: PLUGIN_ADMIN_ADDON_MEDIA_METADATA.CAPTION + name: caption + rows: 3 diff --git a/plugins/admin-addon-media-metadata/assets/1-open-form.jpg b/plugins/admin-addon-media-metadata/assets/1-open-form.jpg new file mode 100755 index 0000000000000000000000000000000000000000..1daff1aa8a1bb9dbca1c319152fd7ec4781666db GIT binary patch literal 86765 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 literal 0 HcmV?d00001 diff --git a/plugins/admin-addon-media-metadata/assets/2-form-opened.jpg b/plugins/admin-addon-media-metadata/assets/2-form-opened.jpg new file mode 100755 index 0000000000000000000000000000000000000000..a547686764a86c150234df4c4cf7d4d5e9da5a34 GIT binary patch literal 45622 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 WE-gxtekSWsdi~#WBa`sH|Nj9Vh1)3r literal 0 HcmV?d00001 diff --git a/plugins/admin-addon-media-metadata/blueprints.yaml b/plugins/admin-addon-media-metadata/blueprints.yaml new file mode 100755 index 0000000..14b9eb3 --- /dev/null +++ b/plugins/admin-addon-media-metadata/blueprints.yaml @@ -0,0 +1,30 @@ +name: Admin Addon Media Metadata +version: 1.1.0 +description: 'This plugin is an addon for the Grav CMS Admin plugin and lets you add and edit metadata for media files' +icon: plug +author: + name: Clive Beckett + email: clive@musikinsnetz.de +homepage: https://github.com/clivebeckett/grav-plugin-admin-addon-media-metadata +keywords: grav, admin, plugin, metadata, image, alt, title, caption +bugs: https://github.com/clivebeckett/grav-plugin-admin-addon-media-metadata/issues +docs: https://github.com/clivebeckett/grav-plugin-admin-addon-media-metadata/blob/develop/README.md +license: MIT + +dependencies: + - { name: grav, version: '1.5 - 1.7' } + - { name: admin, version: '1.8 - 1.10' } + +form: + validation: loose + fields: + enabled: + type: toggle + label: PLUGIN_ADMIN.PLUGIN_STATUS + highlight: 1 + default: 0 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool diff --git a/plugins/admin-addon-media-metadata/composer.json b/plugins/admin-addon-media-metadata/composer.json new file mode 100755 index 0000000..92d3755 --- /dev/null +++ b/plugins/admin-addon-media-metadata/composer.json @@ -0,0 +1,29 @@ +{ + "name": "clivebeckett/admin-addon-media-metadata", + "type": "grav-plugin", + "description": "Add Metadata (title, alt, caption) to image files in admin plugin", + "keywords": ["plugin"], + "homepage": "https://github.com/clivebeckett/grav-plugin-admin-addon-media-metadata", + "license": "MIT", + "authors": [ + { + "name": "Clive Beckett", + "email": "clive@musikinsnetz.de", + "role": "Developer" + } + ], + "require": { + "php": ">=7.1.3" + }, + "autoload": { + "psr-4": { + "Grav\\Plugin\\AdminAddonMediaMetadata\\": "classes/" + }, + "classmap": ["admin-addon-media-metadata.php"] + }, + "config": { + "platform": { + "php": "7.1.3" + } + } +} \ No newline at end of file diff --git a/plugins/admin-addon-media-metadata/composer.lock b/plugins/admin-addon-media-metadata/composer.lock new file mode 100755 index 0000000..7724b63 --- /dev/null +++ b/plugins/admin-addon-media-metadata/composer.lock @@ -0,0 +1,23 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "b884fad27830ca91d1b5af86da9aff06", + "packages": [], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.1.3" + }, + "platform-dev": [], + "platform-overrides": { + "php": "7.1.3" + }, + "plugin-api-version": "1.1.0" +} diff --git a/plugins/admin-addon-media-metadata/languages/de.yaml b/plugins/admin-addon-media-metadata/languages/de.yaml new file mode 100755 index 0000000..0dfd7c0 --- /dev/null +++ b/plugins/admin-addon-media-metadata/languages/de.yaml @@ -0,0 +1,11 @@ +PLUGIN_ADMIN_ADDON_MEDIA_METADATA: + BUTTON: Metadaten ändern + FORM_HEADER: Metadaten für Mediendatei ändern + FILENAME: Dateiname + TITLE: Titel + ALT: Beschreibung für den Fall, dass die Datei nicht angezeigt werden kann (alternativer Text) + CAPTION: Bildunterschrift + WRITING_DATA: Metadaten werden geschrieben + WRITING_FAILED: Metadaten konnten nicht geschrieben werden + ERRORS: + MEDIA_FILE_NOT_FOUND: Die Mediendatei konnte nicht gefunden werden diff --git a/plugins/admin-addon-media-metadata/languages/en.yaml b/plugins/admin-addon-media-metadata/languages/en.yaml new file mode 100755 index 0000000..ebcc018 --- /dev/null +++ b/plugins/admin-addon-media-metadata/languages/en.yaml @@ -0,0 +1,11 @@ +PLUGIN_ADMIN_ADDON_MEDIA_METADATA: + BUTTON: Edit metadata + FORM_HEADER: Edit metadata for media file + FILENAME: Filename + TITLE: Title + ALT: Describe the media file for when it can’t be displayed (alternative text) + CAPTION: Caption + WRITING_DATA: Writing metadata + WRITING_FAILED: Writing image metadata failed + ERRORS: + MEDIA_FILE_NOT_FOUND: The media file could not be found diff --git a/plugins/admin-addon-media-metadata/languages/fr.yaml b/plugins/admin-addon-media-metadata/languages/fr.yaml new file mode 100755 index 0000000..3483c29 --- /dev/null +++ b/plugins/admin-addon-media-metadata/languages/fr.yaml @@ -0,0 +1,11 @@ +PLUGIN_ADMIN_ADDON_MEDIA_METADATA: + BUTTON: Editer les métadonnées pour ce média + FORM_HEADER: Editer les métadonnées pour ce média + FILENAME: Nom du fichier + TITLE: Titre + ALT: Description du média lorsqu'il ne peut être affiché (texte alternatif) + CAPTION: Légende + WRITING_DATA: Ajout des métadonnées + WRITING_FAILED: Impossible d'ajouter les métadonnées + ERRORS: + MEDIA_FILE_NOT_FOUND: Le fichier du média ne peut être trouvé diff --git a/plugins/admin-addon-media-metadata/templates/additionalInlineJS.html.twig b/plugins/admin-addon-media-metadata/templates/additionalInlineJS.html.twig new file mode 100755 index 0000000..b6a39f0 --- /dev/null +++ b/plugins/admin-addon-media-metadata/templates/additionalInlineJS.html.twig @@ -0,0 +1,2 @@ +var adminAddonMediaMetadataButton = '{{ 'PLUGIN_ADMIN_ADDON_MEDIA_METADATA.BUTTON'|t }}'; +var adminAddonMediaMetadataLang = '{{ grav.user.language|default('en') }}'; \ No newline at end of file diff --git a/plugins/admin-addon-media-metadata/templates/metadata-modal.html.twig b/plugins/admin-addon-media-metadata/templates/metadata-modal.html.twig new file mode 100755 index 0000000..0d71cc3 --- /dev/null +++ b/plugins/admin-addon-media-metadata/templates/metadata-modal.html.twig @@ -0,0 +1,36 @@ +
+
+
+

+ {{ "PLUGIN_ADMIN_ADDON_MEDIA_METADATA.FORM_HEADER"|t }}
+ +

+
+ {% for field in fields %} + {% if field.type %} + {% set value = data.value(field.name) %} +
+ {% include ["forms/fields/#{field.type}/#{field.type}.html.twig", 'forms/fields/text/text.html.twig'] %} +
+ {% endif %} + {% endfor %} + +
+
+ {{ "PLUGIN_ADMIN_ADDON_MEDIA_METADATA.WRITING_DATA"|t }} … +
+ + +
+
+
+ +
+
+

{{ "PLUGIN_ADMIN_ADDON_MEDIA_METADATA.WRITING_FAILED"|t }}

+

+
+ +
+
+
\ No newline at end of file diff --git a/plugins/admin-addon-media-metadata/vendor/autoload.php b/plugins/admin-addon-media-metadata/vendor/autoload.php new file mode 100755 index 0000000..fe8182c --- /dev/null +++ b/plugins/admin-addon-media-metadata/vendor/autoload.php @@ -0,0 +1,7 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see http://www.php-fig.org/psr/psr-0/ + * @see http://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + + private $useIncludePath = false; + private $classMap = array(); + private $classMapAuthoritative = false; + private $missingClasses = array(); + private $apcuPrefix; + + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', $this->prefixesPsr0); + } + + return array(); + } + + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return bool|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; +} diff --git a/plugins/admin-addon-media-metadata/vendor/composer/LICENSE b/plugins/admin-addon-media-metadata/vendor/composer/LICENSE new file mode 100755 index 0000000..f27399a --- /dev/null +++ b/plugins/admin-addon-media-metadata/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/plugins/admin-addon-media-metadata/vendor/composer/autoload_classmap.php b/plugins/admin-addon-media-metadata/vendor/composer/autoload_classmap.php new file mode 100755 index 0000000..2147962 --- /dev/null +++ b/plugins/admin-addon-media-metadata/vendor/composer/autoload_classmap.php @@ -0,0 +1,10 @@ + $baseDir . '/admin-addon-media-metadata.php', +); diff --git a/plugins/admin-addon-media-metadata/vendor/composer/autoload_namespaces.php b/plugins/admin-addon-media-metadata/vendor/composer/autoload_namespaces.php new file mode 100755 index 0000000..b7fc012 --- /dev/null +++ b/plugins/admin-addon-media-metadata/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($baseDir . '/classes'), +); diff --git a/plugins/admin-addon-media-metadata/vendor/composer/autoload_real.php b/plugins/admin-addon-media-metadata/vendor/composer/autoload_real.php new file mode 100755 index 0000000..de09f1e --- /dev/null +++ b/plugins/admin-addon-media-metadata/vendor/composer/autoload_real.php @@ -0,0 +1,55 @@ += 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); + if ($useStaticLoader) { + require_once __DIR__ . '/autoload_static.php'; + + call_user_func(\Composer\Autoload\ComposerStaticInit487bda5860f2ea416ef2181e18c0fcbf::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + } + + $loader->register(true); + + return $loader; + } +} diff --git a/plugins/admin-addon-media-metadata/vendor/composer/autoload_static.php b/plugins/admin-addon-media-metadata/vendor/composer/autoload_static.php new file mode 100755 index 0000000..31d4532 --- /dev/null +++ b/plugins/admin-addon-media-metadata/vendor/composer/autoload_static.php @@ -0,0 +1,36 @@ + + array ( + 'Grav\\Plugin\\AdminAddonMediaMetadata\\' => 36, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Grav\\Plugin\\AdminAddonMediaMetadata\\' => + array ( + 0 => __DIR__ . '/../..' . '/classes', + ), + ); + + public static $classMap = array ( + 'Grav\\Plugin\\AdminAddonMediaMetadataPlugin' => __DIR__ . '/../..' . '/admin-addon-media-metadata.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInit487bda5860f2ea416ef2181e18c0fcbf::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit487bda5860f2ea416ef2181e18c0fcbf::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInit487bda5860f2ea416ef2181e18c0fcbf::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/plugins/admin-addon-media-metadata/vendor/composer/installed.json b/plugins/admin-addon-media-metadata/vendor/composer/installed.json new file mode 100755 index 0000000..fe51488 --- /dev/null +++ b/plugins/admin-addon-media-metadata/vendor/composer/installed.json @@ -0,0 +1 @@ +[] diff --git a/plugins/admin/.editorconfig b/plugins/admin/.editorconfig new file mode 100644 index 0000000..6375a81 --- /dev/null +++ b/plugins/admin/.editorconfig @@ -0,0 +1,17 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +charset = utf-8 +end_of_line = lf +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space +indent_size = 2 + +# 4 space indentation +[*.php] +indent_size = 4 diff --git a/plugins/admin/.gitattributes b/plugins/admin/.gitattributes new file mode 100644 index 0000000..c5ef731 --- /dev/null +++ b/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/plugins/admin/.github/FUNDING.yml b/plugins/admin/.github/FUNDING.yml new file mode 100644 index 0000000..e84f52b --- /dev/null +++ b/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/plugins/admin/.github/dependabot.yml b/plugins/admin/.github/dependabot.yml new file mode 100644 index 0000000..203f3c8 --- /dev/null +++ b/plugins/admin/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: +- package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/plugins/admin/.gitignore b/plugins/admin/.gitignore new file mode 100644 index 0000000..ddab4e4 --- /dev/null +++ b/plugins/admin/.gitignore @@ -0,0 +1,17 @@ +themes/grav/.sass-cache +.DS_Store +crowdin.yaml + +# Node Modules +**/node_modules/** +themes/grav/js/admin.js +themes/grav/js/vendor.js +themes/grav/js/*.map +.idea + +tests/_output/* +tests/_support/_generated/* +tests/cache/* +tests/error.log +/crowdin.yaml +.vscode diff --git a/plugins/admin/CHANGELOG.md b/plugins/admin/CHANGELOG.md new file mode 100644 index 0000000..a7e2136 --- /dev/null +++ b/plugins/admin/CHANGELOG.md @@ -0,0 +1,2625 @@ +# v1.10.42 +## 06/14/2023 + +1. [](#new) + * Added a couple of string translations + +# v1.10.41.2 +## 05/11/2023 + +1. [](#improved) + * Fixed an issue with `lastBackup()` that caused admin dashboard to fail with an error. + +# v1.10.41.1 +## 05/09/2023 + +1. [](#improved) + * Fixed another Toolbox deprecation error for `lastBackup()` + +# v1.10.41 +## 05/09/2023 + +1. [](#new) + * Updated to use new `BaconQRCode` version `2.0.8` for new SVG features + PHP 8.2+ fixes +1. [](#improved) + * Require Grav `v1.7.41` + * Fixed a deprecated message where `Admin::$routes` was being dynamically defined + * Fixes to use non-deprecated methods in `ScssCompiler` + +# v1.10.40 +## 03/22/2023 + +1. [](#new) + * Added Github actions for dependabot [#2258](https://github.com/getgrav/grav-plugin-admin/pull/2258) +1. [](#improved) + * Syslog tag fields label added [#2296](https://github.com/getgrav/grav-plugin-admin/pull/2296) + * Updated vendor libraries to the latest versions +1. [](#bugfix) + * Fix more than one file upload [#2317](https://github.com/getgrav/grav-plugin-admin/pull/2317) + +# v1.10.39 +## 02/19/2023 + +1. [](#bugfix) + * Forked and fixed PicoFeed library to support PHP 8.2 + +# v1.10.38 +## 01/02/2023 + +1. [](#new) + * Update copyright dates + * Keep version number in sync with Grav version + +# v1.10.37.1 +## 10/08/2022 + +1. [](#bugfix) + * Removed new GumRoad cart icon + new button styling [getgrav/grav#3631](https://github.com/getgrav/grav/issues/3631) + +# v1.10.37 +## 10/05/2022 + +1. [](#improved) + * Updated vendor libraries to latest versions + * Removed a reference to `SwiftMailer` library to support new **Email** plugin v4.0 + +# v1.10.36 +## 09/08/2022 + +1. [](#bugfix) + * Fixed `fieldset.html.twig` not rendering with `markdown: false` [#2313](https://github.com/getgrav/grav-plugin-admin/pull/2313) + +# v1.10.35 +## 08/04/2022 + +1. [](#improved) + * Improvements in CodeMirror editor in RTL mode [#359](https://github.com/getgrav/grav-plugin-admin/issues/359), [#2297](https://github.com/getgrav/grav-plugin-admin/pull/2297) + +# v1.10.34 +## 06/22/2022 + +1. [](#improved) + * Exposed `UriToMarkdown` util (`Grav.default.Utils.UriToMarkdown`) in admin, to convert links/images +1. [](#bugfix) + * Fixed `Latest Page Updates` permissions [#2294](https://github.com/getgrav/grav-plugin-admin/pull/2294) + +# v1.10.33.1 +## 04/25/2022 + +1. [](#bugfix) + * Reverted [PR#2265](https://github.com/getgrav/grav-plugin-admin/pull/2265) as it broke sections output + +# v1.10.33 +## 04/25/2022 + +1. [](#new) + * Require **Form 6.0.1** +2. [](#improved) + * Added support for a single `field:` vs `fields:` in element form field to store a single value to the option field + * Allow new media collapser logic to configure different cookie storage name location via `data-storage-location` +1. [](#bugfix) + * Fixed nested element form fields + * Fixed `columns` and `column` fields with `.dotted` variables inside to ignore columns and column names + * Fixed initial elements state not being restored + +# v1.10.32 +## 03/28/2022 + +1. [](#new) + * Require **Grav 1.7.32**, **Form 6.0.0**, **Login 3.7.0**, **Email 3.1.6** and **Flex Objects 1.2.0** +2. [](#improved) + * List field: Support for default values other than key/value [#2255](https://github.com/getgrav/grav-plugin-admin/issues/2255) + * Added question icon to admin fields with help text [#2261](https://github.com/getgrav/grav-plugin-admin/issues/2261) +3. [](#bugfix) + * Fix nested `toggleable`: originalValue now checks with `??` instead of `is defined` + +# 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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Logging/Logger.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Logging/Logger.php new file mode 100644 index 0000000..caec463 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Atom.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Atom.php new file mode 100644 index 0000000..0496869 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/DateParser.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/DateParser.php new file mode 100644 index 0000000..b7a015d --- /dev/null +++ b/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 === false || ($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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Feed.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Feed.php new file mode 100644 index 0000000..a56e71c --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Item.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Item.php new file mode 100644 index 0000000..98214b8 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/MalformedXmlException.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/MalformedXmlException.php new file mode 100644 index 0000000..efaf0ff --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/ParserException.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/ParserException.php new file mode 100644 index 0000000..b5fbb69 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Rss20.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Rss20.php new file mode 100644 index 0000000..da9c0d5 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Rss91.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Parser/Rss91.php new file mode 100644 index 0000000..058fca1 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/PicoFeedException.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/PicoFeedException.php new file mode 100644 index 0000000..2de9e4b --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ContentGeneratorProcessor.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ContentGeneratorProcessor.php new file mode 100644 index 0000000..49adf9c --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ItemPostProcessor.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ItemPostProcessor.php new file mode 100644 index 0000000..7b092b5 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ItemProcessorInterface.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Processor/ItemProcessorInterface.php new file mode 100644 index 0000000..5d53226 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/Favicon.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/Favicon.php new file mode 100644 index 0000000..d4ca07d --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/Reader.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/Reader.php new file mode 100644 index 0000000..596b02d --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/ReaderException.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Reader/ReaderException.php new file mode 100644 index 0000000..4f03dbe --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.blogs.nytimes.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.blogs.nytimes.com.php new file mode 100644 index 0000000..ee641b0 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.igen.fr.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.igen.fr.php new file mode 100644 index 0000000..f2028f4 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.nytimes.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.nytimes.com.php new file mode 100644 index 0000000..8ff921c --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.over-blog.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.over-blog.com.php new file mode 100644 index 0000000..cc5d83c --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.phoronix.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.phoronix.com.php new file mode 100644 index 0000000..66713f7 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.slate.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.slate.com.php new file mode 100644 index 0000000..a795bca --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.theguardian.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.theguardian.com.php new file mode 100644 index 0000000..e0d6f3f --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wikipedia.org.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wikipedia.org.php new file mode 100644 index 0000000..7b8f76e --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wired.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wired.com.php new file mode 100644 index 0000000..952b09a --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wsj.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/.wsj.com.php new file mode 100644 index 0000000..f6e6cc1 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/01net.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/01net.com.php new file mode 100644 index 0000000..6d144f0 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/24.hu.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/24.hu.php new file mode 100644 index 0000000..6c269db --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/444.hu.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/444.hu.php new file mode 100644 index 0000000..e65bad1 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/888.hu.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/888.hu.php new file mode 100644 index 0000000..68cfe05 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/abstrusegoose.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/abstrusegoose.com.php new file mode 100644 index 0000000..752d041 --- /dev/null +++ b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/abstrusegoose.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%alt="(.+)" title="(.+)" */>%' => '/>
$1
$2', + ), + ), +); diff --git a/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/achgut.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/achgut.com.php new file mode 100644 index 0000000..1e61fe6 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/adventuregamers.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/adventuregamers.com.php new file mode 100644 index 0000000..98d384e --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/alainonline.net.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/alainonline.net.php new file mode 100644 index 0000000..f440b23 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/aljazeera.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/aljazeera.com.php new file mode 100644 index 0000000..c02eb21 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/allafrica.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/allafrica.com.php new file mode 100644 index 0000000..e8a506d --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/allgemeine-zeitung.de.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/allgemeine-zeitung.de.php new file mode 100644 index 0000000..8ede99b --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/amazingsuperpowers.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/amazingsuperpowers.com.php new file mode 100644 index 0000000..3214c62 --- /dev/null +++ b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/amazingsuperpowers.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
$1', + ), + ), +); diff --git a/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/anythingcomic.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/anythingcomic.com.php new file mode 100644 index 0000000..51247f7 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ap.org.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ap.org.php new file mode 100644 index 0000000..5bb2bb6 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/areadvd.de.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/areadvd.de.php new file mode 100644 index 0000000..fc56922 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/arstechnica.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/arstechnica.com.php new file mode 100644 index 0000000..55e01ce --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/atv.hu.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/atv.hu.php new file mode 100644 index 0000000..170ec4d --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/awkwardzombie.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/awkwardzombie.com.php new file mode 100644 index 0000000..5ab7051 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/backchannel.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/backchannel.com.php new file mode 100644 index 0000000..bc5932a --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bangkokpost.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bangkokpost.com.php new file mode 100644 index 0000000..165515b --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bauerwilli.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bauerwilli.com.php new file mode 100644 index 0000000..b191a6e --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bgr.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bgr.com.php new file mode 100644 index 0000000..7507a2f --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bigfootjustice.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bigfootjustice.com.php new file mode 100644 index 0000000..d06ed12 --- /dev/null +++ b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bigfootjustice.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%-150x150%' => '', + ), + ), +); diff --git a/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bigpicture.ru.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bigpicture.ru.php new file mode 100644 index 0000000..55c4089 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bizjournals.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bizjournals.com.php new file mode 100644 index 0000000..d1cc3da --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/biztimes.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/biztimes.com.php new file mode 100644 index 0000000..d21aa98 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bleepingcomputer.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bleepingcomputer.com.php new file mode 100644 index 0000000..7b74060 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/blog.fefe.de.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/blog.fefe.de.php new file mode 100644 index 0000000..39c88ae --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/blog.mapillary.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/blog.mapillary.com.php new file mode 100644 index 0000000..ce01651 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/brewers.mlb.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/brewers.mlb.com.php new file mode 100644 index 0000000..be406fa --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/buenosairesherald.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/buenosairesherald.com.php new file mode 100644 index 0000000..4e73e79 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bunicomic.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/bunicomic.com.php new file mode 100644 index 0000000..ad83e43 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/buttersafe.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/buttersafe.com.php new file mode 100644 index 0000000..1f313cd --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cad-comic.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cad-comic.com.php new file mode 100644 index 0000000..a631c97 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/chaoslife.findchaos.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/chaoslife.findchaos.com.php new file mode 100644 index 0000000..ea6191e --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/chinafile.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/chinafile.com.php new file mode 100644 index 0000000..450117b --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cicero.de.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cicero.de.php new file mode 100644 index 0000000..2cd1b70 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cliquerefresh.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cliquerefresh.com.php new file mode 100644 index 0000000..9dcc7e5 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cnet.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cnet.com.php new file mode 100644 index 0000000..60767a5 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/coinwelt.de.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/coinwelt.de.php new file mode 100644 index 0000000..28a8bba --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/consomac.fr.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/consomac.fr.php new file mode 100644 index 0000000..9209f9c --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cowbirdsinlove.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cowbirdsinlove.com.php new file mode 100644 index 0000000..3214c62 --- /dev/null +++ b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/cowbirdsinlove.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
$1', + ), + ), +); diff --git a/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/crash.net.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/crash.net.php new file mode 100644 index 0000000..88cef14 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/csmonitor.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/csmonitor.com.php new file mode 100644 index 0000000..481e4b0 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailyjs.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailyjs.com.php new file mode 100644 index 0000000..20eb1d7 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailyreporter.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailyreporter.com.php new file mode 100644 index 0000000..db3fc0e --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailytech.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dailytech.com.php new file mode 100644 index 0000000..5d1df4a --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/degroupnews.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/degroupnews.com.php new file mode 100644 index 0000000..91f5c56 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/derstandard.at.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/derstandard.at.php new file mode 100644 index 0000000..7e95a51 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dilbert.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dilbert.com.php new file mode 100644 index 0000000..b8e9b3d --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/discovermagazine.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/discovermagazine.com.php new file mode 100644 index 0000000..ae0dfe7 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/distrowatch.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/distrowatch.com.php new file mode 100644 index 0000000..aefc8f8 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dozodomo.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/dozodomo.com.php new file mode 100644 index 0000000..e116695 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/drawingboardcomic.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/drawingboardcomic.com.php new file mode 100644 index 0000000..cd30f2e --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/e-w-e.ru.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/e-w-e.ru.php new file mode 100644 index 0000000..8139cc9 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/economist.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/economist.com.php new file mode 100644 index 0000000..522032f --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/encyclopedie.naheulbeuk.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/encyclopedie.naheulbeuk.com.php new file mode 100644 index 0000000..19bcbde --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/endlessorigami.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/endlessorigami.com.php new file mode 100644 index 0000000..d06ed12 --- /dev/null +++ b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/endlessorigami.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%-150x150%' => '', + ), + ), +); diff --git a/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/engadget.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/engadget.com.php new file mode 100644 index 0000000..cf9e448 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/escapistmagazine.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/escapistmagazine.com.php new file mode 100644 index 0000000..e86b59c --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/espn.go.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/espn.go.com.php new file mode 100644 index 0000000..76a20f7 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/exocomics.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/exocomics.com.php new file mode 100644 index 0000000..5adc59f --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/explosm.net.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/explosm.net.php new file mode 100644 index 0000000..3fdf02c --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/extrafabulouscomics.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/extrafabulouscomics.com.php new file mode 100644 index 0000000..12697cc --- /dev/null +++ b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/extrafabulouscomics.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%-150x150%' => '', + ), + ), +); diff --git a/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/factroom.ru.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/factroom.ru.php new file mode 100644 index 0000000..a572061 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcodesign.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcodesign.com.php new file mode 100644 index 0000000..74e70a8 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcoexist.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcoexist.com.php new file mode 100644 index 0000000..6916f28 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcompany.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fastcompany.com.php new file mode 100644 index 0000000..e0869a2 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ffworld.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ffworld.com.php new file mode 100644 index 0000000..20a47b2 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/foreignpolicy.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/foreignpolicy.com.php new file mode 100644 index 0000000..3cbcddc --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fossbytes.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fossbytes.com.php new file mode 100644 index 0000000..6ce4725 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fototelegraf.ru.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fototelegraf.ru.php new file mode 100644 index 0000000..ca2f85a --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fowllanguagecomics.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/fowllanguagecomics.com.php new file mode 100644 index 0000000..3f62f07 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gamechannel.hu.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gamechannel.hu.php new file mode 100644 index 0000000..8ab9c5c --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gamestar.hu.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gamestar.hu.php new file mode 100644 index 0000000..56a4c72 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/geek.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/geek.com.php new file mode 100644 index 0000000..d9ccecc --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/geektimes.ru.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/geektimes.ru.php new file mode 100644 index 0000000..1954138 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gerbilwithajetpack.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gerbilwithajetpack.com.php new file mode 100644 index 0000000..44013b3 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/giantitp.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/giantitp.com.php new file mode 100644 index 0000000..d9c3ae5 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/github.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/github.com.php new file mode 100644 index 0000000..726634f --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gocomics.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gocomics.com.php new file mode 100644 index 0000000..32960f0 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/golem.de.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/golem.de.php new file mode 100644 index 0000000..8731285 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gondola.hu.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gondola.hu.php new file mode 100644 index 0000000..62b1e3c --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gorabbit.ru.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/gorabbit.ru.php new file mode 100644 index 0000000..4e43248 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/habrahabr.ru.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/habrahabr.ru.php new file mode 100644 index 0000000..3f1ec16 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/happletea.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/happletea.com.php new file mode 100644 index 0000000..75b0b83 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hardware.fr.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hardware.fr.php new file mode 100644 index 0000000..56aec4f --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/heise.de.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/heise.de.php new file mode 100644 index 0000000..0ee6915 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hirek.prim.hu.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hirek.prim.hu.php new file mode 100644 index 0000000..1a38809 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hotshowlife.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hotshowlife.com.php new file mode 100644 index 0000000..faf01f3 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/huffingtonpost.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/huffingtonpost.com.php new file mode 100644 index 0000000..b52b07b --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hvg.hu.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/hvg.hu.php new file mode 100644 index 0000000..efc9371 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/idokep.hu.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/idokep.hu.php new file mode 100644 index 0000000..06cae09 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/imogenquest.net.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/imogenquest.net.php new file mode 100644 index 0000000..3214c62 --- /dev/null +++ b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/imogenquest.net.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
$1', + ), + ), +); diff --git a/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/index.hu.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/index.hu.php new file mode 100644 index 0000000..727d7b7 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/indiehaven.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/indiehaven.com.php new file mode 100644 index 0000000..a40ce69 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/inforadio.hu.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/inforadio.hu.php new file mode 100644 index 0000000..569013d --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ing.dk.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ing.dk.php new file mode 100644 index 0000000..5a021a0 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/invisiblebread.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/invisiblebread.com.php new file mode 100644 index 0000000..90f8759 --- /dev/null +++ b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/invisiblebread.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%()%' => '$1', + ), + ), +); diff --git a/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ir.amd.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ir.amd.com.php new file mode 100644 index 0000000..af99fe9 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/japantimes.co.jp.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/japantimes.co.jp.php new file mode 100644 index 0000000..9959441 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/japantoday.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/japantoday.com.php new file mode 100644 index 0000000..22485d6 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/journaldugeek.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/journaldugeek.com.php new file mode 100644 index 0000000..876b269 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/jsonline.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/jsonline.com.php new file mode 100644 index 0000000..5895256 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/justcoolidea.ru.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/justcoolidea.ru.php new file mode 100644 index 0000000..089ff29 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kanpai.fr.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kanpai.fr.php new file mode 100644 index 0000000..c3a1abc --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/karriere.jobfinder.dk.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/karriere.jobfinder.dk.php new file mode 100644 index 0000000..25d6dfa --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kisalfold.hu.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kisalfold.hu.php new file mode 100644 index 0000000..7568901 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kiszamolo.hu.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kiszamolo.hu.php new file mode 100644 index 0000000..c44a08f --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kodi.tv.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/kodi.tv.php new file mode 100644 index 0000000..439fc90 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/koreaherald.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/koreaherald.com.php new file mode 100644 index 0000000..9651056 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/koreatimes.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/koreatimes.php new file mode 100644 index 0000000..f274b4a --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lastplacecomics.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lastplacecomics.com.php new file mode 100644 index 0000000..12697cc --- /dev/null +++ b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lastplacecomics.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%-150x150%' => '', + ), + ), +); diff --git a/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/legorafi.fr.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/legorafi.fr.php new file mode 100644 index 0000000..e6aae46 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lejapon.fr.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lejapon.fr.php new file mode 100644 index 0000000..8f2b293 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lesjoiesducode.fr.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lesjoiesducode.fr.php new file mode 100644 index 0000000..369206a --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lfg.co.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lfg.co.php new file mode 100644 index 0000000..d978a5f --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lifehacker.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lifehacker.com.php new file mode 100644 index 0000000..b9a6933 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lifehacker.ru.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lifehacker.ru.php new file mode 100644 index 0000000..bc140f6 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux-magazin.de.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux-magazin.de.php new file mode 100644 index 0000000..f4bc07d --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux.org.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux.org.php new file mode 100644 index 0000000..2520d0d --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux.org.ru.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linux.org.ru.php new file mode 100644 index 0000000..7fa0249 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linuxinsider.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/linuxinsider.com.php new file mode 100644 index 0000000..4e0a4cc --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lists.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lists.php new file mode 100644 index 0000000..c7051a2 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/loadingartist.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/loadingartist.com.php new file mode 100644 index 0000000..d06ed12 --- /dev/null +++ b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/loadingartist.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%-150x150%' => '', + ), + ), +); diff --git a/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/loldwell.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/loldwell.com.php new file mode 100644 index 0000000..d358e15 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lukesurl.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/lukesurl.com.php new file mode 100644 index 0000000..816233d --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/macg.co.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/macg.co.php new file mode 100644 index 0000000..bbe6dbc --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/maclife.de.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/maclife.de.php new file mode 100644 index 0000000..bca347e --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/magyarkurir.hu.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/magyarkurir.hu.php new file mode 100644 index 0000000..32d78bc --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marc.info.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marc.info.php new file mode 100644 index 0000000..5f582a6 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marriedtothesea.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marriedtothesea.com.php new file mode 100644 index 0000000..469640d --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marycagle.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/marycagle.com.php new file mode 100644 index 0000000..b8665e3 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/maximumble.thebookofbiff.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/maximumble.thebookofbiff.com.php new file mode 100644 index 0000000..8880054 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/medium.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/medium.com.php new file mode 100644 index 0000000..e20860e --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mercworks.net.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mercworks.net.php new file mode 100644 index 0000000..c7a27de --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/metronieuws.nl.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/metronieuws.nl.php new file mode 100644 index 0000000..5011169 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/milwaukeenns.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/milwaukeenns.php new file mode 100644 index 0000000..ddb29a5 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mno.hu.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mno.hu.php new file mode 100644 index 0000000..a2799b8 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mokepon.smackjeeves.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mokepon.smackjeeves.com.php new file mode 100644 index 0000000..1ddcd40 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/monandroid.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/monandroid.com.php new file mode 100644 index 0000000..f87560e --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/monwindows.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/monwindows.com.php new file mode 100644 index 0000000..b2b24d7 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/moya-planeta.ru.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/moya-planeta.ru.php new file mode 100644 index 0000000..dd84284 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mrlovenstein.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mrlovenstein.com.php new file mode 100644 index 0000000..b971091 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/muckrock.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/muckrock.com.php new file mode 100644 index 0000000..9e354a3 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mynorthshorenow.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/mynorthshorenow.com.php new file mode 100644 index 0000000..b630915 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nakedCapitalism.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nakedCapitalism.php new file mode 100644 index 0000000..ec2d5fd --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nasa.gov.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nasa.gov.php new file mode 100644 index 0000000..c6692d0 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nat-geo.ru.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nat-geo.ru.php new file mode 100644 index 0000000..1a42d99 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nationaljournal.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nationaljournal.com.php new file mode 100644 index 0000000..5e612be --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nature.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nature.com.php new file mode 100644 index 0000000..6b9e87f --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nba.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nba.com.php new file mode 100644 index 0000000..c8ea926 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nedroid.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nedroid.com.php new file mode 100644 index 0000000..3214c62 --- /dev/null +++ b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nedroid.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
$1', + ), + ), +); diff --git a/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/networkworld.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/networkworld.com.php new file mode 100644 index 0000000..1852435 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/neustadt-ticker.de.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/neustadt-ticker.de.php new file mode 100644 index 0000000..e0c0d19 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nextinpact.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nextinpact.com.php new file mode 100644 index 0000000..29dd9d6 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/niceteethcomic.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/niceteethcomic.com.php new file mode 100644 index 0000000..f41e443 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nichtlustig.de.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nichtlustig.de.php new file mode 100644 index 0000000..4d083f9 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nlcafe.hu.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/nlcafe.hu.php new file mode 100644 index 0000000..b85e6b2 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/novo-argumente.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/novo-argumente.com.php new file mode 100644 index 0000000..cef3595 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/oglaf.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/oglaf.com.php new file mode 100644 index 0000000..8b2b5b6 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/onhax.net.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/onhax.net.php new file mode 100644 index 0000000..213849d --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/onlinekosten.de.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/onlinekosten.de.php new file mode 100644 index 0000000..7382612 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/onmilwaukee.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/onmilwaukee.php new file mode 100644 index 0000000..f66ac4b --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/openculture.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/openculture.com.php new file mode 100644 index 0000000..84f2bee --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/opennet.ru.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/opennet.ru.php new file mode 100644 index 0000000..1fb7722 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/openrightsgroup.org.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/openrightsgroup.org.php new file mode 100644 index 0000000..94139a7 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/opensource.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/opensource.com.php new file mode 100644 index 0000000..60f3577 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/optipess.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/optipess.com.php new file mode 100644 index 0000000..3214c62 --- /dev/null +++ b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/optipess.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
$1', + ), + ), +); diff --git a/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/origo.hu.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/origo.hu.php new file mode 100644 index 0000000..7bd9496 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/osnews.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/osnews.com.php new file mode 100644 index 0000000..1d1396c --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pastebin.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pastebin.com.php new file mode 100644 index 0000000..b20bf41 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pcgameshardware.de.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pcgameshardware.de.php new file mode 100644 index 0000000..f180aee --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/peebleslab.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/peebleslab.com.php new file mode 100644 index 0000000..ce4891d --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/penny-arcade.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/penny-arcade.com.php new file mode 100644 index 0000000..dd39983 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pixelbeat.org.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pixelbeat.org.php new file mode 100644 index 0000000..fa9052e --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/plus.google.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/plus.google.com.php new file mode 100644 index 0000000..5e48a6c --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/popstrip.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/popstrip.com.php new file mode 100644 index 0000000..801a281 --- /dev/null +++ b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/popstrip.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%( '$1$2$1bonus.png"/>', + ), + ), +); diff --git a/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/portfolio.hu.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/portfolio.hu.php new file mode 100644 index 0000000..ad01dad --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pro-linux.de.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/pro-linux.de.php new file mode 100644 index 0000000..bc76630 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/publicpolicyforum.org.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/publicpolicyforum.org.php new file mode 100644 index 0000000..5dc8be8 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/publy.ru.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/publy.ru.php new file mode 100644 index 0000000..bcfeeb9 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/putaindecode.fr.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/putaindecode.fr.php new file mode 100644 index 0000000..9fa5568 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/recode.net.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/recode.net.php new file mode 100644 index 0000000..343cd12 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/retractionwatch.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/retractionwatch.com.php new file mode 100644 index 0000000..b97c73e --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/rockpapershotgun.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/rockpapershotgun.com.php new file mode 100644 index 0000000..7111078 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/rue89.nouvelobs.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/rue89.nouvelobs.com.php new file mode 100644 index 0000000..cb9116a --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/rugbyrama.fr.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/rugbyrama.fr.php new file mode 100644 index 0000000..9915c23 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/salonkolumnisten.com b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/salonkolumnisten.com new file mode 100644 index 0000000..37f43e9 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/satwcomic.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/satwcomic.com.php new file mode 100644 index 0000000..d63fc11 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/science-skeptical.de.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/science-skeptical.de.php new file mode 100644 index 0000000..fcf045f --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/scrumalliance.org.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/scrumalliance.org.php new file mode 100644 index 0000000..7835fd9 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/securityfocus.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/securityfocus.com.php new file mode 100644 index 0000000..0104514 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/sentfromthemoon.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/sentfromthemoon.com.php new file mode 100644 index 0000000..f435417 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/sitepoint.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/sitepoint.com.php new file mode 100644 index 0000000..ab0eb7d --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/slashdot.org.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/slashdot.org.php new file mode 100644 index 0000000..89ced8b --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smallhousebliss.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smallhousebliss.com.php new file mode 100644 index 0000000..8c13c44 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smarthomewelt.de.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smarthomewelt.de.php new file mode 100644 index 0000000..7463abc --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smashingmagazine.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smashingmagazine.com.php new file mode 100644 index 0000000..cbe1072 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smbc-comics.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/smbc-comics.com.php new file mode 100644 index 0000000..42262dc --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/snopes.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/snopes.com.php new file mode 100644 index 0000000..b0fe655 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/soundandvision.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/soundandvision.com.php new file mode 100644 index 0000000..6448bb0 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/spiegel.de.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/spiegel.de.php new file mode 100644 index 0000000..b42c3aa --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/stereophile.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/stereophile.com.php new file mode 100644 index 0000000..8e410be --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/stupidfox.net.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/stupidfox.net.php new file mode 100644 index 0000000..61182d7 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/subtraction.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/subtraction.com.php new file mode 100644 index 0000000..6d74427 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/sz.de.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/sz.de.php new file mode 100644 index 0000000..90bde5a --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/takprosto.cc.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/takprosto.cc.php new file mode 100644 index 0000000..624ef90 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/techcrunch.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/techcrunch.com.php new file mode 100644 index 0000000..230b791 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/the-ebook-reader.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/the-ebook-reader.com.php new file mode 100644 index 0000000..3b01eb9 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theatlantic.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theatlantic.com.php new file mode 100644 index 0000000..bfad4ab --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theawkwardyeti.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theawkwardyeti.com.php new file mode 100644 index 0000000..fd4f3d5 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thecodinglove.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thecodinglove.com.php new file mode 100644 index 0000000..c6ec5bf --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thedoghousediaries.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thedoghousediaries.com.php new file mode 100644 index 0000000..d2f840d --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thegamercat.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thegamercat.com.php new file mode 100644 index 0000000..f9b4637 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thehindu.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thehindu.com.php new file mode 100644 index 0000000..1e6735b --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thelocal.se.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thelocal.se.php new file mode 100644 index 0000000..c3ec250 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/themerepublic.net.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/themerepublic.net.php new file mode 100644 index 0000000..bc47b27 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/themoscowtimes.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/themoscowtimes.com.php new file mode 100644 index 0000000..0f5bf75 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thenewslens.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thenewslens.com.php new file mode 100644 index 0000000..7538170 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theodd1sout.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theodd1sout.com.php new file mode 100644 index 0000000..d06ed12 --- /dev/null +++ b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theodd1sout.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%-150x150%' => '', + ), + ), +); diff --git a/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theonion.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theonion.com.php new file mode 100644 index 0000000..acbfd36 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theregister.co.uk.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theregister.co.uk.php new file mode 100644 index 0000000..896365a --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thestandard.com.hk.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/thestandard.com.hk.php new file mode 100644 index 0000000..1163b34 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theverge.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/theverge.com.php new file mode 100644 index 0000000..09e876d --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/threepanelsoul.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/threepanelsoul.com.php new file mode 100644 index 0000000..4af6196 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/tichyseinblick.de.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/tichyseinblick.de.php new file mode 100644 index 0000000..6fba3df --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/timesofindia.indiatimes.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/timesofindia.indiatimes.com.php new file mode 100644 index 0000000..1924680 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/totalcar.hu.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/totalcar.hu.php new file mode 100644 index 0000000..f2e009d --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/tozsdeforum.hu.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/tozsdeforum.hu.php new file mode 100644 index 0000000..97a0da0 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/travel-dealz.de.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/travel-dealz.de.php new file mode 100644 index 0000000..4ee4fcd --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/travelo.hu.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/travelo.hu.php new file mode 100644 index 0000000..3ab8ca4 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/treehugger.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/treehugger.com.php new file mode 100644 index 0000000..55eb7e0 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/treelobsters.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/treelobsters.com.php new file mode 100644 index 0000000..3214c62 --- /dev/null +++ b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/treelobsters.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%title="(.+)" */>%' => '/>
$1', + ), + ), +); diff --git a/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/tutorialzine.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/tutorialzine.com.php new file mode 100644 index 0000000..7e39145 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/twogag.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/twogag.com.php new file mode 100644 index 0000000..79f4f62 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/twokinds.keenspot.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/twokinds.keenspot.com.php new file mode 100644 index 0000000..3428fcb --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/undeadly.org.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/undeadly.org.php new file mode 100644 index 0000000..8b15900 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/upi.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/upi.com.php new file mode 100644 index 0000000..ec8d1a1 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/usatoday.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/usatoday.com.php new file mode 100644 index 0000000..edd6aa4 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/version2.dk.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/version2.dk.php new file mode 100644 index 0000000..a6d49f2 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/vezess.hu.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/vezess.hu.php new file mode 100644 index 0000000..acd68c0 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/vgcats.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/vgcats.com.php new file mode 100644 index 0000000..b2830a3 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/vuxml.org.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/vuxml.org.php new file mode 100644 index 0000000..b9bef7a --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/wausaudailyherald.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/wausaudailyherald.com.php new file mode 100644 index 0000000..58aceea --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/welt.de.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/welt.de.php new file mode 100644 index 0000000..83a2ebe --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/westfalen-blatt.de.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/westfalen-blatt.de.php new file mode 100644 index 0000000..adcf417 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.bbc.co.uk.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.bbc.co.uk.php new file mode 100644 index 0000000..98fc368 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.bdgest.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.bdgest.com.php new file mode 100644 index 0000000..41ef68d --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.bgr.in.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.bgr.in.php new file mode 100644 index 0000000..63ca069 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.businessweek.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.businessweek.com.php new file mode 100644 index 0000000..0acc44e --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.cnn.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.cnn.com.php new file mode 100644 index 0000000..31d03ed --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.developpez.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.developpez.com.php new file mode 100644 index 0000000..1535e43 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.egscomics.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.egscomics.com.php new file mode 100644 index 0000000..263f075 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.fakingnews.firstpost.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.fakingnews.firstpost.com.php new file mode 100644 index 0000000..c948c77 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.forbes.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.forbes.com.php new file mode 100644 index 0000000..fd16ed5 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.franceculture.fr.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.franceculture.fr.php new file mode 100644 index 0000000..f7ec0d8 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.futura-sciences.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.futura-sciences.com.php new file mode 100644 index 0000000..ea94a0f --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.geekculture.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.geekculture.com.php new file mode 100644 index 0000000..3d0b6c7 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.howtogeek.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.howtogeek.com.php new file mode 100644 index 0000000..6879e76 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.lepoint.fr.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.lepoint.fr.php new file mode 100644 index 0000000..dcb7e48 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.lesnumeriques.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.lesnumeriques.com.php new file mode 100644 index 0000000..0137e20 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.mac4ever.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.mac4ever.com.php new file mode 100644 index 0000000..60bc1bd --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.makeuseof.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.makeuseof.com.php new file mode 100644 index 0000000..a274564 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.monsieur-le-chien.fr.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.monsieur-le-chien.fr.php new file mode 100644 index 0000000..5f5e987 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.npr.org.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.npr.org.php new file mode 100644 index 0000000..ecc0213 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.numerama.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.numerama.com.php new file mode 100644 index 0000000..fe4971c --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.oneindia.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.oneindia.com.php new file mode 100644 index 0000000..320c214 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.pseudo-sciences.org.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.pseudo-sciences.org.php new file mode 100644 index 0000000..9e467ed --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.sciencemag.org.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.sciencemag.org.php new file mode 100644 index 0000000..ae7a93a --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.slate.fr.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.slate.fr.php new file mode 100644 index 0000000..8c8dc89 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.universfreebox.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.universfreebox.com.php new file mode 100644 index 0000000..0747d0f --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.zeit.de.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/www.zeit.de.php new file mode 100644 index 0000000..316c265 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/xkcd.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/xkcd.com.php new file mode 100644 index 0000000..8495726 --- /dev/null +++ b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/xkcd.com.php @@ -0,0 +1,8 @@ + array( + '%.*%' => array( + '%alt="(.+)" */>%' => '/>
$1', + ), + ), +); diff --git a/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ymatuhin.ru.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/ymatuhin.ru.php new file mode 100644 index 0000000..9fd83f1 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/zarojel.hu.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/zarojel.hu.php new file mode 100644 index 0000000..36d3bdf --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/zdnet.com.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/zdnet.com.php new file mode 100644 index 0000000..79b35dd --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/zoom.hu.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Rules/zoom.hu.php new file mode 100644 index 0000000..3e38781 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/CandidateParser.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/CandidateParser.php new file mode 100644 index 0000000..0f74b3d --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/ParserInterface.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/ParserInterface.php new file mode 100644 index 0000000..3ded4b1 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/RuleParser.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/RuleParser.php new file mode 100644 index 0000000..9beb59c --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/Scraper.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Scraper/Scraper.php new file mode 100644 index 0000000..29383b2 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/Subscription.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/Subscription.php new file mode 100644 index 0000000..12eccfd --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionList.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionList.php new file mode 100644 index 0000000..b173f89 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionListBuilder.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionListBuilder.php new file mode 100644 index 0000000..838e4cb --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionListParser.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionListParser.php new file mode 100644 index 0000000..9085588 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionParser.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Serialization/SubscriptionParser.php new file mode 100644 index 0000000..caff07c --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/AtomFeedBuilder.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/AtomFeedBuilder.php new file mode 100644 index 0000000..34f3780 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/AtomHelper.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/AtomHelper.php new file mode 100644 index 0000000..def6b0b --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/AtomItemBuilder.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/AtomItemBuilder.php new file mode 100644 index 0000000..dfdfe68 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/FeedBuilder.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/FeedBuilder.php new file mode 100644 index 0000000..cf9d024 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/ItemBuilder.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/ItemBuilder.php new file mode 100644 index 0000000..86985bc --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/Rss20FeedBuilder.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/Rss20FeedBuilder.php new file mode 100644 index 0000000..bc3f513 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/Rss20Helper.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/Rss20Helper.php new file mode 100644 index 0000000..72a19e5 --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/Rss20ItemBuilder.php b/plugins/admin/vendor/p3k/picofeed/lib/PicoFeed/Syndication/Rss20ItemBuilder.php new file mode 100644 index 0000000..125dc6a --- /dev/null +++ b/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/plugins/admin/vendor/p3k/picofeed/picofeed b/plugins/admin/vendor/p3k/picofeed/picofeed new file mode 100644 index 0000000..8f35737 --- /dev/null +++ b/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/plugins/admin/vendor/scssphp/scssphp/LICENSE.md b/plugins/admin/vendor/scssphp/scssphp/LICENSE.md new file mode 100644 index 0000000..afcfdfb --- /dev/null +++ b/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/plugins/admin/vendor/scssphp/scssphp/README.md b/plugins/admin/vendor/scssphp/scssphp/README.md new file mode 100644 index 0000000..65bb93e --- /dev/null +++ b/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/plugins/admin/vendor/scssphp/scssphp/bin/pscss b/plugins/admin/vendor/scssphp/scssphp/bin/pscss new file mode 100644 index 0000000..0f009d6 --- /dev/null +++ b/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/plugins/admin/vendor/scssphp/scssphp/composer.json b/plugins/admin/vendor/scssphp/scssphp/composer.json new file mode 100644 index 0000000..f81203d --- /dev/null +++ b/plugins/admin/vendor/scssphp/scssphp/composer.json @@ -0,0 +1,117 @@ +{ + "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": "2022.08.19", + "source": { + "type": "git", + "url": "https://github.com/sass/sass-spec.git", + "reference": "2bdc199723a3445d5badac3ac774105698f08861" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sass/sass-spec/zipball/2bdc199723a3445d5badac3ac774105698f08861", + "reference": "2bdc199723a3445d5badac3ac774105698f08861", + "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 + } + }, + "extra": { + "bamarni-bin": { + "forward-command": false, + "bin-links": false + } + } +} diff --git a/plugins/admin/vendor/scssphp/scssphp/scss.inc.php b/plugins/admin/vendor/scssphp/scssphp/scss.inc.php new file mode 100644 index 0000000..4598378 --- /dev/null +++ b/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/plugins/admin/vendor/scssphp/scssphp/src/Block.php b/plugins/admin/vendor/scssphp/scssphp/src/Block.php new file mode 100644 index 0000000..96668dc --- /dev/null +++ b/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/plugins/admin/vendor/scssphp/scssphp/src/Block/AtRootBlock.php b/plugins/admin/vendor/scssphp/scssphp/src/Block/AtRootBlock.php new file mode 100644 index 0000000..41842c2 --- /dev/null +++ b/plugins/admin/vendor/scssphp/scssphp/src/Block/AtRootBlock.php @@ -0,0 +1,37 @@ +type = Type::T_AT_ROOT; + } +} diff --git a/plugins/admin/vendor/scssphp/scssphp/src/Block/CallableBlock.php b/plugins/admin/vendor/scssphp/scssphp/src/Block/CallableBlock.php new file mode 100644 index 0000000..a18a87c --- /dev/null +++ b/plugins/admin/vendor/scssphp/scssphp/src/Block/CallableBlock.php @@ -0,0 +1,45 @@ +type = $type; + } +} diff --git a/plugins/admin/vendor/scssphp/scssphp/src/Block/ContentBlock.php b/plugins/admin/vendor/scssphp/scssphp/src/Block/ContentBlock.php new file mode 100644 index 0000000..8708498 --- /dev/null +++ b/plugins/admin/vendor/scssphp/scssphp/src/Block/ContentBlock.php @@ -0,0 +1,38 @@ +type = Type::T_INCLUDE; + } +} diff --git a/plugins/admin/vendor/scssphp/scssphp/src/Block/DirectiveBlock.php b/plugins/admin/vendor/scssphp/scssphp/src/Block/DirectiveBlock.php new file mode 100644 index 0000000..b1d3d1a --- /dev/null +++ b/plugins/admin/vendor/scssphp/scssphp/src/Block/DirectiveBlock.php @@ -0,0 +1,37 @@ +type = Type::T_DIRECTIVE; + } +} diff --git a/plugins/admin/vendor/scssphp/scssphp/src/Block/EachBlock.php b/plugins/admin/vendor/scssphp/scssphp/src/Block/EachBlock.php new file mode 100644 index 0000000..b328957 --- /dev/null +++ b/plugins/admin/vendor/scssphp/scssphp/src/Block/EachBlock.php @@ -0,0 +1,37 @@ +type = Type::T_EACH; + } +} diff --git a/plugins/admin/vendor/scssphp/scssphp/src/Block/ElseBlock.php b/plugins/admin/vendor/scssphp/scssphp/src/Block/ElseBlock.php new file mode 100644 index 0000000..6abb4d7 --- /dev/null +++ b/plugins/admin/vendor/scssphp/scssphp/src/Block/ElseBlock.php @@ -0,0 +1,27 @@ +type = Type::T_ELSE; + } +} diff --git a/plugins/admin/vendor/scssphp/scssphp/src/Block/ElseifBlock.php b/plugins/admin/vendor/scssphp/scssphp/src/Block/ElseifBlock.php new file mode 100644 index 0000000..4622bca --- /dev/null +++ b/plugins/admin/vendor/scssphp/scssphp/src/Block/ElseifBlock.php @@ -0,0 +1,32 @@ +type = Type::T_ELSEIF; + } +} diff --git a/plugins/admin/vendor/scssphp/scssphp/src/Block/ForBlock.php b/plugins/admin/vendor/scssphp/scssphp/src/Block/ForBlock.php new file mode 100644 index 0000000..a9cf673 --- /dev/null +++ b/plugins/admin/vendor/scssphp/scssphp/src/Block/ForBlock.php @@ -0,0 +1,47 @@ +type = Type::T_FOR; + } +} diff --git a/plugins/admin/vendor/scssphp/scssphp/src/Block/IfBlock.php b/plugins/admin/vendor/scssphp/scssphp/src/Block/IfBlock.php new file mode 100644 index 0000000..9f21bf8 --- /dev/null +++ b/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/plugins/admin/vendor/scssphp/scssphp/src/Block/MediaBlock.php b/plugins/admin/vendor/scssphp/scssphp/src/Block/MediaBlock.php new file mode 100644 index 0000000..c49ee1b --- /dev/null +++ b/plugins/admin/vendor/scssphp/scssphp/src/Block/MediaBlock.php @@ -0,0 +1,37 @@ +type = Type::T_MEDIA; + } +} diff --git a/plugins/admin/vendor/scssphp/scssphp/src/Block/NestedPropertyBlock.php b/plugins/admin/vendor/scssphp/scssphp/src/Block/NestedPropertyBlock.php new file mode 100644 index 0000000..1ea4a6c --- /dev/null +++ b/plugins/admin/vendor/scssphp/scssphp/src/Block/NestedPropertyBlock.php @@ -0,0 +1,37 @@ +type = Type::T_NESTED_PROPERTY; + } +} diff --git a/plugins/admin/vendor/scssphp/scssphp/src/Block/WhileBlock.php b/plugins/admin/vendor/scssphp/scssphp/src/Block/WhileBlock.php new file mode 100644 index 0000000..ac18d4e --- /dev/null +++ b/plugins/admin/vendor/scssphp/scssphp/src/Block/WhileBlock.php @@ -0,0 +1,32 @@ +type = Type::T_WHILE; + } +} diff --git a/plugins/admin/vendor/scssphp/scssphp/src/Cache.php b/plugins/admin/vendor/scssphp/scssphp/src/Cache.php new file mode 100644 index 0000000..9731c60 --- /dev/null +++ b/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/plugins/admin/vendor/scssphp/scssphp/src/Colors.php b/plugins/admin/vendor/scssphp/scssphp/src/Colors.php new file mode 100644 index 0000000..2df3999 --- /dev/null +++ b/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/plugins/admin/vendor/scssphp/scssphp/src/CompilationResult.php b/plugins/admin/vendor/scssphp/scssphp/src/CompilationResult.php new file mode 100644 index 0000000..36adb0d --- /dev/null +++ b/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/plugins/admin/vendor/scssphp/scssphp/src/Compiler.php b/plugins/admin/vendor/scssphp/scssphp/src/Compiler.php new file mode 100644 index 0000000..ecafc8c --- /dev/null +++ b/plugins/admin/vendor/scssphp/scssphp/src/Compiler.php @@ -0,0 +1,10430 @@ + + * + * @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 Formatter + */ + protected $formatter; + + /** + * @var string + * @phpstan-var class-string + */ + private $configuredFormatter = 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->configuredFormatter, + '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->configuredFormatter(); + $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); + } + } + assert($this->scope !== null); + + $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) { + assert($sourceMapGenerator !== null); + $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 string[] $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 = isset($this->sourceNames[$this->sourceIndex]) ? $this->sourceNames[$this->sourceIndex] : '(stdin)'; + $out->sourceLine = $this->sourceLine; + $out->sourceColumn = $this->sourceColumn; + } + + 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); + assert($this->scope !== null); + $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) { + assert($block->parent !== null); + 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)) { + assert($this->scope !== null); + $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) && + isset($block->parent->selectors) && $block->parent->selectors + ) { + $selfParent = $block->parent; + } + + $this->env = $this->filterWithWithout($envs, $with, $without); + + assert($this->scope !== null); + $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); + + assert($this->scope !== null); + $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; + } + assert($this->rootBlock !== null); + + // 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->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; + assert($this->scope->parent !== null); + $this->scope->parent->children[] = $this->scope; + + $this->compileChildrenNoReturn($block->children, $this->scope); + + assert($this->scope !== null); + $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); + assert($this->scope->parent !== null); + $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); + + assert($this->scope !== null); + $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); + assert($block->selectors !== null); + $env->selectors = $this->evalSelectors($block->selectors); + + $out = $this->makeOutputBlock(null); + + assert($this->scope !== 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) { + assert($block->selfParent !== null); + $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); + + assert($this->scope !== null); + $this->scope->children[] = $out; + } + + /** + * Evaluate selectors + * + * @param array $selectors + * + * @return array + */ + protected function evalSelectors($selectors) + { + $this->shouldEvaluate = false; + + $evaluatedSelectors = []; + foreach ($selectors as $selector) { + $evaluatedSelectors[] = $this->evalSelector($selector); + } + $selectors = $evaluatedSelectors; + + // 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 + * + * @phpstan-impure + */ + protected function evalSelector($selector) + { + return array_map([$this, 'evalSelectorPart'], $selector); + } + + /** + * Evaluate selector part; replaces all the interpolates, stripping quotes + * + * @param array $part + * + * @return array + * + * @phpstan-impure + */ + 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 && + ($p[0] === '"' || $p[0] === "'") && + substr($p, -1) === $p[0] + ) { + $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 at-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) { + $oldSelfParent = $stm[1]->selfParent; + $stm[1]->selfParent = $selfParent; + $ret = $this->compileChild($stm, $out); + $stm[1]->selfParent = $oldSelfParent; + } elseif ($selfParent && \in_array($stm[0], [Type::T_INCLUDE, Type::T_EXTEND])) { + $stm['selfParent'] = $selfParent; + $ret = $this->compileChild($stm, $out); + } 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 ($queryString !== false && 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) && $child[1] instanceof Block) { + $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']); + } + assert($selectors !== null); + + 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']) && $child['selfParent'] instanceof Block && 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]) && $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]"); + } + + return null; + } + + /** + * 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); + + $shouldEval = $inParens || $inExp; + + // 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] + if (\is_callable([$this, $fn = "op{$ucOpName}{$ucLType}{$ucRType}"])) { + $out = $this->$fn($left, $right, $shouldEval); + } elseif (\is_callable([$this, $fn = "op{$ucLType}{$ucRType}"])) { + $out = $this->$fn($op, $left, $right, $shouldEval); + } elseif (\is_callable([$this, $fn = "op{$ucOpName}"])) { + $out = $this->$fn($left, $right, $shouldEval); + } else { + $out = null; + } + + 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' || $lowercasedName === 'rgb' || $lowercasedName === 'rgba' || $lowercasedName === 'hsl' || $lowercasedName === 'hsla') { + $normalizedName = $lowercasedName; + } + + if (($f = $this->getBuiltinFunction($normalizedName)) && \is_callable($f)) { + /** @var string $libName */ + $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->configuredFormatter = Expanded::class; + break; + + case OutputStyle::COMPRESSED: + $this->configuredFormatter = 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. + * + * @phpstan-param class-string $formatterName + */ + 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->configuredFormatter = $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 ($realPath === false) { + $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 + * + * @return never + * + * @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 + * @param bool|float|int|string|null ...$args + * + * @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 + * + * @return void + * + * @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 (!isset($arg[1])) { + continue; // This happens when using a trailing comma + } + 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 $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) { + assert(\is_array($value)); + + 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]); + } + assert(\is_array($value)); + + 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; + } else { + $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|float $hue H from 0 to 360 + * @param int|float $whiteness W from 0 to 100 + * @param int|float $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; + } else { + $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'] ]; + + /** + * @param array $args + * @param array $kwargs + * @param string $funcName + * + * @return array + */ + 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'; + + /** @phpstan-var callable(string, float|int, bool=, bool=): (float|int|null) $getParam */ + $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; + } + + if ($scale || $assertPercent) { + return $number->valueInRange($change ? 0 : -$max, $max, $name); + } + + return $number->valueInRangeWithUnit($change ? 0 : -$max, $max, $name, $checkPercent ? '%' : ''); + }; + + $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; + + 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'] ]; + + /** + * @param array $args + * @param array $kwargs + * @param string $funcName + * + * @return array|null + */ + 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 $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->valueInRangeWithUnit(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->valueInRangeWithUnit(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->assertInteger($args[1]); + + 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->assertInteger($args[1]); + + 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 = max(Util::mbStrlen($stringContent) + 1 + $index, 0); + } + + $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) { + $limit = $this->assertNumber($args[0], 'limit'); + + if ($limit->hasUnits()) { + $unitString = $limit->unitStr(); + $message = <<addLocationToMessage($message)); + } + + $n = $this->assertInteger($limit, '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); + } + + assert(!empty($selectorsMap)); + + $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/plugins/admin/vendor/scssphp/scssphp/src/Compiler/CachedResult.php b/plugins/admin/vendor/scssphp/scssphp/src/Compiler/CachedResult.php new file mode 100644 index 0000000..a662919 --- /dev/null +++ b/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/plugins/admin/vendor/scssphp/scssphp/src/Compiler/Environment.php b/plugins/admin/vendor/scssphp/scssphp/src/Compiler/Environment.php new file mode 100644 index 0000000..b205a07 --- /dev/null +++ b/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/plugins/admin/vendor/scssphp/scssphp/src/Exception/CompilerException.php b/plugins/admin/vendor/scssphp/scssphp/src/Exception/CompilerException.php new file mode 100644 index 0000000..0b00cf5 --- /dev/null +++ b/plugins/admin/vendor/scssphp/scssphp/src/Exception/CompilerException.php @@ -0,0 +1,24 @@ + + * + * @internal + */ +class CompilerException extends \Exception implements SassException +{ +} diff --git a/plugins/admin/vendor/scssphp/scssphp/src/Exception/ParserException.php b/plugins/admin/vendor/scssphp/scssphp/src/Exception/ParserException.php new file mode 100644 index 0000000..f072669 --- /dev/null +++ b/plugins/admin/vendor/scssphp/scssphp/src/Exception/ParserException.php @@ -0,0 +1,58 @@ + + * + * @internal + */ +class ParserException extends \Exception implements SassException +{ + /** + * @var array|null + * @phpstan-var array{string, int, int}|null + */ + private $sourcePosition; + + /** + * Get source position + * + * @api + * + * @return array|null + * @phpstan-return array{string, int, int}|null + */ + public function getSourcePosition() + { + return $this->sourcePosition; + } + + /** + * Set source position + * + * @api + * + * @param array $sourcePosition + * + * @return void + * + * @phpstan-param array{string, int, int} $sourcePosition + */ + public function setSourcePosition($sourcePosition) + { + $this->sourcePosition = $sourcePosition; + } +} diff --git a/plugins/admin/vendor/scssphp/scssphp/src/Exception/RangeException.php b/plugins/admin/vendor/scssphp/scssphp/src/Exception/RangeException.php new file mode 100644 index 0000000..4be4dee --- /dev/null +++ b/plugins/admin/vendor/scssphp/scssphp/src/Exception/RangeException.php @@ -0,0 +1,24 @@ + + * + * @internal + */ +class RangeException extends \Exception implements SassException +{ +} diff --git a/plugins/admin/vendor/scssphp/scssphp/src/Exception/SassException.php b/plugins/admin/vendor/scssphp/scssphp/src/Exception/SassException.php new file mode 100644 index 0000000..9f62b3c --- /dev/null +++ b/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/plugins/admin/vendor/scssphp/scssphp/src/Formatter.php b/plugins/admin/vendor/scssphp/scssphp/src/Formatter.php new file mode 100644 index 0000000..6137dc6 --- /dev/null +++ b/plugins/admin/vendor/scssphp/scssphp/src/Formatter.php @@ -0,0 +1,377 @@ + + * + * @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(); + + try { + $this->block($block); + } catch (\Exception $e) { + ob_end_clean(); + throw $e; + } catch (\Throwable $e) { + ob_end_clean(); + throw $e; + } + + $out = ob_get_clean(); + assert($out !== false); + + 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 !== '') { + assert($this->currentBlock->sourceLine !== null); + assert($this->currentBlock->sourceName !== null); + $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 !== '') { + assert($this->currentBlock->sourceLine !== null); + assert($this->currentBlock->sourceName !== null); + $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/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Compact.php b/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Compact.php new file mode 100644 index 0000000..22f2268 --- /dev/null +++ b/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/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Compressed.php b/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Compressed.php new file mode 100644 index 0000000..58ebe3f --- /dev/null +++ b/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/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Crunched.php b/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Crunched.php new file mode 100644 index 0000000..2bc1e92 --- /dev/null +++ b/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/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Debug.php b/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Debug.php new file mode 100644 index 0000000..b3f4422 --- /dev/null +++ b/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/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Expanded.php b/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Expanded.php new file mode 100644 index 0000000..6eb4a0c --- /dev/null +++ b/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Expanded.php @@ -0,0 +1,72 @@ + + * + * @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) === '/*') { + $replacedLine = preg_replace('/\r\n?|\n|\f/', $this->break, $line); + assert($replacedLine !== null); + $block->lines[$index] = $replacedLine; + } + } + + $this->write($inner . implode($glue, $block->lines)); + + if (empty($block->selectors) || ! empty($block->children)) { + $this->write($this->break); + } + } +} diff --git a/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Nested.php b/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Nested.php new file mode 100644 index 0000000..d5ed85c --- /dev/null +++ b/plugins/admin/vendor/scssphp/scssphp/src/Formatter/Nested.php @@ -0,0 +1,238 @@ + + * + * @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) === '/*') { + $replacedLine = preg_replace('/\r\n?|\n|\f/', $this->break, $line); + assert($replacedLine !== null); + $block->lines[$index] = $replacedLine; + } + } + + $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/plugins/admin/vendor/scssphp/scssphp/src/Formatter/OutputBlock.php b/plugins/admin/vendor/scssphp/scssphp/src/Formatter/OutputBlock.php new file mode 100644 index 0000000..2799656 --- /dev/null +++ b/plugins/admin/vendor/scssphp/scssphp/src/Formatter/OutputBlock.php @@ -0,0 +1,68 @@ + + * + * @internal + */ +class OutputBlock +{ + /** + * @var string|null + */ + 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/plugins/admin/vendor/scssphp/scssphp/src/Logger/LoggerInterface.php b/plugins/admin/vendor/scssphp/scssphp/src/Logger/LoggerInterface.php new file mode 100644 index 0000000..7c0a2f7 --- /dev/null +++ b/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/plugins/admin/vendor/scssphp/scssphp/src/Node.php b/plugins/admin/vendor/scssphp/scssphp/src/Node.php new file mode 100644 index 0000000..fcaf8a9 --- /dev/null +++ b/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/plugins/admin/vendor/scssphp/scssphp/src/Node/Number.php b/plugins/admin/vendor/scssphp/scssphp/src/Node/Number.php new file mode 100644 index 0000000..48e711f --- /dev/null +++ b/plugins/admin/vendor/scssphp/scssphp/src/Node/Number.php @@ -0,0 +1,834 @@ + + * + * @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; + } + + /** + * Returns true if the number has any units + * + * @return bool + */ + public function hasUnits() + { + return !$this->unitless(); + } + + /** + * 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 float|int $min + * @param float|int $max + * @param string $name + * @param string $unit + * + * @return float|int + * @throws SassScriptException + * + * @internal + */ + public function valueInRangeWithUnit($min, $max, $name, $unit) + { + 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, $unit, $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/plugins/admin/vendor/scssphp/scssphp/src/OutputStyle.php b/plugins/admin/vendor/scssphp/scssphp/src/OutputStyle.php new file mode 100644 index 0000000..c284639 --- /dev/null +++ b/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; + /** + * 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->utf8 = ! $encoding || strtolower($encoding) === 'utf-8'; + $this->patternModifiers = $this->utf8 ? 'Aisu' : 'Ais'; + $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 = [ + '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'); + } + + $this->restoreEncoding(); + assert($this->env !== null); + + 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 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() + ) { + 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) { + assert($this->env !== null); + + 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(); + assert($this->env !== null); + + 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(); + assert($this->env !== null); + + 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() + { + assert($this->env !== null); + + // 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 + * + * @return void + */ + protected function seek($where) + { + $this->count = $where; + } + + /** + * Assert a parsed part is plain CSS Valid + * + * @param array|false $parsed + * @param int $startPos + * + * @return array + * + * @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 array|false + */ + 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 + * + * @phpstan-impure + */ + 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 + * + * @phpstan-impure + */ + 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 + * + * @phpstan-impure + */ + 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 + * + * @phpstan-impure + */ + 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 + * + * @phpstan-impure + */ + 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 + $commentStatement = [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 + * + * @return void + */ + protected function appendComment($comment) + { + assert($this->env !== null); + + if (! $this->discardComments) { + $this->env->comments[] = $comment; + } + } + + /** + * Append statement to current block + * + * @param array|null $statement + * @param int $pos + * + * @return void + */ + protected function append($statement, $pos = null) + { + assert($this->env !== 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() + { + assert($this->env !== null); + + $i = \count($this->env->children) - 1; + + if (isset($this->env->children[$i])) { + return $this->env->children[$i]; + } + + return null; + } + + /** + * 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 string|false $endChar + * + * @return bool + * + * @phpstan-impure + */ + 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 = []; + /** @var array|Number|null $value */ + $value = null; + + while ($this->$parseItem($value)) { + $trailing_delim = false; + $items[] = $value; + + if ($delim) { + if (! $this->literal($delim, \strlen($delim))) { + break; + } + + $trailing_delim = true; + } else { + assert(\is_array($value) || $value instanceof Number); + // 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) { + assert(\is_array($value)); + /** @var string $word */ + $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--; + } + + /** @var array|Number|null $nextValue */ + $nextValue = null; + if ($this->$parseItem($nextValue)) { + assert(\is_array($nextValue) || $nextValue instanceof Number); + 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 + * + * @phpstan-impure + */ + 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 string[] $allowedTypes + * + * @return bool + * + * @phpstan-param array $allowedTypes + */ + 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[strtolower($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[strtolower($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(')') + ) { + if (strtolower($name) === 'var' && \count($args) === 2 && $args[1][0] === Type::T_NULL) { + $args[1] = [null, [Type::T_STRING, '', [' ']], false]; + } + + $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 string[] + */ + 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 bool + */ + 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 + * + * @return void + */ + 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 + * @phpstan-return array{int, int} + */ + 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/plugins/admin/vendor/scssphp/scssphp/src/SourceMap/Base64.php b/plugins/admin/vendor/scssphp/scssphp/src/SourceMap/Base64.php new file mode 100644 index 0000000..00b6b45 --- /dev/null +++ b/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/plugins/admin/vendor/scssphp/scssphp/src/SourceMap/Base64VLQ.php b/plugins/admin/vendor/scssphp/scssphp/src/SourceMap/Base64VLQ.php new file mode 100644 index 0000000..2a5210c --- /dev/null +++ b/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/plugins/admin/vendor/scssphp/scssphp/src/SourceMap/SourceMapGenerator.php b/plugins/admin/vendor/scssphp/scssphp/src/SourceMap/SourceMapGenerator.php new file mode 100644 index 0000000..ccd4f02 --- /dev/null +++ b/plugins/admin/vendor/scssphp/scssphp/src/SourceMap/SourceMapGenerator.php @@ -0,0 +1,390 @@ + + * @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_replace($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|null + * + * @throws \ScssPhp\ScssPhp\Exception\CompilerException If the file could not be saved + * @deprecated + */ + public function saveMap($content) + { + $file = $this->options['sourceMapWriteTo']; + assert($file !== null); + $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 $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']); + } + + $jsonSourceMap = json_encode($sourceMap, JSON_UNESCAPED_SLASHES); + + if (json_last_error() !== JSON_ERROR_NONE) { + throw new \RuntimeException(json_last_error_msg()); + } + + assert($jsonSourceMap !== false); + + return $jsonSourceMap; + } + + /** + * 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/plugins/admin/vendor/scssphp/scssphp/src/Type.php b/plugins/admin/vendor/scssphp/scssphp/src/Type.php new file mode 100644 index 0000000..d430887 --- /dev/null +++ b/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/plugins/admin/vendor/scssphp/scssphp/src/Util.php b/plugins/admin/vendor/scssphp/scssphp/src/Util.php new file mode 100644 index 0000000..ad608ce --- /dev/null +++ b/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/plugins/admin/vendor/scssphp/scssphp/src/Util/Path.php b/plugins/admin/vendor/scssphp/scssphp/src/Util/Path.php new file mode 100644 index 0000000..f399e41 --- /dev/null +++ b/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/plugins/admin/vendor/scssphp/scssphp/src/Version.php b/plugins/admin/vendor/scssphp/scssphp/src/Version.php new file mode 100644 index 0000000..d604a50 --- /dev/null +++ b/plugins/admin/vendor/scssphp/scssphp/src/Version.php @@ -0,0 +1,23 @@ + + */ +class Version +{ + const VERSION = '1.11.0'; +} diff --git a/plugins/admin/vendor/scssphp/scssphp/src/Warn.php b/plugins/admin/vendor/scssphp/scssphp/src/Warn.php new file mode 100644 index 0000000..592b44c --- /dev/null +++ b/plugins/admin/vendor/scssphp/scssphp/src/Warn.php @@ -0,0 +1,84 @@ + NOTE: This plugin is a modular component for Grav which requires [Grav](http://github.com/getgrav/grav) and the [Error](https://github.com/getgrav/grav-plugin-error) and [Problems](https://github.com/getgrav/grav-plugin-problems) to operate. + +## Configuration + +Before configuring this plugin, you should copy the `user/plugins/auto-author/auto-author.yaml` to `user/config/plugins/auto-author.yaml` and only edit that copy. + +Here is the default configuration and an explanation of available options: + +```yaml +# enables or disables the plugin +enabled: true +# true = use current admin user (fullname) or false = use site author name (default) +user: false +``` + +## License + +The MIT License (MIT) + +Copyright (c) 2015 Sven Sanzenbacher + +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/plugins/auto-author/auto-author.php b/plugins/auto-author/auto-author.php new file mode 100755 index 0000000..e751fe6 --- /dev/null +++ b/plugins/auto-author/auto-author.php @@ -0,0 +1,54 @@ + ['onAdminCreatePageFrontmatter', 0] + ]; + } + + /** + * Initialize the plugin + * + * @param Event $event + */ + public function onAdminCreatePageFrontmatter(Event $event) + { + $header = $event['header']; + if (!isset($header['author'])) { + if ($this->config->get('plugins.auto-author.user')) { + /** + * @var Admin $admin + */ + $admin = $this->grav['admin']; + $author = $admin->user->get('fullname'); + + } else { + $author = $this->grav['config']->get('site.author.name'); + } + $header['author'] = $author; + $event['header'] = $header; + } + } +} diff --git a/plugins/auto-author/auto-author.yaml b/plugins/auto-author/auto-author.yaml new file mode 100755 index 0000000..1eaead7 --- /dev/null +++ b/plugins/auto-author/auto-author.yaml @@ -0,0 +1,2 @@ +enabled: true +user: false diff --git a/plugins/auto-author/blueprints.yaml b/plugins/auto-author/blueprints.yaml new file mode 100755 index 0000000..34aff83 --- /dev/null +++ b/plugins/auto-author/blueprints.yaml @@ -0,0 +1,39 @@ +name: Auto Author +version: 0.1.0 +description: Automatically adds an author to frontmatter when creating a new page via Grav Admin plugin +icon: user-circle +author: + name: Sven Sanzenbacher +homepage: https://github.com/naucon/grav-plugin-auto-author +keywords: grav, plugin, auto-author, author, autor, frontmatter +bugs: https://github.com/naucon/grav-plugin-auto-author/issues +docs: https://github.com/naucon/grav-plugin-auto-author/blob/develop/README.md +license: MIT + +dependencies: + - { name: admin, version: '>=1.2.3' } + +form: + validation: strict + fields: + enabled: + type: toggle + label: Plugin status + highlight: 1 + default: 0 + options: + 1: Enabled + 0: Disabled + validate: + type: bool + user: + type: toggle + label: Current user + highlight: 1 + default: 0 + options: + 1: Enabled + 0: Disabled + validate: + type: bool + help: use current admin user (fullname) or site author diff --git a/plugins/auto-date/CHANGELOG.md b/plugins/auto-date/CHANGELOG.md new file mode 100755 index 0000000..770878e --- /dev/null +++ b/plugins/auto-date/CHANGELOG.md @@ -0,0 +1,17 @@ +# v1.0.2 +## 05/29/2016 + +1. [](#bugfix) + * Fixed links in blueprint + +# v1.0.1 +## 09/30/2016 + +1. [](#improved) + * Fixed icon + +# v1.0.0 +## 09/30/2016 + +1. [](#new) + * Initial Release diff --git a/plugins/auto-date/LICENSE b/plugins/auto-date/LICENSE new file mode 100755 index 0000000..6c7da64 --- /dev/null +++ b/plugins/auto-date/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Team 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/plugins/auto-date/README.md b/plugins/auto-date/README.md new file mode 100755 index 0000000..4d5d46b --- /dev/null +++ b/plugins/auto-date/README.md @@ -0,0 +1,7 @@ +# Auto Date Plugin + +The **Auto Date** Plugin is designed for [Grav CMS](http://github.com/getgrav/grav) and automatically adds the current date to frontmatter when createing a new page via the Admin plugin. + +## Description + +There's not much to this plugin, simply install it and whenever you create a new page via the admin plugin, the current date will be inserted in the frontmatter of the page and show up in the **Options** -> **Publishing** Tab. The format of the date is dependent upon the value set in `system.yaml` under `pages: dateformat: default` and if not set will use `H:i d-m-Y` as the date format. diff --git a/plugins/auto-date/auto-date.php b/plugins/auto-date/auto-date.php new file mode 100755 index 0000000..cdc7b9e --- /dev/null +++ b/plugins/auto-date/auto-date.php @@ -0,0 +1,42 @@ + ['onAdminCreatePageFrontmatter', 0] + ]; + } + + /** + * Initialize the plugin + */ + public function onAdminCreatePageFrontmatter(Event $event) + { + $header = $event['header']; + if (!isset($header['date'])) { + $header['date'] = date($this->grav['config']->get('system.pages.dateformat.default', 'H:i d-m-Y')); + $header['publish_date'] = date($this->grav['config']->get('system.pages.dateformat.default', 'H:i d-m-Y')); + $event['header'] = $header; + } + } +} diff --git a/plugins/auto-date/auto-date.yaml b/plugins/auto-date/auto-date.yaml new file mode 100755 index 0000000..d4ca941 --- /dev/null +++ b/plugins/auto-date/auto-date.yaml @@ -0,0 +1 @@ +enabled: true diff --git a/plugins/auto-date/blueprints.yaml b/plugins/auto-date/blueprints.yaml new file mode 100755 index 0000000..2988d51 --- /dev/null +++ b/plugins/auto-date/blueprints.yaml @@ -0,0 +1,30 @@ +name: Auto Date +version: 1.0.2 +description: Automatically adds date to frontmatter when creating a new page via Grav Admin plugin +icon: clock-o +author: + name: Team Grav + email: devs@getgrav.org + url: http://getgrav.org +homepage: https://github.com/getgrav/grav-plugin-auto-date +keywords: plugin, auto-date, date, frontmatter +bugs: https://github.com/getgrav/grav-plugin-auto-date/issues +docs: https://github.com/getgrav/grav-plugin-auto-date/blob/develop/README.md +license: MIT + +dependencies: + - { name: admin, version: '>=1.2.3' } + +form: + validation: strict + fields: + enabled: + type: toggle + label: Plugin status + highlight: 1 + default: 0 + options: + 1: Enabled + 0: Disabled + validate: + type: bool diff --git a/plugins/autoseo/.gitignore b/plugins/autoseo/.gitignore new file mode 100755 index 0000000..6c224e0 --- /dev/null +++ b/plugins/autoseo/.gitignore @@ -0,0 +1,41 @@ +# Cache and logs (Symfony2) +/app/cache/* +/app/logs/* +!app/cache/.gitkeep +!app/logs/.gitkeep + +# Email spool folder +/app/spool/* + +# Cache, session files and logs (Symfony3) +/var/cache/* +/var/logs/* +/var/sessions/* +!var/cache/.gitkeep +!var/logs/.gitkeep +!var/sessions/.gitkeep + +# Parameters +/app/config/parameters.yml +/app/config/parameters.ini + +# Managed by Composer +/app/bootstrap.php.cache +/var/bootstrap.php.cache +/bin/* +!bin/console +!bin/symfony_requirements + +# Assets and user uploads +/web/bundles/ +/web/uploads/ + +# PHPUnit +/app/phpunit.xml +/phpunit.xml + +# Build data +/build/ + +# Backup entities generated with doctrine:generate:entities command +**/Entity/*~ diff --git a/plugins/autoseo/CHANGELOG.md b/plugins/autoseo/CHANGELOG.md new file mode 100755 index 0000000..9c05251 --- /dev/null +++ b/plugins/autoseo/CHANGELOG.md @@ -0,0 +1,134 @@ +# v1.4.0 +## 04/08/2022 + +1. []() + * takeover release +2. [](#bugfix) + * do not crash on mbregex search failure in php_mbereg_replace_exec. + +# v1.3.5 +## 01/26/2018 + +1. [](#bugfix) + * fix release dates in changelog. + +# v1.3.3 +## 01/26/2018 + +1. [](#bugfix) + * replace meta title content by page title instead of page slug. + +# v1.3.2 +## 01/10/2018 + +1. [](#bugfix) + * The meta tag fields were wrongly named "property" instead of "name". + +# v1.3.1 +## 08/03/2017 + +1. [](#improved) + * Add Admin plugin dependency (Dávid Szabó ) + * Use Slug utility function (Dávid Szabó +## Bug reports + +A bug is a _demonstrable problem_ that is caused by the code in the repository. +Good bug reports are extremely helpful - thank you! + +Guidelines for bug reports: + +1. **Check you satisfy the Grav requirements** — [http://learn.getgrav.org/basics/requirements](http://learn.getgrav.org/basics/requirements) + +1. **Check this happens on a new Plugin install** — remove and re-install the plugin. Reset the plugin to its default configuration. + +1. **Check this happens on a clean Grav install** — check if the issue happens on any Grav site, or just with a specific configuration of plugins / theme + +1. **Use the GitHub issue search** — check if the issue has already been + reported. + +1. **Check if the issue is already being solved in a PR** — check the open Pull Requests to see if one already solves the problem you're having + +1. **Check if the issue has been fixed** — try to reproduce it using the + latest `develop` branch in the repository. + +1. **Isolate the problem** — create a [reduced test + case](http://css-tricks.com/reduced-test-cases/) and provide a step-by-step instruction set on how to recreate the problem. Include code samples, page snippets or yaml configurations if needed. + +A good bug report shouldn't leave others needing to chase you up for more +information. Please try to be as detailed as possible in your report. + +What is your environment? Is it localhost, OSX, Linux, on a remote server? Same happening locally and or the server, or just locally or just on Linux? + +What steps will reproduce the issue? What browser(s) and OS experience the problem? + +What would you expect to be the outcome? + +Did the problem start happening recently (e.g. after updating to a new version of this plugin) or was this always a problem? + +If the problem started happening recently, can you reproduce the problem in an older version of this plugin ? What's the most recent version in which the problem doesn't happen? You can download older versions from the releases page on Github. + +Can you reliably reproduce the issue? If not, provide details about how often the problem happens and under which conditions it normally happens. + + +All these details will help people to fix any potential bugs. + +Important: [include Code Samples in triple backticks](https://help.github.com/articles/github-flavored-markdown/#fenced-code-blocks) so that Github will provide a proper indentation. [Add the language name after the backticks](https://help.github.com/articles/github-flavored-markdown/#syntax-highlighting) to add syntax highlighting to the code snippets. + +Example: + +> Short and descriptive example bug report title +> +> A summary of the issue and the browser/OS environment in which it occurs. If +> suitable, include the steps required to reproduce the bug. +> +> 1. This is the first step +> 2. This is the second step +> 3. Further steps, etc. +>> +> Any other information you want to share that is relevant to the issue being +> reported. This might include the lines of code that you have identified as +> causing the bug, and potential solutions (and your opinions on their +> merits). + + + +## Feature requests + +Feature requests are welcome. But take a moment to find out whether your idea +fits with the scope and aims of the project. It's up to *you* to make a strong +case to convince the project's developers of the merits of this feature. Please +provide as much detail and context as possible. + + + +## Pull requests + +Good pull requests - patches, improvements, new features - are a fantastic +help. They should remain focused in scope and avoid containing unrelated +commits. + +Please adhere to the coding conventions used throughout the GRAV project (indentation, +accurate comments, etc.) and any other requirements. +**Please also respect the plugin specific conventions if any.** + +See [Using Pull Request](https://help.github.com/articles/using-pull-requests/) and [Fork a Repo](https://help.github.com/articles/fork-a-repo/) if you're not familiar with Pull Requests. + +Any pull request should be based on the `develop` branch. We will not consider pull requests made to master. + +**IMPORTANT**: By submitting a patch, you agree to allow the project owner to +license your work under the same license as that used by the project. + + +### Translations +Translations for this plugin are managed by direct request. Just send me an mail with your translation file. diff --git a/plugins/autoseo/LICENSE b/plugins/autoseo/LICENSE new file mode 100755 index 0000000..681d44e --- /dev/null +++ b/plugins/autoseo/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Laurent Ongaro + +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/plugins/autoseo/README.md b/plugins/autoseo/README.md new file mode 100755 index 0000000..c784ffb --- /dev/null +++ b/plugins/autoseo/README.md @@ -0,0 +1,114 @@ +# [Grav](http://getgrav.org) AutoSEO + +This is the new home of AutoSEO. +I tried to contact the original author (Laurent), but the email bounced back + + +Grav AutoSEO is a plugin for Grav with which you can fill automatically the description and keywords metadata of a page using its content. +It also adds Facebook Open Graph metadata and Twitter Cards Meta Tags (**New** feature since the 1.2 version). + +If the plugin is enabled and **the description and keyword metadata of the page are not manually filled** (i.e. the page headers contains some metadata fields), +the plugin will use the first words of the page summary to fill the description and its categories and tags to fill the keyword metadata. +Facebook and twitter metadata will also be filled if they are enabled in settings and not manually filled in the page header. + +## Installation + +### Manual Installation + +To install this plugin, just download the zip version of this repository and unzip it under `/your/site/grav/user/plugins`. Then rename the folder to `autoseo`. + +You should now have all the plugin files under + +`/your/site/grav/user/plugins/autoseo` + +## Configuration + +Here is the default configuration and an explanation of available options: + +`autoseo.yaml:` + +```yaml +enabled: true # lets you turn the plugin off and on. +description: + enabled: true # lets you turn the plugin off and on for the "description" metadata. + length: 30 # maximal number of words that will be used to fill the "description" metadata. +keywords: + enabled: true # lets you turn the plugin off and on for the "keywords" metadata. + length: 20 # maximal number of words that will be used to fill the "keywords" metadata. +facebook: + enabled: true # Lets you turn the plugin ON and OFF for the "Facebook Open Graph" metadata. +twitter: + enabled: true # Lets you turn the plugin ON and OFF for the "Twitter Cards" metadata. +``` + + * The first `enabled` field lets you turn the plugin on and off. + * The `enabled` field in each metadata section lets you turn on and off the plugin for this metadata only. + * `length` is the maximal count of words that will be used to fill the corresponding metadata. + +If you need to change any value, then the best process is to copy the `autoseo.yaml` file into your `users/config/plugins/` folder (create it if it doesn't exist), and then modify there. This will override the default settings. + +## Per-Page Configuration + +If you want to alter the settings for one or a few pages only, you can do so by adding page specific configurations into your page headers, e.g. + +```yaml +autoseo: false +``` +to disable the `AutoSeo` plugin just for this page. + +Remember you can also override the general plugin settings for a specific page by adding settings in its header. For instance, adding the following lines in a page headers + +```yaml +autoseo: + enabled: true + description: + enabled: true + length: 10 + keywords: + enabled: true + length: 10 + facebook: + enabled: true + twitter: + enabled: false +``` + +will change the description and keyword lengths to 10 words for these page only, enable Facebook Open Graph metadata and disable Twitter Cards tags. + +## Usage + +There's not much to do with this plugin, simply install, enabled it and check its configuration to meet your needs. + +No need to do anything else. + +### Demo + +The plugin is installed and enabled on the following blog : [http://www.gamecoderblog.com](http://www.gamecoderblog.com). + +To see it in action, you have to inspect the meta of the page code source. +**(Use a page other than the home page, because the metadata used in it are those set in the blog configuration)** + +### Performances + +As each page must be analyzed and its content filtered by the plugins, the impact on performance can be important when first access to a page. +But as the result will be cached, once the first analysis is done, you will find no further negative performance impact. + +To limit the impact on performance, **the content analyzed will always be truncated to the 1000 first characters for description metadata**, then the limit given by the `length` setting will be applied. + +### Notes + +`AutoSeo` will make a few cleaning but won't check the content used to auto fill the metadata. +So be sure that the first words of your content (the summary) will be correct to be used as a description. +In a same way, check that the tags and categories of the page are OK to be used as keyword. + +### Bugs And TODO + +Please send any comments or bug reports to the plugin's issue tracker. + +#### TODO + +* No new feature is planned for the moment. + +### Authors + +`AutoSeo` was developed and maintained by Laurent Ongaro and is now looked after by Nuno Costa. diff --git a/plugins/autoseo/autoseo.php b/plugins/autoseo/autoseo.php new file mode 100755 index 0000000..a8331af --- /dev/null +++ b/plugins/autoseo/autoseo.php @@ -0,0 +1,247 @@ + ['onPluginsInitialized', 0], + ]; + } + /** + * Register events with Grav + * @return void + */ + public function onPluginsInitialized() + { + // deactivate plugin in admin + if ( !$this->isAdmin() + and $this->config->get('plugins.autoseo.enabled') + ) { + $this->enable([ + 'onPageInitialized' => ['onPageInitialized', 0] + ]); + } + } + + /** + * Add content after page content was read into the system. + * + */ + public function onPageInitialized() + { + $page = $this->grav['page']; + $config = $this->mergeConfig($page); + if ( !$config['enabled']) return; + + $updateDescription = $config['description.enabled']; + $updatekeywords = $config['keywords.enabled']; + $updateFacebook = $config['facebook.enabled']; + $updateTwitter = $config['twitter.enabled']; + if (!$updateDescription && !$updatekeywords && !$updateFacebook && !$updateTwitter) return; + + $meta = $page->metadata(); + + $metaSite = $this->config->get('site')['metadata']; + + // limit the content size to reduce the performance impact + $content = mb_substr(strip_tags($page->content()),0, 1000 ); + + $cleanContent = $this->cleanText ($content, $config); // here because we don't want to make this call several times + $cleanTitle = $this->cleanString ($page->title()); // here because we don't want to make this call several times + + if ($updateDescription) $meta = $this->getMetaDescription ($meta, $metaSite, $config, $cleanContent); + if ($updatekeywords) $meta = $this->getMetaKeywords ($meta, $metaSite, $config); + if ($updateFacebook) $meta = $this->getMetaOpenGraph ($meta, $metaSite, $config, $cleanContent, $cleanTitle); + if ($updateTwitter) $meta = $this->getMetaTwitter ($meta, $metaSite, $config, $cleanContent, $cleanTitle); + $page->metadata ($meta); + } + + // PROCESS for the description metadata + private function getMetaDescription ($meta, $metaSite, $config, $cleanContent) { + + if (array_key_exists('description', $metaSite)) { $metaSiteContent = htmlspecialchars($metaSite['description'], ENT_QUOTES, 'UTF-8'); } else { $metaSiteContent = ''; } + // if the page has a meta that is different from the default one, we return its value + if (!empty($meta['description']['content']) && $meta['description']['content'] != $metaSiteContent) return $meta; + + $metaPageContent = $cleanContent; + + if (empty($metaPageContent)) $metaPageContent = $metaSiteContent; + + $meta['description'] = [ 'name' => 'description', 'content' => $metaPageContent]; + return $meta; + } + + // PROCESS for the keywords metadata + private function getMetaKeywords ($meta, $metaSite, $config) { + $page = $this->grav['page']; + + if (array_key_exists('keywords', $metaSite)) { $metaSiteContent = htmlspecialchars($metaSite['keywords'], ENT_QUOTES, 'UTF-8'); } else { $metaSiteContent = ''; } + + // if the page has a meta that is different from the default one, we return its value + if (!empty($meta['keywords']['content']) && $meta['keywords']['content'] != $metaSiteContent) return $meta; + $length = $config['keywords.length']; + if ($length <=1 ) $length=20; + + // we create a keywords list using the page tags and categories + if (array_key_exists( 'category', $page->taxonomy() )) { $categories = $page->taxonomy()['category']; } else { $categories = []; } + if (array_key_exists( 'tag', $page->taxonomy() )) { $tags = $page->taxonomy()['tag']; } else { $tags = []; } + + $content = array_merge ($categories, $tags) ; + $content = array_unique ($content); + $content = array_slice($content, 0, $length); + $content = join(',',$content); + $content = $this->cleanString($content); + $metaPageContent = $content; + if (empty($metaPageContent)) $metaPageContent = $metaSiteContent; + + $meta['keywords'] = [ 'name' => 'keywords', 'content' => $metaPageContent]; + return $meta; + } + + // PROCESS for the OpenGraph metadata + private function getMetaOpenGraph ($meta, $metaSite, $config, $cleanContent, $cleanTitle) { + $page = $this->grav['page']; + + $meta['og:sitename']['name'] = 'og:sitename'; + $meta['og:sitename']['property'] = 'og:sitename'; + $meta['og:sitename']['content'] = $this->config->get('site.title'); + $meta['og:title']['name'] = 'og:title'; + $meta['og:title']['property'] = 'og:title'; + $meta['og:title']['content'] = $cleanTitle; + $meta['og:type']['name'] = 'og:type'; + $meta['og:type']['property'] = 'og:type'; + $meta['og:type']['content'] = 'article'; + $meta['og:url']['name'] = 'og:url'; + $meta['og:url']['property'] = 'og:url'; + $meta['og:url']['content'] = $this->grav['uri']->url(true); + $meta['og:description']['name'] = 'og:description'; + $meta['og:description']['property'] = 'og:description'; + if (empty($cleanContent)) $cleanContent = $meta['description']['content']; + else { + if (array_key_exists('description', $metaSite)) { $metaSiteContent = htmlspecialchars($metaSite['description'], ENT_QUOTES, 'UTF-8'); } else { $metaSiteContent = ''; } + if ($meta['description']['content'] != $metaSiteContent) $cleanContent = $meta['description']['content']; + } + + $meta['og:description']['content'] = $cleanContent; + + if (!empty($page->value('media.image'))) { + $images = $page->media()->images(); + $image = array_shift($images); + $meta['og:image']['name'] = 'og:image'; + $meta['og:image']['property'] = 'og:image'; + $meta['og:image']['content'] = $this->grav['uri']->base() . $image->url(); + } + return $meta; + } + + // PROCESS for the twitter metadata + private function getMetaTwitter ($meta, $metaSite, $config, $cleanContent, $cleanTitle) { + $page = $this->grav['page']; + + if (!isset($meta['twitter:card'])) { + $meta['twitter:card']['name'] = 'twitter:card'; + $meta['twitter:card']['property'] = 'twitter:card'; + $meta['twitter:card']['content'] = 'summary_large_image'; + } + + if (!isset($meta['twitter:title'])) { + $meta['twitter:title']['name'] = 'twitter:title'; + $meta['twitter:title']['property'] = 'twitter:title'; + $meta['twitter:title']['content'] = $cleanTitle; + } + + if (!isset($meta['twitter:description'])) { + $meta['twitter:description']['name'] = 'twitter:description'; + $meta['twitter:description']['property'] = 'twitter:description'; + if (empty($cleanContent)) + $cleanContent = $meta['description']['content']; + else { + if (array_key_exists('description', $metaSite)) { $metaSiteContent = htmlspecialchars($metaSite['description'], ENT_QUOTES, 'UTF-8'); } else { $metaSiteContent = ''; } + if ($meta['description']['content'] != $metaSiteContent) $cleanContent = $meta['description']['content']; + } + $meta['twitter:description']['content'] = mb_substr($cleanContent,0,140); + } + + if (!isset($meta['twitter:image'])) { + if (!empty($page->value('media.image'))) { + $images = $page->media()->images(); + $image = array_shift($images); + $meta['twitter:image']['name'] = 'twitter:image'; + $meta['twitter:image']['property'] = 'twitter:image'; + $meta['twitter:image']['content'] = $this->grav['uri']->base() . $image->url(); + } + } + return $meta; + } + + private function cleanMarkdown($text){ + $rules = array ( + '/(#+)(.*)/' => '\2', // headers + '/(<|<)!--\n((.*|\n)*)\n--(>|\>)/' => '', // comments + '/(\*|-|_){3}/' => '', // hr + '/!\[([^\[]+)\]\(([^\)]+)\)/' => '', // images + '/\[([^\[]+)\]\(([^\)]+)\)/' => '\1', // links + '/(\*\*|__)(.*?)\1/' => '\2', // bold + '/(\*|_)(.*?)\1/' => '\2', // emphasis + '/\~\~(.*?)\~\~/' => '\1', // del + '/\:\"(.*?)\"\:/' => '\1', // quote + '/```(.*)\n((.*|\n)+)\n```/' => '\2', // fence code + '/`(.*?)`/' => '\1', // inline code + '/(\*|\+|-)(.*)/' => '\2', // ul lists + '/\n[0-9]+\.(.*)/' => '\2', // ol lists + '/(>|\>)+(.*)/' => '\2', // blockquotes + ); + foreach ($rules as $regex => $replacement) { + if (is_callable ( $replacement)) { + $text = preg_replace_callback ($regex, $replacement, $text); + } else { + $text = preg_replace ($regex, $replacement, $text); + } + } + $text=str_replace(".\n", '.', $text); + $text=str_replace("\n", '.', $text); + $text=str_replace('"', '', $text); + + return htmlspecialchars($text, ENT_QUOTES, 'UTF-8'); + } + + private function cleanText ($content, $config) { + try { + + $length = $config['description.length']; + if ($length <=1 ) $length=20; + + $content = $this->cleanMarkdown($content); + // truncate the content to the number of words set in config + $contentSmall = mb_ereg_replace('((\w+\W*){'.$length.'}(\w+))(.*)', '\\1', $content); // beware if content is less than length words, it will be nulled + if ($contentSmall == '' ) $contentSmall = $content; + + return $contentSmall; + } catch (\Throwable $e) { + $this->grav['log']->addError($e->getMessage()); + + return $content; + } + } + + private function cleanString ($content) { + // remove some annoying characters + $content = str_replace(" ",' ',$content); + $content = str_replace('"',"'",$content); + $content = trim($content); + // Removes special chars. + // $content = \Grav\Plugin\Admin\Utils::slug($content); + return $content; + } +} diff --git a/plugins/autoseo/autoseo.yaml b/plugins/autoseo/autoseo.yaml new file mode 100755 index 0000000..0650cb2 --- /dev/null +++ b/plugins/autoseo/autoseo.yaml @@ -0,0 +1,11 @@ +enabled: true # lets you turn the plugin off and on. +description: + enabled: true # lets you turn the plugin off and on for the "description" metadata. + length: 30 # maximal number of words that will be used to fill the "description" metadata. +keywords: + enabled: true # lets you turn the plugin off and on for the "keywords" metadata. + length: 20 # maximal number of words that will be used to fill the "keywords" metadata. +facebook: + enabled: true # Lets you turn the plugin ON and OFF for the "Facebook Open Graph" metadata. +twitter: + enabled: true # Lets you turn the plugin ON and OFF for the "Twitter Cards" metadata. \ No newline at end of file diff --git a/plugins/autoseo/blueprints.yaml b/plugins/autoseo/blueprints.yaml new file mode 100755 index 0000000..d3afc4b --- /dev/null +++ b/plugins/autoseo/blueprints.yaml @@ -0,0 +1,107 @@ +name: Auto SEO +version: 1.4.0 +description: Grav AutoSEO is a plugin for Grav with which you can fill automatically the description and keywords metadata of a page using its content. It also adds Facebook Open Graph metadata and Twitter Cards Meta Tags. +icon: magic +author: + name: Nuno Costa + email: info@codehaha.com + url: http://www.codehaha.com +homepage: https://github.com/francodacosta/grav-plugin-autoseo +keywords: plugin, seo, metadata extraction, auto fill +bugs: https://github.com/francodacosta/grav-plugin-autoseo/issues +docs: https://github.com/francodacosta/grav-plugin-autoseo/blob/master/README.md +license: MIT +dependencies: + - { name: admin, version: '>=1.5.0' } + +form: + validation: strict + fields: + + global: + type: section + title: PLUGINS.AUTO_SEO.GLOBAL_CONFIG + underline: 1 + + fields: + enabled: + type: toggle + label: PLUGINS.AUTO_SEO.PLUGIN_STATUS + highlight: 1 + default: 0 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + + metadata: + type: section + title: PLUGINS.AUTO_SEO.DEFAULT_CONFIG + underline: 1 + + fields: + description.enabled: + type: toggle + label: PLUGINS.AUTO_SEO.DESCRIPTION.ENABLED_LABEL + help: PLUGINS.AUTO_SEO.DESCRIPTION.ENABLED_HELP + highlight: 1 + default: 0 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + description.length: + type: text + size: x-small + label: PLUGINS.AUTO_SEO.DESCRIPTION.LENGTH_LABEL + help: PLUGINS.AUTO_SEO.DESCRIPTION.LENGTH_HELP + default: 30 + validate: + type: number + min: 2 + max: 50 + keywords.enabled: + type: toggle + label: PLUGINS.AUTO_SEO.KEYWORDS.ENABLED_LABEL + help: PLUGINS.AUTO_SEO.KEYWORDS.ENABLED_HELP + highlight: 1 + default: 0 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + keywords.length: + type: text + size: x-small + label: PLUGINS.AUTO_SEO.KEYWORDS.LENGTH_LABEL + help: PLUGINS.AUTO_SEO.KEYWORDS.LENGTH_HELP + default: 20 + validate: + type: number + min: 2 + max: 30 + facebook.enabled: + type: toggle + label: PLUGINS.AUTO_SEO.FACEBOOK.ENABLED_LABEL + help: PLUGINS.AUTO_SEO.FACEBOOK.ENABLED_HELP + highlight: 1 + default: 0 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + twitter.enabled: + type: toggle + label: PLUGINS.AUTO_SEO.TWITTER.ENABLED_LABEL + help: PLUGINS.AUTO_SEO.TWITTER.ENABLED_HELP + highlight: 1 + default: 0 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool diff --git a/plugins/autoseo/languages.yaml b/plugins/autoseo/languages.yaml new file mode 100755 index 0000000..9829a9d --- /dev/null +++ b/plugins/autoseo/languages.yaml @@ -0,0 +1,49 @@ +# English +en: + PLUGINS: + AUTO_SEO: + GLOBAL_CONFIG: Global configuration + PLUGIN_STATUS: Plugin status + DEFAULT_CONFIG: Default values for the plugin configuration + PLUGIN_DEPENDENCY_FAILED: Auto SEO Plugin failed to load. Composer dependencies not met. + DESCRIPTION: + ENABLED_LABEL: Auto fill for "description" meta + ENABLED_HELP: Lets you turn the plugin ON and OFF for the "description" metadata only. + LENGTH_LABEL: Maximum word count for "description" meta + LENGTH_HELP: The maximum count of words that will be used to fill the "description" metadata. + KEYWORDS: + ENABLED_LABEL: Auto fill for the "keywords" meta + ENABLED_HELP: Lets you turn the plugin ON and OFF for the "keywords" metadata only. + LENGTH_LABEL: Maximum word count for "keywords" meta. + LENGTH_HELP: The maximum count of words that will be used to fill the "keyword" metadata. + FACEBOOK: + ENABLED_LABEL: Auto fill for the Open Graph tags (facebook) + ENABLED_HELP: Lets you turn the plugin ON and OFF for the "Open Graph" metadata (facebook). + TWITTER: + ENABLED_LABEL: Auto fill for the Twitter tags + ENABLED_HELP: Lets you turn the plugin ON and OFF for the "Twitter Cards" metadata. + +# French +fr: + PLUGINS: + AUTO_SEO: + GLOBAL_CONFIG: Configuration globale + PLUGIN_STATUS: Etat du plugin + DEFAULT_CONFIG: Valeurs par défaut pour la configuration du plugin + PLUGIN_DEPENDENCY_FAILED: le plug-in Auto SEO n'a pas pu être chargé. Les dépendances de Composer ne sont pas remplies. + DESCRIPTION: + ENABLED_LABEL: Remplissage automatique pour la méta "Description" + ENABLED_HELP: Permet de mettre le plugin ON et OFF pour la métadonnée "Description" uniquement. + LENGTH_LABEL: nombre maximal de mots pour la méta "Description" + LENGTH_HELP: le nombre maximum de mots qui seront utilisés pour remplir la métadonnée "Description". + KEYWORDS: + ENABLED_LABEL: Remplissage automatique pour la méta "Keywords" + ENABLED_HELP: Permet de mettre le plugin ON et OFF pour la métadonnée "Keywords" uniquement. + LENGTH_LABEL: Nombre maximal de mots pour la méta "Keywords". + LENGTH_HELP: Le nombre maximum de mots qui seront utilisés pour remplir la métadonnée "Keywords". + FACEBOOK: + ENABLED_LABEL: Remplissage automatique pour les tags Open Graph (facebook) + ENABLED_HELP: Permet de mettre le plugin ON et OFF pour la métadonnée "Open Graph" (facebook). + TWITTER: + ENABLED_LABEL: Remplissage automatique pour les tags Twitter + ENABLED_HELP: Permet de mettre le plugin ON et OFF pour la métadonnée "Twitter Cards". diff --git a/plugins/childlist/CHANGELOG.md b/plugins/childlist/CHANGELOG.md new file mode 100755 index 0000000..75d7e63 --- /dev/null +++ b/plugins/childlist/CHANGELOG.md @@ -0,0 +1,5 @@ +# v0.1.0 +## 07/14/2020 + +1. [](#new) + * ChangeLog started... diff --git a/plugins/childlist/LICENSE b/plugins/childlist/LICENSE new file mode 100755 index 0000000..82f90bb --- /dev/null +++ b/plugins/childlist/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2020 armansansd + +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/plugins/childlist/README.md b/plugins/childlist/README.md new file mode 100755 index 0000000..cebb79a --- /dev/null +++ b/plugins/childlist/README.md @@ -0,0 +1,56 @@ +# Childlist Plugin + +**This README.md file should be modified to describe the features, installation, configuration, and general usage of the plugin.** + +The **Childlist** Plugin is an extension for [Grav CMS](http://github.com/getgrav/grav). display a list of children page in admin + +## Installation + +Installing the Childlist plugin can be done in one of three ways: The GPM (Grav Package Manager) installation method lets you quickly install the plugin with a simple terminal command, the manual method lets you do so via a zip file, and the admin method lets you do so via the Admin Plugin. + +### GPM Installation (Preferred) + +To install the plugin via the [GPM](http://learn.getgrav.org/advanced/grav-gpm), through your system's terminal (also called the command line), navigate to the root of your Grav-installation, and enter: + + bin/gpm install childlist + +This will install the Childlist plugin into your `/user/plugins`-directory within Grav. Its files can be found under `/your/site/grav/user/plugins/childlist`. + +### Manual Installation + +To install the plugin manually, download the zip-version of this repository and unzip it under `/your/site/grav/user/plugins`. Then rename the folder to `childlist`. You can find these files on [GitHub](https://github.com//grav-plugin-childlist) or via [GetGrav.org](http://getgrav.org/downloads/plugins#extras). + +You should now have all the plugin files under + + /your/site/grav/user/plugins/childlist + +> NOTE: This plugin is a modular component for Grav which may require other plugins to operate, please see its [blueprints.yaml-file on GitHub](https://github.com//grav-plugin-childlist/blob/master/blueprints.yaml). + +### Admin Plugin + +If you use the Admin Plugin, you can install the plugin directly by browsing the `Plugins`-menu and clicking on the `Add` button. + +## Configuration + +Before configuring this plugin, you should copy the `user/plugins/childlist/childlist.yaml` to `user/config/plugins/childlist.yaml` and only edit that copy. + +Here is the default configuration and an explanation of available options: + +```yaml +enabled: true +``` + +Note that if you use the Admin Plugin, a file with your configuration named childlist.yaml will be saved in the `user/config/plugins/`-folder once the configuration is saved in the Admin. + +## Usage + +**Describe how to use the plugin.** + +## Credits + +**Did you incorporate third-party code? Want to thank somebody?** + +## To Do + +- [ ] Future plans, if any + diff --git a/plugins/childlist/blueprints.yaml b/plugins/childlist/blueprints.yaml new file mode 100755 index 0000000..7e81a81 --- /dev/null +++ b/plugins/childlist/blueprints.yaml @@ -0,0 +1,36 @@ +name: Childlist +slug: childlist +type: plugin +version: 0.1.0 +description: display a list of children page in admin +icon: plug +author: + name: armansansd + email: contact@armansansd.net +homepage: https://github.com/armansansd/grav-plugin-childlist +demo: http://demo.yoursite.com +keywords: grav, plugin, etc +bugs: https://github.com/armansansd/grav-plugin-childlist/issues +docs: https://github.com/armansansd/grav-plugin-childlist/blob/develop/README.md +license: MIT + +dependencies: + - { name: grav, version: '>=1.6.0' } + +form: + validation: loose + fields: + enabled: + type: toggle + label: PLUGIN_ADMIN.PLUGIN_STATUS + highlight: 1 + default: 0 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + text_var: + type: text + label: PLUGIN_CHILDLIST.TEXT_VARIABLE + help: PLUGIN_CHILDLIST.TEXT_VARIABLE_HELP diff --git a/plugins/childlist/childlist.php b/plugins/childlist/childlist.php new file mode 100755 index 0000000..fec98b4 --- /dev/null +++ b/plugins/childlist/childlist.php @@ -0,0 +1,64 @@ + [ + ['autoload', 100000], // TODO: Remove when plugin requires Grav >=1.7 + ['onPluginsInitialized', 0] + ] + ]; + } + + /** + * Composer autoload. + *is + * @return ClassLoader + */ + public function autoload(): ClassLoader + { + return require __DIR__ . '/vendor/autoload.php'; + } + + /** + * Initialize the plugin + */ + public function onPluginsInitialized() + { + // Don't proceed if we are in the admin plugin + // if ($this->isAdmin()) { + // return; + // } + + // Enable the main events we are interested in + $this->enable([ + // Put your main events here + ]); + } + public function onAdminTwigTemplatePaths($event){ + $paths = $event['paths']; + $paths[] = __DIR__ . '/admin/themes/grav/templates'; + $event['paths'] = $paths; + } +} diff --git a/plugins/childlist/childlist.yaml b/plugins/childlist/childlist.yaml new file mode 100755 index 0000000..edbe8cb --- /dev/null +++ b/plugins/childlist/childlist.yaml @@ -0,0 +1,3 @@ +enabled: true +activate: true +text_var: Custom Text added by the **Childlist** plugin (disable plugin to remove) diff --git a/plugins/childlist/composer.json b/plugins/childlist/composer.json new file mode 100755 index 0000000..2888534 --- /dev/null +++ b/plugins/childlist/composer.json @@ -0,0 +1,29 @@ +{ + "name": "armansansd/childlist", + "type": "grav-plugin", + "description": "display a list of children page in admin", + "keywords": ["plugin"], + "homepage": "https://github.com/armansansd/grav-plugin-childlist", + "license": "MIT", + "authors": [ + { + "name": "armansansd", + "email": "contact@armansansd.net", + "role": "Developer" + } + ], + "require": { + "php": ">=7.1.3" + }, + "autoload": { + "psr-4": { + "Grav\\Plugin\\Childlist\\": "classes/" + }, + "classmap": ["childlist.php"] + }, + "config": { + "platform": { + "php": "7.1.3" + } + } +} diff --git a/plugins/childlist/composer.lock b/plugins/childlist/composer.lock new file mode 100755 index 0000000..405b6d9 --- /dev/null +++ b/plugins/childlist/composer.lock @@ -0,0 +1,23 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "7d150ab33e09ea524591068542a890b2", + "packages": [], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.1.3" + }, + "platform-dev": [], + "platform-overrides": { + "php": "7.1.3" + }, + "plugin-api-version": "1.1.0" +} diff --git a/plugins/childlist/languages.yaml b/plugins/childlist/languages.yaml new file mode 100755 index 0000000..7ba9169 --- /dev/null +++ b/plugins/childlist/languages.yaml @@ -0,0 +1,4 @@ +en: + PLUGIN_CHILDLIST: + TEXT_VARIABLE: Text Variable + TEXT_VARIABLE_HELP: Text to add to the top of a page diff --git a/plugins/childlist/template/form/fields/childlist/childlist.html.twig b/plugins/childlist/template/form/fields/childlist/childlist.html.twig new file mode 100755 index 0000000..3b04284 --- /dev/null +++ b/plugins/childlist/template/form/fields/childlist/childlist.html.twig @@ -0,0 +1,9 @@ +{% extends "forms/field.html.twig" %} + +{% block input_attributes %} + type="range" + {% if field.validate.min %}min="{{ field.validate.min }}"{% endif %} + {% if field.validate.max %}max="{{ field.validate.max }}"{% endif %} + {% if field.validate.step %}step="{{ field.validate.step }}"{% endif %} + {{ parent() }} +{% endblock %} diff --git a/plugins/childlist/vendor/autoload.php b/plugins/childlist/vendor/autoload.php new file mode 100755 index 0000000..0c74a6d --- /dev/null +++ b/plugins/childlist/vendor/autoload.php @@ -0,0 +1,7 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see http://www.php-fig.org/psr/psr-0/ + * @see http://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + + private $useIncludePath = false; + private $classMap = array(); + private $classMapAuthoritative = false; + private $missingClasses = array(); + private $apcuPrefix; + + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', $this->prefixesPsr0); + } + + return array(); + } + + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return bool|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; +} diff --git a/plugins/childlist/vendor/composer/LICENSE b/plugins/childlist/vendor/composer/LICENSE new file mode 100755 index 0000000..f27399a --- /dev/null +++ b/plugins/childlist/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/plugins/childlist/vendor/composer/autoload_classmap.php b/plugins/childlist/vendor/composer/autoload_classmap.php new file mode 100755 index 0000000..7131927 --- /dev/null +++ b/plugins/childlist/vendor/composer/autoload_classmap.php @@ -0,0 +1,10 @@ + $baseDir . '/childlist.php', +); diff --git a/plugins/childlist/vendor/composer/autoload_namespaces.php b/plugins/childlist/vendor/composer/autoload_namespaces.php new file mode 100755 index 0000000..b7fc012 --- /dev/null +++ b/plugins/childlist/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($baseDir . '/classes'), +); diff --git a/plugins/childlist/vendor/composer/autoload_real.php b/plugins/childlist/vendor/composer/autoload_real.php new file mode 100755 index 0000000..ff5b708 --- /dev/null +++ b/plugins/childlist/vendor/composer/autoload_real.php @@ -0,0 +1,55 @@ += 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); + if ($useStaticLoader) { + require_once __DIR__ . '/autoload_static.php'; + + call_user_func(\Composer\Autoload\ComposerStaticInit910efd51a496a8e9d2c9ce9e3608936d::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + } + + $loader->register(true); + + return $loader; + } +} diff --git a/plugins/childlist/vendor/composer/autoload_static.php b/plugins/childlist/vendor/composer/autoload_static.php new file mode 100755 index 0000000..a100b23 --- /dev/null +++ b/plugins/childlist/vendor/composer/autoload_static.php @@ -0,0 +1,36 @@ + + array ( + 'Grav\\Plugin\\Childlist\\' => 22, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Grav\\Plugin\\Childlist\\' => + array ( + 0 => __DIR__ . '/../..' . '/classes', + ), + ); + + public static $classMap = array ( + 'Grav\\Plugin\\ChildlistPlugin' => __DIR__ . '/../..' . '/childlist.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInit910efd51a496a8e9d2c9ce9e3608936d::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit910efd51a496a8e9d2c9ce9e3608936d::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInit910efd51a496a8e9d2c9ce9e3608936d::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/plugins/childlist/vendor/composer/installed.json b/plugins/childlist/vendor/composer/installed.json new file mode 100755 index 0000000..fe51488 --- /dev/null +++ b/plugins/childlist/vendor/composer/installed.json @@ -0,0 +1 @@ +[] diff --git a/plugins/cookieconsent/.gitignore b/plugins/cookieconsent/.gitignore new file mode 100755 index 0000000..40df0b2 --- /dev/null +++ b/plugins/cookieconsent/.gitignore @@ -0,0 +1,10 @@ +.DS_Store +.idea +vendor +composer.phar +composer.lock +phpunit.xml +tests/_output/* +tests/_output/* +tests/_output/* +tests/_output/* \ No newline at end of file diff --git a/plugins/cookieconsent/.scrutinizer.yml b/plugins/cookieconsent/.scrutinizer.yml new file mode 100755 index 0000000..1809b3d --- /dev/null +++ b/plugins/cookieconsent/.scrutinizer.yml @@ -0,0 +1,8 @@ +build: + tests: + override: + - + command: 'vendor/bin/codecept run --coverage --coverage-xml' + coverage: + file: 'tests/_output/coverage.xml' + format: 'clover' \ No newline at end of file diff --git a/plugins/cookieconsent/.travis.yml b/plugins/cookieconsent/.travis.yml new file mode 100755 index 0000000..160a7cb --- /dev/null +++ b/plugins/cookieconsent/.travis.yml @@ -0,0 +1,19 @@ +language: php + +php: + - 5.5 + - 5.6 + - 7.0 + - 7.1 + - 7.2 + - hhvm + +matrix: + allow_failures: + - php: hhvm + +before_install: + - composer --prefer-source install + +script: + - vendor/bin/codecept run \ No newline at end of file diff --git a/plugins/cookieconsent/CHANGELOG.md b/plugins/cookieconsent/CHANGELOG.md new file mode 100755 index 0000000..444b423 --- /dev/null +++ b/plugins/cookieconsent/CHANGELOG.md @@ -0,0 +1,35 @@ +# v0.4.0 +## 06/24/2018 + +1. [](#new) + * Added plugin setting to include cookie consent js and css from official cdn or local + * Added sections to structure plugin settings +2. [](#improved) + * Updated cookie consent js and css from version 3.0.3 to 3.0.6. +3. [](#bugfix) + * Fixed typo in helper text for color of button background. + * Fixed typos in README. + +# v0.3.0 +## 06/24/2018 + +1. [](#new) + * Added color picker to fields with color in blueprint +2. [](#improved) + * Changed the validation for policy link to be less strict to allow absolute as well as relative URl and path +3. [](#bugfix) + * Fixed typo in labels and helper + + +# v0.2.0 +## 10/29/2017 + +1. [](#new) + * Add translations for english, french, spanish, german and italian. + * Translations will be used if no `content_message`, `content_dismiss`, `content_link` or `content_href` are defined in `cookieconsent.yaml`. + +# v0.1.0 +## 08/17/2017 + +1. [](#new) + * ChangeLog started... diff --git a/plugins/cookieconsent/LICENSE b/plugins/cookieconsent/LICENSE new file mode 100755 index 0000000..660d04f --- /dev/null +++ b/plugins/cookieconsent/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 naucon + +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/plugins/cookieconsent/README.md b/plugins/cookieconsent/README.md new file mode 100755 index 0000000..b788844 --- /dev/null +++ b/plugins/cookieconsent/README.md @@ -0,0 +1,111 @@ +# Cookie Consent Plugin + +![Cookie Consent](assets/readme_1.png) + +The **Cookie Consent** Plugin is for [Grav CMS](http://github.com/getgrav/grav). This grav plugin is to alert users about the use of cookies on your website. The plugin integrates the popular js lib [cookie consent](https://github.com/insites/cookieconsent/) by insites. + +## Installation + +Installing the Cookieconsent plugin can be done in one of two ways. The GPM (Grav Package Manager) installation method enables you to quickly and easily install the plugin with a simple terminal command, while the manual method enables you to do so via a zip file. + +### GPM Installation (Preferred) + +The simplest way to install this plugin is via the [Grav Package Manager (GPM)](http://learn.getgrav.org/advanced/grav-gpm) through your system's terminal (also called the command line). From the root of your Grav install type: + + bin/gpm install cookieconsent + +This will install the Cookieconsent plugin into your `/user/plugins` directory within Grav. Its files can be found under `/your/site/grav/user/plugins/cookieconsent`. + +### Manual Installation + +To install this plugin, just download the zip version of this repository and unzip it under `/your/site/grav/user/plugins`. Then, rename the folder to `cookieconsent`. You can find these files on [GitHub](https://github.com/naucon/grav-plugin-cookieconsent) or via [GetGrav.org](http://getgrav.org/downloads/plugins#extras). + +You should now have all the plugin files under + + /your/site/grav/user/plugins/cookieconsent + +> NOTE: This plugin is a modular component for Grav which requires [Grav](http://github.com/getgrav/grav) and the [Error](https://github.com/getgrav/grav-plugin-error) and [Problems](https://github.com/getgrav/grav-plugin-problems) to operate. + +## Configuration + +Before configuring this plugin, you should copy the `user/plugins/cookieconsent/cookieconsent.yaml` to `user/config/plugins/cookieconsent.yaml` and only edit that copy. + +Here is the default configuration: + +```yaml +enabled: true +``` + +## Advanced configuration + +You can customize texts, shape and color with the following available options: + +```yaml +# Include JavaScript and CSS files from official CDN or local +cdn: true +# Message on the banner (overwrite translation) +content_message: 'This website uses cookies to ensure you get the best experience on our website.' +# Dismiss button text (overwrite translation) +content_dismiss: 'Got it!' +# Policy link text (overwrite translation) +content_link: 'Learn more' +# Link to policy (overwrite translation) +content_href: 'https://cookiesandyou.com' + +# Color of banner background +popup_background_color: '#000' +# Color of banner text +popup_text_color: '#fff' +# Color of button background +button_background_color: '#f1d600' +# Color of button text +button_text_color: '#000' +# Color of button border +button_border_color: '#f1d600' + +# Position on the website, where the banner will be displayed. +# top = Top +# top-pushdown: Top (Pushdown) +# bottom: Bottom +# bottom-left: Bottom Left +# bottom-right: Bottom Right +position: bottom + +# Button layout +# block: Block (angled corners) +# classic: Classic (round corners) +# edgeless: Edgeless +theme: block +``` + +### Translation + +Translations are defined in the `languages.yaml` file. + +Translations will be used if no `content_message`, `content_dismiss`, `content_link` or `content_href` are defined in `cookieconsent.yaml`. + + +### Known Issues + +#### Incompatible themes + +The plugin hooks into the grav asset manager (https://learn.getgrav.org/themes/asset-manager). Some themes haven't (properbly) integrated the assets manager and therefore do not work. + +Have a look at the following required elements in the base theme. Without them the plugin will not work. + + {{ assets.css() }} + {{ assets.js() }} + + + +## License + +The MIT License (MIT) + +Copyright (c) 2015 Sven Sanzenbacher + +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. \ No newline at end of file diff --git a/plugins/cookieconsent/assets/cookieconsent.min.css b/plugins/cookieconsent/assets/cookieconsent.min.css new file mode 100755 index 0000000..4374f8c --- /dev/null +++ b/plugins/cookieconsent/assets/cookieconsent.min.css @@ -0,0 +1,6 @@ +.cc-window{opacity:1;transition:opacity 1s ease}.cc-window.cc-invisible{opacity:0}.cc-animate.cc-revoke{transition:transform 1s ease}.cc-animate.cc-revoke.cc-top{transform:translateY(-2em)}.cc-animate.cc-revoke.cc-bottom{transform:translateY(2em)}.cc-animate.cc-revoke.cc-active.cc-bottom,.cc-animate.cc-revoke.cc-active.cc-top,.cc-revoke:hover{transform:translateY(0)}.cc-grower{max-height:0;overflow:hidden;transition:max-height 1s} +.cc-link,.cc-revoke:hover{text-decoration:underline}.cc-revoke,.cc-window{position:fixed;overflow:hidden;box-sizing:border-box;font-family:Helvetica,Calibri,Arial,sans-serif;font-size:16px;line-height:1.5em;display:-ms-flexbox;display:flex;-ms-flex-wrap:nowrap;flex-wrap:nowrap;z-index:9999}.cc-window.cc-static{position:static}.cc-window.cc-floating{padding:2em;max-width:24em;-ms-flex-direction:column;flex-direction:column}.cc-window.cc-banner{padding:1em 1.8em;width:100%;-ms-flex-direction:row;flex-direction:row}.cc-revoke{padding:.5em}.cc-header{font-size:18px;font-weight:700}.cc-btn,.cc-close,.cc-link,.cc-revoke{cursor:pointer}.cc-link{opacity:.8;display:inline-block;padding:.2em}.cc-link:hover{opacity:1}.cc-link:active,.cc-link:visited{color:initial}.cc-btn{display:block;padding:.4em .8em;font-size:.9em;font-weight:700;border-width:2px;border-style:solid;text-align:center;white-space:nowrap}.cc-banner .cc-btn:last-child{min-width:140px}.cc-highlight .cc-btn:first-child{background-color:transparent;border-color:transparent}.cc-highlight .cc-btn:first-child:focus,.cc-highlight .cc-btn:first-child:hover{background-color:transparent;text-decoration:underline}.cc-close{display:block;position:absolute;top:.5em;right:.5em;font-size:1.6em;opacity:.9;line-height:.75}.cc-close:focus,.cc-close:hover{opacity:1} +.cc-revoke.cc-top{top:0;left:3em;border-bottom-left-radius:.5em;border-bottom-right-radius:.5em}.cc-revoke.cc-bottom{bottom:0;left:3em;border-top-left-radius:.5em;border-top-right-radius:.5em}.cc-revoke.cc-left{left:3em;right:unset}.cc-revoke.cc-right{right:3em;left:unset}.cc-top{top:1em}.cc-left{left:1em}.cc-right{right:1em}.cc-bottom{bottom:1em}.cc-floating>.cc-link{margin-bottom:1em}.cc-floating .cc-message{display:block;margin-bottom:1em}.cc-window.cc-floating .cc-compliance{-ms-flex:1 0 auto;flex:1 0 auto}.cc-window.cc-banner{-ms-flex-align:center;align-items:center}.cc-banner.cc-top{left:0;right:0;top:0}.cc-banner.cc-bottom{left:0;right:0;bottom:0}.cc-banner .cc-message{-ms-flex:1;flex:1}.cc-compliance{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-line-pack:justify;align-content:space-between}.cc-compliance>.cc-btn{-ms-flex:1;flex:1}.cc-btn+.cc-btn{margin-left:.5em} +@media print{.cc-revoke,.cc-window{display:none}}@media screen and (max-width:900px){.cc-btn{white-space:normal}}@media screen and (max-width:414px) and (orientation:portrait),screen and (max-width:736px) and (orientation:landscape){.cc-window.cc-top{top:0}.cc-window.cc-bottom{bottom:0}.cc-window.cc-banner,.cc-window.cc-left,.cc-window.cc-right{left:0;right:0}.cc-window.cc-banner{-ms-flex-direction:column;flex-direction:column}.cc-window.cc-banner .cc-compliance{-ms-flex:1;flex:1}.cc-window.cc-floating{max-width:none}.cc-window .cc-message{margin-bottom:1em}.cc-window.cc-banner{-ms-flex-align:unset;align-items:unset}} +.cc-floating.cc-theme-classic{padding:1.2em;border-radius:5px}.cc-floating.cc-type-info.cc-theme-classic .cc-compliance{text-align:center;display:inline;-ms-flex:none;flex:none}.cc-theme-classic .cc-btn{border-radius:5px}.cc-theme-classic .cc-btn:last-child{min-width:140px}.cc-floating.cc-type-info.cc-theme-classic .cc-btn{display:inline-block} +.cc-theme-edgeless.cc-window{padding:0}.cc-floating.cc-theme-edgeless .cc-message{margin:2em 2em 1.5em}.cc-banner.cc-theme-edgeless .cc-btn{margin:0;padding:.8em 1.8em;height:100%}.cc-banner.cc-theme-edgeless .cc-message{margin-left:1em}.cc-floating.cc-theme-edgeless .cc-btn+.cc-btn{margin-left:0} \ No newline at end of file diff --git a/plugins/cookieconsent/assets/cookieconsent.min.js b/plugins/cookieconsent/assets/cookieconsent.min.js new file mode 100755 index 0000000..3c47973 --- /dev/null +++ b/plugins/cookieconsent/assets/cookieconsent.min.js @@ -0,0 +1 @@ +!function(e){if(!e.hasInitialised){var t={escapeRegExp:function(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")},hasClass:function(e,t){var i=" ";return 1===e.nodeType&&(i+e.className+i).replace(/[\n\t]/g,i).indexOf(i+t+i)>=0},addClass:function(e,t){e.className+=" "+t},removeClass:function(e,t){var i=new RegExp("\\b"+this.escapeRegExp(t)+"\\b");e.className=e.className.replace(i,"")},interpolateString:function(e,t){var i=/{{([a-z][a-z0-9\-_]*)}}/gi;return e.replace(i,function(e){return t(arguments[1])||""})},getCookie:function(e){var t="; "+document.cookie,i=t.split("; "+e+"=");return 2!=i.length?void 0:i.pop().split(";").shift()},setCookie:function(e,t,i,n,o){var s=new Date;s.setDate(s.getDate()+(i||365));var r=[e+"="+t,"expires="+s.toUTCString(),"path="+(o||"/")];n&&r.push("domain="+n),document.cookie=r.join(";")},deepExtend:function(e,t){for(var i in t)t.hasOwnProperty(i)&&(i in e&&this.isPlainObject(e[i])&&this.isPlainObject(t[i])?this.deepExtend(e[i],t[i]):e[i]=t[i]);return e},throttle:function(e,t){var i=!1;return function(){i||(e.apply(this,arguments),i=!0,setTimeout(function(){i=!1},t))}},hash:function(e){var t,i,n,o=0;if(0===e.length)return o;for(t=0,n=e.length;t=128?"#000":"#fff"},getLuminance:function(e){var t=parseInt(this.normaliseHex(e),16),i=38,n=(t>>16)+i,o=(t>>8&255)+i,s=(255&t)+i,r=(16777216+65536*(n<255?n<1?0:n:255)+256*(o<255?o<1?0:o:255)+(s<255?s<1?0:s:255)).toString(16).slice(1);return"#"+r},isMobile:function(){return/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)},isPlainObject:function(e){return"object"==typeof e&&null!==e&&e.constructor==Object}};e.status={deny:"deny",allow:"allow",dismiss:"dismiss"},e.transitionEnd=function(){var e=document.createElement("div"),t={t:"transitionend",OT:"oTransitionEnd",msT:"MSTransitionEnd",MozT:"transitionend",WebkitT:"webkitTransitionEnd"};for(var i in t)if(t.hasOwnProperty(i)&&"undefined"!=typeof e.style[i+"ransition"])return t[i];return""}(),e.hasTransition=!!e.transitionEnd;var i=Object.keys(e.status).map(t.escapeRegExp);e.customStyles={},e.Popup=function(){function n(){this.initialise.apply(this,arguments)}function o(e){this.openingTimeout=null,t.removeClass(e,"cc-invisible")}function s(t){t.style.display="none",t.removeEventListener(e.transitionEnd,this.afterTransition),this.afterTransition=null}function r(){var t=this.options.onInitialise.bind(this);if(!window.navigator.cookieEnabled)return t(e.status.deny),!0;if(window.CookiesOK||window.navigator.CookiesOK)return t(e.status.allow),!0;var i=Object.keys(e.status),n=this.getStatus(),o=i.indexOf(n)>=0;return o&&t(n),o}function a(){var e=this.options.position.split("-"),t=[];return e.forEach(function(e){t.push("cc-"+e)}),t}function c(){var e=this.options,i="top"==e.position||"bottom"==e.position?"banner":"floating";t.isMobile()&&(i="floating");var n=["cc-"+i,"cc-type-"+e.type,"cc-theme-"+e.theme];e["static"]&&n.push("cc-static"),n.push.apply(n,a.call(this));p.call(this,this.options.palette);return this.customStyleSelector&&n.push(this.customStyleSelector),n}function l(){var e={},i=this.options;i.showLink||(i.elements.link="",i.elements.messagelink=i.elements.message),Object.keys(i.elements).forEach(function(n){e[n]=t.interpolateString(i.elements[n],function(e){var t=i.content[e];return e&&"string"==typeof t&&t.length?t:""})});var n=i.compliance[i.type];n||(n=i.compliance.info),e.compliance=t.interpolateString(n,function(t){return e[t]});var o=i.layouts[i.layout];return o||(o=i.layouts.basic),t.interpolateString(o,function(t){return e[t]})}function u(i){var n=this.options,o=document.createElement("div"),s=n.container&&1===n.container.nodeType?n.container:document.body;o.innerHTML=i;var r=o.children[0];return r.style.display="none",t.hasClass(r,"cc-window")&&e.hasTransition&&t.addClass(r,"cc-invisible"),this.onButtonClick=h.bind(this),r.addEventListener("click",this.onButtonClick),n.autoAttach&&(s.firstChild?s.insertBefore(r,s.firstChild):s.appendChild(r)),r}function h(n){var o=n.target;if(t.hasClass(o,"cc-btn")){var s=o.className.match(new RegExp("\\bcc-("+i.join("|")+")\\b")),r=s&&s[1]||!1;r&&(this.setStatus(r),this.close(!0))}t.hasClass(o,"cc-close")&&(this.setStatus(e.status.dismiss),this.close(!0)),t.hasClass(o,"cc-revoke")&&this.revokeChoice()}function p(e){var i=t.hash(JSON.stringify(e)),n="cc-color-override-"+i,o=t.isPlainObject(e);return this.customStyleSelector=o?n:null,o&&d(i,e,"."+n),o}function d(i,n,o){if(e.customStyles[i])return void++e.customStyles[i].references;var s={},r=n.popup,a=n.button,c=n.highlight;r&&(r.text=r.text?r.text:t.getContrast(r.background),r.link=r.link?r.link:r.text,s[o+".cc-window"]=["color: "+r.text,"background-color: "+r.background],s[o+".cc-revoke"]=["color: "+r.text,"background-color: "+r.background],s[o+" .cc-link,"+o+" .cc-link:active,"+o+" .cc-link:visited"]=["color: "+r.link],a&&(a.text=a.text?a.text:t.getContrast(a.background),a.border=a.border?a.border:"transparent",s[o+" .cc-btn"]=["color: "+a.text,"border-color: "+a.border,"background-color: "+a.background],"transparent"!=a.background&&(s[o+" .cc-btn:hover, "+o+" .cc-btn:focus"]=["background-color: "+v(a.background)]),c?(c.text=c.text?c.text:t.getContrast(c.background),c.border=c.border?c.border:"transparent",s[o+" .cc-highlight .cc-btn:first-child"]=["color: "+c.text,"border-color: "+c.border,"background-color: "+c.background]):s[o+" .cc-highlight .cc-btn:first-child"]=["color: "+r.text]));var l=document.createElement("style");document.head.appendChild(l),e.customStyles[i]={references:1,element:l.sheet};var u=-1;for(var h in s)s.hasOwnProperty(h)&&l.sheet.insertRule(h+"{"+s[h].join(";")+"}",++u)}function v(e){return e=t.normaliseHex(e),"000000"==e?"#222":t.getLuminance(e)}function f(i){if(t.isPlainObject(i)){var n=t.hash(JSON.stringify(i)),o=e.customStyles[n];if(o&&!--o.references){var s=o.element.ownerNode;s&&s.parentNode&&s.parentNode.removeChild(s),e.customStyles[n]=null}}}function m(e,t){for(var i=0,n=e.length;i=0&&(this.dismissTimeout=window.setTimeout(function(){t(e.status.dismiss)},Math.floor(i)));var n=this.options.dismissOnScroll;if("number"==typeof n&&n>=0){var o=function(i){window.pageYOffset>Math.floor(n)&&(t(e.status.dismiss),window.removeEventListener("scroll",o),this.onWindowScroll=null)};this.onWindowScroll=o,window.addEventListener("scroll",o)}}function y(){if("info"!=this.options.type&&(this.options.revokable=!0),t.isMobile()&&(this.options.animateRevokable=!1),this.options.revokable){var e=a.call(this);this.options.animateRevokable&&e.push("cc-animate"),this.customStyleSelector&&e.push(this.customStyleSelector);var i=this.options.revokeBtn.replace("{{classes}}",e.join(" "));this.revokeBtn=u.call(this,i);var n=this.revokeBtn;if(this.options.animateRevokable){var o=t.throttle(function(e){var i=!1,o=20,s=window.innerHeight-20;t.hasClass(n,"cc-top")&&e.clientYs&&(i=!0),i?t.hasClass(n,"cc-active")||t.addClass(n,"cc-active"):t.hasClass(n,"cc-active")&&t.removeClass(n,"cc-active")},200);this.onMouseMove=o,window.addEventListener("mousemove",o)}}}var g={enabled:!0,container:null,cookie:{name:"cookieconsent_status",path:"/",domain:"",expiryDays:365},onPopupOpen:function(){},onPopupClose:function(){},onInitialise:function(e){},onStatusChange:function(e,t){},onRevokeChoice:function(){},content:{header:"Cookies used on the website!",message:"This website uses cookies to ensure you get the best experience on our website.",dismiss:"Got it!",allow:"Allow cookies",deny:"Decline",link:"Learn more",href:"http://cookiesandyou.com",close:"❌"},elements:{header:'{{header}} ',message:'{{message}}',messagelink:'{{message}} {{link}}',dismiss:'{{dismiss}}',allow:'{{allow}}',deny:'{{deny}}',link:'{{link}}',close:'{{close}}'},window:'',revokeBtn:'
Cookie Policy
',compliance:{info:'
{{dismiss}}
',"opt-in":'
{{dismiss}}{{allow}}
',"opt-out":'
{{deny}}{{dismiss}}
'},type:"info",layouts:{basic:"{{messagelink}}{{compliance}}","basic-close":"{{messagelink}}{{compliance}}{{close}}","basic-header":"{{header}}{{message}}{{link}}{{compliance}}"},layout:"basic",position:"bottom",theme:"block","static":!1,palette:null,revokable:!1,animateRevokable:!0,showLink:!0,dismissOnScroll:!1,dismissOnTimeout:!1,autoOpen:!0,autoAttach:!0,whitelistPage:[],blacklistPage:[],overrideHTML:null};return n.prototype.initialise=function(e){this.options&&this.destroy(),t.deepExtend(this.options={},g),t.isPlainObject(e)&&t.deepExtend(this.options,e),r.call(this)&&(this.options.enabled=!1),m(this.options.blacklistPage,location.pathname)&&(this.options.enabled=!1),m(this.options.whitelistPage,location.pathname)&&(this.options.enabled=!0);var i=this.options.window.replace("{{classes}}",c.call(this).join(" ")).replace("{{children}}",l.call(this)),n=this.options.overrideHTML;if("string"==typeof n&&n.length&&(i=n),this.options["static"]){var o=u.call(this,'
'+i+"
");o.style.display="",this.element=o.firstChild,this.element.style.display="none",t.addClass(this.element,"cc-invisible")}else this.element=u.call(this,i);b.call(this),y.call(this),this.options.autoOpen&&this.autoOpen()},n.prototype.destroy=function(){this.onButtonClick&&this.element&&(this.element.removeEventListener("click",this.onButtonClick),this.onButtonClick=null),this.dismissTimeout&&(clearTimeout(this.dismissTimeout),this.dismissTimeout=null),this.onWindowScroll&&(window.removeEventListener("scroll",this.onWindowScroll),this.onWindowScroll=null),this.onMouseMove&&(window.removeEventListener("mousemove",this.onMouseMove),this.onMouseMove=null),this.element&&this.element.parentNode&&this.element.parentNode.removeChild(this.element),this.element=null,this.revokeBtn&&this.revokeBtn.parentNode&&this.revokeBtn.parentNode.removeChild(this.revokeBtn),this.revokeBtn=null,f(this.options.palette),this.options=null},n.prototype.open=function(t){if(this.element)return this.isOpen()||(e.hasTransition?this.fadeIn():this.element.style.display="",this.options.revokable&&this.toggleRevokeButton(),this.options.onPopupOpen.call(this)),this},n.prototype.close=function(t){if(this.element)return this.isOpen()&&(e.hasTransition?this.fadeOut():this.element.style.display="none",t&&this.options.revokable&&this.toggleRevokeButton(!0),this.options.onPopupClose.call(this)),this},n.prototype.fadeIn=function(){var i=this.element;if(e.hasTransition&&i&&(this.afterTransition&&s.call(this,i),t.hasClass(i,"cc-invisible"))){if(i.style.display="",this.options["static"]){var n=this.element.clientHeight;this.element.parentNode.style.maxHeight=n+"px"}var r=20;this.openingTimeout=setTimeout(o.bind(this,i),r)}},n.prototype.fadeOut=function(){var i=this.element;e.hasTransition&&i&&(this.openingTimeout&&(clearTimeout(this.openingTimeout),o.bind(this,i)),t.hasClass(i,"cc-invisible")||(this.options["static"]&&(this.element.parentNode.style.maxHeight=""),this.afterTransition=s.bind(this,i),i.addEventListener(e.transitionEnd,this.afterTransition),t.addClass(i,"cc-invisible")))},n.prototype.isOpen=function(){return this.element&&""==this.element.style.display&&(!e.hasTransition||!t.hasClass(this.element,"cc-invisible"))},n.prototype.toggleRevokeButton=function(e){this.revokeBtn&&(this.revokeBtn.style.display=e?"":"none")},n.prototype.revokeChoice=function(e){this.options.enabled=!0,this.clearStatus(),this.options.onRevokeChoice.call(this),e||this.autoOpen()},n.prototype.hasAnswered=function(t){return Object.keys(e.status).indexOf(this.getStatus())>=0},n.prototype.hasConsented=function(t){var i=this.getStatus();return i==e.status.allow||i==e.status.dismiss},n.prototype.autoOpen=function(e){!this.hasAnswered()&&this.options.enabled&&this.open()},n.prototype.setStatus=function(i){var n=this.options.cookie,o=t.getCookie(n.name),s=Object.keys(e.status).indexOf(o)>=0;Object.keys(e.status).indexOf(i)>=0?(t.setCookie(n.name,i,n.expiryDays,n.domain,n.path),this.options.onStatusChange.call(this,i,s)):this.clearStatus()},n.prototype.getStatus=function(){return t.getCookie(this.options.cookie.name)},n.prototype.clearStatus=function(){var e=this.options.cookie;t.setCookie(e.name,"",-1,e.domain,e.path)},n}(),e.Location=function(){function e(e){t.deepExtend(this.options={},s),t.isPlainObject(e)&&t.deepExtend(this.options,e),this.currentServiceIndex=-1}function i(e,t,i){var n,o=document.createElement("script");o.type="text/"+(e.type||"javascript"),o.src=e.src||e,o.async=!1,o.onreadystatechange=o.onload=function(){var e=o.readyState;clearTimeout(n),t.done||e&&!/loaded|complete/.test(e)||(t.done=!0,t(),o.onreadystatechange=o.onload=null)},document.body.appendChild(o),n=setTimeout(function(){t.done=!0,t(),o.onreadystatechange=o.onload=null},i)}function n(e,t,i,n,o){var s=new(window.XMLHttpRequest||window.ActiveXObject)("MSXML2.XMLHTTP.3.0");if(s.open(n?"POST":"GET",e,1),s.setRequestHeader("X-Requested-With","XMLHttpRequest"),s.setRequestHeader("Content-type","application/x-www-form-urlencoded"),Array.isArray(o))for(var r=0,a=o.length;r3&&t(s)}),s.send(n)}function o(e){return new Error("Error ["+(e.code||"UNKNOWN")+"]: "+e.error)}var s={timeout:5e3,services:["freegeoip","ipinfo","maxmind"],serviceDefinitions:{freegeoip:function(){return{url:"//freegeoip.net/json/?callback={callback}",isScript:!0,callback:function(e,t){try{var i=JSON.parse(t);return i.error?o(i):{code:i.country_code}}catch(n){return o({error:"Invalid response ("+n+")"})}}}},ipinfo:function(){return{url:"//ipinfo.io",headers:["Accept: application/json"],callback:function(e,t){try{var i=JSON.parse(t);return i.error?o(i):{code:i.country}}catch(n){return o({error:"Invalid response ("+n+")"})}}}},ipinfodb:function(e){return{url:"//api.ipinfodb.com/v3/ip-country/?key={api_key}&format=json&callback={callback}",isScript:!0,callback:function(e,t){try{var i=JSON.parse(t);return"ERROR"==i.statusCode?o({error:i.statusMessage}):{code:i.countryCode}}catch(n){return o({error:"Invalid response ("+n+")"})}}}},maxmind:function(){return{url:"//js.maxmind.com/js/apis/geoip2/v2.1/geoip2.js",isScript:!0,callback:function(e){return window.geoip2?void geoip2.country(function(t){try{e({code:t.country.iso_code})}catch(i){e(o(i))}},function(t){e(o(t))}):void e(new Error("Unexpected response format. The downloaded script should have exported `geoip2` to the global scope"))}}}}};return e.prototype.getNextService=function(){var e;do e=this.getServiceByIdx(++this.currentServiceIndex);while(this.currentServiceIndex=0,revokable:t.revokable.indexOf(e)>=0,explicitAction:t.explicitAction.indexOf(e)>=0}},e.prototype.applyLaw=function(e,t){var i=this.get(t);return i.hasLaw||(e.enabled=!1),this.options.regionalLaw&&(i.revokable&&(e.revokable=!0),i.explicitAction&&(e.dismissOnScroll=!1,e.dismissOnTimeout=!1)),e},e}(),e.initialise=function(t,i,n){var o=new e.Law(t.law);i||(i=function(){}),n||(n=function(){}),e.getCountryCode(t,function(n){delete t.law,delete t.location,n.code&&(t=o.applyLaw(t,n.code)),i(new e.Popup(t))},function(i){delete t.law,delete t.location,n(i,new e.Popup(t))})},e.getCountryCode=function(t,i,n){if(t.law&&t.law.countryCode)return void i({code:t.law.countryCode});if(t.location){var o=new e.Location(t.location);return void o.locate(function(e){i(e||{})},n)}i({})},e.utils=t,e.hasInitialised=!0,window.cookieconsent=e}}(window.cookieconsent||{}); \ No newline at end of file diff --git a/plugins/cookieconsent/assets/readme_1.png b/plugins/cookieconsent/assets/readme_1.png new file mode 100755 index 0000000000000000000000000000000000000000..116af3ce84e62dbf6bc8f65038726f367d4b62df GIT binary patch literal 276658 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 z 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%0Ad!f6n-VBy{O{tu_o<-Ani}3K!m2 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

YPp0f>1_}Eaj#2#*@0=>X{&4 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