abqari 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +889 -0
- data/LICENSE +21 -0
- data/README.md +2739 -0
- data/SECURITY.md +73 -0
- data/THIRD_PARTY_NOTICES.md +46 -0
- data/app/assets/css/_common.css +3125 -0
- data/app/assets/js/carousel.js +39 -0
- data/app/assets/js/contact-button.js +28 -0
- data/app/assets/js/random-pool.js +44 -0
- data/app/assets/js/search-init.js +11 -0
- data/app/assets/js/theme-toggle.js +39 -0
- data/app/assets/js/viz-tag-bubble.js +108 -0
- data/app/assets/js/viz-tag-cooccurrence.js +125 -0
- data/app/assets/js/viz-topic-constellation.js +142 -0
- data/app/icons/bluesky.svg +3 -0
- data/app/icons/github.svg +3 -0
- data/app/icons/linkedin.svg +3 -0
- data/app/icons/mail.svg +4 -0
- data/app/icons/mastodon.svg +3 -0
- data/app/icons/moon.svg +3 -0
- data/app/icons/rss.svg +3 -0
- data/app/icons/sun.svg +4 -0
- data/app/icons/x.svg +3 -0
- data/app/views/layouts/about.html.erb +70 -0
- data/app/views/layouts/application.html.erb +65 -0
- data/app/views/layouts/book_series_index.html.erb +43 -0
- data/app/views/layouts/bundle.html.erb +111 -0
- data/app/views/layouts/bundles_index.html.erb +46 -0
- data/app/views/layouts/country_index.html.erb +59 -0
- data/app/views/layouts/gallery_index.html.erb +126 -0
- data/app/views/layouts/home.html.erb +107 -0
- data/app/views/layouts/photo.html.erb +100 -0
- data/app/views/layouts/photos_archive.html.erb +101 -0
- data/app/views/layouts/photos_index.html.erb +204 -0
- data/app/views/layouts/post.html.erb +153 -0
- data/app/views/layouts/posts_archive.html.erb +98 -0
- data/app/views/layouts/posts_index.html.erb +80 -0
- data/app/views/layouts/publication.html.erb +116 -0
- data/app/views/layouts/publications_archive.html.erb +89 -0
- data/app/views/layouts/publications_index.html.erb +246 -0
- data/app/views/layouts/related_index.html.erb +48 -0
- data/app/views/layouts/series.html.erb +110 -0
- data/app/views/layouts/series_index.html.erb +202 -0
- data/app/views/layouts/tag.html.erb +16 -0
- data/app/views/layouts/visualization.html.erb +32 -0
- data/app/views/layouts/workshop.html.erb +163 -0
- data/app/views/layouts/workshops_index.html.erb +209 -0
- data/app/views/partials/_back_link.html.erb +27 -0
- data/app/views/partials/_back_to_index.html.erb +25 -0
- data/app/views/partials/_book_grid.html.erb +76 -0
- data/app/views/partials/_book_jsonld.html.erb +72 -0
- data/app/views/partials/_book_related.html.erb +87 -0
- data/app/views/partials/_breadcrumb_jsonld.html.erb +60 -0
- data/app/views/partials/_bundle_cta.html.erb +26 -0
- data/app/views/partials/_carousel.html.erb +64 -0
- data/app/views/partials/_collection_page_jsonld.html.erb +81 -0
- data/app/views/partials/_contact_button.html.erb +42 -0
- data/app/views/partials/_course_jsonld.html.erb +95 -0
- data/app/views/partials/_draft_banner.html.erb +20 -0
- data/app/views/partials/_event_jsonld.html.erb +122 -0
- data/app/views/partials/_footer.html.erb +88 -0
- data/app/views/partials/_future_banner.html.erb +25 -0
- data/app/views/partials/_head.html.erb +440 -0
- data/app/views/partials/_image_gallery.html.erb +64 -0
- data/app/views/partials/_image_object_jsonld.html.erb +61 -0
- data/app/views/partials/_nav.html.erb +63 -0
- data/app/views/partials/_newsletter_subscribe.html.erb +85 -0
- data/app/views/partials/_next_in_series.html.erb +27 -0
- data/app/views/partials/_next_item.html.erb +38 -0
- data/app/views/partials/_pagination.html.erb +15 -0
- data/app/views/partials/_person_jsonld.html.erb +46 -0
- data/app/views/partials/_plausible.html.erb +24 -0
- data/app/views/partials/_post_list.html.erb +101 -0
- data/app/views/partials/_post_series_previews.html.erb +92 -0
- data/app/views/partials/_publication_card.html.erb +75 -0
- data/app/views/partials/_publication_header.html.erb +61 -0
- data/app/views/partials/_related_item.html.erb +68 -0
- data/app/views/partials/_related_items.html.erb +105 -0
- data/app/views/partials/_search.html.erb +26 -0
- data/app/views/partials/_series_pager.html.erb +48 -0
- data/app/views/partials/_skip_link.html.erb +12 -0
- data/app/views/partials/_taxonomy_row.html.erb +62 -0
- data/app/views/partials/_testimonials.html.erb +149 -0
- data/app/views/partials/_theme_toggle.html.erb +19 -0
- data/app/views/partials/_toc.html.erb +136 -0
- data/app/views/partials/_webmentions.html.erb +131 -0
- data/app/views/partials/_website_jsonld.html.erb +39 -0
- data/app/views/partials/home/_contact.html.erb +19 -0
- data/app/views/partials/home/_featured_publication.html.erb +107 -0
- data/app/views/partials/home/_latest_photo.html.erb +95 -0
- data/app/views/partials/home/_latest_post.html.erb +48 -0
- data/app/views/partials/home/_latest_publication.html.erb +89 -0
- data/app/views/partials/home/_next_workshop.html.erb +119 -0
- data/app/views/partials/home/_photo_gallery.html.erb +71 -0
- data/app/views/partials/home/_random_photo.html.erb +106 -0
- data/app/views/partials/home/_random_post.html.erb +64 -0
- data/exe/abqari +37 -0
- data/lib/abqari/artifact_writer.rb +196 -0
- data/lib/abqari/asset_pipeline.rb +235 -0
- data/lib/abqari/audit/a11y.rb +80 -0
- data/lib/abqari/audit/content.rb +154 -0
- data/lib/abqari/audit/dependencies.rb +127 -0
- data/lib/abqari/audit/links.rb +120 -0
- data/lib/abqari/audit/performance.rb +120 -0
- data/lib/abqari/audit/privacy.rb +42 -0
- data/lib/abqari/audit/rule.rb +56 -0
- data/lib/abqari/audit/seo.rb +105 -0
- data/lib/abqari/audit.rb +149 -0
- data/lib/abqari/bundle_assets.rb +127 -0
- data/lib/abqari/cli/new.rb +541 -0
- data/lib/abqari/cli/theme.rb +181 -0
- data/lib/abqari/cli.rb +130 -0
- data/lib/abqari/erbi_template.rb +72 -0
- data/lib/abqari/feed.rb +159 -0
- data/lib/abqari/folio.rb +195 -0
- data/lib/abqari/font_pipeline.rb +104 -0
- data/lib/abqari/headers_file.rb +324 -0
- data/lib/abqari/helpers.rb +308 -0
- data/lib/abqari/hooks.rb +136 -0
- data/lib/abqari/http_safe.rb +222 -0
- data/lib/abqari/image_pipeline.rb +800 -0
- data/lib/abqari/importers/base.rb +351 -0
- data/lib/abqari/importers/cli.rb +169 -0
- data/lib/abqari/importers/ghost.rb +113 -0
- data/lib/abqari/importers/jekyll.rb +256 -0
- data/lib/abqari/importers/substack.rb +204 -0
- data/lib/abqari/importers/support/html_to_markdown.rb +126 -0
- data/lib/abqari/importers/support/image_downloader.rb +170 -0
- data/lib/abqari/importers/support/report.rb +87 -0
- data/lib/abqari/importers/support/slug_normalizer.rb +53 -0
- data/lib/abqari/importers.rb +64 -0
- data/lib/abqari/indieweb.rb +551 -0
- data/lib/abqari/llms_txt.rb +110 -0
- data/lib/abqari/log.rb +61 -0
- data/lib/abqari/manifest.rb +58 -0
- data/lib/abqari/minifier.rb +108 -0
- data/lib/abqari/og_image_generator.rb +223 -0
- data/lib/abqari/page/bundle.rb +152 -0
- data/lib/abqari/page/incremental.rb +74 -0
- data/lib/abqari/page/parser.rb +129 -0
- data/lib/abqari/page/path.rb +153 -0
- data/lib/abqari/page.rb +424 -0
- data/lib/abqari/paginated_shard.rb +109 -0
- data/lib/abqari/paginator.rb +35 -0
- data/lib/abqari/path_safe.rb +62 -0
- data/lib/abqari/plausible_script.rb +20 -0
- data/lib/abqari/publication_normaliser.rb +111 -0
- data/lib/abqari/publisher_pages.rb +342 -0
- data/lib/abqari/redirects.rb +134 -0
- data/lib/abqari/related_index_page.rb +79 -0
- data/lib/abqari/render_context/cover_helpers.rb +338 -0
- data/lib/abqari/render_context/picture_helpers.rb +178 -0
- data/lib/abqari/render_context/publication_helpers.rb +120 -0
- data/lib/abqari/render_context.rb +251 -0
- data/lib/abqari/renderer.rb +788 -0
- data/lib/abqari/robots.rb +93 -0
- data/lib/abqari/search.rb +68 -0
- data/lib/abqari/security_txt.rb +44 -0
- data/lib/abqari/server.rb +508 -0
- data/lib/abqari/site.rb +952 -0
- data/lib/abqari/site_config.rb +212 -0
- data/lib/abqari/site_loader.rb +265 -0
- data/lib/abqari/sitemap.rb +87 -0
- data/lib/abqari/speculation_rules_guard.rb +26 -0
- data/lib/abqari/syndication.rb +466 -0
- data/lib/abqari/syntax_highlighter.rb +146 -0
- data/lib/abqari/taxonomy_page.rb +129 -0
- data/lib/abqari/templates/site_skeleton/.github/dependabot.yml +53 -0
- data/lib/abqari/templates/site_skeleton/.github/workflows/deploy-cloudflare.yml +107 -0
- data/lib/abqari/templates/site_skeleton/.github/workflows/deploy-github-pages.yml +107 -0
- data/lib/abqari/templates/site_skeleton/.github/workflows/deploy-render.yml +87 -0
- data/lib/abqari/templates/site_skeleton/.gitignore +24 -0
- data/lib/abqari/templates/site_skeleton/.ruby-version.tt +1 -0
- data/lib/abqari/templates/site_skeleton/Gemfile.tt +20 -0
- data/lib/abqari/templates/site_skeleton/README.md.tt +60 -0
- data/lib/abqari/templates/site_skeleton/app/assets/css/site.css +9 -0
- data/lib/abqari/templates/site_skeleton/bin/audit +46 -0
- data/lib/abqari/templates/site_skeleton/bin/build +32 -0
- data/lib/abqari/templates/site_skeleton/bin/fetch-folio +32 -0
- data/lib/abqari/templates/site_skeleton/bin/fetch-fonts +20 -0
- data/lib/abqari/templates/site_skeleton/bin/import +31 -0
- data/lib/abqari/templates/site_skeleton/bin/index +30 -0
- data/lib/abqari/templates/site_skeleton/bin/new +235 -0
- data/lib/abqari/templates/site_skeleton/bin/serve +30 -0
- data/lib/abqari/templates/site_skeleton/config/site.blank.yml.tt +65 -0
- data/lib/abqari/templates/site_skeleton/config/site.yml.tt +266 -0
- data/lib/abqari/templates/site_skeleton/content/404.md +17 -0
- data/lib/abqari/templates/site_skeleton/content/about.blank.md.tt +12 -0
- data/lib/abqari/templates/site_skeleton/content/about.md.tt +18 -0
- data/lib/abqari/templates/site_skeleton/content/index.blank.md.tt +11 -0
- data/lib/abqari/templates/site_skeleton/content/index.md.tt +34 -0
- data/lib/abqari/templates/site_skeleton/content/photos/index.md.tt +12 -0
- data/lib/abqari/templates/site_skeleton/content/posts/index.md +12 -0
- data/lib/abqari/templates/site_skeleton/content/posts/welcome/index.md.tt +50 -0
- data/lib/abqari/templates/site_skeleton/content/publications/index.md.tt +13 -0
- data/lib/abqari/templates/site_skeleton/content/workshops/index.md.tt +13 -0
- data/lib/abqari/templates/site_skeleton/public/robots.txt +6 -0
- data/lib/abqari/templates/site_skeleton/themes/.gitkeep +0 -0
- data/lib/abqari/templates/site_skeleton/vendor/folio/.gitkeep +0 -0
- data/lib/abqari/templates/site_skeleton/vendor/fonts/.gitkeep +0 -0
- data/lib/abqari/theme_bootstrap.rb +19 -0
- data/lib/abqari/theme_fonts.rb +51 -0
- data/lib/abqari/version.rb +18 -0
- data/lib/abqari/visualizations.rb +215 -0
- data/lib/abqari.rb +154 -0
- data/themes/bootstrap/css/app.css +97 -0
- data/themes/bootstrap/public/LICENSE +21 -0
- data/themes/bootstrap/public/css/bootstrap.min.css +6 -0
- data/themes/bootstrap/public/css/bootstrap.min.css.map +1 -0
- data/themes/bootstrap/public/js/bootstrap.bundle.min.js +7 -0
- data/themes/bootstrap/public/js/bootstrap.bundle.min.js.map +1 -0
- data/themes/custom/css/app.css +176 -0
- data/themes/magazine/css/app.css +242 -0
- data/themes/minimal/css/app.css +151 -0
- data/themes/notebook/css/app.css +205 -0
- data/themes/sand/css/app.css +179 -0
- data/vendor/d3/d3.v7.min.js +2 -0
- data/vendor/heroicons/16/solid/academic-cap.svg +4 -0
- data/vendor/heroicons/16/solid/adjustments-horizontal.svg +3 -0
- data/vendor/heroicons/16/solid/adjustments-vertical.svg +3 -0
- data/vendor/heroicons/16/solid/archive-box-arrow-down.svg +4 -0
- data/vendor/heroicons/16/solid/archive-box-x-mark.svg +4 -0
- data/vendor/heroicons/16/solid/archive-box.svg +4 -0
- data/vendor/heroicons/16/solid/arrow-down-circle.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-down-left.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-down-on-square-stack.svg +4 -0
- data/vendor/heroicons/16/solid/arrow-down-on-square.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-down-right.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-down-tray.svg +4 -0
- data/vendor/heroicons/16/solid/arrow-down.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-left-circle.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-left-end-on-rectangle.svg +4 -0
- data/vendor/heroicons/16/solid/arrow-left-start-on-rectangle.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-left.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-long-down.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-long-left.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-long-right.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-long-up.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-path-rounded-square.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-path.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-right-circle.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-right-end-on-rectangle.svg +4 -0
- data/vendor/heroicons/16/solid/arrow-right-start-on-rectangle.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-right.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-top-right-on-square.svg +4 -0
- data/vendor/heroicons/16/solid/arrow-trending-down.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-trending-up.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-turn-down-left.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-turn-down-right.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-turn-left-down.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-turn-left-up.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-turn-right-down.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-turn-right-up.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-turn-up-left.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-turn-up-right.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-up-circle.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-up-left.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-up-on-square-stack.svg +4 -0
- data/vendor/heroicons/16/solid/arrow-up-on-square.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-up-right.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-up-tray.svg +4 -0
- data/vendor/heroicons/16/solid/arrow-up.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-uturn-down.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-uturn-left.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-uturn-right.svg +3 -0
- data/vendor/heroicons/16/solid/arrow-uturn-up.svg +3 -0
- data/vendor/heroicons/16/solid/arrows-pointing-in.svg +3 -0
- data/vendor/heroicons/16/solid/arrows-pointing-out.svg +3 -0
- data/vendor/heroicons/16/solid/arrows-right-left.svg +3 -0
- data/vendor/heroicons/16/solid/arrows-up-down.svg +3 -0
- data/vendor/heroicons/16/solid/at-symbol.svg +3 -0
- data/vendor/heroicons/16/solid/backspace.svg +3 -0
- data/vendor/heroicons/16/solid/backward.svg +3 -0
- data/vendor/heroicons/16/solid/banknotes.svg +4 -0
- data/vendor/heroicons/16/solid/bars-2.svg +3 -0
- data/vendor/heroicons/16/solid/bars-3-bottom-left.svg +3 -0
- data/vendor/heroicons/16/solid/bars-3-bottom-right.svg +3 -0
- data/vendor/heroicons/16/solid/bars-3-center-left.svg +3 -0
- data/vendor/heroicons/16/solid/bars-3.svg +3 -0
- data/vendor/heroicons/16/solid/bars-4.svg +3 -0
- data/vendor/heroicons/16/solid/bars-arrow-down.svg +3 -0
- data/vendor/heroicons/16/solid/bars-arrow-up.svg +3 -0
- data/vendor/heroicons/16/solid/battery-0.svg +3 -0
- data/vendor/heroicons/16/solid/battery-100.svg +4 -0
- data/vendor/heroicons/16/solid/battery-50.svg +4 -0
- data/vendor/heroicons/16/solid/beaker.svg +3 -0
- data/vendor/heroicons/16/solid/bell-alert.svg +4 -0
- data/vendor/heroicons/16/solid/bell-slash.svg +4 -0
- data/vendor/heroicons/16/solid/bell-snooze.svg +3 -0
- data/vendor/heroicons/16/solid/bell.svg +3 -0
- data/vendor/heroicons/16/solid/bold.svg +3 -0
- data/vendor/heroicons/16/solid/bolt-slash.svg +3 -0
- data/vendor/heroicons/16/solid/bolt.svg +3 -0
- data/vendor/heroicons/16/solid/book-open.svg +3 -0
- data/vendor/heroicons/16/solid/bookmark-slash.svg +3 -0
- data/vendor/heroicons/16/solid/bookmark-square.svg +3 -0
- data/vendor/heroicons/16/solid/bookmark.svg +3 -0
- data/vendor/heroicons/16/solid/briefcase.svg +4 -0
- data/vendor/heroicons/16/solid/bug-ant.svg +3 -0
- data/vendor/heroicons/16/solid/building-library.svg +3 -0
- data/vendor/heroicons/16/solid/building-office-2.svg +3 -0
- data/vendor/heroicons/16/solid/building-office.svg +3 -0
- data/vendor/heroicons/16/solid/building-storefront.svg +3 -0
- data/vendor/heroicons/16/solid/cake.svg +3 -0
- data/vendor/heroicons/16/solid/calculator.svg +3 -0
- data/vendor/heroicons/16/solid/calendar-date-range.svg +4 -0
- data/vendor/heroicons/16/solid/calendar-days.svg +4 -0
- data/vendor/heroicons/16/solid/calendar.svg +3 -0
- data/vendor/heroicons/16/solid/camera.svg +4 -0
- data/vendor/heroicons/16/solid/chart-bar-square.svg +3 -0
- data/vendor/heroicons/16/solid/chart-bar.svg +3 -0
- data/vendor/heroicons/16/solid/chart-pie.svg +4 -0
- data/vendor/heroicons/16/solid/chat-bubble-bottom-center-text.svg +3 -0
- data/vendor/heroicons/16/solid/chat-bubble-bottom-center.svg +3 -0
- data/vendor/heroicons/16/solid/chat-bubble-left-ellipsis.svg +3 -0
- data/vendor/heroicons/16/solid/chat-bubble-left-right.svg +4 -0
- data/vendor/heroicons/16/solid/chat-bubble-left.svg +3 -0
- data/vendor/heroicons/16/solid/chat-bubble-oval-left-ellipsis.svg +3 -0
- data/vendor/heroicons/16/solid/chat-bubble-oval-left.svg +3 -0
- data/vendor/heroicons/16/solid/check-badge.svg +3 -0
- data/vendor/heroicons/16/solid/check-circle.svg +3 -0
- data/vendor/heroicons/16/solid/check.svg +3 -0
- data/vendor/heroicons/16/solid/chevron-double-down.svg +3 -0
- data/vendor/heroicons/16/solid/chevron-double-left.svg +3 -0
- data/vendor/heroicons/16/solid/chevron-double-right.svg +3 -0
- data/vendor/heroicons/16/solid/chevron-double-up.svg +3 -0
- data/vendor/heroicons/16/solid/chevron-down.svg +3 -0
- data/vendor/heroicons/16/solid/chevron-left.svg +3 -0
- data/vendor/heroicons/16/solid/chevron-right.svg +3 -0
- data/vendor/heroicons/16/solid/chevron-up-down.svg +3 -0
- data/vendor/heroicons/16/solid/chevron-up.svg +3 -0
- data/vendor/heroicons/16/solid/circle-stack.svg +5 -0
- data/vendor/heroicons/16/solid/clipboard-document-check.svg +4 -0
- data/vendor/heroicons/16/solid/clipboard-document-list.svg +4 -0
- data/vendor/heroicons/16/solid/clipboard-document.svg +4 -0
- data/vendor/heroicons/16/solid/clipboard.svg +3 -0
- data/vendor/heroicons/16/solid/clock.svg +3 -0
- data/vendor/heroicons/16/solid/cloud-arrow-down.svg +3 -0
- data/vendor/heroicons/16/solid/cloud-arrow-up.svg +3 -0
- data/vendor/heroicons/16/solid/cloud.svg +3 -0
- data/vendor/heroicons/16/solid/code-bracket-square.svg +3 -0
- data/vendor/heroicons/16/solid/code-bracket.svg +3 -0
- data/vendor/heroicons/16/solid/cog-6-tooth.svg +3 -0
- data/vendor/heroicons/16/solid/cog-8-tooth.svg +3 -0
- data/vendor/heroicons/16/solid/cog.svg +3 -0
- data/vendor/heroicons/16/solid/command-line.svg +3 -0
- data/vendor/heroicons/16/solid/computer-desktop.svg +3 -0
- data/vendor/heroicons/16/solid/cpu-chip.svg +4 -0
- data/vendor/heroicons/16/solid/credit-card.svg +4 -0
- data/vendor/heroicons/16/solid/cube-transparent.svg +3 -0
- data/vendor/heroicons/16/solid/cube.svg +3 -0
- data/vendor/heroicons/16/solid/currency-bangladeshi.svg +3 -0
- data/vendor/heroicons/16/solid/currency-dollar.svg +4 -0
- data/vendor/heroicons/16/solid/currency-euro.svg +3 -0
- data/vendor/heroicons/16/solid/currency-pound.svg +3 -0
- data/vendor/heroicons/16/solid/currency-rupee.svg +3 -0
- data/vendor/heroicons/16/solid/currency-yen.svg +3 -0
- data/vendor/heroicons/16/solid/cursor-arrow-rays.svg +3 -0
- data/vendor/heroicons/16/solid/cursor-arrow-ripple.svg +5 -0
- data/vendor/heroicons/16/solid/device-phone-mobile.svg +4 -0
- data/vendor/heroicons/16/solid/device-tablet.svg +4 -0
- data/vendor/heroicons/16/solid/divide.svg +4 -0
- data/vendor/heroicons/16/solid/document-arrow-down.svg +3 -0
- data/vendor/heroicons/16/solid/document-arrow-up.svg +3 -0
- data/vendor/heroicons/16/solid/document-chart-bar.svg +3 -0
- data/vendor/heroicons/16/solid/document-check.svg +3 -0
- data/vendor/heroicons/16/solid/document-currency-bangladeshi.svg +3 -0
- data/vendor/heroicons/16/solid/document-currency-dollar.svg +4 -0
- data/vendor/heroicons/16/solid/document-currency-euro.svg +3 -0
- data/vendor/heroicons/16/solid/document-currency-pound.svg +3 -0
- data/vendor/heroicons/16/solid/document-currency-rupee.svg +3 -0
- data/vendor/heroicons/16/solid/document-currency-yen.svg +3 -0
- data/vendor/heroicons/16/solid/document-duplicate.svg +4 -0
- data/vendor/heroicons/16/solid/document-magnifying-glass.svg +4 -0
- data/vendor/heroicons/16/solid/document-minus.svg +3 -0
- data/vendor/heroicons/16/solid/document-plus.svg +3 -0
- data/vendor/heroicons/16/solid/document-text.svg +3 -0
- data/vendor/heroicons/16/solid/document.svg +3 -0
- data/vendor/heroicons/16/solid/ellipsis-horizontal-circle.svg +3 -0
- data/vendor/heroicons/16/solid/ellipsis-horizontal.svg +3 -0
- data/vendor/heroicons/16/solid/ellipsis-vertical.svg +3 -0
- data/vendor/heroicons/16/solid/envelope-open.svg +3 -0
- data/vendor/heroicons/16/solid/envelope.svg +4 -0
- data/vendor/heroicons/16/solid/equals.svg +3 -0
- data/vendor/heroicons/16/solid/exclamation-circle.svg +3 -0
- data/vendor/heroicons/16/solid/exclamation-triangle.svg +3 -0
- data/vendor/heroicons/16/solid/eye-dropper.svg +3 -0
- data/vendor/heroicons/16/solid/eye-slash.svg +4 -0
- data/vendor/heroicons/16/solid/eye.svg +4 -0
- data/vendor/heroicons/16/solid/face-frown.svg +3 -0
- data/vendor/heroicons/16/solid/face-smile.svg +3 -0
- data/vendor/heroicons/16/solid/film.svg +3 -0
- data/vendor/heroicons/16/solid/finger-print.svg +3 -0
- data/vendor/heroicons/16/solid/fire.svg +3 -0
- data/vendor/heroicons/16/solid/flag.svg +3 -0
- data/vendor/heroicons/16/solid/folder-arrow-down.svg +3 -0
- data/vendor/heroicons/16/solid/folder-minus.svg +3 -0
- data/vendor/heroicons/16/solid/folder-open.svg +3 -0
- data/vendor/heroicons/16/solid/folder-plus.svg +3 -0
- data/vendor/heroicons/16/solid/folder.svg +3 -0
- data/vendor/heroicons/16/solid/forward.svg +3 -0
- data/vendor/heroicons/16/solid/funnel.svg +3 -0
- data/vendor/heroicons/16/solid/gif.svg +3 -0
- data/vendor/heroicons/16/solid/gift-top.svg +4 -0
- data/vendor/heroicons/16/solid/gift.svg +4 -0
- data/vendor/heroicons/16/solid/globe-alt.svg +3 -0
- data/vendor/heroicons/16/solid/globe-americas.svg +3 -0
- data/vendor/heroicons/16/solid/globe-asia-australia.svg +3 -0
- data/vendor/heroicons/16/solid/globe-europe-africa.svg +3 -0
- data/vendor/heroicons/16/solid/h1.svg +3 -0
- data/vendor/heroicons/16/solid/h2.svg +3 -0
- data/vendor/heroicons/16/solid/h3.svg +3 -0
- data/vendor/heroicons/16/solid/hand-raised.svg +3 -0
- data/vendor/heroicons/16/solid/hand-thumb-down.svg +3 -0
- data/vendor/heroicons/16/solid/hand-thumb-up.svg +3 -0
- data/vendor/heroicons/16/solid/hashtag.svg +3 -0
- data/vendor/heroicons/16/solid/heart.svg +3 -0
- data/vendor/heroicons/16/solid/home-modern.svg +3 -0
- data/vendor/heroicons/16/solid/home.svg +3 -0
- data/vendor/heroicons/16/solid/identification.svg +3 -0
- data/vendor/heroicons/16/solid/inbox-arrow-down.svg +4 -0
- data/vendor/heroicons/16/solid/inbox-stack.svg +4 -0
- data/vendor/heroicons/16/solid/inbox.svg +3 -0
- data/vendor/heroicons/16/solid/information-circle.svg +3 -0
- data/vendor/heroicons/16/solid/italic.svg +3 -0
- data/vendor/heroicons/16/solid/key.svg +3 -0
- data/vendor/heroicons/16/solid/language.svg +3 -0
- data/vendor/heroicons/16/solid/lifebuoy.svg +3 -0
- data/vendor/heroicons/16/solid/light-bulb.svg +3 -0
- data/vendor/heroicons/16/solid/link-slash.svg +3 -0
- data/vendor/heroicons/16/solid/link.svg +4 -0
- data/vendor/heroicons/16/solid/list-bullet.svg +3 -0
- data/vendor/heroicons/16/solid/lock-closed.svg +3 -0
- data/vendor/heroicons/16/solid/lock-open.svg +3 -0
- data/vendor/heroicons/16/solid/magnifying-glass-circle.svg +4 -0
- data/vendor/heroicons/16/solid/magnifying-glass-minus.svg +4 -0
- data/vendor/heroicons/16/solid/magnifying-glass-plus.svg +4 -0
- data/vendor/heroicons/16/solid/magnifying-glass.svg +3 -0
- data/vendor/heroicons/16/solid/map-pin.svg +3 -0
- data/vendor/heroicons/16/solid/map.svg +3 -0
- data/vendor/heroicons/16/solid/megaphone.svg +3 -0
- data/vendor/heroicons/16/solid/microphone.svg +4 -0
- data/vendor/heroicons/16/solid/minus-circle.svg +3 -0
- data/vendor/heroicons/16/solid/minus.svg +3 -0
- data/vendor/heroicons/16/solid/moon.svg +3 -0
- data/vendor/heroicons/16/solid/musical-note.svg +3 -0
- data/vendor/heroicons/16/solid/newspaper.svg +4 -0
- data/vendor/heroicons/16/solid/no-symbol.svg +3 -0
- data/vendor/heroicons/16/solid/numbered-list.svg +3 -0
- data/vendor/heroicons/16/solid/paint-brush.svg +3 -0
- data/vendor/heroicons/16/solid/paper-airplane.svg +3 -0
- data/vendor/heroicons/16/solid/paper-clip.svg +3 -0
- data/vendor/heroicons/16/solid/pause-circle.svg +3 -0
- data/vendor/heroicons/16/solid/pause.svg +3 -0
- data/vendor/heroicons/16/solid/pencil-square.svg +4 -0
- data/vendor/heroicons/16/solid/pencil.svg +3 -0
- data/vendor/heroicons/16/solid/percent-badge.svg +3 -0
- data/vendor/heroicons/16/solid/phone-arrow-down-left.svg +4 -0
- data/vendor/heroicons/16/solid/phone-arrow-up-right.svg +4 -0
- data/vendor/heroicons/16/solid/phone-x-mark.svg +4 -0
- data/vendor/heroicons/16/solid/phone.svg +3 -0
- data/vendor/heroicons/16/solid/photo.svg +3 -0
- data/vendor/heroicons/16/solid/play-circle.svg +3 -0
- data/vendor/heroicons/16/solid/play-pause.svg +3 -0
- data/vendor/heroicons/16/solid/play.svg +3 -0
- data/vendor/heroicons/16/solid/plus-circle.svg +3 -0
- data/vendor/heroicons/16/solid/plus.svg +3 -0
- data/vendor/heroicons/16/solid/power.svg +3 -0
- data/vendor/heroicons/16/solid/presentation-chart-bar.svg +3 -0
- data/vendor/heroicons/16/solid/presentation-chart-line.svg +3 -0
- data/vendor/heroicons/16/solid/printer.svg +3 -0
- data/vendor/heroicons/16/solid/puzzle-piece.svg +3 -0
- data/vendor/heroicons/16/solid/qr-code.svg +9 -0
- data/vendor/heroicons/16/solid/question-mark-circle.svg +3 -0
- data/vendor/heroicons/16/solid/queue-list.svg +3 -0
- data/vendor/heroicons/16/solid/radio.svg +3 -0
- data/vendor/heroicons/16/solid/receipt-percent.svg +3 -0
- data/vendor/heroicons/16/solid/receipt-refund.svg +3 -0
- data/vendor/heroicons/16/solid/rectangle-group.svg +3 -0
- data/vendor/heroicons/16/solid/rectangle-stack.svg +3 -0
- data/vendor/heroicons/16/solid/rocket-launch.svg +4 -0
- data/vendor/heroicons/16/solid/rss.svg +3 -0
- data/vendor/heroicons/16/solid/scale.svg +3 -0
- data/vendor/heroicons/16/solid/scissors.svg +4 -0
- data/vendor/heroicons/16/solid/server-stack.svg +4 -0
- data/vendor/heroicons/16/solid/server.svg +4 -0
- data/vendor/heroicons/16/solid/share.svg +3 -0
- data/vendor/heroicons/16/solid/shield-check.svg +3 -0
- data/vendor/heroicons/16/solid/shield-exclamation.svg +3 -0
- data/vendor/heroicons/16/solid/shopping-bag.svg +3 -0
- data/vendor/heroicons/16/solid/shopping-cart.svg +3 -0
- data/vendor/heroicons/16/solid/signal-slash.svg +3 -0
- data/vendor/heroicons/16/solid/signal.svg +5 -0
- data/vendor/heroicons/16/solid/slash.svg +3 -0
- data/vendor/heroicons/16/solid/sparkles.svg +3 -0
- data/vendor/heroicons/16/solid/speaker-wave.svg +4 -0
- data/vendor/heroicons/16/solid/speaker-x-mark.svg +3 -0
- data/vendor/heroicons/16/solid/square-2-stack.svg +4 -0
- data/vendor/heroicons/16/solid/square-3-stack-3d.svg +5 -0
- data/vendor/heroicons/16/solid/squares-2x2.svg +3 -0
- data/vendor/heroicons/16/solid/squares-plus.svg +3 -0
- data/vendor/heroicons/16/solid/star.svg +3 -0
- data/vendor/heroicons/16/solid/stop-circle.svg +3 -0
- data/vendor/heroicons/16/solid/stop.svg +3 -0
- data/vendor/heroicons/16/solid/strikethrough.svg +3 -0
- data/vendor/heroicons/16/solid/sun.svg +3 -0
- data/vendor/heroicons/16/solid/swatch.svg +4 -0
- data/vendor/heroicons/16/solid/table-cells.svg +3 -0
- data/vendor/heroicons/16/solid/tag.svg +3 -0
- data/vendor/heroicons/16/solid/ticket.svg +3 -0
- data/vendor/heroicons/16/solid/trash.svg +3 -0
- data/vendor/heroicons/16/solid/trophy.svg +3 -0
- data/vendor/heroicons/16/solid/truck.svg +5 -0
- data/vendor/heroicons/16/solid/tv.svg +4 -0
- data/vendor/heroicons/16/solid/underline.svg +3 -0
- data/vendor/heroicons/16/solid/user-circle.svg +3 -0
- data/vendor/heroicons/16/solid/user-group.svg +3 -0
- data/vendor/heroicons/16/solid/user-minus.svg +3 -0
- data/vendor/heroicons/16/solid/user-plus.svg +3 -0
- data/vendor/heroicons/16/solid/user.svg +3 -0
- data/vendor/heroicons/16/solid/users.svg +3 -0
- data/vendor/heroicons/16/solid/variable.svg +3 -0
- data/vendor/heroicons/16/solid/video-camera-slash.svg +3 -0
- data/vendor/heroicons/16/solid/video-camera.svg +3 -0
- data/vendor/heroicons/16/solid/view-columns.svg +3 -0
- data/vendor/heroicons/16/solid/viewfinder-circle.svg +3 -0
- data/vendor/heroicons/16/solid/wallet.svg +3 -0
- data/vendor/heroicons/16/solid/wifi.svg +3 -0
- data/vendor/heroicons/16/solid/window.svg +3 -0
- data/vendor/heroicons/16/solid/wrench-screwdriver.svg +4 -0
- data/vendor/heroicons/16/solid/wrench.svg +3 -0
- data/vendor/heroicons/16/solid/x-circle.svg +3 -0
- data/vendor/heroicons/16/solid/x-mark.svg +3 -0
- data/vendor/heroicons/20/solid/academic-cap.svg +3 -0
- data/vendor/heroicons/20/solid/adjustments-horizontal.svg +3 -0
- data/vendor/heroicons/20/solid/adjustments-vertical.svg +3 -0
- data/vendor/heroicons/20/solid/archive-box-arrow-down.svg +3 -0
- data/vendor/heroicons/20/solid/archive-box-x-mark.svg +4 -0
- data/vendor/heroicons/20/solid/archive-box.svg +4 -0
- data/vendor/heroicons/20/solid/arrow-down-circle.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-down-left.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-down-on-square-stack.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-down-on-square.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-down-right.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-down-tray.svg +4 -0
- data/vendor/heroicons/20/solid/arrow-down.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-left-circle.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-left-end-on-rectangle.svg +4 -0
- data/vendor/heroicons/20/solid/arrow-left-on-rectangle.svg +4 -0
- data/vendor/heroicons/20/solid/arrow-left-start-on-rectangle.svg +4 -0
- data/vendor/heroicons/20/solid/arrow-left.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-long-down.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-long-left.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-long-right.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-long-up.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-path-rounded-square.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-path.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-right-circle.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-right-end-on-rectangle.svg +4 -0
- data/vendor/heroicons/20/solid/arrow-right-on-rectangle.svg +4 -0
- data/vendor/heroicons/20/solid/arrow-right-start-on-rectangle.svg +4 -0
- data/vendor/heroicons/20/solid/arrow-right.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-small-down.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-small-left.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-small-right.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-small-up.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-top-right-on-square.svg +4 -0
- data/vendor/heroicons/20/solid/arrow-trending-down.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-trending-up.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-turn-down-left.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-turn-down-right.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-turn-left-down.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-turn-left-up.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-turn-right-down.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-turn-right-up.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-turn-up-left.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-turn-up-right.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-up-circle.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-up-left.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-up-on-square-stack.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-up-on-square.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-up-right.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-up-tray.svg +4 -0
- data/vendor/heroicons/20/solid/arrow-up.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-uturn-down.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-uturn-left.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-uturn-right.svg +3 -0
- data/vendor/heroicons/20/solid/arrow-uturn-up.svg +3 -0
- data/vendor/heroicons/20/solid/arrows-pointing-in.svg +3 -0
- data/vendor/heroicons/20/solid/arrows-pointing-out.svg +3 -0
- data/vendor/heroicons/20/solid/arrows-right-left.svg +3 -0
- data/vendor/heroicons/20/solid/arrows-up-down.svg +3 -0
- data/vendor/heroicons/20/solid/at-symbol.svg +3 -0
- data/vendor/heroicons/20/solid/backspace.svg +3 -0
- data/vendor/heroicons/20/solid/backward.svg +3 -0
- data/vendor/heroicons/20/solid/banknotes.svg +3 -0
- data/vendor/heroicons/20/solid/bars-2.svg +3 -0
- data/vendor/heroicons/20/solid/bars-3-bottom-left.svg +3 -0
- data/vendor/heroicons/20/solid/bars-3-bottom-right.svg +3 -0
- data/vendor/heroicons/20/solid/bars-3-center-left.svg +3 -0
- data/vendor/heroicons/20/solid/bars-3.svg +3 -0
- data/vendor/heroicons/20/solid/bars-4.svg +3 -0
- data/vendor/heroicons/20/solid/bars-arrow-down.svg +3 -0
- data/vendor/heroicons/20/solid/bars-arrow-up.svg +3 -0
- data/vendor/heroicons/20/solid/battery-0.svg +3 -0
- data/vendor/heroicons/20/solid/battery-100.svg +4 -0
- data/vendor/heroicons/20/solid/battery-50.svg +4 -0
- data/vendor/heroicons/20/solid/beaker.svg +3 -0
- data/vendor/heroicons/20/solid/bell-alert.svg +4 -0
- data/vendor/heroicons/20/solid/bell-slash.svg +3 -0
- data/vendor/heroicons/20/solid/bell-snooze.svg +3 -0
- data/vendor/heroicons/20/solid/bell.svg +3 -0
- data/vendor/heroicons/20/solid/bold.svg +3 -0
- data/vendor/heroicons/20/solid/bolt-slash.svg +4 -0
- data/vendor/heroicons/20/solid/bolt.svg +3 -0
- data/vendor/heroicons/20/solid/book-open.svg +3 -0
- data/vendor/heroicons/20/solid/bookmark-slash.svg +3 -0
- data/vendor/heroicons/20/solid/bookmark-square.svg +3 -0
- data/vendor/heroicons/20/solid/bookmark.svg +3 -0
- data/vendor/heroicons/20/solid/briefcase.svg +4 -0
- data/vendor/heroicons/20/solid/bug-ant.svg +3 -0
- data/vendor/heroicons/20/solid/building-library.svg +3 -0
- data/vendor/heroicons/20/solid/building-office-2.svg +3 -0
- data/vendor/heroicons/20/solid/building-office.svg +3 -0
- data/vendor/heroicons/20/solid/building-storefront.svg +3 -0
- data/vendor/heroicons/20/solid/cake.svg +3 -0
- data/vendor/heroicons/20/solid/calculator.svg +3 -0
- data/vendor/heroicons/20/solid/calendar-date-range.svg +4 -0
- data/vendor/heroicons/20/solid/calendar-days.svg +4 -0
- data/vendor/heroicons/20/solid/calendar.svg +3 -0
- data/vendor/heroicons/20/solid/camera.svg +3 -0
- data/vendor/heroicons/20/solid/chart-bar-square.svg +3 -0
- data/vendor/heroicons/20/solid/chart-bar.svg +3 -0
- data/vendor/heroicons/20/solid/chart-pie.svg +4 -0
- data/vendor/heroicons/20/solid/chat-bubble-bottom-center-text.svg +3 -0
- data/vendor/heroicons/20/solid/chat-bubble-bottom-center.svg +3 -0
- data/vendor/heroicons/20/solid/chat-bubble-left-ellipsis.svg +3 -0
- data/vendor/heroicons/20/solid/chat-bubble-left-right.svg +4 -0
- data/vendor/heroicons/20/solid/chat-bubble-left.svg +3 -0
- data/vendor/heroicons/20/solid/chat-bubble-oval-left-ellipsis.svg +3 -0
- data/vendor/heroicons/20/solid/chat-bubble-oval-left.svg +3 -0
- data/vendor/heroicons/20/solid/check-badge.svg +3 -0
- data/vendor/heroicons/20/solid/check-circle.svg +3 -0
- data/vendor/heroicons/20/solid/check.svg +3 -0
- data/vendor/heroicons/20/solid/chevron-double-down.svg +3 -0
- data/vendor/heroicons/20/solid/chevron-double-left.svg +3 -0
- data/vendor/heroicons/20/solid/chevron-double-right.svg +3 -0
- data/vendor/heroicons/20/solid/chevron-double-up.svg +3 -0
- data/vendor/heroicons/20/solid/chevron-down.svg +3 -0
- data/vendor/heroicons/20/solid/chevron-left.svg +3 -0
- data/vendor/heroicons/20/solid/chevron-right.svg +3 -0
- data/vendor/heroicons/20/solid/chevron-up-down.svg +3 -0
- data/vendor/heroicons/20/solid/chevron-up.svg +3 -0
- data/vendor/heroicons/20/solid/circle-stack.svg +3 -0
- data/vendor/heroicons/20/solid/clipboard-document-check.svg +4 -0
- data/vendor/heroicons/20/solid/clipboard-document-list.svg +4 -0
- data/vendor/heroicons/20/solid/clipboard-document.svg +4 -0
- data/vendor/heroicons/20/solid/clipboard.svg +3 -0
- data/vendor/heroicons/20/solid/clock.svg +3 -0
- data/vendor/heroicons/20/solid/cloud-arrow-down.svg +3 -0
- data/vendor/heroicons/20/solid/cloud-arrow-up.svg +3 -0
- data/vendor/heroicons/20/solid/cloud.svg +3 -0
- data/vendor/heroicons/20/solid/code-bracket-square.svg +3 -0
- data/vendor/heroicons/20/solid/code-bracket.svg +3 -0
- data/vendor/heroicons/20/solid/cog-6-tooth.svg +3 -0
- data/vendor/heroicons/20/solid/cog-8-tooth.svg +3 -0
- data/vendor/heroicons/20/solid/cog.svg +4 -0
- data/vendor/heroicons/20/solid/command-line.svg +3 -0
- data/vendor/heroicons/20/solid/computer-desktop.svg +3 -0
- data/vendor/heroicons/20/solid/cpu-chip.svg +4 -0
- data/vendor/heroicons/20/solid/credit-card.svg +3 -0
- data/vendor/heroicons/20/solid/cube-transparent.svg +3 -0
- data/vendor/heroicons/20/solid/cube.svg +3 -0
- data/vendor/heroicons/20/solid/currency-bangladeshi.svg +3 -0
- data/vendor/heroicons/20/solid/currency-dollar.svg +4 -0
- data/vendor/heroicons/20/solid/currency-euro.svg +3 -0
- data/vendor/heroicons/20/solid/currency-pound.svg +3 -0
- data/vendor/heroicons/20/solid/currency-rupee.svg +3 -0
- data/vendor/heroicons/20/solid/currency-yen.svg +3 -0
- data/vendor/heroicons/20/solid/cursor-arrow-rays.svg +3 -0
- data/vendor/heroicons/20/solid/cursor-arrow-ripple.svg +5 -0
- data/vendor/heroicons/20/solid/device-phone-mobile.svg +4 -0
- data/vendor/heroicons/20/solid/device-tablet.svg +3 -0
- data/vendor/heroicons/20/solid/divide.svg +3 -0
- data/vendor/heroicons/20/solid/document-arrow-down.svg +3 -0
- data/vendor/heroicons/20/solid/document-arrow-up.svg +3 -0
- data/vendor/heroicons/20/solid/document-chart-bar.svg +3 -0
- data/vendor/heroicons/20/solid/document-check.svg +3 -0
- data/vendor/heroicons/20/solid/document-currency-bangladeshi.svg +3 -0
- data/vendor/heroicons/20/solid/document-currency-dollar.svg +3 -0
- data/vendor/heroicons/20/solid/document-currency-euro.svg +3 -0
- data/vendor/heroicons/20/solid/document-currency-pound.svg +3 -0
- data/vendor/heroicons/20/solid/document-currency-rupee.svg +3 -0
- data/vendor/heroicons/20/solid/document-currency-yen.svg +3 -0
- data/vendor/heroicons/20/solid/document-duplicate.svg +4 -0
- data/vendor/heroicons/20/solid/document-magnifying-glass.svg +4 -0
- data/vendor/heroicons/20/solid/document-minus.svg +3 -0
- data/vendor/heroicons/20/solid/document-plus.svg +3 -0
- data/vendor/heroicons/20/solid/document-text.svg +3 -0
- data/vendor/heroicons/20/solid/document.svg +3 -0
- data/vendor/heroicons/20/solid/ellipsis-horizontal-circle.svg +3 -0
- data/vendor/heroicons/20/solid/ellipsis-horizontal.svg +3 -0
- data/vendor/heroicons/20/solid/ellipsis-vertical.svg +3 -0
- data/vendor/heroicons/20/solid/envelope-open.svg +3 -0
- data/vendor/heroicons/20/solid/envelope.svg +4 -0
- data/vendor/heroicons/20/solid/equals.svg +3 -0
- data/vendor/heroicons/20/solid/exclamation-circle.svg +3 -0
- data/vendor/heroicons/20/solid/exclamation-triangle.svg +3 -0
- data/vendor/heroicons/20/solid/eye-dropper.svg +3 -0
- data/vendor/heroicons/20/solid/eye-slash.svg +4 -0
- data/vendor/heroicons/20/solid/eye.svg +4 -0
- data/vendor/heroicons/20/solid/face-frown.svg +3 -0
- data/vendor/heroicons/20/solid/face-smile.svg +3 -0
- data/vendor/heroicons/20/solid/film.svg +3 -0
- data/vendor/heroicons/20/solid/finger-print.svg +3 -0
- data/vendor/heroicons/20/solid/fire.svg +3 -0
- data/vendor/heroicons/20/solid/flag.svg +3 -0
- data/vendor/heroicons/20/solid/folder-arrow-down.svg +3 -0
- data/vendor/heroicons/20/solid/folder-minus.svg +3 -0
- data/vendor/heroicons/20/solid/folder-open.svg +3 -0
- data/vendor/heroicons/20/solid/folder-plus.svg +3 -0
- data/vendor/heroicons/20/solid/folder.svg +3 -0
- data/vendor/heroicons/20/solid/forward.svg +3 -0
- data/vendor/heroicons/20/solid/funnel.svg +3 -0
- data/vendor/heroicons/20/solid/gif.svg +3 -0
- data/vendor/heroicons/20/solid/gift-top.svg +3 -0
- data/vendor/heroicons/20/solid/gift.svg +4 -0
- data/vendor/heroicons/20/solid/globe-alt.svg +3 -0
- data/vendor/heroicons/20/solid/globe-americas.svg +3 -0
- data/vendor/heroicons/20/solid/globe-asia-australia.svg +3 -0
- data/vendor/heroicons/20/solid/globe-europe-africa.svg +3 -0
- data/vendor/heroicons/20/solid/h1.svg +3 -0
- data/vendor/heroicons/20/solid/h2.svg +3 -0
- data/vendor/heroicons/20/solid/h3.svg +3 -0
- data/vendor/heroicons/20/solid/hand-raised.svg +3 -0
- data/vendor/heroicons/20/solid/hand-thumb-down.svg +3 -0
- data/vendor/heroicons/20/solid/hand-thumb-up.svg +3 -0
- data/vendor/heroicons/20/solid/hashtag.svg +3 -0
- data/vendor/heroicons/20/solid/heart.svg +3 -0
- data/vendor/heroicons/20/solid/home-modern.svg +3 -0
- data/vendor/heroicons/20/solid/home.svg +3 -0
- data/vendor/heroicons/20/solid/identification.svg +3 -0
- data/vendor/heroicons/20/solid/inbox-arrow-down.svg +4 -0
- data/vendor/heroicons/20/solid/inbox-stack.svg +4 -0
- data/vendor/heroicons/20/solid/inbox.svg +3 -0
- data/vendor/heroicons/20/solid/information-circle.svg +3 -0
- data/vendor/heroicons/20/solid/italic.svg +3 -0
- data/vendor/heroicons/20/solid/key.svg +3 -0
- data/vendor/heroicons/20/solid/language.svg +4 -0
- data/vendor/heroicons/20/solid/lifebuoy.svg +3 -0
- data/vendor/heroicons/20/solid/light-bulb.svg +3 -0
- data/vendor/heroicons/20/solid/link-slash.svg +3 -0
- data/vendor/heroicons/20/solid/link.svg +4 -0
- data/vendor/heroicons/20/solid/list-bullet.svg +3 -0
- data/vendor/heroicons/20/solid/lock-closed.svg +3 -0
- data/vendor/heroicons/20/solid/lock-open.svg +3 -0
- data/vendor/heroicons/20/solid/magnifying-glass-circle.svg +4 -0
- data/vendor/heroicons/20/solid/magnifying-glass-minus.svg +4 -0
- data/vendor/heroicons/20/solid/magnifying-glass-plus.svg +4 -0
- data/vendor/heroicons/20/solid/magnifying-glass.svg +3 -0
- data/vendor/heroicons/20/solid/map-pin.svg +3 -0
- data/vendor/heroicons/20/solid/map.svg +3 -0
- data/vendor/heroicons/20/solid/megaphone.svg +3 -0
- data/vendor/heroicons/20/solid/microphone.svg +4 -0
- data/vendor/heroicons/20/solid/minus-circle.svg +3 -0
- data/vendor/heroicons/20/solid/minus-small.svg +3 -0
- data/vendor/heroicons/20/solid/minus.svg +3 -0
- data/vendor/heroicons/20/solid/moon.svg +3 -0
- data/vendor/heroicons/20/solid/musical-note.svg +3 -0
- data/vendor/heroicons/20/solid/newspaper.svg +4 -0
- data/vendor/heroicons/20/solid/no-symbol.svg +3 -0
- data/vendor/heroicons/20/solid/numbered-list.svg +3 -0
- data/vendor/heroicons/20/solid/paint-brush.svg +3 -0
- data/vendor/heroicons/20/solid/paper-airplane.svg +3 -0
- data/vendor/heroicons/20/solid/paper-clip.svg +3 -0
- data/vendor/heroicons/20/solid/pause-circle.svg +3 -0
- data/vendor/heroicons/20/solid/pause.svg +3 -0
- data/vendor/heroicons/20/solid/pencil-square.svg +4 -0
- data/vendor/heroicons/20/solid/pencil.svg +3 -0
- data/vendor/heroicons/20/solid/percent-badge.svg +3 -0
- data/vendor/heroicons/20/solid/phone-arrow-down-left.svg +3 -0
- data/vendor/heroicons/20/solid/phone-arrow-up-right.svg +3 -0
- data/vendor/heroicons/20/solid/phone-x-mark.svg +3 -0
- data/vendor/heroicons/20/solid/phone.svg +3 -0
- data/vendor/heroicons/20/solid/photo.svg +3 -0
- data/vendor/heroicons/20/solid/play-circle.svg +3 -0
- data/vendor/heroicons/20/solid/play-pause.svg +3 -0
- data/vendor/heroicons/20/solid/play.svg +3 -0
- data/vendor/heroicons/20/solid/plus-circle.svg +3 -0
- data/vendor/heroicons/20/solid/plus-small.svg +3 -0
- data/vendor/heroicons/20/solid/plus.svg +3 -0
- data/vendor/heroicons/20/solid/power.svg +3 -0
- data/vendor/heroicons/20/solid/presentation-chart-bar.svg +3 -0
- data/vendor/heroicons/20/solid/presentation-chart-line.svg +3 -0
- data/vendor/heroicons/20/solid/printer.svg +3 -0
- data/vendor/heroicons/20/solid/puzzle-piece.svg +3 -0
- data/vendor/heroicons/20/solid/qr-code.svg +3 -0
- data/vendor/heroicons/20/solid/question-mark-circle.svg +3 -0
- data/vendor/heroicons/20/solid/queue-list.svg +3 -0
- data/vendor/heroicons/20/solid/radio.svg +3 -0
- data/vendor/heroicons/20/solid/receipt-percent.svg +3 -0
- data/vendor/heroicons/20/solid/receipt-refund.svg +3 -0
- data/vendor/heroicons/20/solid/rectangle-group.svg +3 -0
- data/vendor/heroicons/20/solid/rectangle-stack.svg +3 -0
- data/vendor/heroicons/20/solid/rocket-launch.svg +4 -0
- data/vendor/heroicons/20/solid/rss.svg +4 -0
- data/vendor/heroicons/20/solid/scale.svg +3 -0
- data/vendor/heroicons/20/solid/scissors.svg +4 -0
- data/vendor/heroicons/20/solid/server-stack.svg +4 -0
- data/vendor/heroicons/20/solid/server.svg +4 -0
- data/vendor/heroicons/20/solid/share.svg +3 -0
- data/vendor/heroicons/20/solid/shield-check.svg +3 -0
- data/vendor/heroicons/20/solid/shield-exclamation.svg +3 -0
- data/vendor/heroicons/20/solid/shopping-bag.svg +3 -0
- data/vendor/heroicons/20/solid/shopping-cart.svg +3 -0
- data/vendor/heroicons/20/solid/signal-slash.svg +3 -0
- data/vendor/heroicons/20/solid/signal.svg +4 -0
- data/vendor/heroicons/20/solid/slash.svg +3 -0
- data/vendor/heroicons/20/solid/sparkles.svg +3 -0
- data/vendor/heroicons/20/solid/speaker-wave.svg +4 -0
- data/vendor/heroicons/20/solid/speaker-x-mark.svg +3 -0
- data/vendor/heroicons/20/solid/square-2-stack.svg +4 -0
- data/vendor/heroicons/20/solid/square-3-stack-3d.svg +5 -0
- data/vendor/heroicons/20/solid/squares-2x2.svg +3 -0
- data/vendor/heroicons/20/solid/squares-plus.svg +3 -0
- data/vendor/heroicons/20/solid/star.svg +3 -0
- data/vendor/heroicons/20/solid/stop-circle.svg +3 -0
- data/vendor/heroicons/20/solid/stop.svg +3 -0
- data/vendor/heroicons/20/solid/strikethrough.svg +3 -0
- data/vendor/heroicons/20/solid/sun.svg +3 -0
- data/vendor/heroicons/20/solid/swatch.svg +3 -0
- data/vendor/heroicons/20/solid/table-cells.svg +3 -0
- data/vendor/heroicons/20/solid/tag.svg +3 -0
- data/vendor/heroicons/20/solid/ticket.svg +3 -0
- data/vendor/heroicons/20/solid/trash.svg +3 -0
- data/vendor/heroicons/20/solid/trophy.svg +3 -0
- data/vendor/heroicons/20/solid/truck.svg +4 -0
- data/vendor/heroicons/20/solid/tv.svg +4 -0
- data/vendor/heroicons/20/solid/underline.svg +3 -0
- data/vendor/heroicons/20/solid/user-circle.svg +3 -0
- data/vendor/heroicons/20/solid/user-group.svg +3 -0
- data/vendor/heroicons/20/solid/user-minus.svg +3 -0
- data/vendor/heroicons/20/solid/user-plus.svg +3 -0
- data/vendor/heroicons/20/solid/user.svg +3 -0
- data/vendor/heroicons/20/solid/users.svg +3 -0
- data/vendor/heroicons/20/solid/variable.svg +3 -0
- data/vendor/heroicons/20/solid/video-camera-slash.svg +3 -0
- data/vendor/heroicons/20/solid/video-camera.svg +3 -0
- data/vendor/heroicons/20/solid/view-columns.svg +3 -0
- data/vendor/heroicons/20/solid/viewfinder-circle.svg +3 -0
- data/vendor/heroicons/20/solid/wallet.svg +3 -0
- data/vendor/heroicons/20/solid/wifi.svg +3 -0
- data/vendor/heroicons/20/solid/window.svg +3 -0
- data/vendor/heroicons/20/solid/wrench-screwdriver.svg +4 -0
- data/vendor/heroicons/20/solid/wrench.svg +3 -0
- data/vendor/heroicons/20/solid/x-circle.svg +3 -0
- data/vendor/heroicons/20/solid/x-mark.svg +3 -0
- data/vendor/heroicons/24/outline/academic-cap.svg +3 -0
- data/vendor/heroicons/24/outline/adjustments-horizontal.svg +3 -0
- data/vendor/heroicons/24/outline/adjustments-vertical.svg +3 -0
- data/vendor/heroicons/24/outline/archive-box-arrow-down.svg +3 -0
- data/vendor/heroicons/24/outline/archive-box-x-mark.svg +3 -0
- data/vendor/heroicons/24/outline/archive-box.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-down-circle.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-down-left.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-down-on-square-stack.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-down-on-square.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-down-right.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-down-tray.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-down.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-left-circle.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-left-end-on-rectangle.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-left-on-rectangle.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-left-start-on-rectangle.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-left.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-long-down.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-long-left.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-long-right.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-long-up.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-path-rounded-square.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-path.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-right-circle.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-right-end-on-rectangle.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-right-on-rectangle.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-right-start-on-rectangle.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-right.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-small-down.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-small-left.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-small-right.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-small-up.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-top-right-on-square.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-trending-down.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-trending-up.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-turn-down-left.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-turn-down-right.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-turn-left-down.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-turn-left-up.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-turn-right-down.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-turn-right-up.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-turn-up-left.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-turn-up-right.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-up-circle.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-up-left.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-up-on-square-stack.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-up-on-square.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-up-right.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-up-tray.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-up.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-uturn-down.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-uturn-left.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-uturn-right.svg +3 -0
- data/vendor/heroicons/24/outline/arrow-uturn-up.svg +3 -0
- data/vendor/heroicons/24/outline/arrows-pointing-in.svg +3 -0
- data/vendor/heroicons/24/outline/arrows-pointing-out.svg +3 -0
- data/vendor/heroicons/24/outline/arrows-right-left.svg +3 -0
- data/vendor/heroicons/24/outline/arrows-up-down.svg +3 -0
- data/vendor/heroicons/24/outline/at-symbol.svg +3 -0
- data/vendor/heroicons/24/outline/backspace.svg +3 -0
- data/vendor/heroicons/24/outline/backward.svg +3 -0
- data/vendor/heroicons/24/outline/banknotes.svg +3 -0
- data/vendor/heroicons/24/outline/bars-2.svg +3 -0
- data/vendor/heroicons/24/outline/bars-3-bottom-left.svg +3 -0
- data/vendor/heroicons/24/outline/bars-3-bottom-right.svg +3 -0
- data/vendor/heroicons/24/outline/bars-3-center-left.svg +3 -0
- data/vendor/heroicons/24/outline/bars-3.svg +3 -0
- data/vendor/heroicons/24/outline/bars-4.svg +3 -0
- data/vendor/heroicons/24/outline/bars-arrow-down.svg +3 -0
- data/vendor/heroicons/24/outline/bars-arrow-up.svg +3 -0
- data/vendor/heroicons/24/outline/battery-0.svg +3 -0
- data/vendor/heroicons/24/outline/battery-100.svg +3 -0
- data/vendor/heroicons/24/outline/battery-50.svg +3 -0
- data/vendor/heroicons/24/outline/beaker.svg +3 -0
- data/vendor/heroicons/24/outline/bell-alert.svg +3 -0
- data/vendor/heroicons/24/outline/bell-slash.svg +3 -0
- data/vendor/heroicons/24/outline/bell-snooze.svg +3 -0
- data/vendor/heroicons/24/outline/bell.svg +3 -0
- data/vendor/heroicons/24/outline/bold.svg +3 -0
- data/vendor/heroicons/24/outline/bolt-slash.svg +3 -0
- data/vendor/heroicons/24/outline/bolt.svg +3 -0
- data/vendor/heroicons/24/outline/book-open.svg +3 -0
- data/vendor/heroicons/24/outline/bookmark-slash.svg +3 -0
- data/vendor/heroicons/24/outline/bookmark-square.svg +3 -0
- data/vendor/heroicons/24/outline/bookmark.svg +3 -0
- data/vendor/heroicons/24/outline/briefcase.svg +3 -0
- data/vendor/heroicons/24/outline/bug-ant.svg +3 -0
- data/vendor/heroicons/24/outline/building-library.svg +3 -0
- data/vendor/heroicons/24/outline/building-office-2.svg +3 -0
- data/vendor/heroicons/24/outline/building-office.svg +3 -0
- data/vendor/heroicons/24/outline/building-storefront.svg +3 -0
- data/vendor/heroicons/24/outline/cake.svg +3 -0
- data/vendor/heroicons/24/outline/calculator.svg +3 -0
- data/vendor/heroicons/24/outline/calendar-date-range.svg +3 -0
- data/vendor/heroicons/24/outline/calendar-days.svg +3 -0
- data/vendor/heroicons/24/outline/calendar.svg +3 -0
- data/vendor/heroicons/24/outline/camera.svg +4 -0
- data/vendor/heroicons/24/outline/chart-bar-square.svg +3 -0
- data/vendor/heroicons/24/outline/chart-bar.svg +3 -0
- data/vendor/heroicons/24/outline/chart-pie.svg +4 -0
- data/vendor/heroicons/24/outline/chat-bubble-bottom-center-text.svg +3 -0
- data/vendor/heroicons/24/outline/chat-bubble-bottom-center.svg +3 -0
- data/vendor/heroicons/24/outline/chat-bubble-left-ellipsis.svg +3 -0
- data/vendor/heroicons/24/outline/chat-bubble-left-right.svg +3 -0
- data/vendor/heroicons/24/outline/chat-bubble-left.svg +3 -0
- data/vendor/heroicons/24/outline/chat-bubble-oval-left-ellipsis.svg +3 -0
- data/vendor/heroicons/24/outline/chat-bubble-oval-left.svg +3 -0
- data/vendor/heroicons/24/outline/check-badge.svg +3 -0
- data/vendor/heroicons/24/outline/check-circle.svg +3 -0
- data/vendor/heroicons/24/outline/check.svg +3 -0
- data/vendor/heroicons/24/outline/chevron-double-down.svg +3 -0
- data/vendor/heroicons/24/outline/chevron-double-left.svg +3 -0
- data/vendor/heroicons/24/outline/chevron-double-right.svg +3 -0
- data/vendor/heroicons/24/outline/chevron-double-up.svg +4 -0
- data/vendor/heroicons/24/outline/chevron-down.svg +3 -0
- data/vendor/heroicons/24/outline/chevron-left.svg +3 -0
- data/vendor/heroicons/24/outline/chevron-right.svg +3 -0
- data/vendor/heroicons/24/outline/chevron-up-down.svg +3 -0
- data/vendor/heroicons/24/outline/chevron-up.svg +3 -0
- data/vendor/heroicons/24/outline/circle-stack.svg +3 -0
- data/vendor/heroicons/24/outline/clipboard-document-check.svg +3 -0
- data/vendor/heroicons/24/outline/clipboard-document-list.svg +3 -0
- data/vendor/heroicons/24/outline/clipboard-document.svg +3 -0
- data/vendor/heroicons/24/outline/clipboard.svg +3 -0
- data/vendor/heroicons/24/outline/clock.svg +3 -0
- data/vendor/heroicons/24/outline/cloud-arrow-down.svg +3 -0
- data/vendor/heroicons/24/outline/cloud-arrow-up.svg +3 -0
- data/vendor/heroicons/24/outline/cloud.svg +3 -0
- data/vendor/heroicons/24/outline/code-bracket-square.svg +3 -0
- data/vendor/heroicons/24/outline/code-bracket.svg +3 -0
- data/vendor/heroicons/24/outline/cog-6-tooth.svg +4 -0
- data/vendor/heroicons/24/outline/cog-8-tooth.svg +4 -0
- data/vendor/heroicons/24/outline/cog.svg +3 -0
- data/vendor/heroicons/24/outline/command-line.svg +3 -0
- data/vendor/heroicons/24/outline/computer-desktop.svg +3 -0
- data/vendor/heroicons/24/outline/cpu-chip.svg +3 -0
- data/vendor/heroicons/24/outline/credit-card.svg +3 -0
- data/vendor/heroicons/24/outline/cube-transparent.svg +3 -0
- data/vendor/heroicons/24/outline/cube.svg +3 -0
- data/vendor/heroicons/24/outline/currency-bangladeshi.svg +3 -0
- data/vendor/heroicons/24/outline/currency-dollar.svg +3 -0
- data/vendor/heroicons/24/outline/currency-euro.svg +3 -0
- data/vendor/heroicons/24/outline/currency-pound.svg +3 -0
- data/vendor/heroicons/24/outline/currency-rupee.svg +3 -0
- data/vendor/heroicons/24/outline/currency-yen.svg +3 -0
- data/vendor/heroicons/24/outline/cursor-arrow-rays.svg +3 -0
- data/vendor/heroicons/24/outline/cursor-arrow-ripple.svg +3 -0
- data/vendor/heroicons/24/outline/device-phone-mobile.svg +3 -0
- data/vendor/heroicons/24/outline/device-tablet.svg +3 -0
- data/vendor/heroicons/24/outline/divide.svg +3 -0
- data/vendor/heroicons/24/outline/document-arrow-down.svg +3 -0
- data/vendor/heroicons/24/outline/document-arrow-up.svg +3 -0
- data/vendor/heroicons/24/outline/document-chart-bar.svg +3 -0
- data/vendor/heroicons/24/outline/document-check.svg +3 -0
- data/vendor/heroicons/24/outline/document-currency-bangladeshi.svg +3 -0
- data/vendor/heroicons/24/outline/document-currency-dollar.svg +3 -0
- data/vendor/heroicons/24/outline/document-currency-euro.svg +3 -0
- data/vendor/heroicons/24/outline/document-currency-pound.svg +3 -0
- data/vendor/heroicons/24/outline/document-currency-rupee.svg +3 -0
- data/vendor/heroicons/24/outline/document-currency-yen.svg +3 -0
- data/vendor/heroicons/24/outline/document-duplicate.svg +3 -0
- data/vendor/heroicons/24/outline/document-magnifying-glass.svg +3 -0
- data/vendor/heroicons/24/outline/document-minus.svg +3 -0
- data/vendor/heroicons/24/outline/document-plus.svg +3 -0
- data/vendor/heroicons/24/outline/document-text.svg +3 -0
- data/vendor/heroicons/24/outline/document.svg +3 -0
- data/vendor/heroicons/24/outline/ellipsis-horizontal-circle.svg +3 -0
- data/vendor/heroicons/24/outline/ellipsis-horizontal.svg +3 -0
- data/vendor/heroicons/24/outline/ellipsis-vertical.svg +3 -0
- data/vendor/heroicons/24/outline/envelope-open.svg +3 -0
- data/vendor/heroicons/24/outline/envelope.svg +3 -0
- data/vendor/heroicons/24/outline/equals.svg +3 -0
- data/vendor/heroicons/24/outline/exclamation-circle.svg +3 -0
- data/vendor/heroicons/24/outline/exclamation-triangle.svg +3 -0
- data/vendor/heroicons/24/outline/eye-dropper.svg +3 -0
- data/vendor/heroicons/24/outline/eye-slash.svg +3 -0
- data/vendor/heroicons/24/outline/eye.svg +4 -0
- data/vendor/heroicons/24/outline/face-frown.svg +3 -0
- data/vendor/heroicons/24/outline/face-smile.svg +3 -0
- data/vendor/heroicons/24/outline/film.svg +3 -0
- data/vendor/heroicons/24/outline/finger-print.svg +3 -0
- data/vendor/heroicons/24/outline/fire.svg +4 -0
- data/vendor/heroicons/24/outline/flag.svg +3 -0
- data/vendor/heroicons/24/outline/folder-arrow-down.svg +3 -0
- data/vendor/heroicons/24/outline/folder-minus.svg +3 -0
- data/vendor/heroicons/24/outline/folder-open.svg +3 -0
- data/vendor/heroicons/24/outline/folder-plus.svg +3 -0
- data/vendor/heroicons/24/outline/folder.svg +3 -0
- data/vendor/heroicons/24/outline/forward.svg +3 -0
- data/vendor/heroicons/24/outline/funnel.svg +3 -0
- data/vendor/heroicons/24/outline/gif.svg +3 -0
- data/vendor/heroicons/24/outline/gift-top.svg +3 -0
- data/vendor/heroicons/24/outline/gift.svg +3 -0
- data/vendor/heroicons/24/outline/globe-alt.svg +3 -0
- data/vendor/heroicons/24/outline/globe-americas.svg +3 -0
- data/vendor/heroicons/24/outline/globe-asia-australia.svg +3 -0
- data/vendor/heroicons/24/outline/globe-europe-africa.svg +3 -0
- data/vendor/heroicons/24/outline/h1.svg +3 -0
- data/vendor/heroicons/24/outline/h2.svg +3 -0
- data/vendor/heroicons/24/outline/h3.svg +3 -0
- data/vendor/heroicons/24/outline/hand-raised.svg +3 -0
- data/vendor/heroicons/24/outline/hand-thumb-down.svg +3 -0
- data/vendor/heroicons/24/outline/hand-thumb-up.svg +3 -0
- data/vendor/heroicons/24/outline/hashtag.svg +3 -0
- data/vendor/heroicons/24/outline/heart.svg +3 -0
- data/vendor/heroicons/24/outline/home-modern.svg +3 -0
- data/vendor/heroicons/24/outline/home.svg +3 -0
- data/vendor/heroicons/24/outline/identification.svg +3 -0
- data/vendor/heroicons/24/outline/inbox-arrow-down.svg +3 -0
- data/vendor/heroicons/24/outline/inbox-stack.svg +3 -0
- data/vendor/heroicons/24/outline/inbox.svg +3 -0
- data/vendor/heroicons/24/outline/information-circle.svg +3 -0
- data/vendor/heroicons/24/outline/italic.svg +3 -0
- data/vendor/heroicons/24/outline/key.svg +3 -0
- data/vendor/heroicons/24/outline/language.svg +3 -0
- data/vendor/heroicons/24/outline/lifebuoy.svg +3 -0
- data/vendor/heroicons/24/outline/light-bulb.svg +3 -0
- data/vendor/heroicons/24/outline/link-slash.svg +3 -0
- data/vendor/heroicons/24/outline/link.svg +3 -0
- data/vendor/heroicons/24/outline/list-bullet.svg +3 -0
- data/vendor/heroicons/24/outline/lock-closed.svg +3 -0
- data/vendor/heroicons/24/outline/lock-open.svg +3 -0
- data/vendor/heroicons/24/outline/magnifying-glass-circle.svg +3 -0
- data/vendor/heroicons/24/outline/magnifying-glass-minus.svg +3 -0
- data/vendor/heroicons/24/outline/magnifying-glass-plus.svg +3 -0
- data/vendor/heroicons/24/outline/magnifying-glass.svg +3 -0
- data/vendor/heroicons/24/outline/map-pin.svg +4 -0
- data/vendor/heroicons/24/outline/map.svg +3 -0
- data/vendor/heroicons/24/outline/megaphone.svg +3 -0
- data/vendor/heroicons/24/outline/microphone.svg +3 -0
- data/vendor/heroicons/24/outline/minus-circle.svg +3 -0
- data/vendor/heroicons/24/outline/minus-small.svg +3 -0
- data/vendor/heroicons/24/outline/minus.svg +3 -0
- data/vendor/heroicons/24/outline/moon.svg +3 -0
- data/vendor/heroicons/24/outline/musical-note.svg +3 -0
- data/vendor/heroicons/24/outline/newspaper.svg +3 -0
- data/vendor/heroicons/24/outline/no-symbol.svg +3 -0
- data/vendor/heroicons/24/outline/numbered-list.svg +3 -0
- data/vendor/heroicons/24/outline/paint-brush.svg +3 -0
- data/vendor/heroicons/24/outline/paper-airplane.svg +3 -0
- data/vendor/heroicons/24/outline/paper-clip.svg +3 -0
- data/vendor/heroicons/24/outline/pause-circle.svg +3 -0
- data/vendor/heroicons/24/outline/pause.svg +3 -0
- data/vendor/heroicons/24/outline/pencil-square.svg +3 -0
- data/vendor/heroicons/24/outline/pencil.svg +3 -0
- data/vendor/heroicons/24/outline/percent-badge.svg +3 -0
- data/vendor/heroicons/24/outline/phone-arrow-down-left.svg +3 -0
- data/vendor/heroicons/24/outline/phone-arrow-up-right.svg +3 -0
- data/vendor/heroicons/24/outline/phone-x-mark.svg +3 -0
- data/vendor/heroicons/24/outline/phone.svg +3 -0
- data/vendor/heroicons/24/outline/photo.svg +3 -0
- data/vendor/heroicons/24/outline/play-circle.svg +4 -0
- data/vendor/heroicons/24/outline/play-pause.svg +3 -0
- data/vendor/heroicons/24/outline/play.svg +3 -0
- data/vendor/heroicons/24/outline/plus-circle.svg +3 -0
- data/vendor/heroicons/24/outline/plus-small.svg +3 -0
- data/vendor/heroicons/24/outline/plus.svg +3 -0
- data/vendor/heroicons/24/outline/power.svg +3 -0
- data/vendor/heroicons/24/outline/presentation-chart-bar.svg +3 -0
- data/vendor/heroicons/24/outline/presentation-chart-line.svg +3 -0
- data/vendor/heroicons/24/outline/printer.svg +3 -0
- data/vendor/heroicons/24/outline/puzzle-piece.svg +3 -0
- data/vendor/heroicons/24/outline/qr-code.svg +4 -0
- data/vendor/heroicons/24/outline/question-mark-circle.svg +3 -0
- data/vendor/heroicons/24/outline/queue-list.svg +3 -0
- data/vendor/heroicons/24/outline/radio.svg +3 -0
- data/vendor/heroicons/24/outline/receipt-percent.svg +3 -0
- data/vendor/heroicons/24/outline/receipt-refund.svg +3 -0
- data/vendor/heroicons/24/outline/rectangle-group.svg +3 -0
- data/vendor/heroicons/24/outline/rectangle-stack.svg +3 -0
- data/vendor/heroicons/24/outline/rocket-launch.svg +3 -0
- data/vendor/heroicons/24/outline/rss.svg +3 -0
- data/vendor/heroicons/24/outline/scale.svg +3 -0
- data/vendor/heroicons/24/outline/scissors.svg +3 -0
- data/vendor/heroicons/24/outline/server-stack.svg +3 -0
- data/vendor/heroicons/24/outline/server.svg +3 -0
- data/vendor/heroicons/24/outline/share.svg +3 -0
- data/vendor/heroicons/24/outline/shield-check.svg +3 -0
- data/vendor/heroicons/24/outline/shield-exclamation.svg +3 -0
- data/vendor/heroicons/24/outline/shopping-bag.svg +3 -0
- data/vendor/heroicons/24/outline/shopping-cart.svg +3 -0
- data/vendor/heroicons/24/outline/signal-slash.svg +3 -0
- data/vendor/heroicons/24/outline/signal.svg +3 -0
- data/vendor/heroicons/24/outline/slash.svg +3 -0
- data/vendor/heroicons/24/outline/sparkles.svg +3 -0
- data/vendor/heroicons/24/outline/speaker-wave.svg +3 -0
- data/vendor/heroicons/24/outline/speaker-x-mark.svg +3 -0
- data/vendor/heroicons/24/outline/square-2-stack.svg +3 -0
- data/vendor/heroicons/24/outline/square-3-stack-3d.svg +3 -0
- data/vendor/heroicons/24/outline/squares-2x2.svg +3 -0
- data/vendor/heroicons/24/outline/squares-plus.svg +3 -0
- data/vendor/heroicons/24/outline/star.svg +3 -0
- data/vendor/heroicons/24/outline/stop-circle.svg +4 -0
- data/vendor/heroicons/24/outline/stop.svg +3 -0
- data/vendor/heroicons/24/outline/strikethrough.svg +3 -0
- data/vendor/heroicons/24/outline/sun.svg +3 -0
- data/vendor/heroicons/24/outline/swatch.svg +3 -0
- data/vendor/heroicons/24/outline/table-cells.svg +3 -0
- data/vendor/heroicons/24/outline/tag.svg +4 -0
- data/vendor/heroicons/24/outline/ticket.svg +3 -0
- data/vendor/heroicons/24/outline/trash.svg +3 -0
- data/vendor/heroicons/24/outline/trophy.svg +3 -0
- data/vendor/heroicons/24/outline/truck.svg +3 -0
- data/vendor/heroicons/24/outline/tv.svg +3 -0
- data/vendor/heroicons/24/outline/underline.svg +3 -0
- data/vendor/heroicons/24/outline/user-circle.svg +3 -0
- data/vendor/heroicons/24/outline/user-group.svg +3 -0
- data/vendor/heroicons/24/outline/user-minus.svg +3 -0
- data/vendor/heroicons/24/outline/user-plus.svg +3 -0
- data/vendor/heroicons/24/outline/user.svg +3 -0
- data/vendor/heroicons/24/outline/users.svg +3 -0
- data/vendor/heroicons/24/outline/variable.svg +3 -0
- data/vendor/heroicons/24/outline/video-camera-slash.svg +3 -0
- data/vendor/heroicons/24/outline/video-camera.svg +3 -0
- data/vendor/heroicons/24/outline/view-columns.svg +3 -0
- data/vendor/heroicons/24/outline/viewfinder-circle.svg +3 -0
- data/vendor/heroicons/24/outline/wallet.svg +3 -0
- data/vendor/heroicons/24/outline/wifi.svg +3 -0
- data/vendor/heroicons/24/outline/window.svg +3 -0
- data/vendor/heroicons/24/outline/wrench-screwdriver.svg +3 -0
- data/vendor/heroicons/24/outline/wrench.svg +4 -0
- data/vendor/heroicons/24/outline/x-circle.svg +3 -0
- data/vendor/heroicons/24/outline/x-mark.svg +3 -0
- data/vendor/heroicons/24/solid/academic-cap.svg +5 -0
- data/vendor/heroicons/24/solid/adjustments-horizontal.svg +3 -0
- data/vendor/heroicons/24/solid/adjustments-vertical.svg +3 -0
- data/vendor/heroicons/24/solid/archive-box-arrow-down.svg +4 -0
- data/vendor/heroicons/24/solid/archive-box-x-mark.svg +4 -0
- data/vendor/heroicons/24/solid/archive-box.svg +4 -0
- data/vendor/heroicons/24/solid/arrow-down-circle.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-down-left.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-down-on-square-stack.svg +4 -0
- data/vendor/heroicons/24/solid/arrow-down-on-square.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-down-right.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-down-tray.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-down.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-left-circle.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-left-end-on-rectangle.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-left-on-rectangle.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-left-start-on-rectangle.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-left.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-long-down.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-long-left.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-long-right.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-long-up.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-path-rounded-square.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-path.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-right-circle.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-right-end-on-rectangle.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-right-on-rectangle.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-right-start-on-rectangle.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-right.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-small-down.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-small-left.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-small-right.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-small-up.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-top-right-on-square.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-trending-down.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-trending-up.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-turn-down-left.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-turn-down-right.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-turn-left-down.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-turn-left-up.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-turn-right-down.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-turn-right-up.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-turn-up-left.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-turn-up-right.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-up-circle.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-up-left.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-up-on-square-stack.svg +4 -0
- data/vendor/heroicons/24/solid/arrow-up-on-square.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-up-right.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-up-tray.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-up.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-uturn-down.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-uturn-left.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-uturn-right.svg +3 -0
- data/vendor/heroicons/24/solid/arrow-uturn-up.svg +3 -0
- data/vendor/heroicons/24/solid/arrows-pointing-in.svg +3 -0
- data/vendor/heroicons/24/solid/arrows-pointing-out.svg +3 -0
- data/vendor/heroicons/24/solid/arrows-right-left.svg +3 -0
- data/vendor/heroicons/24/solid/arrows-up-down.svg +3 -0
- data/vendor/heroicons/24/solid/at-symbol.svg +3 -0
- data/vendor/heroicons/24/solid/backspace.svg +3 -0
- data/vendor/heroicons/24/solid/backward.svg +3 -0
- data/vendor/heroicons/24/solid/banknotes.svg +5 -0
- data/vendor/heroicons/24/solid/bars-2.svg +3 -0
- data/vendor/heroicons/24/solid/bars-3-bottom-left.svg +3 -0
- data/vendor/heroicons/24/solid/bars-3-bottom-right.svg +3 -0
- data/vendor/heroicons/24/solid/bars-3-center-left.svg +3 -0
- data/vendor/heroicons/24/solid/bars-3.svg +3 -0
- data/vendor/heroicons/24/solid/bars-4.svg +3 -0
- data/vendor/heroicons/24/solid/bars-arrow-down.svg +3 -0
- data/vendor/heroicons/24/solid/bars-arrow-up.svg +3 -0
- data/vendor/heroicons/24/solid/battery-0.svg +3 -0
- data/vendor/heroicons/24/solid/battery-100.svg +3 -0
- data/vendor/heroicons/24/solid/battery-50.svg +4 -0
- data/vendor/heroicons/24/solid/beaker.svg +3 -0
- data/vendor/heroicons/24/solid/bell-alert.svg +4 -0
- data/vendor/heroicons/24/solid/bell-slash.svg +4 -0
- data/vendor/heroicons/24/solid/bell-snooze.svg +3 -0
- data/vendor/heroicons/24/solid/bell.svg +3 -0
- data/vendor/heroicons/24/solid/bold.svg +3 -0
- data/vendor/heroicons/24/solid/bolt-slash.svg +3 -0
- data/vendor/heroicons/24/solid/bolt.svg +3 -0
- data/vendor/heroicons/24/solid/book-open.svg +3 -0
- data/vendor/heroicons/24/solid/bookmark-slash.svg +3 -0
- data/vendor/heroicons/24/solid/bookmark-square.svg +3 -0
- data/vendor/heroicons/24/solid/bookmark.svg +3 -0
- data/vendor/heroicons/24/solid/briefcase.svg +4 -0
- data/vendor/heroicons/24/solid/bug-ant.svg +3 -0
- data/vendor/heroicons/24/solid/building-library.svg +5 -0
- data/vendor/heroicons/24/solid/building-office-2.svg +3 -0
- data/vendor/heroicons/24/solid/building-office.svg +3 -0
- data/vendor/heroicons/24/solid/building-storefront.svg +4 -0
- data/vendor/heroicons/24/solid/cake.svg +3 -0
- data/vendor/heroicons/24/solid/calculator.svg +3 -0
- data/vendor/heroicons/24/solid/calendar-date-range.svg +4 -0
- data/vendor/heroicons/24/solid/calendar-days.svg +4 -0
- data/vendor/heroicons/24/solid/calendar.svg +3 -0
- data/vendor/heroicons/24/solid/camera.svg +4 -0
- data/vendor/heroicons/24/solid/chart-bar-square.svg +3 -0
- data/vendor/heroicons/24/solid/chart-bar.svg +3 -0
- data/vendor/heroicons/24/solid/chart-pie.svg +4 -0
- data/vendor/heroicons/24/solid/chat-bubble-bottom-center-text.svg +3 -0
- data/vendor/heroicons/24/solid/chat-bubble-bottom-center.svg +3 -0
- data/vendor/heroicons/24/solid/chat-bubble-left-ellipsis.svg +3 -0
- data/vendor/heroicons/24/solid/chat-bubble-left-right.svg +4 -0
- data/vendor/heroicons/24/solid/chat-bubble-left.svg +3 -0
- data/vendor/heroicons/24/solid/chat-bubble-oval-left-ellipsis.svg +3 -0
- data/vendor/heroicons/24/solid/chat-bubble-oval-left.svg +3 -0
- data/vendor/heroicons/24/solid/check-badge.svg +3 -0
- data/vendor/heroicons/24/solid/check-circle.svg +3 -0
- data/vendor/heroicons/24/solid/check.svg +3 -0
- data/vendor/heroicons/24/solid/chevron-double-down.svg +4 -0
- data/vendor/heroicons/24/solid/chevron-double-left.svg +4 -0
- data/vendor/heroicons/24/solid/chevron-double-right.svg +4 -0
- data/vendor/heroicons/24/solid/chevron-double-up.svg +4 -0
- data/vendor/heroicons/24/solid/chevron-down.svg +3 -0
- data/vendor/heroicons/24/solid/chevron-left.svg +3 -0
- data/vendor/heroicons/24/solid/chevron-right.svg +3 -0
- data/vendor/heroicons/24/solid/chevron-up-down.svg +3 -0
- data/vendor/heroicons/24/solid/chevron-up.svg +3 -0
- data/vendor/heroicons/24/solid/circle-stack.svg +6 -0
- data/vendor/heroicons/24/solid/clipboard-document-check.svg +4 -0
- data/vendor/heroicons/24/solid/clipboard-document-list.svg +4 -0
- data/vendor/heroicons/24/solid/clipboard-document.svg +5 -0
- data/vendor/heroicons/24/solid/clipboard.svg +3 -0
- data/vendor/heroicons/24/solid/clock.svg +3 -0
- data/vendor/heroicons/24/solid/cloud-arrow-down.svg +3 -0
- data/vendor/heroicons/24/solid/cloud-arrow-up.svg +3 -0
- data/vendor/heroicons/24/solid/cloud.svg +3 -0
- data/vendor/heroicons/24/solid/code-bracket-square.svg +3 -0
- data/vendor/heroicons/24/solid/code-bracket.svg +3 -0
- data/vendor/heroicons/24/solid/cog-6-tooth.svg +3 -0
- data/vendor/heroicons/24/solid/cog-8-tooth.svg +3 -0
- data/vendor/heroicons/24/solid/cog.svg +4 -0
- data/vendor/heroicons/24/solid/command-line.svg +3 -0
- data/vendor/heroicons/24/solid/computer-desktop.svg +3 -0
- data/vendor/heroicons/24/solid/cpu-chip.svg +4 -0
- data/vendor/heroicons/24/solid/credit-card.svg +4 -0
- data/vendor/heroicons/24/solid/cube-transparent.svg +3 -0
- data/vendor/heroicons/24/solid/cube.svg +3 -0
- data/vendor/heroicons/24/solid/currency-bangladeshi.svg +3 -0
- data/vendor/heroicons/24/solid/currency-dollar.svg +4 -0
- data/vendor/heroicons/24/solid/currency-euro.svg +3 -0
- data/vendor/heroicons/24/solid/currency-pound.svg +3 -0
- data/vendor/heroicons/24/solid/currency-rupee.svg +3 -0
- data/vendor/heroicons/24/solid/currency-yen.svg +3 -0
- data/vendor/heroicons/24/solid/cursor-arrow-rays.svg +3 -0
- data/vendor/heroicons/24/solid/cursor-arrow-ripple.svg +3 -0
- data/vendor/heroicons/24/solid/device-phone-mobile.svg +4 -0
- data/vendor/heroicons/24/solid/device-tablet.svg +4 -0
- data/vendor/heroicons/24/solid/divide.svg +3 -0
- data/vendor/heroicons/24/solid/document-arrow-down.svg +4 -0
- data/vendor/heroicons/24/solid/document-arrow-up.svg +4 -0
- data/vendor/heroicons/24/solid/document-chart-bar.svg +4 -0
- data/vendor/heroicons/24/solid/document-check.svg +4 -0
- data/vendor/heroicons/24/solid/document-currency-bangladeshi.svg +3 -0
- data/vendor/heroicons/24/solid/document-currency-dollar.svg +3 -0
- data/vendor/heroicons/24/solid/document-currency-euro.svg +4 -0
- data/vendor/heroicons/24/solid/document-currency-pound.svg +3 -0
- data/vendor/heroicons/24/solid/document-currency-rupee.svg +3 -0
- data/vendor/heroicons/24/solid/document-currency-yen.svg +3 -0
- data/vendor/heroicons/24/solid/document-duplicate.svg +4 -0
- data/vendor/heroicons/24/solid/document-magnifying-glass.svg +5 -0
- data/vendor/heroicons/24/solid/document-minus.svg +4 -0
- data/vendor/heroicons/24/solid/document-plus.svg +4 -0
- data/vendor/heroicons/24/solid/document-text.svg +4 -0
- data/vendor/heroicons/24/solid/document.svg +4 -0
- data/vendor/heroicons/24/solid/ellipsis-horizontal-circle.svg +3 -0
- data/vendor/heroicons/24/solid/ellipsis-horizontal.svg +3 -0
- data/vendor/heroicons/24/solid/ellipsis-vertical.svg +3 -0
- data/vendor/heroicons/24/solid/envelope-open.svg +4 -0
- data/vendor/heroicons/24/solid/envelope.svg +4 -0
- data/vendor/heroicons/24/solid/equals.svg +3 -0
- data/vendor/heroicons/24/solid/exclamation-circle.svg +3 -0
- data/vendor/heroicons/24/solid/exclamation-triangle.svg +3 -0
- data/vendor/heroicons/24/solid/eye-dropper.svg +3 -0
- data/vendor/heroicons/24/solid/eye-slash.svg +5 -0
- data/vendor/heroicons/24/solid/eye.svg +4 -0
- data/vendor/heroicons/24/solid/face-frown.svg +3 -0
- data/vendor/heroicons/24/solid/face-smile.svg +3 -0
- data/vendor/heroicons/24/solid/film.svg +3 -0
- data/vendor/heroicons/24/solid/finger-print.svg +3 -0
- data/vendor/heroicons/24/solid/fire.svg +3 -0
- data/vendor/heroicons/24/solid/flag.svg +3 -0
- data/vendor/heroicons/24/solid/folder-arrow-down.svg +3 -0
- data/vendor/heroicons/24/solid/folder-minus.svg +3 -0
- data/vendor/heroicons/24/solid/folder-open.svg +3 -0
- data/vendor/heroicons/24/solid/folder-plus.svg +3 -0
- data/vendor/heroicons/24/solid/folder.svg +3 -0
- data/vendor/heroicons/24/solid/forward.svg +3 -0
- data/vendor/heroicons/24/solid/funnel.svg +3 -0
- data/vendor/heroicons/24/solid/gif.svg +3 -0
- data/vendor/heroicons/24/solid/gift-top.svg +4 -0
- data/vendor/heroicons/24/solid/gift.svg +3 -0
- data/vendor/heroicons/24/solid/globe-alt.svg +3 -0
- data/vendor/heroicons/24/solid/globe-americas.svg +3 -0
- data/vendor/heroicons/24/solid/globe-asia-australia.svg +4 -0
- data/vendor/heroicons/24/solid/globe-europe-africa.svg +3 -0
- data/vendor/heroicons/24/solid/h1.svg +3 -0
- data/vendor/heroicons/24/solid/h2.svg +3 -0
- data/vendor/heroicons/24/solid/h3.svg +3 -0
- data/vendor/heroicons/24/solid/hand-raised.svg +3 -0
- data/vendor/heroicons/24/solid/hand-thumb-down.svg +3 -0
- data/vendor/heroicons/24/solid/hand-thumb-up.svg +3 -0
- data/vendor/heroicons/24/solid/hashtag.svg +3 -0
- data/vendor/heroicons/24/solid/heart.svg +3 -0
- data/vendor/heroicons/24/solid/home-modern.svg +4 -0
- data/vendor/heroicons/24/solid/home.svg +4 -0
- data/vendor/heroicons/24/solid/identification.svg +3 -0
- data/vendor/heroicons/24/solid/inbox-arrow-down.svg +4 -0
- data/vendor/heroicons/24/solid/inbox-stack.svg +4 -0
- data/vendor/heroicons/24/solid/inbox.svg +3 -0
- data/vendor/heroicons/24/solid/information-circle.svg +3 -0
- data/vendor/heroicons/24/solid/italic.svg +3 -0
- data/vendor/heroicons/24/solid/key.svg +3 -0
- data/vendor/heroicons/24/solid/language.svg +3 -0
- data/vendor/heroicons/24/solid/lifebuoy.svg +3 -0
- data/vendor/heroicons/24/solid/light-bulb.svg +4 -0
- data/vendor/heroicons/24/solid/link-slash.svg +3 -0
- data/vendor/heroicons/24/solid/link.svg +3 -0
- data/vendor/heroicons/24/solid/list-bullet.svg +3 -0
- data/vendor/heroicons/24/solid/lock-closed.svg +3 -0
- data/vendor/heroicons/24/solid/lock-open.svg +3 -0
- data/vendor/heroicons/24/solid/magnifying-glass-circle.svg +4 -0
- data/vendor/heroicons/24/solid/magnifying-glass-minus.svg +3 -0
- data/vendor/heroicons/24/solid/magnifying-glass-plus.svg +3 -0
- data/vendor/heroicons/24/solid/magnifying-glass.svg +3 -0
- data/vendor/heroicons/24/solid/map-pin.svg +3 -0
- data/vendor/heroicons/24/solid/map.svg +3 -0
- data/vendor/heroicons/24/solid/megaphone.svg +3 -0
- data/vendor/heroicons/24/solid/microphone.svg +4 -0
- data/vendor/heroicons/24/solid/minus-circle.svg +3 -0
- data/vendor/heroicons/24/solid/minus-small.svg +3 -0
- data/vendor/heroicons/24/solid/minus.svg +3 -0
- data/vendor/heroicons/24/solid/moon.svg +3 -0
- data/vendor/heroicons/24/solid/musical-note.svg +3 -0
- data/vendor/heroicons/24/solid/newspaper.svg +4 -0
- data/vendor/heroicons/24/solid/no-symbol.svg +3 -0
- data/vendor/heroicons/24/solid/numbered-list.svg +3 -0
- data/vendor/heroicons/24/solid/paint-brush.svg +3 -0
- data/vendor/heroicons/24/solid/paper-airplane.svg +3 -0
- data/vendor/heroicons/24/solid/paper-clip.svg +3 -0
- data/vendor/heroicons/24/solid/pause-circle.svg +3 -0
- data/vendor/heroicons/24/solid/pause.svg +3 -0
- data/vendor/heroicons/24/solid/pencil-square.svg +4 -0
- data/vendor/heroicons/24/solid/pencil.svg +3 -0
- data/vendor/heroicons/24/solid/percent-badge.svg +3 -0
- data/vendor/heroicons/24/solid/phone-arrow-down-left.svg +4 -0
- data/vendor/heroicons/24/solid/phone-arrow-up-right.svg +4 -0
- data/vendor/heroicons/24/solid/phone-x-mark.svg +3 -0
- data/vendor/heroicons/24/solid/phone.svg +3 -0
- data/vendor/heroicons/24/solid/photo.svg +3 -0
- data/vendor/heroicons/24/solid/play-circle.svg +3 -0
- data/vendor/heroicons/24/solid/play-pause.svg +3 -0
- data/vendor/heroicons/24/solid/play.svg +3 -0
- data/vendor/heroicons/24/solid/plus-circle.svg +3 -0
- data/vendor/heroicons/24/solid/plus-small.svg +3 -0
- data/vendor/heroicons/24/solid/plus.svg +3 -0
- data/vendor/heroicons/24/solid/power.svg +3 -0
- data/vendor/heroicons/24/solid/presentation-chart-bar.svg +3 -0
- data/vendor/heroicons/24/solid/presentation-chart-line.svg +3 -0
- data/vendor/heroicons/24/solid/printer.svg +3 -0
- data/vendor/heroicons/24/solid/puzzle-piece.svg +3 -0
- data/vendor/heroicons/24/solid/qr-code.svg +3 -0
- data/vendor/heroicons/24/solid/question-mark-circle.svg +3 -0
- data/vendor/heroicons/24/solid/queue-list.svg +3 -0
- data/vendor/heroicons/24/solid/radio.svg +3 -0
- data/vendor/heroicons/24/solid/receipt-percent.svg +3 -0
- data/vendor/heroicons/24/solid/receipt-refund.svg +3 -0
- data/vendor/heroicons/24/solid/rectangle-group.svg +3 -0
- data/vendor/heroicons/24/solid/rectangle-stack.svg +3 -0
- data/vendor/heroicons/24/solid/rocket-launch.svg +4 -0
- data/vendor/heroicons/24/solid/rss.svg +3 -0
- data/vendor/heroicons/24/solid/scale.svg +3 -0
- data/vendor/heroicons/24/solid/scissors.svg +4 -0
- data/vendor/heroicons/24/solid/server-stack.svg +4 -0
- data/vendor/heroicons/24/solid/server.svg +4 -0
- data/vendor/heroicons/24/solid/share.svg +3 -0
- data/vendor/heroicons/24/solid/shield-check.svg +3 -0
- data/vendor/heroicons/24/solid/shield-exclamation.svg +3 -0
- data/vendor/heroicons/24/solid/shopping-bag.svg +3 -0
- data/vendor/heroicons/24/solid/shopping-cart.svg +3 -0
- data/vendor/heroicons/24/solid/signal-slash.svg +3 -0
- data/vendor/heroicons/24/solid/signal.svg +3 -0
- data/vendor/heroicons/24/solid/slash.svg +3 -0
- data/vendor/heroicons/24/solid/sparkles.svg +3 -0
- data/vendor/heroicons/24/solid/speaker-wave.svg +4 -0
- data/vendor/heroicons/24/solid/speaker-x-mark.svg +3 -0
- data/vendor/heroicons/24/solid/square-2-stack.svg +4 -0
- data/vendor/heroicons/24/solid/square-3-stack-3d.svg +5 -0
- data/vendor/heroicons/24/solid/squares-2x2.svg +3 -0
- data/vendor/heroicons/24/solid/squares-plus.svg +3 -0
- data/vendor/heroicons/24/solid/star.svg +3 -0
- data/vendor/heroicons/24/solid/stop-circle.svg +3 -0
- data/vendor/heroicons/24/solid/stop.svg +3 -0
- data/vendor/heroicons/24/solid/strikethrough.svg +3 -0
- data/vendor/heroicons/24/solid/sun.svg +3 -0
- data/vendor/heroicons/24/solid/swatch.svg +4 -0
- data/vendor/heroicons/24/solid/table-cells.svg +3 -0
- data/vendor/heroicons/24/solid/tag.svg +3 -0
- data/vendor/heroicons/24/solid/ticket.svg +3 -0
- data/vendor/heroicons/24/solid/trash.svg +3 -0
- data/vendor/heroicons/24/solid/trophy.svg +3 -0
- data/vendor/heroicons/24/solid/truck.svg +5 -0
- data/vendor/heroicons/24/solid/tv.svg +4 -0
- data/vendor/heroicons/24/solid/underline.svg +3 -0
- data/vendor/heroicons/24/solid/user-circle.svg +3 -0
- data/vendor/heroicons/24/solid/user-group.svg +4 -0
- data/vendor/heroicons/24/solid/user-minus.svg +3 -0
- data/vendor/heroicons/24/solid/user-plus.svg +3 -0
- data/vendor/heroicons/24/solid/user.svg +3 -0
- data/vendor/heroicons/24/solid/users.svg +3 -0
- data/vendor/heroicons/24/solid/variable.svg +3 -0
- data/vendor/heroicons/24/solid/video-camera-slash.svg +3 -0
- data/vendor/heroicons/24/solid/video-camera.svg +3 -0
- data/vendor/heroicons/24/solid/view-columns.svg +3 -0
- data/vendor/heroicons/24/solid/viewfinder-circle.svg +3 -0
- data/vendor/heroicons/24/solid/wallet.svg +3 -0
- data/vendor/heroicons/24/solid/wifi.svg +3 -0
- data/vendor/heroicons/24/solid/window.svg +3 -0
- data/vendor/heroicons/24/solid/wrench-screwdriver.svg +5 -0
- data/vendor/heroicons/24/solid/wrench.svg +3 -0
- data/vendor/heroicons/24/solid/x-circle.svg +3 -0
- data/vendor/heroicons/24/solid/x-mark.svg +3 -0
- data/vendor/heroicons/LICENSE +21 -0
- data/vendor/heroicons/VERSION +5 -0
- metadata +1664 -0
data/lib/abqari/folio.rb
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'net/http'
|
|
4
|
+
require 'json'
|
|
5
|
+
require 'openssl'
|
|
6
|
+
require 'yaml'
|
|
7
|
+
require 'fileutils'
|
|
8
|
+
require 'set'
|
|
9
|
+
|
|
10
|
+
module Abqari
|
|
11
|
+
# Folio integration. Folio (foliobooks.app) is a publishing/storefront app
|
|
12
|
+
# that exposes a public read-only JSON API for embedding book metadata on
|
|
13
|
+
# author websites. This class fetches that data at build time and stashes
|
|
14
|
+
# it in `site.data` keyed by slug, so layouts can render books / bundles /
|
|
15
|
+
# series without hitting Folio at runtime — and the visitor never makes a
|
|
16
|
+
# request to Folio either.
|
|
17
|
+
#
|
|
18
|
+
# API endpoints used:
|
|
19
|
+
# GET /api/v1/authors/:slug/publications.json
|
|
20
|
+
# GET /api/v1/authors/:slug/bundles.json
|
|
21
|
+
# GET /api/v1/authors/:slug/series.json
|
|
22
|
+
#
|
|
23
|
+
# Cache-first design (matches the Jekyll plugin in apps/memoirs):
|
|
24
|
+
# 1. Fresh build, network OK → 200 → write cache → use it
|
|
25
|
+
# 2. Subsequent build, no change → 304 → use cache
|
|
26
|
+
# 3. Folio briefly unreachable → use cache, log warning
|
|
27
|
+
# 4. First build, no network → empty data; layouts fall back to front matter
|
|
28
|
+
#
|
|
29
|
+
# Cache files live in `vendor/folio/` (gitignored) so each CI runner
|
|
30
|
+
# rebuilds its own cache and there's no version-control churn.
|
|
31
|
+
class Folio
|
|
32
|
+
OPEN_TIMEOUT = 5
|
|
33
|
+
READ_TIMEOUT = 10
|
|
34
|
+
# 8 MB is enormously generous for Folio's JSON shape — a prolific
|
|
35
|
+
# author with hundreds of titles plus full metadata still fits well
|
|
36
|
+
# under 1 MB. The cap exists so a compromised or misconfigured
|
|
37
|
+
# upstream can't exhaust the CI runner's memory.
|
|
38
|
+
MAX_RESPONSE_BYTES = 8 * 1024 * 1024
|
|
39
|
+
USER_AGENT = "abqari-folio-fetcher/#{Abqari::VERSION}"
|
|
40
|
+
|
|
41
|
+
def initialize(site)
|
|
42
|
+
@site = site
|
|
43
|
+
@cfg = site.config['folio'] || {}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def enabled?
|
|
47
|
+
base_url && author_slug
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def base_url
|
|
51
|
+
@cfg['base_url']
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def author_slug
|
|
55
|
+
@cfg['author_slug']
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def config
|
|
59
|
+
@cfg
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def cache_dir
|
|
63
|
+
# Folio cache is site-specific (different sites pull different
|
|
64
|
+
# publications), so it lives under the site root.
|
|
65
|
+
File.join(@site.site_root, 'vendor', 'folio')
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Fetches publications + bundles, derives series, populates site.data.
|
|
69
|
+
# Called from Site#build before page rendering so layouts can read
|
|
70
|
+
# site.data['folio_publications'] etc. when they render.
|
|
71
|
+
#
|
|
72
|
+
# Slug filtering. An author may have multiple imprints under one Folio
|
|
73
|
+
# account (e.g. fiction + non-fiction) but want a given site to show
|
|
74
|
+
# only some. Configure either of:
|
|
75
|
+
#
|
|
76
|
+
# folio:
|
|
77
|
+
# include_slugs: [memoirs-of-an-assassin, the-russia-assignment]
|
|
78
|
+
# exclude_slugs: [some-other-book]
|
|
79
|
+
#
|
|
80
|
+
# `include_slugs` (when set) wins — only those publications survive,
|
|
81
|
+
# and only the bundles/series that reference them are kept. Otherwise
|
|
82
|
+
# `exclude_slugs` removes the listed publications. Both default to
|
|
83
|
+
# empty (all publications kept) so existing sites are unaffected.
|
|
84
|
+
def fetch
|
|
85
|
+
return unless enabled?
|
|
86
|
+
|
|
87
|
+
FileUtils.mkdir_p(cache_dir)
|
|
88
|
+
|
|
89
|
+
pubs = filter_publications(fetch_endpoint('publications'))
|
|
90
|
+
bundles = filter_bundles(fetch_endpoint('bundles'), pubs)
|
|
91
|
+
series = filter_series(fetch_endpoint('series'), pubs)
|
|
92
|
+
|
|
93
|
+
@site.data['folio_publications'] = index_by_slug(pubs)
|
|
94
|
+
@site.data['folio_bundles'] = index_by_slug(bundles)
|
|
95
|
+
@site.data['folio_series'] = index_by_slug(series)
|
|
96
|
+
|
|
97
|
+
pubs_count = @site.data['folio_publications'].size
|
|
98
|
+
bundles_count = @site.data['folio_bundles'].size
|
|
99
|
+
series_count = @site.data['folio_series'].size
|
|
100
|
+
Log.info "Folio: loaded #{pubs_count} publication(s), #{bundles_count} bundle(s), #{series_count} series"
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
private
|
|
104
|
+
|
|
105
|
+
# Apply include/exclude slug filters to the fetched publications list.
|
|
106
|
+
# `include_slugs` (when present) is treated as the only-keep set;
|
|
107
|
+
# `exclude_slugs` removes named slugs. Both arrays of strings.
|
|
108
|
+
def filter_publications(pubs)
|
|
109
|
+
include = Array(config['include_slugs']).map(&:to_s)
|
|
110
|
+
exclude = Array(config['exclude_slugs']).map(&:to_s)
|
|
111
|
+
|
|
112
|
+
pubs = pubs.select { |p| include.include?(p['slug'].to_s) } if include.any?
|
|
113
|
+
pubs = pubs.reject { |p| exclude.include?(p['slug'].to_s) } if exclude.any?
|
|
114
|
+
pubs
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Drop bundles whose `publications` array would be empty after filtering
|
|
118
|
+
# (otherwise we ship empty-bundle pages). Bundles that retain at least
|
|
119
|
+
# one publication keep all their original publications array — we
|
|
120
|
+
# don't surgically rewrite the bundle's contents.
|
|
121
|
+
def filter_bundles(bundles, kept_pubs)
|
|
122
|
+
kept_slugs = kept_pubs.map { |p| p['slug'].to_s }.to_set
|
|
123
|
+
bundles.select do |b|
|
|
124
|
+
Array(b['publications']).any? { |p| kept_slugs.include?(p['slug'].to_s) }
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Drop series with zero remaining publications.
|
|
129
|
+
def filter_series(series_list, kept_pubs)
|
|
130
|
+
kept_slugs = kept_pubs.map { |p| p['slug'].to_s }.to_set
|
|
131
|
+
series_list.select do |s|
|
|
132
|
+
Array(s['publications']).any? { |p| kept_slugs.include?(p['slug'].to_s) }
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Endpoint name → list-payload key mapping (matches Folio's API response shape):
|
|
137
|
+
ENDPOINTS = {
|
|
138
|
+
'publications' => 'publications',
|
|
139
|
+
'bundles' => 'bundles',
|
|
140
|
+
'series' => 'series'
|
|
141
|
+
}.freeze
|
|
142
|
+
|
|
143
|
+
def fetch_endpoint(name)
|
|
144
|
+
cache_path = File.join(cache_dir, "#{name}.yml")
|
|
145
|
+
etag_path = File.join(cache_dir, "etag-#{name}")
|
|
146
|
+
cached = File.exist?(cache_path) ? (YAML.safe_load_file(cache_path, permitted_classes: Abqari::YAML_PERMITTED_CLASSES) || {}) : {}
|
|
147
|
+
etag = File.exist?(etag_path) ? File.read(etag_path).strip : nil
|
|
148
|
+
|
|
149
|
+
uri = URI("#{base_url.sub(%r{/\z}, '')}/api/v1/authors/#{author_slug}/#{name}.json")
|
|
150
|
+
headers = { 'Accept' => 'application/json', 'User-Agent' => USER_AGENT }
|
|
151
|
+
headers['If-None-Match'] = etag if etag
|
|
152
|
+
|
|
153
|
+
# HttpSafe streams the body, caps it at MAX_RESPONSE_BYTES, and
|
|
154
|
+
# applies timeouts. TooLargeError bubbles to the rescue below so
|
|
155
|
+
# we fall back to cached data rather than crashing the build.
|
|
156
|
+
res = HttpSafe.get(uri,
|
|
157
|
+
headers: headers,
|
|
158
|
+
max_bytes: MAX_RESPONSE_BYTES,
|
|
159
|
+
open_timeout: OPEN_TIMEOUT,
|
|
160
|
+
read_timeout: READ_TIMEOUT)
|
|
161
|
+
|
|
162
|
+
case res.code
|
|
163
|
+
when '304'
|
|
164
|
+
cached[ENDPOINTS[name]] || []
|
|
165
|
+
when '200'
|
|
166
|
+
body = JSON.parse(res.body)
|
|
167
|
+
items = body[ENDPOINTS[name]] || []
|
|
168
|
+
File.write(cache_path, { ENDPOINTS[name] => items }.to_yaml)
|
|
169
|
+
File.write(etag_path, res['etag'].to_s) if res['etag']
|
|
170
|
+
items
|
|
171
|
+
else
|
|
172
|
+
Log.warn "Folio: unexpected HTTP #{res.code} from /#{name} — using cached data"
|
|
173
|
+
cached[ENDPOINTS[name]] || []
|
|
174
|
+
end
|
|
175
|
+
# Narrowed rescue list: the expected failure modes for a Folio
|
|
176
|
+
# fetch are network (timeouts, DNS, TCP/TLS), an oversized
|
|
177
|
+
# response, malformed JSON, or filesystem failure writing the
|
|
178
|
+
# cache. Anything else (a Ruby bug, a programming error) should
|
|
179
|
+
# surface so we don't silently mask it as "Folio unreachable."
|
|
180
|
+
# Backtrace logged at debug so `ABQARI_LOG=debug` surfaces the
|
|
181
|
+
# full stack when triaging upstream issues.
|
|
182
|
+
rescue Net::OpenTimeout, Net::ReadTimeout, Errno::ECONNRESET, Errno::ECONNREFUSED,
|
|
183
|
+
Errno::EHOSTUNREACH, Errno::ENETUNREACH, SocketError, IOError,
|
|
184
|
+
OpenSSL::SSL::SSLError, HttpSafe::TooLargeError,
|
|
185
|
+
JSON::ParserError, Psych::SyntaxError, SystemCallError => e
|
|
186
|
+
Log.warn "Folio: fetch /#{name} failed (#{e.class}: #{e.message}) — using cached data"
|
|
187
|
+
e.backtrace&.first(5)&.each { |line| Log.debug " #{line}" }
|
|
188
|
+
cached[ENDPOINTS[name]] || []
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def index_by_slug(items)
|
|
192
|
+
items.each_with_object({}) { |item, h| h[item['slug']] = item if item['slug'] }
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'uri'
|
|
4
|
+
require 'fileutils'
|
|
5
|
+
|
|
6
|
+
module Abqari
|
|
7
|
+
class FontPipeline
|
|
8
|
+
GOOGLE_CSS_API = 'https://fonts.googleapis.com/css2'
|
|
9
|
+
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ' \
|
|
10
|
+
'(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
|
|
11
|
+
|
|
12
|
+
# Timeouts and per-response cap. CSS responses are <10 KB and woff2
|
|
13
|
+
# files <500 KB typically; 8 MB is far above worst-case and exists so
|
|
14
|
+
# a misbehaving upstream can't hang the build or fill memory.
|
|
15
|
+
OPEN_TIMEOUT = 5
|
|
16
|
+
READ_TIMEOUT = 10
|
|
17
|
+
MAX_RESPONSE_BYTES = 8 * 1024 * 1024
|
|
18
|
+
|
|
19
|
+
def initialize(site)
|
|
20
|
+
@site = site
|
|
21
|
+
# Font cache is site-specific — populated from the site's own
|
|
22
|
+
# `fonts:` config.
|
|
23
|
+
@cache_dir = File.join(@site.site_root, 'vendor', 'fonts')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def fetch
|
|
27
|
+
fonts = Array(@site.config['fonts'])
|
|
28
|
+
if fonts.empty?
|
|
29
|
+
Log.info 'No fonts configured. Add a `fonts:` array to config/site.yml.'
|
|
30
|
+
return
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
FileUtils.mkdir_p(@cache_dir)
|
|
34
|
+
generated = fonts.map { |font| download_font(font) }
|
|
35
|
+
File.write(File.join(@cache_dir, 'fonts.css'), generated.join("\n\n"))
|
|
36
|
+
Log.info "Fetched #{fonts.size} font family/families → vendor/fonts/"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def download_font(font)
|
|
42
|
+
family = font['family'] || raise(ArgumentError, "Font config missing 'family'")
|
|
43
|
+
weights = Array(font['weights'] || [400])
|
|
44
|
+
style = font['style'] || 'normal'
|
|
45
|
+
|
|
46
|
+
css = fetch_css(family, weights, style)
|
|
47
|
+
rewrite_and_download(css)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def fetch_css(family, weights, style)
|
|
51
|
+
family_param = "#{family.gsub(' ', '+')}:#{weight_spec(weights, style)}"
|
|
52
|
+
uri = URI("#{GOOGLE_CSS_API}?family=#{family_param}&display=swap")
|
|
53
|
+
|
|
54
|
+
response = http_get(uri)
|
|
55
|
+
response.body
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Build the family axis spec for the Google Fonts CSS API.
|
|
59
|
+
#
|
|
60
|
+
# Normal: `wght@300;400;700` — one weight per entry
|
|
61
|
+
# Italic: `ital,wght@1,300;1,400;1,700` — each (ital, weight) tuple on
|
|
62
|
+
# its own, separated by `;`. Google rejects `ital,wght@1,300;400;700`
|
|
63
|
+
# with a 400 Bad Request because every entry past the first must
|
|
64
|
+
# carry its own ital flag.
|
|
65
|
+
def weight_spec(weights, style)
|
|
66
|
+
sorted = weights.sort
|
|
67
|
+
if style == 'italic'
|
|
68
|
+
"ital,wght@#{sorted.map { |w| "1,#{w}" }.join(';')}"
|
|
69
|
+
else
|
|
70
|
+
"wght@#{sorted.join(';')}"
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def rewrite_and_download(css)
|
|
75
|
+
css.gsub(%r{url\((https://fonts\.gstatic\.com/[^)]+\.woff2)\)}) do
|
|
76
|
+
url = ::Regexp.last_match(1)
|
|
77
|
+
filename = File.basename(URI(url).path)
|
|
78
|
+
dest = File.join(@cache_dir, filename)
|
|
79
|
+
|
|
80
|
+
download(url, dest) unless File.exist?(dest)
|
|
81
|
+
|
|
82
|
+
"url(/assets/fonts/#{filename})"
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def download(url, dest)
|
|
87
|
+
response = http_get(URI(url))
|
|
88
|
+
File.binwrite(dest, response.body)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def http_get(uri)
|
|
92
|
+
response = HttpSafe.get(uri,
|
|
93
|
+
headers: { 'User-Agent' => USER_AGENT },
|
|
94
|
+
max_bytes: MAX_RESPONSE_BYTES,
|
|
95
|
+
open_timeout: OPEN_TIMEOUT,
|
|
96
|
+
read_timeout: READ_TIMEOUT)
|
|
97
|
+
unless response.success?
|
|
98
|
+
raise "Fetch failed for #{uri}: #{response.code} #{response.message}"
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
response
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'uri'
|
|
4
|
+
|
|
5
|
+
require_relative 'theme_bootstrap'
|
|
6
|
+
require_relative 'plausible_script'
|
|
7
|
+
|
|
8
|
+
module Abqari
|
|
9
|
+
class HeadersFile
|
|
10
|
+
# The CSP is built per-build based on which optional features are
|
|
11
|
+
# configured (Plausible analytics, etc.). The base policy is strict:
|
|
12
|
+
# 'self' only, with the inline theme-bootstrap script pinned by SHA256
|
|
13
|
+
# so we don't need 'unsafe-inline'. Each opt-in feature extends the
|
|
14
|
+
# policy minimally — Plausible adds plausible.io to script-src and
|
|
15
|
+
# connect-src plus the inline init script's hash, and that's it.
|
|
16
|
+
#
|
|
17
|
+
# To allow an origin the engine doesn't model, add it to `csp:` in
|
|
18
|
+
# config/site.yml — additive, so everything computed here survives.
|
|
19
|
+
# `media:` does the same for off-origin audio / video.
|
|
20
|
+
#
|
|
21
|
+
# Override the whole thing by setting `headers:` in config/site.yml
|
|
22
|
+
# — that disables this dynamic build entirely and ships your structure
|
|
23
|
+
# verbatim. Reach for it only when you need to weaken a hardening
|
|
24
|
+
# directive or use a non-http scheme; `csp:` covers adding origins
|
|
25
|
+
# without losing the pinned script hashes.
|
|
26
|
+
BASE_HEADERS = {
|
|
27
|
+
'X-Content-Type-Options' => 'nosniff',
|
|
28
|
+
'Referrer-Policy' => 'strict-origin-when-cross-origin',
|
|
29
|
+
'Permissions-Policy' => 'camera=(), microphone=(), geolocation=(), interest-cohort=()',
|
|
30
|
+
'Strict-Transport-Security' => 'max-age=31536000; includeSubDomains'
|
|
31
|
+
}.freeze
|
|
32
|
+
|
|
33
|
+
def initialize(site)
|
|
34
|
+
@site = site
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def write
|
|
38
|
+
File.write(File.join(@site.output_dir, '_headers'), build)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def build
|
|
44
|
+
# User override wins outright — no merging.
|
|
45
|
+
if (custom = @site.config['headers'])
|
|
46
|
+
return custom.map { |path, hdrs| section(path, hdrs) }.join("\n\n") + "\n"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
sections = [
|
|
50
|
+
section('/*', BASE_HEADERS.merge('Content-Security-Policy' => csp_policy)),
|
|
51
|
+
section('/assets/*', { 'Cache-Control' => 'public, max-age=31536000, immutable' })
|
|
52
|
+
]
|
|
53
|
+
sections.join("\n\n") + "\n"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def section(path, hdrs)
|
|
57
|
+
lines = [path.to_s]
|
|
58
|
+
hdrs.each { |k, v| lines << " #{k}: #{v}" }
|
|
59
|
+
lines.join("\n")
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Build the CSP from a structured representation so opt-in features
|
|
63
|
+
# can extend it cleanly. Returns the serialized policy string.
|
|
64
|
+
#
|
|
65
|
+
# Static-site defence in depth:
|
|
66
|
+
# - `object-src 'none'` — never load <object>/<embed>/<applet>.
|
|
67
|
+
# A static site has no legitimate reason to embed plugins; the
|
|
68
|
+
# directive blocks an attacker who somehow lands HTML on the
|
|
69
|
+
# site from pulling in a Flash/PDF/etc.
|
|
70
|
+
# - `form-action 'self'` — `<form action="https://evil.com">`
|
|
71
|
+
# becomes a no-op. Abqari emits only same-origin / same-provider
|
|
72
|
+
# newsletter forms, so the constraint is invisible to honest
|
|
73
|
+
# templates and stops a content-injection from doubling as a
|
|
74
|
+
# phishing redirect.
|
|
75
|
+
def csp_policy
|
|
76
|
+
policy = {
|
|
77
|
+
'default-src' => ["'self'"],
|
|
78
|
+
'img-src' => ["'self'", 'data:'],
|
|
79
|
+
'style-src' => ["'self'"],
|
|
80
|
+
'script-src' => ["'self'", "'#{ThemeBootstrap::SHA256}'", "'#{SpeculationRulesGuard::SHA256}'"],
|
|
81
|
+
'font-src' => ["'self'"],
|
|
82
|
+
'connect-src' => ["'self'"],
|
|
83
|
+
'object-src' => ["'none'"],
|
|
84
|
+
'frame-ancestors' => ["'none'"],
|
|
85
|
+
'form-action' => ["'self'"],
|
|
86
|
+
'base-uri' => ["'self'"]
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
apply_plausible(policy) if plausible_key
|
|
90
|
+
apply_folio(policy) if folio_enabled?
|
|
91
|
+
apply_fontawesome_kit(policy) if fontawesome_kit?
|
|
92
|
+
apply_search(policy) if search_enabled?
|
|
93
|
+
apply_speculation_rules(policy) if speculation_rules_enabled?
|
|
94
|
+
apply_newsletter(policy)
|
|
95
|
+
apply_media(policy)
|
|
96
|
+
# Last, so an operator-declared origin can extend a directive that
|
|
97
|
+
# a feature rule above created.
|
|
98
|
+
apply_csp_extensions(policy)
|
|
99
|
+
|
|
100
|
+
policy.map { |k, vs| "#{k} #{vs.join(' ')}" }.join('; ')
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Off-origin audio / video. Media served from the site itself needs
|
|
104
|
+
# no directive at all — it falls under `default-src 'self'`, which is
|
|
105
|
+
# why the base policy declares no `media-src`. Setting `media.host`
|
|
106
|
+
# creates it as `'self' <host>` (`add_origin` seeds `'self'` on any
|
|
107
|
+
# directive it has to create), so colocated bundle audio keeps
|
|
108
|
+
# working alongside the CDN.
|
|
109
|
+
#
|
|
110
|
+
# Accepts one host or a list:
|
|
111
|
+
#
|
|
112
|
+
# media:
|
|
113
|
+
# host: https://media.example.com
|
|
114
|
+
#
|
|
115
|
+
# media:
|
|
116
|
+
# host:
|
|
117
|
+
# - https://audio.example.com
|
|
118
|
+
# - https://video.example.com
|
|
119
|
+
def apply_media(policy)
|
|
120
|
+
cfg = @site.config['media']
|
|
121
|
+
return unless cfg.is_a?(Hash)
|
|
122
|
+
|
|
123
|
+
Array(cfg['host']).each { |host| add_origin(policy, 'media-src', host) }
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Directives an operator may extend via `csp:`. The omissions are
|
|
127
|
+
# deliberate: `default-src` would silently widen every directive
|
|
128
|
+
# that inherits from it, and `object-src` / `frame-ancestors` /
|
|
129
|
+
# `base-uri` are the static-site hardening directives documented on
|
|
130
|
+
# `csp_policy` — making those easy to weaken is exactly what this
|
|
131
|
+
# key must not do. A site that genuinely needs to change them owns
|
|
132
|
+
# the whole header via `headers:`.
|
|
133
|
+
EXTENDABLE_DIRECTIVES = %w[
|
|
134
|
+
child-src connect-src font-src form-action frame-src img-src
|
|
135
|
+
manifest-src media-src script-src style-src worker-src
|
|
136
|
+
].freeze
|
|
137
|
+
|
|
138
|
+
# Operator-declared extra origins:
|
|
139
|
+
#
|
|
140
|
+
# csp:
|
|
141
|
+
# img-src: [https://cdn.example.com]
|
|
142
|
+
# connect-src: [https://api.example.com]
|
|
143
|
+
#
|
|
144
|
+
# Additive only. Values are appended to the computed policy, so
|
|
145
|
+
# `'self'`, the pinned inline-script hashes and every feature-derived
|
|
146
|
+
# origin survive. That's the point of the key: before it existed the
|
|
147
|
+
# only way to allow an unmodelled origin was `headers:`, which
|
|
148
|
+
# replaces the built policy wholesale and takes the theme-bootstrap
|
|
149
|
+
# hash, `'wasm-unsafe-eval'` and the Plausible hash down with it.
|
|
150
|
+
#
|
|
151
|
+
# Raises on an unknown directive or a value that isn't an http(s)
|
|
152
|
+
# origin. A malformed CSP fails open — the browser ignores the parts
|
|
153
|
+
# it can't parse — so skipping bad config silently would ship a
|
|
154
|
+
# policy the operator believes is in force. Fail the build instead.
|
|
155
|
+
def apply_csp_extensions(policy)
|
|
156
|
+
cfg = @site.config['csp']
|
|
157
|
+
return unless cfg.is_a?(Hash)
|
|
158
|
+
|
|
159
|
+
cfg.each do |directive, values|
|
|
160
|
+
name = directive.to_s
|
|
161
|
+
unless EXTENDABLE_DIRECTIVES.include?(name)
|
|
162
|
+
raise ArgumentError,
|
|
163
|
+
"csp: #{name.inspect} is not an extendable directive. " \
|
|
164
|
+
"Extendable: #{EXTENDABLE_DIRECTIVES.join(', ')}. " \
|
|
165
|
+
'Set `headers:` to take over the whole header instead.'
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
Array(values).each do |value|
|
|
169
|
+
assert_http_origin!(name, value)
|
|
170
|
+
add_origin(policy, name, value)
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# `add_origin` is deliberately silent for feature-derived values (a
|
|
176
|
+
# relative `newsletter.action` is legitimately same-origin). Values
|
|
177
|
+
# typed directly into `csp:` get the opposite treatment: anything
|
|
178
|
+
# that isn't a scheme + host is an operator error worth stopping the
|
|
179
|
+
# build for, and rejecting everything else is what keeps `*`,
|
|
180
|
+
# `data:` and `'unsafe-inline'` out of this path by construction.
|
|
181
|
+
def assert_http_origin!(directive, value)
|
|
182
|
+
uri = begin
|
|
183
|
+
URI.parse(value.to_s)
|
|
184
|
+
rescue URI::InvalidURIError
|
|
185
|
+
nil
|
|
186
|
+
end
|
|
187
|
+
return if (uri.is_a?(URI::HTTP) || uri.is_a?(URI::HTTPS)) && !uri.host.to_s.empty?
|
|
188
|
+
|
|
189
|
+
raise ArgumentError,
|
|
190
|
+
"csp: #{directive} value #{value.inspect} is not an http(s) origin. " \
|
|
191
|
+
'Use scheme + host (e.g. https://cdn.example.com). CSP keywords and ' \
|
|
192
|
+
"non-http schemes ('unsafe-inline', data:, blob:, *) are rejected here — " \
|
|
193
|
+
'set `headers:` if you need them.'
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# Pagefind (opt-in via `search: true`) loads its runtime from the
|
|
197
|
+
# same origin, but that runtime compiles a WebAssembly module —
|
|
198
|
+
# and WASM compilation is governed by `script-src` regardless of
|
|
199
|
+
# origin. Without `'wasm-unsafe-eval'` the search box silently
|
|
200
|
+
# fails with a CSP violation on any host that enforces `_headers`
|
|
201
|
+
# (Cloudflare Pages, Netlify). Same-origin does NOT exempt WASM.
|
|
202
|
+
def apply_search(policy)
|
|
203
|
+
policy['script-src'] << "'wasm-unsafe-eval'"
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def search_enabled?
|
|
207
|
+
@site.config['search'] == true
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# The `<script type="speculationrules">` block the head emits is an
|
|
211
|
+
# inline script as far as CSP is concerned, so `script-src` must
|
|
212
|
+
# carry `'inline-speculation-rules'` (Chrome's keyword for exactly
|
|
213
|
+
# this) or the block is rejected — no prerender, plus a console
|
|
214
|
+
# error on every page. Its content is config-dependent (posts slug,
|
|
215
|
+
# eagerness), so a static hash can't cover it. On by default; the
|
|
216
|
+
# head gates on `speculation_rules.enabled` not being false.
|
|
217
|
+
def apply_speculation_rules(policy)
|
|
218
|
+
policy['script-src'] << "'inline-speculation-rules'"
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def speculation_rules_enabled?
|
|
222
|
+
cfg = @site.config['speculation_rules']
|
|
223
|
+
return true unless cfg.is_a?(Hash)
|
|
224
|
+
|
|
225
|
+
cfg['enabled'] != false
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# Plausible: external tracker + inline init script. Both need explicit
|
|
229
|
+
# CSP allowlisting. Outbound tracking events also hit plausible.io's
|
|
230
|
+
# API endpoint, which is why connect-src is extended.
|
|
231
|
+
def apply_plausible(policy)
|
|
232
|
+
policy['script-src'] << 'https://plausible.io'
|
|
233
|
+
policy['script-src'] << "'#{PlausibleScript::SHA256}'"
|
|
234
|
+
policy['connect-src'] << 'https://plausible.io'
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# Folio cover images are served from a separate cover host. Layouts
|
|
238
|
+
# emit them as `<img src="https://…">`, so img-src needs the host
|
|
239
|
+
# explicitly. Defaults to the hosted foliobooks.app cover CDN; a
|
|
240
|
+
# Folio instance on another domain sets `folio.covers_host` to its
|
|
241
|
+
# own. Buy / cart URLs are anchor navigations (no CSP) — only
|
|
242
|
+
# img-src needs extension.
|
|
243
|
+
DEFAULT_FOLIO_COVERS_HOST = 'https://covers.foliobooks.app'
|
|
244
|
+
|
|
245
|
+
def apply_folio(policy)
|
|
246
|
+
cfg = @site.config['folio'] || {}
|
|
247
|
+
covers = cfg['covers_host'].to_s
|
|
248
|
+
covers = DEFAULT_FOLIO_COVERS_HOST if covers.empty?
|
|
249
|
+
add_origin(policy, 'img-src', covers)
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def folio_enabled?
|
|
253
|
+
cfg = @site.config['folio'] || {}
|
|
254
|
+
!cfg['base_url'].to_s.empty? && !cfg['author_slug'].to_s.empty?
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Font Awesome Pro kit. Loaded via JS from kit.fontawesome.com, which
|
|
258
|
+
# injects styles into the page (so style-src needs 'unsafe-inline')
|
|
259
|
+
# and pulls woff2s from ka-f.fontawesome.com (font-src). The trade-off
|
|
260
|
+
# vs the vendored Free dist: PRO icons + auto-versioning, in exchange
|
|
261
|
+
# for a weaker CSP. Sites that want strict CSP should use the
|
|
262
|
+
# `fontawesome: true` (Free vendored) path instead.
|
|
263
|
+
def apply_fontawesome_kit(policy)
|
|
264
|
+
policy['script-src'] << 'https://kit.fontawesome.com'
|
|
265
|
+
policy['style-src'] << "'unsafe-inline'"
|
|
266
|
+
policy['font-src'] << 'https://ka-f.fontawesome.com'
|
|
267
|
+
policy['connect-src'] << 'https://ka-f.fontawesome.com'
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def fontawesome_kit?
|
|
271
|
+
kit = (@site.config['icons'] || {})['fontawesome_kit']
|
|
272
|
+
kit.is_a?(String) && !kit.empty?
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
# `_newsletter_subscribe.html.erb` lets the operator point the form at
|
|
276
|
+
# any third-party provider (Mailchimp, Buttondown, ConvertKit, …). The
|
|
277
|
+
# default `form-action 'self'` would block those POSTs. We trust the
|
|
278
|
+
# operator-configured `newsletter.action` (and the optional `script:`
|
|
279
|
+
# URL) and add their origins to the matching directives — narrowly,
|
|
280
|
+
# not via `unsafe-inline` or wildcards.
|
|
281
|
+
def apply_newsletter(policy)
|
|
282
|
+
cfg = @site.config['newsletter']
|
|
283
|
+
return unless cfg.is_a?(Hash)
|
|
284
|
+
|
|
285
|
+
add_origin(policy, 'form-action', cfg['action'])
|
|
286
|
+
add_origin(policy, 'script-src', cfg['script'])
|
|
287
|
+
add_origin(policy, 'connect-src', cfg['script'])
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
# Parse `value` as an http(s) URL and append its `scheme://host`
|
|
291
|
+
# origin to `directive` if it isn't already there. Silent no-op for
|
|
292
|
+
# anything that doesn't parse as http(s) — same-origin / relative
|
|
293
|
+
# values fall under `'self'`, scheme-based attacks (javascript:,
|
|
294
|
+
# data:) never get past the URI type-check.
|
|
295
|
+
def add_origin(policy, directive, value)
|
|
296
|
+
return if value.nil? || value.to_s.empty?
|
|
297
|
+
|
|
298
|
+
uri = URI.parse(value.to_s)
|
|
299
|
+
return unless uri.is_a?(URI::HTTP) || uri.is_a?(URI::HTTPS)
|
|
300
|
+
return if uri.host.to_s.empty?
|
|
301
|
+
|
|
302
|
+
origin = "#{uri.scheme}://#{uri.host}"
|
|
303
|
+
policy[directive] ||= ["'self'"]
|
|
304
|
+
policy[directive] << origin unless policy[directive].include?(origin)
|
|
305
|
+
rescue URI::InvalidURIError
|
|
306
|
+
# Malformed config — let it through unguarded; the form just won't
|
|
307
|
+
# work, which is the same surface visitors would see anyway.
|
|
308
|
+
nil
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
# The Plausible script key when the analytics block is fully
|
|
312
|
+
# configured — both `enabled: true` AND `key:` set. Used to gate
|
|
313
|
+
# the CSP extension (plausible.io added to script-src + connect-src
|
|
314
|
+
# only when we're actually emitting the tracker).
|
|
315
|
+
def plausible_key
|
|
316
|
+
cfg = @site.config['plausible']
|
|
317
|
+
return nil unless cfg.is_a?(Hash)
|
|
318
|
+
return nil unless cfg['enabled'] == true
|
|
319
|
+
|
|
320
|
+
key = cfg['key'].to_s
|
|
321
|
+
key.empty? ? nil : key
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
end
|