From f66e9a2cbfbf49eb7b1ce5aef256a65d75b34052 Mon Sep 17 00:00:00 2001 From: donmckenna Date: Tue, 4 Aug 2020 23:44:59 -0600 Subject: [PATCH] docs(docsWeb): redesign docs, add nested navigation link list (#753) * docs(docsWeb): redesign docs, add nested navigation link list Total redesign of documentation styles, page structure and hierarchies. Navigation accommodates nested links and offers parameters for link positioning and styles. ISSUES CLOSED: #630 * docs(docsWeb): add / fix incorrect files from first commit Add missed plugins FAQ entry. Remove unecessary comment in prism-js.md Correct test component paths * docs(docsWeb): fix jest snapshots * docs(docsWeb): fix jest snapshots * docs(docsWeb): fix jest snapshot(?) * docs(docsWeb): move prismjs from devDependencies to dependencies * docs(docsWeb): remove ViewEncapsulation and make all styles global * docs(docsWeb): cleanup old styles, update highlighting Remove remaining evidence of component encapsulated styles. Give `json` syntax highlighting more contrast * docs(docsWeb): all styles dependent only on workspace.json * docs(docsWeb): simplify component selectors * docs(docsWeb): update jest snapshots * docs(docsWeb): add language select ability Language selector shows the language of the current page, links to other corresponding language pages, and indicators showing this, as well as an indicator showing if a current page has no corresponding language equivalent. Will link back to a default language page. Added additional functionality for pages to affect their parent directories' linkText and routes. * docs(docsWeb): fix missing underscore (_) * test(docsWeb): new snaptshots * remove snapshot * remove snapshots * docs(docsWeb): merge in main, update snapshots * feat(docsWeb): add some fixes, and the other pr for showcase * test(docsWeb): updated snapshots * test(docsWeb): merged master, updated snapshots Co-authored-by: sanderelias Co-authored-by: jorgeucano --- ...hosting.ZGlzdFxzdGF0aWNcZG9jLXNpdGVz.cache | 107 + README.md | 4 +- .../scully-docs/src/app/app-routing.module.ts | 9 +- apps/scully-docs/src/app/app.component.css | 97 +- apps/scully-docs/src/app/app.component.html | 82 - .../scully-docs/src/app/app.component.spec.ts | 17 +- apps/scully-docs/src/app/app.component.ts | 25 +- apps/scully-docs/src/app/app.module.ts | 13 +- .../app/components/book/book.component.css | 0 .../app/components/book/book.component.html | 8 - .../components/book/book.component.sandbox.ts | 9 - .../src/app/components/book/book.component.ts | 16 - .../components/button/button.component.css | 0 .../components/button/button.component.html | 6 - .../button/button.component.sandbox.ts | 30 - .../app/components/button/button.component.ts | 22 - .../app/components/card/card.component.css | 3 - .../app/components/card/card.component.html | 9 - .../components/card/card.component.sandbox.ts | 54 - .../src/app/components/card/card.component.ts | 33 - .../components/code/code.component.sandbox.ts | 17 - .../src/app/components/code/code.component.ts | 12 - .../src/app/components/components.module.ts | 40 - .../footer/component/footer.component.css | 44 + .../component/footer.component.spec.ts} | 12 +- .../footer/component/footer.component.ts | 32 + .../app/components/footer/footer.module.ts | 11 + .../src/app/components/footer/index.ts | 1 + .../nav-header/nav-header.component.css | 88 + .../nav-header/nav-header.component.spec.ts} | 12 +- .../nav-header/nav-header.component.ts | 18 + .../header/header.component.sandbox.ts | 6 - .../header/header.component.spec.ts | 24 - .../app/components/header/header.component.ts | 11 - .../app/components/header/header.module.ts | 12 + .../src/app/components/header/index.ts | 1 + .../app/components/hr/hr.component.sandbox.ts | 6 - .../app/components/hr/hr.component.spec.ts | 24 - .../src/app/components/hr/hr.component.ts | 9 - .../app/components/icon/icon.component.css | 0 .../app/components/icon/icon.component.html | 1 - .../components/icon/icon.component.sandbox.ts | 6 - .../components/icon/icon.component.spec.ts | 24 - .../src/app/components/icon/icon.component.ts | 12 - .../lang-select/lang-select.component.css | 156 + .../lang-select/lang-select.component.spec.ts | 24 + .../lang-select/lang-select.component.ts | 31 + .../src/app/components/lang-select/index.ts | 1 + .../lang-select/lang-select.module.ts | 12 + .../components/lang-select/models/index.ts | 1 + .../lang-select/models/lang-select.ts | 32 + .../components/lang-select/services/index.ts | 1 + .../lang-select/lang-select.service.spec.ts | 16 + .../lang-select/lang-select.service.ts | 144 + .../left-menu/left-menu.component.css | 34 - .../left-menu/left-menu.component.html | 19 - .../left-menu/left-menu.component.sandbox.ts | 23 - .../left-menu/left-menu.component.spec.ts | 24 - .../left-menu/left-menu.component.ts | 32 - .../marketing-header.component.sandbox.ts | 6 - .../marketing-header.component.spec.ts | 24 - .../marketing-header.component.ts | 11 - .../child-list/child-list.component.css | 219 + .../child-list/child-list.component.spec.ts | 24 + .../child-list/child-list.component.ts | 72 + .../nav-list/nav-list.component.css | 7 + .../nav-list/nav-list.component.spec.ts} | 12 +- .../components/nav-list/nav-list.component.ts | 18 + .../src/app/components/nav-list/index.ts | 1 + .../app/components/nav-list/models/index.ts | 1 + .../components/nav-list/models/nav-list.ts | 34 + .../components/nav-list/nav-list.module.ts | 13 + .../app/components/nav-list/services/index.ts | 1 + .../nav-list/services/nav-list/index.ts | 1 + .../nav-list/nav-list.service.spec.ts | 16 + .../services/nav-list/nav-list.service.ts | 199 + .../nav-list/services/nav-util/index.ts | 1 + .../nav-util/nav-util.service.spec.ts | 16 + .../services/nav-util/nav-util.service.ts | 160 + .../subheader/subheader.component.sandbox.ts | 6 - .../subheader/subheader.component.spec.ts | 24 - .../subheader/subheader.component.ts | 11 - .../src/app/landing/landing.component.css | 173 - .../src/app/landing/landing.component.html | 130 - .../src/app/landing/landing.component.ts | 12 - .../src/app/landing/landing.module.ts | 12 - .../src/app/pages/docs/docs-routing.module.ts | 21 + .../src/app/pages/docs/docs.module.ts | 14 + .../pages/docs/page/docs.page.component.css | 16 + .../docs/page/docs.page.component.spec.ts} | 12 +- .../pages/docs/page/docs.page.component.ts | 13 + .../features/features.component.css | 82 + .../features/features.component.spec.ts | 24 + .../components/features/features.component.ts | 37 + .../components/intro/intro.component.css | 156 + .../components/intro/intro.component.spec.ts | 24 + .../components/intro/intro.component.ts | 27 + .../components/quote/quote.component.css | 71 + .../components/quote/quote.component.spec.ts | 24 + .../components/quote/quote.component.ts | 16 + .../resources/resources.component.css | 61 + .../resources/resources.component.spec.ts | 24 + .../resources/resources.component.ts | 24 + .../landing/landing-routing.module.ts | 6 +- .../src/app/pages/landing/landing.module.ts | 23 + .../landing/page}/landing.component.spec.ts | 12 +- .../pages/landing/page/landing.component.ts | 14 + .../src/assets/1800contacts_logo_indigo.png | Bin 25218 -> 0 bytes .../src/assets/angular-original.png | Bin 2385 -> 0 bytes apps/scully-docs/src/assets/book.png | Bin 1795 -> 0 bytes apps/scully-docs/src/assets/both.png | Bin 12707 -> 0 bytes apps/scully-docs/src/assets/bullet.png | Bin 1807 -> 0 bytes apps/scully-docs/src/assets/green-bullet.png | Bin 381 -> 0 bytes apps/scully-docs/src/assets/img/footer-bg.png | Bin 0 -> 14437 bytes .../img/icons/angle-double-right-solid.svg | 1 + .../icons/angular-brands.svg} | 0 .../src/assets/img/icons/arrow-left-solid.svg | 1 + .../assets/img/icons/arrow-right-solid.svg | 1 + .../src/assets/img/icons/blog-solid.svg | 1 + .../src/assets/img/icons/book-solid.svg | 1 + .../src/assets/img/icons/check-solid.svg | 1 + .../assets/img/icons/chevron-right-solid.svg | 1 + .../assets/img/icons/code-branch-solid.svg | 1 + .../img/icons/file-exclamation-regular.svg | 1 + .../src/assets/img/icons/github-brands.svg | 1 + .../src/assets/img/icons/globe-solid.svg | 1 + .../src/assets/img/icons/play-solid.svg | 1 + .../assets/img/icons/puzzle-piece-solid.svg | 1 + .../src/assets/img/scully-symbol.svg | 12 + .../src/assets/img/scully-triad.svg | 44 + .../assets/{ => img}/scullyio-logo-black.svg | 0 .../src/assets/img/scullyio-logo.svg | 95 + .../assets/img/showcase/1800contacts-01.jpg | Bin 0 -> 44885 bytes .../src/assets/img/showcase/appsatease-01.jpg | Bin 0 -> 60786 bytes .../src/assets/img/showcase/configcat-01.jpg | Bin 0 -> 41882 bytes .../assets/img/showcase/ledgedevops-01.jpg | Bin 0 -> 58326 bytes .../assets/img/showcase/nicolatoledo-01.jpg | Bin 0 -> 43545 bytes .../src/assets/img/showcase/scully-01.jpg | Bin 0 -> 50740 bytes .../src/assets/img/showcase/solocoding-01.jpg | Bin 0 -> 52497 bytes .../src/assets/machine-learning.png | Bin 35756 -> 0 bytes apps/scully-docs/src/assets/scully-bg-s.svg | 14 - apps/scully-docs/src/assets/scully-triad.svg | 7 - apps/scully-docs/src/assets/scullyio-icon.svg | 1 - apps/scully-docs/src/assets/scullyio-logo.svg | 1 - apps/scully-docs/src/assets/wordmark.svg | 1 - apps/scully-docs/src/closeLangSelect.js | 7 + .../src/docs/doc-page/doc-page.component.css | 0 .../src/docs/doc-page/doc-page.component.html | 10 - .../docs/doc-page/doc-page.component.spec.ts | 24 - .../src/docs/doc-page/doc-page.component.ts | 12 - .../src/docs/docs-routing.module.ts | 22 - apps/scully-docs/src/docs/docs.component.css | 0 apps/scully-docs/src/docs/docs.component.html | 13 - .../src/docs/docs.component.spec.ts | 24 - apps/scully-docs/src/docs/docs.component.ts | 32 - apps/scully-docs/src/docs/docs.module.ts | 20 - apps/scully-docs/src/index.html | 2 - apps/scully-docs/src/styles.css | 455 - apps/scully-docs/src/styles/_beta.css | 8 + apps/scully-docs/src/styles/_fonts.css | 2 + apps/scully-docs/src/styles/_reset.css | 39 + apps/scully-docs/src/styles/_variables.css | 20 + apps/scully-docs/src/styles/blockquote.css | 36 + apps/scully-docs/src/styles/code.css | 136 + apps/scully-docs/src/styles/details.css | 43 + apps/scully-docs/src/styles/headings.css | 70 + apps/scully-docs/src/styles/icon_button.css | 34 + apps/scully-docs/src/styles/link_table.css | 83 + apps/scully-docs/src/styles/links.css | 13 + .../scully-docs/src/styles/paragraph_list.css | 32 + apps/scully-docs/src/styles/prev_next.css | 89 + apps/scully-docs/src/styles/prism-scully.css | 94 + apps/scully-docs/src/styles/showcase.css | 47 + apps/scully-docs/src/styles/table.css | 28 + apps/scully-docs/src/styles/toc.css | 62 + docs/CODE_OF_CONDUCT_es.md | 13 - docs/CONTRIBUTING.md | 240 - docs/blog_es.md | 95 - .../code-of-conduct.md} | 4 +- docs/community/contributing.md | 12 + docs/community/issues.md | 13 + docs/community/showcase.md | 51 + docs/community/support.md | 11 + docs/features.md | 35 - docs/features_es.md | 34 - docs/getting-started.md | 146 - docs/getting-started_es.md | 172 - docs/issues.md | 13 - docs/learn/command-line-options.md | 179 + docs/learn/config.md | 243 + .../core-features/idle-monitor-service.md | 75 + .../core-features/scully-content-component.md | 18 + .../core-features/scully-routes-service.md | 71 + .../core-features/transfer-state-service.md | 46 + docs/learn/core-features/utility-methods.md | 28 + docs/learn/create-a-blog/add-blog-support.md | 119 + .../create-a-blog/generate-new-blog-posts.md} | 110 +- .../use-blog-post-data-in-template.md | 96 + docs/{ => learn}/faq.md | 155 +- docs/learn/getting-started/building.md | 45 + docs/learn/getting-started/installation.md | 54 + docs/learn/getting-started/requirements.md | 59 + docs/learn/getting-started/serving.md | 29 + .../learn/getting-started/tips-for-testing.md | 35 + docs/learn/introduction.md | 37 + docs/learn/introduction_es.md | 39 + docs/learn/legacy-support/angular-v8.md | 22 + docs/{ => learn/legacy-support}/polyfills.md | 12 +- docs/learn/plugins/built-in-plugins/adoc.md | 12 + .../plugins/built-in-plugins/contentFolder.md | 60 + .../learn/plugins/built-in-plugins/ignored.md | 16 + .../plugins/built-in-plugins/json.md} | 37 +- docs/learn/plugins/built-in-plugins/md.md | 12 + .../learn/plugins/built-in-plugins/router-.md | 12 + .../built-in-plugins/seoHrefOptimize.md | 12 + .../community-plugins/disableAngular.md | 106 + docs/learn/plugins/community-plugins/fouc.md | 65 + .../plugins/community-plugins/http404.md | 103 + .../plugins/community-plugins/lazyImages.md | 67 + .../plugins/community-plugins/mediumZoom.md | 65 + .../plugins/community-plugins/minifyHtml.md | 150 + docs/learn/plugins/community-plugins/regex.md | 97 + docs/learn/plugins/community-plugins/rss.md | 123 + .../plugins/community-plugins/sitemap.md | 117 + docs/learn/plugins/community-plugins/toc.md | 83 + docs/learn/plugins/overview.md | 51 + docs/learn/plugins/register-a-new-plugin.md | 81 + docs/learn/plugins/types/allDone.md | 13 + docs/learn/plugins/types/fileHandler.md | 62 + docs/learn/plugins/types/overview-.md | 48 + docs/learn/plugins/types/render.md | 78 + .../learn/plugins/types/routeDiscoveryDone.md | 15 + docs/learn/plugins/types/router.md | 224 + docs/learn/schematics/create-blog-config.md | 8 + .../create-markdown-files-and-skeleton.md | 8 + .../schematics/create-plugin-skeleton.md | 8 + .../create-scully-files-with-ng-add.md | 8 + docs/learn/schematics/run-router-discovery.md | 8 + .../github-actions/scully-publish.md | 11 + docs/learn/utilities/overview---.md | 18 + .../syntax-highlighting/prism-js.md} | 44 +- docs/plugin/contentFolderPlugin.md | 40 - docs/plugin/contentFolderPlugin_es.md | 40 - docs/plugin/ingoredPlugin.md | 7 - docs/plugin/ingoredPlugin_es.md | 7 - docs/plugin/jsonPlugin_es.md | 57 - docs/plugins.md | 373 - docs/plugins_es.md | 373 - docs/pre-requisites.md | 45 - docs/pre-requisites_es.md | 45 - docs/recommended-plugins.md | 54 - docs/recommended-plugins_es.md | 54 - docs/release-for-v8.md | 23 - docs/roadmap.md | 21 - docs/routeParameters.md | 28 - docs/scully-cmd-line.md | 208 - docs/scully-configuration.md | 248 - docs/scully-lib-core.md | 160 - docs/scully-provided-plugins.md | 25 - docs/scully.md | 46 - docs/scully_es.md | 46 - docs/showcase.md | 36 - .../src/lib/fileHanderPlugins/markdown.ts | 43 +- .../scully/src/lib/testData/users-testdata.ts | 4010 +- package-lock.json | 46 + package.json | 5 +- .../__snapshots__/blog-index.spec.ts.snap | 83 +- .../__snapshots__/docsThere.spec.ts.snap | 101299 +++++++++++---- tests/jest/src/__tests__/docsThere.spec.ts | 30 +- workspace.json | 33 +- 270 files changed, 87147 insertions(+), 29538 deletions(-) create mode 100644 .firebase/hosting.ZGlzdFxzdGF0aWNcZG9jLXNpdGVz.cache delete mode 100644 apps/scully-docs/src/app/app.component.html delete mode 100644 apps/scully-docs/src/app/components/book/book.component.css delete mode 100644 apps/scully-docs/src/app/components/book/book.component.html delete mode 100644 apps/scully-docs/src/app/components/book/book.component.sandbox.ts delete mode 100644 apps/scully-docs/src/app/components/book/book.component.ts delete mode 100644 apps/scully-docs/src/app/components/button/button.component.css delete mode 100644 apps/scully-docs/src/app/components/button/button.component.html delete mode 100644 apps/scully-docs/src/app/components/button/button.component.sandbox.ts delete mode 100644 apps/scully-docs/src/app/components/button/button.component.ts delete mode 100644 apps/scully-docs/src/app/components/card/card.component.css delete mode 100644 apps/scully-docs/src/app/components/card/card.component.html delete mode 100644 apps/scully-docs/src/app/components/card/card.component.sandbox.ts delete mode 100644 apps/scully-docs/src/app/components/card/card.component.ts delete mode 100644 apps/scully-docs/src/app/components/code/code.component.sandbox.ts delete mode 100644 apps/scully-docs/src/app/components/code/code.component.ts delete mode 100644 apps/scully-docs/src/app/components/components.module.ts create mode 100644 apps/scully-docs/src/app/components/footer/component/footer.component.css rename apps/scully-docs/src/app/components/{book/book.component.spec.ts => footer/component/footer.component.spec.ts} (56%) create mode 100644 apps/scully-docs/src/app/components/footer/component/footer.component.ts create mode 100644 apps/scully-docs/src/app/components/footer/footer.module.ts create mode 100644 apps/scully-docs/src/app/components/footer/index.ts create mode 100644 apps/scully-docs/src/app/components/header/component/nav-header/nav-header.component.css rename apps/scully-docs/src/app/components/{code/code.component.spec.ts => header/component/nav-header/nav-header.component.spec.ts} (54%) create mode 100644 apps/scully-docs/src/app/components/header/component/nav-header/nav-header.component.ts delete mode 100644 apps/scully-docs/src/app/components/header/header.component.sandbox.ts delete mode 100644 apps/scully-docs/src/app/components/header/header.component.spec.ts delete mode 100644 apps/scully-docs/src/app/components/header/header.component.ts create mode 100644 apps/scully-docs/src/app/components/header/header.module.ts create mode 100644 apps/scully-docs/src/app/components/header/index.ts delete mode 100644 apps/scully-docs/src/app/components/hr/hr.component.sandbox.ts delete mode 100644 apps/scully-docs/src/app/components/hr/hr.component.spec.ts delete mode 100644 apps/scully-docs/src/app/components/hr/hr.component.ts delete mode 100644 apps/scully-docs/src/app/components/icon/icon.component.css delete mode 100644 apps/scully-docs/src/app/components/icon/icon.component.html delete mode 100644 apps/scully-docs/src/app/components/icon/icon.component.sandbox.ts delete mode 100644 apps/scully-docs/src/app/components/icon/icon.component.spec.ts delete mode 100644 apps/scully-docs/src/app/components/icon/icon.component.ts create mode 100644 apps/scully-docs/src/app/components/lang-select/component/lang-select/lang-select.component.css create mode 100644 apps/scully-docs/src/app/components/lang-select/component/lang-select/lang-select.component.spec.ts create mode 100644 apps/scully-docs/src/app/components/lang-select/component/lang-select/lang-select.component.ts create mode 100644 apps/scully-docs/src/app/components/lang-select/index.ts create mode 100644 apps/scully-docs/src/app/components/lang-select/lang-select.module.ts create mode 100644 apps/scully-docs/src/app/components/lang-select/models/index.ts create mode 100644 apps/scully-docs/src/app/components/lang-select/models/lang-select.ts create mode 100644 apps/scully-docs/src/app/components/lang-select/services/index.ts create mode 100644 apps/scully-docs/src/app/components/lang-select/services/lang-select/lang-select.service.spec.ts create mode 100644 apps/scully-docs/src/app/components/lang-select/services/lang-select/lang-select.service.ts delete mode 100644 apps/scully-docs/src/app/components/left-menu/left-menu.component.css delete mode 100644 apps/scully-docs/src/app/components/left-menu/left-menu.component.html delete mode 100644 apps/scully-docs/src/app/components/left-menu/left-menu.component.sandbox.ts delete mode 100644 apps/scully-docs/src/app/components/left-menu/left-menu.component.spec.ts delete mode 100644 apps/scully-docs/src/app/components/left-menu/left-menu.component.ts delete mode 100644 apps/scully-docs/src/app/components/marketing-header/marketing-header.component.sandbox.ts delete mode 100644 apps/scully-docs/src/app/components/marketing-header/marketing-header.component.spec.ts delete mode 100644 apps/scully-docs/src/app/components/marketing-header/marketing-header.component.ts create mode 100644 apps/scully-docs/src/app/components/nav-list/components/child-list/child-list.component.css create mode 100644 apps/scully-docs/src/app/components/nav-list/components/child-list/child-list.component.spec.ts create mode 100644 apps/scully-docs/src/app/components/nav-list/components/child-list/child-list.component.ts create mode 100644 apps/scully-docs/src/app/components/nav-list/components/nav-list/nav-list.component.css rename apps/scully-docs/src/app/components/{button/button.component.spec.ts => nav-list/components/nav-list/nav-list.component.spec.ts} (56%) create mode 100644 apps/scully-docs/src/app/components/nav-list/components/nav-list/nav-list.component.ts create mode 100644 apps/scully-docs/src/app/components/nav-list/index.ts create mode 100644 apps/scully-docs/src/app/components/nav-list/models/index.ts create mode 100644 apps/scully-docs/src/app/components/nav-list/models/nav-list.ts create mode 100644 apps/scully-docs/src/app/components/nav-list/nav-list.module.ts create mode 100644 apps/scully-docs/src/app/components/nav-list/services/index.ts create mode 100644 apps/scully-docs/src/app/components/nav-list/services/nav-list/index.ts create mode 100644 apps/scully-docs/src/app/components/nav-list/services/nav-list/nav-list.service.spec.ts create mode 100644 apps/scully-docs/src/app/components/nav-list/services/nav-list/nav-list.service.ts create mode 100644 apps/scully-docs/src/app/components/nav-list/services/nav-util/index.ts create mode 100644 apps/scully-docs/src/app/components/nav-list/services/nav-util/nav-util.service.spec.ts create mode 100644 apps/scully-docs/src/app/components/nav-list/services/nav-util/nav-util.service.ts delete mode 100644 apps/scully-docs/src/app/components/subheader/subheader.component.sandbox.ts delete mode 100644 apps/scully-docs/src/app/components/subheader/subheader.component.spec.ts delete mode 100644 apps/scully-docs/src/app/components/subheader/subheader.component.ts delete mode 100644 apps/scully-docs/src/app/landing/landing.component.css delete mode 100644 apps/scully-docs/src/app/landing/landing.component.html delete mode 100644 apps/scully-docs/src/app/landing/landing.component.ts delete mode 100644 apps/scully-docs/src/app/landing/landing.module.ts create mode 100644 apps/scully-docs/src/app/pages/docs/docs-routing.module.ts create mode 100644 apps/scully-docs/src/app/pages/docs/docs.module.ts create mode 100644 apps/scully-docs/src/app/pages/docs/page/docs.page.component.css rename apps/scully-docs/src/app/{components/card/card.component.spec.ts => pages/docs/page/docs.page.component.spec.ts} (55%) create mode 100644 apps/scully-docs/src/app/pages/docs/page/docs.page.component.ts create mode 100644 apps/scully-docs/src/app/pages/landing/components/features/features.component.css create mode 100644 apps/scully-docs/src/app/pages/landing/components/features/features.component.spec.ts create mode 100644 apps/scully-docs/src/app/pages/landing/components/features/features.component.ts create mode 100644 apps/scully-docs/src/app/pages/landing/components/intro/intro.component.css create mode 100644 apps/scully-docs/src/app/pages/landing/components/intro/intro.component.spec.ts create mode 100644 apps/scully-docs/src/app/pages/landing/components/intro/intro.component.ts create mode 100644 apps/scully-docs/src/app/pages/landing/components/quote/quote.component.css create mode 100644 apps/scully-docs/src/app/pages/landing/components/quote/quote.component.spec.ts create mode 100644 apps/scully-docs/src/app/pages/landing/components/quote/quote.component.ts create mode 100644 apps/scully-docs/src/app/pages/landing/components/resources/resources.component.css create mode 100644 apps/scully-docs/src/app/pages/landing/components/resources/resources.component.spec.ts create mode 100644 apps/scully-docs/src/app/pages/landing/components/resources/resources.component.ts rename apps/scully-docs/src/app/{ => pages}/landing/landing-routing.module.ts (54%) create mode 100644 apps/scully-docs/src/app/pages/landing/landing.module.ts rename apps/scully-docs/src/app/{landing => pages/landing/page}/landing.component.spec.ts (54%) create mode 100644 apps/scully-docs/src/app/pages/landing/page/landing.component.ts delete mode 100644 apps/scully-docs/src/assets/1800contacts_logo_indigo.png delete mode 100644 apps/scully-docs/src/assets/angular-original.png delete mode 100644 apps/scully-docs/src/assets/book.png delete mode 100644 apps/scully-docs/src/assets/both.png delete mode 100644 apps/scully-docs/src/assets/bullet.png delete mode 100644 apps/scully-docs/src/assets/green-bullet.png create mode 100644 apps/scully-docs/src/assets/img/footer-bg.png create mode 100644 apps/scully-docs/src/assets/img/icons/angle-double-right-solid.svg rename apps/scully-docs/src/assets/{angular.svg => img/icons/angular-brands.svg} (100%) create mode 100644 apps/scully-docs/src/assets/img/icons/arrow-left-solid.svg create mode 100644 apps/scully-docs/src/assets/img/icons/arrow-right-solid.svg create mode 100644 apps/scully-docs/src/assets/img/icons/blog-solid.svg create mode 100644 apps/scully-docs/src/assets/img/icons/book-solid.svg create mode 100644 apps/scully-docs/src/assets/img/icons/check-solid.svg create mode 100644 apps/scully-docs/src/assets/img/icons/chevron-right-solid.svg create mode 100644 apps/scully-docs/src/assets/img/icons/code-branch-solid.svg create mode 100644 apps/scully-docs/src/assets/img/icons/file-exclamation-regular.svg create mode 100644 apps/scully-docs/src/assets/img/icons/github-brands.svg create mode 100644 apps/scully-docs/src/assets/img/icons/globe-solid.svg create mode 100644 apps/scully-docs/src/assets/img/icons/play-solid.svg create mode 100644 apps/scully-docs/src/assets/img/icons/puzzle-piece-solid.svg create mode 100644 apps/scully-docs/src/assets/img/scully-symbol.svg create mode 100644 apps/scully-docs/src/assets/img/scully-triad.svg rename apps/scully-docs/src/assets/{ => img}/scullyio-logo-black.svg (100%) create mode 100644 apps/scully-docs/src/assets/img/scullyio-logo.svg create mode 100644 apps/scully-docs/src/assets/img/showcase/1800contacts-01.jpg create mode 100644 apps/scully-docs/src/assets/img/showcase/appsatease-01.jpg create mode 100644 apps/scully-docs/src/assets/img/showcase/configcat-01.jpg create mode 100644 apps/scully-docs/src/assets/img/showcase/ledgedevops-01.jpg create mode 100644 apps/scully-docs/src/assets/img/showcase/nicolatoledo-01.jpg create mode 100644 apps/scully-docs/src/assets/img/showcase/scully-01.jpg create mode 100644 apps/scully-docs/src/assets/img/showcase/solocoding-01.jpg delete mode 100644 apps/scully-docs/src/assets/machine-learning.png delete mode 100644 apps/scully-docs/src/assets/scully-bg-s.svg delete mode 100644 apps/scully-docs/src/assets/scully-triad.svg delete mode 100644 apps/scully-docs/src/assets/scullyio-icon.svg delete mode 100644 apps/scully-docs/src/assets/scullyio-logo.svg delete mode 100644 apps/scully-docs/src/assets/wordmark.svg create mode 100644 apps/scully-docs/src/closeLangSelect.js delete mode 100644 apps/scully-docs/src/docs/doc-page/doc-page.component.css delete mode 100644 apps/scully-docs/src/docs/doc-page/doc-page.component.html delete mode 100644 apps/scully-docs/src/docs/doc-page/doc-page.component.spec.ts delete mode 100644 apps/scully-docs/src/docs/doc-page/doc-page.component.ts delete mode 100644 apps/scully-docs/src/docs/docs-routing.module.ts delete mode 100644 apps/scully-docs/src/docs/docs.component.css delete mode 100644 apps/scully-docs/src/docs/docs.component.html delete mode 100644 apps/scully-docs/src/docs/docs.component.spec.ts delete mode 100644 apps/scully-docs/src/docs/docs.component.ts delete mode 100644 apps/scully-docs/src/docs/docs.module.ts delete mode 100644 apps/scully-docs/src/styles.css create mode 100644 apps/scully-docs/src/styles/_beta.css create mode 100644 apps/scully-docs/src/styles/_fonts.css create mode 100644 apps/scully-docs/src/styles/_reset.css create mode 100644 apps/scully-docs/src/styles/_variables.css create mode 100644 apps/scully-docs/src/styles/blockquote.css create mode 100644 apps/scully-docs/src/styles/code.css create mode 100644 apps/scully-docs/src/styles/details.css create mode 100644 apps/scully-docs/src/styles/headings.css create mode 100644 apps/scully-docs/src/styles/icon_button.css create mode 100644 apps/scully-docs/src/styles/link_table.css create mode 100644 apps/scully-docs/src/styles/links.css create mode 100644 apps/scully-docs/src/styles/paragraph_list.css create mode 100644 apps/scully-docs/src/styles/prev_next.css create mode 100644 apps/scully-docs/src/styles/prism-scully.css create mode 100644 apps/scully-docs/src/styles/showcase.css create mode 100644 apps/scully-docs/src/styles/table.css create mode 100644 apps/scully-docs/src/styles/toc.css delete mode 100644 docs/CODE_OF_CONDUCT_es.md delete mode 100644 docs/CONTRIBUTING.md delete mode 100644 docs/blog_es.md rename docs/{CODE_OF_CONDUCT.md => community/code-of-conduct.md} (93%) create mode 100644 docs/community/contributing.md create mode 100644 docs/community/issues.md create mode 100644 docs/community/showcase.md create mode 100644 docs/community/support.md delete mode 100644 docs/features.md delete mode 100644 docs/features_es.md delete mode 100644 docs/getting-started.md delete mode 100644 docs/getting-started_es.md delete mode 100644 docs/issues.md create mode 100644 docs/learn/command-line-options.md create mode 100644 docs/learn/config.md create mode 100644 docs/learn/core-features/idle-monitor-service.md create mode 100644 docs/learn/core-features/scully-content-component.md create mode 100644 docs/learn/core-features/scully-routes-service.md create mode 100644 docs/learn/core-features/transfer-state-service.md create mode 100644 docs/learn/core-features/utility-methods.md create mode 100644 docs/learn/create-a-blog/add-blog-support.md rename docs/{blog.md => learn/create-a-blog/generate-new-blog-posts.md} (61%) create mode 100644 docs/learn/create-a-blog/use-blog-post-data-in-template.md rename docs/{ => learn}/faq.md (53%) create mode 100644 docs/learn/getting-started/building.md create mode 100644 docs/learn/getting-started/installation.md create mode 100644 docs/learn/getting-started/requirements.md create mode 100644 docs/learn/getting-started/serving.md create mode 100644 docs/learn/getting-started/tips-for-testing.md create mode 100644 docs/learn/introduction.md create mode 100644 docs/learn/introduction_es.md create mode 100644 docs/learn/legacy-support/angular-v8.md rename docs/{ => learn/legacy-support}/polyfills.md (73%) create mode 100644 docs/learn/plugins/built-in-plugins/adoc.md create mode 100644 docs/learn/plugins/built-in-plugins/contentFolder.md create mode 100644 docs/learn/plugins/built-in-plugins/ignored.md rename docs/{plugin/jsonPlugin.md => learn/plugins/built-in-plugins/json.md} (54%) create mode 100644 docs/learn/plugins/built-in-plugins/md.md create mode 100644 docs/learn/plugins/built-in-plugins/router-.md create mode 100644 docs/learn/plugins/built-in-plugins/seoHrefOptimize.md create mode 100644 docs/learn/plugins/community-plugins/disableAngular.md create mode 100644 docs/learn/plugins/community-plugins/fouc.md create mode 100644 docs/learn/plugins/community-plugins/http404.md create mode 100644 docs/learn/plugins/community-plugins/lazyImages.md create mode 100644 docs/learn/plugins/community-plugins/mediumZoom.md create mode 100644 docs/learn/plugins/community-plugins/minifyHtml.md create mode 100644 docs/learn/plugins/community-plugins/regex.md create mode 100644 docs/learn/plugins/community-plugins/rss.md create mode 100644 docs/learn/plugins/community-plugins/sitemap.md create mode 100644 docs/learn/plugins/community-plugins/toc.md create mode 100644 docs/learn/plugins/overview.md create mode 100644 docs/learn/plugins/register-a-new-plugin.md create mode 100644 docs/learn/plugins/types/allDone.md create mode 100644 docs/learn/plugins/types/fileHandler.md create mode 100644 docs/learn/plugins/types/overview-.md create mode 100644 docs/learn/plugins/types/render.md create mode 100644 docs/learn/plugins/types/routeDiscoveryDone.md create mode 100644 docs/learn/plugins/types/router.md create mode 100644 docs/learn/schematics/create-blog-config.md create mode 100644 docs/learn/schematics/create-markdown-files-and-skeleton.md create mode 100644 docs/learn/schematics/create-plugin-skeleton.md create mode 100644 docs/learn/schematics/create-scully-files-with-ng-add.md create mode 100644 docs/learn/schematics/run-router-discovery.md create mode 100644 docs/learn/utilities/github-actions/scully-publish.md create mode 100644 docs/learn/utilities/overview---.md rename docs/{util.md => learn/utilities/syntax-highlighting/prism-js.md} (73%) delete mode 100644 docs/plugin/contentFolderPlugin.md delete mode 100644 docs/plugin/contentFolderPlugin_es.md delete mode 100644 docs/plugin/ingoredPlugin.md delete mode 100644 docs/plugin/ingoredPlugin_es.md delete mode 100644 docs/plugin/jsonPlugin_es.md delete mode 100644 docs/plugins.md delete mode 100644 docs/plugins_es.md delete mode 100644 docs/pre-requisites.md delete mode 100644 docs/pre-requisites_es.md delete mode 100644 docs/recommended-plugins.md delete mode 100644 docs/recommended-plugins_es.md delete mode 100644 docs/release-for-v8.md delete mode 100644 docs/roadmap.md delete mode 100644 docs/routeParameters.md delete mode 100644 docs/scully-cmd-line.md delete mode 100644 docs/scully-configuration.md delete mode 100644 docs/scully-lib-core.md delete mode 100644 docs/scully-provided-plugins.md delete mode 100644 docs/scully.md delete mode 100644 docs/scully_es.md delete mode 100644 docs/showcase.md diff --git a/.firebase/hosting.ZGlzdFxzdGF0aWNcZG9jLXNpdGVz.cache b/.firebase/hosting.ZGlzdFxzdGF0aWNcZG9jLXNpdGVz.cache new file mode 100644 index 000000000..314a09a9b --- /dev/null +++ b/.firebase/hosting.ZGlzdFxzdGF0aWNcZG9jLXNpdGVz.cache @@ -0,0 +1,107 @@ +6-es2015.8a69b62f6d61f8764ebd.js,1596566020657,a6a6438faffe9fba089bdcb28fe287ee8f90bdcbc29a82863903c7368f265c63 +404.html,1596567912655,74617fc2973e3ed88217bee4f5eac6484031df288705794710c882ed06865a18 +6-es5.8a69b62f6d61f8764ebd.js,1596566020645,e948c1ea4473654bbafbbcc097c8bdf07633204a4d24b44957548248c117996b +7-es2015.4daf3051a8e77d91c592.js,1596567906554,80de54ebeb6113bc422a458bc2d802956d416055645bd6fd2536e3f983bc2859 +common-es2015.5a4281ba7b6b6fabed25.js,1596566020715,5aa3eabbde9e6f48ebedc86cec812e8cbb68d97fd5c21e837c628ef4aae24037 +7-es5.4daf3051a8e77d91c592.js,1596567906520,87b9805601993c1219298d3ab667249e85699a8e6bc2ccfaa936723c310c5538 +common-es5.5a4281ba7b6b6fabed25.js,1596566020684,226989f7634c57c6b6def9a1873ec11dd765d827f94ffe705e02b9343c6c9669 +favicon.ico,1594305359573,c84b11caf102c2b876d1a09c26e8105caf41f8cc764767dd6ada9e57779b8955 +3rdpartylicenses.txt,1596567905508,c12c91b46a2c65901bea9b21c10b199fc5fc549af0a77b14fff72b3fd69b0177 +polyfills-es2015.7133defd57fb98ef8d2c.js,1596566020312,d4e332cc0bb7195bcfc146cf22ed168b4b81b6b44ecc8519aa028010d9769d48 +runtime-es2015.3a9c121c6eb32d5f96a7.js,1596567906008,8406017490ae90f8245c16c014d0c1c82eee5a0e9106bf8ff905af82e51eeb96 +runtime-es5.3a9c121c6eb32d5f96a7.js,1596567906058,443048832399065202846bf8227125984c7f67a6a77e2c0b7a0bb86a14bf1c15 +scripts.402f7c92c5806ba16414.js,1596567905509,d44908ca8f827d302a5bf99c6bec57ce4feaa2005070843d337cbe290f46419f +scully-plugin-disable-angular-stats.json,1596568024919,595bd35756e52df560ed4bf6f53397f70a9b2a87c7f8366e58d1b90d92b03940 +index.html,1596568071052,a610ed7f6acfd620682d25f3490ab9f7802449e35f046202f14918fea55ad1e7 +assets/img/scully-symbol.svg,1596565910932,1cb369c9039f9ae99b40f56c2500e6e9e0d0768cab964c559101c189737a21f7 +assets/img/scully-triad.svg,1596565910932,9243ae398ef6279b87e32d79084a7af698557e5dc34836c29b2dd8e7f044cf4e +assets/img/scullyio-logo-black.svg,1596565910932,e8268c4ae5a0d44e17ac0aafbdeca37212fdd21c690f3d6e86190fbdab67bf9c +assets/img/footer-bg.png,1596565910928,5821ff2adbd8c89329b2f9c526697199621d135d18800756bbec2eeea5e9d70c +assets/img/icons/angle-double-right-solid.svg,1596565910929,b3de323594c8a4df26e7f2bb1625252882b797a6cbfe311cdf20304219886080 +assets/img/icons/angular-brands.svg,1596565910929,d627d0b8278e1addf61636799e4f964118cff1df4451a050f2c4a0c1d5a93601 +assets/img/icons/arrow-left-solid.svg,1596565910929,71fbc98c6ede18065abee8d9041c120d75a6b488a16a0cf5fb057ba8e2d3881c +assets/img/icons/arrow-right-solid.svg,1596565910929,2cac144caf6f91c3fe4d5dcb11e9b2add853c6455e80dbac3822012836fda01d +assets/img/icons/blog-solid.svg,1596565910930,dfe03d4ce3999bdec70c1832410a5a9ebde07849c71c64447b097063fa59362e +assets/img/icons/book-solid.svg,1596565910930,e84e3526d530f0c333695c7b0b99d3d35a3af03ba770901ae8e21c4f5bfb7a04 +assets/img/icons/check-solid.svg,1596565910930,e18cbe4e765ed24eca6c4ae9281f95f3ba58fa8ec9eb063010e4b0a98c3b35af +assets/img/icons/chevron-right-solid.svg,1596565910930,89f649749a98081212901fdd4ef19cb4fca93a6de880ae79f118f5caf6a72581 +assets/img/scullyio-logo.svg,1596565910933,253dfaf6322a693494cef650c5a5c0b95131dcbb2b971f3eee13d842ec0b63af +assets/img/icons/code-branch-solid.svg,1596565910931,0a6823f85ba08c38fb6465e0fb3bff110838087dedacc0505db30b7335e1bb04 +assets/img/icons/file-exclamation-regular.svg,1596565910931,3cda489bbe384f6edf6860bbe5de6885a71936eef7a02db5abb310a2aab274ba +assets/img/icons/globe-solid.svg,1596565910931,4d9cbed8126f54fababdfccf00dbf25fe5d5e7d99d050f5901134c22445ed356 +assets/img/icons/github-brands.svg,1596565910931,2f12af87ba27c26cf063dd44430096ec8bb711b8661b5a30218812c743e4bf5e +assets/img/icons/puzzle-piece-solid.svg,1596565910932,680512fedfb67119abbc3566bb7ceaa5575a0816f1f97f0b6f48e8895a7a99b0 +assets/img/icons/play-solid.svg,1596565910931,d420d0eafbdb5ec46385be6e313300094102740f1a484ec9e993028f7c43c7b1 +assets/scully-routes.json,1596568069863,13a2f73a597a3e4816ebd5c9950b81c4ea06f44a26163342f8f2bcc8c22634b9 +styles.c837721c1770080ef903.css,1596567905509,c2ac83fb0f0d92814baca4540d077eddd4ea087debf4b5c14fcf9e970ab67e46 +docs/index.html,1596568074973,f2c18db6439b18c26c46baa755250db936e258a092cbed2d0a09492ffa583fc4 +assets/beta-badge.png,1596460072492,ac5a6bb7d2b6991e1dbf76cfa4181ec471cf81b575b6225963a0f67150773c28 +docs/community/code-of-conduct/index.html,1596568071923,e04e1e26b63925f1cb3c280719ec0dd3d2be653cbd6c60b1d57e8fbb1fe01749 +assets/img/showcase/1800contacts-01.jpg,1596565910933,751ea02163e7d99d00cd10875f87b61cb6d9943d722e3074d11a5bb23578fe4c +assets/img/showcase/configcat-01.jpg,1596565910934,1d7fae1095c52726a8769993aa463226c73a537d39e4df3828100ff4eb480826 +assets/img/showcase/nicolatoledo-01.jpg,1596565910935,e15e6543d0b9ebeab54fc0b45dbf5b3528f6a41fc9d8aace54b05fe90aa057f1 +assets/img/showcase/scully-01.jpg,1596565910936,e055a770409566a72364da94bef480f0260b5e6d55ff631ba1513ba8ecc887b1 +assets/img/showcase/solocoding-01.jpg,1596565910936,f3a90219916e5c91343b28afa01c1a57b97090533b1aa9b486e3fef6e2dc3730 +assets/img/showcase/ledgedevops-01.jpg,1596565910935,430302869bf39f5ff176f6b52a997f02e91844e077ba5ad63e73477adef06b7b +docs/community/contributing/index.html,1596568071927,a6a596ad7d193203a4f2b104625108c1179715237fb87a382c7485ada8880956 +docs/community/issues/index.html,1596568071928,01f26675bdda0a97b5acfd07bc84d004ef565fa40e71247ce8affeaab1606c36 +docs/learn/core-features/scully-content-component/index.html,1596568071932,3c4ff6dfa252152d87d60e9ba6869f85cd6f6d0d2356f3609072d232c6834167 +docs/learn/command-line-options/index.html,1596568072430,65b0cf2dfdd2e810a82d09e98dc792875de87737d49918bba501f780a9b7c5f2 +docs/learn/core-features/scully-routes-service/index.html,1596568071527,46518b8de87d4b9d70f2e7495a7647af0c2eed6eccc1577cd88caf0681594808 +docs/learn/core-features/transfer-state-service/index.html,1596568071933,1cc1131097877145767773a93083f6a694be84cd9cd968e36fafd1a5aaa72b09 +assets/img/showcase/appsatease-01.jpg,1596565910934,dcc914b02400b7a5514ca9de7d09d94925c37dd66f64aacf7f68505958ff4018 +docs/learn/config/index.html,1596568071410,8000589a56a14adbcb4bfa20899f392c9349180b1ca866f35a2773cb95d2c92a +docs/learn/core-features/utility-methods/index.html,1596568072432,bfe910f30b84ac359655947cf9db97f6dee84bdc228abf6539019553e531cd02 +docs/learn/create-a-blog/add-blog-support/index.html,1596568072440,b186632754c5d94bd18fe9a8ee520f36fb4d17d0498eeb736f7c212817d032b7 +docs/learn/create-a-blog/generate-new-blog-posts/index.html,1596568072444,577e61461fee2b22858cd80611a53b1b9875148cc6871be0c3fd467257235ff9 +docs/learn/create-a-blog/use-blog-post-data-in-template/index.html,1596568072434,238a160eb131f6be4f1759946d6443a0afe52412d48c29a35c781ed51390087f +docs/learn/getting-started/building/index.html,1596568072442,84c16de6a664ed67080cd43ed766046f3d7db3e7905545b37f0fe00d50629146 +docs/learn/getting-started/installation/index.html,1596568072448,999cc832c620e5b802a7003a11253a87c1bbf9345070c6d3683b3595fcb2d447 +docs/learn/getting-started/serving/index.html,1596568072446,9139f21b48e3d2eb0160022f1685514e863c1e2c7ebf046e68f8c86ed5ddf066 +docs/learn/getting-started/requirements/index.html,1596568072435,bb02807021a5d4ccb2b03debb355439e35f6cc6dc64526b00e50cbd9cba42de9 +docs/learn/getting-started/tips-for-testing/index.html,1596568072499,a15c25489c076bfb52a86254282da9a9291b6c588e07c2364b8895d1cf626afa +docs/learn/introduction_es/index.html,1596568071931,cba76069bfb85d16356e98e89bb71a19e910202b8d957a8106269eb4cf2ad9db +docs/learn/legacy-support/angular-v8/index.html,1596568073294,1c7cb3243b0e3eefe584a9f093d0886c5f6f0a434db4ab8c2e2e3cb15f688b59 +docs/learn/introduction/index.html,1596568072580,fca4de2896e20ce10348be0d940c7c9796bb2232d2523da0d847987d6b849b75 +docs/learn/legacy-support/polyfills/index.html,1596568073365,7a57e64a00d83c1f4ec96ff14d61a61b59d141dcf8c44d06c3c931d3ed3ace04 +docs/learn/plugins/built-in-plugins/adoc/index.html,1596568073413,d7f4d424bf624232add743510a53fa849a86d02441e6e0f6fb47630c4b5df4fb +docs/learn/plugins/built-in-plugins/ignored/index.html,1596568073820,c716d91af78931dc07cfdee7b13ddc3c54ae1f937fc9cd00bc7d52fe0f264b26 +docs/learn/plugins/built-in-plugins/contentFolder/index.html,1596568073818,77c91fe9d18f4df891145567ec3e52d73d1e2268700a6a31a70dcec872976115 +docs/learn/plugins/built-in-plugins/json/index.html,1596568073463,55489660f9b8004978948fc26db370c6355bce308f9c995a73decd4c9b6e580f +docs/learn/plugins/built-in-plugins/md/index.html,1596568073596,fa4befb3f162a18827a62a3acbd09df7858ba43bbde7502d549ceecbb3ec0628 +docs/learn/plugins/built-in-plugins/router-/index.html,1596568073823,e938b38eebcca70115c859042157300ca2da167a4e1b39a2ec042c73152ee969 +docs/learn/plugins/built-in-plugins/seoHrefOptimize/index.html,1596568073506,cdd031510ac8e5f37e2a4eaf72f7d29904688f70c8289aa0a38d4b9b7c33be39 +docs/learn/plugins/community-plugins/disableAngular/index.html,1596568073710,1f836ad6c20b429f511c263d0fa0f1634cf393fcbea4cf9b76be50c85d2acc64 +docs/learn/plugins/community-plugins/lazyImages/index.html,1596568074358,b74028559821edadf01532e8fc429305889e701a9facf65770f0189f927a30ac +docs/learn/plugins/community-plugins/fouc/index.html,1596568073560,8a965028230d041542eab3f153944323ada7bebef9b64c7d3b404143998ec5bd +docs/learn/plugins/community-plugins/http404/index.html,1596568073651,9a7fa5917b7db3c9b2777ba3053b9a82cbf466c3925d5154db258f5e3f2f1a6b +docs/community/showcase/index.html,1596568071926,d27a1c0cd0320386beabb026e35381d9a124ce9d40fd0eb7449de695d1f7d5b8 +docs/community/support/index.html,1596568071929,7515e9b360d0dfa580c78d350be9c8cd28ddcb6cb5c9669e3139ac39e40e5f99 +docs/learn/core-features/idle-monitor-service/index.html,1596568071924,c9fb7b75385dcccb1b5cb618840f08510cc2a8389a2bcff4e54be713777b553f +docs/learn/plugins/community-plugins/mediumZoom/index.html,1596568074352,167aca844a741b2dde7c08b6b84c3c008216a8924f79e93df57821a80ba4b5d2 +docs/learn/faq/index.html,1596568072438,54bc429c37dd37dbed937339f3a7e093ca67ab01817de36465a315487b8652f1 +polyfills-es5.cf81b6d994a335b9e794.js,1596566022868,b1066a9d4ab783d99ead1379bafe4ad4c3ab9fcf031b327617b8e58c4d4b575f +docs/learn/plugins/community-plugins/regex/index.html,1596568074355,a0e067681376498b1faf6961f10916487e5b0b2c258f30b8a5ba2171ca712f7e +docs/learn/plugins/community-plugins/minifyHtml/index.html,1596568073893,28eb85725c0f0c6d0e0230b8769e41c25c8bbe5f9799d708fbdedbc88840a23a +docs/learn/plugins/community-plugins/rss/index.html,1596568074350,ad2b17d3768de1d1eaf9f9447ff2eb50dc3fa1cf42e5ee4dd58e17bdb65f74ce +docs/learn/plugins/community-plugins/toc/index.html,1596568073952,750f40b6022c9fc9a88647fd71b4dcd36be0a8e657df90ffe8482789758562a1 +docs/learn/plugins/overview/index.html,1596568074356,ba85c6883b0af6af81e962558c8bb951c3def7c64660078af59d199dc80fa6a0 +docs/learn/plugins/community-plugins/sitemap/index.html,1596568074359,b539b920c575422d477bfa7b2bb02f096449c4653d1c2cf1374cc2bf9ab43a9a +docs/learn/plugins/register-a-new-plugin/index.html,1596568074353,8c0eed2c6a485701e80c2f9051d62f20037ee87326c3863d17dff085cd0f30af +docs/learn/plugins/types/allDone/index.html,1596568074360,7be2b210521905b2cf9fac1950434c3d109f456e474835f41183c3b26cecb81b +docs/learn/plugins/types/overview-/index.html,1596568074362,fe3e5b059831083e9b94deb7fa222a520a16377bd69a3190110049c55ad6c8dd +docs/learn/plugins/types/fileHandler/index.html,1596568074363,68b8958df745705007fadb502a395b5decf6cd36581a3a43c7fed374e2164662 +docs/learn/plugins/types/render/index.html,1596568074436,b351449b85b7020551047c36c5c0852aa271fe2d09b4e6c430e2d7d0d0a98c2b +docs/learn/plugins/types/routeDiscoveryDone/index.html,1596568075042,acc64fd50bbf6f3cc25ee340ee9a65b475916991b750fb384f06d33ad801b3df +docs/learn/schematics/create-blog-config/index.html,1596568075157,6db4de1a9e756fe0464465ea303dc01f973515bc739345d8b9b31dbff2d74f17 +docs/learn/schematics/create-markdown-files-and-skeleton/index.html,1596568075040,3c03d7fdc7bba7c46fcda10ab2799654ef88b1341c264f3551982f42e11476a2 +docs/learn/plugins/types/router/index.html,1596568074962,2c818488dec60586e487dee7ae82bdb799dd4ff5edeaa9c1e2d6bc6f9b4209f3 +docs/learn/schematics/create-scully-files-with-ng-add/index.html,1596568075155,5eb76116648583af49d0dda6eee7b275eabb7986c5b90b35f6b07e64296f7e5d +docs/learn/schematics/run-router-discovery/index.html,1596568075160,10497dcee13c3e58aa120fd7c6cd82ab1ea7e05a4d063619e066cf6800f17276 +docs/learn/utilities/github-actions/scully-publish/index.html,1596568075195,525b048d699aa6d1db7e98200dc47c3bb416b66dad7a685753f6b2043bf4a355 +docs/learn/utilities/overview---/index.html,1596568075286,99a4a6d022b11e82ef03bae1768d399f1edb1917055b4a34a3689edddc01739f +docs/learn/schematics/create-plugin-skeleton/index.html,1596568075159,1dffd47c633d8633e7c6644af60b649242aa864c1b7c0a45a43f3b82495a11e9 +docs/learn/utilities/syntax-highlighting/prism-js/index.html,1596568075253,e3a6f8c3843e75109a4b15bc84f45dc74e9b22cc3c4e08af7dc96295d6970529 +main-es2015.03f6df5606af94e3b675.js,1596567912213,914ba09b4f7a4fc989fe386108d352ffa085402f79055c121714b482b5034609 +main-es5.03f6df5606af94e3b675.js,1596567911415,a08f4539705617033ffdeab500f1cca3984e1407a6e674f1f694ac71a86018ce +stats-es2015.json,1596567905514,885cc5a47efe16799289a7f5dc8f184e9f018eece09192178b85aad2bbd0cc70 diff --git a/README.md b/README.md index 85f835637..bc4402bb9 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ [![CLA assistant](https://cla-assistant.io/readme/badge/scullyio/scully)](https://cla-assistant.io/scullyio/scully) ![CI](https://github.com/scullyio/scully/workflows/Node.js%20CI/badge.svg) -The best way to build the fastest Angular apps. Scully is a static site generator for Angular projects looking to embrace the JAMStack. +The best way to build the fastest Angular apps. Scully is a static site generator for Angular projects looking to embrace the Jamstack. - [Getting Started](docs/getting-started.md) - [Full Documentation](docs/scully.md) @@ -41,7 +41,7 @@ The security and cost implications to that fact can be mind blowing when you thi For those wanting to know more about this process, please read the [Getting Started](docs/getting-started.md) guide. For those who want to know more about the theory behind pre-rendering JavaScript SPAs, our friends at [Netlify](https://netlify.com) -wrote a [free book about the JAMStack](https://www.netlify.com/pdf/oreilly-modern-web-development-on-the-jamstack.pdf). +wrote a [free book about the Jamstack](https://www.netlify.com/pdf/oreilly-modern-web-development-on-the-jamstack.pdf). Check that out today. #### GET A HOLD OF US 24/7 diff --git a/apps/scully-docs/src/app/app-routing.module.ts b/apps/scully-docs/src/app/app-routing.module.ts index 2e4ee1fbd..b21ba5f31 100644 --- a/apps/scully-docs/src/app/app-routing.module.ts +++ b/apps/scully-docs/src/app/app-routing.module.ts @@ -4,17 +4,16 @@ import { Routes, RouterModule } from '@angular/router'; const routes: Routes = [ { path: '', - loadChildren: () => - import('./landing/landing.module').then(m => m.LandingModule) + loadChildren: () => import('./pages/landing/landing.module').then((m) => m.LandingModule), }, { path: 'docs', - loadChildren: () => import('../docs/docs.module').then(m => m.DocsModule) - } + loadChildren: () => import('./pages/docs/docs.module').then((m) => m.DocsModule), + }, ]; @NgModule({ imports: [RouterModule.forRoot(routes)], - exports: [RouterModule] + exports: [RouterModule], }) export class AppRoutingModule {} diff --git a/apps/scully-docs/src/app/app.component.css b/apps/scully-docs/src/app/app.component.css index 502db5d1b..ac44bb02d 100644 --- a/apps/scully-docs/src/app/app.component.css +++ b/apps/scully-docs/src/app/app.component.css @@ -1,84 +1,27 @@ -:host { - display: grid; - height: 100vh; - grid-template-rows: 60px 1fr 60px; +app-root { + position: relative; + display: flex; + flex-direction: column; + align-items: flex-start; + height: 100%; + max-height: 100vh; } -:host > header { - display: grid; - margin: 0; - padding: 0px 20px; - grid-template-columns: 120px 1fr; - place-items: center right; - overflow: none; +app-root > .page-content { + flex: 1; + display: flex; + width: 100%; + max-height: 100%; + padding-top: 80px; } -header h1, -footer h3 { - margin: 0; +app-root > .page-content .nav-container { + display: flex; + flex-direction: column; } -main { - padding: 10px; - background-image: url(../assets/scully-bg-s.svg); - background-size: cover; -} - -.github { - float: right; - margin-top: 10px; - margin-left: 20px; -} - -footer { - padding-top: 48px; - min-height: 250px; - display: grid; - grid-template-columns: 25% 15% 15% 15% 25%; - background: var(--scully-green-wash); -} - -.footer-1 { - grid-column-start: 2; - grid-column-end: 2; - text-align: center; -} - -.footer-2 { - grid-column-start: 3; - grid-column-end: 3; - text-align: center; -} - -.footer-3 { - grid-column-start: 4; - grid-column-end: 4; - text-align: center; -} -a { - text-decoration: none; - color: var(--scully-darkgray); - cursor: pointer; -} - -.footer-1 > h3, -.footer-2 > h3, -.footer-3 > h3 { - color: var(--scully-green); - margin-bottom: 10px; -} - -@media (max-width: 1024px) { - footer { - grid-template-columns: 16px 1fr 1fr 1fr 16px; - } - nav { - transform: scale(0.9); - } -} - -header { - background: #000; - color: #fff; - min-height: 90px; +app-root > .page-content .router-container { + flex: 1; + max-height: 100vh; + overflow-y: auto; } diff --git a/apps/scully-docs/src/app/app.component.html b/apps/scully-docs/src/app/app.component.html deleted file mode 100644 index e2305430c..000000000 --- a/apps/scully-docs/src/app/app.component.html +++ /dev/null @@ -1,82 +0,0 @@ -
- - scullyLogo - - -
- -
- - diff --git a/apps/scully-docs/src/app/app.component.spec.ts b/apps/scully-docs/src/app/app.component.spec.ts index 005364c90..d81ff33e7 100644 --- a/apps/scully-docs/src/app/app.component.spec.ts +++ b/apps/scully-docs/src/app/app.component.spec.ts @@ -6,7 +6,7 @@ describe('AppComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [RouterTestingModule], - declarations: [AppComponent] + declarations: [AppComponent], }).compileComponents(); })); @@ -15,19 +15,4 @@ describe('AppComponent', () => { const app = fixture.componentInstance; expect(app).toBeTruthy(); }); - - it(`should have as title 'scullyDocs'`, () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('scullyDocs'); - }); - - it('should render title', () => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.nativeElement; - expect(compiled.querySelector('.content span').textContent).toContain( - 'scullyDocs app is running!' - ); - }); }); diff --git a/apps/scully-docs/src/app/app.component.ts b/apps/scully-docs/src/app/app.component.ts index e4f9f05bd..92548b2b1 100644 --- a/apps/scully-docs/src/app/app.component.ts +++ b/apps/scully-docs/src/app/app.component.ts @@ -1,10 +1,27 @@ -import { Component } from '@angular/core'; +import { Component, ViewEncapsulation } from '@angular/core'; +import { Router } from '@angular/router'; @Component({ selector: 'app-root', - templateUrl: './app.component.html', - styleUrls: ['./app.component.css'] + encapsulation: ViewEncapsulation.None, + template: ` + + +
+ + +
+ +
+
+ `, }) export class AppComponent { - title = 'scullyDocs'; + constructor(private router: Router) {} + get showNavlist() { + return this.router.url !== '/'; + } } diff --git a/apps/scully-docs/src/app/app.module.ts b/apps/scully-docs/src/app/app.module.ts index 2f56c07e5..5fc9cd078 100644 --- a/apps/scully-docs/src/app/app.module.ts +++ b/apps/scully-docs/src/app/app.module.ts @@ -4,7 +4,9 @@ import { BrowserModule } from '@angular/platform-browser'; import { ScullyLibModule } from '@scullyio/ng-lib'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; -import { ComponentsModule } from './components/components.module'; +import { HeaderModule } from './components/header'; +import { LangSelectModule } from './components/lang-select'; +import { NavListModule } from './components/nav-list'; @NgModule({ declarations: [AppComponent], @@ -12,10 +14,11 @@ import { ComponentsModule } from './components/components.module'; BrowserModule, AppRoutingModule, HttpClientModule, - ComponentsModule, - ScullyLibModule.forRoot({ useTransferState: true }) + HeaderModule, + LangSelectModule, + NavListModule, + ScullyLibModule.forRoot({ useTransferState: true }), ], - providers: [], - bootstrap: [AppComponent] + bootstrap: [AppComponent], }) export class AppModule {} diff --git a/apps/scully-docs/src/app/components/book/book.component.css b/apps/scully-docs/src/app/components/book/book.component.css deleted file mode 100644 index e69de29bb..000000000 diff --git a/apps/scully-docs/src/app/components/book/book.component.html b/apps/scully-docs/src/app/components/book/book.component.html deleted file mode 100644 index 6cc850c4b..000000000 --- a/apps/scully-docs/src/app/components/book/book.component.html +++ /dev/null @@ -1,8 +0,0 @@ - - Book icon - -
-

{{ header }}

-

{{ text }}

-
-
diff --git a/apps/scully-docs/src/app/components/book/book.component.sandbox.ts b/apps/scully-docs/src/app/components/book/book.component.sandbox.ts deleted file mode 100644 index 5b01bbc4f..000000000 --- a/apps/scully-docs/src/app/components/book/book.component.sandbox.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { sandboxOf } from 'angular-playground'; -import { BookComponent } from './book.component'; - -export default sandboxOf(BookComponent).add('default', { - template: ` - ` -}); diff --git a/apps/scully-docs/src/app/components/book/book.component.ts b/apps/scully-docs/src/app/components/book/book.component.ts deleted file mode 100644 index 49a972725..000000000 --- a/apps/scully-docs/src/app/components/book/book.component.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Component, Input, OnInit } from '@angular/core'; - -@Component({ - selector: 'app-book', - templateUrl: './book.component.html', - styleUrls: ['./book.component.css'], -}) -export class BookComponent implements OnInit { - @Input() header: string; - @Input() text: string; - @Input() href: string; - - constructor() {} - - ngOnInit(): void {} -} diff --git a/apps/scully-docs/src/app/components/button/button.component.css b/apps/scully-docs/src/app/components/button/button.component.css deleted file mode 100644 index e69de29bb..000000000 diff --git a/apps/scully-docs/src/app/components/button/button.component.html b/apps/scully-docs/src/app/components/button/button.component.html deleted file mode 100644 index 5848c858e..000000000 --- a/apps/scully-docs/src/app/components/button/button.component.html +++ /dev/null @@ -1,6 +0,0 @@ -{{ text }} diff --git a/apps/scully-docs/src/app/components/button/button.component.sandbox.ts b/apps/scully-docs/src/app/components/button/button.component.sandbox.ts deleted file mode 100644 index fb7e56890..000000000 --- a/apps/scully-docs/src/app/components/button/button.component.sandbox.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { sandboxOf } from 'angular-playground'; -import { ButtonComponent } from './button.component'; - -export default sandboxOf(ButtonComponent) - .add('default', { - template: `` - }) - .add('nav-select-active', { - template: `` - }) - .add('nav-default-inactive', { - template: `` - }) - .add('invert', { - template: `` - }) - .add('full-menu', { - template: ` - - ` - }); diff --git a/apps/scully-docs/src/app/components/button/button.component.ts b/apps/scully-docs/src/app/components/button/button.component.ts deleted file mode 100644 index a89c37670..000000000 --- a/apps/scully-docs/src/app/components/button/button.component.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Component, Input, OnInit, ElementRef } from '@angular/core'; - -@Component({ - selector: 'app-button', - templateUrl: './button.component.html', - styleUrls: ['./button.component.css'] -}) -export class ButtonComponent implements OnInit { - elm = this.elmRef.nativeElement as HTMLElement; - @Input() text: string; - @Input() class: string; - @Input() active: boolean; - @Input() link: string; - - constructor(private elmRef: ElementRef) {} - - ngOnInit(): void { - if (this.elm) { - this.elm.setAttribute('tabindex', '-1'); - } - } -} diff --git a/apps/scully-docs/src/app/components/card/card.component.css b/apps/scully-docs/src/app/components/card/card.component.css deleted file mode 100644 index a2b9cdd2d..000000000 --- a/apps/scully-docs/src/app/components/card/card.component.css +++ /dev/null @@ -1,3 +0,0 @@ -.card-container { - height: 100%; -} diff --git a/apps/scully-docs/src/app/components/card/card.component.html b/apps/scully-docs/src/app/components/card/card.component.html deleted file mode 100644 index 6cd92f294..000000000 --- a/apps/scully-docs/src/app/components/card/card.component.html +++ /dev/null @@ -1,9 +0,0 @@ -
-
- -
-
-

{{ header }}

-

{{ text }}

-
-
diff --git a/apps/scully-docs/src/app/components/card/card.component.sandbox.ts b/apps/scully-docs/src/app/components/card/card.component.sandbox.ts deleted file mode 100644 index 3cfc61bb6..000000000 --- a/apps/scully-docs/src/app/components/card/card.component.sandbox.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { sandboxOf } from 'angular-playground'; -import { CardComponent } from './card.component'; - -export default sandboxOf(CardComponent) - .add('default', { - template: ` - ` - }) - .add('invert color', { - template: ` - ` - }) - .add('png icon', { - template: ` - ` - }) - .add('svg external src', { - template: ` - ` - }) - .add('svg external src inverting color', { - template: ` - ` - }) - .add('png external src', { - template: ` - ` - }); diff --git a/apps/scully-docs/src/app/components/card/card.component.ts b/apps/scully-docs/src/app/components/card/card.component.ts deleted file mode 100644 index 77bd40365..000000000 --- a/apps/scully-docs/src/app/components/card/card.component.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Component, Input, OnInit } from '@angular/core'; - -@Component({ - selector: 'app-card', - templateUrl: './card.component.html', - styleUrls: ['./card.component.css'] -}) -export class CardComponent implements OnInit { - @Input() alt: string; - @Input() iconUrl: string; - @Input() header: string; - @Input() text: string; - @Input() invertColors?: boolean; - @Input() toWhite = false; - - isSvg: boolean; - - constructor() {} - - ngOnInit(): void { - if (this.invertColors) { - this.isSvg = this.checkIconFormat(); - } - } - - private checkIconFormat(): boolean { - if (this.iconUrl) { - return this.iconUrl.substring(this.iconUrl.length - 3) === 'svg'; - } else { - return false; - } - } -} diff --git a/apps/scully-docs/src/app/components/code/code.component.sandbox.ts b/apps/scully-docs/src/app/components/code/code.component.sandbox.ts deleted file mode 100644 index 384d02b82..000000000 --- a/apps/scully-docs/src/app/components/code/code.component.sandbox.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { sandboxOf } from 'angular-playground'; -import { CodeComponent } from './code.component'; - -// tslint:disable-next-line:variable-name -const _code = `const Prism = require('prismjs'); -// The code snippet you want to highlight, as a string -const code = \`var data = 1;\`; - -// Returns a highlighted HTML string -const html = Prism.highlight(code, Prism.languages.javascript, 'javascript');`; - -export default sandboxOf(CodeComponent).add('default', { - template: ``, - context: { - code: _code - } -}); diff --git a/apps/scully-docs/src/app/components/code/code.component.ts b/apps/scully-docs/src/app/components/code/code.component.ts deleted file mode 100644 index 13cefac67..000000000 --- a/apps/scully-docs/src/app/components/code/code.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Component, Input } from '@angular/core'; - -@Component({ - selector: 'app-code', - template: ` -
{{codeText}}
- ` -}) -export class CodeComponent { - @Input() codeClass = 'LANGUAGE-BASH'; - @Input() codeText: string; -} diff --git a/apps/scully-docs/src/app/components/components.module.ts b/apps/scully-docs/src/app/components/components.module.ts deleted file mode 100644 index eb0de46bb..000000000 --- a/apps/scully-docs/src/app/components/components.module.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { ButtonComponent } from './button/button.component'; -import { RouterModule } from '@angular/router'; -import { HeaderComponent } from './header/header.component'; -import { SubheaderComponent } from './subheader/subheader.component'; -import { CodeComponent } from './code/code.component'; -import { CardComponent } from './card/card.component'; -import { BookComponent } from './book/book.component'; -import { LeftMenuComponent } from './left-menu/left-menu.component'; -import { IconComponent } from './icon/icon.component'; -import { MarketingHeaderComponent } from './marketing-header/marketing-header.component'; -import { HrComponent } from './hr/hr.component'; -import { FormsModule } from '@angular/forms'; - -@NgModule({ - declarations: [ - ButtonComponent, - HeaderComponent, - SubheaderComponent, - CodeComponent, - CardComponent, - BookComponent, - LeftMenuComponent, - IconComponent, - MarketingHeaderComponent, - HrComponent - ], - exports: [ - ButtonComponent, - HeaderComponent, - HrComponent, - CodeComponent, - CardComponent, - LeftMenuComponent, - BookComponent - ], - imports: [CommonModule, RouterModule, FormsModule] -}) -export class ComponentsModule {} diff --git a/apps/scully-docs/src/app/components/footer/component/footer.component.css b/apps/scully-docs/src/app/components/footer/component/footer.component.css new file mode 100644 index 000000000..5e94a68f5 --- /dev/null +++ b/apps/scully-docs/src/app/components/footer/component/footer.component.css @@ -0,0 +1,44 @@ +footer.scullyio-footer { + flex-shrink: 0; + position: relative; + display: flex; + justify-content: center; + width: 100%; + padding: 64px; + padding-bottom: 112px; + background: var(--scully-night) url('/assets/img/footer-bg.png') 0 0 no-repeat; +} + +footer.scullyio-footer section { + display: flex; + flex-direction: column; +} +footer.scullyio-footer section:not(:first-child) { + margin-left: 124px; +} + +footer.scullyio-footer section h2 { + color: var(--scully-white); + font-size: 20px; + font-weight: 900; + letter-spacing: 1px; + text-transform: uppercase; +} + +footer.scullyio-footer section ul { + list-style: none; + margin: 18px 0; +} + +footer.scullyio-footer section ul li a { + display: block; + padding: 6px 0; + color: var(--scully-white); + font-size: 15px; + font-weight: 600; + letter-spacing: 0.5px; + opacity: 0.8; +} +footer.scullyio-footer section ul li a:hover { + opacity: 1; +} diff --git a/apps/scully-docs/src/app/components/book/book.component.spec.ts b/apps/scully-docs/src/app/components/footer/component/footer.component.spec.ts similarity index 56% rename from apps/scully-docs/src/app/components/book/book.component.spec.ts rename to apps/scully-docs/src/app/components/footer/component/footer.component.spec.ts index 6254275b5..163f646eb 100644 --- a/apps/scully-docs/src/app/components/book/book.component.spec.ts +++ b/apps/scully-docs/src/app/components/footer/component/footer.component.spec.ts @@ -1,19 +1,19 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { BookComponent } from './book.component'; +import { FooterComponent } from './footer.component'; -describe('BookComponent', () => { - let component: BookComponent; - let fixture: ComponentFixture; +describe('FooterComponent', () => { + let component: FooterComponent; + let fixture: ComponentFixture; beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [BookComponent] + declarations: [FooterComponent], }).compileComponents(); })); beforeEach(() => { - fixture = TestBed.createComponent(BookComponent); + fixture = TestBed.createComponent(FooterComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/apps/scully-docs/src/app/components/footer/component/footer.component.ts b/apps/scully-docs/src/app/components/footer/component/footer.component.ts new file mode 100644 index 000000000..ea837e4ed --- /dev/null +++ b/apps/scully-docs/src/app/components/footer/component/footer.component.ts @@ -0,0 +1,32 @@ +import { Component, ViewEncapsulation } from '@angular/core'; + +@Component({ + selector: 'footer.scullyio-footer', + encapsulation: ViewEncapsulation.None, + template: ` +
+

Learn

+ +
+
+

Community

+ +
+
+

Organization

+ +
+ `, +}) +export class FooterComponent {} diff --git a/apps/scully-docs/src/app/components/footer/footer.module.ts b/apps/scully-docs/src/app/components/footer/footer.module.ts new file mode 100644 index 000000000..2d00fb291 --- /dev/null +++ b/apps/scully-docs/src/app/components/footer/footer.module.ts @@ -0,0 +1,11 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { RouterModule } from '@angular/router'; +import { FooterComponent } from './component/footer.component'; + +@NgModule({ + declarations: [FooterComponent], + exports: [FooterComponent], + imports: [CommonModule, RouterModule], +}) +export class FooterModule {} diff --git a/apps/scully-docs/src/app/components/footer/index.ts b/apps/scully-docs/src/app/components/footer/index.ts new file mode 100644 index 000000000..bf8bb0e8f --- /dev/null +++ b/apps/scully-docs/src/app/components/footer/index.ts @@ -0,0 +1 @@ +export * from './footer.module'; diff --git a/apps/scully-docs/src/app/components/header/component/nav-header/nav-header.component.css b/apps/scully-docs/src/app/components/header/component/nav-header/nav-header.component.css new file mode 100644 index 000000000..8942378c4 --- /dev/null +++ b/apps/scully-docs/src/app/components/header/component/nav-header/nav-header.component.css @@ -0,0 +1,88 @@ +nav.scullyio-nav-header { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 80px; + background: black; +} +nav.scullyio-nav-header ul { + display: flex; + justify-content: stretch; + width: 100%; + height: 100%; +} +nav.scullyio-nav-header ul li { + flex: 0; + display: flex; + align-items: center; + white-space: nowrap; + color: rgba(0, 0, 0, 0.8); + color: white !important; + font-size: 12px; + font-weight: 800; + text-transform: uppercase; + letter-spacing: 1.5px; +} +nav.scullyio-nav-header ul li a { + padding: 28px; + color: var(--scully-black); + color: white !important; + font-weight: 800; + opacity: 0.7; + transition: box-shadow var(--scully-transition-ease), background-color var(--scully-transition-ease); +} +nav.scullyio-nav-header ul li a:active { + transform: translateY(1px); +} +nav.scullyio-nav-header ul li a:hover { + opacity: 1; + box-shadow: 0 3px 0 var(--scully-green); +} + +nav.scullyio-nav-header ul li.text { + padding: 0 28px; +} + +nav.scullyio-nav-header ul li.logo { + flex: 1; +} +nav.scullyio-nav-header ul li.logo a { + width: 142px; + height: 46px; + margin: 0 28px; + box-shadow: none; + background: url('/assets/img/scullyio-logo.svg') center no-repeat; + background-size: cover; + opacity: 1; +} +nav.scullyio-nav-header ul li.logo a:hover { + opacity: 0.9; +} + +nav.scullyio-nav-header ul li.feature a { + margin: 0 28px; + padding: 15px 40px; + color: var(--scully-white); + border-radius: 8px; + box-shadow: none; + border: solid 3px var(--scully-green); + background: var(--scully-green); + opacity: 1; +} +nav.scullyio-nav-header ul li.feature a:hover { + color: var(--scully-green); + background: transparent; +} + +nav.scullyio-nav-header ul li.icon { + padding: 4px 0; +} + +nav.scullyio-nav-header ul li.icon.github a { + -webkit-mask: url('/assets/img/icons/github-brands.svg') no-repeat 100% 100%; + mask: url('/assets/img/icons/github-brands.svg') no-repeat 100% 100%; + -webkit-mask-size: cover; + mask-size: cover; + background-color: white; +} diff --git a/apps/scully-docs/src/app/components/code/code.component.spec.ts b/apps/scully-docs/src/app/components/header/component/nav-header/nav-header.component.spec.ts similarity index 54% rename from apps/scully-docs/src/app/components/code/code.component.spec.ts rename to apps/scully-docs/src/app/components/header/component/nav-header/nav-header.component.spec.ts index a68754a86..128d98171 100644 --- a/apps/scully-docs/src/app/components/code/code.component.spec.ts +++ b/apps/scully-docs/src/app/components/header/component/nav-header/nav-header.component.spec.ts @@ -1,19 +1,19 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { CodeComponent } from './code.component'; +import { NavHeaderComponent } from './nav-header.component'; -describe('CodeComponent', () => { - let component: CodeComponent; - let fixture: ComponentFixture; +describe('NavHeaderComponent', () => { + let component: NavHeaderComponent; + let fixture: ComponentFixture; beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [CodeComponent] + declarations: [NavHeaderComponent], }).compileComponents(); })); beforeEach(() => { - fixture = TestBed.createComponent(CodeComponent); + fixture = TestBed.createComponent(NavHeaderComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/apps/scully-docs/src/app/components/header/component/nav-header/nav-header.component.ts b/apps/scully-docs/src/app/components/header/component/nav-header/nav-header.component.ts new file mode 100644 index 000000000..5890401a5 --- /dev/null +++ b/apps/scully-docs/src/app/components/header/component/nav-header/nav-header.component.ts @@ -0,0 +1,18 @@ +import { Component, ViewEncapsulation } from '@angular/core'; + +@Component({ + selector: 'nav.scullyio-nav-header', + encapsulation: ViewEncapsulation.None, + template: ` + beta + + `, +}) +export class NavHeaderComponent {} diff --git a/apps/scully-docs/src/app/components/header/header.component.sandbox.ts b/apps/scully-docs/src/app/components/header/header.component.sandbox.ts deleted file mode 100644 index 37e4e3d4e..000000000 --- a/apps/scully-docs/src/app/components/header/header.component.sandbox.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { sandboxOf } from 'angular-playground'; -import { HeaderComponent } from './header.component'; - -export default sandboxOf(HeaderComponent).add('default', { - template: `` -}); diff --git a/apps/scully-docs/src/app/components/header/header.component.spec.ts b/apps/scully-docs/src/app/components/header/header.component.spec.ts deleted file mode 100644 index 65e339f66..000000000 --- a/apps/scully-docs/src/app/components/header/header.component.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { HeaderComponent } from './header.component'; - -describe('HeaderComponent', () => { - let component: HeaderComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [HeaderComponent] - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(HeaderComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/apps/scully-docs/src/app/components/header/header.component.ts b/apps/scully-docs/src/app/components/header/header.component.ts deleted file mode 100644 index 22320531d..000000000 --- a/apps/scully-docs/src/app/components/header/header.component.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Component, Input } from '@angular/core'; - -@Component({ - selector: 'app-header', - template: ` -

{{ title }}

- ` -}) -export class HeaderComponent { - @Input() title: string; -} diff --git a/apps/scully-docs/src/app/components/header/header.module.ts b/apps/scully-docs/src/app/components/header/header.module.ts new file mode 100644 index 000000000..7035eec87 --- /dev/null +++ b/apps/scully-docs/src/app/components/header/header.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { RouterModule } from '@angular/router'; + +import { NavHeaderComponent } from './component/nav-header/nav-header.component'; + +@NgModule({ + declarations: [NavHeaderComponent], + exports: [NavHeaderComponent], + imports: [CommonModule, RouterModule], +}) +export class HeaderModule {} diff --git a/apps/scully-docs/src/app/components/header/index.ts b/apps/scully-docs/src/app/components/header/index.ts new file mode 100644 index 000000000..b9af6ea04 --- /dev/null +++ b/apps/scully-docs/src/app/components/header/index.ts @@ -0,0 +1 @@ +export * from './header.module'; diff --git a/apps/scully-docs/src/app/components/hr/hr.component.sandbox.ts b/apps/scully-docs/src/app/components/hr/hr.component.sandbox.ts deleted file mode 100644 index db28fd057..000000000 --- a/apps/scully-docs/src/app/components/hr/hr.component.sandbox.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { sandboxOf } from 'angular-playground'; -import { HrComponent } from './hr.component'; - -export default sandboxOf(HrComponent).add('default', { - template: `` -}); diff --git a/apps/scully-docs/src/app/components/hr/hr.component.spec.ts b/apps/scully-docs/src/app/components/hr/hr.component.spec.ts deleted file mode 100644 index b8d8aa21d..000000000 --- a/apps/scully-docs/src/app/components/hr/hr.component.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { HrComponent } from './hr.component'; - -describe('HrComponent', () => { - let component: HrComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [HrComponent] - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(HrComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/apps/scully-docs/src/app/components/hr/hr.component.ts b/apps/scully-docs/src/app/components/hr/hr.component.ts deleted file mode 100644 index dd86d242d..000000000 --- a/apps/scully-docs/src/app/components/hr/hr.component.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -@Component({ - selector: 'app-hr', - template: ` -
- ` -}) -export class HrComponent {} diff --git a/apps/scully-docs/src/app/components/icon/icon.component.css b/apps/scully-docs/src/app/components/icon/icon.component.css deleted file mode 100644 index e69de29bb..000000000 diff --git a/apps/scully-docs/src/app/components/icon/icon.component.html b/apps/scully-docs/src/app/components/icon/icon.component.html deleted file mode 100644 index b43cd0174..000000000 --- a/apps/scully-docs/src/app/components/icon/icon.component.html +++ /dev/null @@ -1 +0,0 @@ -

icon works!

diff --git a/apps/scully-docs/src/app/components/icon/icon.component.sandbox.ts b/apps/scully-docs/src/app/components/icon/icon.component.sandbox.ts deleted file mode 100644 index 32d79e5bd..000000000 --- a/apps/scully-docs/src/app/components/icon/icon.component.sandbox.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { sandboxOf } from 'angular-playground'; -import { IconComponent } from './icon.component'; - -export default sandboxOf(IconComponent).add('default', { - template: `` -}); diff --git a/apps/scully-docs/src/app/components/icon/icon.component.spec.ts b/apps/scully-docs/src/app/components/icon/icon.component.spec.ts deleted file mode 100644 index 727fb2469..000000000 --- a/apps/scully-docs/src/app/components/icon/icon.component.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { IconComponent } from './icon.component'; - -describe('IconComponent', () => { - let component: IconComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [IconComponent] - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(IconComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/apps/scully-docs/src/app/components/icon/icon.component.ts b/apps/scully-docs/src/app/components/icon/icon.component.ts deleted file mode 100644 index f62870a21..000000000 --- a/apps/scully-docs/src/app/components/icon/icon.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -@Component({ - selector: 'app-icon', - templateUrl: './icon.component.html', - styleUrls: ['./icon.component.css'] -}) -export class IconComponent implements OnInit { - constructor() {} - - ngOnInit(): void {} -} diff --git a/apps/scully-docs/src/app/components/lang-select/component/lang-select/lang-select.component.css b/apps/scully-docs/src/app/components/lang-select/component/lang-select/lang-select.component.css new file mode 100644 index 000000000..56ac1d694 --- /dev/null +++ b/apps/scully-docs/src/app/components/lang-select/component/lang-select/lang-select.component.css @@ -0,0 +1,156 @@ +.scullyio-lang-select { + position: relative; + display: flex; + justify-content: flex-start; + margin: 0 6px 6px; +} + +.scullyio-lang-select label.select { + position: relative; + display: flex; + padding: 8px 14px; + padding-right: 48px; + color: rgba(0, 0, 0, 0.7); + font-size: 12px; + font-weight: 900; + text-transform: uppercase; + letter-spacing: 1px; + border-radius: 4px; + box-shadow: 0 0 1px 1px rgba(0, 0, 0, 0.1); + background: #fff; + cursor: pointer; + transition: color var(--scully-transition-ease), box-shadow var(--scully-transition-ease); + user-select: none; +} +.scullyio-lang-select label.select:hover { + color: rgba(0, 0, 0, 0.94); + box-shadow: 0 0 0 2px var(--scully-green); +} +.scullyio-lang-select label.select:active { + transform: translateY(1px); +} + +.scullyio-lang-select label.select:after { + content: ''; + display: block; + position: absolute; + top: 50%; + right: 12px; + width: 10px; + height: 10px; + transform: translateY(-50%) rotate(90deg); + background: url('/assets/img/icons/chevron-right-solid.svg') center no-repeat; + background-position: cover; + transition: transform var(--scully-transition-ease), opacity var(--scully-transition-ease); + opacity: 0.5; +} +.scullyio-lang-select label.select:hover:after { + opacity: 0.9; +} +.scullyio-lang-select input[type='checkbox']:checked + label.select:after { + transform: translateY(-50%) rotate(-90deg); +} + +.scullyio-lang-select input[type='checkbox'] { + position: absolute; + opacity: 0; +} + +.scullyio-lang-select .lang-select-options { + position: absolute; + display: none; + flex-direction: column; + bottom: -6px; + left: 0; + padding: 8px 0; + border-radius: 4px; + box-shadow: 0 0 1px 1px rgba(0, 0, 0, 0.1); + background: #fff; + transform: translateY(100%); + animation: openLangSelect 160ms ease-out; + overflow: visible; + z-index: 99999; +} + +.scullyio-lang-select input[type='checkbox']:checked ~ .lang-select-options { + display: flex; +} + +.scullyio-lang-select .lang-select-options a { + position: relative; + display: block; + padding: 8px 40px; + padding-right: 70px; + color: var(--scully-black); + font-size: 13px; + font-weight: 700; + user-select: none; + opacity: 0.8; +} +.scullyio-lang-select .lang-select-options a:hover:not(.active):not(.unavailable) { + background: rgba(0, 0, 0, 0.05); + opacity: 1; +} + +.scullyio-lang-select .lang-select-options a.active { + color: var(--scully-green); + font-weight: 900; + opacity: 1; + cursor: default; +} +.scullyio-lang-select .lang-select-options a:active:not(.active) { + transform: translateY(1px); +} + +.scullyio-lang-select .lang-select-options a.active:before { + content: ''; + position: absolute; + top: 50%; + left: 0; + width: 12px; + height: 12px; + margin-left: 16px; + transform: translateY(-50%); + background: url('/assets/img/icons/check-solid.svg') center no-repeat; + background-position: cover; + transition: transform var(--scully-transition-ease), opacity var(--scully-transition-ease); + filter: var(--scully-green-filter); +} +.scullyio-lang-select .lang-select-options a:hover:not(.active):before { + filter: var(--scully-white-filter); +} + +.scullyio-lang-select .lang-select-options a.unavailable { + opacity: 0.54; +} +.scullyio-lang-select .lang-select-options a.unavailable:hover { + opacity: 0.74; + background: rgba(0, 0, 0, 0.07); +} + +.scullyio-lang-select .lang-select-options a.unavailable:after { + content: ''; + display: block; + position: absolute; + top: 50%; + right: 0; + width: 16px; + height: 100%; + padding: 0 22px; + transform: translateY(-50%); + background: url('/assets/img/icons/file-exclamation-regular.svg') center 8px no-repeat; + background-position: cover; + background-size: 12px; + transition: transform var(--scully-transition-ease), opacity var(--scully-transition-ease); +} + +@keyframes openLangSelect { + 0% { + opacity: 0.9; + transform: translateY(calc(100% - 6px)); + } + 100% { + opacity: 1; + transform: translateY(100%); + } +} diff --git a/apps/scully-docs/src/app/components/lang-select/component/lang-select/lang-select.component.spec.ts b/apps/scully-docs/src/app/components/lang-select/component/lang-select/lang-select.component.spec.ts new file mode 100644 index 000000000..f08038172 --- /dev/null +++ b/apps/scully-docs/src/app/components/lang-select/component/lang-select/lang-select.component.spec.ts @@ -0,0 +1,24 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LangSelectComponent } from './lang-select.component'; + +describe('LangSelectComponent', () => { + let component: LangSelectComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [LangSelectComponent], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(LangSelectComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/apps/scully-docs/src/app/components/lang-select/component/lang-select/lang-select.component.ts b/apps/scully-docs/src/app/components/lang-select/component/lang-select/lang-select.component.ts new file mode 100644 index 000000000..7e8d249ab --- /dev/null +++ b/apps/scully-docs/src/app/components/lang-select/component/lang-select/lang-select.component.ts @@ -0,0 +1,31 @@ +import { Component, ViewEncapsulation } from '@angular/core'; +import { Observable } from 'rxjs'; +import { LangSelectService } from '../../services'; +import { CurrentPageLanguageData } from '../../models'; + +@Component({ + selector: '.scullyio-lang-select', + encapsulation: ViewEncapsulation.None, + template: ` + + + + + + + `, +}) +export class LangSelectComponent { + langDefaults = this.langSelectService.langDefaults; + currentPageLangData$: Observable = this.langSelectService.currentPageLangData$; + + constructor(private langSelectService: LangSelectService) {} +} diff --git a/apps/scully-docs/src/app/components/lang-select/index.ts b/apps/scully-docs/src/app/components/lang-select/index.ts new file mode 100644 index 000000000..695ea2db5 --- /dev/null +++ b/apps/scully-docs/src/app/components/lang-select/index.ts @@ -0,0 +1 @@ +export * from './lang-select.module'; diff --git a/apps/scully-docs/src/app/components/lang-select/lang-select.module.ts b/apps/scully-docs/src/app/components/lang-select/lang-select.module.ts new file mode 100644 index 000000000..90f38d02e --- /dev/null +++ b/apps/scully-docs/src/app/components/lang-select/lang-select.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { RouterModule } from '@angular/router'; + +import { LangSelectComponent } from './component/lang-select/lang-select.component'; + +@NgModule({ + declarations: [LangSelectComponent], + exports: [LangSelectComponent], + imports: [CommonModule, RouterModule], +}) +export class LangSelectModule {} diff --git a/apps/scully-docs/src/app/components/lang-select/models/index.ts b/apps/scully-docs/src/app/components/lang-select/models/index.ts new file mode 100644 index 000000000..db16124bd --- /dev/null +++ b/apps/scully-docs/src/app/components/lang-select/models/index.ts @@ -0,0 +1 @@ +export * from './lang-select'; diff --git a/apps/scully-docs/src/app/components/lang-select/models/lang-select.ts b/apps/scully-docs/src/app/components/lang-select/models/lang-select.ts new file mode 100644 index 000000000..a82ccf65e --- /dev/null +++ b/apps/scully-docs/src/app/components/lang-select/models/lang-select.ts @@ -0,0 +1,32 @@ +/** Array of language abbreviations collected from available routes */ +export type AllLanguages = string[]; + +/** Values to substitute for given page language */ +export interface LanguageDefaults { + labels: { [key: string]: string }; + routes: { [key: string]: string }; +} + +/** Alternate routes for other languages of a given page */ +export interface PageLanguages { + [key: string]: string; +} + +/** Observable object holding keys of PageLanguages */ +export interface PageLanguageData { + [key: string]: PageLanguages; +} + +/** Clarity for template variables */ +export interface PageLangRoutes { + lang: string; + route: string; +} + +/** Consumed by template */ +export interface CurrentPageLanguageData { + allLangs: string[]; + langRoutes?: PageLanguages; + pageLang: string; + pageLangRoutes: PageLangRoutes[]; +} diff --git a/apps/scully-docs/src/app/components/lang-select/services/index.ts b/apps/scully-docs/src/app/components/lang-select/services/index.ts new file mode 100644 index 000000000..66c1f9836 --- /dev/null +++ b/apps/scully-docs/src/app/components/lang-select/services/index.ts @@ -0,0 +1 @@ +export * from './lang-select/lang-select.service'; diff --git a/apps/scully-docs/src/app/components/lang-select/services/lang-select/lang-select.service.spec.ts b/apps/scully-docs/src/app/components/lang-select/services/lang-select/lang-select.service.spec.ts new file mode 100644 index 000000000..65120ffd1 --- /dev/null +++ b/apps/scully-docs/src/app/components/lang-select/services/lang-select/lang-select.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { LangSelectService } from './lang-select.service'; + +describe('LangSelectService', () => { + let service: LangSelectService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(LangSelectService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/apps/scully-docs/src/app/components/lang-select/services/lang-select/lang-select.service.ts b/apps/scully-docs/src/app/components/lang-select/services/lang-select/lang-select.service.ts new file mode 100644 index 000000000..369627817 --- /dev/null +++ b/apps/scully-docs/src/app/components/lang-select/services/lang-select/lang-select.service.ts @@ -0,0 +1,144 @@ +import { Injectable } from '@angular/core'; +import { Observable, forkJoin } from 'rxjs'; +import { map, take } from 'rxjs/operators'; +import { ScullyRoute, ScullyRoutesService } from '@scullyio/ng-lib'; +import { AllLanguages, CurrentPageLanguageData, LanguageDefaults, PageLanguageData } from '../../models'; +import { NavUtilService } from '../../../nav-list/services/nav-util'; + +@Injectable({ providedIn: 'root' }) +export class LangSelectService { + public langDefaults: LanguageDefaults = { + labels: { + en: 'English', + es: 'Español', + }, + routes: { + en: '/docs/learn/introduction', + es: '/docs/learn/introduction_es', + }, + }; + + /** + * Find counterpart languages for each route + */ + private pageLangs$: Observable = this.scully.available$.pipe( + map((availableRoutes: ScullyRoute[]) => { + // add stripped, array version of routes + const postsArray = this.util.simplifyRootRoutes(availableRoutes); + // find counterpart languages for each route + const pageLanguages = this.createNavListLanguages(postsArray); + return pageLanguages; + }) + ); + + /** + * All available language abbreviations, derived from available page languages. + */ + private allLanguages$: Observable = this.scully.available$.pipe( + map((availablePosts: ScullyRoute[]) => { + // make collection of available language abbreviations from page list + const availableLangs = {}; + for (const post of availablePosts) { + if (post.lang && !availableLangs[post.lang]) { + availableLangs[post.lang] = true; + } + } + const alllanguages = Object.keys(availableLangs).map((key) => key); + return alllanguages; + }) + ); + + /** + * Compiled current data to use in lang-select template. + */ + public currentPageLangData$: Observable = forkJoin( + this.pageLangs$.pipe(take(1)), + this.allLanguages$.pipe(take(1)), + this.scully.getCurrent().pipe(take(1)) + ).pipe( + map(([pageLangs, langs, currentPage]) => { + const routeLangs: CurrentPageLanguageData = { + allLangs: [], + langRoutes: {}, + pageLang: 'en', + pageLangRoutes: null, + }; + // populate routeLangs with relevant data + const currentRouteLangData = pageLangs[currentPage.route]; + for (const lang of langs) { + if (currentRouteLangData[lang]) { + routeLangs.langRoutes = pageLangs[currentPage.route]; + } + } + routeLangs.pageLang = currentPage.lang; + routeLangs.allLangs = langs; + // determine which route to use for select option: given or a default + routeLangs.pageLangRoutes = langs.map((lang) => ({ + lang, + route: this.getLangRoute(lang, routeLangs), + })); + return routeLangs; + }) + ); + + constructor(private scully: ScullyRoutesService, private util: NavUtilService) {} + + /** + * Finds all the language "versions" of a page and constructs a list + * indicating alternative language routes for each specific page. + * + * @param scullyRoutes Array of ScullyRoutes to assess. + */ + private createNavListLanguages(scullyRoutes: ScullyRoute[]): PageLanguageData { + const langs = {}; + for (const page of scullyRoutes) { + const itemLangs = {}; + const affectedRoutes = []; + // check if page has any counterparts of another language and + // collect alternate language page routes to include in all affected pages + for (const pageCompareItem of scullyRoutes) { + if (pageCompareItem?.route !== page.route && pageCompareItem?.route?.includes(page.route)) { + // add language routes to root route identifier object's languages + itemLangs[page.lang] = page.route; + itemLangs[pageCompareItem.lang] = pageCompareItem.route; + // add routes to list of affected items, to later include all languages with + affectedRoutes.push(page.route, pageCompareItem.route); + } + } + // flatten array and store language route group to apply to all routes later + const affectedRoutesUnique = [...new Set(affectedRoutes)]; + for (const route of affectedRoutesUnique) { + langs[route] = itemLangs; + } + } + // create link for each link regardless of if it has another lanugage counterpart + const pageAvailableLangs = {}; + for (const itemPage of scullyRoutes) { + // if language route group is empty, use only page route for availableLangs + // otherwise use collected sibling/counterpart lang routes + const availableLangs = langs[itemPage.route] ? langs[itemPage.route] : { [itemPage.lang]: itemPage.route }; + pageAvailableLangs[itemPage.route] = availableLangs; + } + return pageAvailableLangs; + } + + /** + * Determines which route to use for a given language link. + * + * @param lang Available language abbreviation. + * @param langData Compiled data to determine lang-select state + */ + getLangRoute(lang: string, langData: CurrentPageLanguageData): string { + switch (true) { + // if page exists in given lang, use that oage's route + case !!langData.langRoutes[lang]: + return langData.langRoutes[lang]; + // if page doesn't exist in given lang, but has a default route, use default route + case !!this.langDefaults.routes[lang]: + return this.langDefaults.routes[lang]; + // if page langData doesn't fit above criteria, default to default English ('en') route + default: + return this.langDefaults.routes['en']; + } + } +} diff --git a/apps/scully-docs/src/app/components/left-menu/left-menu.component.css b/apps/scully-docs/src/app/components/left-menu/left-menu.component.css deleted file mode 100644 index 4c79e9b87..000000000 --- a/apps/scully-docs/src/app/components/left-menu/left-menu.component.css +++ /dev/null @@ -1,34 +0,0 @@ -:host { - display: block; - background: var(--scully-green-wash); - height: 100%; - padding-top: 2rem; -} - -li { - padding-top: 1rem; - padding-left: 70px; - list-style: none; -} - -li.active { - padding-left: 50px; -} - -li.active:before { - content: ''; - display: inline-block; - position: relative; - height: 20px; - width: 20px; - margin-right: 20px; - left: -50px; - background-image: url(/assets/green-bullet.png); - background-repeat: no-repeat; - background-position: left; -} - -a { - text-decoration: none; - color: var(--scully-darkgray); -} diff --git a/apps/scully-docs/src/app/components/left-menu/left-menu.component.html b/apps/scully-docs/src/app/components/left-menu/left-menu.component.html deleted file mode 100644 index 35917b24c..000000000 --- a/apps/scully-docs/src/app/components/left-menu/left-menu.component.html +++ /dev/null @@ -1,19 +0,0 @@ - - diff --git a/apps/scully-docs/src/app/components/left-menu/left-menu.component.sandbox.ts b/apps/scully-docs/src/app/components/left-menu/left-menu.component.sandbox.ts deleted file mode 100644 index 4c3334702..000000000 --- a/apps/scully-docs/src/app/components/left-menu/left-menu.component.sandbox.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { sandboxOf } from 'angular-playground'; -import { LeftMenuComponent } from './left-menu.component'; - -// tslint:disable-next-line:variable-name -const _list = [ - { - title: 'getting Started', - list: [ - { title: 'Prerequisites', url: '/getting-started/prerequisites' }, - { title: 'Instalation', url: '/getting-started/instalation' }, - { title: 'Setup', url: '/getting-started/setup' } - ] - }, - { title: 'Tutorial', url: '/tutorial' }, - { title: 'Command Line', url: '/command-line' } -]; - -export default sandboxOf(LeftMenuComponent).add('default', { - template: ``, - context: { - list: _list - } -}); diff --git a/apps/scully-docs/src/app/components/left-menu/left-menu.component.spec.ts b/apps/scully-docs/src/app/components/left-menu/left-menu.component.spec.ts deleted file mode 100644 index 63f9e7909..000000000 --- a/apps/scully-docs/src/app/components/left-menu/left-menu.component.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { LeftMenuComponent } from './left-menu.component'; - -describe('LeftMenuComponent', () => { - let component: LeftMenuComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [LeftMenuComponent] - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(LeftMenuComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/apps/scully-docs/src/app/components/left-menu/left-menu.component.ts b/apps/scully-docs/src/app/components/left-menu/left-menu.component.ts deleted file mode 100644 index a13228b2d..000000000 --- a/apps/scully-docs/src/app/components/left-menu/left-menu.component.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Component, Input } from '@angular/core'; - -@Component({ - selector: 'app-left-menu', - templateUrl: './left-menu.component.html', - styleUrls: ['./left-menu.component.css'], -}) -export class LeftMenuComponent { - @Input() set list(_list: any[]) { - if (Array.isArray(_list)) { - this.fullList.push(..._list); - } - - this.changeLang(); - } - @Input() first = true; - url: string; - lang = 'en'; - showList = []; - private fullList = []; - - changeLang() { - this.showList = []; - if (this.fullList) { - this.fullList.forEach((post) => { - if (post && post.lang === this.lang) { - this.showList.push(post); - } - }); - } - } -} diff --git a/apps/scully-docs/src/app/components/marketing-header/marketing-header.component.sandbox.ts b/apps/scully-docs/src/app/components/marketing-header/marketing-header.component.sandbox.ts deleted file mode 100644 index 69700fdef..000000000 --- a/apps/scully-docs/src/app/components/marketing-header/marketing-header.component.sandbox.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { sandboxOf } from 'angular-playground'; -import { MarketingHeaderComponent } from './marketing-header.component'; - -export default sandboxOf(MarketingHeaderComponent).add('default', { - template: `` -}); diff --git a/apps/scully-docs/src/app/components/marketing-header/marketing-header.component.spec.ts b/apps/scully-docs/src/app/components/marketing-header/marketing-header.component.spec.ts deleted file mode 100644 index 483384d4e..000000000 --- a/apps/scully-docs/src/app/components/marketing-header/marketing-header.component.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { MarketingHeaderComponent } from './marketing-header.component'; - -describe('MarketingHeaderComponent', () => { - let component: MarketingHeaderComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [MarketingHeaderComponent] - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(MarketingHeaderComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/apps/scully-docs/src/app/components/marketing-header/marketing-header.component.ts b/apps/scully-docs/src/app/components/marketing-header/marketing-header.component.ts deleted file mode 100644 index 5f8ef0370..000000000 --- a/apps/scully-docs/src/app/components/marketing-header/marketing-header.component.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Component, Input } from '@angular/core'; - -@Component({ - selector: 'app-marketing-header', - template: ` -

{{ text }}

- ` -}) -export class MarketingHeaderComponent { - @Input() text: string; -} diff --git a/apps/scully-docs/src/app/components/nav-list/components/child-list/child-list.component.css b/apps/scully-docs/src/app/components/nav-list/components/child-list/child-list.component.css new file mode 100644 index 000000000..6bf9efb90 --- /dev/null +++ b/apps/scully-docs/src/app/components/nav-list/components/child-list/child-list.component.css @@ -0,0 +1,219 @@ +li.scullyio-nav-child-list { + --transition-ease: 80ms ease; + list-style: none; + position: relative; + display: flex; + flex-direction: column; +} + +li.scullyio-nav-child-list a { + position: relative; + display: block; + padding-left: var(--offset-left); + color: rgba(0, 0, 0, 0.6); + font-weight: 700; + text-align: left; + user-select: none; +} +li.scullyio-nav-child-list a:hover { + color: rgba(0, 0, 0, 1); +} +li.scullyio-nav-child-list a:active { + transform: translateY(1px); +} + +li.scullyio-nav-child-list a.active { + color: var(--scully-green); + font-weight: 900; + transition: color var(--scully-transition-ease); +} +li.scullyio-nav-child-list a.active span.parent:after { + transform: translate(-50%) scale(0); +} + +li.scullyio-nav-child-list a.heading { + padding: 24px; + padding-left: 54px; + font-size: 12px; + font-weight: 800; + letter-spacing: 16%; + text-transform: uppercase; + letter-spacing: 1px; +} + +li.scullyio-nav-child-list a span { + position: relative; +} +li.scullyio-nav-child-list a span:after { + content: ''; + position: absolute; + top: 50%; + left: 0; + width: 6px; + height: 6px; + margin-left: -31px; + border-radius: 50%; + transform: translateY(-50%) scale(0); + background: var(--scully-green); + transition: transform var(--scully-transition-ease), opacity var(--scully-transition-ease); + opacity: 0; +} +li.scullyio-nav-child-list a span.parent:after { + display: none; +} + +li.scullyio-nav-child-list a.active span:after { + transform: translateY(-50%) scale(1); + opacity: 1; +} + +li.scullyio-nav-child-list .no-route-link { + position: relative; + display: block; + padding-left: var(--offset-left); + color: rgba(0, 0, 0, 0.6); + font-weight: 700; + text-align: left; + user-select: none; +} +li.scullyio-nav-child-list .no-route-link:hover { + color: rgba(0, 0, 0, 1); +} + +li.scullyio-nav-child-list .no-route-link.active { + color: var(--scully-green); + font-weight: 900; + transition: color var(--scully-transition-ease); +} + +li.scullyio-nav-child-list .no-route-link.heading { + padding-left: 11px; + font-size: 12px; + font-weight: 800; + letter-spacing: 16%; + text-transform: uppercase; + letter-spacing: 1px; +} + +li.scullyio-nav-child-list label { + position: absolute; + display: flex; + justify-content: center; + align-items: center; + margin-left: var(--offset-left); + left: calc((-1 * 34px) - 11px); + width: 34px; + height: 34px; + z-index: 9999; +} +li.scullyio-nav-child-list label:active { + transform: translateY(1px); +} + +li.scullyio-nav-child-list label.heading { + margin-top: 15px; + margin-left: calc(var(--offset-left) + 10px); +} + +li.scullyio-nav-child-list label.no-route { + position: relative; + width: 100%; + justify-content: flex-start; + align-items: center; +} + +li.scullyio-nav-child-list label .indicator { + width: 10px; + height: 10px; + background: url('/assets/img/icons/chevron-right-solid.svg') center no-repeat; + transition: transform var(--scully-transition-ease); + opacity: 0.4; +} +li.scullyio-nav-child-list :checked ~ label .indicator { + transform: rotate(90deg); +} +li.scullyio-nav-child-list label:hover .indicator { + opacity: 0.8; +} + +li.scullyio-nav-child-list label.no-route .indicator { + width: 38px; +} + +li.scullyio-nav-child-list label.no-route.heading .indicator { + margin-top: 12px; +} + +li.scullyio-nav-child-list a.active ~ label .indicator { + filter: invert(43%) sepia(96%) saturate(1549%) hue-rotate(110deg) brightness(96%) contrast(79%); + opacity: 1; +} + +li.scullyio-nav-child-list input[type='checkbox'] { + display: none; + position: absolute; + margin-left: var(--offset-left); + left: calc((-1 * 34px) - 11px); +} + +li.scullyio-nav-child-list ul { + display: none; + padding-top: 12px; + padding-bottom: 12px; + box-shadow: inset 0 3px 2px -2px rgba(88, 74, 74, 0.1), inset 0 -2px 2px -2px rgba(0, 0, 0, 0.1); + background: rgba(0, 0, 0, 0.02); + overflow: hidden; + transition: 1s ease; +} +li.scullyio-nav-child-list ul ul { + margin: 0; +} + +li.scullyio-nav-child-list ul a, +li.scullyio-nav-child-list ul .no-route-link { + padding: 8px 24px; + padding-left: var(--offset-left); + font-size: 13px; +} +li.scullyio-nav-child-list ul .no-route-link { + width: 100%; + padding-left: 12px; + color: rgba(0, 0, 0, 0.6); + cursor: pointer; +} +li.scullyio-nav-child-list ul .no-route-link:hover { + color: rgba(0, 0, 0, 1); +} +li.scullyio-nav-child-list ul .no-route-link:active { + transform: none; +} + +li.scullyio-nav-child-list :checked ~ ul { + display: block; + margin-top: 12px; + margin-bottom: 12px; + padding-top: 12px; + padding-bottom: 12px; +} +li.scullyio-nav-child-list :checked ~ ul input[type='checkbox']:checked + ul { + margin: 12px 0; +} + +li.scullyio-nav-child-list .heading + ul { + margin-top: 0; + margin-bottom: 0; +} + +li.scullyio-nav-child-list .heading.no-route { + display: flex; + align-items: stretch; + justify-content: stretch; + margin-bottom: 15px; +} + +li.scullyio-nav-child-list .heading.no-route .no-route-link { + display: flex; + align-items: center; + width: 100%; + cursor: pointer; +} diff --git a/apps/scully-docs/src/app/components/nav-list/components/child-list/child-list.component.spec.ts b/apps/scully-docs/src/app/components/nav-list/components/child-list/child-list.component.spec.ts new file mode 100644 index 000000000..1aac8db05 --- /dev/null +++ b/apps/scully-docs/src/app/components/nav-list/components/child-list/child-list.component.spec.ts @@ -0,0 +1,24 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ChildListComponent } from './child-list.component'; + +describe('ChildListComponent', () => { + let component: ChildListComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ChildListComponent], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ChildListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/apps/scully-docs/src/app/components/nav-list/components/child-list/child-list.component.ts b/apps/scully-docs/src/app/components/nav-list/components/child-list/child-list.component.ts new file mode 100644 index 000000000..4e7626d8d --- /dev/null +++ b/apps/scully-docs/src/app/components/nav-list/components/child-list/child-list.component.ts @@ -0,0 +1,72 @@ +import { Component, ViewEncapsulation, Input, HostBinding } from '@angular/core'; +import { Router } from '@angular/router'; +import { NavListItem } from '../../models'; + +@Component({ + selector: 'li.scullyio-nav-child-list', + encapsulation: ViewEncapsulation.None, + template: ` + + {{ link.linkText }} + + + + + + + + + +
    +
  • +
+
+ `, +}) +export class ChildListComponent { + leftDefault = 32; + leftOffset = 12; + + /** Compiled offset padding of parent components */ + @Input() leftOffsetExisting?: number; + + /** NavListItem and any potential children */ + @Input() link: NavListItem; + + /** Currently only changes .list-item styles */ + @Input() isHeading?: boolean; + + /** Assigns template-consumable offset padding in px to variable */ + @HostBinding('style.--offset-left') get leftOffsetPx(): string { + return `${this.leftPadding}px`; + } + + constructor(public router: Router) {} + + /** Determine if each checkbox should be checked based on the current url and toggleId */ + get isChecked(): boolean { + return !!this.router.url.includes(this.link.toggleId); + } + + /** Returns cumulative offset to indent list item arbitrary steps */ + get leftPadding(): number { + return this.leftOffsetExisting ? this.leftOffset + this.leftOffsetExisting : this.leftOffset + this.leftDefault; + } +} diff --git a/apps/scully-docs/src/app/components/nav-list/components/nav-list/nav-list.component.css b/apps/scully-docs/src/app/components/nav-list/components/nav-list/nav-list.component.css new file mode 100644 index 000000000..f0f8ecb2a --- /dev/null +++ b/apps/scully-docs/src/app/components/nav-list/components/nav-list/nav-list.component.css @@ -0,0 +1,7 @@ +ul.scullyio-nav-list { + width: 340px; + max-height: 100vh; + padding-bottom: 22px; + overflow-y: auto; + overflow-x: hidden; +} diff --git a/apps/scully-docs/src/app/components/button/button.component.spec.ts b/apps/scully-docs/src/app/components/nav-list/components/nav-list/nav-list.component.spec.ts similarity index 56% rename from apps/scully-docs/src/app/components/button/button.component.spec.ts rename to apps/scully-docs/src/app/components/nav-list/components/nav-list/nav-list.component.spec.ts index 4362b91de..11182e3d2 100644 --- a/apps/scully-docs/src/app/components/button/button.component.spec.ts +++ b/apps/scully-docs/src/app/components/nav-list/components/nav-list/nav-list.component.spec.ts @@ -1,19 +1,19 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { ButtonComponent } from './button.component'; +import { NavListComponent } from './nav-list.component'; -describe('ButtonComponent', () => { - let component: ButtonComponent; - let fixture: ComponentFixture; +describe('NavListComponent', () => { + let component: NavListComponent; + let fixture: ComponentFixture; beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ButtonComponent] + declarations: [NavListComponent], }).compileComponents(); })); beforeEach(() => { - fixture = TestBed.createComponent(ButtonComponent); + fixture = TestBed.createComponent(NavListComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/apps/scully-docs/src/app/components/nav-list/components/nav-list/nav-list.component.ts b/apps/scully-docs/src/app/components/nav-list/components/nav-list/nav-list.component.ts new file mode 100644 index 000000000..bed831e42 --- /dev/null +++ b/apps/scully-docs/src/app/components/nav-list/components/nav-list/nav-list.component.ts @@ -0,0 +1,18 @@ +import { Component, ViewEncapsulation } from '@angular/core'; +import { Observable } from 'rxjs'; +import { NavListService } from '../../services'; +import { NavListItem } from '../../models'; + +@Component({ + selector: 'ul.scullyio-nav-list', + encapsulation: ViewEncapsulation.None, + template: ` + +
  • +
    + `, +}) +export class NavListComponent { + docs$: Observable = this.navService.docs$; + constructor(private navService: NavListService) {} +} diff --git a/apps/scully-docs/src/app/components/nav-list/index.ts b/apps/scully-docs/src/app/components/nav-list/index.ts new file mode 100644 index 000000000..9acfa8d88 --- /dev/null +++ b/apps/scully-docs/src/app/components/nav-list/index.ts @@ -0,0 +1 @@ +export * from './nav-list.module'; diff --git a/apps/scully-docs/src/app/components/nav-list/models/index.ts b/apps/scully-docs/src/app/components/nav-list/models/index.ts new file mode 100644 index 000000000..8f253d2c0 --- /dev/null +++ b/apps/scully-docs/src/app/components/nav-list/models/index.ts @@ -0,0 +1 @@ +export * from './nav-list'; diff --git a/apps/scully-docs/src/app/components/nav-list/models/nav-list.ts b/apps/scully-docs/src/app/components/nav-list/models/nav-list.ts new file mode 100644 index 000000000..447e6701f --- /dev/null +++ b/apps/scully-docs/src/app/components/nav-list/models/nav-list.ts @@ -0,0 +1,34 @@ +/** Available formatting options for nav link text */ +export interface NavTextFormats { + none?: boolean; + capitalize?: boolean; + capitalizeFirstLetter?: boolean; +} + +/** Page options, converted from .md file header */ +export interface NavHierarchyItem { + linkText: string; + route?: string; + lang?: string; + position?: number; + parentIndex?: boolean; + parentPosition?: number; + excludeSelf?: boolean; + textFormats?: NavTextFormats; + [key: string]: any; +} + +/** Object hierarchy of nav items, later to be converted to NavListItem[] */ +export interface NavHierarchy { + [key: string]: NavHierarchyItem; +} + +/** Consumed by template. */ +export interface NavListItem { + linkText: string; + route?: string; + position?: number; + children?: NavListItem[]; + toggleId?: string; + lang?: string; +} diff --git a/apps/scully-docs/src/app/components/nav-list/nav-list.module.ts b/apps/scully-docs/src/app/components/nav-list/nav-list.module.ts new file mode 100644 index 000000000..fb80bbeb8 --- /dev/null +++ b/apps/scully-docs/src/app/components/nav-list/nav-list.module.ts @@ -0,0 +1,13 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { RouterModule } from '@angular/router'; + +import { NavListComponent } from './components/nav-list/nav-list.component'; +import { ChildListComponent } from './components/child-list/child-list.component'; + +@NgModule({ + declarations: [NavListComponent, ChildListComponent], + exports: [NavListComponent], + imports: [CommonModule, RouterModule], +}) +export class NavListModule {} diff --git a/apps/scully-docs/src/app/components/nav-list/services/index.ts b/apps/scully-docs/src/app/components/nav-list/services/index.ts new file mode 100644 index 000000000..8f253d2c0 --- /dev/null +++ b/apps/scully-docs/src/app/components/nav-list/services/index.ts @@ -0,0 +1 @@ +export * from './nav-list'; diff --git a/apps/scully-docs/src/app/components/nav-list/services/nav-list/index.ts b/apps/scully-docs/src/app/components/nav-list/services/nav-list/index.ts new file mode 100644 index 000000000..0899299d2 --- /dev/null +++ b/apps/scully-docs/src/app/components/nav-list/services/nav-list/index.ts @@ -0,0 +1 @@ +export * from './nav-list.service'; diff --git a/apps/scully-docs/src/app/components/nav-list/services/nav-list/nav-list.service.spec.ts b/apps/scully-docs/src/app/components/nav-list/services/nav-list/nav-list.service.spec.ts new file mode 100644 index 000000000..3231cd907 --- /dev/null +++ b/apps/scully-docs/src/app/components/nav-list/services/nav-list/nav-list.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { NavListService } from './nav-list.service'; + +describe('NavListService', () => { + let service: NavListService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(NavListService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/apps/scully-docs/src/app/components/nav-list/services/nav-list/nav-list.service.ts b/apps/scully-docs/src/app/components/nav-list/services/nav-list/nav-list.service.ts new file mode 100644 index 000000000..2bcef9ecf --- /dev/null +++ b/apps/scully-docs/src/app/components/nav-list/services/nav-list/nav-list.service.ts @@ -0,0 +1,199 @@ +import { Injectable } from '@angular/core'; +import { Observable, forkJoin } from 'rxjs'; +import { map, take } from 'rxjs/operators'; +import { ScullyRoute, ScullyRoutesService } from '@scullyio/ng-lib'; +import { NavHierarchy, NavListItem } from '../../models'; +import { NavUtilService } from '../nav-util'; + +@Injectable({ providedIn: 'root' }) +export class NavListService { + /** + * Template-consumable list of available pages filtered by language. + */ + public docs$: Observable = forkJoin( + this.scully.available$.pipe(take(1)), + this.scully.getCurrent().pipe(take(1)) + ).pipe( + map(([availablePosts, currentPage]) => { + // console.log('availablePosts: ', availablePosts); // TODO: possible scully bug: overwrites page with same name but different directories + // add stripped, array version of routes + const postsArray = this.util.simplifyRootRoutes(availablePosts); + // filter by current page's language + const langFilteredPosts = this.util.filterPostsByLang(postsArray, currentPage.lang); + // convert post objects and route arrays into hierarchical object + const navListHierarchy = this.createNavListHierarchy(langFilteredPosts); + // convert navListHierarchy object into an array of objects with arrays in them + const navList = this.createNavList(navListHierarchy); + return navList; + }) + ); + + constructor(private scully: ScullyRoutesService, private util: NavUtilService) {} + + /** + * Converts ScullyRoute[] array into NavHierarchy object. + * + * @param postsArray ScullyRoute[] with simplified route paths. + */ + private createNavListHierarchy(postsArray: ScullyRoute[]): NavHierarchy { + let navList: NavHierarchy = {}; + for (const post of postsArray) { + // convert generated string to JSON object + const navListObj = this.createNavListItem(post); + // merge all objects together into one, maintaing original hierarchy + navList = this.util.deepMergeObjects(navList, navListObj); + } + return navList; + } + + /** + * Converts NavHierarchy object into NavListItem[] array for docs$ Observable. + * + * @param navHierarchy NavHierarchy created by createNavListHierarchy(). + */ + private createNavList(navHierarchy: NavHierarchy): NavListItem[] { + const navListItem: NavListItem[] = []; + // identifier of last nav item in chain, `route` is unique to the last item. + // there may be a better way to identify this, but it's currently a reliable identifier. + if (!navHierarchy.linkText) { + for (const item of Object.keys(navHierarchy)) { + const navItem = this.defineNavItemProperties(item, navHierarchy); + // if not explicitly excluded, add compiled items to returned array + if (!navHierarchy[item].excludeSelf) { + navListItem.push(navItem); + } + } + } + // sort by `navlist_position`, null values positioned last + navListItem.sort((a, b) => this.util.sortNavItems(a, b)); + return navListItem; + } + + /** + * Creates a NavHierarchy by recursively assessing if a given route + * represents an actual link, or just a parent directory heading. + * + * @param post ScullyRoute with simplified route paths. + */ + private createNavListItem(post: ScullyRoute): NavHierarchy { + // if not explicitly defined, current item name is last item of routeArrayB + const currentItemName = post.navlist_linkText ? post.navlist_linkText : post.routeArray[post.routeArray.length - 1]; + // array needs to be reversed to reverse traverse correctly + const routeArrayReverse = post.routeArray.reverse(); + // ------------------------------ + // define recursive string handler so we can JSON.parse it within this function + const createString = (postB: ScullyRoute, routeArray: string[]): string => { + // index of where to slice routeArray when recursively calling createNavListItem() again + const lastParentIndex = routeArray.length - 1; + // returned string in shape of NavHierarchyItem + const objString = !routeArray.length + ? // current navListItem is a route / has a link + `{ + "linkText": "${currentItemName}" + ,"route": "${postB.route}" + ${postB.lang ? ',"lang": "' + postB.lang + '"' : ''} + ${postB.navlist_position ? ',"position": ' + parseInt(postB.navlist_position, 0) : ''} + ${postB.navlist_parentIndex ? ',"parentIndex": ' + postB.navlist_parentIndex : ''} + ${postB.navlist_parentLinkText ? ',"parentLinkText": "' + postB.navlist_parentLinkText + '"' : ''} + ${postB.navlist_parentPosition ? ',"parentPosition": ' + postB.navlist_parentPosition : ''} + ${postB.navlist_excludeSelf ? ',"excludeSelf": ' + postB.navlist_excludeSelf : ''} + ${this.util.isNavListTextFormatType(post) ? ',"textFormats": ' + this.util.navListTextFormats(postB) : ''} + }` + : // current navListItem is a parent heading + `{ + "${routeArray[lastParentIndex]}": ${createString(postB, routeArray.slice(0, lastParentIndex))} + }`; + return objString; + }; + // ------------------------------ + // convert generated string to object + const navListParsed: NavHierarchy = JSON.parse(createString(post, routeArrayReverse)); + return navListParsed; + } + + /** + * Creates NavListItem to be added to NavListItem[] array + * returned by docs$ Observable. + * Populates each item with individual template-consumable + * parameters defined in each .md file. + * + * @param item Item name derived from NavHierarchy keys. + * @param navHierarchy NavHierarchy itself returned from createNavListHierarchy() + */ + private defineNavItemProperties(item: string, navHierarchy: NavHierarchy): NavListItem { + const hierarchyItem = navHierarchy[item]; + let navItem: NavListItem; + // ------------------------------ + // -- Link Text + // use existing `linkText` if available, otherwise create string from item name / route + const linkText = hierarchyItem.linkText ? hierarchyItem.linkText : item; + // initialize simplest NavListItem structure based on current item + navItem = { linkText: this.util.formatLinkText(linkText, hierarchyItem.textFormats) }; + // ------------------------------ + // -- Position + // only include position if current object has `position` property + if (hierarchyItem.position) { + navItem = { position: hierarchyItem.position, ...navItem }; + } + // ------------------------------ + // -- Routes + // only include route if current object has `route` property + if (hierarchyItem.route) { + navItem = { route: hierarchyItem.route, ...navItem }; + } + // ------------------------------ + // -- Language + // only include language if current object has `lang` property + if (hierarchyItem.lang) { + navItem = { lang: hierarchyItem.lang, ...navItem }; + } + // ------------------------------ + // -- Parent Directory Parameters + // current assessed item is not a page, but a directory, + // known because directories don't have their own linkText + if (!hierarchyItem.linkText) { + for (const child of Object.keys(hierarchyItem)) { + const childKeys = Object.keys(hierarchyItem[child]); + // ------------------------------ + // -- Parent Index + // child route is acting as the index route for this directory + if (childKeys.includes('parentIndex')) { + navItem = { route: hierarchyItem[child].route, ...navItem }; + navItem.lang = hierarchyItem[child].lang; + // ------------------------------ + // -- Link Text + // child route determines linkText for this directory + if (childKeys.includes('parentLinkText')) { + navItem.linkText = hierarchyItem[child].parentLinkText; + } + // ------------------------------ + // -- Position + // child route determines position for this directory + if (childKeys.includes('parentPosition')) { + navItem = { position: hierarchyItem[child].parentPosition, ...navItem }; + } + } + } + } + // ------------------------------ + // -- Children + // only include extra properties if item has children + if (Object.keys(navHierarchy).length) { + const navList = this.createNavList(hierarchyItem); + // generate id to compare against window.location.pathName to + // determine if child nav items should be visible on page load + const toggleId = navItem.route + ? navItem.route.split('/').slice(0, -1).join('/') + : navList[0].route.split('/').slice(0, -1).join('/'); + // add children and toggleId to navList + navItem = navList.length + ? { + ...navItem, + children: navList, + toggleId, + } + : navItem; + } + return navItem; + } +} diff --git a/apps/scully-docs/src/app/components/nav-list/services/nav-util/index.ts b/apps/scully-docs/src/app/components/nav-list/services/nav-util/index.ts new file mode 100644 index 000000000..777d19e61 --- /dev/null +++ b/apps/scully-docs/src/app/components/nav-list/services/nav-util/index.ts @@ -0,0 +1 @@ +export * from './nav-util.service'; diff --git a/apps/scully-docs/src/app/components/nav-list/services/nav-util/nav-util.service.spec.ts b/apps/scully-docs/src/app/components/nav-list/services/nav-util/nav-util.service.spec.ts new file mode 100644 index 000000000..12e86da74 --- /dev/null +++ b/apps/scully-docs/src/app/components/nav-list/services/nav-util/nav-util.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { NavUtilService } from './nav-util.service'; + +describe('NavUtilService', () => { + let service: NavUtilService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(NavUtilService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/apps/scully-docs/src/app/components/nav-list/services/nav-util/nav-util.service.ts b/apps/scully-docs/src/app/components/nav-list/services/nav-util/nav-util.service.ts new file mode 100644 index 000000000..86a858953 --- /dev/null +++ b/apps/scully-docs/src/app/components/nav-list/services/nav-util/nav-util.service.ts @@ -0,0 +1,160 @@ +import { Injectable } from '@angular/core'; +import { ScullyRoute } from '@scullyio/ng-lib'; +import { NavHierarchy, NavListItem, NavTextFormats } from '../../models'; + +@Injectable({ providedIn: 'root' }) +export class NavUtilService { + /** + * Remove redundant route paths from scully.available$ + * and return simplified, array version of each path. + * + * @param availablePosts ScullyRoute[] directly from scully.available$ + */ + public simplifyRootRoutes(availablePosts: ScullyRoute[]): ScullyRoute[] { + return availablePosts + .map((post) => { + // remove default path /docs/ to accommodate scully's need + // for a dedicated route to display rendered md files. + const routeArray = post.route.split('/'); + routeArray.splice(0, 2); + // combine with existing post data + if (routeArray.length > 0) { + return { ...post, routeArray }; + } + // only include path after /docs/ + }) + .filter((post) => !!post); + } + + /** + * Filters available routes by language (of current page). + * + * @param postsArray Array of ScullyRoutes. + * @param lang Language abbreviation to filter by. eg 'en'|'es' + */ + public filterPostsByLang(postsArray: ScullyRoute[], lang: string): ScullyRoute[] { + return postsArray.filter((post) => post.lang === lang); + } + + /** + * In .md file header, define custom string formatting for + * linkText with `navlist_textFormat` + * + * If no additional textFormat is defined, by default each linkText + * will be capitalized. + * + * @param linkText String to be formatted. + * @param textFormat Type of formatting to apply to linkText. + */ + public formatLinkText(linkText: string, textFormat: NavTextFormats): string { + if (textFormat) { + switch (true) { + // ------------------------------ + // none + case textFormat.none: + return linkText; + // ------------------------------ + // capitalize + case textFormat.capitalize: + return linkText + .split('-') + .map((text) => this.smartToUppercase(text)) + .join(' '); + // ------------------------------ + // capitalize first letter + case textFormat.capitalizeFirstLetter: + return linkText.charAt(0).toUpperCase() + linkText.split('-').join(' ').slice(1); + } + } + // default capitalize first letter + return linkText.charAt(0).toUpperCase() + linkText.split('-').join(' ').slice(1); + } + + /** + * When capitalizing every word of a link's text string, + * some words should never be capitalized. + * This function makes sure these words stay lowercase. + * + * @param text String to assess and alter. + */ + private smartToUppercase(text: string): string { + const alwaysLowercase = ['a', 'of', 'the']; + const formattedWord = alwaysLowercase.includes(text) ? text : text.charAt(0).toUpperCase() + text.slice(1); + return formattedWord; + } + + /** + * Determines if link text should have custom formatting. + * + * @param post ScullyRoute with simplified route paths. + */ + public isNavListTextFormatType(post: ScullyRoute): boolean { + for (const key of Object.keys(post)) { + if (key.includes('navlist_textFormat')) { + return true; + } + } + return false; + } + + /** + * Converts `navlist_textFormat`s into a stringified NavTextFormats + * as a part of a single NavHierarchyItem. + * + * @param post ScullyRoute with simplified route paths. + */ + public navListTextFormats(post: ScullyRoute): string { + const textFormats = {}; + for (const key of Object.keys(post)) { + if (key.includes('navlist_textFormat')) { + const formatNameArray = key.split('_'); + const formatName = formatNameArray[formatNameArray.length - 1]; + textFormats[formatName] = true; + } + } + return JSON.stringify(textFormats); + } + + /** + * Create an updated NavHierarchy object by deep merging + * two NavHierarchy objects. + * + * @param obj1 NavHierarchy object to be merged. + * @param obj2 NavHierarchy object to be merged. + */ + public deepMergeObjects(obj1: NavHierarchy, obj2: NavHierarchy): NavHierarchy { + for (const key of Object.keys(obj2)) { + if (!obj1.hasOwnProperty(key) || typeof obj2[key] !== 'object') { + obj1[key] = obj2[key]; + } else { + this.deepMergeObjects(obj1[key], obj2[key]); + } + } + return obj1; + } + + /** + * Sorts each NavItem by `navlist_position`. + * null values positioned last. + * + * @param a NavListItem item to compare. + * @param b NavListItem item to compare. + */ + public sortNavItems(a: NavListItem, b: NavListItem): number { + let va: number | string = a.position; + let vb: number | string = b.position; + if (a.position === null) { + va = ''; + } + if (b.position === null) { + vb = ''; + } + if ('' + va < '' + vb) { + return -1; + } + if ('' + va > '' + vb) { + return 1; + } + return 0; + } +} diff --git a/apps/scully-docs/src/app/components/subheader/subheader.component.sandbox.ts b/apps/scully-docs/src/app/components/subheader/subheader.component.sandbox.ts deleted file mode 100644 index 2153c29ba..000000000 --- a/apps/scully-docs/src/app/components/subheader/subheader.component.sandbox.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { sandboxOf } from 'angular-playground'; -import { SubheaderComponent } from './subheader.component'; - -export default sandboxOf(SubheaderComponent).add('default', { - template: `` -}); diff --git a/apps/scully-docs/src/app/components/subheader/subheader.component.spec.ts b/apps/scully-docs/src/app/components/subheader/subheader.component.spec.ts deleted file mode 100644 index d3d18aafa..000000000 --- a/apps/scully-docs/src/app/components/subheader/subheader.component.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { SubheaderComponent } from './subheader.component'; - -describe('SubheaderComponent', () => { - let component: SubheaderComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [SubheaderComponent] - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(SubheaderComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/apps/scully-docs/src/app/components/subheader/subheader.component.ts b/apps/scully-docs/src/app/components/subheader/subheader.component.ts deleted file mode 100644 index 7a90ac51c..000000000 --- a/apps/scully-docs/src/app/components/subheader/subheader.component.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Component, Input } from '@angular/core'; - -@Component({ - selector: 'app-subheader', - template: ` -

    {{ title }}

    - ` -}) -export class SubheaderComponent { - @Input() title: string; -} diff --git a/apps/scully-docs/src/app/landing/landing.component.css b/apps/scully-docs/src/app/landing/landing.component.css deleted file mode 100644 index 60f8b7916..000000000 --- a/apps/scully-docs/src/app/landing/landing.component.css +++ /dev/null @@ -1,173 +0,0 @@ -.container { - display: grid; - grid-template-columns: 20% 10% 50% 10%; - grid-template-rows: 0 50px auto; -} - -main { - grid-column-start: 2; - grid-column-end: 4; - grid-row-start: row1-start; - grid-row-end: 4; - - display: grid; - grid-template-columns: 20% 1%; - grid-template-rows: 0 50px auto; -} - -.sub-header { - margin-top: 20px; -} - -.title { - grid-column-start: 1; - grid-column-end: 4; - grid-row-end: 1; -} - -.code { - grid-column-start: 4; - grid-column-end: 5; - grid-row-end: 1; - min-height: 400px; - background-image: url(/assets/scully-triad.svg); - background-size: cover; - object-fit: cover; -} - -.shell { - margin-top: 30%; -} - -.container-features-title { - display: grid; - grid-template-columns: 20% 20% 20% 20% 20%; - grid-template-rows: 0 50px auto; -} - -.features-title { - grid-column-start: 3; - text-align: center; -} - -.container-features { - display: grid; - grid-template-columns: 20% 20% 20% 20% 20%; - grid-template-rows: minmax(75px, auto); - padding-bottom: 70px; -} - -.features-fist { - grid-column-start: 2; - grid-column-end: 2; - text-align: center; -} -.features-fast { - grid-column-start: 3; - grid-column-end: 3; - text-align: center; -} -.features-best { - grid-column-start: 4; - grid-column-end: 4; - text-align: center; -} - -.container-deliver { - display: grid; - grid-template-columns: 20% 20% 20% 20% 20%; - grid-template-rows: 0 50px auto; -} - -.container-deliver-title { - display: grid; - grid-template-columns: 20% 60% 20%; - grid-template-rows: 0 50px auto; -} - -.container-deliver-content { - display: grid; - grid-template-columns: 20% 60% 20%; - grid-template-rows: 0 150px auto; -} - -.deliver-title { - grid-column-start: 2; - text-align: center; -} - -.container-tools { - display: grid; - grid-template-columns: 20% 30% 30% 20%; - grid-template-rows: 0 250px auto; -} - -.container-tools-title { - display: grid; - grid-template-columns: 20% 60% 20%; - grid-template-rows: 0 50px auto; -} - -.tools-title { - grid-column-start: 2; - text-align: center; -} - -.guide-1 { - grid-column-start: 2; - grid-column-end: 2; - text-align: center; - cursor: pointer; -} - -.guide-2 { - grid-column-start: 3; - grid-column-end: 3; - text-align: center; - cursor: pointer; -} - -@media (max-width: 1300px) { - .code { - background-size: contain; - background-repeat: no-repeat; - } - .container-features { - grid-template-columns: 8px 1fr 1fr 1fr 8px; - } - - .container-tools { - grid-template-columns: 1fr; - grid-template-rows: 1fr 1fr; - grid-gap: 24px; - } - .guide-1, - .guide-2 { - grid-column-start: inherit; - grid-column-end: inherit; - cursor: pointer; - } -} - -@media (max-width: 1024px) { - .container { - display: grid; - grid-template-columns: 10% 80% 10%; - grid-template-rows: 0 50px auto; - } - - .main { - grid-column-start: 1; - grid-row-start: 1; - grid-auto-rows: auto; - } - .title { - grid-column-start: 0; - grid-column-end: 4; - } - - .container-deliver-content, - .container-deliver-title { - grid-template-columns: 8px 1fr 8px; - } -} diff --git a/apps/scully-docs/src/app/landing/landing.component.html b/apps/scully-docs/src/app/landing/landing.component.html deleted file mode 100644 index 3920959ef..000000000 --- a/apps/scully-docs/src/app/landing/landing.component.html +++ /dev/null @@ -1,130 +0,0 @@ -
    -
    -
    - - - -

    - Scully makes building, testing, - and deploying Jamstack apps extremely simple -

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

    FEATURES

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

    Deliver insanely fast apps to your users

    -
    -
    - -
    -
    -

    - - Nothing will make your Angular project as fast as using Scully and - embracing Jamstack. - -
    - ~ Aaron Frost -
    - Scully Core Team Member -

    -
    -
    - -
    -
    -

    TOOLS & RESOURCES

    -
    -
    - -
    -
    - - -
    -
    - - -
    -
    diff --git a/apps/scully-docs/src/app/landing/landing.component.ts b/apps/scully-docs/src/app/landing/landing.component.ts deleted file mode 100644 index bc5058ee0..000000000 --- a/apps/scully-docs/src/app/landing/landing.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -@Component({ - selector: 'app-landing', - templateUrl: './landing.component.html', - styleUrls: ['./landing.component.css'] -}) -export class LandingComponent implements OnInit { - constructor() {} - - ngOnInit(): void {} -} diff --git a/apps/scully-docs/src/app/landing/landing.module.ts b/apps/scully-docs/src/app/landing/landing.module.ts deleted file mode 100644 index e63b1d1c8..000000000 --- a/apps/scully-docs/src/app/landing/landing.module.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; - -import { LandingRoutingModule } from './landing-routing.module'; -import { LandingComponent } from './landing.component'; -import { ComponentsModule } from '../components/components.module'; - -@NgModule({ - declarations: [LandingComponent], - imports: [CommonModule, LandingRoutingModule, ComponentsModule] -}) -export class LandingModule {} diff --git a/apps/scully-docs/src/app/pages/docs/docs-routing.module.ts b/apps/scully-docs/src/app/pages/docs/docs-routing.module.ts new file mode 100644 index 000000000..524977f57 --- /dev/null +++ b/apps/scully-docs/src/app/pages/docs/docs-routing.module.ts @@ -0,0 +1,21 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; + +import { DocsPageComponent } from './page/docs.page.component'; + +const routes: Routes = [ + { + path: '', + component: DocsPageComponent, + children: [ + { path: ':slug', component: DocsPageComponent }, + { path: '**', component: DocsPageComponent }, + ], + }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], +}) +export class DocsRoutingModule {} diff --git a/apps/scully-docs/src/app/pages/docs/docs.module.ts b/apps/scully-docs/src/app/pages/docs/docs.module.ts new file mode 100644 index 000000000..ff3418037 --- /dev/null +++ b/apps/scully-docs/src/app/pages/docs/docs.module.ts @@ -0,0 +1,14 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ScullyLibModule } from '@scullyio/ng-lib'; + +import { FooterModule } from '../../components/footer'; +import { DocsRoutingModule } from './docs-routing.module'; + +import { DocsPageComponent } from './page/docs.page.component'; + +@NgModule({ + declarations: [DocsPageComponent], + imports: [CommonModule, ScullyLibModule, FooterModule, DocsRoutingModule], +}) +export class DocsModule {} diff --git a/apps/scully-docs/src/app/pages/docs/page/docs.page.component.css b/apps/scully-docs/src/app/pages/docs/page/docs.page.component.css new file mode 100644 index 000000000..d5cfa7fb5 --- /dev/null +++ b/apps/scully-docs/src/app/pages/docs/page/docs.page.component.css @@ -0,0 +1,16 @@ +/* this :host is used to position footer at the bottom always */ +scullyio-docs-page { + height: 100%; + display: flex; + flex-direction: column; +} + +.docs-page-content { + flex: 1 0 auto; + display: flex; + flex-direction: column; + align-items: stretch; + justify-content: stretch; + padding: 34px 64px; + padding-bottom: 134px; +} diff --git a/apps/scully-docs/src/app/components/card/card.component.spec.ts b/apps/scully-docs/src/app/pages/docs/page/docs.page.component.spec.ts similarity index 55% rename from apps/scully-docs/src/app/components/card/card.component.spec.ts rename to apps/scully-docs/src/app/pages/docs/page/docs.page.component.spec.ts index ec26c83d3..7e5fdb42b 100644 --- a/apps/scully-docs/src/app/components/card/card.component.spec.ts +++ b/apps/scully-docs/src/app/pages/docs/page/docs.page.component.spec.ts @@ -1,19 +1,19 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { CardComponent } from './card.component'; +import { DocsPageComponent } from './docs.page.component'; -describe('CardComponent', () => { - let component: CardComponent; - let fixture: ComponentFixture; +describe('DocsPageComponent', () => { + let component: DocsPageComponent; + let fixture: ComponentFixture; beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [CardComponent] + declarations: [DocsPageComponent], }).compileComponents(); })); beforeEach(() => { - fixture = TestBed.createComponent(CardComponent); + fixture = TestBed.createComponent(DocsPageComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/apps/scully-docs/src/app/pages/docs/page/docs.page.component.ts b/apps/scully-docs/src/app/pages/docs/page/docs.page.component.ts new file mode 100644 index 000000000..747c3a3fa --- /dev/null +++ b/apps/scully-docs/src/app/pages/docs/page/docs.page.component.ts @@ -0,0 +1,13 @@ +import { Component, ViewEncapsulation } from '@angular/core'; + +@Component({ + selector: 'scullyio-docs-page', + encapsulation: ViewEncapsulation.None, + template: ` +
    + +
    +
    + `, +}) +export class DocsPageComponent {} diff --git a/apps/scully-docs/src/app/pages/landing/components/features/features.component.css b/apps/scully-docs/src/app/pages/landing/components/features/features.component.css new file mode 100644 index 000000000..a91cfc10a --- /dev/null +++ b/apps/scully-docs/src/app/pages/landing/components/features/features.component.css @@ -0,0 +1,82 @@ +section.scullyio-landing-features { + display: flex; + justify-content: center; + padding: 50px 0 60px; + box-shadow: inset 0 3px 2px -2px rgba(88, 74, 74, 0.1), inset 0 -2px 2px -2px rgba(0, 0, 0, 0.1); + background: rgba(0, 110, 110, 0.05); + background: var(--scully-night); +} + +section.scullyio-landing-features .features { + --transition-ease: 160ms ease; + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 54px; + width: 1000px; + max-width: 100%; + margin: 34px 0; +} + +section.scullyio-landing-features .features .feature { + display: flex; + flex-direction: column; +} +section.scullyio-landing-features .features .feature h2 { + margin: 34px 0 20px; + color: var(--scully-white); + font-size: 28px; + font-weight: 700; + line-height: 1.3; +} +section.scullyio-landing-features .features .feature h2 strong { + font-weight: 900; +} +section.scullyio-landing-features .features .feature h2 a { + color: var(--scully-white); + font-weight: 700; +} +section.scullyio-landing-features .features .feature h2 a:hover { + text-decoration: underline; +} + +section.scullyio-landing-features .features .feature .icon-container { + display: flex; + justify-content: center; + align-items: center; + height: 80px; + padding: 4px; + width: 80px; + height: 80px; + background: var(--scully-white); + background: url('/assets/img/scully-symbol.svg') center no-repeat; + background-size: contain; + margin-left: 12px; +} +section.scullyio-landing-features .features .feature .icon-container img { + display: block; + width: 70px; + height: 74px; + margin-top: 1px; + margin-top: -4px; + margin-left: -40px; + color: var(--scully-darkgray-lighter); + font-size: 70px; + transform: translateY(-6px); + filter: var(--scully-darkgray-lighter-filter); +} +section.scullyio-landing-features .features .feature .icon-container img { + width: 70px; + height: 74px; + transform: translateY(-6px); +} + +section.scullyio-landing-features .features .feature p { + color: var(--scully-white); + font-size: 16px; + font-weight: 500; + line-height: 1.8; + opacity: 0.8; +} +section.scullyio-landing-features .features .feature p strong { + font-weight: 800; +} diff --git a/apps/scully-docs/src/app/pages/landing/components/features/features.component.spec.ts b/apps/scully-docs/src/app/pages/landing/components/features/features.component.spec.ts new file mode 100644 index 000000000..10f6567fe --- /dev/null +++ b/apps/scully-docs/src/app/pages/landing/components/features/features.component.spec.ts @@ -0,0 +1,24 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LandingFeaturesComponent } from './features.component'; + +describe('LandingFeaturesComponent', () => { + let component: LandingFeaturesComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [LandingFeaturesComponent], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(LandingFeaturesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/apps/scully-docs/src/app/pages/landing/components/features/features.component.ts b/apps/scully-docs/src/app/pages/landing/components/features/features.component.ts new file mode 100644 index 000000000..1ec3487c9 --- /dev/null +++ b/apps/scully-docs/src/app/pages/landing/components/features/features.component.ts @@ -0,0 +1,37 @@ +import { Component, ViewEncapsulation } from '@angular/core'; + +@Component({ + selector: 'section.scullyio-landing-features', + encapsulation: ViewEncapsulation.None, + template: ` +
    +
    +
    +

    Jamstack Toolchain

    +

    + Scully's CLI is powerful enough to make JAMstack possible for all Angular and Angular-hybrid projects. Everything needed + to build, test, and deploy is included out of the box. +

    +
    + +
    +
    +

    Runtime Tooling

    +

    + Scully gives developers the necessary tools to JAMstackify any Angular project, including fine-grained control where + needed. +

    +
    + +
    +
    +

    Plugin System

    +

    + Extend and adapt Scully to any need with its powerful plugin ecosystem. Choose from built-in plugins, community plugins, + or make you own custom plugin and unleash the full power of Scully. +

    +
    +
    + `, +}) +export class LandingFeaturesComponent {} diff --git a/apps/scully-docs/src/app/pages/landing/components/intro/intro.component.css b/apps/scully-docs/src/app/pages/landing/components/intro/intro.component.css new file mode 100644 index 000000000..728393a36 --- /dev/null +++ b/apps/scully-docs/src/app/pages/landing/components/intro/intro.component.css @@ -0,0 +1,156 @@ +section.scullyio-landing-intro { + --transition-ease: 160ms ease; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + width: 1000px; + max-width: 100%; + margin: 0 auto; + padding: 72px 0 124px; +} + +section.scullyio-landing-intro .text h1 { + margin-bottom: 30px; + color: var(--scully-green); + font-size: 58px; + font-weight: 800; + line-height: 1.05; + letter-spacing: -1px; +} + +section.scullyio-landing-intro .text p { + max-width: 540px; + margin-bottom: 18px; + font-size: 18px; + font-weight: 600; + line-height: 1.5; + color: rgba(0, 0, 0, 0.8); +} +section.scullyio-landing-intro .text p strong { + font-weight: 800; +} + +section.scullyio-landing-intro .text p a { + position: relative; + display: inline-block; + color: var(--scully-green); + font-weight: 800; + opacity: 0.9; +} +section.scullyio-landing-intro .text p a:active { + transform: translateY(1px); +} +section.scullyio-landing-intro .text p a:hover { + opacity: 1; +} +section.scullyio-landing-intro .text p a:hover::before { + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 2px; + border-radius: 4px; + background: var(--scully-green); +} + +section.scullyio-landing-intro .text .button-container { + display: flex; + margin-top: 42px; +} +section.scullyio-landing-intro .text .button-container a { + display: block; + margin-right: 18px; + padding: 15px 40px; + color: var(--scully-white); + font-size: 18px; + font-weight: 800; + letter-spacing: 0.2px; + border-radius: 8px; + box-shadow: none; + border: solid 3px var(--scully-green); + background: var(--scully-green); + opacity: 1; + transition: box-shadow var(--scully-transition-ease), background-color var(--scully-transition-ease); +} +section.scullyio-landing-intro .text .button-container a:active { + transform: translateY(1px); +} +section.scullyio-landing-intro .text .button-container a:hover { + color: var(--scully-green); + background: transparent; +} +section.scullyio-landing-intro .text .button-container a:last-child { + color: var(--scully-green); + background: transparent; +} +section.scullyio-landing-intro .text .button-container a:last-child:hover { + color: var(--scully-white); + background: var(--scully-green); +} + +section.scullyio-landing-intro .cli { + position: relative; +} + +section.scullyio-landing-intro .cli .triad { + position: absolute; + content: ''; + top: 60%; + left: -54%; + width: 540px; + height: 540px; + background: url('/assets/img/scully-triad.svg') center no-repeat; + background-size: contain; + transform: translateY(-50%); +} + +section.scullyio-landing-intro .cli pre, +section.scullyio-landing-intro .cli code { + color: rgba(0, 0, 0, 0.7); + font-family: 'Roboto Mono', monospace; + font-size: 16px; + font-weight: 500; + border-radius: 4px; + overflow-x: auto; +} +section.scullyio-landing-intro .cli code { + margin: 0 2px; + padding: 2px 6px; + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.1); + background: rgba(68, 106, 107, 0.1); +} +section.scullyio-landing-intro .cli pre { + position: relative; + padding: 20px 36px; + padding-bottom: 4px; + padding-right: 42px; + box-shadow: 0 0 0 2px var(--scully-white), 0 0 50px 60px rgba(255, 255, 255, 0.96); + background: var(--scully-night); +} +section.scullyio-landing-intro .cli pre::before { + content: attr(class); + position: relative; + display: block; + margin-bottom: 6px; + color: rgba(255, 255, 255, 0.5); + font-family: 'Nunito', sans-serif; + font-size: 9px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 2px; + overflow: hidden; + transform: translateY(-8px) translateX(-20px); +} +section.scullyio-landing-intro .cli pre code { + max-width: 100%; + margin: 0; + padding: 0; + color: var(--scully-white); + font-weight: 400; + letter-spacing: 0.5px; + background: none; + box-shadow: none; + overflow-x: auto; +} diff --git a/apps/scully-docs/src/app/pages/landing/components/intro/intro.component.spec.ts b/apps/scully-docs/src/app/pages/landing/components/intro/intro.component.spec.ts new file mode 100644 index 000000000..b05c0d8c5 --- /dev/null +++ b/apps/scully-docs/src/app/pages/landing/components/intro/intro.component.spec.ts @@ -0,0 +1,24 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LandingIntroComponent } from './intro.component'; + +describe('LandingIntroComponent', () => { + let component: LandingIntroComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [LandingIntroComponent], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(LandingIntroComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/apps/scully-docs/src/app/pages/landing/components/intro/intro.component.ts b/apps/scully-docs/src/app/pages/landing/components/intro/intro.component.ts new file mode 100644 index 000000000..d101692cb --- /dev/null +++ b/apps/scully-docs/src/app/pages/landing/components/intro/intro.component.ts @@ -0,0 +1,27 @@ +import { Component, ViewEncapsulation } from '@angular/core'; + +@Component({ + selector: 'section.scullyio-landing-intro', + encapsulation: ViewEncapsulation.None, + template: ` +
    +

    Static Angular sites,
    wicked fast.

    +

    + Scully makes building, testing and deploying Jamstack apps + extremely simple. +

    + +
    + +
    +
    +
    +ng add @scullyio/init
    +      
    +
    + `, +}) +export class LandingIntroComponent {} diff --git a/apps/scully-docs/src/app/pages/landing/components/quote/quote.component.css b/apps/scully-docs/src/app/pages/landing/components/quote/quote.component.css new file mode 100644 index 000000000..ae16ca15f --- /dev/null +++ b/apps/scully-docs/src/app/pages/landing/components/quote/quote.component.css @@ -0,0 +1,71 @@ +section.scullyio-landing-quote { + position: relative; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 100%; + margin-top: 104px; + padding-top: 44px; +} + +section.scullyio-landing-quote::before, +section.scullyio-landing-quote::after { + content: ''; + position: absolute; +} +section.scullyio-landing-quote::before { + top: 0; + left: 50%; + transform: translateX(-50%); + width: 340px; + max-width: 50%; + border-top: solid 4px var(--scully-green); +} +section.scullyio-landing-quote::after { + content: '"'; + display: flex; + justify-content: center; + align-items: center; + top: 0; + left: 50%; + transform: translateX(-50%) translateY(-36%); + width: 72px; + height: 72px; + padding-right: 2px; + color: var(--scully-green); + font-size: 44px; + font-style: oblique; + border-radius: 50%; + background: var(--scully-white); +} + +section.scullyio-landing-quote cite, +section.scullyio-landing-quote blockquote { + width: 100%; + max-width: 640px; + text-align: center; + font-style: normal; +} +section.scullyio-landing-quote blockquote { + margin-bottom: 34px; + color: var(--scully-night-darker); + font-size: 32px; + font-weight: 600; + letter-spacing: -1px; +} + +section.scullyio-landing-quote cite p.name { + margin-bottom: 8px; + font-size: 16px; + font-weight: 800; + opacity: 0.72; +} + +section.scullyio-landing-quote cite p.org { + font-size: 11px; + letter-spacing: 1px; + font-weight: 900; + text-transform: uppercase; + opacity: 0.44; +} diff --git a/apps/scully-docs/src/app/pages/landing/components/quote/quote.component.spec.ts b/apps/scully-docs/src/app/pages/landing/components/quote/quote.component.spec.ts new file mode 100644 index 000000000..4ee9a6dcb --- /dev/null +++ b/apps/scully-docs/src/app/pages/landing/components/quote/quote.component.spec.ts @@ -0,0 +1,24 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LandingQuoteComponent } from './quote.component'; + +describe('LandingQuoteComponent', () => { + let component: LandingQuoteComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [LandingQuoteComponent], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(LandingQuoteComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/apps/scully-docs/src/app/pages/landing/components/quote/quote.component.ts b/apps/scully-docs/src/app/pages/landing/components/quote/quote.component.ts new file mode 100644 index 000000000..9cf6af046 --- /dev/null +++ b/apps/scully-docs/src/app/pages/landing/components/quote/quote.component.ts @@ -0,0 +1,16 @@ +import { Component, ViewEncapsulation } from '@angular/core'; + +@Component({ + selector: 'section.scullyio-landing-quote', + encapsulation: ViewEncapsulation.None, + template: ` +
    +

    Nothing will make your Angular project as fast as using Scully and embracing Jamstack.

    +
    + +

    - Aaron Frost

    +

    Scully Core Team Member

    +
    + `, +}) +export class LandingQuoteComponent {} diff --git a/apps/scully-docs/src/app/pages/landing/components/resources/resources.component.css b/apps/scully-docs/src/app/pages/landing/components/resources/resources.component.css new file mode 100644 index 000000000..e0f934462 --- /dev/null +++ b/apps/scully-docs/src/app/pages/landing/components/resources/resources.component.css @@ -0,0 +1,61 @@ +section.scullyio-landing-resources { + --transition-ease: 160ms ease; + display: flex; + flex-wrap: wrap; + justify-content: space-between; + width: 1000px; + max-width: 100%; + margin: 0 auto; + padding: 100px 0; +} + +section.scullyio-landing-resources a { + box-sizing: border-box; + width: 34%; + flex: 0.46 0 auto; + display: flex; + align-items: flex-start; + margin-bottom: 24px; + padding: 34px 42px; + color: rgba(0, 0, 0, 0.8); + border: solid 3px rgba(0, 0, 0, 0.1); + border-radius: 8px; + transition: border-color var(--scully-transition-ease), background-color var(--scully-transition-ease); +} + +section.scullyio-landing-resources a img { + width: 54px; + height: 54px; + margin-top: 6px; + margin-right: 42px; + filter: var(--scully-green-filter); + transition: filter var(--scully-transition-ease); +} + +section.scullyio-landing-resources a .text { + display: flex; + flex-direction: column; + padding-right: 64px; +} +section.scullyio-landing-resources a .text h3 { + margin-bottom: 8px; + font-size: 26px; + letter-spacing: -0.5px; +} +section.scullyio-landing-resources a .text p { + opacity: 0.9; + font-size: 18px; + line-height: 1.44; +} + +section.scullyio-landing-resources a:active { + transform: translateY(1px); +} +section.scullyio-landing-resources a:hover { + border-color: var(--scully-green); + background-color: var(--scully-green); + color: var(--scully-white); +} +section.scullyio-landing-resources a:hover img { + filter: var(--scully-white-filter); +} diff --git a/apps/scully-docs/src/app/pages/landing/components/resources/resources.component.spec.ts b/apps/scully-docs/src/app/pages/landing/components/resources/resources.component.spec.ts new file mode 100644 index 000000000..224506b4d --- /dev/null +++ b/apps/scully-docs/src/app/pages/landing/components/resources/resources.component.spec.ts @@ -0,0 +1,24 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LandingResourcesComponent } from './resources.component'; + +describe('LandingResourcesComponent', () => { + let component: LandingResourcesComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [LandingResourcesComponent], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(LandingResourcesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/apps/scully-docs/src/app/pages/landing/components/resources/resources.component.ts b/apps/scully-docs/src/app/pages/landing/components/resources/resources.component.ts new file mode 100644 index 000000000..5aefa2a4d --- /dev/null +++ b/apps/scully-docs/src/app/pages/landing/components/resources/resources.component.ts @@ -0,0 +1,24 @@ +import { Component, ViewEncapsulation } from '@angular/core'; + +@Component({ + selector: 'section.scullyio-landing-resources', + encapsulation: ViewEncapsulation.None, + template: ` + + +
    +

    Guides

    +

    Easy step-by-step guides to help you get started.

    +
    +
    + + + +
    +

    Create a blog

    +

    Create your own static Angular blog in 5 minutes.

    +
    +
    + `, +}) +export class LandingResourcesComponent {} diff --git a/apps/scully-docs/src/app/landing/landing-routing.module.ts b/apps/scully-docs/src/app/pages/landing/landing-routing.module.ts similarity index 54% rename from apps/scully-docs/src/app/landing/landing-routing.module.ts rename to apps/scully-docs/src/app/pages/landing/landing-routing.module.ts index 9d66ec6e7..c6412adb1 100644 --- a/apps/scully-docs/src/app/landing/landing-routing.module.ts +++ b/apps/scully-docs/src/app/pages/landing/landing-routing.module.ts @@ -1,12 +1,12 @@ import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; -import { LandingComponent } from './landing.component'; +import { LandingPageComponent } from './page/landing.component'; -const routes: Routes = [{ path: '', component: LandingComponent }]; +const routes: Routes = [{ path: '', component: LandingPageComponent }]; @NgModule({ imports: [RouterModule.forChild(routes)], - exports: [RouterModule] + exports: [RouterModule], }) export class LandingRoutingModule {} diff --git a/apps/scully-docs/src/app/pages/landing/landing.module.ts b/apps/scully-docs/src/app/pages/landing/landing.module.ts new file mode 100644 index 000000000..f3855856a --- /dev/null +++ b/apps/scully-docs/src/app/pages/landing/landing.module.ts @@ -0,0 +1,23 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { FooterModule } from '../../components/footer'; +import { LandingRoutingModule } from './landing-routing.module'; + +import { LandingFeaturesComponent } from './components/features/features.component'; +import { LandingIntroComponent } from './components/intro/intro.component'; +import { LandingPageComponent } from './page/landing.component'; +import { LandingQuoteComponent } from './components/quote/quote.component'; +import { LandingResourcesComponent } from './components/resources/resources.component'; + +@NgModule({ + declarations: [ + LandingFeaturesComponent, + LandingIntroComponent, + LandingPageComponent, + LandingQuoteComponent, + LandingResourcesComponent, + ], + imports: [CommonModule, FooterModule, LandingRoutingModule], +}) +export class LandingModule {} diff --git a/apps/scully-docs/src/app/landing/landing.component.spec.ts b/apps/scully-docs/src/app/pages/landing/page/landing.component.spec.ts similarity index 54% rename from apps/scully-docs/src/app/landing/landing.component.spec.ts rename to apps/scully-docs/src/app/pages/landing/page/landing.component.spec.ts index 6b5dc3972..8a403d76b 100644 --- a/apps/scully-docs/src/app/landing/landing.component.spec.ts +++ b/apps/scully-docs/src/app/pages/landing/page/landing.component.spec.ts @@ -1,19 +1,19 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { LandingComponent } from './landing.component'; +import { LandingPageComponent } from './landing.component'; -describe('LandingComponent', () => { - let component: LandingComponent; - let fixture: ComponentFixture; +describe('LandingPageComponent', () => { + let component: LandingPageComponent; + let fixture: ComponentFixture; beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [LandingComponent] + declarations: [LandingPageComponent], }).compileComponents(); })); beforeEach(() => { - fixture = TestBed.createComponent(LandingComponent); + fixture = TestBed.createComponent(LandingPageComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/apps/scully-docs/src/app/pages/landing/page/landing.component.ts b/apps/scully-docs/src/app/pages/landing/page/landing.component.ts new file mode 100644 index 000000000..abecac1e1 --- /dev/null +++ b/apps/scully-docs/src/app/pages/landing/page/landing.component.ts @@ -0,0 +1,14 @@ +import { Component, ViewEncapsulation } from '@angular/core'; + +@Component({ + selector: 'scullyio-landing-page', + encapsulation: ViewEncapsulation.None, + template: ` +
    +
    +
    +
    +
    + `, +}) +export class LandingPageComponent {} diff --git a/apps/scully-docs/src/assets/1800contacts_logo_indigo.png b/apps/scully-docs/src/assets/1800contacts_logo_indigo.png deleted file mode 100644 index 811deed3339620e732fbe0d8cf73e114df9e902a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25218 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 diff --git a/apps/scully-docs/src/assets/angular-original.png b/apps/scully-docs/src/assets/angular-original.png deleted file mode 100644 index c5102939182281314e8f79f1d7f7cd2145cd81f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2385 zcma)7Yg7{07RIs3%FxPQR!&yqtJ0hZ5q!V36s>HM!9+u$2FwSRhKg2B<&>E{G!#O# zwA6e=j)|gO?V+h4plBtal?v$qDI=3vgaK)w- z0000O;O~7%hw3kTnZE99-CJR-15QX_sE-c&4ED4e*$MUSznU)mkNyA5Kl8u(I!A2c z^2*FfcJ9u|rGiEI)VyNq({Ykkt9^SSZGL!kc4TzSGn%*mxawJ#qP=Tm$NsL}{!{ci z>HRw0XkGb-y+_$jMHy)#GgHe@3YgxRlDsIzilq0|Sw&Y(Mu@wkSyKF}g2KfF85E0efvcWi^e-(3c~#)b>`TQ2)>6zHAmrMd-Stf-V=Oj zU|bgI<@i-s9DGM~8e77!JU&BVo2CnzGbOe#tP;Vul%}y2h;}~u-%*q<+MSR8BC3L7 z8XSt4URzS*4V`AssYpj|Vzz9q78l55t9WVHt=T2?Gut}JIRsIh z1%d!9ZTJz0B;Ds&fZx58g;kJ+7Y{6mdr%8A^3Vy)yS)| zsbKXMQWg=wJBnuq3Ta7hXa)wz;|x+dHDw#{0*dc&FU3?ws*lXV1bG|vkTrJc?lHjN zxV+q;QM+`wt7km|b_ZnGa6omy8ka&`>FSU(Au&;`u4v~q>eRrPTlEkZxaSP+X!}zh z6N!0pnRbDHC4JX!?2S_{tb*eRhOZP-d-2#)A`^8SoC@*u8x4$*m2wC>aof*q=r%;( zmNzNY*S9Ky_l(sSQ#xn(hSs>Z_KQE=1bH>kWPX7H=X26Js;1gbJRzO;(y*u^y40Wj zaWqDG)+ibnjM@fe#20WE*K`(wgRBxQx1!**kM4qD<>d}Cy@?|8^A>n3FYDA^i2&%{ zJq|%w`VNpzg;y{@>$8Vq`_*}j%^zd6LAyr^4t$aoy!<>Yi?--az z<(m^N4e1+Zs#fz#YbgQY%Y@}o2$PfR^Fc-SYQbHwr}|Mb#im`NE9?#4bFoai`C7OS z*kl*k}6{1T5!RH3W5Y$66%T7aX^xOg+9-zpuWmVZpO|{MrF-usr&Ys6i zc*u*CfGr-Xhud&(J=JJ0Hh!a8a2*_+r5se)NN&(Mz^w(ca4>6fz?QI5xZwh`r>3w) zJ#_cjpv1__V{MBY2(%$D)L#CVn0F(Ed=1PK@&C1~<@p)aI19Qs-VZhFOeJ2=fw%BE zeD@;Mv2wA42gDf$Z|yGe?&rm-E3O@ib%OKfFGcD%-)uc~D|u=lX9})i9u#E{^z=J@ zW;PP7!XToi!*f#X&k&K07^%;&u@{jD4b}2*X(> zHAR)l?@tr{f;XS4{zoHs$fb(Uae=f|%+IzkH>wDm1X93VnR*{`#WYgXrDQ*3x*D+Y)Ihu{Q7!rfGMwO?^v ljI?SQ9hwt}{Ftxy#)W*NndmOdGy3wQ2l&9ft34yn{|yqu>aG9) diff --git a/apps/scully-docs/src/assets/book.png b/apps/scully-docs/src/assets/book.png deleted file mode 100644 index 2fa2a4be349aafccedff557eaf9f0d72942ec289..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1795 zcmV+e2mJVnP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGmbN~PnbOGLGA9w%&2AD}iK~#8N?VQth1^(&djt33JAvH8x#x4wIlt{({Up5l4!czf{BG5j@XMhfZ1WDN zXN>6g>DT01n#5u-z`i%E`(BRF*ZIxZuibpsNjnz) ztyi;q;k!L*1zxCwh!l7QUV%>vDe!WJr*Qg=F%#!Z*O6|{!dcTboEo@Gr(j->r@w>jMw9+{+wX{ z8zmcf8gSXD3Z_{bhpu)$M~?kI(o9!zNOuPNG$(jF`lKaKOP|u`n=CcGKT^RT4CU$b z!6l>`uf+5(Bw4^8)2H+0O=&aD-W6+J-1}`5J(Pms5(Gj)(aT?Q_!RwFG`d^iSa70> z&Gw0bi-PUMsL1gco`8STn!`p(4*z)k877uIC?0vj4V_RMv8s2!gmrFM^cW74t)m z!)z(vW%5EUpp7j;F}87xBb~_Ag~;SqiK3o489n&RnL@J;X>7c6`C%VTsYTMx{Z>LC%PJAOvouaez<}75{3Q#yw&XS!vZonEC zB!SY;m1DIi7%D-!`G)AMEuOX={t^pYSHfXY1qXUKVr{{PXxrhhu^TRjgGkYx6}-Nk z+ID!#;HU=oF;dw7t8IrTeT=g6$B-oOa*+bBz$@@vlE719Le-tf@6->KvZDQbn(^wo z(-=yKGR)Z@91F+>KG*(`XK4|TqYRAdd(oAd3Kr#2j2~%30h21h0!FlC1D|Ql<>zz} zup|03JRGT9*B@1JsoWK5LrG5_duT~N^HNBGSKt+RE(JbX3cLa@+zCm6SKt-+q>uuy zz$@@v3VgH_`1kNsZlY6EdXb3UnTd!F5a~q&I)lp_DoP5`TOq-4cpa-CJk`$V)$W$b z4s=bc(dO<&tE*>CnrSmEJ_kD7{b)}T>AY6{uSKI-W8mqPPC79)``PDkCvIsgklK}x z)17%qt-FRAw(R4~{9!0Gg+9TLg{u4gk0s6h=0)I<8nl%QVRAy|`^2t2&79>r(K8Om(s|7t5hI2G19m=ZzDY@h>WVL9wYG)%G^j$W-l4Ei-s=_I&Sz z37<0-{3{dKI4RHs0}&VN@S@^aa~=KbfR$=n;PH` lEX43_3BS{&!0%4I!@tKwk79yvlu!Tw002ovPDHLkV1n$Uc4q(p diff --git a/apps/scully-docs/src/assets/both.png b/apps/scully-docs/src/assets/both.png deleted file mode 100644 index 3b556d9741a43108369285dded9cdf1980d7a0ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12707 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 diff --git a/apps/scully-docs/src/assets/img/footer-bg.png b/apps/scully-docs/src/assets/img/footer-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..fc5d882fceeba294fbd4ddc5f9e5e6d48a4a8912 GIT binary patch literal 14437 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 literal 0 HcmV?d00001 diff --git a/apps/scully-docs/src/assets/img/icons/angle-double-right-solid.svg b/apps/scully-docs/src/assets/img/icons/angle-double-right-solid.svg new file mode 100644 index 000000000..998f8595f --- /dev/null +++ b/apps/scully-docs/src/assets/img/icons/angle-double-right-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/scully-docs/src/assets/angular.svg b/apps/scully-docs/src/assets/img/icons/angular-brands.svg similarity index 100% rename from apps/scully-docs/src/assets/angular.svg rename to apps/scully-docs/src/assets/img/icons/angular-brands.svg diff --git a/apps/scully-docs/src/assets/img/icons/arrow-left-solid.svg b/apps/scully-docs/src/assets/img/icons/arrow-left-solid.svg new file mode 100644 index 000000000..fd02abe2f --- /dev/null +++ b/apps/scully-docs/src/assets/img/icons/arrow-left-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/scully-docs/src/assets/img/icons/arrow-right-solid.svg b/apps/scully-docs/src/assets/img/icons/arrow-right-solid.svg new file mode 100644 index 000000000..604b62c91 --- /dev/null +++ b/apps/scully-docs/src/assets/img/icons/arrow-right-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/scully-docs/src/assets/img/icons/blog-solid.svg b/apps/scully-docs/src/assets/img/icons/blog-solid.svg new file mode 100644 index 000000000..0f91da52d --- /dev/null +++ b/apps/scully-docs/src/assets/img/icons/blog-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/scully-docs/src/assets/img/icons/book-solid.svg b/apps/scully-docs/src/assets/img/icons/book-solid.svg new file mode 100644 index 000000000..df61bde6b --- /dev/null +++ b/apps/scully-docs/src/assets/img/icons/book-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/scully-docs/src/assets/img/icons/check-solid.svg b/apps/scully-docs/src/assets/img/icons/check-solid.svg new file mode 100644 index 000000000..15d7ab5e8 --- /dev/null +++ b/apps/scully-docs/src/assets/img/icons/check-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/scully-docs/src/assets/img/icons/chevron-right-solid.svg b/apps/scully-docs/src/assets/img/icons/chevron-right-solid.svg new file mode 100644 index 000000000..6f3ecc4dc --- /dev/null +++ b/apps/scully-docs/src/assets/img/icons/chevron-right-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/scully-docs/src/assets/img/icons/code-branch-solid.svg b/apps/scully-docs/src/assets/img/icons/code-branch-solid.svg new file mode 100644 index 000000000..c0b53a482 --- /dev/null +++ b/apps/scully-docs/src/assets/img/icons/code-branch-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/scully-docs/src/assets/img/icons/file-exclamation-regular.svg b/apps/scully-docs/src/assets/img/icons/file-exclamation-regular.svg new file mode 100644 index 000000000..28913f4b4 --- /dev/null +++ b/apps/scully-docs/src/assets/img/icons/file-exclamation-regular.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/scully-docs/src/assets/img/icons/github-brands.svg b/apps/scully-docs/src/assets/img/icons/github-brands.svg new file mode 100644 index 000000000..7870c06dc --- /dev/null +++ b/apps/scully-docs/src/assets/img/icons/github-brands.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/scully-docs/src/assets/img/icons/globe-solid.svg b/apps/scully-docs/src/assets/img/icons/globe-solid.svg new file mode 100644 index 000000000..0b3f0f3f4 --- /dev/null +++ b/apps/scully-docs/src/assets/img/icons/globe-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/scully-docs/src/assets/img/icons/play-solid.svg b/apps/scully-docs/src/assets/img/icons/play-solid.svg new file mode 100644 index 000000000..bcd81f7a6 --- /dev/null +++ b/apps/scully-docs/src/assets/img/icons/play-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/scully-docs/src/assets/img/icons/puzzle-piece-solid.svg b/apps/scully-docs/src/assets/img/icons/puzzle-piece-solid.svg new file mode 100644 index 000000000..19481c9b6 --- /dev/null +++ b/apps/scully-docs/src/assets/img/icons/puzzle-piece-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/scully-docs/src/assets/img/scully-symbol.svg b/apps/scully-docs/src/assets/img/scully-symbol.svg new file mode 100644 index 000000000..b7d7ccd34 --- /dev/null +++ b/apps/scully-docs/src/assets/img/scully-symbol.svg @@ -0,0 +1,12 @@ + + + + + + diff --git a/apps/scully-docs/src/assets/img/scully-triad.svg b/apps/scully-docs/src/assets/img/scully-triad.svg new file mode 100644 index 000000000..5e6530dad --- /dev/null +++ b/apps/scully-docs/src/assets/img/scully-triad.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/scully-docs/src/assets/scullyio-logo-black.svg b/apps/scully-docs/src/assets/img/scullyio-logo-black.svg similarity index 100% rename from apps/scully-docs/src/assets/scullyio-logo-black.svg rename to apps/scully-docs/src/assets/img/scullyio-logo-black.svg diff --git a/apps/scully-docs/src/assets/img/scullyio-logo.svg b/apps/scully-docs/src/assets/img/scullyio-logo.svg new file mode 100644 index 000000000..af418780b --- /dev/null +++ b/apps/scully-docs/src/assets/img/scullyio-logo.svg @@ -0,0 +1,95 @@ + + + + +logo + + + + + + + + + + + + + + + + diff --git a/apps/scully-docs/src/assets/img/showcase/1800contacts-01.jpg b/apps/scully-docs/src/assets/img/showcase/1800contacts-01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2dbb03dadbdafb4942cb8b97a18face597ef1185 GIT binary patch literal 44885 zcmdSA1$1P~jv$z3cA25f%*^aEGcz+YGc$9UnVFgGvR!6oW@e^ZzxVt9>7JhL={;xm zoZU#>2uYz(#Fa7w^6LIs{<950kPs0U0RRC306+SwgM|1R8Q@2U z0R@8qhlKjG3V;Ox0std`Abd4`g?O=j5TYpkOAmPSeS7L`M2!bw$_2~wlTo=>c`@<* z1kWg0FptsPg@A`eVF#+qG_Bgw9Sy77UoC`&SyQ>iAD{5!{-S`Gg~SlZ!ct6#OOZ(# z5YiINqok5~%G}3>+PzL=H7Fm7Yrlk`GGf3-2!!hv-Zww^UskhAS6@3j7HQsn87KB| zZCOd@;tszV7uFf?{iX7s38?w~bBk^V$M%eFe|WQvbWT3poNbHJSCbdyHQ6;sl7b&U zH8(Y%{GajwfI-`{*1~0{9RMIbrri)!0F4vUau0O-Q_Amu$b4Z-Toby0M|hhr6x4t> z-%h3j@a_A${#B)mYG7B8m3ac0kwv-W_`Q??NsvoVN z+80$!D>f{8g!5jq)>}7S%UAR?t&Ij@3qV-U3?AAaDpmR5jlu@Kg|@R?0Jss|-cB7{ zf(mu}^fZx9$LmL@b*?4pV+)=c+F*x_RHadhlo`BI25nKXsAq_VJuLDl&Z2gAXVZRP z7Eh+CyKRuRIULHQnmP6{euC$i{Ulpj(5zOE!n3TdY|`ywIY@uMG<@P^&2B{udkyd7 zJO_};PG;v>8d;)en)kBW&+|%Dk@Pee^thrdYn;lWCkCIB57qDfN)+i`&{@jRpm9fY ziOC?+wL1RAMDdC|UV{$+K%zF+H)xxj!E+Os-Fx7rWevo9b+atdzOaU-LbEy~G~am| z#bjJ9E%0w%1cgI9KJswiAI9^HRF=2R_iB1?fHp)%2sbg!Cj@}bF%AL%0Jr(3b<=h} zLF?kq^ZD*b!8@Wh`;JXosTme#)jefgWuY71q=i@${o*`~*wReo>Rw<}-XAV&m?@xF zbbKm-_l>6CUp9F?e7x`1DWR`ya`;?zF09upmG7V8_s^@uzIp%v{H?ld793n{bMBK- zmWsOIBM*li_xvQJ0Dym52Xr>UD6Aiuw{aN%%~RWZm+obp6iP@a=jb*AyY^`uimLfh ztYpcFElqn0KtQYG%n3(y-*p>?R=7&DrFSD8F88k?T7C`D#fHiEu*7cfn&v^?qMDM> z`pNbKV|OD`@VRSA)9T!-=M^SQhY0PT=B=;Y%zv}!A@@ie_{~tZ8@_V|w4Lcnheh^l zL_p7Ne8pzQvq@<>H4FfNagiY@{>U{6?-Vg$u{ltuuJ#H0AY zM{e2Dy$U4~bg9Ooy1SeXkz)ewYZ3z9ijOX67e!6R{FZ#`#kJ6hf0xc1d_&u$XweB{ z@UpPrlokT-Q?zyJ{P{NSw3WTMUe*0~hd|%s3cu_@PHI0|UYIsomVfl+CIA2o^^LP+ z-C;~-OqPXZFX~hIp(&Q5;Mf-NOkD(5_zCxDjCN!DWop^%_FaSZumM|y=#&iftQLUl zq%0ko^fjLJ&T;j>6axUzT#MIJ(z}g6Yo^s5$vj`M$EjGe`5u>n#Y?K)RmD~`tdqMB zuotf0ZAUgIV%L4Rq|*%)h!7u;1Duxul2Y#r&x-ekm@^(+DJHmvZFh@nnB7j&!(`}_ z5w)^BC%ZN=Im4b6XFcKkz+j>-8r=)5+ z(Z+pPD{1jyl7{CMTlZ#)cbf8i836(gx#YvSmr>sAR6O>u%Cz!yJvycE!&h7{-pUA! zvbw&9Xqb0Gk6L+IuSoHr%`tJ0e6PCbjJp-txZ^tS(ahoLNatI0pWx~qjvDIkt2;v- z`ZqiJr|4T%&}=4-MrCo$JTOl?#hP#4{ruF+Z0T@?-}iUx0TdQjO1Z{7G9x9 zJLI`s9d}v9VtJQBHY`S<#!R1-IPPJ*p!t?x5EDAr`3F!fXSBOzch@>lW&fFV^Z~sW z>*C&}F1vNmiZmhio#E`3pxJ*}OiN)=bm+PM3!D7lbc`q@l}vnQzMg zXpORTWZW6KU$=Gj+*;vt^bFjc8mp8A)tNQO%xFlFDdYkLDF6bOU2(mW$@6 z#eV>?K1Pw?!clBo-}n}fw5m4lM1zLQYnTz0QNMHp?J=Kiq`(=Y>fY3BS?MM%dTLuw zE{s)0wz0B`&1rUt7D`LASV!|tTYNM(%#x7}{QhlUZ+E^fZQQiDRd;m>N4soEQ{5bJ zfR3fgs#9YKqITij^mx{$-uBbL_+>!pqG=)J(tQD!35!fSO;=bC=mx9nrp)LsJN<_Q zl{ezEG&3qt3p94m>Dff|A?;pZ4IUXkB|3Co%%;H$<+D_fVlbRoeLrk^#^4d)k8rF*~kDLD{ zE&J_jXUY6!aBu)97zi*pFfhp9ZGnKlc9!6XNXQ5%sA%Z;1Pp}q5X6iu{6C2F<>Z;z z?7udgkbmt*Awk|A(V~|ql3FX62}FLNnQ18Hy4WX{*rUy4GKwkt<9`;Zi`p{kDn(a_ zKZv#MLr-$Fw4+*LlBBhn%*mL^YYwWOC^s4%BvctB3cZld1k+I9=rB-cC^pxosyCmk z4iKNRKOz>H%J-qd`qJCUxM7#F;P!0{AU2n4N|F!!&|i@Yi9SZ zyGJplf_+Zn$j%=?>8zZYGdrgN8GK$_#;-=_fp%gc8~J#Nala za;-5=Ha_}B0U43x&zc(pAJs}9&0i=3Uod!I@CCn6{>uM_|D)>vXx?wT<1M5XBPMFR z6f;(X^HYb5w$nx1?Y#YF#d)v(Y}jlFrwGF(N>7cphws_acMb0?_=IUBYS@z~b$>vD zO+zyGJe4Y-5Pqe0qC#nGWJq*?h%PhA$dHIGfru~CGK3Ogr8RRtL2m4e+wH&?A0I-U z8gEQkhKcF*F{YHZz}usqM%+X-tyA;|aE=Ck#p}|n0ec5!WNn8?jTMIZ^O=w(y@{0p z)ivubUxgYzGcW2U)+3JD}JQKScl znU@&5th`O1PRQ2y<_vlw4kaZn!~MCOVgk1EG)@`#b*Wb3WD;q zMDm0T*t<;N<<$+U(pieiriJIpXp9p@l#gX&F1yX^oTH<&8kYJ>N{g)}75Vdu18Gyg z%KB>wnX=*s!)(}3a~D)pkRnH^>#{ErCrDa{ zQ^})B7_rjKCKYu_jp|aMS|+x^<;T^N61R-d7$sGSivr)r@4E*n(P%BA=n4%YTdg#- zT&#des;l4(u#NbWhP18D`b3>*hYDN$Jj1K4?Wf9avn9XwYN;R|(ss6tt0bGy4puHv zK6A2>-^g2}F(iYLQdrBNG{NJTE9u@fvj;H`XX&1+k8?PXIdN@fD5~>%fP0S^A{dQT z`TVfKe6wzMG`4OQk=^nWJz>BQzU&>whS|tgJ+G?NITxkB2T#UJeScpn4FTrSWbO`9MGPK zWJ52`GZV|K{=*bpWME1or2-4hI`i1rlD)19$I4P5H%LyzZ~DOxPBxbED##t7pLWqMJC8KSME4AYcwlB3{8r4Z-Ay2)pZOd%L#{*xEg zgUwW*vQem7I&kuni2jgJ2d~VBMTN3NraAoHGMXH{tWfAR({$NF>9slFv@+Vw18Q1-@!=pQD=+)W6WkFtHC%^d0NCL2R|$K8nP2v zyAe{&i7n>(Wk10{tC~}+8wW+OpB#(%->5X?vLxbmw^Tc*6rtxcSV%@&RI=&CDax(l z(zv9XB^rfU#!(m5cAZB0A1itWtUoC<8y6kP)_0@KA%ENS4klup+-g|EHl|?FZMUv) zt~8p5Cp-lBmn^5*ns+t4mCF-1u%(p9G8CF4J4&HD?7`NT{0Qs5$(YL%y^Bdd#7dnZ zRk=iDi}2?(CqhShz)bL7Xq{d+vtefYjuj0z6tX91pVvD52jJVMP!B!76MCMMRJp4> zlE!Eh+?K2Mb06nkQ7D=f{Jc9>`9mrY4pGaVtuAi-PHcnowBkEkg?x)PPB+QP^Am?c zR_00fV^WCPrZaU(;mFi62az!WNFjJPHoO1g|_St%w1td|*%6bY| z8V2ntM4#>WsGX+9_1i#_@VK>jEPsz;ISIjHyH}drCq<2 zs$e&>)uO_UIB3&KbDRU~^F0#DalgV@x5A$JGW!!G2(CS3r%n5nSV05NvcobBI{BZH?fPC`_AamBmbWdcQo}oHvI* zv&>MXoaVpT(J2t6=;{pUrJ9W~E}J=A#Aw$w_Psk?M28I1E<0y|mGOpd*>HKrhj$sOaR#twO`(chCinpk`gr9&!$Llk>DRBpO=w7 z$wX1^6nou^Xi!nbWl@|=gQlTeZz(#UvIbLM!8-(UCnBDTPa(^DH~}t{El1XrM&1is z2m>BSg!0Ezvdox4`;W9Uv0X35CNAS#3C< z&`P@6kM6#PklMN?nsJ`w86}9E*%5sm>)R*h z?Vu3R3;5$RDHtTwf%E70p(R&2K_Y;zpiB?i3H~cwQ|Ky$Y=wKb?tK0YK`$plm$Br zR?Y9XC6`QP9zh2K>-cJ9r2UR_s4%0B%RmK1!Y-K!7_DKM*ky7%#eRma>9BR}1>4$s zDJ6GGZ0W5AZ^3V~*I1H*)Bh$Zr{qovolPL8^g;<8OY%c;kPXYtFKHSa`47r~lCZCyUR9!UUR5G90{<@m+r8&oJcIr7`b(*WC(E*L`-0V!V(1%< zW@KKXI@SRWwYv3)@nT{0`r6zdK;xR$RlhF)y7=ZyY|&G=Nsvm->+P8gTb($-~`ojWp`CPAkVP{3{YCBR=WB0p;%{SY3KTQ*OA1ZuS9End+rnc?Q$u15}u9qa~H^HWsO(7E!jAuRMQy zX50Q0`dVjo`(IVH)T4w;F=`(!gZH-adR|@DXgS^Jz>jSX! z;Q7lA)5Qz>U=dg^-KB|WLS6BHfDT(yqz-dug`$mlS*P-@`QaG7GkrOR?++mTlPEjE zgJa)_zTS%_Jl9bMFa5afwu2we`Nt84hS8*^*P@1sxgIB>J4=Y=naoiYlPYmj;xP6_ zie=q|-HP$MygZ!u<{XR#H4%GNdEa^oLt8&uxA#rcV#m)L;sqp6G(MAb>8}M3&W`Jg zBP=aeR{B)eU4dJxf8s*JpiEqyH4Qj%uN|&xdiw)lJu6A+eKk1x!J3E)-+dIlW8QW` zSQwo>fz9&0B7iBe$sD>;QArZ5nL?6*rKK^jG`p!VM}nuDlsA`)wS{|h_D(slK$mHa zd38h5AI*C%vTk^a4wJiTq#YKGTKI*F^0-mCdm_tye-X+dd* z!j{GF6z-YO!}cd-q}gf9FxG`#?92VzWgO}7Y3agWf>&*OZg|KB?=YTX%5LftnAWv; zpXF;Co#X9fAHL2k?N=n{)G+@k#L z1U+hEFaBgfWJ$sW*74=3f%Qf!8d%HpUd&pYg45EyKACNO6TA+hiZb62cIm|X*oIXv zhz8>)ZF)4lf#8*O8Z1~snba8Ggz5X4xc499VOpq?SO#pJKRVYR_Zyw)4Nol6EUU0! zpE? zpt1-}lzK(|RQ1Ad-%%LSX0jWXgscAFy;I7T_ zcxTvhmk-c6r-6&Zo&%TPYjsicxVjG9a-X1qrC#&H(#NT$diL=!HwwRnRcPv;Kwm}k zFAe!}0(-g6#31T|+_M+yrKEe%~g!BC4C#m+e~EbiwJ zv`D8ew1|Y}!e5n6R&IKRT;dwI`4;7Vd*?O{u=;ICyDl`S^3{(sk~E}h%eS;#iySh{G?cO~m=6j0h}ci8T$#1}rv zNn%7~lWAtscr7Tol~NMMU)D8T+h}N{B{A*wRR*PDMlxa7iQ=s>m!geoL9C zFE6pG4pd}TmLiEkA35kUcPpGl96Ubs7Sg#?LH0DRAMIwF&mtXd{~3a?#;nFrUI?x- z9bpHU=y22!NnA7AqmOmD(26&X-*PU>XJMLxy_Q4~nd#2F*>_|SLAguYk^K54TY`A28ZY7#hnycPdV6(zQKzBY^muD{>=(x zaZZ=&v)MsLZ-isu!p3WVib+Vj8TX?AsP4#`=ZD^h=WEAe)rN|zr0J(pT>E8h!yDao z>Du}Ii?|#n+&nU+h}v=&NB9jEEGOS9bJlF4%f{4}!}4`8=&wGlHmyfzS)v|Dsb0HGmGT*o(;178%&9FF zRU~SRv<6u{KFwRF$GM4t!Fyvqq_AgPznt1{&|gJt<<5}gO9bI*#*W5D0Ch(EU2>Ej zod^ZSw1*K6zKwoCV0~7<(NG7gdsG`ZuYTnET@Kl)bU51=Ci&A{{L zbqibBL-b&2QDG?$MhOnztIQujpweC}8ylWz`x|HX$dNv~=VIK_8I-wU#;mKN!`fq0 z)Gxim-wq_0cf%^aM%sOClmj#yrqRYX@ZFQ0-L%$R0&HNJ9iB>AkNl4r<$iswwiJP@ z7OQwvuOWv|VEH*p`oC%twJ@!?ti4Mu@w5DIxUF$yaD=%~YQ+rV2M&pRmu!2je4f}4 z@ABD8V#sfCGG@@$v)N1Fxr=+PDbYY05n`8}{WhEQe$VuCiVsA5J%x_>fgOJspL(zw z9O!fNmR`Xc6BYdj(4QYt48@VULbjnxkl@=H!GL{nYNw$b|ARaD%5o)xu6e_JF(Mm( zTE`XcKoN@BTl$Axi*$hr9r0OH|Mo{-n^`!xiy221G8sb}b5>WRfcPo{Ijrjx5Eln# zByFt5^ps_dmrxZ9`8vR7LFlXc@Oq0k)jZCtd`SO;DR-3J^he%2Z&C#qT5 zkWl5kK?o!L3kwhlu2yO7ulXFv^-E~ zz9vr~r`-yGmE<4J>H8;(J zWXz(Es()q! zc65q8Mc>Wgu{Kt`>4Z;g-?B~4<3q+Ck6rf6xXPNLY}S8JR^Z#n%TIIwhWeTl7f2dw>0H;*{(;;tLXA0}4NLD`7lf@vQy; zD&9#G#sUtvik3Z5XpO){>SjXqA4~oK9&FXOj6+0O&#m$le_hZT`zKPXtb|n&d4!WU zB|DDc;y)SGj@e%QMYb>8`FE}txQwRJ z5W4Bo{OkVw;7S|eXOT5sgM2(UwVBe1p(Ukg)@DNdW%$nnajY6#YKyto~Amq>T)0rK>UT1Eb-YQg#Fs1A4jWt>P5-UmwABLri&EfL3e9ZYM6P_< z1i>Y?NA^6Pz-iSsu+nAC2%gZac9Ecd?-M;&BkmKF!B6LQN(%NcBCQ!3FIE~Xo07tr zkM}CkcC1amnkgyRgN4pD>#*ZHGHv!AN8M#94!BE_ZnG6f-QOVSHhfn%t99ehv-#mJ zoQ8FzdZQoNU6WrVfWyP802ibuQNP_<#KyIn- zD|95^cr~aMV$(9bv3%yv$bU`xtOYo5=dI5fPKcf>HKfgTG*hfioS4?hz`bZOu4etzrSiiumRWOsTv1}q z&TC2GN6DXL#na>1h_YUcEx%fz`Vel@c2W$mdk*G~ab8=_6n&krGOIoCyzox#u<<_$ zwLaCP^LjCI2b*NKU20O|%bM$In2@@1oFSraZ!@+VJWF~a+dT5yCsyz4jcI(!!~$y3 zo^fTXX^p)awQYdJRF@>kZ~L`O@7i0b){VDZjT=vy`u{Hi3Ev==UdmHK zZK2!w$}|M%<|_(zE7bo0;Fh0O=pnkUmbl#6Wa487EQegmM{`Kj<@XCPFxK%Az2X`$ z$r!r$BiCN|10eDLBhW0se$4soiA$_`D+A#9G7N0qNYD3Q^7TLZ|D$Nn*B>{O2w$@&nNqQjHc|9_L+MeLyl2Ln3GJI z|AAE5`i67(F)(-ue&^M_sO;Yb-d4T?92Nod8yH@ca?ltqV7Ew81mUFh9O;2SqQ3XWZNknQKjaYq(_j#S4Npnx zLvr;sT|0BVU>eTdu*Ya=Mo-y))!9+EdyD%1hG~X#2m(Z+*YDuCZsea=etU#Jp3#6Q zswyjkmHGK4jS!afS$frHn}W&tEh3InE^7)kv@l_WsTPl>aSRBH1L1ycl%F%ZZ7YKU z8q~V<;Zf~=4BGqw>>`4h;^+6n(aggb_|!n$XBHib!a#`!j_3j0nFAOL626^~OX!BS zyXT1Sc$4|xXN%6d<%n;4lSTi9esK@I$lFc!lLkh z&IziH!^7%UuBV`SD87Vw-GN`K&{x&Y8{)~Xk${3HLrn7YcpobeqVh6E$KpkRIPa#% zUVh-;I;&LO!43z7TEN4Pyt2ziJD_|=v=8{a%2!x{S8vF*vJ3T#-Z3<*yP(4`uvU{QU5=Euzd zKK%)yl>2RK(so9Y+cBh3slpg!6@&9z@D?GzBQ?15{sHeQ!x>H-WQ$K2SD!E4J_A(I zwXy#sVmAeQza)7}U)t$Rz5>UrdJ7slQR*yFLw%jzj=KmINdpT%L0p+_e-RgGKfEO(Bn>UTarTN`2v+6D6bhfb06UxN{w$Kxsdac_0)VxP+0hYUFdc z;xQt$`)aiRbU>cXSkSZxlV6~m!2~@W7o4HS^zUuvWGE1n57GXsh|WXwCDq(8t`klX z(<$rxoj!drJ01;zc7iGa3K|fB`7wCd-)yrHt-(<}r5}uusjk8lCL?N5fi%Y7cKaI2 z>@kAMV>w+xFWsw+eUjD@n5{A((NQse#Y6DhC#jy&P5@Dce487wLJH}lg1)wy=8C(Z z;)8IKn}gd?6J{Hj_E+)TF)E~%r^_$bMdVgzu*N{pMGB(C8*f~#6sV!G6WvN z-^o<%tRvrrL`j~$=-92GNOSNX6IF~8sm)eL_Zzk#2O zn8r%eaoiaO-BkTWvrY;%V1V$TB^U-O(o}hq?03+|@C~xDx^YMlDCl@Kc(^S|-s|HJ zfImHF@QN%Gn1ZzMBHnF>4h^M>QYCVVOD%N}oVfpk9JrEsT!1_Gdlv!m8!({*F)I;U zG!>B3GB8kHRDZ#5K_yE=uL=S6ICV`#IKhIDC;6!M03OOY6$Knmnth zrHN$a9@O~r5KqveN7$@1Zo<3d@9WsC?i%41tv44=bn_&$`DXa)MM826MQPH6Z~?>s zpcyL4@MyFTc!lC-RECD21Y)BU@io_BV5UG6b+V^jR$y|=gc@ms9hN{J@$wFExtRB5 zaFhy#Wcmcg_4PRexE`~}Ow_eYRar=r#&%5fI6|sQTxMoN;HEfiLu)B0nE_)@<(tr7 zvj%#0ZsrsNhT1~R2n-2W3e2IhwSNGRz=+fFAA{ff0$8=1{Cc@QCA(Ehi)%@LWPxmP z7na-%*bm{04BDoP?@)qIB838@wXzvAfci=I^QOtbD+>98mj50`M913!NW#W<%!}wv zuTS@~wP!p6=_?Dc=Z==*OMoNjDO}`K!0&*-Nt3Wefyf5u*3OxK;B<5oLI!63f+ZJh zXZeOYNW=Jyi~^48RI=VNOX%0hu$dG@*o{_+Hn>TSD!R+%9xpq-*8#4tqancGh8G7! zeXII}fOAZ2yXsjQAY4o!qwpQ9K{j*5oe-4>X|VJb7>3n83A_!9Xke2R=P)!x1XMxa z%Ac>y-l}7-Ql5J$hA7jXJkjR9_XjM5oC^vuP-YzYi?XjBYGpvuddkeJej=1NtR;65 zn3!W~N#i?ZznZ{c3P`*#xTPlBo&d6zpDg-f+)c<%^^9OZLD;^Lcyv5EAKXvx7LF>WRI_V%bfAN%u@FBIV3=Um z@neG`1=?Ng1;1@yUz$<+>4~5cKKg^+=!V#lUISpr69zc^ag0R{fn(Q&?OCD}lekOV z&|bMsW5AlP!tvp9F_Xj7-T0-^$$_pJ5pm%w06&VIVjf!&RYWpLDCS{>(d#DVjUSNu z*K8aY(s+9<5~X@i zgwKo+M-4C#Z!8Zs2tI63!x32rf-_KQ3kGTpVjmnpTuv~8a$^r#ZNr$K3$n=VlqE4y zzUtaGs)&HnbIh26us+0>9I>KzVAh7kSLic=FihT#umNb9M-j42CsF(AdyfZ2@sCDv z=JBJVlyt}(~$(f!z zVFzM;q_+hgST~Lls$eGze+Ca#Lpdou9Ti!zCHVmM9ommF&Ehxfr1tv+tV}6((tvZzLwpwl9vQS^AD3ncd3Ji5)W9uob|0_YXjhQm2 z(?=^PP$57lmo6-s2JwkHEQXUr4W|?w*dfupvX?~%T0fuM9(2duW^{r%C<{i>S)sib zCkOmnKbV}Bmi_xrS#2Jthq=6 z;XWZsUgk-h7)DwUL=L^@1cY;JD&S5gzMn;w;FK*s`@cZ_H_7O-P~~gwzV}ViA~8Xj zKLiA);^+|pD0~AzMIjM8o4V-MVL8D8qf_SjV$0w&W|@JF%PbD~LZ-Ug68~ z^ZGv;Pf(bp^+DN^4saK1v5-uY(85Avn3Cg19G8WRz{XMHOkn5k(kj#4gmNu4THa&$ z1JMyU<$zGM)XfXgjZQ2W-gLbtU^uK~z7tJ5Ix=!X-RfajUH^&IO#_lvW#5eH3r zCDH>Fn`fx%mqD~FA%&b9gvZ2vj%3lVX>zv{2q>C%n5ICl96E)Y!OUQ&o2Cq5XD5uY znqxd<@@;9(pKv*r9EZHpTO#*0e2;to4qX4QGZ02P-@;V&bg=`b;e1v&#}pZgk{24u zt>Zz}Hq^&FW|YX*nt9mo;3S0Oh=7ani;NsPwQ5d2e#(x)rx^5fwofkkl2_FUoXGP|zGtyzQrA`m@W<=n0@3~htv z+o1i?tld<8aqyRyIozO*rMnn~5f+xxTGp|b@`L?e7+1TjnoJ`{2lco%Uo8?y%t#VW zDWdOe1#v}1L65l(rT65CMh4D8YFH=>;ded)XQRGBeS#@&wd5XJ#1x76nLU4Lo3jIN ziWlTN=qNIURySTwhqKCf@)a%i^PBSgAArIn;fs7xz?{JMu0zFv3iSr<%!k3ng)k}; zuZDj==6~Kmn0lk9V`06%Z}LE?jF|4!R*lcc+tbxn&sXum^!#Z48C$Y{`*x@5`l~|s-Rc$k2@O#*XIRWHpiKU0D4TAze_}N4Q{{X@`W{S#+=s}ht(472g;B2ws zZ#R)1B!)Wr$UbF_w4eU~Y8zlCyR69846JQ+MBTQ&-X7gus!`a0Pw85!(dqJdIQ!4V zZ*;~6#j`(v`G-G%Q;)BIoq2p;vwJ>dbw5jL{s0sgbZg?hmhOePeQ$DZB~^2h;VwWW zOI(E@Tn*v-_Gm4j(B;gxH^>w$rLL_re2taItziQP9V89!g?l3_N;9F%1b3o+L7mX( zxCvq8?_*}4NxG6Y&?!DCkSY*>Eb7$Iq7SzB=QeFJobdyKPbUT&VI-trHVx&xe=qVI zyIAXE)_3s5fsLcaYV7LK@E^DZRD!p&-INsWng?MX((-ES_*l_+;uWKzuzgI^^boU1 zEAy|D-8Mst&egz_jG2Zjthx7QxWJ`vr3ir@%3FRh#1>iQ-%p#GTR1nOTnR-LY>;ULrNrP|N0oSSE)-4Z z83JCu!0_P7twg3H(3IEeFfla(#PyTAWo1EW{z?mhn3heOMH2z1At@-CpH5ho_S%qOt^8l|4zD-VAe4Vu;TU8rLPp#$U=@+%mwWm3eF;VCzcf3p1ULHoZOHXEGq%Nb3vQ5r-=({fI3}d0F=kqW=-TDA?qs z^!sN4XKDpGmTP>4ojl%@PHF_MM8!|!E}@XKro+B@ob)vC0sdSbeNTi&^9oGCK;1#$ zMZ%hS@4P<%RM^L!eWzRxL|cx|na-)!dERtq3`z7)+?(a=)JJbQ4Jip!EmXST9}LTI zk;9pSB=64dFP7k?wE8j+164EHjtNvI>sC!x=qZ?ib>4m177(iK;T5@=8dNAw#-%>* zSw5c)FdXh!}#C0XytfaQ5DufP2V>- z@`-c@_3g~S@HcdTwMY3h*fS3>(PK<(ej{;x!Zuh-v0R-Qzt=YD@$=QsH0hmj9o8`R zs|!@An9@awnNBhY@X;5+9luIvZo zg-Mg>rPSi<1Rj+PVIM7P$?K=wk{@ADoj%LCgY?ZFpY8{=o+HtkqQyKHyhyD@1Gmn(!8Zv>#FLKQGS}+wC)qc+SU*ETP8P;=H1MBQ_TaRrRKq;_ zX`REmB&JgzsokZGyNwSm(04Pp>6`B`ubN$sAjF}%&~gOZwMaPxkcKjFI0mTuBiHD# zPRK0KsiWSlO`FHXoPxI!P%_>oaP3i**?M*~Xjx3Y-=7-fE{WYFN!RN;s|e;*870Cx zG4bn5plp|&br=+_BBJ2AH=VOn-WCg+QPC}%{FoS5#}r5V^~~-P)%c=7+F1@e+kiq% zb1XMhN39QRom4Yp$69Bv4xV1Aaut@*|7~usVrsmEP~aJif{CiQOI=^(5 z{jj@J#^BY3jx>p^lEyCx+ENT7duTgBo|0uB$1`W7S!#P%tXD!7Ar3O2&p5(dR22CZ z56&Ath*-18rPube=Z3ALFg|Dc}+rl$%qP9cgZa6;Xzj2BS1Es*gwR{ur>15}3B{IQYi3 zC>9FI0vKUGKpCsIzPw4J!Hmcmb5L$lFLUuLvxyT223vJ2=ALQ_=G0SJz)!}?S<=#g zp|2xyF)ap_b-zzJifrlYWd};wh}&P-PWM$wiA5x$a+ImsQR_UMtK2xh{fB00VS@eb z=}0Nx_ifH*1tnCp=ZaFEzr7^>0YG!hkOKA|eeJ4%U$$W1k$W93-qSnZf7Q~|qP(PL znWa1we>U{u1Pgvn-G!hmyF6u=nO3={{sBbipGNkfs7mkAUi9SaXi!?LxqOha zOZk6{ zQrV96EdT$Y4Xft-R5->s z=1}nhGg*r9Nc?^Gp-Up@V=XD|SWIA!WMw9-9A}Hac(75O_5M@oTHqD)9zh_P<@egb zX~##P^Mu`DIqs|7OP4fUMC31uPa(C)XM`^kIE?Zi8D0|<(+r0=LajO7iug2@_G*$? zu2uD#oeqi&jD1K6|MX6Z=>P;){P6XCohgaW@l$ie0y<@|s<@+mH$cC=}x^@rssV zg4y+ks?$EE_Vn$X@z+dy--Ixz+-gLMMkK3FHwmb9>18ris|5N_u(vwUc*QC==KyVe znjwQq`+;}DpcTHEO;guQ(@eEj%v;2qWz`Q-taaB9@)G8hy-r_t$J5&{Iyw)_j z6ij7Q4dv+0$?tv}?e_dUMQ>r3@1-=F(yqxT4-(be*c5$jY7yODZr8ah+4#NNIF&wg zUnaj+T>EH30Bba1pCU|NB&AB-y-f5(J=v7kP6ff=J}L=O13=!58r&46&ApuJ zY>SV|>C2_VoVta$;ZtIv&O6}z0m$8lqsnAq&}se>@*cAtNQ7%Y?=OKD6R01e8IrlC z?ICONKHj|n;R8<9UoQ}qjotNgZ?S$R_*Q3F|4y%6zi3Jqcln6_-Hq#T7b!W1@hWpl z?Gt*9yMeOj_?!E4>)z*6PNF!D?9gIqyU+Jvl3T4x+pHFqkOmxg{QdNpl2uGFYn?S^ zb@T1jNz%!*Zql?>&exTfk_{&hk@WS!Iw`XgbV%L?Y4j~*)tpq7z6jq~lx8=aR32D6 z+nfjZpI*K{JWHDww^>`#UucwVcdJ_^6r%U84v|2D>hF5gytF$dNgG;lPV8_-b?ex^ z<*sYNCja)8j|fWLyp%cqG<`n3yK|Zl#7jHXU4Njv^!WM2Bl(tH^f9IIc~s`>IN#HD zrn}A`tEct{up^P0rRK3*LOXey&fRDTr={)Z#NJM@Hl&J-8ch3tG4~dLarDZX=$M(A zDKR@SGc&Wt%rP^^cFfFn%*@Qp%*>84W@g4XZ~p&3=iYNJ?B3mX_wAd}sH@b1R!h@e zlBzxp9ag;YvzaiNfUC%fTZW*zlv{SAg-KW$rtxq~r-L7qK&=1If7LSv2o8v<^|IoGA}=2 zj($^megiIDW<8%M6g=DR%H*{wBkm&k@wpL4E$gn&@i#!!r}tj}nHfIh@DTk=e2MT_ zvX~Q=1AS1KAIHfYs)g;@AbQ~jX|utRlI2jbpy_}jo=@5`u^F5mhi?ug*BvMaY z34wA;LQO`I0a%(1zy5BEQzKE=TWx zXA#s)U-2N6X5eP8x$yrky|TH@c0lVa-+ba6O|F($kwCw3saIlHMb{Yxz-1;)vw6p-XHt5}-8WstWaTOs zHlNivXK2^6eb@u6qSzGv*<985S;OgQ$=-OJi4`W^a*{7^^s_}3?{C0>aCCcQ$idDj z;-`+ef!c0q;%25RRjn~>6GvSfJy-P2G-|(CQW~{jC%kQ!xTx&}NHd^9RA zg1&R9)UQVRf=HcDFdv8Gtrz@Gb@4!N+vB`5!)zYe9Y&5FH7G*!u2`6B#iNG|Ib*Kh z0OTv_N_R9#DDupmY&CA|6dF`33bF;zP@w{N`88u6-DFWtY`^-<2Rn zq#&LCk6&n_zda`x_AMFVQnP<5mS@VE!70QE?3+8+RBXZ}qLN>wrJS4+QzaSYc0Qgj zme1sNKIv+nZjs#}Fu_W1t2}kwz)}6Cc8X;AM8s&9(;+d(4WlTbFx+3&7hp9jbo`~P zTFTwR!~T|8NB-b9z|fxi>r*kv3fb91_Rc%Nr8~@?M_@!_Li`RMSZ1{4zQe+TJ#US; z$MtmB%Llc%^vF;jq3wJca!&IjJB-dRI(jhKjkNzv`VtlPb=^ zk%sSC_!+~CBT+xJgZ!wNw!=#xjzo)V>KdCw=LGIk>UcQ>%_Oi?kSW@(OoPoMwFu$# zaLZ5j8}EoYd`7*dlZJow+An@pCD)S5y15tqH7)*+grSH$L1mGjXc_2ULy>ypPl?f_ zQi~WJS8E#H%=^)kHi;a6ATsrE&wF5Zg=m}_hJE`qo=vx%5YuRS2KxZVfUDFJ;${aC zo|uZm16omNtMO**aHso-5xcL|i%ft^nClWWE3Te|u&ksD17;!Qq<-b1Xq6t70IDrZ z@xjurVMU$8B(Dq*FG!GY?8a={xdn@+B^~$P%RN$^5OHdG$`soWa8o{C_BtrN9L}un zy6XmuU1z1d+O3~5VCb>?)8UfyF~f6;?~wR5#(lWs|46{LsAH$Yv)y~<$H13L{Fi!Fe9Jcw>)p{-+;W!GQ26F2QkK#a;%{Lhg*Yi_B7dKo-g*WUWnzj~}I{7>_OTjk3B0}%ra00s&ECnN?G zTyH*j#%em4EI*4$+LiCYDq^Hk1|+UPt9C)6SN(7=fxvg6QPL3{(~ zB=v8L1eGoYk!P&e+2tUm_p_zY(_<&`{4`v>xr*k$%;GdxQG+7qg3<<^ABO+Me*KF* z1+iJ6vwveR|Hzq|Zfz6mvz?A&XQzYo!|R~c+9UR7yAGfa|9|-cu5h@!eOnjbpr$_C zeN)C3oS?8%z&B-ZQ$9P2hhMTRwzS zT(dk~xvbZ0=&=!W>WcF>GLXepJv++%=|^@H;Ra|-C9Zt$s z77<;OEvGnc8_^~v$wmo!)(?_SNY*(g38)5qV=pNEphi*SBj853#f%nH0q#R$(f!gt zV^Fzo5R`BtJDU3)8*V2_s*q75?f%QMHntu&(=J`VF}<;u_)Ebxg5jK2q4nek=fa7m z?_*8%M=p^1XSMc|`dPeAw!_Ha>*~~%w|qvnjUYyAu2rL&dX=Ovy=IZXFVaex}UyPH9D#Tkt|&DP<}xs6J^&gCKt{r zZL}lmQg4`!_acJ^As^Z&G}bamCzYy}l5V@RGZh>+z9Y`Hv0YYLqVzSfvEx3|W~)v;-Ig?ayhkN(T20a2^Auav!aFO{}DScK|1 zr@(5cic4vYW0fx)+ZKJi6OhhKb3)!6J#TjM0XFiFu_!>k>041TU%pS*j*ZFC?(uD z^iCNv_a6{%F~9&O$tgqoLBCvUzV|5nc$ROQogYC_98xcNqT`?;$*ku#)h0YeTgyy( z(IjDAsZ*T*Y9i?@mo2A3yW(C*kk(t&F9nkU_XVi-ZR*K{CcNDFjG!B5CG|h`+*x zVOu)~UCn|wtLF-Jn8&adHN=?tE45@;FM`TD^sVga>z6NH=GUlAFjAHi_F_!d+;oT9 z*RxB%0Y(^k=#8ja&fk~>){U>MQ5nr~Nu9zzRU)L0r9(0pYXzdl3?~P8>S=X_r{XBRCK@dsmBJ|9u~jX{N}*{Fg;F2Z7MQ>7S132qc}v!mJt=epnw8+! zWB|q28<8FdNmA2sZcP*J*6`vVkQ~1=u_!?miy8T}48Ph9kLcCnS~weTSq;BgJ=kz7 zM9MA*!AM~I8WI4oH#G5zxX$gK;0ij6XgsyW{xZAD#^55jYu4%amO9K3IIbn&hB*$a zboS-CCQfhdT9f|H#Hf*@9Un;ob_ML)>}9bY`^a|r*nJdy{^=y9?UGcS50Po5S9-TIrt3ER|X2Zvu- z@2|Lr?ZORmRU4mNrt*-yf-$x*e*u%MO(<(X^zrflr{|eC3b0)VUvkcEUFi(49D_aOe_9~nD4Y1$L zr}&UqnIv(@P-2!k=W9RLdM~|qx)R)P#=Au9-JgL!w;S8d4;;<1O~>-cn>Y{3M>3ou zj2h7Tx~3gocja=_%;g$QylkA|PNB>G342sQhH?aE5mQ-O(jaqvO)vy0rUa>oBYw;0 zGsf&5T~O>cH93d=s;< z>J^V4WkkeeDBJ3AW;^mp0BO66!t8Fize5V6Kjo`WSVTnZ_S6TG=#3q<)#v@y=llMQ z&!&a7mWOlDKae}5utLYe_JdI3x(gsTgR~YJKc0xid?P2DT+G64Lk#FOr(P@(#`WHob2>QwQtJ`QT(**!|%8nl!~_t1u{+bAxGVJF0z$x z_%`Q0Zpj<8yfHy1cR<&qU*QiQ*KwUxq(pC8RbQ6bhJjj&RI?}W&KH|pD0w;j+c+}oyX$~BhYu|j!wvfsQ#Ig zKpvm3li3V~C;h%QD#|bFr2&2)A>or^tMK0sB%+L6ZlE z;L*D1BMmp546PZ0YMQY7mbDT7krcyAeama7TQZ~bh@+CiZ+Ob2I!O)O$@iz#81t}8 zDJO#Anv-G|@1(7&)aao3aPTB}^u{bGd|;fOXJo&kA6v4QjmCRGiG7?d+w|^wPpg2~ zGf4%+S`2bA)YVY`cZAFRQ6;7jNj4b5^!)zej4qy1HH!~FKE;jJmh(4!gy?{r)aY5Z zL%YM?xGsfb#<4k}>o2zMdP-bDA&32<-oWtL*MO~ji;MSa=G*7*5;A1&SGV7x4ovpv zlFVe!v!OSWm|ni!#$Rx4|0G{)0Kbh{joW^itL7>1PVvZ$PBlt;n`dnNiP-d%hiK4A zN};U%T|DXOxtV07PUV1^BYAjAI;a#dcdPuZnu~HibHeT3^_|J};s0muoe5=qJb9?^ zX4vC^#^WcA#}W+(ON7H5BwFn&(`#fyOb8xbYLFE{jD^jFiD&hpkKKZ9w-Q_A7sCKt z5BB0R0aMtyf71>AUFVR6W2$E})cG)!R8)IDcfw*($JB3ZDCq8F^^d*hpOQs=28|*F zK%)q7aA+u4IB*cI^Bwyql&`e;a{oY$yzOE(EjS>s#{BT7p{JN5I$b3(k!QMu4aE% z53W?JWQSJbEtm7#aR;VD4BS+*!-VZ?S)*W#H7pZTC0f+*D$vdwe9clT>bd@}MH~Ag z74yGjf+q^f^RFTj{>aMYUvmC44r1OPBV|DOr}DlXgPU)Z|&oTqG);@)fiaruB9 zucZI2i|h_F@5V^JX298TeE*pDCa-0UnCF%7T70K+nY}0r5RHubzNlG^@*PHBqK=99 z?y|3~Os)#3)bPV1Tl{P$g{0=LeBIAsY0YKoOyI-Gjg$X_ zq)oM@`Oh?tqNwA1kAER%x8Eqv8ov6#zA_M#^zo18zp(Qc7WCzF$;TyJ)#Ck9I-1L` za!ezSkgcq~y}2mt&CUDL);q<BFUgsB|{Ha(m}eSX12hd57l`a*8ZDa&75;6&D4M z;1%e`IdYfmFFR0u`-lQLI|P-&sG!vi_FVB;mh>-GPNHkD{ka^H{&H(}T0EM_1iIt| zT^FE#FIp=%x0U6>Um1amWhbfr^3qZ7J*yG%BT}epPkn|#(}(1Ro!W}8^*Us z!FwB{p)%!scvI>MSZKX1;90Vhbaum*p;mEY{p(q#r!MD%9)j9mxOL&qGimhcm8zUB zmEaQN*{Q22EFB7?UJ`_ljqlO)j1AH|c1j3^U&cap*b=b@ThOx(nnKaD zz@>)d>VX3{$Ht3mqcI;&>&hZ)4tVM)T`3f+YJ@q)#tsA9%G$^-sqnO1ST!1aAN-*L z@h2(-f+Vc+L@*-+`QoZZPn6O~*wfJ2ZR$MY;$^0Nq{k}KLaD>~XozEE7o#gJNg2mw zjz=EE8nyYPCOvf}PE;E*~_ltek5682=Ldh!};);?u^!CN841kUEl za<`%~Ea$`YxhL$28LuSfeJ$y&NwIQ{68DN__&{Chq(^9>PP+8dhnAK{A89HvP(84+ z8Vg%7H{HBttX{RzD1+!Ih@I1?=CYr-n^GI zqmlK!TxTO8feLprF;I#5p*E|4-iyXE4?|mipH1gP7yvB<@6}Cheg%c&{eg`DvZn>Aoh7BJSAh!(#b=H z<8<}#cX!Rehtlm$H4zN0n)h#uzX9>w2{)UyvR(|&BRShZ{QX6NqL-e;`Hq|6oTtp- z*{sp@qWl*w-ugOSjpaNQTjr$QlZRWTJxd!CII@*mR?5KDw&KZX43@g&dj4m6F}U$Y z0W;NRidl;iH?5o($tsLg@(9M*OtZbvB4P{8V=(r#lemRK`3Q@#F}K_oTf?~FTt};M zYIV^XX2;|CtY2d#E^~D&uTE{+?THQBrw>Z>;6!=yfv1yXPLq$5o<_!IrP|{$6@p0N zqNNbPnQ^fD2zRE#SU|@D_?*DPC@)`2MAJP(y;{4&aJrER9%xi_mdq`__UTuvleKKJ zb9)zPp25BB?OT9B!)46lKNIb-LmPXJ$yLz(n|@uT*AYKc7x)pmiz^+13ALv8mfb9 zqtBg;yDjgu=Sl6}WB6kdpVarSlf0%`EDCtVk@G_qyR6q~U#Azz8xtz9GquurN-^ii zxouf1k!l+?sO-4ru&5HerFW_ujTcgk%!`*lu z6scRI`Z6O#G9PNf;D$Dh5u5E;U)spZwdWktS`IGRi~wczOsPWN7FB#}GBPvUn{Y|0 zy2OGbLnn4*F(`Dh}%Vmf*xd&5|0K8Lzzrs}9%-Ylh`uX$PfRF`q6 z0vC09>u30jj{C2U8&hD}>)siesFutP=d>~Tc81N2D3)Z+Z&pmm1!mj_^xVVyK#Eyt z#~+3g1-e23Iz>7zU>!GFd4vlhsY-B^C)bHh)X55s1_}b$=cRkTwF$pmS;5uAy$0Kg2@f}PZ{`7j*HLohLu=&tg~T z?(c~x!~;w{7@$`o?yZ2$J|Ar$oo)HX7@bBNe@^@gMu=>eKWmVLpARy5-0}I0eQ|$4`wftN1b!4P#dPN@@u4{RV`7~JBoae_b~She4rZVxeMSlQBVq zBw|4!W>yLoVZ{$@ATY5%#bA)uEG!sy-9LXy%WT-HEVT%Q7aA?|Ai-B#)+4vObd?Bn zgcj=A)k?!pRfwvx)d-+Q%ZwEq)X>DM$V|#3J{i#Ff3!^Xqyh@go0JDIEI18P)J4$! z;|Fq7Btxt1XOK%L{HX`j(j8spk-GLwRdcSco$%j-vHmGouhaHc{o5kcYF)H(KwcwwQRift-D{-q zl7E2Vuh8v_x}Lhe({ka08h40yWMZHS$Y9Jz5lK!$;JZ88cz6dVHw&5BGoMfMJ=nYj zsTL>pcc=nC5FrU73jZKDv7@2#{mi%i_XssqF-&An7i6sv29c!PamD=-#|17+oo21Y zwx!CYMoV3gb+h&_iFa(DBvoFzx4QDj=K0-?SBi@YLsn*!kSHN!Z*ZC$>qR)Gm-mC% z-iPSF0nMZREYj_2t5u7xW8uxgx~-MW zE`U_O;5enESY;=^Hf5PXC!BBx$D$RdRyEH-O~&#?Oj!{SjZ}xfpyt`acKEp$3y;ht{DH0KSDaXO>vq_0fUrDttrghHP(fYnI^D4}6UZFm%m=YP zU#cEkYHu=$W-lEpB%;+F6~=}h?6L8L>b+a?rq{0regksJ0r7?fvEV8eGWk+iPE(yw?9InM8Wn$G-z zeK`@8+gn~kyY+L^S2$b*PL8Z^+sJ1o{)YKIaSSHtHvln+Fc>{eBxvZ5+Z*$RQHH0Y zH(QRlbzwCE;)hVIa9k&0*a67rWS% z2F&x~B8Y(H6@tV?G)F2Ye&3;pUxw_|tG0Z8&|vFcPI6eR;+iyv!F6EtYNAcwh0Y2K zz84g4(^G7{NackzvJAvV(D|0Ns*W8>hD) z(t8swvliA)!w)n6II*%Hp655m5^^kJC_BTV0hPtFJgRDOQpadiSywg)_Y~Zf89l-K zj;elE?{yg$$Jn~qh*It{5`CJG_c@dk8Ky7drI+O?$VBU`#h3158FT6D#ARWn(`0&a zsg_6Lzw`8vVz#(?qgqSiZd(bKS0X2*_lub)s8&P?*r=VJQHzIq`he6uqrD_kKuHkP z#T`ILL>wnrd8@%cD?63Eq}+v#=fL%sG`>?iUSZUBj5m`EQFXWC2BK@&G!h|5pmTK0>385yd=1R4r-NFj^bhqep(P+pB` zya`D(@kb}L@E;6_p0tj&S2v}^oa@v~6bjfv9a!x((f3%NO1;gPb&~7%nZbN=V-dc! zB8q2LvU9suiQtfh&aFP~F*)M4A}Wg{=y=ke(i~Y#%qttQ?5Mqs@@WVhmnI+MKnIO{ zD*5!#Vgi}kDHb&R%~wYk7k}5yglVOWbUg{2DVw?a6KQQ(IGBnu1w(#;dCi=1v6%S$ zX0n)7l`guqsvSGNwCW436oD~l$B7M+&MIUawC-e54{yp3u10iIZi!X(>%gteg|G3; zazmuECVcjpP1|%8|~(|Vbc@w0GmU-61;{unqp@=Bv~)kQ1oxjcm~z< z^qyY~?3I?w>5bu0Mp-q)X)O!wOU4Q!c#zUo*4W~u4C}99yL%3U5Uc%_D4@B=-8PN1 z*XcZi?CcpX0L{zswM+X?trv0o7mwf)kr$fl^{r-(Q~R0YJV|c!7Y}NSy&_;~)*@)x z7@+QQx98?ghi;p{;A~%{Pm9)P=9FAw8HpWfsA0w#R%rK*v8;L6F4s>;j1v@QSSL8o zMu`+T3_NG;jNhGJ|H8!2&R^Sm$Bg!%QI2I)p%z{Xq#gW6vMhB)3NG;}O8jG(!bH5B za>G5{{N4O8(jwJ250BLHT93`xf;5inGGlr?_r?YO~fq397 z&oF|&AEbU5DMHdX!C+4s)z_`V#w^iDie?;;nwqp#K!`0-%;t-5X65yW`85Hg^%$o` zN-NsW6V5f%nl1BPcaAwW_5_a4L@c(_^GxCs&D*RDsZHFlP9fAsJ7Fs!Fe;6gpIqYt zv4~i$Id+R6hDj;K;(qKF8SSyASBU^Ko9ZAww|i7;FOfD^2-#`)|Ez`TG(zwgz`hS< zI7R)x5xnTLFA@Aha-!d205~67S&XI)BnQ7hirGdP?Kl3Cc-^?%o^^6)S}OX4fe`^1b?_)>dgTc~oqf>@$XkDYTokc^V{p_g!K@a&` zI(?Ar$MNTMC=4_t6ciZX?@ASDxuDt5xY_M12vkx=B|~%vzwhMCg0;Pn!ivh*Mil;i zf0O?})1Ze9DY?oPtw6t4*4z&tTcjWyi?D;2G@g{A*B#&Q5v2omIu6aM%Lq`*8O zXN%2a8dgHh->A!~72ibB)iH_TtLZt2!=6M9QOi@$S6}11JgUt;AY2lg$P~{;BRoQK zfg#&yx7h|^%}d^HkudoRx6vUKc#2FXu}Krf>VgyWq45lo!7G;Q2hs?Cugp&czNhD! z4G6gK@y1$1@?xoB!SW7|2v<9j;JkOg&16b?b?JY>|1rFMb=N#UsR{dJFnhdGPdyxe zfL#tWjUtHBKA(0d#43v`cj!ee4Q@OfFApd>(*K4@&z~^o0i^+?*8j`~@%$S=Ax-{n zUJCn5Ooxbri`zF`fX!lbkS9_9wfbYF<)AHf_4G?8md{C$*P@kbVx{4oi{0@(bWBOP zn>ZUTkltAgRqxiY)nxmSfenfhGP@A?wa*fMcC0Co41ThT{kxKA zZywD6abjgIq_54dg>c|pH=l;W_f_Ji(~k|TeONsMJ>=me&+H-tL>AZ$_iqjhhXbHc*g#3~nB@7dR&$&Tvj(8kZSr_-!~DYDj+r#%r{JJ+LT& zi;k>%9P*;0ZX2#o;>OFu1!~`*_AzP1vk~P^r~OLfWj8GA zvycem!5;a*?}%7V+Adj%$@Ssi$Ri$A=GdT6PZb`bqJ|%GkInU@dolJ^IaE_V$>LBV z#6ykx@AWzwv@+6hVKbyGbr1ByXf)Xr*R6!d3&p6_;~zB{xO-gVQz{6SU?ZnBTr@6| z5&uGsqHQqf6;+e)%cgk>u(HQevZ3ysqUs~Nn$^~_A>UXa?nLvWnC_b~m5s|oi;^io zNjm8>lx5at`B?v#C(A5b2y}@?K`!;c+u1GLK%b=%z#pVu$ z^Xv1smr$;$zydVwoSv}K=H&)i*H!*A&pU7-oYz14CI*4XZPAhtKb$Qec-wEvv`yuk zAk7Pfsep%L8rse(wvzX063x{-qFz)tjr?r(|I-Wu}MNAKB z)HKR8%BYXuh8Xy^?XEM0kFck*P*#5fT3!@DPk35X&@vYYW(x9O&0PNinL;&mh$GFd zoxQqd^y?K=-2U^S4%$9S0F?}%C*#+H_p5+ccGvW#*=7CX%In!b2Gn>FZSq(;g9!=| zTMFznl9|68`Y{`5Hu;f`kqUJ(rl~~PHgxzYCvd2v{VWfRA(A%N3+QO6+0o!8-`}2C9Wx8FXh%%y8-k1?}bq z^0;diH|}jm;6GZ{%`e}3JXqm3c=oUC6)kOtI^_i&4ARip@s-O97i0e5$rL7mPgk5wy2ZrgOd)=Z67X@}WpEhHvmctl8hH`hmzh73VS0KqQpZa@v%~ zmPLOm&QUZB{exs2Ip{!JT=?};yVI*`LC^RK59sXl&W4=FiR>97QbSCpQ?~j^f@AqN zz;*(Kzpr_O@pMo}%~Dv+^~toxx~cq`0BqPQp+@xYpzqtCgL~2lyYCY^C7JMsjX>vO5jjE$>kuhI3O``|H2d_qmCCS(x*VB)W8kUm3=czGIf zwBAF|d1h@jozLnu5gw%kDf4ypN?_|KZW(EXTNaYr?xy?9yK>zMq$!G{mySHh;xzG} z7|eRyA=^2a;*xBa11q%}Ewg!5Mp+HF-J?uV1NoZ^Bkgm0-`RPeCv zdoLk#AB_}(ljlm7$6(cwv}7U~S5z6f+N>Q^*jn7-IT(Y(de1$#OsU~PdW(>A)~4+2 z(y%m}Uo9u{LOyvh&E!HU;TQ&y6heW*d@~w{n?5$GdSPhnF~*6#fU^eFU_vxgd{3xV zxP*tcvcJ-|^3bDCpF0Ff_pp?bJq3{nN$D*f$KK$f-C_iv|@QsA>Wq1547q@VYMaNvF8P%rr zJaQ~kNlmL;O}hr20<*AZc#4%h_mfT+2@wf4AQ)dfETxZlY51|PphPgd zHsVhAJ6=9{)1ZmkMOlq822&RX0$h$F9 zutTz7XUS^d_yZzO^X%x78$s_r9b|#vU_+1^UkVCbV7t^|1gGaMXu%Ff_JNic>jSwM z@zz`*U|J+P1Wk5uLKZ2!A7_B_Kn#Ec&*SGRi-kD{x~UtgK;aJ~YK|=@F^T98*5|CRgFzxYLx^*4vei#tgc@#nHRpX)0dB&Lbg;U zL;K{*B7B@X$+7^np?5hl7#hYVG%Ls;3F={AMc=sKGf5Uqe*-dfovs-D@87j-49!i5 zco~G6c$AxqKJvhRR`s0|LdI?Q4XD5pa;D8IhAmpE<^&m~#qaC}X;@WAW zguSH3fnVV+K4k4{&XxJniMT-AfT)?hRu`|Orcogf1`W7`SXH`vxxx2EC4`_jVpP_Qn{53OIXqes zFKCiC5J<7o$28Le!$=!ZeX@wX9le>gAMHHWPOvnuDtQ#SI(j3`Nf-i0lwv&Y^)zWn zP6Sz+$iw!lu>Gl6u*Y5)GBwjARkUAgA*+*h+T`a&Tyx2?B3= zY5uNdW0>R5NJyQ5f(5RPGeMT!l8tbvLD5^19rYeuM!?V8+h04AsHl*LHW16Rau{h4 ziI~wJH&T3E3M-^VEIA46#n79>KhPSqa}Hl$M)wLO!be1M86X~Efn%1q15z>>_F2*P zjU7E{O2V!1M01i82D3*ctm}v(OqM;?f`&uT)i3{w-*m>soL9FlltF*Yn_Ol?z z${a%^ioKos2ZFPv?r8WbJ}Z61k{^=68K&Y)%9`&M9+LRtt|hk4aF$0~alOS8S|4r5 zs4#mMoHG1w8w?hTd~M+jDSPW@cOF!Ow~UG%oHE9MD-;JKv30z5#C8cYp^0HtWm`WR zJ|k#KiB}PabmC^qbr{e3$0jF zreLYNJ;^0u8?3Jx-w=832tf#BaWrH?9*qSJ{p(EH0^w?J~W4_)= z_~?@I!+h~)f&^d$*Ia-#X5#v9iubWaKeZ?6XF8?QH!isv_)oG z|LP^JO0w>Hv5LaLq)?Ycnpui$jFSdFg}owp*X1+k9`ncbJTz{?JuH_k4W(tyLD-KQ z+-{sMoYECBAaz{Geiwn_9UW-flh%-H?jp+5R*-#=3+KJD^?;(As`7;rHEn|H#0(=* zT(n?a{T?oJ-4B3ySS_mPazLPguED|)7*Iq;%~8XJ`-+_LhXE>9UraM`!S_af*e^W(g0PM##V~Cogxx2 zqMajj6mD?OTUk!;2;Wgg%A!DpKOWaOP#!}#R)3TFb>p+SqanWbwhM~!q4{t^Po3GQ ziR7@b%nySudwUjTA#)bL%Y$$P$f~$3IWOH})oeb#6@T4i+G!5>9+~etse?ShVkbXv zHf@Le^N*YZ6)E11K1``1I~HnNy@mDM_EM=I2~5jN^jLSxSA4df-uts1f)om%GfP&V zw@5dw&u|Xq*B9Rt0%ll^C^skRPTGx%dj=%{v6-k#R&@gx#1#8%3D|a3da1ffVCM~N$SCJc{@SjAn_{>{>?4cCFnqLqeoTVjo8Qeh|FhHMCImiRCT>HODrm+V-1w6&l zWRw!_eRYdFY+QFZ>0uJ$bTjfVm1jNf5BX#k%mX3#6*H-TCNB-4@kj*L3|ue~6;_Y( zYInzoYQz!8XDzDK4+YbRcc4S{Dk0{V3V(KW|9Hba;+de08x!R&-S{2}NxYZC{u3sO zCD0I!{h2Xy9LE^t8HhUJ3 z=(VvF_SJVq@W}{?O3c_StjlWAH_gxK){G-__BQ|>jkz$(MNGs6*bsGT%0Ka(8yg7mO15@5=xQ5z2{aO_hMo^G@?U502kpN>- zPlvGx1OM=+knu`p8xK&gQK_LNKf=H8{rWBaH0Epj>CRrGf1oNgy*xp@>EBV6gEua%A)_&Mm@z|o)Ex8NQ-0IbQw|>IemZ^< ziQBvDk0p)&0EJ4A3KbE+Jc_9SKhRlk6zku++&+`eSPBn`PbCg|jS9vjbV8IlLnF?N zkZ}=*SaZ~s4Xb^a-+>r5;9dpKdP@Pqm=s3GA-14NFqnB!3p9*Jh$`~XJXrXjJ8AJv z^Iy4j)UAAtffVEIpwM(SR36Ut&zJy4qJWLj?D6r50uPdyYv5j0t&0A02w!*h%Zv<|pWoSBwRMZ}^G$q_E1|U=5|d;8+YlI|ZG$%3YXR+yCCu4YX=he$m)pqInDtMl==HRO%^Ody7Gkm8Znr7ip1J+$iaqdL|tSMk*&gljXb}_A{sx0+{fT6*Uv?Z0Ei|yci$Q);vpVU ziQ()&1%$=CL6K!efdM~oNLW--p)bs8ynF-mZZ*V+zLM^6FCp?Tp1Eg9VooQe?9UPT_4;~tfxkV2y7g_*zv!Y8oM3dBA{$5!U?Rf znO}p9e(t^`%<#$CnnvR~h>6(S)N%I)e3W>m7CJ=i=3`yH(+IyQYkhWmPPF-D76Bj3 zq3Bqb9||c3rcOfjxp<`h%hu2tsu)t<4c~}1zsDw8y`kxM#xm3hu$o6{Z41Ve9oQ7_ zfWS-oA7H!yyqxA8(&1gxnW3gJ`V)FYX(b?1%P+z&CpHg6Q@huV9=oWv&tj+m+E}om zALh>W$g&mAZ5X93p*t1iNCc9%lNaHq`8&(kIgARX|eu$rX=h4UCWj=qGnWexQOAEHM7snl%rtsGT4z(q^9c2%S`Idw)p`_qgzPLAx8I+#V1#y*Or5}R^YUgnm9Yye^#cPKd}mzFaW{o4CselziVn~+tnSuu z8=DC9kJm@Wa?hnbl!)%U!4X$z8<>EDU(Q41#(Cw!VBon#kWBJ$-CuKs*=`5A02F`4Mg zpZX18DMFyq^+DuOV8BCsQ#=3phM1~>$Di<8;shgn^A(pSjx`G`(tW;+Na^Go+ef5T z`cK8R<8glK)#h#&C-y^IN#q)c=cu}zg{YF35|eO;VVtp?ZoTbLKbaN@mf=$r=rM>b71;D4E-{s+E_Wip zI`h86wpYP$@6%zxWevn517c}UG{sgQl$nfXgL-_w3 ziV7bDx<&OB2%Ni+@Cx?<6h}W-+1+;JG#W(ZY)kJ~V;ik4aWgm*<^9SX<3ADFl7ayk zo^PcRAO*_l>iKTX9A5(nXh}h~zJZS{GJ-jBkR0``Dy8resJK`X#=@69WiOBJUJwHT zSP<^)FZpK#F5&A%$0#sPS!&Be23tm5T6#uyT<#9b?&Rjoi}**lmZ>K7l_z2!(}IS} zw=u;S=|FP@m$)cJSF`@Y8@~N0mNvY#5qzKO7M)=TYed=5h7thoAENQ#fv(;@%`yMNGroWXMX`x4 zQ6qP8c-Nbu;R`|n!uswd(%lr&HAmeiQYu8f65je{;s7nmR z?E7dwsXu22`K11@9#U{{W17inJ+2(L^IZln5$dODZ+Ow8iMa>wCr9c~c|s6E z>VE??Y39M_Q$>*Ng?Ga^vI5yKl{twxuv&6hOM!TwjNDzH%+bJU2TrD-T4&fG_RLU5 z2vD~5T8Tv!s^g>Fm5zCY3LczVjOjeOp2e06_?VbbC@)J)+?NKR%F?Jyho;w(Eh>9Oq|{m_ z>54LJ5`NcQ1>?SrrM8vQ>L6hP#lzi~js-h|?a{a62i~fT*pT}fb5t`61+3|( zUi!PZWc_HKSUVRp6T|m~l2+u^T{3tJic~nCg7e69|L+chihz5btAt|-1mF^uI%%SW zq}*!m$KDhdcgae%fh27kN5KYzWq-g|EQuI^a9bX$$@yJFpP1>wiMroXqs+DDE-lDx=Ixx`~q?NAD zTXHm>P}jwe+8^mbhcuCPfXD0zlAwLuf;U=~R+&nPFxBLHa4ALkbih&uhb=`_-Yw7O z7s-8GpX@AUJ(!`v$ki;Ie#i*{_q|Nr0KU|l#?9yG0JL4V>0~h@Gu$}=oIW4AD7nE?F|)YR7pj}6~_!88IwT?v!!g?h@Ph$}acA&hBrwKR3JFFYPvYADb_;Jl7tl`OaStvmSokPJ4Pk|G$cGMK zkho=YGX98~e}9Rqy^|%Fh-W5j&JR37h#F}{F|@CUs6~8nO;YZ9;9G@-WvHT|;SOOk zbsKQT1S2<22$4fYd^C%jxET-UNO&@nd&nuS`wQ%Bav7Y# ziGa-V$V^(htf|O8XfLm@r_>i{V!x0a!y{aeeU(L=*tbZAwC;k8rYPw91 zuGxp1$hJgOP-RKAy#xES6Ob>>W=;QD2n@&QEMJTmaU-e;`~$0=@mDAzC83!QjaWD1 zv$-XxV)-tRs8{DiXI8yJk`1Mbfgfl?Z$gj2ebJ;t6*J4PLAaDeremm{q1mKyF9P}w z$03I*Io3&cyWegjj?~C%b+b$`%F6>|`RGYfEZ6nu#0)w;1B%yh7m)obs*ldA8te)I!c+m6jV$NK`XV_W!4~uMDaq+R{C^JHbP6 z3-0b7IJgEm!Gd#ecXxLPZoxSO3vLPS8vNky4jFFEyYIevGgI?tx_5Q0)q7WW*Y4`Q ztJnV4_c_uG?ZXQZfL(cA&sZeLTPHhv5bNY>P8xbb^tuIZ`$+Jv`av z!eOBBzt6(-oCu;)XWZ4m61Cf?d+KLXW$Uu2x4bV{uF$o4f#1bCAFHmrm~%#l;jukL z)~W5W(1?-?fvcjX=|j@J)U6~H{lR){jB%kTV2g;Ul`k{2;IvN6s^c%$s8NTaV8mG{ zX)6g|*7ip7aA^NjTS!&Am9y$I_x`9#7ltzL_KlSA>;_=m7Jl z%9m8@ZW`8bwt1xp^+nzIN3e?j1#EOL-}Q;)~NaD8l&!{OerY{MAN&h>E) zr^BEC3Wk0c@1e9+jJlzUSr7Ju{%ULVHf4h;idM{COcY?{!Z`15+CY~y>$W74tZsuZL!gk}%`7tNM!{=C1$^(IrWXM82Z;|z zPH&%XC?n)^Be@}<6QDA3l-mZ5#C)SdKp>6g%@xjkr_WG?RQeu0GpZ+lDL(c1W zPIeU=U5DJX3$*n9T=4%O%Aup*$c>spS-^TBLeV7sP=~W+jmY3g$)XJ0R~XUai&!{d z5X{de<0q@^K2Fty1nQ=gQA=iHOYmAMxy`m>4;2vQ7h?-JWdvwsl#XmJ{D7{?10M)m zW~&+dkQJ0=j`4e3v`HucWwcsgmVf~!7{lLkQrTIuH0*x@7$_yT5VAhjDgYsxeb_4{ zQ-oTWDtt6Szr>~TCDTbh)4mgcnHSm_05dVi4V$X>wwOis7_7-*?kyhnh6s>z;sBm)G*aLqC^40H!6Kc4WLq-t>XC3E-SykwbN=l^6)63IM-6V z$cGAhUU*IeePN?Y5R34hxZ+!1{Cei$_(`1U7PWQ;i9xRfyT=V*&TWHO%MxF14gky` zc@H>U2o!X2j$p1UCV(UF_H=^xCN~hGZ;=L*1@5MlB5-pP*RZqbfN`(pFW8s7pNvHI z=HOWona(f!dSckqqiF99R-li)P7G6${mAM-&z}ArTV<1$b=v?%$!g`C5Z7Gf7t-r) zB~-Hd@PUnPH3_K<1|M%TVEoir=9fxhZ(|?SzW@?;(B>2Wxry`1%NeGJ6AV({*jtje zTNsIZ;^AMwX>4MDaU_HEy_p2CbmppKbDy%=@C{dketO~M-aL48&%W+jzg-;$f5ax)-v&X zfMNAY%d#a{-yWj@6k6(FM?ye3RSdso7Z`ZFuhKzFZbow2LS_Hso@(vvK((CkyZS`{VX^o z*&bq1wlo{)sZEZ8AED>sVMI2eVw*DcAH?((j`jj6*#1S-)JvbI@@sh!vCj0Eh7`tP zniQrvkWR4GbE31{)Y~oD`~U1eNkCvWM)czKe_o5SGDnw9$+Ee!oM4%K!2|}E3&v}} zJ>%}e`LnA89(&xyD`!H=;?~*R4IM+Bt zt_(K#AiW>2*2^RLYy0X%_#)TqzHjH)w1`8o?0TEbOsa~}bNSc;gLGm_hQ6nA=osC) z3eLJ6CZNvryIbY=kI_JCyrFpVGbI9vz2^Z3kq$rj9+to^tr*)G z2Fby3x^6i&ZdBY_MtP<2>XTP|j=QpNy~LO^^g}QD;lbUxyW_WCSHkau`EB#C{joG) zGxDfp>BE=NBFEbt>I*J86meOYJ;AYja0R%69XWi(2cL$q=x^m|&|SnEC>`)5yQmTH z5(13B5*|Kq+C&A-dDS>gr{1?*oFQF=vG9+RnXK;uTph)ich2rP#xvmUgJ)+>c4AaU zNIc_jdcYIk-k6(j<|#5KpL6&2SFvn?ndzg^%bDlEJxz^eH|DC={xsatd zAlFo7R$p^^SA3XA01KN3#Vs;#I=a~Oq^dYI5t5-3uG`3myotv7i%7r^7VG8?XU)&h z4^6uJkodlj-GT*}x9{!YB2hMi*>1n)5I(+r(`%S8#%UKkYGs<;8{uppb%ezV!uA2B zp=W$y377$BOhUm3jH+akjtV4J*v-f-lO$@JVz8;JToW;AjoP<4&K{uaJpvdRVXOrd z@FVf&3%U&p>0~I9wEVb=uP%*7K5wnm2j`88hmqHBPvu_*x5J`p#WAjWLh|Xs5PJ`r zB}+l6NTc3A@zj{8l$u*?&|LVhDTF00!cv(F(eI6&?7l=TQ;DHc_tHpj`}Tv$54^sN z*A6{zFT*sv@a5G)5ym3U7hk|10=sZDRj}U1>X0>n7K04a6f6Pq(i>5Sq8VN})@=V6 zJ$AujR)&ItTzDm>nmEEv7G8yobaItMRKPAMy(%A5o(fuh)Kj*WDvR3TseY0S&eUD##}!#{FETn&X*4EJiDuBtmKc@j`#gQ zLR+)zb}m@RY=rmODLCHrS9`JJP_zbNqhg%sBl! z6xQ+M4S4CR&dW&tz2r*xZPS|FS-&9h2Rn{ROxKIS9;5(-d(^f^(4pJH3~nRrA@6Z* zlDJc=H+GD&O-+RkHpNUyvlk$HgQ_=h(FB+P$6Blrl-+E93GM)y7jJZo1nwkfF7Gr^$roGKja#;^AJZ{B=Li2TAp`;)=wg zG+6`EC#*p(vX-&$)bv}WrU8zT9_WB{vwVhA7emM>%jw3Ug68bjwD9xgi+Tt<6>>I`=Son#HH-wRtV%N}@a~-1xCZGTZVem<_0-j(BK>N<=7dL`V?qsJ65?BRP zT~tP|CLDKpTc(J#ha`e@-e(T?m2?dVUU|zHhQ!@B%H+81L=y}SUtW9*z6VVt1p8?d z`E&!$O@DRF5^r+#ehryG`GzM<=b?0-xyeq6WvNkljd|*Nd~#?UH)usfasQ=g1nbq; zak=YMV-_{u@XFqZVL=itz{6_1MuQ7xkz#ZGvCPL+>%Pl}SX&4B8xsr5|K%(_I|_va zVCcl?QJSe2MlV5)1>!eCKm$4iOfhJ=F(USXgi4VCY=^`Yyfvm+WfD(LVyv%uchb9z(#yhH>_DgIr&gQG zL2m(q_Zx3F~s=Sp$b5ChOHnLkzVxR`i7xuWn| z`nZe4M2)(yuy#T)Ik1-GHW2`0(lJ)2q|NR{ zfFD_ZrZ~j!Z32krRcR;r^j32JhBC!*Av!F`o@A+5qCkVTi@q#8Y?^PVCFU zdL*!<$_WbkWOUXDP4s{>xK*6Se~2Q~sM8a#b@V;8-T_qFrE4 zZ2vFdpZl}Iod4%1b2x6J62#}+?ZPRjrRUWGo}Bq66l-7D=B~NnjZ-M@pRHdYp8p;e zddtszlPUSXGNJ!e33W_-lPM`Uzv!9zmrCec=;$ph^bR#tvOu+5lj;8$+V+5Yfvf}q z1yd=zyO@FfpZs(SZZnbPArTqjx#8A|13^bDDs>1w{2LvcC06tdz7h<28KdU!x9VZ! zaS(|6CG;UeKWH4aiKUllw&o&{Gb4kZv}ql}2EV=o(ZN#EUYseNtA1(X%B@$6{yfa} zjtHnl#YX-9N0w4{`Y*WR{Ua$?Q_L9-JbY>b-%o1*+A;$vLlAa z?|u#ORYh;cu;_m>XeR9Q%JTmLL^HYmlpP+twe8IObbA1Zw~sF?I^2JJ^ovW7zqM@m z3oxXAa2cIwR;+rW^=quWT1x$|E+^U${A{gq(Fxy~tc+zHsDY{(luXzv@Ri-1OT~`m z;BcI0OmcfrMYr)0Kc~Tn%J#K>D!(Fl*4WXlhKhN+9hgxRf%Pms@*>TT#N`=+%Fbq` z=EG%mTF8bU8^^(c!#7s1Ac4##9!9X!j8LOBPnA=R<|F&I%BXcYP}Y{&z96)mQ)^8c z|Bs><>8+7?@(G8{+F7Jx{I=}lKdPKMDu(|T%#u?anzRZ1t*6(c=(DF9wyx8b&cA@R z|Hlt#@%;;Map)vl5ZWAb?j)Oxo#;Ay`>9#W+kTZAwo$vOa=n=;QAkBfqJMf(hpYYz z@K-jXtIb1>nH9y(%s0?n;!8t*7?RN8QcWeuVpSdQyTsZp5K9dNL9)L&-CusQd0|qj zfDhz|!CpA@lIUk$L9O$9EgIQQe!R^SM)JK zGG=W-SNBK*ag_FCgIyp+YRohee` z6!v69yWWU5$Jcr8lI>4LQ?FbV-jfD{M0I@Ek?y4jw5J?CLsrNh*$3)D1WvRTM65E4 z=6B^mElKjDtJJ)%=5{60$zdpQX=C$A{orZJbQix!(+(b30-{qBsrTSAZJL|?5l)#jbwfKtN)76+W**;-;Z4;)a0%|6}I2GO5O?;FM?plMmFk*d0aM|2TdW>Q5;y=*P< z1z$1|MSM~3p+_Zz^)*eP&%#+xYeD$tM4MgiqWQP=0&4U2n3DP`C&0WPU0Gp++9?Q= zl^~72nZI~n3n1%UI1pVO1@0X-VYf!awVR*i^!TP5sIjq&naHtp>s}%+d+J88B8N{v z3)^F8!9jEqI-T~Zl+KeoE|mdRDV|Y1E!hXiWe2r~Y`e zrZT4n1sm4TE#psDK=~|_nRcIKFYJ14JC4=8Q-)D44w4C*QOfA27A|fY-(y>^(WTNv zMMQeu%-l4W8Ez%)6zSE>t$Af4CHVfhdM+fSS`3^em~s`)<-6e9PrC~8vTo!H?}Od^ zWBs^Z)o>iJGRJWEOmkbW#}FwpT4Zr)&4*no1GnH4+){Dr96qX>m03_!c>@iwm*YWg z7N}NKwo}8Z6HJlp1b8V$IO9pj_6YBaoF!)lu~7_)zoyV?l`|qB;bP<&+<()gnXZwg zOpbV)K0MO=*b{*H&ubydDM#M5ur%X)uzf3)4#R)9Y+{g9%Qr3S!Tnv`i?K%r5S^L*=U~qkZC=q)qV80!ekVxJc9K zIkF&W;*b!;rJp6gI1SL?%YXAKu-Ro$fz|jc$0CDyzr=Q|M#V}Z)0i-uAv$y5ApmX2 zY6Y;e3n{U-WbVqTi7p;;Qfz5eG3I*|MuY6pii@12=<%l|k@0cd#EU%3NDS1c5Y-NR zRJQ^t%u&?ES3eCHnT8S5c%h)^gjiv0;09+SU@E5~H}sbe@{i6+-hVR-(zPFNW_A@a zvR30kQKFF_N?_r7;p?QMYO@mvUpGgekH(zC=YKf1k+dZFFfs3QW%(+y*5Fsp`TPEP zT#-e&lFf+vF|n*1#4QRWW}OX~x40w!VG}OdCm+Q@auR-I|!U*((G*NnjB z+3z~Wc%v)=pIct5j$C;oH*=twjs2saNv6M~lr7yendB4HyAm?!Z?8x5V1y>khnNCu z)gKu6rPzv2Ju>q}G#uPXLiNbElOkv2kIHaV*Rom1p7cLkEbWHtMmG(lTqhNXE1!>M z!$pHKI}wz1q-K2F{sKbOo2`c)n2eUr@h;6?rA8H;O5`u_3p%g)+m54anMbV7mfW=8 zW_xv_bL`K(Vw?EYj}3l`B=a`AP9BUK@bmSXzILlv*|@Vwd-4%?a?52)7(>r%0>2`6 zh9TK}3do(&RwCpEoVun}9OBoBI6sNRhfS5Amo_qR<%xgT8eGOU1m*F>48Rk{@aeI6 zh*O{t(1|7KuX@D~sk{L)p-DB9TBlhsgt+a^=N`D++1Y*Wiud%x^UpSe>@L>65{WUJ1>fZBg05qL6JW2e%HhnC;ZUy zeKkgkTNK=7X5kLL~#FQE>(fL@AB@QrF0?;K!F4&$v)b1 zgaOf29xzv7I{rL!6>=5GB0zwMfiYK_78KmlVlyit!a zQi|UuSPh=SMfG^z?IzQCgjJur9(^k!vU4E9PPK)?2#(?-$U(NR?N#y7SvZ+%+`&LF zha@cx{9B5H&kPr#%CoE)@u+@`iS#H$p`zJ3zDY^QKSzUX&aiY0kuc?g zdko@?g*K|9f(9T1`m?{g_DVy|5-Dkn2!aXcISAO8>*-w;;)$GP~VesW7VD!|pH znl;st;LB2m7y}jALlec?aL$Dn(3=V}kUCi4m14%sA-2177g>jQeb24tO%q!y4Fmx>5$ z2g9%lkxU{ZE8s92N{9m*FdjNAxLaD^2d`O~F*cc7*2vZY?58Cos0>3=^Nu?(U=Q5! z#8#Oc*CtwiosLdFp=xs>hJVIqMc;U8t}XJbAYz{Lk!;3o*hzOe zr<;AC&bLJpC#f}M5owb55F)KrEB04}KpqCjGc06|p}r=eq)CzOr8R+#j~b9g7E)Co zyf5bOV+{|_LG*Inq{QM&{7b{7AIJ3Rn^gU$T?@6Gm;fzw?p2$mdOi_*uq2b zIQaFyg$77t*Q4u#6V0q>3)s0RuVwdwHeWEIz1qz!^0knc3OB>}$lA;&RgDiw`os>w z)xLQr8hFPk@m5v=DOx*4V~H|OKNmiB{HMcoC0mRSM!@hSk5P|XeGap2&gYtJ; zLhLQEDOCx!1GRDsl%&P_YDsO&h`<&PWB9qKZKQf-guj3xneKf}-osoo&6S~Khs#KH ziwt|(2rgk>P86EyA?6t7^GYcJf%4+53vonxDqcB@3{wP7NjaBe9K7CzclMtS&HNK; z_#g&s7A;0&;Et?KZ=T*;o6zG0w51xt|L(M+Rer=ifU_f3KNe8m>$cJ%Q}_YKDKQd+ z<&vyy_CA2=$b58ENliW#rQS9CmP^|cRm5us-CIlAW$n~aVG*jvhH^_uW+#T5ECdGGATLzz7$QqM-$>NPk8 zW+n9LGtagrXSE{ZWNKoui)WaPh}rO$(^k-JOO+?y0ZP8^c?)V~q(4W*Wesp7bKY_b z(|AeJ$SUb2?#JTI*#<^5Bhp<+YyG$$rD;l=h`!^(Aqd!GZjO@X;~cyFgE@efRos6d zmLKFJqlbgTd!z`gCqDYaEw3TSoc8DHC)9%WkB|n1#(Y3@wcuG+GR}OF^n@|b-CuwV zO_IX@SWphgx~@S*69hE!E7$|Bxnkx%VhyctAQx*@vullIi$n<&GuybKx8)OZ&9}f@ zeqwfF5p43IDp`OONTIo!2c8Rk$r<^`_`_{&`jh&0qNe)c7KeJ5nP8O;hxuPXJkuM= zaN+lVY{hJ=)=nWSN2uPZOaZNR*HA_2BHf!}shF)23C^MRXT)(-aDc9A|PObw9r9C z2oQQG655Bpckg@md-vY=e*g8Y|N57=v(`CtW@gWxJ-eJaGw0-N;_NekTJiDI#{dEX z0D$292RNGsJOo@OA-zOOeEAaTC33RM~suQnQmRbbNlA?o1FLfB<|ni z5#`~$DfC!aR7ytfq1;`;Cn`^5RU{tB$@~yPKt@hZMM1?zL&GM+b(2fxe_YNw0W_q9 ztVAM&1T=sPGz5e+1ZVF7%;!p8ApD{3Z-t1M@FK~DA4Eoizm?xe0Kf$T!iz*_Qvh

    #x&IxvfVKH^0tK4K4Yl?$3|e4f3Tg# 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 b4KuvTnYhXvbrnt8{#~dvL+$ha;a~sR_edHx literal 0 HcmV?d00001 diff --git a/apps/scully-docs/src/assets/img/showcase/configcat-01.jpg b/apps/scully-docs/src/assets/img/showcase/configcat-01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..882491ad8d5c66a8135d5702c91653f36eddbaec GIT binary patch literal 41882 zcmbTd1$Z1ilP)@Ddraflj+tX-j4@{Bn3}HI4FmJ{2MY%e2MY^?g@FMg0)g-d9|Qx3gp7!Q^cVkC^0)fmS|0%c76$gO#Q!(? z(+fa>1zdu~K!BkDz)`>;P{9851MmPJ)

      _g@4K1qJ~L{bAAv8z1c7*#C(S{=tR% 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%0D3YS(!S5QPSGBz4m_JlcvO{s`as7 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 literal 0 HcmV?d00001 diff --git a/apps/scully-docs/src/assets/img/showcase/ledgedevops-01.jpg b/apps/scully-docs/src/assets/img/showcase/ledgedevops-01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bfdde23d131ce2ff8d830f5675723536f05dfa3e GIT binary patch literal 58326 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 J_dof6|Jmy_gnIx0 literal 0 HcmV?d00001 diff --git a/apps/scully-docs/src/assets/img/showcase/nicolatoledo-01.jpg b/apps/scully-docs/src/assets/img/showcase/nicolatoledo-01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9001cfc9381a4edcf45a8257c9ef7a4c4c66eb3f GIT binary patch literal 43545 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 literal 0 HcmV?d00001 diff --git a/apps/scully-docs/src/assets/img/showcase/solocoding-01.jpg b/apps/scully-docs/src/assets/img/showcase/solocoding-01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6c637b459e5dd839911983e0c3b1d5364d175442 GIT binary patch literal 52497 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

      lLntKL}*j-g=!Yp^Ks#8ksK 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

      >&f>olz3#^SB|aDSz+|9 zXE=9F@5)5k*jm-RCU|k{w7)a>hiH@vmDN3A?Zod{#EqN~Wt4$XRrqcMPi;y@Ka=;b zXoxDP!-f_1C7Dd%T^#mdFm<7Kpsjxaq@*@l2c~dQFXvgqu&1j-4Gxy1!YEWxhWc?5 zf1ujQvZLNr@wq5FWQbr7|I4-((uBv2Nz`j8U56g}4M|L(+|bgO~rZa$~VeV6)yejvLW);x5|MjfMJ5=6qDp3ZYR{ENI+~ zYKd}KY5)eY9GRDDidEIsmfw?HAoo-(0;OK%0)2(EsX#m!o!z2*JoN~``YNqv1Bqas*^V-T`Xtyf`l26QU5WQVxTRoLrLpIPT&%D- zXLd#V)}-0MYx}L7`ieRfM&vS!j7!dIjtS*CA$dUVj~YF$S34g_WsPO)_f1Q+h{I-B zo&$%R{$2v&43mg^aTeQEJ)~)A0Y5mTF}L!emyzJRTy1et#j~CzNwWTRtO&) zBL=y2IjNsDI}cTu0yEEQqZMtj9)#4E)a&N<=wjs!N+7N#v-PLH5nzK`*=6ctILEX! zoOoNDZ#=L`Qez9<_rAYQJarnbT_!qw4xv`K$KFJJr#hi@>~+6%$}hl%1|&qGJh~Y2 zDxuxmBXsP)b%XHM-xDaj{RdBH8L(7aG}YDCFn%$#2O_L38ZLfnYO6iJsYKR94wHQf z`JA-&MU?iIet{vnax}_Zqu)9byDH;4H2iNaC%15O+tKj-hf#zlPg;2KdD|}a|FU+} z39x7;%}TI(qwQzibmH18!KIicAKj9xdl!1&`&R>-5{+e%aA$TJ4eFq9P(_y*>v+O( z!>g1O&D;fX)CAVQs^}n=4~m}Pw^eDI_>dHSyn$|KHA$UUHNV~T|GfmSq?| zRz{VDySJ z$lkiX&>SJ`$%jWV%j{wfrJ0~oks`*p*2j_Q|6WevF@VcS2cR{E#-vm)aDT>g{RFKDay~q0O+XwkI!SR$@C`X@2z`*h*eW%d(F7s2Au3IY zh>*1NY%BjC%k^?KoizHb$wGHimo2Mcp~8WaN&q+1?yWRu1pHf@RW(tqusmi|K;z9j zRG#R6OsD#R94~*$>EbGd#uqQ1(uYX5DBF3R=6wg7=A$I@iHZd+>gdf$sVA({l+CK< zQcm{4TAyx2<2D&bepGI2e3!B)PICT3a-|dSSwJu2a-3}UFF<`~*O!}d76Tthe%sBM zjX&(=m6{MgtkBOkzK}R;iN(=%zZy0tpPaSWrNx7)+2rOPdJD)o{fuJSg`MSn#1FO= zw77tUtgF6yi}h<#txTiqiF6IF85>7e zVbQVdnz;i?`f#as_I?1Ir6%Id^s<~^08dTPiC2d@*HTkoZE=YSWiRYS19+l47Ef-X zRBcz`X@|c3+stx>#f9i%syo=ps>N< zzU_;Vu&AoJJH??iqu5TVHEDROL^Pd@o zdUlPT7ytBMsnAjubC<-I6a9yuq$^G46Xn`Q)cxiN=^~+|=-*Ie?=(eTTlh8+^@ zTz5eQ$ra$3--pBH4=b)dOC858Vd9r}`Nx|yflyGtvjpUgyB?pcDoBgjl>Y*RT_9_z zJjwWJG0ZQvhD3Ecy=2c?brgoS{Innb-sLW)IJGe_ zrSY;CALXMu7{@Q}1eF@)yJ~B`)BzMWc}a&n{O6;|il(fQrf4k1%c!1!@|()<1MfeM zC6{*&=p&vhRm&YNwPJ4-7C9;bLa}@0nK`Km#Xf;3ZL(QNUN%k!Kr@coKUst(DZXG* zSbhE3P8viiB6o)f(!2Sg|-#cVG&V7h_@fknnjy&O5(uWxxxav{T42c=>#g5aBXd)Wc zv(F13NHRuDwJob{Mu1OcA*Bwm&96BWi@70n(Vuf6PmkHnx-|9UUzPDnB3Uc%cyhT+ zrkHQ`Ox%r@P7U=v&)ucu8Cd4(csX!6XDU4V8X122WEQpIYb3F9L8h9{9K$b@VMW1L zE7NPeP+DolN(ftB`XVvNVlQ$GU`7BPdSaa80di8HQw ze8!Eoopo1NJk1X~2j%xZCx)`a@)w}P(X3i`@&893=2$;IwtN}3zkX4=gGsspoIh}! z9{>|yHR^x=s*OGY%x~!TKmJiJ0)U4VK}}}Ve5!XA0T9~ZOJ~-t!hM)_ie~*b{%#Ow zx?AxntM%K*5LPWuD}}6>45D|GjEZck{w0I-?IjhmfVmE z(h*4YQk*7a7%|OoM&~|2mUq+t&sD!tKzjK;H*c@^Bk;RPT6L@$Bkjqf~&+x?xy83;O+twECO>< z=olPDv2)f5A5ji2pi(C4l_n&D^1kZ8pnTn6+-YjpT2CcKnc~bLt!o= zQ7=KWGo=4%#$}D61a~YS8)+Yf!kk|oO>!Cv3UOt;?QM%wZrrpXfY42?4tjmtexz+U zF((vsa3wdf4b2vdfmEj}EHB{m8}pD(Q}yTxvACltMw3v&SF%Kp>SYNFsLcp@Z%It; z(qy2C5dCRM1p6f!W+CBBtW|_LgD7bTaoh=jgb*rK zPCD6dzdN@xK`o5Ua6%0US~usyjt%JrsU>_R0Hw!|@zME`C(-QIe(3qUq9`Ys(!94B z#)rWVIy0WkkF;zo=f!tUI^E_>S`Qb5yEug)zfr8y^aSbS(Us5=UrNpbX;49qaZzw$ z&}D2p@##6@Fwi<(iN^2Ds$-Q(b*Le~M8Z4KEajS_GCxKr(Zer2iRQBzl`|n|Pmn}* zh+iUX=D4=?u5`=`>Mg315C&|=SZk=q3(&5WuMw1vJh^j)0JOVu%BYljm0QQK)(efG zR8->mmD4{Zu%P6m!g!>M4;$(GynpxXYL0?+>m?y`4%FVAjvRlLQl2qG?#9zc*Yr4e ztn_g5(Tgmtl}ky9)5F}K%CEmpZIg+Zb1F0W34#urxr8G&LF`c2-vd|S*FPft0xZNl zV|P7?Po@dMZ}3sCApcz3@A;Y{#5#1p6V@hQpp*_E*dfT z%|WJNLh%Uhc><+!?AQg4vv%9g(sFTyKzJN>RdH$nJWAZDSgY6|HSOTE4P`AxpWb)8 z`{((nRu#6Jpg2oO!gMJVIx%b*M`e6o%&m@|Ge2s?Sq;as07O*_bIf?cAQ&uF%urZ3 zGwWtz(w=ltG5EM(t5E16#4N@9pt}P8pjWPVB5R(M1i4%XZf?jQdLZzUf z6iZLCM1XX_A2?blgbmSzcplHQ>GA79P|!91Fq9^WpI4rlJQo4=8DJbvj-**E{rie_ zdQSe}Fv5t|p!3PYuz%dqqQ#6?5GSeU;BbI3X`v8i_`p`oZ?=)9DMVw*irs>7cHBV- zL;DUfKNyxfN4IelBoEWuzqrFDbDnW(iH+20t-pvM)3vm4bI>|Mi{4o`4G3X}KE+@r zkgo|nT|AZS>Iofvmz`4t%3C!}5z-GPbHQR#VT)4SzW_JAOXIF36Z*EuUDwem3utG& z7${>Yp=?6|B{S#b_YcaLwy&Lptvk*6Jnuh>1F$TEsFV^R`Obsq_qR54{xvi3lpmb9e z%l-WC8m1wRcq*P}*9@(-(DAe=S>#+Mx=9C{>Cg9YH_=L8^ca z5Cm^PkDmYhcf9-V8}E&G$5`xa)|zXsx#s-lTsw2G>}>`C2DU_`BW8vu-|}=7&wZp2 z$U7)POHOTY>z=YA*Kic#Jf~ty1(VjCEbgJ2gXe;D%^RO2y$h$UwQ;9-!smetkLq*HNyP0DWz!NxG3 zS1j~5OXq^n8lCGp2 z`9#Jbd^V4cA2QF*Yp@zB9of{UrCYxk4>JMe!&IQ{2<&Sh9ZWw88V*Egp#l(qe*P;r z_;8?^BtStVE*u16WzzyRX@@U+&KCk^?w!bBn-7$3LOL}Hf$Y6DhCw7ZNVU@8l3`EH zw4qrvov)7r`z^?Cs1Fs~Ya_pmBm$QQnb1ZtRIm;FEbkVfPFc&>iDyh!XNjM2F01i?G(_^@abIEYo#`P zRv}-<$ux}7Our8lrMTQuIOO-?_Gdw5rlm{f|12!1aIASgACw%saz6FuKTC?Wx;Chl z=YZR(Ne@G-RZfv_etQ_+zLIM5S-(0!=)xKL3ht=?D-Cq+0`qj9|4&%|mXg5$8?5QD zvfDfI?UCx?5u-2l^Mge<8K0o=f#EH8$qpop`(hs#?X%9oH+%Y|j9`B4X>YZiVfX@x z-h$B**XdavzB-@4>Fy2jcXSNKPqObV%`a~)Gj}*eP*261sq?$TLVS7sFsGDoreE8_v4iZ$Md;h@0K5e1={s^BQ|dtdOv{ zN30<9Wfm+d2Zo|o-Rvp{f*(FgWq)5Gx!a%lm^%=tG#}UW=S!JnE~Q6zbUl)`B5c!% zYk%8_Y=0II6<(!G-nM>`DEuGe!!0#tg)X3v9^m1tGOQ^b0df~aM8yg3du6_f`<}C! zhe9UKEOlae@I9?va!t0Psh2Smx9LljUXX7FubcUI4%$d$nZZb3B+xj8aGx?!u<)8| zX1d7Cbm@RPy?C7Q)xsN4midMtYrk<|lwDT0e8V}5kKU4T`eEU@s$RQx)h~#zE)K0x zmNb05`X$sp+sy9|pr2$@Yuel6pXMv;ou%kTB_|>AMyuN?^Hs$$9{Ns}*il+8kie$R8?RzVXS( z{(Y3W2nVNw9umLsRuMTa&oLRsOdkFbmAgzYAYCwPUHwAY9@U1Z7-}cAm6t^&P1N}W zMOfUejeG~nGs$JY-kYa=+pzm1!;I@#yHs8rHKh2uq=(W+?SdJ@2)>1|^W(5lCOR~+1^66eHKAX3CaH~A^i#;y0lG@y27CV~vuQI+I z+tE{bmJedfX=$;&A4p6bFpL3l5Ft4`rHY$*)v}&zQ$(wkG%*E7AN1L@2Pgk2G#nt4 zww{wW%c*!rm~oBzOyrQQMRBic>+9mJi0n3V=jd4R%Z25AG*OnxdFRm2%qF=(aj=^Jp2Rk+>cKN+65a2>=K_-J5Eh<+WKH z4pVhovkYLaEN&BCu40~5_ImufOJf5&xfj#Lba+}mJdWfY<;7y$#sfSTN@bu$aSWDc6`*g zicGdQiwpiRw+)f1_pX2>GHS#c=u`IUr5{c0iMH33N#?tojr9GVn6tW_uMmA;MtpYV zgvtr7xJ-5({!&YUPwBNH_5DaTvf%)mGB-l@y)jqP}vc~n6*@yR7S!J|}@Z?>EP%S2X(E+~(dBw6XRb@b<}{gqHc`YUOIdvidLXaah5QvH{D=_1Tk15}(f;yu@)F z*@>u~J;!>E_&HsVL^2j|E86&nj$eFNEx z%^><*oH^% zJ9;M4*i~yxG7c8$O;wdRvR2Ko5`AqaUNq%wqiTmN`@HP)G9QvD=`2(vIoJ3P{gYgE z?qK0AMu+j~nli=-IRBg{VWp)Ts?lw)Wz}q~Fi1A+uyEt_3WqTyvs0wcJiI3FJv^+r z0Pf@^+Q7b_&+z=w7juOm)g21-HzzPU^bcq#If2vmxW8Vbx3vfd@ja`Q;}$PpnPZsM znJ$dBHNnvN&n+O{Pv!)@hm`NR$;jlo;aQk^P{*rR^|2GOYmfePK+~7Z>8HN%zMC=E zFV0I&9|1Er>EH62ch!RX8p_}fbvY`#+3Qf<`h;RLm%GaE{v4<3^fV~5IOtbQ|LH?z zS$0MbgNqd`!Dj}1JLUEhz1`tOI%sJ#Wvx?ILTarY0BqUVgfgZn!;i_RkU2&-F=s^L zS}t-Tq{k6MbYUN0u^))To|?rDoHzbgxH&wr#5RSSf^;}8TqHOA?gmLAVUo-2r`S(U z;K~E=>-2^jOGhCpI18@WX}P6}IKeI z8v@9s^v{nv8G(WSlWpET-Sk!VIb?U2!9bOMxPY_6W*KkYZo%+=J`}4@_$4( z2lKi2Odq*4AF%a2*_MqwK9wT+x)i+8sNih-9l>p*o56vY zRA+N71>y=E*r>Dm*)^7mE=|N|2P1Lqv|Y5crwSi=Dw&FHi5z@MK#MRWn_LAk@1Hxq zvhGc5XPjZk%_?ptzk3n`sOgJ{C_I7UzZ@=)DT}RZPPO}}MWDxM{Q%r>WMZKx1esWM z-mfg&lIVr9`l-hN{+C`S|5^*=VeF!u5^qX`4$o>7f9wCzu~4kVe3mdxMX!HyO;n%_ zht!vwmyNqLSX3gA{GTn5$Chk6dFHR`aq=EWN)9F?AteEj{7l}{lR){T7CM=!b{f0Q3*BPL7j3*nu9t(2`W_uJ6*IRoT4m|?P53jyFH8A+2OLNo1T&@Hx%5)$DZprD?0f=7z27(U6PX_NUbPn%*eT<| zI4Y(g6@eG;qN5PHnjF|fBODJvDf6j6Rh?m!2S1SR9dCi`-MuZ;+TFdLJ>GqZI-B{} zue#qDIW;qaq|VlZ*b;C)tp3=9k46ORfD+1t572mC54EVt$ZeS;@E7fKmT%RfS_%HN zZDM=6y>_2ijEJ`gw;Jbt0ufJD&Gn=xc(}pSQ-Jr&JBPiBDeDdttzXbwEj&=qrQ{%` z2ZOGKtRFtS@n2K#*{tAXb9t%4o9^aHHsdv`G9FiOIz~f=+_4iJ#{1b{+LL%s12Qq5 zaI28>Ew|o8MeYNC;0s9LjjgplPUwV@`7&?#>^|5UZ#|@0k7>C1)ge zCKzVC2P8-HkWsV)9Nj3v*x)ON8ihVM)ZUnHWkHuxS8;vQ$jr+%Kqsmvw?0NdO_}&^ zw`tEH_z7Mye*yP@(8*BHH^A~|5yx$koT0p&HkuG*cnCo05W@CfRA=Y9#jJMtM#e9* z8or;#zt^LjzCrhqb#RX2jCLA|GGE`bNs2kMR3r+WWiw(9j%6aE_+z}q*;vzhL4{Ne%e0A4i5gjJl-<~L##_R1kulBf#%Px>xRP#n4du7Vto%acC2S8L zBJ=1d?*y2V!|!v=|tq{aYb|@k%%&5XjIC$e#s@$pm3Qz;Gn&7a^U^!ed&jU zH-fQ80PnqR$ujexl;frq<6{lhFs3Oim1?n$$5M`ijK}#oFz@lU%Ja41{O%yXT)oh0 zek#`_(u7mD_2|P@JOrN(MaGLn(qo0i+ESD7TCAIz$McosM{RYuHCvfg<2S0uVxjG| zCUj&xZ+Aaylaj@_EPZVT`U)hofiOlrZ33YO0jZ!e;xCW&{jNxyF?&l!>fN%Jt(SFG zIa!fkfj2`CTSu;-ek!Jer2~G5 zWuR;d^;k#DWdiGZX0`bh@-_NYz$mPBTM0OujCny@mk!|{-Pa}TaC1glJ*30Y>a?h! zy9q#ikvCR%X$@oGwpUf2o6mcg0wFABjtk3r1C@!1O;47KUvRbb6oMN?+Ils5!iU{} zQ@DY`xPD$55kxlS6pjBpY08FhN@*VrL5;H2FDwkEpdU#>HStlRP4R^$qomXQev;i= zMKmvNS~GBt%_-$uC)`xdj(mKuqEu;wn% zO^V)wAqJ?b()y@KnOZrKDKvsv>&f@8I^cn)WP~`;M{5sZU-T7p@pMn;ybW=rSXbFLkFW3^ZmCpMHG6|Eh9fjmq3H);(Fh53V-XVCEvcXUz4?B!%L7+187C~;07<)E51-5AtTWvb=NG@iB1X%YoaBSUY(1Fhxl4O>2M0qcID^e z%(bHH8ffca_0qwWv%QW$C+sR2N@^T;NDTklTM#RJm25ilgVys8(6Xmy0C!=*5seft zUQrgHqA({e32H2;j9EL|Q-*};s&8&xH3;M9BQ;2G@dWeR8*P@~+tUPS=&()`aT**( zbp-I!0U;Gxk;2>y9(WJH+I<1@Ni8>0l!#j+SN3YtJ3H~Dwxqdu2kGe~{0!+jR+tec zwbiMP<FgiXeI;m4-!`vdk%dbqjZe-TFh0*Weq7u>O z+`3Q~FO{UV!$SxR5Vr!pu~>IC8{E}F&c3yKLx_Jb#w%6T&CpyZ7m$S1^m={1SbJ0ScD!EhZp}6c0merq zZMkIBOfCWQHjB-}y%F<-c$^BFh1pY)lFFnu)2TloTkO9>7nIsW_Sodeet~(ibppS0M!t^wO zz^nG|czsqjh|16&aGz0)2r61EPoCx+#R_p{{aI0@xoW(RR!gPD{(FAxS0d~`$({Xg zw=uy}^@~gi=rZ&F@&pmGuuUI&KhbZ|BTTqsnN@+46Pbn>93d~hj*?SD)*r!GnDIW(JD?V_2w?)Mb|O9?%{)9^LR^AZ*gXwi2Pcw%!6+ty zXmK(+m^;6r?t;Ck`q%M)Tow!1{Rw{bvD#o6<}jjAcCk^TvG{B+vdChyF>< z1PWR{2-xs44zvC`EQiaENx%nysiK0R)k^FK>w|9Aed9j z^~c27%TMVtCyMi0AnHS%K_g_u-*2ACdC%ds1`D=6RBqhAXHkhbzMpOyktULDD|XEB z;{d*mWW^@hsZVjeu;x^t5@v4=Q#2;%~;u)9H@ z>1_vN2p{tvEOPVDUT>bH(v7?J3^az)Us~z-nCA$_1aN(dO1T`zM2Nb^4TzlK)CO0> ziRr?JaO$N?^J|yrgg|P<1aArnX3H7VxG?!6I=WM#Bc1R zk;^*-rJJ29eNp#ypE{mBxd@d(#0ZEOU` zW2tM{b^~ep9!2!}S!dp)nK%A0{e z4)3Jubo&JNwK)DTjdkZ2fpKf9J8n|bb*9IF4Am!Y##y8DfCr|`{+b3~!{OQPylUfy zkZ9%vm=HSXyv|0(eN7D^pWyrA+!x*#{LqYeqh9@u1`jgl%Ut%BkzG~c4wKd+``V$& zGS=KPmbKc$8L{i?Ik{#8$R92W+^fIY*RM|eX4CuZnEMIi=SN5wkQ zXPn~_2`+M;tGINjZ9(4Xhan%t_ZD1tJ#%%LAxdj5v|a9nJKx3WSN8x`Pt2SPnTGc@ zD_~3!s9OcA0uBS(U$O>=_{v2xiKBd?0tSBx_ zD$d(WdB{I9N(h|ifr@`p_`R5a_qr&`x=&5ci0GqNS`v%}|z zyLTW{xEDj!Y%#A!-U5Bp67n3Bvi{O$$(q4kic88IA;qKS@g>^T@`Lz^@OogqLxJ+( z@`^kk&HLYM>sN14v5ZNQ$$ZZD_FBy%orG+BY`u%R86Gwqz*>9wV$kJVgw$8|_-D>e z?M@>j5vxms;%S(WB3a-5Rc6|1Uz%p72(4R$xe7PStCQ~I8F9yk8tXG$qS^XANW(Dm zjsp{BiWNSZ8>3?Y?34L?AeAk8_nISGd+G-??~Xrr{iN}ra;^DhIpP2_vV)6Q&G*LK zg7jq;0RW*790~%6vdhgwBm93vN&BhB#HrOMOT%lcAxpzgXMeJJo1x*0 zk_YY*?qIf6hIaKrth0lV+8gaQ>x|LqP!o5`LxCgss|ekO;L|R(-uI_GZr22BrhSXk zv9Ep5IGlk<&bsb0GtXLjoYUR&Q#Ri z6I1cGP~VAV*w-w}f39b^O6!_GhHO}c4Sen@el^{DcfR(=6y!k4nRnOcX8(4p*Y3B9 zYgV&N=0yv&*(4esmbCjwiwFd);+aERsgw}}dUBWX@R8R*Yt9(qyQ){34J~ZJjYZnF z%6$`lu*$XPnxt+yKSHKkI!R%3kqg3>0QC{yP8ks(%c_e}Wzpo1e4Tw(5H|U6!Z*y$ z>1Ex{Tm@N0Vn>d>`!`M`b$lXlM&50#?%4EAGZJ|BnMT*X3j}jM_f1+l#l5?3;zjl?zfdZPg^GJ76#w47R7*i=k?^GSf z)#FTIDWO@P;U;q4R|5+9?E;$*Ciq7)0y#U$6r_H03y>OU^g-1S*|a)-`piK>+_f?f zAnOErg4Tb}VNKs#6VLdJxw===n&>^BN;g_+M0X5>T?X=S zY5!iPHJf9E&lI)GcW;tzvQV3DmtT+e4h5;|ESpUEJ5IJn?VxPPrZ;Cx4d5M>k43|^ zPvQ>oz5!a~(HjUO91SO4eS>f0W($f*YTB$TB|9AakcxL@x>w}ydl!E1V!-8AB{;E# zVkQQt#aaK_-;jGloORpC4H*7`7@_+9bsxlUHzCu&_zigUkd27T;t@ZoOvJQRnPYFj k!0bO(79XO94M!Nm;OMfGF9-&?nn)V*`I-|&(|(`&58q+07ytkO literal 0 HcmV?d00001 diff --git a/apps/scully-docs/src/assets/machine-learning.png b/apps/scully-docs/src/assets/machine-learning.png deleted file mode 100644 index 538004b93e04d6f23c67f7d5e56f3411f4d060de..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35756 zcmXtf2Rv2(|Nptywb!*b*CsNu_cgOaM%g4I8ATtPYwwK6C|o3p>@qU0O|~*3BZNrC zwJsO`)A#@Qc|5r0<9&|ve!X7L^-eS~zD-HSN(KM`rJk;q82~`QPayya5%^;Jw89m9 zA@$Y0?*{&q;50?FmpXFF!h zp0m|Plt)rj-$M7=u*Uk&$Jbb^?>7kW4{Sc6#9=?!w=4b%vrkjI#*H&X;D#NN2s$5B z-K*>VPH;UNacOm)7J+{d%gjQNFTVRoHMp8SLY5-`>-W$=Mx1TL`PZVPHR^~n&Dctu zeZ=K4{b;eOL##o5u}oF^xB&6r9{$l47M!nM={?P3oNaaS-ofN;t}<2pe$O{zuF#cr zr-+M%W!H$)&&w9h_^Z>-n!tlTrsRmVO`mY=tKQ8wo^I=*;_XLfaT_&RYiie6H4%1Y zhy2l;zVwJS`^-Y>aZC~Exb9vZ?OH68y>6&#Rfet9K?=iRK-CBG{9=WM)gYuG_*II- z_4#bI$J?kH?wQ#>)-N(WO1RaT2bKfIXQfC|41*IzqT;zH7Kfxo3kKlH}pKW2;{^wQnQnt`kR-m|92|9t*4 zp36AK+n1yD`Vmf4+9%eP(vvf2JwwYwN0ofkDl}kR<sH|W?_ig>2gHG&D2(htHYdU)XMwF@8q_h z9^cPb9bXLDYk$VbBh8t3jpmn)v^)`Q-eeJX(7G@9J}__$-6Z{xvu zPLI^V^;+JG*VLZf)mFDX@1KnAH{qAVP8Y3`Wzr0!nx8L+2HKxTcu?+jTzHpDm)`Gr z-0gWUS-~GW>E~?TSFjgxeHwAsr~TM6cr;(e1BF}}`uD)iM69Y~3JbZzgl?@a2Jd`$ zr}Vd(H{fEoY4(BW{d%p7)h#U9d4&DzoX*`(3p~l2N0+P$%LM^T_t)gOMk9l^CB0jI zy&NRhUmmZ=JvGP?+dX}Hz;Y!x-lNhVSbqP%0_8&O0M7PPR>da!lzis#fms1}N`uo_ znSuG+d3zhLe2gbwE40WSE!C^;*sA-j_hA*vS)NhW{WaYrX#e@$cQ4Sg)w?qwcHF&i zH3WT{S5Ct+c#YpwW5VG^<(8`e5@xoBtNnO27l*Lp=@KzdrQhQbSJ-bQ+R5A1omb~X zDSgRI#P-ow4(glJ$=IFW7c=DN$qx9EmpTMQcD(6Zzpokm?c0?jes;%Z(`-~`jR*8l z%6*Frj3#+CCeltFEcfvf_9y4B%hja=3hwcH23Tq5l|`*U)eZpx&s>J_xQoit3#0q0 z4oNfZ&p$Yob+I~k==>1;JA1-%@O&M+7`T=ynX?2h)mb5 z#hGRQuSPS-t9j3w$TTS!G*50Rur!J<1S`Y6ai{ZaHCZCpBBR4zuQhQpr>12ipFS1; zan^nzaPir!%+((^HK|}z|8T;v8p!fR+VxplTxE6Zmq7L3c_a>uSF4( zvyviGXZOL<&1<3aa7swxY%gl;i}*#3xSuK4B+MU%AsugyYw^;+Mo1?`FSF z>$rPoB(vVJioT<#qo^T|dJlH`7@Klbz+Sjpu6F4WS^e-9mjl6$OfT;6v$Pw5o%sIc zgwma#Z57zb21=n(N6OzJWfy(tF=531{2nPf(UhZb6YxfP#3VwZ30D z4)#yJKg?lpr|2I4S8t~uH7BmO#oCXiTqzWr#J+?cwNr#~VWl68`-V2TISkRrts5}^JO~>W;VU!YGUUab^;-WTsKD+Lz9!>=I=XbHLwyaCVO;Ut(=mg8nNNXbRLiGTM9;^d_eC3}nyHnCcgh0}U zhK`TaKODXVmg!B_XkD&I&MY%VgtmA?b9!UND3e3z6VV;1Fg3rQu}oAYlTW({nJ5&m z@z{%-LScpFlRP@AD^Hte$s`-aADsO8-iKR1cJBy3O&i}=Q>?+2B#RyLKY9_}QB<-c zO}N~$tm+@L0r4|xu~X}W1(wGv#0KCg)3I(5-eEJ5Qj6iqG3PZaNB&R(>((z zv@nIDAeWo!GsAIPi{<9DNX)Ft>p=*)ygv;({l~G}X#R92eNrVcjp0V) zS7Xnz$?6oMU*=a6AEe(-1?Kh>OP|llYrHOfSS2+kUn;-+uDo!5Y~Xi!k!r$KPT<+^ zJh#HU?vK+rU+QKirak&SW97Tw(E)aA?j5YhxL&E5<`S0RfDhZ)Nq1jKt}TtGxN7&f zZw2&}a|j~6Y~WKQAvvRTOiMhS0!i3=(!|;wIl8r`bX}{RryYA?dm-QH?kLyUJ%3@W z_%8ACRk9+7v{>1}%kCo;X;s?JYq?aS(SYHNQib`s(3?m1=fQ3!NgSc`BYHR>DL}W> zjw-*V{~%Q1A*ElnN1WO+SoJ^F13T(v{Eejeo-wHdaW0uKqAsk?tA>yb!Ebt#W6KEz zTqAc@jYM{xqe*sOtNi))?k-!J+SOUt(}`uTBdO9q=jC7T_2h=Dq*6);_oWy8+`Op@ zm?>|~f4uwFkY$8e)$cg8SvErTASJbWqjYm<%Dr5Hs9|zzA2;QH$@mLry~X)@D&;T~ zo%aV>U2Kpa85V8s&Fq<6NCJT>Y>rSD6iG&?B-(hv14wrB@5uj*>18_lynN}+n@S}~ zCO!XLVI%i>G_`8;-PiT}spZUT5j_8e4jr|BnM0@+4ZjsmoFCu}c}$r~1@5ER@K3|I z->1Dy^s_Fr1GYE+?DghlF4?`*`JMM11OTol;dUcAZzsDq(>vGv@XP$86WB=C`Ck`h z8P8hcoG-0yrzp(X=icicdaHm9;#I8TgyA*@Q4oL-uIqFUMRie+h~F&i#mm5hQ1wUk zbaoTGY0CA#6L_C*^*f1>$lfPgcsHCoYsw>)5DwdbcQ$@ zXYE6NQ7dktx#QWN>dtmvE_8nU+i~&t_s|PLH)^FnwO!JRk{y@3K7yan%`e-;HZZoi zFT#DYi@1WfiW3v7iP?RTFAFP=M3-@60ZHQ;MKYY>XFm&=k3yWWAdvC)XuGYz^}*)D zy`Cw*wQG6tcM55W+Z6&O3=;;MAS_-jJP5(!LgGT8`RK9wXgF2x*@X=SIty(&;Krbi6-KTkhhoWeJx1WF-CrfzD0c zOyP>niA!m?5amE9v%}@K)#uW&fjy1~J0F^6mXtQqPZ``)kC!etdNvPVgRm4w{$wlb zD@AJ5U-pt=(Slj-t@qJ<=*KCzr$?7!6zA=!)!);WK!7?hmfR-wwLia%@>9hZK>Cg< zZaw^ziiunHQ6N!u$NBbK5ZVk7KwuY$|2R}{Yvj7xHNHqn2sEKRkeJu){RrN)aimTT zv*Lyt@|Kk3W!(1mBS2mJ@(-a9Gl0y?LXIqJE{jL$T3BS`)s%^L+^c>?S9iV~v$>7F z%MPRWoc8M`>fr56^Zc2wzWLQJd!w?d%GOP(XjkRIb9wB$Q+C;+K(6M2G&WXNS7A>t zBPp$bShQcU##9i;YAAk02R+GNIw{-gs_57uJ?6Bz$%8U7rR*ajha)_c*j&nah0zdu z$U2qQkn&AVaz;^PoF%6sAwCrb=!AzuQLDqanWm0u?Q?%N$_H??ANg6~nYa3bcgtTE z)@PRyNc14y(UF^!IU11c#M_HYMx@p9!t`mHJAi^!)RCjS!+|YM#kS|j9%6VH(wo(f z)e{~%v6sA^h5HsFQ;^oll-X@;O4&f;A&?N+;2$1;W-s`^b^IQymKsrQuKe$>p^qK0 zH}r1;5M8Li4JGJtdR@Zc;wzty?_+(R0}oceb;pv^{9S-OSzW%qT>g+Lz2$U}85fFu zwak8)>JwU85FXdTr&x}{_D$U6JL+*`2(W)5XhpghQ%CQ5gk^RoMiQgBiBWuil%S9G zqu+_@XrgSN!0#%y+*Xx{9}V4BnIF5o>65-Q`Qu0E8&VSH2}3xqTcWHIVd|>e3`)oE zsp^D`9j}+9gY|w?+w$un6=+3mvBtwlvImM>xBT=dkzSMlkkpb(xXrzg)`9A#NQDAC z58dC1i;%!H7|oKRrSd*@7S)Xt!M+vDxyC2ge?G*CmSxp<@u#5+6t>5>Zqp{*V0iMG zf*_J|cXyYVC=$uO;WjHl1YrxNYL1g684QW;1uXcJ+M~h@nRZA_d9wW*!&e>SqW9@NmU^lh3Lx}djmK>XZczDc^#Qq)0t-p{YMt`!?%Z0cy&_|01g8F zf}?!KVFw)Jdc|AB5F{snY}Mpp(2KS&?9%wMcwL^qxSSxY(8E837ofPjYxUn|x zl$^Ga>~#(qtMVjOOo;tc8eW}07>`Kz3M4Phh8!f4FK-zJ`xa7Hcjt_wX*oRP(eJ6U zkJPGX2mpQF$K>z>R#E?I1ccdExUJH(87QzyuOdwd(JbI1=DAvO`W#Vn^X{q-(+F2@ zV0A9oWJCk5miYK0VgH3&l!2 z;aHkE$9cLG;*-P&(38Hqy4;I!z|D4EJzHx)Q=BC+h}`PDI5pdfrxm+ zS7gkK&)4rp_T9F3_6Fe9xoVG9nMP^|B1uM;EB&73x01AYW^6S4$1oL`(;xq%v=kC~ z2S$ST{?YuThvv)0aZN;+&~B2^b9eKHNWqakVrX@)1LxLcZEuJ12=X{KKh;U0h9{j{jG z+xXS;>EpUSMpI~s1Xu5ptb37a|KcrpMP+43=;8X1=09XWG%lDd48Ee&8IfU{mtiohV7H-{tkT}xoqFj z^U)spguZhPd@kOqs|mbB!;;Uozcmxe=6h64v;@RnLdGr3i4Sr3MZu!br$0ezYZN5e z6K5nRJWKHo`utt8#CGJ%N8+9Mr;K4xePDmPvc?hs!a>1Cov?xv*zlo*K!mTjy8eq0 z0Zg8S&mzzd!gCPl7v2==C<0_Vw7FwoYqIn!F=wEoQYts|zbP+rq4Hi;jNdp0a$Q3P z?LHGC_?U#4n3$;DN)o9ad~uXv%nCCvSpKM6{hs~P6X+*m>vvrwXHy2^7B2yy9U#2r zl1Ee9&y8iGsH&s|!b=k3Gjf+@jS*tlwRyeIYlh0yaR>|q;nN&$UHMGouRJMqAxQMg z-9Pv#EP_`qS**LizrU#D=KM<=@4P2{_->Qk5uwco{)V5SkjB7}t>XAcrW;(em@nBP z7tx!CzlKHf*lK4Our|&2!r$ov8M$iuwI=Kv0l!|zwY-Ip+=C#QO$8{RArfhtX@POK ztcnL0x7eiJCq#MH^NTg(UF{?~jb0{N!KaQnvgSrOQUGt2Xl+hb#6`b;BxP#6V4n*N@h78IQLjfR@VCM+a; zN;io)bvcm~btHsiEzaSKJjii+E`rb{^U%J;m{S1=R5tvI4~aQpg&-VZz^B!%7*aZ- zU9jYP9O>jiI?X1nvuKz*)&Uk{6XJ39f2VuNAu|^LWg<*MW$9z@*Ewq&-M)RhjC|t` zElgB1?JLhRI#)Y^PiX;Xax?d=IWiXds?rdoE>#bQkd_?gT5&J4?+Gyxz+eVaPrt<0 z$V>b3>!;sghbPdk(-Ff;!e@zL8W2n-?(Wph_!3^B@1H=FNx2NFcJULp(QMh0Ulrvz zM<-!&TzI@c2Yg#J^?X3xG5TKov1S~F!hYQVXXQsoq>#Gm6C~nGKn9ZU7FF^w>}q%U zYLpo^aVzz#$y9&<_sp6~`5%N}f0UL?hS4G7U3X2+y6ss2Plf`hkl&sT7xNne09>$J z+?%oZrmvRMdh=8?5e)k8!dm1L=ToHIJ02!1Retyo7QbO*RMc*~=8aG5*If*_ALujt zM(+igp;_)`HgTkfI&ch=T@J;nOk~V!aU{_FWQxsL1Bj=7o8CbJNTvgw3hS#-=bkC_#PFCwAP4#05;pXrfaaqP!fLz9I(l1$x+U8o79gyN$F+Hxw%ngSt_ z8UQf_dM)+nTLp)B$Jy%n-@o3o_rqjMLLW~jKD4$pQ8?awwCXziHhpKVJZV z0qODDz=`eCA^v9o(3qu>!?37OF+h|Bb~;8^5)#>W-~SQ+(t`D8U2~TyD6xj~?s}3n zR%#<=B@b#S0pz!(2mvZ#>G@c*+^OSO=GwpygbuYc5sEnhNtwhZnC{h53 zhBc8ZboXbx1~>xPpPm0Mm-G7c-L<;m+%P35k%ijSJ|(cq2tW>G3Ew@B#8lmHNKz4- zETsc{r!A~3g7i4l@IR@s07`0Hxxr}nOLS5@QV;?p@_85*skXnbuKsHk)iwMBMUXMQ znWLSXbs>?^W!DEEJoIpOvj=}sU6rQyO4vR~_#`|pY$RuVF{nsa7*gFfEcUs|1Alff z%8iV^2_Q(Mv=r`D*Y zsiq~Zs-5Wj!t!*6*vO0;Kysn}@nRBag&nmy6c8d*USrqh;pJ(umgou|+9JrCE_bC7 z;6T24;GYB0g2IBe-|s5+9Q&l`&|-bC5ol z7-HF2*{Deoe{j6xaNU|Xmj)|oGRk!zhCZg0Be8&OV_d(mhac4vzEXn2Kz_8Rj9Y(U zlZacOmR~`6JGr?pgX+4S%kewzc4N(i#LcPRkedJy-2dN^y4C|T0BN?^LO@*s+C_~c zPyo%M*?m`+cS5%XUDdI;DOPz$uBeBv#Gae9YQd{%Q3s{x=&u6$HHHDHmF=jh$3zIs zF8q)+Spz`R3uz5JA6cm&K-+sT^Zj=2(q^(VNBHg(N;qlUwz9IC5oGKVGVY>>5%DCF z?9RM3dNm^opeX^&!V4u8V})PzqyWcr0L67jO4t!O6-=y{ynh#pIt6#-s~P}?ASHQ* z5f5Y9<^-Uz3QMQogS;T9h|>ofJccYNOh;jadPaR)eG}uvX}3( zz)+$pbouYWe=jlED0Y*PzyV?}D6+(qL#zYD60Z#yF#Ure6{`4YS* zRK9sZ#SB53Xgh82{GquHvEzLnLZmbFT@+D~!^S3K26;sG7>>aV1lzsVU`9|jvhDBp zP>=KI&kRuJDuNH3%=iatkdS#0iJ+;Ctex=AlqSvwF{*xCtZ!*MpwWiNs!$^9EwlCZ$2%l$YZNooNDH)&266Vs3BQ)C*ir$oJhlk9$JvPR9qQ$d>KZVOr-oe z9>(KB^T;fbfco6HutO^F`tp=Z2XWZwW`dl7!dwo%Wg4N}rKB)J$orElg90oSbCWg# z1UK#5=IjsA;^8-bV^k-t4+G3IE-P6{XbEANBj9c55?gkB-3hWc*TXOYJhBXS;v1if zdgo1uh@)KAi{(d(pf+VNN639_kdw<+CU zQHcf z7~Zn*MMjzK7-nLwRS{7v&C5)qtw)@k<|K0dnG|5whnC3`DiZ7IL_6k`v?vjw5hQz* z%NjP9L$#ELVm9*Id zfkKaxqGJCRG}2k3vyBN*><&%Nj;*a+m@u@m%K7GZ2YWtCoj?xVIaqp?pYN)6wi1my zSQ`lV`nuX6>R<^~ryo@;hseKV&4yi2FcMNiBkkIa-c=NxokbSNZiAHZ&SxQaT_5CH z2XLF?nYk2=lVCzZwNep*xWUE8hv8I9jB*Uk~Dn)iK=2+vZo2<0eY>J0hIw=#U%X-Q`) zhk5)tCb0K~$T=m7o;d)Sz*IunZO>|P(4=0VDee5_^<`UR_^81#T(}F;`+52z0V$Qu z^AgjX@R*roBIIxObfO;X`5Nf=6&j=qLJ1Nw#mL2i2`q<~P$0X%Za=WA0bTG*kS|y$ zgMwmTKf-_2tynUFk_0o0yIZ5I@{HgG>`Og~nmBj6da61_2m$LUAw1lDYqP*_bIePN z+gKJ9%pXE$4MCecztq`dBlY7lHv~h(|$E zv)jcFg!a!z4`dLvg{pQ69(MV){3v2DZ4pFD?;f*P07Z2tD^Eim$$>V=;MK*R8Y~m2 z|KmPZ=~9Qeq~YnP1` zZjyJcQm4dv+A7$6-(dD;*)%P|%dohjvxSX(r|9y7_t>Fv zm=G&EF~q_%p z2a_#g_0qsThC(B-*zYyEo0f@eq|u7H)EWG8iB2S?6QEE4QG-Fu%ORH~IQb7= z6FV7wm2Iy-y5@VEY*x2zY;68l&woMd!^Y_!!QO4X{wa7R+u}Nr-hr#deY^IElfhQ* zz)kJV3?6NMtrBZ4i>|Z%Jr*X7HsyOt|E5Vw%IO z!pz$PBVOU)E&r`&+%7T4I#Sr(zZp&yzPcwro=~m#7K`o`4bZQ_UfO-;f`(OP#8 z5^PSNFy^UPH|leyyAZAGu9Ze)28D}}6xgM_9)ZrhGW}dijt@v)oGI!IiCT}Q3_c)N z(9u+1hFlQI9iAEL$Oock4vZu|3{CI`$71K9C)W78M$g)WAZ(HsU+$l#rm>kjf95nX za?CMF3ZIweO`WQ&84>IHL-wLQz5Z9+hy!Ceyu2+i>v&}d$-^<1>ssBsnpE$CfC8V- z3PB}!4SHNJw*q?G?*5S8o5TJqB;rG?FpXS?vG($@(SfJLs#o1i9knlp{&L0F@tkBg zxL!4%veKkryXC)^#}K^&SNvL8gZb7W@M&Wp=#nkxNHV}{Xj(9LS;&}MKRQERy7Ub} z0Q!c>T);Pf$N7m;?US)ray5b6_u=cHjY$cExQNz8Ax!(;fM7#0E>o#nn^i+dCZ`Hi zco@Z*$Xmgn$y>YK_n#2(cwFg{ABCQ%cy3$TZF{0)o|Iwy4HBd>)4Se7)&v=$%c^ij(Q}QVEaDXWJD(Gbw@{poUU&54jsu~&* zzH?6T)AgB-UhZChzU;dU;_-ooyz|*+rj_sCi^V+WGc&!UxRcoD!R8v%=Ni5clID>t z3_&%$JFN8)?|zf32Eh2vcsEvVGzSo3u@w`8Psrl>zx2B62$RN@pfBBZUcz3qLnarM zXt-ASb8Is~%;MY*8P-br=N!FcAoS8SScBQ}zh!X>9}(Ba{b!t8sOs{J={1Q+&Dh`? zj~*`{uc+jPTv!~8qAuu{%EbwfVLt8|0zC&)ZjBe8I!jNyY?Y6VnAA-(UCd7Wnj%V; zl#g1z{2O5UvQtY+h)kbWF)2!x0GOCwFgOHSU;B+I5Z-5G|CMln1IM||@Rz8j;_N48 zeylDrguD2skkixi`1q%@Tq)6gIk7YA?=uD-#=X3wb8mHoODBu8#rXn)+WeXfw@-YN zr#2{nJhH9>Q%w=-!NR#?T*AiO6fn?2`w~S?3RpxgBv3azy6?L{X5UY2;@Y3WLO8?x z#`J_pYsa}!!Z>&gl~OBF=U|QP+$+5v_MPOnb)NXf@1I{>HbmmdRe}2!z$!(hNe*!C zXeX@j%}Y$YA11}_AXiWXRLCD%Y^(HITCP>{gmiFUBdK0LaJ1enH`ex>_yqdG)Xu5u zhlRrg?wU7{4O48j*}X3sD-~o|oCFyC-$8%;IZmVAEUOqZ12l6`tJ0dDXsPbdjbygO z-{gP>tq>H@x(9%|q?HGepOdkcZj$dG1TZ*|>x1;r`9!4YhW>g-&F&LX>3L4)=n7Ui1dh)BhChpH-h^WurFXHycPf{pg~x{f!L7yUbp@??MC+= zvFN#)av5vt_}?uv+iA(pyKoc!_c2Hia%y>sF#xY40S8S|AlHVOhmIH(`IhB7r)>qm z4jKTnh0d_w_aw+JBt)!Y%W*&3Zy20|$SGUUp_PxjH86&YD z6$j_{Zt+qO-}%jd*_@7?tA#BDa{z;mA^?U;>5l}og^W(nm|b+UN2R&(-3l(jbQ=Pc zKpvF<5);yz+yAjD6Z0Yf6d#Icb%+9jOqPIB(NfXNuIA5P43SwqXxB1{(PkoKA2UA9U>K02uTgZ;|%^ z6Js^9gA@9<-1)yv=SY*duWmf~7Bp#=h^t^4NuyocX`UN@zkMX4S^ZYVr)lxO#Z_wy zQzT|3>{l^VYt*9FDV#}~fSN5Z1&KT%dTc(PC*x^JM2p&@oRjuhYCA(9b<_w=#l6V@ zFt;kjWk(U8h}!ryA}85uC-;6Ni?s@A0w(ZcOe%JBJdFw(gUGIubEHd*i%h)52YEw7 zItbDdTgeC#lEI6%(Vb69Lf9ddfnSvfyE)`mm^=_8=D*_e@d z$L}Skggsx@1&ERqKsX+R>+9%G4r7F@xT&y$>QV{s3Gb-4GLEXh>hACZ<3$e{ToA{d+X3SSM;xv)-L%BE)a&j9?ZFz1Col-|BUwB!b$|0 z$~q4;+e7Cb4=Bs+31}I833+w6QI>3O^Wz(OqN4iplSP+>3T%Nvsm`1^xQ7vN!&=yVyP^@BI#HeNNELI-!1hI9&yJ+jVCW{{YGUN(g7_MRO`dx zm$3$%{?3dJz*96DAR}+S<@K|l1gOKs`t@Xdfrkm8H9 zC1l%EN_D?>IVNlu(X{eF0COlLbi{`cT5&?J&NHQ2V@@1c9Ywy8rY{BhdY|<@cxw>h zW4sH;UBp~fVXKLPcy&h*x3PR@gEK@<*nP{c6!F-|Ax^Q?ef8s?WHhnbF$6)CMLTz0 zPfkus+Sak~wW2|x(SL7*r*6QCu-26L8!Ve1sYqA3D2PbU_uAC)22IA@yx>z zVu#oMSP|fUO=%B9lZ{a$ZD|1wr*;S2}Tdjh}tveR^dZN19g&}|S zz7jc*1A(|-ISpk?D0hmee;;^)31*g_3~(gMsO>`{qjs7D&az2?rRGE1 zUK+8Y_`6JWKYG_bkuM@95~HSP=^zXrOr9WsXqppv@0T1axWg%KjV;_ujd$}pA%Gmv zWn#nx#58OGi~_h~wZn{&I?|K3eh7;NMW zV8_*pqG0+=KDwX~${%Yl@$JxvF8oW*^pXhrFU~(nq8lmxr*Rd}>qaY6*cDZ4qE%+fSvX zT7tcVsp~e;qp^Xd{=*}O^jXj+R6(3KN$H`#%8X{o5XX`sAixa_@`xy1~CvyN8MF?u}Lg+(t zuh~Y@Z$x^w*ShW3Es50JhIkOCJ~D}YB%y32db>w>R2ihq-|Lr9l~y&zG(2xy{3ak< zlnL+UEaDWO&d2`-719|?o)KY1g{V7^K7FVjSlq(LmBs1`N{21Q_*0O*S z6@!0V7vJnZ&SWt{G*Khxn9qk|{m!<})Oi-0yoCDU{9&VOQ(CD*dFAVE*X4+bKwIXT zE1Lm~?lmlF_~?$)eghRgVdoc#-znb^{;gQ|n?*}1TNiDCxaZV%4!4wQmUalB0+}dr zfTUJ92-2+8L!SD#VO;g*>YARt?i$UVWzP0*fm*7!Jw11%=WB0eE=_k3JbCYleE@pc z(^HiHjKzm|IFAuvvRNUA9&;;T{H#aw@L!V2`r!bV_L?HAr*ibkOtb3Kg@+K5j1gy! zvkVyaGc;1dswi5t8*|}?9bzS@Ljp6G|B~3CPp?9QK;%ZWGyUPAfPz^e!dns)M@U+X zC75@A^l_UZ$_D;f`o@8G2X4cLe65fYdn$bDkm;=j{pM=>ab?do20Bo}vbxDiLy{G; z{jNOfccii5G8pv6#e@)?)AF$1BN^g9)6JAQMN&)u%50XVHy^8dFMZUP*qRZ-2Op^v(3t0 zhXEgfHh86L*5BEDzt=zPZ-CSY;d(;^eiB9)4udIvWN#iR_G<~qz5p9QG7 zignZK@|4+cKoJ~spSET7_CIEX5QyEYMdupv0q7tw5o;PukWXuGdd+gnWsvhI$|{)< z$JblYy(r7ClJ(o?QzRFm)d&|8tYl_4EkoNqxaeWHuXRJi&h|FvmtRjKN}h$rU&V2(EuR@ z<_#--#=+Edj+PIGY@Oj12po-&_u(;&U$a)$3A~KgZXT4VI;ktQv#NX<_j=KAd~xG{ zmouK1EK}|N3N$MewM3s!H}YyQ77JrNFITupwJz~1LVb+13qAx;6$%)>J3mC`)NN#N z>8-i5y?O6T+(p~frSM-%ejo@v!dXc?5qvaxn|NvjEK|!IP#79{t>8xnvSu*ptQkU3 zQYLB5#%61;Dyns|te;WzTdzHzLfWAz^~18&d$+!NpQc%R`_8 zcvt4hYHu;jd$A2wE&@+LoDiRP$&6TT5D&1*%E%NDtI6v@D%RjSQi|{u%QK{FvdwQ@ zxqFWj8UN`9Mp3~Fo6$ALrAe#akX(Z1iwv&j1wWdRh5?2{$1LJSqlb+|Hfa8UbHT>NwMjZ~-Mc&iS) z%V!H0F6+NFLE4yW@`SYwmYE%eL_o1@xGsjbFFo{2Sycx_`V69w@jyV zYv#AFG}={IU$162SxcQn`{~`*hdPDtr z(KkrR>~9E$LNNdkrerpjr&hd#%1poR*>PxEc0cvyhnzh;?i-nWIsUm+tXjPxWbl0} zzKtUj3gOARA)zMOe~p&T*Uh&UY~9px1(IdfWg{ynR>%S8j{k2yqNUk2LLvSsAs4h=wHLJ0nueqL}*@Y$qIvh9=B zM11#l=pJ&p6*i@`(oMATV%kaMFl`+OYye|~4~GR$*`N~Vol;GH>n zHoVDJo=7PyMVrPfS<|A zm3d6)g8{XxCr=T+;E_73IwYErR^dypG*5+S8}PCnvO`aRem8EJWSiIr!5n&}Pct#W zwwZq(#SmuJ_UD_?1`hWc(f8tSSwV@^O#3}Q%&N&QnbRip;`6T!vZkz1RR z|3|L3DHG%YTA4;gRtS>u3BcG6`3N|!G~ASw_^*zS2U4fR?0Vb>iKGSKl1I5Qne~|q zh)>hco;}0KkB9^4#l1^DLg?GspGu!Px18f;s1}EPfY^ zFejuqFMUhZ3Y!}LDsnCP(p4eta}lNQOCfr@K~ zT)YF~AZ+|Z{bF&8qL0LogQqWuB1^~+|HX1zxEy_LicPK+&l$c9@4P(Ov2AcQa@in0 zNMn%_7+t#4*#X>;!c`FTk7{)zwIC2StAgja7Neg=K6lH1_97j@*o8-?ypsEa$B#Tc zm7dS|eqb`AO&N>Ksx5?EDSpDn-x6Yto;xDq11g+b0Nnql+*wN~LfV@tRSo_P_cO>H zyUo)KG6n_pc;SG*QnQh)V*)ILkAyyeQtK>n)27D%Eu}R5PdkKjI=nptiH&zZRRbaluFgPxSdD-;bZvH9_A57Sm5!EN&SwYuQ`PAa+)@bZ4C{6x94@q1q=Mm zc9uf+7M(R7NQMwtX2K9VkoCWv*H^x9qz`hE6`Z_m6Az_JmRMlW!~FRA)wJ;M5yb$8 zY48nCdNC8XBpfNg#mtmUEsSI$S?6^gMxsT0Ir!j1=Bw!3u;jTbOb1X;4Wxbmqd=#l zTkTnsrjf84z$qWiiU#fnMgJN}PRb|d;Kd2`}iTE#97|i0%*3veoe*5Qfy-xfo z`vle@-0aj&B6FSAi)Y;sduw;6P`TwXWdNw%NQYU@;|OwPEB@U7evMG6&4C+Jbp#J`Tr~31AzJ+r(2Kqfv)idKj zIo+{h$en#4mB5!m32m!tgtG*xVi<@V1Io&W2uLcXcHWR3s9yYeq5b7AC}S^Nm5GP_ z9`22aIF)^Pd@LDV4AO#8Xr?cy~q4Z@W$q>6lcJ;f5%cQtffd<>!dIr)Rf?J zJVIMcA5c%$KPpH-tPgRw$vG}fN8Pxjw#YE$R3Z_$PTj|L@`rbJFVLS?ex&!@KH9W9 z;g;V*N8h^G>x?*Mu(F+;TUrX2C%4SJA7=Tm?)&C^N6aJf?#Hs9pI_eu@G4Hb%L+HJ zel&$|3T~KR@mqMFoh#vcUWqE{*lQsWY!?$dncxW%>t7JCmn)WWCAQIVH; z8B=@Du8BX#?x8L_AqhpEQh@gZFe>@m@Xu-Gas?f(g$pmwI+x0-++!cZtnusxp<1Qk z&F%0dmM1B1HszDIHq`HbP48ztzf9A*eHsFhp(IXlrB!e*tr7C1`U3fP_ONQ7oio#s zA27_9euqiF2-1X0JX{HHhcL|AtO5xCE0B3REkU?6Zh1$)MrbgQ0XDwT|^t@`T_^H8Sk*9!2a2LsnZ08O@>X9)*O3Wzqh&CmsSP z2mdm-S$Y5{RK}7?AZP*NNR^X0&09ZxxuNlqm`!!4F1-n{K6Ir|YlS#o5qO1?py=>H zK-vUtJEK`9aQgB>r_W3Hse);~oMMeOgl`ZX!bcycM_S*qfngr3=rmxIben2Cx4 zR})|R(u8l}i0ywyTsz;;xR^AA5?Zgf4TR_$X_nPi%=eaBm3A}7ABN972KX6JA&?lF z+ATuR@XeqTN7>59qFei)bJ&dYMQ*BuJxE`Y0FV`#;VeS`mjw`M19+ChyiiPz1z>34 zy5XKb@jN+thBj+Dq!T=01dofH`5S=^0E zF^vsY>1q%6FL?VvA2r?g#r*9h6NW!*f&DrQF_iMgc#*>h5&dsWbv@)G43U8RL^ey~ z{SiTx)_X~x_O(#j!|eHQmrm?CabcF0{L%ko>b%3L{{OiDIRnQ&RvF>gGb5`cj*O5p zvdJbRBP+XetO#XhZ`pf>Y)NEfQ%1?Ikd@i}_Wj-0eck_@uC5E`5 zQ`rryo#ED7agI$`cn}8hfD+4+WER*|`T|?zXJ^-d#^aFw#8Y+TG8 z2~)3nVnD_Ff+aaY$i?Ai_?Y&)gursI1-dw#kdJ_h?)W9a9d=IiPEPajyKt^y`tZK6 z{7RqHUKZ8QQT9q0j~&AH{ufxelbPY~Nd##?jwo1`R%Ln zEt^z6)1+#gKUbM0<-V8tqnW=dT6j89Zb3K@nDiYP^t6a3J6(Am`VcBx3P30XK0hU^ znC4bj`MVVXv!j0Wlz4Y3Tq8re{)e88El0=Ylk054Ho@Rs8yp-YxId~J}&d;X* zI>?1!UpsXPp9jFApUs+Llw!_q)LC|j?F61J+K1aGh`Dn+1OFZ5o8}2Viu-vVYg*bPytO0* zr8mf|5%3|a;{Z3*cadk9?vh_$$s?->RiTDf)QR{u%)tTNlc+b>$cw1Kf~=i+MsW_(`Zu#_h7Y@oY~j-mF8$r1 zceBPSA}>oP5!YkE1*2EFVgW%bcMM#j3&pABxq0I{tz*z#35TF%{SA}?W;^VXQu{%E zCjsLV6Z^We(Z)8da#N0|ePbZQ5-$?T{l$Oz-LdfR{7`Hgu0n@%&eejT#}M;#7GJwb zuH8GIP%S(?G~2hFuj_caDWoaHh21DT&ZBl*P(^;}(02Nwr9Jp3&TXogvKEG8u>a7n z%7jIslEuA>KL=2KG{2@!Kj~&ThW=KSPiV4f*dTRyD!@cnDL?#l3AC(I6=hV}@GBe^ zk~kxKME2p#e{Ba)Sb`|#qB0}T9DDF}X!1&(@;sRs-0O<}cBdgoBC&C(Zya1c@&*NR z0;5;^pSm0QivDO?`3x0&ACl3TbAv7*Dj ze69bP@i8^5EKVzn3$>QqUfJ4u*0Q@Y=%}-K+5*AoXKh@t+U>?DsNXIO{95l}oV8jH z1CN&J`UuPio@zm!Y`&oYF3`0N#(}>f zpVxU{^?|vz{dENiF5!0?tgM^w{=B@ELtt5i!jJRrE!ll1uXAv0 z$YE-v(rh#t4U@apOtP5XA5CLm?bvjvP7iF_LEcO05<_pgFr??KmOQX*(tBUH* zNI*!Po46>{PdcYG8|7)EoNnI=ECydD`$e#;NZJd?xEQjjA{N}<{f@Z%NICD?LCI1p z=*?A85WQ~k>~0o5=8`lVwNsuH|IgMJY^i*HA(JxF)oy159LyBHcRMSShy0OAxe!hg z4hf_J{)wXl0W>abSkq&NxZ~0x9>6wC5~N6i))r4O%MUcL?N#bE4}X_59E5*X@1 zH0u=DF$Z2>C0$ttixlrY;kx^;kqSz&$g6W_C{g>(=2`y`#ak5cL$~Uz(6F!-_YW`_ zkzs&^VMsy5E#>tFiwzt%-Bh2$)@prmW#v{ubx}jZ0V3F1QjyC`Fccpa#M_5TI+#2K0ekB|EC$XnCwx|6OI@m+wqjxB!636@F7*g zQM9Ys9K{%r^v^lpVnKO@C%_~Ka?z|^9kR)7*gx;P08JM{UaWYi`Z>me7ewjfm43ars z%c}>AL{@2X;KO$1TRor{6E9-Qq&`p&`zZK!w^%ttEH0;wK6nC6A-SH?ZxgVK4G`Dw6zpieZHe zaeK9#u*VK$LH}*rAdmB{uJX#3DTmd`!yz85IVv?KPHpTW60f^YSj84$=cW^&Eof($ zB?Zz_9%r_pxEi5V1wpy32`Q&p@%2X)JA&+o$*B?vGwhPyXPc56$#O+YA{7%(rTsp# z669bX_qK|E7rg(#zSoC)t+cW&)n|85Y5;~Uf+qCd1Y6}kgx^@pxtaf11aHfhcjwi- zbo|G%KYM5ET(DbL@ZLfB>FHLu%_~KMw;xuvMbPl{*G>77LW^^;&wdkdu5PQzmW|k% zyS;o{P|mN3goF+RVxua66-!LsK2M|dPrtwnh_LD==s<8Bi9O;iP)!^-644D)Pt${N z=?chj@$S_Y*Kb{f(iK#s&GR4rMF0Eca2K1ZcC(@urJK<{^JJNw?lDPCloWNi;%^)u z)OYy8=(t(L$%#Q2fvzeUtAs;?)h{E@ZBkey%fD9c)PrF*yd7> zMu2ku0R^5Phh!&(VoFxXD&INO3h!>dqmad9GkQdi&w}-`!PpmOJtHEK_GI8{<741A zk`<4iW*qI!47|v8W&tXhrAx;Jx=GF{&yRPLJh>g1eYAy=7lv=fAW=wB7}gw|YwsQT zpC`d5rX0P{DO}fwdM=@@n>-Vg=LD!f%Xi{A4C5#Mj{NU zh;S+$r=Wcj>(+THgzdonjTCOq%Uend!ucjJ{z=ENka1vW8t-)(hA3CaUN#JoKYZy6 zkHagb<07cgQFXWLKP2mHkwY+w#kXE|f}{?FDo`-V;*q|%5h>KsbctNmYE1nr=p@JL ze+3XL9|qLk_ydj5(t4={fA>qGJ?xjWzul2Lj-^9kygM&!R44;c9?)7PaSoW}-E z92GdGK~l9d!=0dHx4f!xEpp^X<~Q~P_PTI-G6eJ%qwfw?@y-20z^_1hkvHHAu{svn zaAdKFU4X3Zr{t>!S`P|Svg2$m4+sTU_QFm6vjL?rDP0C$C_XnBNs_6r{nF2w+Gs3f z5s5O38etN-hBBb`i%qGW`RUC^z&mIC_RgY&%L9!QorF+z_=P5`!5%sC-E>zZLA9G9 zl3pARO;&$+>)cL=jDq3(!n5Jt-)5d~u^XTsMv#{>-mwjAi+!PKzB!Lu+lYQ_8cUYI z166JPiJr$@WBwaNDrCp5C5%R{agV8(gnwolVMMZ1`|R8pUEf1!lbEw*m+-p^5m9h5 zD3MQxCo9pH+TTeRynUBlxcRfF(*XjfRtyhcVT|?N=fglx9>O~|1Nm{*fmED& z=7+oY(a_>KmE_~;Da@tafnX@R?|~#R&kizq$|y>^B5M3Nn9$xX9jvE|M4@0eFeZh2 zxUVZv+{nL*pU3rL&ex{KA@)il|F?s_xiRw!+%SYc8?ljOaqt7?P#8^DaoBkwBX$=o* zRQE-gg3}5^+%#z}Mr8@4JM+ZaWx(YC@B5{p>q}8J&$H9iSiPn#%83sM$q4XBvWI^d zE)m0xhT(ELe2bq+h2No%NNd&=n9ed^?)Y;XhRlRWAJDf}CSO#P^Sy#yvP#TrtAvm3 z?A~go*Jdt1QY3&8f8PuhfBJfZkj(u2v-rH#0qSAQ=bM=iUAh(HJ2gph-eu$v8axLI zCC8X?WC#-X!c?`1YQPtf>AO*Er=sake>+cnU8$VH7jYbfy{+fmM4x7{Lx9>_!$LhK zytG1LqBfxQ{44*x3fH#3Jji@qdp7NN7k31VzKwj5nk9%$#i|%7|G(Rx3?F4oynTPk zI4bX7Kv~bhorFUwK>yAq8B!lGgI)rs+S|Nk#b%uH6$HR@;ZPO-TlpUn3gsk(U!p zK_#%Vc>vZInE~muw|WmB&RxDQy`FD7^M(fo{O~uA%3I9-sp%UA^tjt65F};bRk&Pe zqUDWLbf2b<=*yrWH#L_I>7-qIZ1#=Lfq^;yDE-W^et~b>%o`L$!-WWZ8K`yBT}QRe z=@!(v^CXF!EVlw{3RQ^?1UL8m1k-4i-_x$J(gq*hd5&)@;LI3P9|0*;*;`Jtb+!~x zes0U7Kx!%ND%kcsj`MY0s-D0-%MWfH7@LP7X!bG{*eEw9;yV#>DZH8aN7mIy5j13u z(DX&Xx4reu4dv0pHTT=;Kd34bbcn2M%>sSmd9U@kI#N|)6%ExOAt#`k7q1QZAqs|M zc0b93|2=>iIhDRvHb2+9gTX}m+Rql7#=N#S#VgbBxP}v3OpE04nqMOnFvUw%fZ^yO`m(>M7R7f;MuT(TetlF_t( zoqWc@c5ul11PA-743q1HPwM~Pe?m^TBD{WT9;jzG&aew|cx3_?NE$z24QV9hz;NOOo%;FUxS-m3 z+y!oK<8*h}<=Rj3>992}eIWsT%yzj;K>}A2?vK8|j$8PI)+N zO#Ol<*tTtLP0(vZkb2MtO@yS6Cpi~tq_gt5mQn=F_L^7)?Sbb)yxisWiS?j?Qxx!VMfF`hYoq%WCQ6 z7T$T+9E3wkk8FVsx%)mdgG2obU_?AnW?r81%&&DY9A`3}HM z0QHIo-CYD!Xi|w%SS-WxZseR*fPD5Z<><~i8X&- za#GzkOoq| z2+Q0;#Zr4L?oK{ka47nu4HQOn3fiB~F2!M^R%`p&)r%G^7muS@Zb?Tof2l0UB!^Tk zTNp&k&y-TGrn`0#qXIw9UXzOAf88!0x<;P zq5n$CqYP61NI(GgdvH<4`2fse zWB{xmY=V>K5DvdaUL=`J-*;pwl#j$$ilyNuZ+1jJ2q%$v#5bi{_oI1p`vD#Dhksdt zsjMoroxm8JY8tQ=vD>!cwBdF|pi840cfa;noLKR`m^`cB&+73Dzz`Rdoy!W15YuIL zE5wUvfuBxoq~c7UfD~Rr_EU!=cimf{?<5VMAvNtd+!&HJnzO@kgNp*n)V9(T6*-UY zm7Omz&r$61lTe@eeXVqu2$^mhlq)d}XfINu^BWVTcUxhs0eheO@tm13@1`4f3`62@ z=b^n>GFh)D%POx7bM|P^GA>Vq3B+MCVSVg^u$Kiz1y2@Vl0!wU#|F`zuio9Wc_-=p zvgVjD``I$CBIgoh3ZzYK7wjlq2@&qdmpRZ}A0t@1P?bI#*2u=0WVX%6{P^mbD z&SOOES^p^mvkg_rr&mYKZJ;8iJR5r2HnwIM_B$1VwkGs-btej8Fw^c~L%po-^F#;k zq6ZQb{2dntHyzjo0OrrV=MZKf3MWC4(!SW=%xLN15vye2AF*&e*?4V#e_!s={`%C3 z4wK#+*bLt8ve%$yM8^l*k86=tQAbK6im$o}V)O6KeaS z!7Q>iQ5b|1TX_nDhoxj+Bhfq{jCvR5fEkI`kY#Xox%~(Cll<>k*7>*(z5Q*A*OECO zRIRCO8N}eonyBfHs#*qA*;K+6N<@(UyXcDU!R2&bq|YLr$Scno7O~(%x`h=I+Rdw} zsBvU{|9hW?A)5o+Q5Q0$b()&ojj71i&?2%P?1c?%MBWt(`?fJ{B5mk`-IUN#z$aZb zwl%E{g0f$8Aq;it&h(4+TaC7;^cr`nmH3L{_- zlUV2O&+%}04(&-wu&&e12btc}x1>W&?l$O;M1a!oZ10F~zIWV8 zuF>hq`OB9t)#5HmTNGzqf5Lt{cC+W7e{c-?%d2fu5q3iN-H(T}LWOBGXlSM3Ik_%-aNNp;Xz{Dardv$J@Zuf)5kLw*d`G`CTgCe7f0>lN{`SY(! za_2j*+-oo@1`}F!BDMtbaeW)LRLk+2%(vfP8wmYzd`TL8)sk$E!zljnIJ{q`*%jev zH8f}Tk3d2L>T(vJ_2_v9Yz!;I;NZA&0d?`*`Tib%7}diPzDRG$qxY)xU5qlzB@8r? zL#eD7UIb8?D3_jx$%a-A|$4jT2`fWVB@$;v@kgOIni~gb!*9Y6U6ObPw(PgIV@i)cb@VNUP>^jlb<+J?V3@izw^bjmFc0) z{*By}n&2d)0^d1k-0mS@hSX$Ck`Of48t=xD%kP>=M{qTA?e>7B9__f2o>|Pz;n0(j zDG3@YwgGs6O2UFv(!ee56vdyv&404gi$>(~Z!h@KV?sPf@tLPoqF<(WLjW7*e=`E) z?A~cinecc`e@C~TOcGBS&;0AbVqR^mQl^WckhFO@Q8eC3gN;JwEDWc+EK^5X)4H=V zgyFVPUwu@YC~dSfAzTrO$%`qi$e`TP#-u&@_;GO7RYGIt%3~7=o&xv|>Dm(p?6~lC zj+{_Iu}M!aFP7xt)vaJWI%me1g%Qdx?&6enb(%YFz!M!^!`jV3ZTml7V_ zw_j|95htda46X8(4%^Bm5wop}TJ`D-rr)UDzF@Ayj-OtnCbX%3?@MyExPJeqxYi!a zpgp%w{`A}+I2ils$lF=I`%$y0s_2c_iAru_TCbo|16^LN_kugPDlsQQg+LcLO=ddB5)Nqiu|C9 zl#Lca_QwGofJ&3);m4V2p?FC9El(nuols=bFeFMi5Y#D6cPWM1Tt?r<^|~a>-~WJN zq8BMUlq9$e(jhR_y_c9WbohM2iaZU@7%x0MV?vn0al*3bL zl0sQjsZZ>Y>ha@qx%4nGPFUS_2{>UBEC=pS@f9a8l+hy(ebTsj7NZ)^?Md3G+ujv3 z`bJ4xe&`GB!?mPOT3k9|bFI;$2fWfjy(v$LjOx6lNfw`8mr#IP?e?Pus$1TddeEQWS@@0bYgG)NY&N(7HS z_zB1NLyKZ+VycAjHxVCZtubgAP6!QBlp-nzgzB7VR89w{Hhm~uf#5F>89@W_Ch)P< zZ9XFY_~k$TD`{xg&y|%GVTZ55_PRT9us5>KKngGTh*k99o;o$@@_6|eJAX_y-d zv5-Xl`I`Em;vkNaz|@+7#Doy4nfqI)Bqra=qDhiDS)Cxk_(r$~1o+Ymo{n+5!Qcvb z;pVkmpro?JYMOH*&VKO7@u8r0ak5$9;V&?$ zz+a%QMK2D|NDjnN#RYy4alwErBYKf$lVH?NQDR@S09Yw-PNT#ML$09p|UAW($mJ_%%bH% z|CXZoTFmvxnV0PQJ^(6zP42T#nCiolTLt%{sEaO|+`)FgVp3+f+L*l2lyBDGHSn%? z0P;#X=G-YNfg&mhQzM0WxVCG6=8X7G5nF?TLAUExj(%r}biH0`6c;*>v^}DO{RJ?h zG9^9MUr6S<2a^%Zg=RA%_pah@hpavz4JyKjyx%lK=O;BCdQ`}OZRyErY7HPMaoxS` zNEWxZ$Ck^JBdwkx?Kv`%qfm>G7kj}w{7cw)H2IrT)QkaJ$C(psV|(;d_ERyE6yFO! zsz7njoaRo~{Im2R%#?}yJ%VeTkGQvMN-g;D&wV|^5PJ1|JyO%{>w%t!Cd3l> z@N;YSy#O!JQ>OyRZu_yhF`yP2!-83(Ey8)GL2DOt)tS z3cqKn%CQw`6KET#eD6pmL{cKkONw7iZ*Fc5^_Vv&NKYS$vJRZ>to_;c&FAPw^eghO zxvYg_>rBA=bR_X}2>D&X&RT)9%7Cl$(p4iJc_=1{s}uAk`Tjlai3~CYM2@Tvx!FP_ zGK@A<4r=b}5bmE)uunhP<6<2WPo&=R?vV{}Rmc@AQ0_`fGJSLb$1XZfHt{*2!R=o- z*xbPqNk=SWhCzXC^Ksho@v-r`tgK}C@8DJ|wrJVXwbxoFA zIhcBKO-@xm{iwZjoHnzO3Wci++p4dtOUK==@n{vIfR`L6Dr${@im)7<4=JEUW7@rc zSVPw&u1rKNDq!OeLE<|SwUb{@}_uKD}JyqS@5YV zRO-_gdaZDYqF1DF^o&;S&$zon_8S`;v-05`PsOObC1~(kboQk0zjQteo1`Bfhw13P z;D}E^`jZ9znf<;$Rmo|3*|rGrIE(L@Dlzb=h6EL)II7u)KB|;Qpa;*fcVK zu2`R|q9$IOx6M&e{GaBvtoSu**F`kipeqB|^r*R9S@(^kyZS8XCE>2L|Z;dnZA3CMe|_g@6JL1EzJm zs2}?#vke(dC}dz6cxlms*6zqj`X9F-b$DdYut46tx|x~T27om@jvs#B!MmI=g5@2S z$*cB`HW7OI1;{F-u2f+Jm$;t%$2AI^!?VFI#(QKH9xP@#ls-bB!^t5BHDSklwzvH^ zdz|$+IPw0|Snyu_G8f`aKv&qkFs*3$#3OPnHt_J4#ct7`gxTlvdFAEhn5;;-g$r;( zZgFvOZ*5V89WU|T3kiVE`F6dB7{!;}otS?Nh$uD#oHz-`$^0HU{x?+HK;j*iwhpv6 z=X(o>1((S_Vz4OFH%pEbxdatSw>!|2K`tHw2?RNHc#yKWTWkeEvV20$ zY~=RCv6Gy``qvdL_xCtVp11F)e?OYf^E22qm9<5UJrg&$v$gS3EypMjZXxqEpa zNne#?u|&7De?99w7C=%`_X*29I!|Sc906{ZAf$+Yf7OZ^5OJQ0e%0G>`TONgyW{iw zY1{r^hlMxCJdXtJ<^^7PY)1E=ermNQg-;%x@-G<{P&2)`e6sg15)N19SZlTa%|#3l z4fkIAJugIBbSL&P$1oA426J{^wmTw{S_ID)xm30+Cj7q2=ZJbibkQ}T-C9|%U!c@} zE)GwunWnh4H=>+y^P-$S+Zeesy0A_2taKIoh0j1sEG;{G;;5x@z|96!c!y|)eGg!RqiVxwgI4>?+Gw?SEO%02Y+ z?b6E(P{Qr1+`Hwwlyh-&woKN_wA&R(1hp-eKCR{vP4R76hNB36({>L+PV#vik)q?zXi{hhf6~LzSDJLTc1hwxc zZy!)Cy)Os?zBy3BI}pIbO}nDIv#bA|pFHLL$8vwkl~JzX32StcUD<8?it!FAhvO7OS?nr}?)msizB{;{-gv=E&0A8Ff^9vU2 zNdzf8^{~73TIs}FGN9uWf3>5q?0$|~PWp&NLS8$!c-iqQLF`ObM_r`C;?2;UV5%7A z-IHni!i>ot|H6g59nLTN)P^J1Ls)D;?E^=hAvDaY3v^C2{G*iG)nRxR3V6dO)<4d- z-&@mEFNpEpa4w;!LdiMyYTNay5NP(C%dSY12gsGN*;fv>9^*KOa8nZU4{Sj96&bdI z;r0*blueVA(47ManWQ2Bdb z!;24(6Ms3{vM~#`>!X{u44aA8O(pv@%?QJu$Y&?vJDNrG&BiUXtwf^`<%VZVaH6)I)4azFI+*^t0hueB4S3`FF3FfzM}&ObqMiVXAz zJnO47hL{`6ZcQySyOoUr&tMo3H>km4SboqAyO+{37XFy`xr1{e|^LRc~Rh zIYMeSmwF7q8=kN39_5(24$7YgTI1ttQp44K$AfTq&Yt~$l5)gY7I4;rVTt&8b8evi z$vL&{^OBH2n2)z+TrE9VZh_f0BsGG6Re3UWIGjsfD<-gkaX;lQ_V)71Q*!Ulm4w)@ zmQf%vp`i4t7qF|QY6DIZ45=jQS2{K4Ba1MKZ(Q3c0(3Bm}LyAp&=Ew4Ezyq-8(NDxgO zho~im!cXwH9L64w%O8-c&>s*6VuN{v4`D$`{PCUXYl6n|MH~NY1Ro6WNg=0@+uPrs z&Vh+}`xl8Z1WF?I)ILM$4iH^BS?pzZ1>v?q3>n-4t0MSPC=r+iy&O#jIEqsQT<>TLg#4rppKL_4| z;tEY(^~0ZI92|{_ZtqX!Mb|DlU!Caf+?`;}-%%n!Eix}UmD?=pbP8zLE47_HD2Wy6 zYWYnU*C8FgGELWcMTn+WT!L_?Hac-9l^!2>>Oj_2Z&V`Mms+vLF4_%YZ3;-*PnI$0 zoR9s4#^{($L_b>S()$<3`?^`u2P~4 z=u5-NqIrzR0Hyr(bJc{NaWt3K9|cBi3pt|mv_ihar45PA*4K(QRbFc}=!5g0vkM2U zQt;a6TtS9?eyiIpqI{EQo>>Q??=d&L#E&(cSB!g}YBd~{HOm;BX%lgEC&Q)BG3W7R zm!_3?k4tn=-Jw8FAm@R~a5NG&cXkkh!xnL3sj(bJ!8^Y@*2p~0k5*d{crfMeWJ27K zi433rybfJ^%1C*?r_L0Id$96hLG^F3Q;1m7XM*o&7Y=71M)PO|Q6r5*-wNw|(2;drw4g3LwKkGHB9Zc<(zL zV{rPBA-5ghZoKY}sqH)dOeeZCV&Xu<%jidFxNU^qz;Z=>e zEk<(rP=onp1l+z?1T)H-LQnkOFaAx-UFV9)$w~PFA6iL;cz3ordpo1i92o3jiqjHf zF#1Gy<&jr-kl=uj4D%CMM=&|!b45{v%CPk7@e=nRXVimb@|3+MLWg%4+c}S=?|BFJ zdZ#&%lu5-P`>{A&9kDYO29ZB@7uqKTJM90%LivK}VB%JXca*7aeHB?z_(jF8>7w1b za?d0{H3%0`Dr}E7rwZJhIqO!rPO|0SpTIZ4yU9GN-9N2TM4Z4!>JbsAVUgmvQ!#xu zpI==oGVUpA&r|50_=2OZ7vpfiMO;`K3dL*8A6`O5MgOR8X&99@NA{r^0$&YM>Q8h&lVSzz8k`lglO${}r-b}#X zp{CHUA<_0l@mkm8(^H{qT|vKZev1-encsBe3=z1i7qJ7wYjUuCIYKDd#J{K(@z&sC z2FUmy?x7R(>cqViHi14^0tm3jsI+4wAeG9nIve#&nH#H5+ab3)pXbp;hSki>%!!O> zlrE8q+LuRwVzG~U%R$%C*v{dLpoYM4=>Kw~)`a-u@Px51**pvHU;46;M@>^X??4LI zLWz8g5{W;#ca1}xcxzvRI_~WhcT|W9@|_nZWR&}_qcP_}*3CEs?ttsxm|C%}AK!EEDu6AcOBU3Mq0z}|I_Q-Wj9@js_;UiVC3{>wGW5XI!Kr;P5A2S)4T}rw)F86cRv^V4YoH4#1!} zCoN1|0glc7WIjGU?M+WL^sM$Mik&#GLaEP>nAQa-#_6V%ny`@O?phQAh9TLl-Fl6O z;*kx9lKbI5KZi&i5)Z?Fk4=LwN6dpB`4O-ubYDSUz)Q-0l7~O;=%$oQkCf1GKnv(8 z8&KyKlB0So&WkYS$)lx&jVeKZZw5T$pT%Fa6d4Rdc$w*}bCk=^9V@`-1gE};k;=Mg z&bo&*-G>*>-;p&gN;>QqUWF8Tl59qP)+;tz>lFrJvqoJ$OW()+Z5(HE1qW5nivgY9 z#P5K7ED$LS-MB#aUs&fl{XRyU|4z|N$|6Q_GJIj>iWGU-2~G`yyGH>W#9}F*IDmI} zAzrch7#ORpx4|hy|5x{wdl+$gD%F4@N>S?G`;C(7#gf-NQgGPY4>MnwLhr?L0ntZ{ zXQKLfe&Z|v{<;wMa`KtWvC?7hJ$ZRW5Cqf#)JnB#7NA}FS&^@W%`#(^~D+LGHr z(mpDLN0h_j@x-Uw)ElaBB=zH+Nz6j<=wvzq8$9yu%goK_G#h>E>EFM9M+nlyF~K~= zuLxMi{B43$gWhhA)MBJ?+w?-!MaiXGHIHjza(>J9=84pqLG}3^A@nz(cmj#J*gF)% z9o~70Z-9LQqn`9eDBMu0cBAa+@`*OR*F(`9-^zo+Z{K}%(u5)(C~2iZuWm8HfNLit z*{tn3|0U1qQa=7aLcXwzFh%)xPq?3I$Pt^)NQL1`2wBv~GM`sZwhW+97(vi6 z{1iC!XZjY_$o2p)_>GNK45+jk4~A}T?L`u{Xv9M7c&ucaXXZ3bf>JUkNbvx$7b^?cpGeI3#>;3f_6d2@jIYuej^{rbLg+0o*)sSHHX3;Oh^|47R7I4&rrymN$U8*r&mHPq}T?ukQ2_R=7% z%;1itc6}cuUCsJiHEDMpJJfl_W)!*=|5YhQfBX92KbtIO;aIEDd{uIp>PH}3Us^*I z(0Y%+N;1ToNKKJEk0A+ZDS~N6|C=K%*6kGFAx@P)|Hl~(LU1|}ynTV%=s_*ZKzXr$ z=z09FnG++Bq{x<9{7)J01!i?!IOvx+oSQw>hcnsKhpuL&G>Bz9D-f77)-&TA4pB+$ z!N|S{>#(wq@ML>I+G!U=Qb47scvU7ThF;>uV1EwiixqtB?> zbyQ^e{UAj7(#yMz-=bdN(xT#gP{&30{&kwzGDjaM`^`wYu`=@EqfX}2i;F3Tb@lb9 ztlpaxA}uMD&qHCPg*=8jR>jC;`r)rjw~0BY#d%X~hZcm(UYZH;^V{C^V3K@DgSjhr zH=mHH4x$}Jz0iaVkUCF)&C*?)l_d6#@g;tZyX@TUb#Qbhqm=C2Iow@~NGXsC{@vP@ z@UEjkFE}$qPnqCmm+)6}_s2sY2Whb{M6}O@Rqz-tk*SNinix;2moFq&XiPMCFFX7%PI(P7T!MuKdW%zKO zbD0D)=FrZncJXSa)?wEvx> zp&(hmf1C`Z6=7|ARLYrNs9Z)OS0WVhHmttzYI`tQ3k9y&zdvu6zOEF>z3Uaz1dF}0 zxBabq{Um|~^?RoF4qX#$7sSkH-SVKa$NN6T$cxu<*cJAHD zA@@TUdfWV`t*J%;*gncs#@f1j(xkvYs@XB1gLAFOaLu^@`NJc7qEiRs{Qc?3)j}s= zO&GPRIxa|a=6_OzydUoQyaOCw%9aVgwm*||L)bbCYeVt|kSoD_m4(7QNX;tTr^RIi z1j^l~vgQ9Ez-8`PIt*T`=lNzF&B?18o=L?p#*ZX!Gx5Q^97G=nKglU0G-!<%bZ+-2 za$hUvP>u>W@mWrM_Aw?&R72#S*;v^D5A(LE_Uh{szr|PH1YTv3K<0CwuTBP>L`u#b z)QXV}Z_~Os$a$)6eH|T*LucYXgJF`>@7lgJx=?n)I}CC4j#HO3*&1kZG(49km{lUJPlLc15kUuqzbA&Q6jf2Tl<{(+MyXt^ z>z}uFZ_);~QjZkqR~wYgtjxYBuO;eoG8m{<)q~s+uXS{FpK!TOTC>%!g5~t;4e#x2 zep+lu`Q*FFC{DM6-B zJ}5-SsS`ueQOQ#k+qGJENk4?%`1yOTrE~kiW7IP#_BB+d=1n|Q0i+gA0N>8=_>o#+!PuVZKA3u>lL{{yXFYftG+AzZ z`S#nqi+O=k;^I*xgux7SIHqq;M@3EF9?sGUHL?VHCE|?lhF&G>zfn({yZiOWkGz*O z-;ypX2cqQs=ZMWJ7h&B;C2I=abAyaPq$WFdZrJ+8$+rF;CtqNbCX+{Sq$n3dFd`9f zyjKm#1}(*AL1}*xmV+GJw73Ffh*IX@*RpuLxV%{o)CM|9y!$!3PK$s`CcFn2fZqj= zd1)OIOyWp600iK9R-!lD*JjBU_PHcx$G6GwCYIh)U`W-pTvy~x9&zMan)9u0i#q&A zzE4Bi&0pq3M+8Z7?MXt+wr|TVrFeAx6G(W!GMKh2sLo)r6P2-gjSu=PRp>hI3y|10 z*Mlv_F`QDNeLvjyC-luW#NkvGU{#ek1d2r|XOTgZn+?9C#Qv(A!DZA4sbL0)@iy_y zn~hvoIaM{H+%0Eg&^^089bcSxdVSi8`!UPOLE+-vN5tN(#+`|{wLIFeZr)&-J-8b2 z72NNxEM>NXKcL5PsmmQI(}k@fW}Z{0A`=70s}B_fRE*mDO#KX>yD5X%2Nk#;QBd6 zg)QlK>)$!Yg+PHqRI3L&HF**2vNYAcci)!j_a(KCA{J9#*hkFu34J3YBhH2l9llfg zqeAtR?`nTNZ)YY@|*w@TRMKUFfIa@%=G! zl~cYlmx@udPx2i5($oVn*tMGHac7iUZeg@r9`6r*dDz_q$e;F4l(jkSt*`H5w{W0>F@~ z0W{j*e=d$Ej{zRgc{KP9bG?lwRVT;UZDRYbe@ClXr6A4iGp?AE?%6HYlc&niFwc=0 zTlXvW3yyP*pi8DwaoQPodf)vJ9`EE~Oakfq`T2n~No{W@`(>GUYZ>bn8RM5^^gA|I zZXH{J$J3iTM?NL5NOQ8f{yytUqP^{X0EVC?t8jdrwjV2asJ1&JDqgAnG+&CwK>D{p zAtI>3><*Z#u`n?~mv;S$<#>>;sNwbcbaI36hZwv!Veo{{4fEr;_cDN2?^5Hs|h-kG%H!-Eii z#+cFPLgm-H*Cc`-VNTtB{rucrz;Jp8&H+qcO%C$$!wawGH!u)B@95~rm>@bJ=utW^ zK7T0VZ`N@$7+i9lvbg#BqEtI=2bkz<1AqoH&R zvFQ$&O3xp|9$CO-6(RMH!|r!uF>=(0-SV50xIWZ3%(DjjLCmZ0{r>B=0WpFqmxVUo zQ@0;=mU{B!!Gi~Xf$%M82tIy%4RtKOYit^EhC*g-COK}AF;_41 z)iNE2Td?)1slADI^R?iG)$x&L>0^$4Efr5v`Ah4x6Gp6{e$&Dvq&dpioc4JMVe z7sXmx#u(eIa>Vs0|A)Y=L)FGL&yNE|LXJuEwT&}q&lvA~8M)u(QdhY7hReKRcB`IR zL}1vF3&YS;By--bz!jtS_d_((;Zy4KpMd?upKJ9)q@h-?!o)D>1V8~c)QHQB>eb{A z`13!SR$CGzsD+U7Ppq;`egH!^Cf8*MmtAC_-_){y9<FxSM^TPJ3ECe)f<)5* zOket@2b0<9q1gcr0!#0eAz-`KHe=a64$* zdX{A3MjRq{q5e=I=1GEch}B%pT7By|xTQKm9!>XEUOlGDy#DR;HWhPNkn#)O>L*LeoLtO^9J2i0@gIQ%w^C?3 z9%$U6Gi&j3+5xse!}0lf7MlCAw~qgyd9;ylZruW=aH@(BR#l|e);vH=NdmOjwT)@h zo1|V|SMeV1fj3K6?-wAv4v*%H;9d()9f^~pPg4qrg^tl2|J3ti+d;(kTBbB-7=;`l z5Gko(@8Ui+G$cTSyL7&CS;%~P?6T6etK8H997{WY+lyYd8!s}H9k`4QAE}~s7unx+ zJaVw*7#RY?BwyX|a|x5(lF)|6xi>DHq#@z~dnuKCdyM-qzO;Ezhf&Ag9Xa=08(~`p zLe^ks5Tef8$LEIl&<;*j&_|HApCi?4RDIy^M+2>A)N(oRr_l5^o=yI`TCNUNfe6a1 zjCYTSSThs1Y{J{+kRz8aeLpA+(D+{a`T4EAuZCUwE*1wwh4<1fRd+e6*dBq}l@3k& z{TyTsj7b`m3hIN#J@*2sa0z%r*O*SX3+#xoiOD@FZB9V|L>Bq$dVa^1Q~(!xA1yT>4v|cNI0Eng39bZD`?B-=b=O^2X43&C zj(0#Gz{>l0M$+dLpR6zHE=)kf=g|gsp4S8VK-SkvA68XW;lyb5;>C+gF=eFD$JXlp zi!Z(yTEBjMK0$%FXH){4H*Z!T5P1HjmtHC)LCLX*DkUu1H{X1tVzqwa#EFH1zq8X= z4%+jCCq_^paN151LQ0@i1o^10tE(&3wc!xqC;DOp1)DZ)$|rhxrmlbmc~p@VxU;h} z>+7$-&LSDM7Q^s|AAV4}y1K&16#yl0`0!!JQ;4s=`YHx@Pu#6M2XJh%&_zT>QN|Zv ze37vn9Fatz1VDd(f3{P6eSLk|vfcv&1BT_`KlvQqaf=W1fd-@JK)a-m`ZDSiAIg#S zHtR#O7-RH|+Sb;lE?BU@(OjOGJoM_TujUct<{ z$s)xOf9tKc;-7r-3FjF_c=!zpTuVz!?klgnl27-1y5~A=(_}K4{pFWmYJG#nQKRRG z_S`L7wrKRVwzjJD+0l_+lHcHW-+dQ4cI;T_#~*(*mo0<~#=}qoM~@zL6;689s#PIs ztOPY$9`4P}%_$v<@A7{DnN-)Z+fe8*ikPhrkxEzy7)^{!eV*zTK4{K~qzcf_9Q^MkD)> z@^Z%Ws2JHCp~t|!k1Dm!>169 zTK-Ca-#jDx&<~#BeaLx+XpBhu(6>aRCw)l5uOJK9nKNgU-rnA!W#UKtNg5&;@c1IL zFo@K|$WDp`g&%zIK^S-OJ@(E!?}WX?hxBF$fGErV@WT(o@4x?kM1H6La=fOIXvmS} z6J!gJ^!bL5=!zkw+eaUL1RAyP?d|Q+3@P56;tMnSQu+{mi$3<6XOOEBxheq2T17Y` z@;fqF`^hteBkXq{B2K@ghiJ?ws=5Z@&#K_x$?6c1XfqoD9fv=;ZL!t7sX}%l*An}QSEWc=^d1Myo<3RQB4IgM>bZJ1eW`lO0 z`Y^=%j_~20bKt;%pda|C{S-ZY0A#ZE10N#hQrTE%(P(45^QY;<|LcV;#8_Me96fpz z_mH3Xu!cbpmT=_Ak&xds3S3zN!hYieO`JxyW8+sJhD6_KK=^|`)2DQHc7`Po?%*)A zX_(RHdmnQ80D(X2_4Cg^D<@B$3`)Sf#7}(P-QAe?D7Z@)PWlKm{C?BOp{J+ESA6I* u4xrgje4uAI>BEIS - - - - - - - - - - - - - diff --git a/apps/scully-docs/src/assets/scully-triad.svg b/apps/scully-docs/src/assets/scully-triad.svg deleted file mode 100644 index d2e888611..000000000 --- a/apps/scully-docs/src/assets/scully-triad.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/apps/scully-docs/src/assets/scullyio-icon.svg b/apps/scully-docs/src/assets/scullyio-icon.svg deleted file mode 100644 index e64540e5b..000000000 --- a/apps/scully-docs/src/assets/scullyio-icon.svg +++ /dev/null @@ -1 +0,0 @@ -icon \ No newline at end of file diff --git a/apps/scully-docs/src/assets/scullyio-logo.svg b/apps/scully-docs/src/assets/scullyio-logo.svg deleted file mode 100644 index 3b11bd6ba..000000000 --- a/apps/scully-docs/src/assets/scullyio-logo.svg +++ /dev/null @@ -1 +0,0 @@ -logo \ No newline at end of file diff --git a/apps/scully-docs/src/assets/wordmark.svg b/apps/scully-docs/src/assets/wordmark.svg deleted file mode 100644 index 871c5137b..000000000 --- a/apps/scully-docs/src/assets/wordmark.svg +++ /dev/null @@ -1 +0,0 @@ -wordmark \ No newline at end of file diff --git a/apps/scully-docs/src/closeLangSelect.js b/apps/scully-docs/src/closeLangSelect.js new file mode 100644 index 000000000..74f1cb945 --- /dev/null +++ b/apps/scully-docs/src/closeLangSelect.js @@ -0,0 +1,7 @@ +document.addEventListener('click', (e) => { + const checkbox = document.getElementById('lang-select-checkbox'); + const label = document.getElementById('lang-select-label'); + const span = document.getElementById('lang-select-text'); + if (e.target !== checkbox && e.target !== label && e.target !== span && window.location.pathname !== '/') + checkbox.checked = false; +}); diff --git a/apps/scully-docs/src/docs/doc-page/doc-page.component.css b/apps/scully-docs/src/docs/doc-page/doc-page.component.css deleted file mode 100644 index e69de29bb..000000000 diff --git a/apps/scully-docs/src/docs/doc-page/doc-page.component.html b/apps/scully-docs/src/docs/doc-page/doc-page.component.html deleted file mode 100644 index 70dff2d0d..000000000 --- a/apps/scully-docs/src/docs/doc-page/doc-page.component.html +++ /dev/null @@ -1,10 +0,0 @@ - - diff --git a/apps/scully-docs/src/docs/doc-page/doc-page.component.spec.ts b/apps/scully-docs/src/docs/doc-page/doc-page.component.spec.ts deleted file mode 100644 index 49de2cf4a..000000000 --- a/apps/scully-docs/src/docs/doc-page/doc-page.component.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { DocPageComponent } from './doc-page.component'; - -describe('DocPageComponent', () => { - let component: DocPageComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [DocPageComponent] - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(DocPageComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/apps/scully-docs/src/docs/doc-page/doc-page.component.ts b/apps/scully-docs/src/docs/doc-page/doc-page.component.ts deleted file mode 100644 index ad3889aa4..000000000 --- a/apps/scully-docs/src/docs/doc-page/doc-page.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -@Component({ - selector: 'app-doc-page', - templateUrl: './doc-page.component.html', - styleUrls: ['./doc-page.component.css'] -}) -export class DocPageComponent implements OnInit { - constructor() {} - - ngOnInit(): void {} -} diff --git a/apps/scully-docs/src/docs/docs-routing.module.ts b/apps/scully-docs/src/docs/docs-routing.module.ts deleted file mode 100644 index 849341b0b..000000000 --- a/apps/scully-docs/src/docs/docs-routing.module.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { NgModule } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; - -import { DocsComponent } from './docs.component'; -import { DocPageComponent } from './doc-page/doc-page.component'; - -const routes: Routes = [ - { - path: '', - component: DocsComponent, - children: [ - { path: ':slug', component: DocPageComponent }, - { path: '**', component: DocPageComponent } - ] - } -]; - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule] -}) -export class DocsRoutingModule {} diff --git a/apps/scully-docs/src/docs/docs.component.css b/apps/scully-docs/src/docs/docs.component.css deleted file mode 100644 index e69de29bb..000000000 diff --git a/apps/scully-docs/src/docs/docs.component.html b/apps/scully-docs/src/docs/docs.component.html deleted file mode 100644 index 432dbd303..000000000 --- a/apps/scully-docs/src/docs/docs.component.html +++ /dev/null @@ -1,13 +0,0 @@ - - -

      - -
      -
      diff --git a/apps/scully-docs/src/docs/docs.component.spec.ts b/apps/scully-docs/src/docs/docs.component.spec.ts deleted file mode 100644 index c3d90fccd..000000000 --- a/apps/scully-docs/src/docs/docs.component.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { DocsComponent } from './docs.component'; - -describe('DocsComponent', () => { - let component: DocsComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [DocsComponent] - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(DocsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/apps/scully-docs/src/docs/docs.component.ts b/apps/scully-docs/src/docs/docs.component.ts deleted file mode 100644 index fc5167f03..000000000 --- a/apps/scully-docs/src/docs/docs.component.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { ScullyRoutesService, ScullyRoute } from '@scullyio/ng-lib'; -import { filter, first, map } from 'rxjs/operators'; - -@Component({ - selector: 'app-docs', - templateUrl: './docs.component.html', - styleUrls: ['./docs.component.css'], -}) -export class DocsComponent implements OnInit { - docs$ = this.srs.available$.pipe( - map((routes) => routes.filter((r) => r.route.startsWith('/docs/'))), - map((routes) => - routes.map((r) => ((r.title = r.title || properify(r.route)), r)) - ), - map((routes) => sortRoutes(routes)) - ); - - constructor(private srs: ScullyRoutesService) {} - - ngOnInit(): void {} -} - -function sortRoutes(routes: ScullyRoute[]): ScullyRoute[] { - return routes - .map((r) => ({ ...r, order: r.order || 9999 })) - .sort((x, y) => (x.order < y.order ? -1 : 1)); -} - -function properify(s: string): string { - return s.split('/docs/').join(''); -} diff --git a/apps/scully-docs/src/docs/docs.module.ts b/apps/scully-docs/src/docs/docs.module.ts deleted file mode 100644 index e89f3cc6a..000000000 --- a/apps/scully-docs/src/docs/docs.module.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { DocPageComponent } from './doc-page/doc-page.component'; -import { DocsRoutingModule } from './docs-routing.module'; -import { DocsComponent } from './docs.component'; -import { ScullyLibModule } from '@scullyio/ng-lib'; -import { ComponentsModule } from '../app/components/components.module'; -import { FormsModule } from '@angular/forms'; - -@NgModule({ - declarations: [DocsComponent, DocPageComponent], - imports: [ - CommonModule, - DocsRoutingModule, - ScullyLibModule, - ComponentsModule, - FormsModule - ] -}) -export class DocsModule {} diff --git a/apps/scully-docs/src/index.html b/apps/scully-docs/src/index.html index b68d36956..c5226a461 100644 --- a/apps/scully-docs/src/index.html +++ b/apps/scully-docs/src/index.html @@ -6,10 +6,8 @@ - - beta diff --git a/apps/scully-docs/src/styles.css b/apps/scully-docs/src/styles.css deleted file mode 100644 index 8c8fafdf0..000000000 --- a/apps/scully-docs/src/styles.css +++ /dev/null @@ -1,455 +0,0 @@ -@import url('https://fonts.googleapis.com/css?family=Comfortaa|PT+Mono&display=swap'); - -*, -*::before, -*::after { - box-sizing: border-box; - margin: 0; - padding: 0; -} - -@charset "UTF-8"; -.tabs label, -.text-center { - text-align: center; -} - -/* VARS */ - -:root { - /* COLORS */ - --scully-green: #3aa860; - --scully-brightgreen: #6cce7a; - --scully-night: #232d2a; - --scully-darkgray: #4c615b; - --scully-lightgray: #d3d3d3; - --scully-offwhite: #fafbfc; - --scully-white: #ffffff; - --scully-black: #000000; - --scully-green-wash: rgba(58, 168, 96, 0.05); -} - -/* reset */ -a, -aside, -body, -div, -h1, -h2, -h3, -h4, -h5, -h6, -header, -input, -label, -menu, -p { - font-family: Comfortaa, Roboto, sans-serif; -} -h1, -h2, -h3, -h4, -h5, -h6 { - margin-bottom: 0.8em; - line-height: 130%; -} -p { - margin-bottom: 20px; - letter-spacing: 0.02rem; - line-height: 2rem; -} -h1 { - color: var(--scully-night); - font-size: 24px; - font-weight: bold; - margin: 8px 0 8px 0; -} -h2 { - color: var(--scully-green); - font-size: 18px; - font-weight: bold; - text-transform: uppercase; -} -h3 { - font-size: 18px; - font-weight: bold; - color: var(--scully-night); -} -/* Marketing Blurb Header */ -h4 { - /* Should be 32px according to guidelines but it looks way too big */ - font-size: 16px; - font-weight: bold; - color: var(--scully-darkgray); -} -h5 { - font-size: 20.8px; -} -h6 { - font-size: 18px; -} -a, -p { - font-size: 16px; - margin-top: 16px; -} - -body { - color: var(--scully-darkgray); - font-size: 16px; - line-height: 1.2; -} -ol { - margin-bottom: 24px; - list-style-position: inside; - letter-spacing: 0.03rem; -} -li { - padding-bottom: 8px; -} - -playground-host { - display: block; - padding: 50px; - background-image: linear-gradient( - 45deg, - #fcfcfc 16.67%, - #858585 16.67%, - #858585 33.33%, - #fff 33.33%, - #fff 50%, - #fcfcfc 50%, - #fcfcfc 66.67%, - #858585 66.67%, - #858585 83.33%, - #fff 83.33%, - #fff 100% - ); - background-size: 8.49px 8.49px; -} - -/* BUTTONS */ - -nav > a, -nav > app-button > a { - background-color: var(--scully-green); - color: var(--scully-white); - display: inline-block; - padding: 12px; - margin: 10px 3px; - border-radius: 4px; - height: 40px; - min-width: 168px; - text-align: center; - text-decoration: none; - cursor: pointer; -} - -app-doc-page > li > ul { - margin-left: 20px; -} - -app-docs { - margin-top: 20px; -} - -nav > a.btn-secondary, -nav > app-button > a.btn-secondary { - background-color: var(--scully-white); - color: var(--scully-night); - display: inline-block; - padding: 12px; - margin: 10px 3px; - border-radius: 4px; - height: 40px; - min-width: 60px; - text-align: center; - text-decoration: none; - cursor: pointer; -} - -nav > a.btn-invert, -nav > app-button > a.btn-invert { - color: var(--scully-green); - background-color: var(--scully-white); - border: 1px solid var(--scully-green); - border-radius: 4px; - display: inline-block; - padding: 12px; - margin: 10px 3px; - height: 40px; - min-width: 168px; - text-align: center; - text-decoration: none; - cursor: pointer; -} - -.router-link-active { - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); - transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); -} - -nav > a:hover, -nav > app-button > a.router-link-active:hover { - box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22); -} - -nav > a:active, -nav > app-button > a.router-link-active:active { - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); -} - -/* BOOKS */ -app-book > a { - width: 90%; - margin: auto; - min-height: 160px; - background-color: var(--scully-offwhite); - border-radius: 4px; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-color: var(--scully-lightgray); - box-shadow: 0 3px 8px rgba(0, 0, 50, 0.15); - -moz-box-shadow: 0 3px 8px rgba(0, 0, 50, 0.15); - -webkit-box-shadow: 0 3px 8px rgba(0, 0, 50, 0.15); - display: flex; - justify-content: flex-start; - align-items: center; - text-decoration: none; -} - -app-book > a > img { - height: 80px; - margin: 40px; -} - -app-book > a > .card-content > h3 { - color: var(--scully-green); - margin-bottom: 0; - margin-top: 5px; - text-align: left; -} - -app-book > a > .card-content > p { - text-align: left; - line-height: 2; - margin-bottom: 0; - margin-right: 56px; - color: var(--scully-darkgray); -} - -/* CARDS */ -app-card > div { - width: 90%; - min-height: 380px; - padding: 5%; - background-color: var(--scully-night); - border-radius: 10px; - -webkit-border-radius: 10px; - -moz-border-radius: 10px; - box-shadow: 0 3px 8px rgba(0, 0, 50, 0.15); - -moz-box-shadow: 0 3px 8px rgba(0, 0, 50, 0.15); - -webkit-box-shadow: 0 3px 8px rgba(0, 0, 50, 0.15); -} - -app-card > div > .icon-background { - width: 60px; - height: 60px; - margin: 20px auto; - background-color: var(--scully-darkgray); - border-radius: 50%; - -moz-border-radius: 50%; - -webkit-border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; -} - -app-card > div > .icon-background > img { - width: 40px; - height: 40px; -} - -.svg { - filter: invert(1); -} - -app-card > div > .card-content > p { - text-align: center; - line-height: 2; - margin-bottom: 0; -} - -app-card > div > .card-content > .header { - color: var(--scully-brightgreen); -} - -app-card > div > .card-content > .main-text { - color: var(--scully-offwhite); -} - -/* CODE */ -app-code > pre, -pre { - background: var(--scully-night); - color: var(--scully-offwhite); - border-radius: 8px; - border-top: black solid 15px; - overflow-x: auto; - min-height: 100px; - padding: 16px 35px 35px 20px; - margin: 35px 75px; -} - -app-code > pre > code::before, -pre > code::before { - background-color: var(--scully-darkgray); - border-radius: 3px; - border-left: 3px solid var(--scully-darkgray); - border-right: 3px solid var(--scully-darkgray); - content: attr(class); - text-indent: -9.2ch; - text-transform: uppercase; - display: block; - padding: 2px 2px; - margin-bottom: 16px; - width: fit-content; - overflow: hidden; -} - -/* HEADER */ -app-header > p.header-title, -p.header-title { - color: var(--scully-green); - font-size: 60px; - font-weight: bold; - line-height: 100%; - padding-top: 15%; -} - -app-marketing-header > h1.marketing, -h1.marketing { - font-color: var(--scully-night); - font-size: 32px; - font-weight: bold; -} - -/* SUB HEADER */ -app-subheader > p.subheader-title, -p.subheader-title { - color: var(--scully-brightgreen); - font-size: 24px; -} - -.color-scully-green { - color: var(--scully-green); - font-weight: bold; -} - -/* ICON */ - -/* LEFT MENU */ - -/* LINE */ -app-hr > hr { - padding: 3px; - border: 1px solid var(--scully-brightgreen); - border-radius: 5px; - background: var(--scully-brightgreen); - width: 170px; -} - -hr { - margin-bottom: 60px; -} - -.invert { - filter: invert(1); -} - -.hljs-comment, -.hljs-quote { - color: #d4d0ab; -} -.hljs-variable, -.hljs-template-variable, -.hljs-tag, -.hljs-name, -.hljs-selector-id, -.hljs-selector-class, -.hljs-regexp, -.hljs-deletion { - color: #ffa07a; -} -.hljs-number, -.hljs-built_in, -.hljs-builtin-name, -.hljs-literal, -.hljs-type, -.hljs-params, -.hljs-meta, -.hljs-link { - color: #f5ab35; -} -.hljs-attribute { - color: #ffd700; -} -.hljs-string, -.hljs-symbol, -.hljs-bullet, -.hljs-addition { - color: #abe338; -} -.hljs-title, -.hljs-section { - color: #00e0e0; -} -.hljs-keyword, -.hljs-selector-tag { - color: #dcc6e0; -} -.hljs { - display: block; - overflow-x: auto; - background: #2b2b2b; - color: #f8f8f2; - padding: 0.5em; -} -.hljs-emphasis { - font-style: italic; -} -.hljs-strong { - font-weight: bold; -} - -.badge { - position: absolute; - width: 80px; -} - -@media screen and (-ms-high-contrast: active) { - .hljs-addition, - .hljs-attribute, - .hljs-built_in, - .hljs-builtin-name, - .hljs-bullet, - .hljs-comment, - .hljs-link, - .hljs-literal, - .hljs-meta, - .hljs-number, - .hljs-params, - .hljs-string, - .hljs-symbol, - .hljs-type, - .hljs-quote { - color: highlight; - } - .hljs-keyword, - .hljs-selector-tag { - font-weight: bold; - } -} diff --git a/apps/scully-docs/src/styles/_beta.css b/apps/scully-docs/src/styles/_beta.css new file mode 100644 index 000000000..7daf8dc77 --- /dev/null +++ b/apps/scully-docs/src/styles/_beta.css @@ -0,0 +1,8 @@ +img.badge { + position: absolute; + top: 0; + left: 0; + height: 100%; + width: auto; + z-index: 99999; +} diff --git a/apps/scully-docs/src/styles/_fonts.css b/apps/scully-docs/src/styles/_fonts.css new file mode 100644 index 000000000..f05438573 --- /dev/null +++ b/apps/scully-docs/src/styles/_fonts.css @@ -0,0 +1,2 @@ +@import url('https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,400;0,600;0,700;0,800;0,900;1,400;1,600;1,700;1,800;1,900&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,400;0,500;0,600;1,400;1,500;1,600&display=swap'); diff --git a/apps/scully-docs/src/styles/_reset.css b/apps/scully-docs/src/styles/_reset.css new file mode 100644 index 000000000..4b565d267 --- /dev/null +++ b/apps/scully-docs/src/styles/_reset.css @@ -0,0 +1,39 @@ +*, +*::before, +*::after, +html, +body { + margin: 0; + padding: 0; + box-sizing: border-box; + text-rendering: optimizeLegibility !important; + -webkit-font-smoothing: antialiased !important; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} +html, +body { + height: 100%; + color: var(--scully-text-color); + font-family: Nunito, Roboto, sans-serif; + font-weight: 700; + background: var(--scully-white); + overflow-x: hidden; +} + +a, +button { + display: block; + border: 0; + padding: 0; + font-family: Nunito, Roboto, sans-serif; + font-weight: 600; + text-decoration: none; + background: none; + outline: none; + cursor: pointer; +} +a:disabled, +a:active:disabled, +button:disabled { + cursor: not-allowed; +} diff --git a/apps/scully-docs/src/styles/_variables.css b/apps/scully-docs/src/styles/_variables.css new file mode 100644 index 000000000..461c9bebe --- /dev/null +++ b/apps/scully-docs/src/styles/_variables.css @@ -0,0 +1,20 @@ +:root { + /* COLORS */ + --scully-green: rgb(27, 172, 78); + --scully-night: #232d2a; + --scully-night-darker: #181818; + --scully-darkgray-lighter: #6c857d; + --scully-link-blue: #0078bd; + --scully-link-blue-light: rgb(57, 206, 243); + --scully-text-color: #191819; + --scully-white: #ffffff; + --scully-black: #000000; + /* filter color equivalents for things like images */ + --scully-green-filter: invert(43%) sepia(96%) saturate(1549%) hue-rotate(110deg) brightness(96%) contrast(79%); + --scully-darkgray-lighter-filter: invert(53%) sepia(24%) saturate(234%) hue-rotate(110deg) brightness(89%) contrast(90%); + --scully-link-blue-filter: invert(26%) sepia(46%) saturate(4161%) hue-rotate(184deg) brightness(97%) contrast(101%); + --scully-white-filter: brightness(0) invert(1); + --scully-grey_5-filter: brightness(0) invert(0.5); + /* transitions */ + --scully-transition-ease: 160ms ease; +} diff --git a/apps/scully-docs/src/styles/blockquote.css b/apps/scully-docs/src/styles/blockquote.css new file mode 100644 index 000000000..82b9fa44d --- /dev/null +++ b/apps/scully-docs/src/styles/blockquote.css @@ -0,0 +1,36 @@ +.docs-page-content blockquote { + box-sizing: border-box; + position: relative; + max-width: 858px; + margin: 12px 0 24px; + margin-left: 42px; + padding: 18px 30px; + border-left: solid 4px var(--scully-darkgray-lighter); + border-radius: 4px; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1); + background: var(--scully-white); + background: rgba(0, 0, 0, 0.02); +} +.docs-page-content blockquote::before { + content: '"'; + position: absolute; + left: -48px; + top: 27px; + width: 34px; + height: 34px; + color: var(--scully-darkgray-lighter); + font-size: 44px; + font-weight: 800; + background: var(--scully-white); + transform: skew(-10deg); + opacity: 0.8; +} + +.docs-page-content blockquote, +.docs-page-content blockquote p { + font-size: 15px; + line-height: 27px; +} +.docs-page-content blockquote p:last-child { + margin-bottom: 0; +} diff --git a/apps/scully-docs/src/styles/code.css b/apps/scully-docs/src/styles/code.css new file mode 100644 index 000000000..dc2e72c9a --- /dev/null +++ b/apps/scully-docs/src/styles/code.css @@ -0,0 +1,136 @@ +.docs-page-content pre, +.docs-page-content code { + max-width: 900px; + color: rgba(0, 0, 0, 0.7); + font-family: 'Roboto Mono', monospace; + font-size: 13px; + font-weight: 500; + border-radius: 4px; + overflow-x: auto; +} + +.docs-page-content pre { + position: relative; + align-self: stretch; + margin-bottom: 24px; + padding: 16px 22px; + padding-right: 42px; + background: var(--scully-night); +} + +.docs-page-content pre:not([class]) { + align-self: flex-start; +} + +.docs-page-content code { + margin: 0 2px; + padding: 2px 6px; + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.1); + background: rgba(68, 106, 107, 0.1); +} + +.docs-page-content pre code { + max-width: 100%; + margin: 0; + padding: 0; + color: var(--scully-white); + font-weight: 400; + letter-spacing: 0.5px; + background: none; + box-shadow: none; + overflow-x: auto; +} +.docs-page-content pre code::before { + content: attr(class); + position: relative; + display: block; + margin-bottom: 6px; + color: rgba(255, 255, 255, 0.5); + font-family: 'Nunito', sans-serif; + font-size: 8px; + font-weight: 700; + text-indent: calc(-13ch - 2px); + text-transform: uppercase; + letter-spacing: 2px; + overflow: hidden; + transform: translateY(-6px) translateX(-11px); +} +/* if code block pre not labeled, it shouldn't take up DOM space */ +.docs-page-content pre code:not([class])::before { + margin-bottom: -1px; +} + +.docs-page-content p code { + white-space: nowrap; +} + +.docs-page-content strong code { + font-weight: 900; +} + +.docs-page-content a code { + color: var(--scully-link-blue); + font-weight: 600; +} +.docs-page-content a:hover code { + color: var(--scully-link-blue-light); + background: rgba(68, 106, 107, 0.05); +} + +.docs-page-content h1 code, +.docs-page-content h2 code, +.docs-page-content h3 code, +.docs-page-content h4 code, +.docs-page-content h6 code { + color: rgba(0, 0, 0, 0.9); + font-size: 16px; + font-weight: 500; + background: rgba(68, 106, 107, 0.05); + background: none; + padding: 0; + box-shadow: none; + overflow: visible; +} +.docs-page-content h1 code { + margin-right: 8px; + color: var(--scully-black); + font-size: 36px; + box-shadow: none; + background: none; +} +.docs-page-content h2 code { + margin-left: 4px; + margin-right: 4px; + margin-bottom: 3px; + color: var(--scully-black); + font-weight: 800; + font-size: 18px; + text-transform: none; + box-shadow: none; + background: none; +} + +.docs-page-content h1 a code, +.docs-page-content h2 a code, +.docs-page-content h3 a code, +.docs-page-content h4 a code, +.docs-page-content h5 a code, +.docs-page-content h6 a code { + color: var(--scully-link-blue); + box-shadow: none; + background: none; + overflow: visible; +} +.docs-page-content h1 a code:hover, +.docs-page-content h2 a code:hover, +.docs-page-content h3 a code:hover, +.docs-page-content h4 a code:hover, +.docs-page-content h5 a code:hover, +.docs-page-content h6 a code:hover { + box-shadow: none; + background: none; +} + +.docs-page-content table td code { + background: rgba(0, 0, 0, 0.05); +} diff --git a/apps/scully-docs/src/styles/details.css b/apps/scully-docs/src/styles/details.css new file mode 100644 index 000000000..fd5ca8d41 --- /dev/null +++ b/apps/scully-docs/src/styles/details.css @@ -0,0 +1,43 @@ +.docs-page-content details { + position: relative; + max-width: 900px; + list-style: none; + outline: none; +} + +.docs-page-content details summary { + margin: 8px 0; + color: var(--scully-link-blue); + outline: none; + cursor: pointer; +} +.docs-page-content details summary:hover { + color: var(--scully-link-blue-light); +} + +.docs-page-content details[open] { + margin-bottom: 42px; +} + +.docs-page-content details[open] summary + blockquote { + margin-top: 28px; +} + +.docs-page-content details[open] summary ~ * { + animation: sweep 240ms ease-out; +} + +.docs-page-content details[open] summary { + margin-bottom: 14px; +} + +@keyframes sweep { + 0% { + opacity: 0.9; + transform: translateY(-10px); + } + 100% { + opacity: 1; + transform: translateY(0px); + } +} diff --git a/apps/scully-docs/src/styles/headings.css b/apps/scully-docs/src/styles/headings.css new file mode 100644 index 000000000..4c69c88a6 --- /dev/null +++ b/apps/scully-docs/src/styles/headings.css @@ -0,0 +1,70 @@ +.docs-page-content h1 { + margin-bottom: 24px; + font-size: 44px; + line-height: 1.1; + letter-spacing: -0.5px; + opacity: 0.9; +} + +.docs-page-content h2 { + margin-top: 32px; + margin-bottom: 18px; + font-size: 18px; + font-weight: 900; + text-transform: uppercase; + opacity: 0.9; +} + +.docs-page-content h3, +.docs-page-content h5 { + margin-top: 24px; + margin-bottom: 20px; + color: rgba(0, 0, 0, 0.9); + font-size: 20px; + font-weight: 600; +} +.docs-page-content h2 + h3 { + margin-top: 6px; +} + +.docs-page-content h4 { + margin-top: 24px; + margin-bottom: 24px; + padding-top: 16px; + color: rgba(0, 0, 0, 0.9); + font-size: 20px; + font-weight: 600; + border-top: solid 3px rgba(0, 0, 0, 0.05); +} + +.docs-page-content h5 { + font-size: 18px; + font-weight: 800; +} + +.docs-page-content ul + h2, +.docs-page-content ul + h3, +.docs-page-content ul + h4 { + margin-top: 42px; +} + +/* A trick to make code heading margins look appear as if +only removing left margin of code block, if it is the first +element of a code block in a heading. +Leaves margins when code block is surrounded by inline text. */ +.docs-page-content h1, +.docs-page-content h2, +.docs-page-content h3, +.docs-page-content h4, +.docs-page-content h5, +.docs-page-content h6 { + display: inline-grid; + align-self: flex-start; + grid-auto-flow: column; + justify-content: space-between; + align-items: center; + gap: 6px; +} +.docs-page-content h1 { + gap: 8px; +} diff --git a/apps/scully-docs/src/styles/icon_button.css b/apps/scully-docs/src/styles/icon_button.css new file mode 100644 index 000000000..043523413 --- /dev/null +++ b/apps/scully-docs/src/styles/icon_button.css @@ -0,0 +1,34 @@ +.docs-icon-button { + --button-color: var(--scully-link-blue); + --button-color-filter: var(--scully-link-blue-filter); + display: flex !important; + align-items: center; + max-width: 360px; + margin: 24px 0; + padding: 18px 30px; + padding-right: 84px; + color: var(--button-color); + font-size: 14px; + font-weight: 700; + line-height: 18px; + border: solid 2px var(--button-color); + border-radius: 6px; + transition: background-color var(--scully-transition-ease); +} +.docs-icon-button:active { + transform: translateY(1px); +} +.docs-icon-button:hover { + color: var(--scully-white); + background: var(--button-color); +} + +.docs-icon-button img { + width: 16px; + height: 16px; + margin-right: 30px; + filter: var(--button-color-filter); +} +.docs-icon-button:hover img { + filter: var(--scully-white-filter); +} diff --git a/apps/scully-docs/src/styles/link_table.css b/apps/scully-docs/src/styles/link_table.css new file mode 100644 index 000000000..d744263a1 --- /dev/null +++ b/apps/scully-docs/src/styles/link_table.css @@ -0,0 +1,83 @@ +.docs-link_table { + display: flex; + align-self: flex-start; + margin-bottom: 24px; + box-shadow: inset 0 0 0 1px rgb(223, 226, 229); + border-radius: 3px; + overflow: hidden; +} + +.docs-link_table a { + display: flex; + padding: 10px 15px; + padding-right: 18px; + color: #586069; + font-size: 12px; + font-weight: 700; + text-transform: capitalize; + transition: background-color var(--scully-transition-ease); +} +.docs-link_table a:not(:first-child) { + border-left: solid 1px rgb(223, 226, 229); +} + +.docs-link_table a:active { + transform: translateY(1px); +} +.docs-link_table a:hover { + color: var(--scully-white); + background: var(--scully-green); +} + +.docs-link_table a::after { + position: relative; +} +.docs-link_table a::before { + content: ''; + position: relative; + display: block; + width: 14px; + height: 16px; + margin-right: 12px; + background-position: center; + background-repeat: no-repeat; + background-size: contain; + opacity: 0.8; + filter: var(--scully-green-filter); +} +.docs-link_table a:hover::before { + opacity: 1; + filter: var(--scully-white-filter); +} + +/* homepage */ +.docs-link_table a.homepage::before { + background-image: url('/assets/img/icons/globe-solid.svg'); +} +.docs-link_table a.homepage::after { + content: 'homepage'; +} + +/* repository */ +.docs-link_table a.repository::before { + background-image: url('/assets/img/icons/code-branch-solid.svg'); +} +.docs-link_table a.repository::after { + content: 'repository'; +} + +/* view-code */ +.docs-link_table a.view-code::before { + background-image: url('/assets/img/icons/code-branch-solid.svg'); +} +.docs-link_table a.view-code::after { + content: 'view code'; +} + +/* view-in-repo */ +.docs-link_table a.view-in-repo::before { + background-image: url('/assets/img/icons/code-branch-solid.svg'); +} +.docs-link_table a.view-in-repo::after { + content: 'view in repository'; +} diff --git a/apps/scully-docs/src/styles/links.css b/apps/scully-docs/src/styles/links.css new file mode 100644 index 000000000..c2ba2a032 --- /dev/null +++ b/apps/scully-docs/src/styles/links.css @@ -0,0 +1,13 @@ +.docs-page-content a:not([class]) { + display: inline-block; + padding: 0 2px; + color: var(--scully-link-blue); + font-weight: 800; +} +.docs-page-content a:not([class]):hover { + color: var(--scully-link-blue-light); +} + +.docs-page-content h2 a { + font-weight: 900; +} diff --git a/apps/scully-docs/src/styles/paragraph_list.css b/apps/scully-docs/src/styles/paragraph_list.css new file mode 100644 index 000000000..a0ce11c5e --- /dev/null +++ b/apps/scully-docs/src/styles/paragraph_list.css @@ -0,0 +1,32 @@ +.docs-page-content li, +.docs-page-content p { + max-width: 900px; + margin-bottom: 18px; + color: rgba(0, 0, 0, 0.8); + font-size: 16px; + font-weight: 600; + line-height: 30px; + letter-spacing: 0.2px; +} +.docs-page-content li p { + margin-bottom: 0; +} +.docs-page-content ul + p { + margin-top: 18px; +} + +.docs-page-content ul { + padding-left: 24px; +} +.docs-page-content ul li { + margin-bottom: 0px; +} + +.docs-page-content b, +.docs-page-content strong { + font-weight: 800; +} + +.docs-page-content h1 + p { + margin-top: 28px; +} diff --git a/apps/scully-docs/src/styles/prev_next.css b/apps/scully-docs/src/styles/prev_next.css new file mode 100644 index 000000000..e77aed9a6 --- /dev/null +++ b/apps/scully-docs/src/styles/prev_next.css @@ -0,0 +1,89 @@ +.docs-prev_next { + display: grid; + grid-template-columns: 1fr 0.382fr 1fr; + gap: 12px; + justify-items: stretch; + align-items: center; + width: 100%; + margin: 94px 0; + padding: 4px 0; +} +@media screen and (max-width: 1400px) { + .docs-prev_next { + grid-template-columns: repeat(2, 1fr); + } +} + +.docs-prev_next a { + display: flex; + justify-content: space-between; + flex: 0.382; + padding: 18px 30px; + color: var(--scully-green); + font-size: 12px; + font-weight: 900; + text-transform: uppercase; + letter-spacing: 1px; + border: solid 2px var(--scully-green); + border-radius: 6px; + transition: background-color var(--scully-transition-ease), border-color var(--scully-transition-ease); +} + +.docs-prev_next a::before, +.docs-prev_next a::after { + content: ''; + position: relative; + width: 15px; + height: 16px; + background-position: center; + background-repeat: no-repeat; + background-size: contain; + filter: var(--scully-green-filter); +} + +.docs-prev_next a.prev { + --icon-margin: 24px; + color: rgba(0, 0, 0, 0.5); + border-color: rgba(0, 0, 0, 0.05); + grid-column-start: 1; + grid-column-end: 2; + justify-content: flex-start; +} +.docs-prev_next a.prev::before { + margin-right: var(--icon-margin); + background-image: url('/assets/img/icons/arrow-left-solid.svg'); + filter: var(--scully-grey_5-filter); +} +.docs-prev_next a.next::before { + display: none; +} +.docs-prev_next a.next::after { + margin-left: var(--icon-margin); + grid-column-start: 3; + grid-column-end: 4; + background-image: url('/assets/img/icons/arrow-right-solid.svg'); + /* justify-content:flex-end; asymmetrical but still reads ok ltr */ +} +.docs-prev_next a.next { + grid-column-start: 3; + grid-column-end: 4; +} +@media screen and (max-width: 1400px) { + .docs-prev_next a.next { + grid-column-start: 2; + grid-column-end: 3; + } +} + +.docs-prev_next a:active { + transform: translateY(1px); +} +.docs-prev_next a:hover { + color: var(--scully-white); + border-color: var(--scully-green); + background: var(--scully-green); +} +.docs-prev_next a:hover::before, +.docs-prev_next a:hover::after { + filter: var(--scully-white-filter); +} diff --git a/apps/scully-docs/src/styles/prism-scully.css b/apps/scully-docs/src/styles/prism-scully.css new file mode 100644 index 000000000..19ab52af1 --- /dev/null +++ b/apps/scully-docs/src/styles/prism-scully.css @@ -0,0 +1,94 @@ +/** + * prism.js Scully.io theme + * Based on Funky theme by Lea Verou http://lea.verou.me/polyfilling-the-gaps/ + * @author @donmckenna_ + */ + +.token.comment { + color: #777; +} + +.token.prolog, +.token.doctype, +.token.cdata { + color: #aaa; +} + +.token.namespace { + opacity: 0.7; +} + +.token.punctuation, +.token.operator, +.token.constant { + color: #fff; +} + +.token.tag .token.punctuation { + color: #999; +} + +.token.atrule, +.token.boolean, +.token.interpolation-punctuation, +.token.keyword, +.token.property, +.token.symbol, +.token.tag { + color: rgb(127, 201, 250); +} + +.token.number { + color: #fff1a0; +} + +.token.attr-value, +.token.builtin, +.token.char, +.token.selector, +.token.string, +.token.variable, +.language-css .token.string, +pre.diff-highlight.diff-highlight > code .token.inserted:not(.prefix), +pre > code.diff-highlight.diff-highlight .token.inserted:not(.prefix), +pre > code.language-json .token.property { + color: #ffcb7c; +} + +.token.attr-name { + color: hsl(46, 100%, 86%); +} + +.token.entity, +.token.url, +.token.inserted { + color: yellowgreen; +} + +/* .token.important, <-- infiltrates .md syntax incorrectly */ +.token.regex { + color: orange; +} + +.token.important, +.token.bold { + font-weight: bold; +} +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +.token.deleted { + color: red; +} + +/* Plugin styles: Diff Highlight */ +pre.diff-highlight.diff-highlight > code .token.deleted:not(.prefix), +pre > code.diff-highlight.diff-highlight .token.deleted:not(.prefix) { + background-color: rgba(255, 0, 0, 0.3); + display: inline; +} diff --git a/apps/scully-docs/src/styles/showcase.css b/apps/scully-docs/src/styles/showcase.css new file mode 100644 index 000000000..08566806a --- /dev/null +++ b/apps/scully-docs/src/styles/showcase.css @@ -0,0 +1,47 @@ +.docs-page-content .docs-showcase { + position: relative; + display: grid; + grid-template-columns: repeat(4, 1fr); + grid-template-rows: auto; + gap: 24px; + margin-top: 24px; +} + +.docs-page-content .docs-showcase a { + position: relative; + display: grid; + grid-template-rows: repeat(auto, 2); + align-items: flex-end; + width: 100%; + padding-bottom: 10px; + color: var(--scully-night); + font-size: 14px; + font-weight: 700; + border-radius: 6px; + overflow: hidden; + opacity: 0.9; + transition: color var(--scully-transition-ease), opacity var(--scully-transition-ease); +} +.docs-page-content .docs-showcase a:active { + transform: translateY(1px); +} +.docs-page-content .docs-showcase a:hover { + color: var(--scully-link-blue-light); + opacity: 1; +} + +.docs-page-content .docs-showcase a img { + grid-row: 1 / 1; + align-self: flex-start; + width: auto; + max-height: 150px; + margin-bottom: 12px; + transform-origin: center bottom; + transition: opacity var(--scully-transition-ease), filter var(--scully-transition-ease); + opacity: 0.9; + filter: saturate(0) brightness(0.9); +} +.docs-page-content .docs-showcase a:hover img { + opacity: 1; + filter: saturate(1); +} diff --git a/apps/scully-docs/src/styles/table.css b/apps/scully-docs/src/styles/table.css new file mode 100644 index 000000000..9a2529695 --- /dev/null +++ b/apps/scully-docs/src/styles/table.css @@ -0,0 +1,28 @@ +.docs-page-content table { + margin-bottom: 32px; + border-collapse: collapse; +} +.docs-page-content table td, +.docs-page-content table th { + padding: 10px 12px; + font-size: 14px; +} +.docs-page-content table td { + font-weight: 600; +} +.docs-page-content table thead th { + font-size: 12px; + font-weight: 900; + text-transform: uppercase; + text-align: left; + letter-spacing: 1px; + opacity: 0.6; +} +.docs-page-content table tbody { + border-radius: 4px; + border-spacing: 4px; + border: solid 1px rgba(0, 0, 0, 0.1); +} +.docs-page-content table tr:nth-child(odd) td { + background: rgba(68, 106, 107, 0.05); +} diff --git a/apps/scully-docs/src/styles/toc.css b/apps/scully-docs/src/styles/toc.css new file mode 100644 index 000000000..2cf0a05b2 --- /dev/null +++ b/apps/scully-docs/src/styles/toc.css @@ -0,0 +1,62 @@ +.docs-page-content .docs-toc + ul { + display: flex; + flex-direction: column; + align-self: flex-start; + min-width: 384px; + max-width: 100%; + margin: 24px 0 24px; + padding: 20px 28px; + padding-right: 64px; + color: #586069; + font-weight: 700; + list-style: none; + border-radius: 3px; + border: solid 1px rgba(223, 226, 229, 0.6); + border-left: solid 4px var(--scully-green); + overflow: hidden; +} + +.docs-page-content .docs-toc + ul li { + position: relative; + margin-bottom: 0px; + font-size: 12px; + line-height: 1; + list-style: none; +} + +.docs-page-content .docs-toc + ul ul { + padding-left: 24px; +} +.docs-page-content .docs-toc + ul ul li:before { + content: ''; + position: absolute; + top: 0; + left: 0; + margin-top: 10px; + width: 4px; + height: 4px; + margin-left: -16px; + border-radius: 50%; + background: rgba(0, 0, 0, 0.15); +} + +.docs-page-content .docs-toc + ul a { + display: block; + padding: 7px 2px; + font-size: 13px; + font-weight: 700; + line-height: 1; +} + +.docs-page-content .docs-toc + ul code { + margin: 0; + padding: 0 2px; + font-size: 12px; + line-height: 1; + box-shadow: none; + background: none; +} + +.docs-page-content .docs-toc.no-spacing + ul { + margin: 6px 0 18px; +} diff --git a/docs/CODE_OF_CONDUCT_es.md b/docs/CODE_OF_CONDUCT_es.md deleted file mode 100644 index ca6a2026c..000000000 --- a/docs/CODE_OF_CONDUCT_es.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Codigo de Conducta -order: 900 -lang: es ---- - -# Código de Conducta - -Como contribuyentes y mantenedores del proyecto Scully, nos comprometemos a respetar a todos los que contribuyen mediante la publicación de problemas, la actualización de la documentación, el envío de solicitudes de extracción, la retroalimentación en los comentarios y cualquier otra actividad. -La comunicación a través de cualquiera de los canales de Scully (GitHub, Gitter, Twitter, etc.) debe ser constructiva y nunca recurrir a ataques personales, trolling, acoso público o privado, insultos u otra conducta no profesional. -Prometemos extender la cortesía y el respeto a todos los involucrados en este proyecto, independientemente de su género, identidad de género, orientación sexual, discapacidad, edad, raza, etnia, religión o nivel de experiencia. Esperamos que cualquiera que contribuya al proyecto Scully haga lo mismo. -Si algún miembro de la comunidad viola este código de conducta, los encargados del proyecto Scully pueden tomar medidas, eliminar problemas, comentarios y relaciones públicas o bloquear cuentas, según se considere apropiado. -Si está sujeto o es testigo de un comportamiento inaceptable, o tiene alguna otra inquietud, envíenos un correo electrónico a [coc@hero.dev](mailto: coc@hero.dev). diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md deleted file mode 100644 index 0c991ea7d..000000000 --- a/docs/CONTRIBUTING.md +++ /dev/null @@ -1,240 +0,0 @@ ---- -title: Contributing to Scully -order: 910 -lang: en ---- - -# Contributing to Scully - -We would love for you to contribute to Scully and help make it even better than it is -today! As a contributor, here are the guidelines we would like you to follow: - -- [Code of Conduct](#coc) -- [Question or Problem?](#question) -- [Issues and Bugs](#issue) -- [Feature Requests](#feature) -- [Submission Guidelines](#submit) -- [Coding Rules](#rules) -- [Commit Message Guidelines](#commit) -- [Signing the CLA](#signing-the-cla) - -##
      Code of Conduct - -Help us keep Scully open and inclusive. Please read and follow our [Code of Conduct][coc]. - -## Got a Question or Problem? - -Do not open issues for general support questions as we want to keep GitHub issues for bug reports and feature requests. You've got much better chances of getting your question answered on [Stack Overflow][stackoverflow]) where the questions should be tagged with tag `scully`. - -Stack Overflow is a much better place to ask questions since: - -- there are thousands of people willing to help on Stack Overflow -- questions and answers stay available for public viewing so your question / answer might help someone else -- Stack Overflow's voting system assures that the best answers are prominently visible. - -To save your and our time, we will systematically close all issues that are requests for general support and redirect people to Stack Overflow. - -If you would like to chat about the question in real-time, you can reach out via our [gitter channel](https://gitter.im/scullyio/community). - -## Found a Bug? - -If you find a bug in the source code, you can help us by -[submitting an issue][github-issue] to our [GitHub Repository][github]. Even better, you can -[submit a Pull Request](#submit-pr) with a fix. - -## Missing a Feature? - -You can _request_ a new feature by [submitting an issue](#submit-issue) to our GitHub -Repository. If you would like to _implement_ a new feature, please submit an issue with -a proposal for your work first, to be sure that we can use it. -Please consider what kind of change it is: - -- For a **Major Feature**, first open an issue and outline your proposal so that it can be - discussed. This will also allow us to better coordinate our efforts, prevent duplication of work, - and help you to craft the change so that it is successfully accepted into the project. -- **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr). - -## Submission Guidelines - -### Submitting an Issue - -Before you submit an issue, please search the issue tracker, maybe an issue for your problem already exists and the discussion might inform you of workarounds readily available. - -We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it. In order to reproduce bugs, we will systematically ask you to provide a minimal reproduction. Having a minimal reproducible scenario gives us a wealth of important information without going back & forth to you with additional questions. - -A minimal reproduction allows us to quickly confirm a bug (or point out a coding problem) as well as confirm that we are fixing the right problem. - -We will be insisting on a minimal reproduction scenario in order to save maintainers time and ultimately be able to fix more bugs. Interestingly, from our experience users often find coding problems themselves while preparing a minimal reproduction. We understand that sometimes it might be hard to extract essential bits of code from a larger code-base but we really need to isolate the problem before we can fix it. - -Unfortunately, we are not able to investigate / fix bugs without a minimal reproduction, so if we don't hear back from you we are going to close an issue that doesn't have enough info to be reproduced. - -You can file new issues by selecting from our [new issue templates][github-choose] and filling out the issue template. - -### Submitting a Pull Request (PR) - -Before you submit your Pull Request (PR) consider the following guidelines: - -1. Search [GitHub](https://github.com/scullyio/scully/pulls) for an open or closed PR - that relates to your submission. You don't want to duplicate effort. -1. Be sure that an issue describes the problem you're fixing, or documents the design for the feature you'd like to add. - Discussing the design up front helps to ensure that we're ready to accept your work. -1. Fork the scullyio/scully repo. -1. Make your changes in a new git branch: - - ```shell - git checkout -b my-fix-branch main - ``` - -1. Create your patch, **including appropriate test cases**. - -1. Commit your changes using a descriptive commit message that follows our - [commit message conventions](#commit). Adherence to these conventions - is necessary run the command `npm run commit` (this add all the files using `git add .`) or - if you need only add some files, you can need run the command `npm run commit:select`. - -1. Push your branch to GitHub: - - ```shell - git push origin my-fix-branch - ``` - -1. In GitHub, send a pull request to `scully:main`. - -- If we suggest changes then: - - - Make the required updates. - - Rebase your branch and force push to your GitHub repository (this will update your Pull Request): - - ```shell - git rebase main -i - git push -f - ``` - -That's it! Thank you for your contribution! - -#### After your pull request is merged - -After your pull request is merged, you can safely delete your branch and pull the changes -from the main (upstream) repository: - -- Delete the remote branch on GitHub either through the GitHub web UI or your local shell as follows: - - ```shell - git push origin --delete my-fix-branch - ``` - -- Check out the main branch: - - ```shell - git checkout main -f - ``` - -- Delete the local branch: - - ```shell - git branch -D my-fix-branch - ``` - -- Update your main with the latest upstream version: - - ```shell - git pull --ff upstream main - ``` - -## Commit Message Guidelines - -We have very precise rules over how our git commit messages can be formatted. This leads to **more -readable messages** that are easy to follow when looking through the **project history**. - -### Commit Message Format - -Each commit message consists of a **header**, a **body** and a **footer**. The header has a special -format that includes a **type**, a **scope** and a **subject**: - -_The command `npm run commit` was previously configured to use all these rules_ - -``` -(): - - - -
      -``` - -The **header** is mandatory and the **scope** of the header is optional. - -Any line of the commit message cannot be longer 100 characters! This allows the message to be easier -to read on GitHub as well as in various git tools. - -The footer should contain a [closing reference to an issue](https://help.github.com/articles/closing-issues-via-commit-messages/) if any. - -Samples from Angular Repository: (even more [samples](https://github.com/angular/angular/commits/main)) - -``` -docs(changelog): update changelog to beta.5 -``` - -``` -fix(release): need to depend on latest ng-lib - -The version in our package.json gets copied to the one we publish, and users need the latest of these. -``` - -### Type - -Must be one of the following: - -- **build**: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm) -- **docs**: Documentation only changes -- **feat**: A new feature -- **fix**: A bug fix -- **perf**: A code change that improves performance -- **refactor**: A code change that neither fixes a bug nor adds a feature -- **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc) -- **test**: Adding missing tests or correcting existing tests - -### Scope - -The scope should be the name of the npm package affected (as perceived by the person reading the changelog generated from commit messages). - -The following is the list of supported scopes: - -- **scully** -- **ng-lib** -- **schematics** - -### Subject - -The subject contains a succinct description of the change: - -- use the imperative, present tense: "change" not "changed" nor "changes" -- don't capitalize the first letter -- no dot (.) at the end - -### Body - -Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes". -The body should include the motivation for the change and contrast this with previous behavior. - -### Footer - -The footer should contain any information about **Breaking Changes** and is also the place to -reference GitHub issues that this commit **Closes**. - -**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this. - -## Signing the CLA - -Please sign our Contributor License Agreement (CLA) before sending pull requests. For any code changes to be accepted, the CLA must be signed. It's a quick process, we promise! - -- For individuals we have a [simple click-through form][cla-individual]. -- For corporations we'll need you to [print, sign and one of scan+email, fax or mail the form][cla-corporations]. - -[coc]: https://scully.io/docs/CODE_OF_CONDUCT -[github]: https://github.com/scullyio/scully -[github-issue]: https://github.com/scullyio/scully/issues/new?assignees=&labels=bug&template=---bug-report.md&title= -[github-feature]: https://github.com/scullyio/scully/issues/new?assignees=&labels=enhancement&template=---feature-request.md&title= -[github-choose]: https://github.com/scullyio/scully/issues/new/choose -[stackoverflow]: http://stackoverflow.com/questions/tagged/scully -[cla-individual]: https://cla-assistant.io/scullyio/scully -[cla-corporations]: https://gist.github.com/Villanuevand/4178efad870e8397565c6944fc3d292d diff --git a/docs/blog_es.md b/docs/blog_es.md deleted file mode 100644 index 133253106..000000000 --- a/docs/blog_es.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -title: Crear un blog -order: 600 -lang: es ---- - -# Crear un blog - -Scully es la mejor opción para mover tu blog a Angular! - -Tiene un schematic que permite que las aplicaciones de Angular utilicen archivos de markdown para el contenido del blog. - -1. [Agregar soporte de Blog](#agregar-soporte-de-blog) -2. [Generar una nueva publicacion de blog](#generar-una-nueva-publicacion-de-blog) - -_IMPORTANTE:_ Solo necesita una aplicación Angular con Scully, si no la tiene, puedes verificarlos en [Comenzando](/docs/getting-started_es). - -## Agregar soporte de Blog - -Para agregar soporte de blog a su aplicación, ejecute el siguiente comando: - -```bash -ng generate @scullyio/init:blog -``` - -Este comando agrega el módulo y las funciones de blog a su aplicación. Además, crea una carpeta `./blog` para los archivos de markdown del blog. - -Para crear una carpeta con un nombre diferente, ejecute el siguiente comando: - -```bash -ng generate @scullyio/init:markdown -``` - -Y va a aparecer una serie de preguntas, para que completes: - -```bash -? What name do you want to use for the module? blog -? What slug do you want for the markdown file? title -? Where do you want to store your markdown files? mdblog -? Under which route do you want your files to be requested? blog -``` - -o puedes hacerlo manualmente - -```bash -ng generate @scullyio/init:markdown --name="blog" --slug="title" --source-dir="mdblog" --route="blog" -``` - -Y el resultado es: - -```bash - ✅️ Update scully.{{yourApp}}.config.js -UPDATE scully.{{yourApp}}.config.js (653 bytes) -UPDATE src/app/app-routing.module.ts (726 bytes) -UPDATE src/app/blog/blog-routing.module.ts (429 bytes) -UPDATE src/app/blog/blog.component.css (157 bytes) -UPDATE src/app/blog/blog.component.html (160 bytes) -UPDATE src/app/blog/blog.component.spec.ts (639 bytes) -UPDATE src/app/blog/blog.component.ts (508 bytes) -UPDATE src/app/blog/blog.module.ts (391 bytes) - ✅️ Blog ./mdblog/2020-03-24-blog.md file created -CREATE mdblog/2020-03-24-blog.md (95 bytes) -``` - -**NOTA:** Slug es el nombre del url matcher para buscar el archivo. - -La siguiente tabla muestra todas las opciones disponibles: - -| Opcion | Descripcion | Defecto | -| -------------- | -------------------------------------------------------- | ------------------------ | -| `name` | Define el nombre del modulo | 'blog' | -| `slug` | Define el nombre del slug `:slug` | 'id' | -| `routingScope` | Setea el routing scope (`Root` o `Child`) | Child | -| `sourceDir` | Define el nombre de source directory (defecto: `name`) | value from `name` option | -| `route` | Define el path route antes del `:slug` (defecto: `name`) | value from `name` option | - -Scully funciona bien en combinación con otras herramientas y [utilidades](utils_es.md). - -Por ejemplo, si el contenido de markdown incluye bloques de código, y desea resaltarlo, puedes usar una utilidad. - -## Generar una nueva publicacion de blog - -Para crear una nueva publicación de blog, ejecute el siguiente comando: - -```bash -ng generate @scullyio/init:post --name="This is my post" -``` - -La siguiente tabla muestra todas las opciones disponibles: - -| Opcion | Descripcion | Defecto | -| -------------- | ------------------------------------------------------------------------- | --------- | -| `name` | Define el nombre para el post creado | 'blog-X' | -| `target` | Defina el directorio de destino para el nuevo archivo de publicación | 'blog' | -| `metaDataFile` | Utilice una plantilla de metadatos yaml de un archivo para la publicación | undefined | diff --git a/docs/CODE_OF_CONDUCT.md b/docs/community/code-of-conduct.md similarity index 93% rename from docs/CODE_OF_CONDUCT.md rename to docs/community/code-of-conduct.md index 748d2df45..6c8fc8f49 100644 --- a/docs/CODE_OF_CONDUCT.md +++ b/docs/community/code-of-conduct.md @@ -1,7 +1,9 @@ --- title: Code of Conduct -order: 900 +published: true lang: en +navlist_position: 1 +navlist_textFormat_capitalize: true --- # Code of Conduct diff --git a/docs/community/contributing.md b/docs/community/contributing.md new file mode 100644 index 000000000..cb3ff99ef --- /dev/null +++ b/docs/community/contributing.md @@ -0,0 +1,12 @@ +--- +title: Contributing +lang: en +published: true +--- + +# Contributing + +Do you want to contribute to Scully or share your experience with the community? +Please check our [CONTRIBUTING](https://github.com/scullyio/scully/blob/main/CONTRIBUTING.md) guidelines. + +The team would love your feedback and to hear how you're using Scully with other tools! diff --git a/docs/community/issues.md b/docs/community/issues.md new file mode 100644 index 000000000..86d120154 --- /dev/null +++ b/docs/community/issues.md @@ -0,0 +1,13 @@ +--- +title: Issues +lang: en +published: true +--- + +# Issues + +To create a bug report, use the [Scully Bug template.](https://github.com/scullyio/scully/issues/new?assignees=&labels=bug&template=---bug-report.md&title=) + +To propose a new feature, use the [Scully Feature Request template.](https://github.com/scullyio/scully/issues/new?assignees=&labels=enhancement&template=---feature-request.md&title=) + +The Scully team is working on better documentation for creating issues. diff --git a/docs/community/showcase.md b/docs/community/showcase.md new file mode 100644 index 000000000..d6a69b20a --- /dev/null +++ b/docs/community/showcase.md @@ -0,0 +1,51 @@ +--- +title: Showcase +lang: en +published: true +--- + +# Scully site Showcase + + diff --git a/docs/community/support.md b/docs/community/support.md new file mode 100644 index 000000000..ca0592a8c --- /dev/null +++ b/docs/community/support.md @@ -0,0 +1,11 @@ +--- +title: Support +lang: en +published: true +--- + +# Support + +Join the Scully community on [Gitter](https://gitter.im/scullyio/community). + +Scully [Office Hours](https://meet.google.com/vcm-wekz-hsx?authuser=1) Google Meet every Tuesday at noon MST. diff --git a/docs/features.md b/docs/features.md deleted file mode 100644 index 3d2cf9096..000000000 --- a/docs/features.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -title: Features -order: 1900 -lang: en ---- - -# Scully's Features - -Under the hood, Scully analyzes an Angular application and generates a static -version of it. It provides several Angular schematics to make -its usage AS EASY AS POSSIBLE! - -[Core Features](/docs/scully-lib-core): - -- Idle Monitor Service -- Router Service -- Scully Content Component -- Transfer State Service -- Utility Methods - -[Plugins System](/docs/plugins): - -- Router Plugins -- Render Plugins -- File Handler Plugins -- AllDone Plugins -- routeDiscoveryDone Plugins - -[Schematics](/docs/schematics): - -- Install and create files for Scully (ng-add). -- Creating a blog config for Scully & Angular. -- Generate a plugin's skeleton. -- Run the router discovery. -- Create markdown files and skeleton. diff --git a/docs/features_es.md b/docs/features_es.md deleted file mode 100644 index 43f64960a..000000000 --- a/docs/features_es.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: Caracteristicas -order: 1900 -lang: es ---- - -# Caracteristicas de Scully - -Tras bambalinas, Scully analiza la aplicación de Angular y genera una versión estática de esta. Proporciona varios esquemas (schematics) de Angular para -hacer su uso LO MÁS SENCILLO POSIBLE! - -[Características Principales](/docs/scully-lib-core_es): - -- Servicio de Monitor Sin Utilizar (Idle Monitor Service) -- Servico de Rutas (Router Service) -- Componente de Contenido de Scully (Scully Content Component) -- Servicio de Transferencia de Estado (Transfer State Service) -- Métodos de Utilería (Utility Methods) - -[Sistema de Plugins](/docs/plugin_es): - -- Router Plugins -- Render Plugins -- File Handler Plugins -- AllDone Plugins -- routeDiscoveryDone Plugins - -[Schematics](/docs/schematics_es): - -- Instalar y crear archivos para Scully (ng-add). -- Crear y cnfigurar un blog config para Scully & Angular. -- Generar el esqueleto de un plugin. -- Correr el descubrimiento de rutas. -- Crear esqueletos de archivos markdown. diff --git a/docs/getting-started.md b/docs/getting-started.md deleted file mode 100644 index 91c3fd2e6..000000000 --- a/docs/getting-started.md +++ /dev/null @@ -1,146 +0,0 @@ ---- -title: Getting Started -order: 200 -lang: en ---- - -# Getting Started with Scully - -Welcome to Scully! - -Before getting started, please read the [Prerequisites](pre-requisites.md). - -**_All about Scully in one video_** : [Building the Fastest Angular Apps Possible](https://thinkster.io/tutorials/scully-webinar-building-the-fastest-angular-apps-possible) - -This getting started guide covers the following topics: - -1. [Installation](#installation) -2. [Building](#building-the-scully-application) -3. [Serving](#serving) -4. [Tips for Testing](#tips-for-testing) - ---- - -## Installation - -_Before adding Scully to your Angular project; make sure that -your project has at least one route set up. If you have questions about adding -routes, see the [Angular routing docs](https://angular.io/start/start-routing)._ - -Adding Scully to your project is as simple as running one command: - -```bash -ng add @scullyio/init -``` - -If you have an Angular workspace, Scully by default take the default project from your `angular.json`, if you want to install Scully in another project run: - -```bash -ng add @scullyio/init --project= -``` - -If you are using a `NX` vanilla workspaces (non Angular workspace) - -```bash -npm install @scullyio/init -nx g @scullyio/init:install -- --project= -``` - -**NOTE**: After installation, if you were serving the app during the installation; you need to restart `ng serve`. - -Running the `@scullyio/init` schematic makes all the necessary changes the Angular -project, so you do not need to go through a lengthy setup process. - -The command above creates a Scully config file named `scully..config.ts`, where the `projectName` is the name of your Angular project. This file looks like this: - -```typescript -import { ScullyConfig } from '@scullyio/scully'; - -export const config: ScullyConfig = { - projectRoot: './src', - projectName: '', - outDir: './dist/static', - routes: {}, -}; -``` - -Even with this basic config, you are now ready to build your Angular app using Scully for the first time! - -**NOTE**: It is important to know that any routes in the Angular project that contain route parameters -will not be pre-rendered until you modify the above config to account for those parameters. - -[HERE](./plugin/jsonPlugin.md) -is an example of how to configure route parameters with Scully. - ---- - -## Building the Scully Application - -Running Scully for the first time is exciting. Congrats on making it here! - -Before Scully can run you need to build your Angular project. Most projects' built is: - -```bash -ng build -``` - -Now that the Angular project is built, Scully can do its work. Run Scully with the following command: - -```bash -npm run scully -``` - -You did it! You have turned your Angular app into a wicked fast pre-rendered static site thanks to Scully. - -The Scully-built version of the project is located in the `./dist/static` folder. It contains all the static pages in the project. - -**NOTE**: In case of any errors or warnings during the build process, please follow the instructions in the errors/warnings section or [submit an issue](https://github.com/scullyio/scully/issues/new/choose). - -**NOTE**: The following is a common error when building with Scully for the first time: - -```bash -No configuration for route `/user/:userId` found. Skipping -``` - -This message indicates that Scully has skept any unconfigured routes. Read more about [Route Parameters & Scully](./routeParameters.md). - ---- - -## Serving - -Once the app is built with Scully, see the output and test how it runs as a statically generated webpage. - -To see the pre-rendered site, open the `/dist/static` folder where you can find one `index.html` for every route in your app. Hence, if the application has 1000 routes, there should be 1000 `index.html` files in the `dist/static` folder. -These `index.html` files are jamstack-packed with HTML and CSS. This means that Scully built successfully, and that your site is now pre-rendered. - -Scully provides a server, so that you can test out your jamstack site after the Scully build. To launch Scully's test server, run the following command: - -```bash -npm run scully:serve -``` - -This command actually launches **2 (two)** servers. The first one is hosting the results of `ng build`, and the second server hosts the results of the Scully build. This allows you to test both versions of your built app. Very cool! - ---- - -## Tips for Testing - -#### Only rebuild Angular if you change Angular - -Although this may seem evident; if this is your first time using Scully, it is easy rebuild Angular even if it is not needed. When writing Scully plugins OR modifying your blog's markdown files, you DO NOT need to `ng build` the app each time you re-run Scully. Again, `ng build` Angular if the Angular app changes. - -Whenever you are confused about re-running the Angular build, just ask yourself: Did I change the Angular code, or the Scully code? - -#### Scully Serve - -Running `npm run scully` pre-builds your project with Scully. Any time a plugin or a markdown file change, re-run this process. In addition, if any of the content that the Angular app depends on changes, you need to re-run the Scully build. - -To make the `serve` process easier run the following command: - -```bash -npm run scully -- --watch -``` - -Running Scully build with the `--watch` option live-reloads the Scully build. In other words, It watches for any changes from the Angular build or from any of the markdown files. If any of those change, the Scully build re-executes, and it serves the new results in realtime. - -**NOTE**: This is ideal for a faster development, but DO NOT use the `--watch` option during production or any devops proccess or the build will never finish. diff --git a/docs/getting-started_es.md b/docs/getting-started_es.md deleted file mode 100644 index 88135207c..000000000 --- a/docs/getting-started_es.md +++ /dev/null @@ -1,172 +0,0 @@ ---- -title: Primeros Pasos -order: 200 -lang: es ---- - -# Iniciando con Scully - -¡Bienvenido a Scully! - -Antes de iniciar, por favor lea los [Prerrequisitos](pre-requisites_es.md). - -**_Todo acerca de Scully en un video_** : [Construyendo las Apps de Angular más rápidas](https://thinkster.io/tutorials/scully-webinar-building-the-fastest-angular-aps-possible) - -La guia de inicio cubre los siguientes temas: - -1. [Instalación](#instalación) -2. [Construcción](#build) - -## Instalación - -Primero, abra abra la ruta de su aplicación de Angular en una terminal y corra el siguiente comando: - -```bash -ng add @scullyio/init -``` - -Una ves se ha instalado exitosamente se mostrará el siguiente mensaje: - -```bash -Installing packages for tooling via npm. -Installed packages for tooling via npm. - Install ng-lib for Angular v9 - ✅️ Added dependency -UPDATE src/app/app.module.ts (466 bytes) -UPDATE src/polyfills.ts (3031 bytes) -UPDATE package.json (1378 bytes) -√ Packages installed successfully. - ✅️ Update package.json - ✅️ Created scully configuration file in scully.{{yourApp}}.config.js -CREATE scully.{{yourApp}}.config.js (109 bytes) -UPDATE package.json (1438 bytes) -``` - -## Generar un Blog - -Corra el siguiente comando para generar un módulo de blog. - -[más información aquí](blog.md) - -```bash -ng generate @scullyio/init:blog -``` - -Ahora, elimine el contenido del archivo `app.component.html` y solo deje el tag ``. - -[más información aquí](blog_es.md) - -### Crear el Punto de Entrada de la Aplicación (Página de Inicio) - -Crear un _Módule de Inicio_ con las rutas configuradas y con un _Componente de Inicio_; con el siguiente comando: - -```bash -ng generate module home --route=home --module=app-routing -``` - -**Scully depende del _punto de entrada de las rutas (route entry point)_.** - -### Configurar el Módulo de Inicio como la Raíz del Proyecto - -Abra el archivo `app-routing.module.ts` y agregue un atributo de ruta de inicio, como se muestra a continuación: - -```typescript -const routes: Routes = [ - // ... - { - path: '', - loadChildren: () => import('./home/home.module').then(m => m.HomeModule) - } -]; -``` - -### Inyectando el Servicio de Rutas de Scully - -Scully proporciona un servicio para acceder a las rutas generadas de una manera sencilla. - -Abra el archivo `home.component.ts` y agregue el siguiente código: - -```typescript -import { ScullyRoutesService } from '@scullyio/ng-lib'; -import { Observable } from 'rxjs'; - -@Component() -//... -export class HomeComponent implements OnInit { - links$: Observable = this.scully.available$; - - constructor(private scully: ScullyRoutesService) {} - - ngOnInit() { - // debug current pages - this.links$.subscribe(links => { - console.log(links); - }); - } -} -``` - -Ahora es posible iterar a través de los links dentro de la plantilla al abrir el archivo `home.component.html` y agregando el siguiente código: - -```html -

      home works!

      - -
        -
      • {{ page.route }}
      • -
      -``` - -**NOTA:** Si no se agrega el servicio de rutas de Scully, las páginas no se procesarán y no se mostrarán. - -## Construyendo la Aplicación de Scully - -En este punto el proyecto de Angular con Scully está listo. - -Primero, construya la aplicación de Angular con el comando: - -```bash -ng build -``` - -Ahora, construya con Scully para convertir la ap de Angular en un citio estático preprocesado. - -```bash -npm run scully -``` - -¡Felicidades! Ha convertido su aplicación de Angular en un sitio estatico extremadamente rápido gracias a Scully. - -La versión estática del sitio se localiza en el archivo `./dist/static`. Contiene todas las páginas estáticas. - -**NOTA:** En caso de cualquier error o advertencia durante el proceso de construcción, por favor siga las instrucciones en la saección de errores/advertencias o [genere un issue](https://github.com/scullyio/scully/issues/new/choose). - -## Servir el Sitio Estático - -Sirva el contenido del sitio estático con el comando: - -```bash -npm run scully serve -``` - -Este comando crea dos servidores web, uno para la aplicación de Angular y uno para la ap de Scully. - -### Deshabilitando JS - -**Extra**: Mientras se está sirviendo la ap de Scully, [deshabilite JavaScript](https://developers.google.com/web/tools/chrome-devtools/javascript/disable) -y la navegación del sitio aun funciona. Pero sobre todo, la mayor parte del sitio aun funciona a pesar de que JS ha sido deshabilitado. - -### Debugging de la Aplicación de Scully - -**Extra**: Para poder hacer debug en la aplicación de Scully con ngServe, asegúrese de correr: - -```bash -npm run scully -``` - -Ahora, inicie el servidor: - -```bash -npm run scully:serve -``` - -Scully usa el HTML generado para llenar el contenido de la sesión `ng serve`. diff --git a/docs/issues.md b/docs/issues.md deleted file mode 100644 index 4a715b4a7..000000000 --- a/docs/issues.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Issues -order: 1000 -lang: en ---- - -# Issues - -To create a bug report: Go to [Scully Bug template](https://github.com/scullyio/scully/issues/new?assignees=&labels=bug&template=---bug-report.md&title=). - -To propose a new feature: Go to [Scully Feature request](https://github.com/scullyio/scully/issues/new?assignees=&labels=enhancement&template=---feature-request.md&title=) - -The Scully team is working on better documentation for creating issues. diff --git a/docs/learn/command-line-options.md b/docs/learn/command-line-options.md new file mode 100644 index 000000000..2854deceb --- /dev/null +++ b/docs/learn/command-line-options.md @@ -0,0 +1,179 @@ +--- +title: Command Line Options +lang: en +navlist_position: 500 +--- + +# Command Line Options + +
      + +- [`serve`](#serve) +- [`watch`](#watch) +- [`showBrowser`](#showbrowser) +- [`showGuessError`](#showguesserror) +- [`configFile`](#configfile) +- [`project`](#project) +- [`baseFilter`](#basefilter) +- [`proxyConfig`](#proxyconfig) +- [`removeStaticDist`](#removestaticdist) +- [`open`](#open) +- [`scanRoutes`](#scanroutes) +- [`ssl`](#ssl) +- [`ssl-cert`](#ssl-cert) +- [`ssl-key`](#ssl-key) +- [`highlight`](#highlight) +- [`tds`](#tds) +- [`pluginsError`](#pluginserror) + +#### `serve` + +```bash +npx scully serve +``` + +Starts the scully server. This process does not _build_ the project. It only serves the Angular build files, and the Scully static files. + +#### `watch` + +```bash +npx scully --watch +``` + +By default, Scully has the watchMode in false. You need to add this flag to use Watch Mode. + +#### `showBrowser` + +```bash +npx scully --showBrowser +``` + +Alias `--sb`. Chromium browser renders the application. + +#### `showGuessError` + +```bash +npx scully --showGuessError +``` + +Alias `--sge`. Displays Guess-Parse's errors in the console. + +#### `configFile` + +```bash +npx scully --configFile someName +``` + +Alias `--cf`. Loads a different config file. If it is used at the same time as the `--project` flag, the project flag takes precedence. + +#### `project` + +```bash +npx scully --project someName +``` + +Alias `--pr`. It is used to select a different project. Scully uses the default project from generated by the the Angular CLI. + +#### `baseFilter` + +```bash +npx scully --baseFilter /someRoute +``` + +Alias `--bf`. Enables Scully to start rendering a specific route. + +#### `proxyConfig` + +Alias `--proxy`. Takes a relative filename for a proxy config file. + +For more details look at [http-proxy-middleware](https://github.com/chimurai/http-proxy-middleware). + +Scully uses the same config format as [webpackDevServer](https://webpack.js.org/configuration/dev-server/#devserverproxy). + +#### `removeStaticDist` + +```bash +npx scully --removeStaticDist +``` + +Alias `--RSD`. Removes the static folder generated by Scully from previous renders. + +#### `open` + +```bash +npx scully serve/watch --open +``` + +Alias `--o`. Opens the default browser and renders the dist folder generated by Scully. + +#### `scanRoutes` + +Alias `--sr` or `--scan`. Scans the application again to find unhandled routes. This is normally done just once. When routes in the application are added or changed, use this flag to discover all the new routes. + +#### `ssl` + +```bash +npx scully serve/watch --ssl +``` + +Runs the Scully server with ssl. + +#### `ssl-cert` + +```bash +npx scully serve/watch --ssl --ssl-cert=./url/to/file +``` + +Adds a url to the ssl certificate file for a server with SSL. + +#### `ssl-key` + +```bash +npx scully serve/watch --ssl --ssl-key=./url/to/file +``` + +Adds a url to an ssl key file for a server with SSL. + +#### `highlight` + +```bash +npx scully serve/watch --hl +``` + +Add highlight.js to render into the markdown's files. + +If you use this flag, you need to add the css into the index.html: + +```html + +``` + +#### `tds` + +```bash +npx scully --tds +``` + +Launches the Test Data Server. This is only helpful for demos. + +The following APIs are supported on the test data server: + +| api | returns | +| -------------- | --------------------------------------------------------------------- | +| `/users` | A list of users | +| `/users/:id` | Just one user by id | +| `/posts` | A list of posts | +| `/posts/:id` | A post by id | +| `/slow/:delay` | 200 code after a delay has gone by. Eg: `/slow/2000` takes 2 seconds. | + +#### `pluginsError` + +```bash +npx scully --pluginsError=false +``` + +Show the error from the plugin, but continue rendering. +If you do not use the flag (by default is true) when you have an error into any plugin, the scully's run exit. diff --git a/docs/learn/config.md b/docs/learn/config.md new file mode 100644 index 000000000..ca6d5a891 --- /dev/null +++ b/docs/learn/config.md @@ -0,0 +1,243 @@ +--- +title: Scully Config +published: true +lang: en +navlist_position: 400 +--- + +# Scully Config + + + +
      + +- [Overview](#overview) +- [Interface](#interface) +- [Properties](#properties) + - [`projectRoot?:` _`string`_](#projectroot-string) + - [`homeFolder?:` _`string`_](#homefolder-string) + - [`outDir?:` _`string`_](#outdir-string) + - [`distFolder?:` _`string`_](#distfolder-string) + - [`logFileSeverity:` _`LogSeverity`_](#logfileseverity-logseverity) + - [`routes:` _`RouteConfig`_](#routes-routeconfig) + - [Unhandled Routes](#unhandled-routes) + - [Handled Routes](#handled-routes) + - [`extraRoutes?:` _`string | string[] | Promise`_](#extraroutes-string--string--promisestring--string) + - [`appPort?:` _`number`_](#appport-number) + - [`staticPort?:` _`number`_](#staticport-number) + - [`proxyConfig?:` _`string`_](#proxyconfig-string) + - [`puppeteerLaunchOptions?:` _`LaunchOptions`_](#puppeteerlaunchoptions-launchoptions) + - [`hostName?:` _`string`_](#hostname-string) + - [`hostUrl?:` _`string`_](#hosturl-string) + - [`guessParserOptions?:` _`GuessParserOptions`_](#guessparseroptions-guessparseroptions) + - [`ignoreResourceTypes?:` _`ResourceType[]`_](#ignoreresourcetypes-resourcetype) + - [`handle404?:` _`string`_](#handle404-string) + +## Overview + +The central part of a Scully project is the `scully..config.ts` file. This file exports the Scully build configuration for an application. + +If you are new to Scully, it is recommended to read the [Getting Started](docs/learn/getting-started/requirements/) documentation. + + + +The `scully..config.ts` file's structure is shown below: + +## Interface + +```typescript +export interface ScullyConfig { + /** is this a bare project (without angular.json?) */ + bareProject?: boolean; + /** the name of the project we are using. Provided by Scully itself */ + projectName?: string; + /** the folder where project is. Can be any off the projects in a repo, read from angular.json */ + projectRoot?: string; + /** the folder where the project sources resides, read from angular.json */ + sourceRoot?: string; + /** Array with string ID's of the content-renderers that will be run on all routes */ + defaultPostRenderers?: string[]; + /** the root of the project (where angular.json lives) */ + homeFolder?: string; + /** the destination of the Scully generated files */ + outDir?: string; + /** the place where distribution files of the project are. Should be a subfolder of dist. */ + distFolder?: string; + /** transferState only inlined into page, and not written into separate data.json */ + inlineStateOnly?: boolean; + /** Set what is what is written to the logfile, defaults to warnings and errors */ + logFileSeverity?: LogSeverity; + /** routes that need additional processing have their configuration in here */ + routes: RouteConfig; + /** routes that are in the application but have no route in the router */ + extraRoutes?: string | string[] | Promise; + /** Port-number where the original application is served */ + appPort?: number; + /** Boolean that determines saving of site-tumbnails files */ + thumbnails?: boolean; + /** port-number where the Scully generated files are available */ + staticport?: number; + /** port for the live reload service */ + reloadPort?: number; + /** optional proxy config file, uses the same config file as the CLI */ + proxyConfig?: string; + /** optional launch-options for puppeteer */ + puppeteerLaunchOptions?: LaunchOptions; + /** hostname to use for local server, defaults to `localhost` */ + hostName?: string; + /** optional hostURL, if this is provided, we are going to use this server instead of the build-in one. */ + hostUrl?: string; + /** optional guessParserOptions, if this is provided we are going to pass those options to the guess parser. */ + guessParserOptions?: GuessParserOptions; + /** the maximum of concurrent puppeteer tabs open. defaults to the available amounts of cores */ + maxRenderThreads?: number; + /** the resource types to ignore when generating pages via Puppeteer */ + ignoreResourceTypes?: ResourceType[]; + /** how to handle 404 in Scully server */ + handle404?: string; +} +``` + +## Properties + +The `ScullyConfig` interface provides parameters for configuring how Scully works in a project. + +#### `projectRoot?:` _`string`_ + +The project's from which Scully generates the static content. + +#### `homeFolder?:` _`string`_ + +A reference to the Angular project's root folder. +This property is for internal use, and it defaults to the angular.json file's location. + +#### `outDir?:` _`string`_ + +The folder's path where Scully leaves the statics files. +This should not be the same as the `distFolder`. +The default path is: + +```URL +./dist/static +``` + +#### `distFolder?:` _`string`_ + +Path to the Angular application's dist folder. +Scully takes the `angular.json` file's default path, and will use this folder during rendering. +This option can be modified according to your needs. + +#### `logFileSeverity:` _`LogSeverity`_ + +Determines what of the Scully output will be written into the `scully.log` file in the root of the project. + +| option | result | +| ------ | ----------------------------- | +| `0` | Logs everything | +| `1` | Logs warnings and errors only | +| `2` | Logs errors only | + +#### `routes:` _`RouteConfig`_ + +Scully has two types of routes, **unhandled routes** and **handled routes**: + +##### Unhandled Routes + +Routes with dynamic data. This are the routes as you would use them inside your app. Those routes can come from the automated route discovery, or from the extraRoutes property in the `scully..config.ts`. Eg: + +```URL +/foo/:id +``` + +All unhandled routes with dynamic data need to be handled through plugins. When there is a route with dynamic data that has no configuration in the configs routes, it will be logged to screen and skipped during processing. + +**This means there will be NO STATIC FILES for ROUTES which HAVE DYNAMIC DATA but NO CONFIG** + +For more information about router plugins read the [Plugins](/docs/learn/plugins/overview) documentation. + +##### Handled Routes + +Routes with static params. Eg: + +```URL +/foo/1 +``` + +#### `extraRoutes?:` _`string | string[] | Promise`_ + +Allows developers to add an array of unhandled routes. These routes can exist in AngularJS, React, or any other framework. + +```typescript +extraRoutes: [ + '/foo/:id', + new Promise('/bar/:barId'), + new Promise(['/foo/:fooId', '/bar/:id']), +]; +``` + +#### `appPort?:` _`number`_ + +Scully provides a server to to render the Angular application. + +Configure the port where the Angular application runs. + +The default port is: `1864` + +#### `staticPort?:` _`number`_ + +Similar to [_`appPort`_](#appport-number), `staticport` provides a server to to render the static files compiled by Scully. + +The default port is: `1668` + +#### `proxyConfig?:` _`string`_ + +Takes a relative filename for a proxy config file. + +For more details look at [http-proxy-middleware](https://github.com/chimurai/http-proxy-middleware) +Scully uses the same config format as [webpackDevServer](https://webpack.js.org/configuration/dev-server/#devserverproxy) +This is an optional property, and it is also used by the [Angular CLI](https://angular.io/guide/build#proxying-to-a-backend-server) + +This can also be provided with the `--proxy filname` command line flag + +#### `puppeteerLaunchOptions?:` _`LaunchOptions`_ + +If the application is in a restricted environment, puppeteer's default options may not work. In that case, +this option can be overwrite with settings that match a specific environment. + +**A word of warning,** some settings might interfere with the way Scully is working, creating inaccurate results. +Read about [puppeteerlaunchoptions](https://pptr.dev/#?product=Puppeteer&version=v2.0.0&show=api-puppeteerlaunchoptions) for more information. + +#### `hostName?:` _`string`_ + +Allows to set a different name for the `localhost`. + +#### `hostUrl?:` _`string`_ + +Connects your application to a different host. This is useful when using your own server. + +#### `guessParserOptions?:` _`GuessParserOptions`_ + +The`guessParserOptions` that get passed to the `guess-parser` library. + +Currently, the only supported property is `excludedFiles`, and it excludes files from the `guess-parser` route discovery process. + +#### `ignoreResourceTypes?:` _`ResourceType[]`_ + +The `ignoreResourceTypes` array that get passed to the `puppeteerRenderPlugin`. +Any `ResourceType` that is listed here will be ignored by the Puppeteer instance rendering the requested page. +For example if you add `image` and `font` all requests to images and fonts loaded on your pages will be ignored. + +#### `handle404?:` _`string`_ + +How routes which are **not**provided in the application, are handled by the Scully server. +When the server gets a request for a route (file) that does not exist on the file-system, this option amends how that route is handled. + +| option | result | +| -------------- | ------------------------------------------------------------ | +| `""` (default) | Will render a 404 page, and raise a waring during rendering. | +| `index` | Will render the `index.html` from the dist root folder. | +| `baseOnly` | Will use express route matcher on unhandled routes only. | +| `404` | Will render the `404.html` from the dist root folder. | +| `none` | Will leave it up to the express software layer. | diff --git a/docs/learn/core-features/idle-monitor-service.md b/docs/learn/core-features/idle-monitor-service.md new file mode 100644 index 000000000..70f39f8f3 --- /dev/null +++ b/docs/learn/core-features/idle-monitor-service.md @@ -0,0 +1,75 @@ +--- +title: IdleMonitorService +published: true +lang: en +navlist_textFormat_capitalize: true +--- + +# `IdleMonitorService` + + + +
      + +- [Overview](#overview) +- [Adding Custom Mechanisms](#adding-custom-mechanisms) + +## Overview + +The [`IdleMonitorService`](https://github.com/scullyio/scully/blob/main/libs/ng-lib/src/lib/idleMonitor/idle-monitor.service.ts) hooks into Zonejs. It is located in the [`ScullyLibModule`](https://github.com/scullyio/scully/blob/main/libs/ng-lib/src/lib/scully-lib.module.ts). + +When Angular goes idle **(more precisely, when all outgoing HTTP requests finish)** Scully triggers Puppeteer in order to know when it is ready to render. + +If your content is loaded out of sight of zones, Scully scrapes the page before its ready. + +## Adding Custom Mechanisms + +To disable Scully ready mechanism and add a custom mechanism, put following config object in the `forRoot` config: + +```typescript +ScullyLibModule.forRoot({ + useTransferState: true, + alwaysMonitor: false, + manualIdle: true, +}); +``` + +This will cause Scully to fall-back to using a 25 second timeout, on every page rendered. + +Then in your component, trigger the `fireManualMyAppReadyEvent()` + +```typescript +export class ManualIdleComponent implements OnInit { + text = 'this text is displayed by automated detection'; + + constructor(private ims: IdleMonitorService) {} + + ngOnInit(): void { + setTimeout(() => (this.text = '__ManualIdle__'), 3 * 1000); + setTimeout(() => this.ims.fireManualMyAppReadyEvent(), 3.25 * 1000); + } +} +``` + +To enable this for single route, provide `manualIdle: true` inside the `config.ts` file in the route configuration: + +```typescript +// scully.config.ts +export const config: ScullyConfig = { + routes: { + '/user/:userId': { + type: 'json', + // Add the following to your route + exposeToPage:{ + manualIdle: true + } + userId: { + url: 'http://localhost:8200/users', + property: 'id' + } + } + } +}; +``` diff --git a/docs/learn/core-features/scully-content-component.md b/docs/learn/core-features/scully-content-component.md new file mode 100644 index 000000000..31e838cc4 --- /dev/null +++ b/docs/learn/core-features/scully-content-component.md @@ -0,0 +1,18 @@ +--- +title: ScullyContentComponent +published: true +lang: en +navlist_textFormat_capitalize: true +--- + +# `ScullyContentComponent` + + + +## Overview + +The [`scully-content`](https://github.com/scullyio/scully/blob/main/libs/ng-lib/src/lib/scully-content/scully-content.component.ts) component inserts the render process' result into the HTML document. + +**NOTE:** The [`scully-content`](https://github.com/scullyio/scully/blob/main/libs/ng-lib/src/lib/scully-content/scully-content.component.ts) component does not work inside an `*ngIf` directive. diff --git a/docs/learn/core-features/scully-routes-service.md b/docs/learn/core-features/scully-routes-service.md new file mode 100644 index 000000000..bcae77438 --- /dev/null +++ b/docs/learn/core-features/scully-routes-service.md @@ -0,0 +1,71 @@ +--- +title: ScullyRoutesService +published: true +lang: en +navlist_textFormat_capitalize: true +--- + +# `ScullyRoutesService` + + + +
      + +- [Overview](#overview) +- [Interface](#interface) +- [Observables & Methods](#observables--methods) + + - [`available$:` _`Observable`_](#available-observablescullyroute) + - [`unPublished$:` _`Observable`_](#unpublished-observablescullyroute) + - [`topLevel$:` _`Observable`_](#toplevel-observablescullyroute) + - [`getCurrent():` _`Observable`_](#getcurrent-observablescullyroute) + - [`reload():` _`void`_](#reload-void) + + - [`available$:` _`Observable`_](#available-observablescullyroute) + - [`unPublished$:` _`Observable`_](#unpublished-observablescullyroute) + - [`topLevel$:` _`Observable`_](#toplevel-observablescullyroute) + - [`getCurrent():` _`Observable`_](#getcurrent-observablescullyroute) + - [`reload():` _`void`_](#reload-void) + +## Overview + +The [`ScullyRoutesService`](https://github.com/scullyio/scully/blob/main/libs/ng-lib/src/lib/route-service/scully-routes.service.ts) provides methods and observables that allow you to know the routes rendered by Scully. + +## Interface + +The [`ScullyRoutesService`](https://github.com/scullyio/scully/blob/main/libs/ng-lib/src/lib/route-service/scully-routes.service.ts)'s types come from the [`ScullyRoute`](https://github.com/scullyio/scully/blob/main/libs/ng-lib/src/lib/route-service/scully-routes.service.ts) interface: + +```typescript +export interface ScullyRoute { + route: string; + title?: string; + slugs?: string[]; + published?: boolean; + slug?: string; + [prop: string]: any; +} +``` + +## Observables & Methods + +#### `available$:` _`Observable`_ + +Returns routes containing the property `published` with a value of true. + +#### `unPublished$:` _`Observable`_ + +Returns routes containing the property `published` with a value of false. + +#### `topLevel$:` _`Observable`_ + +Returns the top-level routes. + +#### `getCurrent():` _`Observable`_ + +A method that returns the current location. + +#### `reload():` _`void`_ + +A method that checks if new routes have been added to the `scully-routes.json` file. diff --git a/docs/learn/core-features/transfer-state-service.md b/docs/learn/core-features/transfer-state-service.md new file mode 100644 index 000000000..10c7aabf0 --- /dev/null +++ b/docs/learn/core-features/transfer-state-service.md @@ -0,0 +1,46 @@ +--- +title: TransferStateService +published: true +lang: en +navlist_textFormat_capitalize: true +--- + +# `TransferStateService` + + + +
      + +- [Usage](#usage) + - [`getState()`](#getstate) + - [`setState()`](#setstate) + +## Overview + +The [`TransferStateService`](https://github.com/scullyio/scully/blob/main/libs/ng-lib/src/lib/transfer-state/transfer-state.service.ts) allows to transfer an Angular application's state into the static site rendered by Scully. + +More over, it allows you to load the state on subsequent route changes after the initial page has been loaded. + +A route change fetches the next route's state from the page on the serve, and it is returned to the client. Hence, having a state consumed as part of the build despite any CMS content in production + +## Usage + +To get or set the application's state, use `getState` and `setState` below: + +#### `getState()` + +This method returns an observable that fires once and then completes. It does executes after the page's navigation has finished. + +```typescript +getState(name: string): Observable +``` + +#### `setState()` + +This method sets values to the property key. + +```typescript +setState(name: string, val: T): void; +``` diff --git a/docs/learn/core-features/utility-methods.md b/docs/learn/core-features/utility-methods.md new file mode 100644 index 000000000..59043e127 --- /dev/null +++ b/docs/learn/core-features/utility-methods.md @@ -0,0 +1,28 @@ +--- +title: Utility methods +published: true +lang: en +--- + +# Utility methods + + + +
      + +- [`isScullyRunning():` _`boolean`_](#isscullyrunning-boolean) +- [`isScullyGenerated():` _`boolean`_](#isscullygenerated-boolean) + +## Overview + +These methods provide useful information about Scully processes. + +#### `isScullyRunning():` _`boolean`_ + +This method returns `true` or `false` if the Scully build is currently running. + +#### `isScullyGenerated():` _`boolean`_ + +This method returns `true` if the Scully build has run. diff --git a/docs/learn/create-a-blog/add-blog-support.md b/docs/learn/create-a-blog/add-blog-support.md new file mode 100644 index 000000000..9941c4746 --- /dev/null +++ b/docs/learn/create-a-blog/add-blog-support.md @@ -0,0 +1,119 @@ +--- +title: Adding blog support +published: true +lang: en +navlist_position: 100 +navlist_parentIndex: true +navlist_parentPosition: 300 +--- + +# Adding blog support + +
      + +- [Overview](#overview) +- [Usage](#usage) +- [Available options](#available-options) +- [Create an entry point (Home page)](#create-an-entry-point-home-page) +- [Configure entry point Module as project Root](#configure-entry-point-module-as-project-root) +- [Extending functionality](#extending-functionality) + +## Overview + +Scully is the best option for moving a blog to Angular! +It provides a schematic that enables Angular applications to use markdown files for your blog's content. + +**IMPORTANT:** If you don't have an Angular app with Scully, please check the [Getting Started guide](/docs/learn/getting-started/requirements) first. + +## Usage + +Add blog support by running the following command: + +```bash +ng generate @scullyio/init:blog +``` + +The above command adds the blog modules' routes to the Angular application. +In addition, it creates a `./blog` folder for the blog's markdown files. + +In case you want to use a different folder name, run the following command: + +```bash +ng generate @scullyio/init:markdown +``` + +You will be prompted with the following questions: + +```bash +? What name do you want to use for the module? blog +? What slug do you want for the markdown file? title +? Where do you want to store your markdown files? mdblog +? Under which route do you want your files to be requested? blog +``` + +After adding the blog support, you should see the following message: + +```output + ✅️ Update scully.{{yourApp}}.config.js +UPDATE scully.{{yourApp}}.config.js (653 bytes) +UPDATE src/app/app-routing.module.ts (726 bytes) +UPDATE src/app/blog/blog-routing.module.ts (429 bytes) +UPDATE src/app/blog/blog.component.css (157 bytes) +UPDATE src/app/blog/blog.component.html (160 bytes) +UPDATE src/app/blog/blog.component.spec.ts (639 bytes) +UPDATE src/app/blog/blog.component.ts (508 bytes) +UPDATE src/app/blog/blog.module.ts (391 bytes) + ✅️ Blog ./mdblog/2020-03-24-blog.md file created +CREATE mdblog/2020-03-24-blog.md (95 bytes) +``` + +Alternatively, it is possible to run the `@scullyio/init:markdown` command with flags to avoid the prompts as follows: + +```bash +ng generate @scullyio/init:markdown --name="blog" --slug="title" --source-dir="mdblog" --route="blog" +``` + +## Available options + +| Option | Description | Default | +| -------------- | --------------------------------------------------------- | ------------------------ | +| `name` | Defines the name for the created module | 'blog' | +| `slug` | Defines the name for the url matcher file. `:slug` | 'id' | +| `routingScope` | Sets a routing scope (`Root` or `Child`) | `Child` | +| `sourceDir` | Defines a source directory name (default: `name`) | value from `name` option | +| `route` | Defines a route path before the `:slug` (default: `name`) | value from `name` option | + +## Create an entry point (Home page) + +Create a _Home Module_ with routes configured and with a _Home Component_ with the following command: + +```bash +ng generate module home --route=home --module=app-routing +``` + +**Scully depends on the _route entry point_.** + +## Configure entry point Module as project Root + +Open the `app-routing.module.ts` file and set an empty path attribute for the home route as shown below: + +```typescript +const routes: Routes = [ + // ... + { + path: '', + loadChildren: () => import('./home/home.module').then((m) => m.HomeModule), + }, +]; +``` + +## Extending functionality + +Scully works well in combination with other tools and [utilities](/docs/learn/utilities/overview---). + +For instance, if the markdown content includes code blocks, and you want to highlight them; use a utility. + + diff --git a/docs/blog.md b/docs/learn/create-a-blog/generate-new-blog-posts.md similarity index 61% rename from docs/blog.md rename to docs/learn/create-a-blog/generate-new-blog-posts.md index 975be5605..9a1d6d608 100644 --- a/docs/blog.md +++ b/docs/learn/create-a-blog/generate-new-blog-posts.md @@ -1,80 +1,23 @@ --- -title: Create a blog -order: 600 +title: Generating new blog posts +published: true lang: en +navlist_position: 200 --- -# Creating a Blog - -Scully is the best option for moving a blog to Angular! It provides a schematic that enables Angular applications to use markdown files for blog's content. - -This guide covers the following topics: - -1. [Adding Blog Support](#adding-blog-support) -2. [Generating New Blog Posts](#generating-new-blog-posts) - -_IMPORTANT:_ If you do not have an Angular app with Scully, please check the [getting started](/docs/getting-started) guide first. - -## Adding Blog Support - -Add blog support by running the following command: - -```bash -ng generate @scullyio/init:blog -``` - -The above command adds the blog modules' routes to the Angular application. In addition, it creates a `./blog` folder for the blog's markdown files. In case you want to use a different folder name, run the following command: - -```bash -ng generate @scullyio/init:markdown -``` - -You will be prompted with the following questions; - -```bash -? What name do you want to use for the module? blog -? What slug do you want for the markdown file? title -? Where do you want to store your markdown files? mdblog -? Under which route do you want your files to be requested? blog -``` - -After adding the blog support, you should see the following message: +# Generating new blog posts -```bash - ✅️ Update scully.{{yourApp}}.config.js -UPDATE scully.{{yourApp}}.config.js (653 bytes) -UPDATE src/app/app-routing.module.ts (726 bytes) -UPDATE src/app/blog/blog-routing.module.ts (429 bytes) -UPDATE src/app/blog/blog.component.css (157 bytes) -UPDATE src/app/blog/blog.component.html (160 bytes) -UPDATE src/app/blog/blog.component.spec.ts (639 bytes) -UPDATE src/app/blog/blog.component.ts (508 bytes) -UPDATE src/app/blog/blog.module.ts (391 bytes) - ✅️ Blog ./mdblog/2020-03-24-blog.md file created -CREATE mdblog/2020-03-24-blog.md (95 bytes) -``` - -Alternatively, it is possible to run the `@scullyio/init:markdown` command with flags to avoid the prompts as follows: - -```bash -ng generate @scullyio/init:markdown --name="blog" --slug="title" --source-dir="mdblog" --route="blog" -``` - -The following table shows all available options: - -| Option | Description | Default | -| -------------- | --------------------------------------------------------- | ------------------------ | -| `name` | Defines the name for the created module | 'blog' | -| `slug` | Defines the name for the url matcher file. `:slug` | 'id' | -| `routingScope` | Sets a routing scope (`Root` or `Child`) | Child | -| `sourceDir` | Defines a source directory name (default: `name`) | value from `name` option | -| `route` | Defines a route path before the `:slug` (default: `name`) | value from `name` option | +
      -Scully works well in combination with other tools and [utilities](utils.md). +- [Overview](#overview) +- [Available Options](#available-options) +- [Usage](#usage) +- [Generating the blog post route](#generating-the-blog-post-route) +- [Serve the website](#serve-the-website) +- [Going live](#going-live) +- [Overriding the slug](#overriding-the-slug) -For instance, if the markdown content includes code blocks, and you want to highlight them; use a utility. - -## Generating New Blog Posts +## Overview To create a new blog post, run the following command: @@ -82,7 +25,7 @@ To create a new blog post, run the following command: ng generate @scullyio/init:post --name="This is my post" ``` -The following table shows all available options: +## Available Options | option | description | default | | -------------- | ------------------------------------------------------ | --------- | @@ -90,7 +33,7 @@ The following table shows all available options: | `target` | Define the target directory for the new post file | 'blog' | | `metaDataFile` | Use a meta data yaml template from a file for the post | undefined | -## New blog post example +## Usage Let's look at an example. We want to create a new blog post so we type the following in the terminal `ng generate @scullyio/init:post --name="Angular tutorial"`. This triggers the following output: @@ -103,7 +46,7 @@ CREATE blog/angular-tutorial.md (99 bytes) Above you are prompted where you want to place your blog post. You go with default, which is the `blog/` directory. You can then see above how the file `angular-tutorial.md` is created with this message: -```bash +```output CREATE blog/angular-tutorial.md ``` @@ -125,7 +68,7 @@ At the top of the file there is a frontmatter, a set of instructions Scully is u - `description`, this is the description - `published`, this is a property representing whether the blog post is published or not. It takes a `true` or `false`. -### Generating the blog post route +## Generating the blog post route Next you want to build Scully to generate the route. Type the following in the terminal: @@ -142,14 +85,16 @@ description: 'blog description' published: false slugs: - ___UNPUBLISHED___kao8mvda_pmldPr7aN7owPpStZiuDXFZ1ILfpcv5Z ----# Angular tutorial +--- + +# Angular tutorial ``` The property `slugs` have been added to the frontmatter above. `slugs` contains an anonymous URL as long as the property `published` is set to `false`. This is a URL that you can share with others to for example get feedback on your blog post before it goes live. > NOTE, when you gave the command to build Scully the blog post you just created in Markdown was converted to HTML and placed in the directory `dist/static/blog//index.html`. -### Serve the website +## Serve the website Now that page and the route has been generated, let's serve up the application and ensure it works. Type the following command to serve the static site built by Scully: @@ -170,13 +115,13 @@ Your blog post can be found on the URL `http://localhost:1668/blog/ + + + diff --git a/docs/learn/create-a-blog/use-blog-post-data-in-template.md b/docs/learn/create-a-blog/use-blog-post-data-in-template.md new file mode 100644 index 000000000..293f288fa --- /dev/null +++ b/docs/learn/create-a-blog/use-blog-post-data-in-template.md @@ -0,0 +1,96 @@ +--- +title: Using blog data in an Angular template +published: true +lang: en +navlist_position: 300 +--- + +# Using blog data in an Angular template + +
      + +- [Injecting Scully's Route Service](#injecting-scullys-route-service) +- [Adding metadata to ScullyRoutes](#adding-metadata-to-scullyroutes) + +## Injecting Scully's [Route Service](/docs/learn/core-features/scully-routes-service) + +Scully provides a service for accessing generated routes with ease. To use it, open the `home.component.ts` file we made earlier and add the following code: + +```typescript +import { ScullyRoutesService, ScullyRoute } from '@scullyio/ng-lib'; +import { Observable } from 'rxjs'; + +@Component() +//... +export class HomeComponent implements OnInit { + links$: Observable = this.scully.available$; + + constructor(private scully: ScullyRoutesService) {} + + ngOnInit() { + // debug current pages + this.links$.subscribe((links) => { + console.log(links); + }); + } +} +``` + +We can see `ScullyRoutesService.available$` returns an Observable of an array of [`ScullyRoute`](https://github.com/scullyio/scully/blob/main/libs/ng-lib/src/lib/route-service/scully-routes.service.ts)s, the interface of which looks like this: + +```typescript +export interface ScullyRoute { + route: string; + title?: string; + slugs?: string[]; + published?: boolean; + slug?: string; + sourceFile?: string; + [prop: string]: any; +} +``` + +To extract data from the available `links$` Scully has rendered, we can loop through them inside the template by opening the `home.component.html` file and adding the following code: + +```html +

      home works!

      + +
        +
      • {{ page.route }}
      • +
      +``` + +**NOTE:** If you don't add any route, Scully will pre-render 0 pages. + +## Adding metadata to ScullyRoutes + +At the very top of each `.md` blog post file, between the opening and closing `---` indicators, each line of text corresponds to a property we can pull out of `ScullyRoutesService.available$`. + +For example, a `.md` file beginning with: + +``` +--- +title: blog title +description: blog description +published: true +arbitraryValue: single value +arbitraryArray: [first item, second item] +--- +``` + +... lets us use these values in our template like this: + +```html +
        +
      • + {{ page.route }} {{ page.arbitraryValue }} + + {{ arrayItem }} + +
      • +
      +``` + + diff --git a/docs/faq.md b/docs/learn/faq.md similarity index 53% rename from docs/faq.md rename to docs/learn/faq.md index eec534466..104091ecc 100644 --- a/docs/faq.md +++ b/docs/learn/faq.md @@ -1,69 +1,28 @@ --- title: Frequently Asked Questions -order: 9000 +published: true lang: en +navlist_position: 600 +navlist_linkText: FAQ --- -# Frequently Asked Questions +# Frequently Asked Questions -
      - - language in route? - - -> In my project i have a routing like this:
      -> /:lang
      -> /:lang/page1
      -> /:lang/page2
      -> etc...
      -> -> It's very simple. :lang can have few values (it, en...) and If possible I prefer to store it in the config, without have -> an endpoint dedicated.
      How can I solve this? - -As the Scully config file is typescript, you can post-process the routing object. a very crude solution would be something like this: - -```typescript -import { ScullyConfig } from '@scullyio/scully'; - -const preLangConfig: ScullyConfig = { - /** settngs */ - routes: { - ':lang/route1': { type: 'default' }, - ':lang/route2': { type: 'default' }, - ':lang/route3': { type: 'default' }, - ':lang/route4': { type: 'default' }, - }, -}; -export const config = { - ...preLangConfig, - routes: Object.fromEntries( - // make sure you use a node-version that supports this, or use a reduce. - Object.entries(preLangConfig.routes).reduce((all, [route, config]) => { - if (route.includes(':lang')) { - ['it', 'en', 'nl', 'sp'].forEach(( - lang // <-- language array - ) => all.push([route.split(':lang').join(lang), config])); - } else { - all.push([route, config]); - } - return all; - }, []) - ), -}; +
      -console.log(config.routes); -``` +- [Ignoring Routes](#ignoring-routes) +- [Plugins](#plugins) +- [Route Parameters](#route-parameters) -It takes the `preLangConfig` and iterates over all the routes. When it finds the `:lang` parameter, it creates an entry with every value provided in the language array. That way the final config will have a route for every language available. - -
      +## Ignoring Routes
      -Ignore routes without config? +Ignore routes without config -> In my app I have a lot of routes I don't want scully to handle. How can I deal with that. +> I have a lot of routes I don't want Scully to handle. +> How can I deal with this? -Scully will use the `default` plugin for any route that is not specified. When you want to have another way to handle defaults, you can replace this plugin with another one. +Scully will use the `default` plugin for any route that is not specified. When you want to have another way to handle defaults, you can replace this plugin with another one. For example, if you want to ignore all undefined routes you can do: ```typescript @@ -98,10 +57,12 @@ registerPlugin(
      +## Plugins +
      How do I fix plugin build errors related to the `express-serve-static-core` module? -Building a plugin results in a fatal error `Cannot find module 'express-serve-static-core'`, originating from `node_modules/@scullyio/scully/lib/utils/serverstuff/staticServer.d.ts` +> Building a plugin results in a fatal error `Cannot find module 'express-serve-static-core'`, originating from `node_modules/@scullyio/scully/lib/utils/serverstuff/staticServer.d.ts` To correct this, add the `skipLibCheck` and `skipDefaultLibCheck` flags to your `tsconfig.json` => `compilerOptions` like this: @@ -117,14 +78,80 @@ To correct this, add the `skipLibCheck` and `skipDefaultLibCheck` flags to your
      - +If you run Scully and the following warning is displayed, you need to teach Scully how to use the project's route parameters. + +```bash +No configuration for route `/user/:userId` found. Skipping +``` + +The above error is given because Scully does not know all the possible values for `:userId`. Teach Scully how to get the list of `:userId`s from your app. Scully can turn `/user/:userId` into a list of meaningful pre-renderable routes like so: + +``` +/user/1 +/user/2 +/user/3 +... +/user/100 +``` + +Even small Angular projects have routes that contain route parameters. To stop Scully from skipping these routes, configure a [route plugin](/docs/learn/plugins/types/router). Route plugins teach Scully how to fetch data and merges it into routes using parameters. + +The easiest way to understand route plugin is by understanding the [`jsonPlugin`](/docs/learn/plugins/built-in-plugins/json). It simply fetches data from any API that you specify, and it returns a list of properties that can be used to replace the route parameter. Checkout the [jsonPlugin docs](/docs/learn/plugins/built-in-plugins/json) to see an example of how easy this configuration is. + + + +
      +Language params in routes + +> I have a routing structure which looks like this: +> `/:lang` +> `/:lang/page1` +> `/:lang/page2` +> etc. +> `:lang` can have few values (`'it'`, `'en'`, etc.) +> I prefer to store `:lang` in the config, without a dedicated endpoint. +> How can I solve this? + +As the Scully config file is typescript, you can post-process the routing object. +A very crude solution would be something like this: + +```typescript +import { ScullyConfig } from '@scullyio/scully'; + +const preLangConfig: ScullyConfig = { + /** settngs */ + routes: { + ':lang/route1': { type: 'default' }, + ':lang/route2': { type: 'default' }, + ':lang/route3': { type: 'default' }, + ':lang/route4': { type: 'default' }, + }, +}; +export const config = { + ...preLangConfig, + routes: Object.fromEntries( + // make sure you use a node-version that supports this, or use a reduce. + Object.entries(preLangConfig.routes).reduce((all, [route, config]) => { + if (route.includes(':lang')) { + ['it', 'en', 'nl', 'sp'].forEach(( + lang // <-- language array + ) => all.push([route.split(':lang').join(lang), config])); + } else { + all.push([route, config]); + } + return all; + }, []) + ), +}; + +console.log(config.routes); +``` + +It takes the `preLangConfig` and iterates over all the routes. When it finds the `:lang` parameter, it creates an entry with every value provided in the language array. That way the final config will have a route for every language available. + +
      diff --git a/docs/learn/getting-started/building.md b/docs/learn/getting-started/building.md new file mode 100644 index 000000000..eb81d05dd --- /dev/null +++ b/docs/learn/getting-started/building.md @@ -0,0 +1,45 @@ +--- +title: Building a Scully app +published: true +lang: en +navlist_position: 300 +--- + +# Building a Scully app + +## Overview + +Running Scully for the first time is exciting. Congrats on making it here! + +Before Scully can run you need to build your Angular project. Most projects' built is: + +```bash +ng build +``` + +Now that the Angular project is built, Scully can do its work. Run Scully with the following command: + +```bash +npm run scully +``` + +You did it! You have turned your Angular app into a wicked fast pre-rendered static site thanks to Scully. + +The Scully-built version of the project is located in the `./dist/static` folder. It contains all the static pages in the project. + +## Troubleshooting + +**NOTE**: In case of any errors or warnings during the build process, please follow the instructions in the errors/warnings section or [submit an issue](https://github.com/scullyio/scully/issues/new/choose). + +**NOTE**: The following is a common error when building with Scully for the first time: + +```bash +No configuration for route `/user/:userId` found. Skipping +``` + +This message indicates that Scully has skipped any unconfigured routes. Read more about [Route Parameters & Scully](/docs/learn/faq#route-parameters). + + diff --git a/docs/learn/getting-started/installation.md b/docs/learn/getting-started/installation.md new file mode 100644 index 000000000..dda0aed4a --- /dev/null +++ b/docs/learn/getting-started/installation.md @@ -0,0 +1,54 @@ +--- +title: Installation +published: true +lang: en +navlist_position: 200 +--- + +# Installation + +## Overview + +Before adding Scully to your Angular project, make sure it meets [Scully's requirements](/docs/learn/getting-started/requirements). + +Adding Scully to your project is as simple as running one command: + +```bash +ng add @scullyio/init +``` + +If you are using a `NX` vanilla workspace (non Angular workspace) + +```bash +npm install @scullyio/init +nx g @scullyio/init:install -- --project= +``` + +**NOTE**: After installation, if you were serving the app during the installation, you need to restart `ng serve`. + +Running the `@scullyio/init` schematic makes all the necessary changes the Angular project, so you don't need to go through a lengthy setup process. + +The above command creates a Scully config file named `scully..config.ts`, where the `projectName` is the name of your Angular project. +This file looks like this: + +```typescript +import { ScullyConfig } from '@scullyio/scully'; + +export const config: ScullyConfig = { + projectRoot: './src', + projectName: '', + outDir: './dist/static', + routes: {}, +}; +``` + +Even with this basic config, you are now ready to build your Angular app using Scully for the first time! + +**NOTE**: It is important to know that any routes in the Angular project that contain route parameters will not be pre-rendered until you modify the above config to account for those parameters. + +The [JSON Plugin](docs/learn/plugins/built-in-plugins/json) is an example of how to configure route parameters with Scully. + + diff --git a/docs/learn/getting-started/requirements.md b/docs/learn/getting-started/requirements.md new file mode 100644 index 000000000..342d3acd0 --- /dev/null +++ b/docs/learn/getting-started/requirements.md @@ -0,0 +1,59 @@ +--- +title: Requirements +published: true +lang: en +navlist_position: 100 +navlist_parentIndex: true +navlist_parentPosition: 200 +--- + +# Requirements + +
      + +- [Overview](#overview) +- [Software Requirements](#software-requirements) +- [Creating a New Angular Application](#creating-a-new-angular-application) +- [Add Router Modules](#add-router-modules) + +## Overview + +You need an existing Angular application, or you can create a new one in order to use Scully. + +## Software Requirements + +- Angular versions: **v8.x.x** and **v9.x.x** +- Node.js: **10** or higher. +- Chromium: **IMPORTANT:** _Scully uses Chromium. Therefore, your Operating System, as well as its administrator rights must allow its installation and execution._ + +## Creating a New Angular Application + +Install the Angular CLI globally with the following command: + +```bash +npm install -g @angular/cli +``` + +Then, create a new application. + +```bash +ng new my-scully-app +``` + +## Add Router Modules + +Your Angular project needs at least one route set up. If you have questions about adding routes, see the [Angular routing docs](https://angular.io/start/start-routing).
      +**IMPORTANT:** _Scully depends on the app's router module in order to generate the website's pages_ + +Add a router module with the following command: + +```bash +ng generate module app-routing --flat --module=app +``` + +Find more info about the Angular CLI here [👉 angular.io/cli](https://angular.io/cli) + + diff --git a/docs/learn/getting-started/serving.md b/docs/learn/getting-started/serving.md new file mode 100644 index 000000000..cab470005 --- /dev/null +++ b/docs/learn/getting-started/serving.md @@ -0,0 +1,29 @@ +--- +title: Serving a Scully app +published: true +lang: en +navlist_position: 400 +--- + +# Serving a Scully app + +## Overview + +After [building](/docs/learn/getting-started/building), see the output and test how it runs as a statically generated webpage. + +To see the pre-rendered site, open the `/dist/static` folder where you can find one `index.html` for every route in your app. Hence, if the application has 1000 routes, there should be 1000 `index.html` files in the `dist/static` folder. + +These `index.html` files are jamstack-packed with HTML and CSS. This means that Scully built successfully, and that your site is now pre-rendered. + +Scully provides a server, so that you can test out your jamstack site after the Scully build. To launch Scully's test server, run the following command: + +```bash +npm run scully:serve +``` + +This command actually launches **2 (two)** servers. The first one is hosting the results of `ng build`, and the second server hosts the results of the Scully build. This allows you to test both versions of your built app. Very cool! + + diff --git a/docs/learn/getting-started/tips-for-testing.md b/docs/learn/getting-started/tips-for-testing.md new file mode 100644 index 000000000..5bf3a6d79 --- /dev/null +++ b/docs/learn/getting-started/tips-for-testing.md @@ -0,0 +1,35 @@ +--- +title: Tips for Testing +published: true +lang: en +navlist_position: 500 +--- + +# Tips for Testing + +### Only rebuild Angular if you change Angular + +Although this may seem evident, if this is your first time using Scully it is easy to rebuild Angular even if it is not needed. When writing Scully plugins OR modifying your blog's markdown files, you DO NOT need to `ng build` the app each time you re-run Scully. Again, `ng build` Angular only if the Angular app changes. + +Whenever you are confused about re-running the Angular build, just ask yourself: + +> Did I change the Angular code, or the Scully code? + +### Scully Serve + +Running `npm run scully` pre-builds your project with Scully. Any time a plugin or a markdown file changes, re-run this process. In addition, if any of the content that the Angular app depends on changes, you need to re-run the Scully build. + +To make the `serve` process easier run the following command: + +```bash +npm run scully -- --watch +``` + +Running Scully build with the `--watch` option live-reloads the Scully build. In other words, It watches for any changes from the Angular build or from any of the markdown files. If any of those change, the Scully build re-executes, and it serves the new results in realtime. + +**NOTE**: This is ideal for a faster development, but **DO NOT** use the `--watch` option during production or any devops process or the build will never finish. + + diff --git a/docs/learn/introduction.md b/docs/learn/introduction.md new file mode 100644 index 000000000..65bed1ce5 --- /dev/null +++ b/docs/learn/introduction.md @@ -0,0 +1,37 @@ +--- +title: Introduction +published: true +lang: en +navlist_position: 100 +navlist_parentIndex: true +navlist_parentPosition: 100 +--- + +# Introduction + +## What is Scully? + +Scully is the best static site generator for Angular projects looking to embrace the [Jamstack](https://jamstack.org/). +Scully works on Windows, Linux and macOS. + +All about Scully in one video: + + +Building the Fastest Angular Apps Possible + + +## How does it work? + +Scully analyzes the route structure of your compiled Angular application and generates a static version of each page. + +## How do I use it? + +Scully provides a number of utilities to manipulate static pages, such as: + +- [Render .md files as .html](/docs/learn/create-a-blog/add-blog-support) and [extract data from generated routes](/docs/learn/create-a-blog/use-blog-post-data-in-template) to use in Angular templates via simple observable. +- A [flexible plugin system](/docs/learn/plugins/overview) to bake your own functionality into Scully's processes. +- Several [Angular schematics](/docs/learn/schematics/create-scully-files-with-ng-add) to make its usage as easy as possible! + + diff --git a/docs/learn/introduction_es.md b/docs/learn/introduction_es.md new file mode 100644 index 000000000..f081fa2b1 --- /dev/null +++ b/docs/learn/introduction_es.md @@ -0,0 +1,39 @@ +--- +title: Introducción +published: true +lang: es +navlist_linkText: Introducción +navlist_position: 100 +navlist_parentIndex: true +navlist_parentPosition: 100 +navlist_parentLinkText: Aprender +--- + +# Introducción + +## ¿Qué es Scully? + +Scully es el mejor generador de sitios estáticos para proyectos Angular que buscan adoptar el [Jamstack](https://jamstack.org/). +Scully funciona en Windows, Linux y macOS. + +Todo sobre Scully en un video: + + +Construyendo las aplicaciones Angular más rápidas posibles + + +## ¿Como funciona? + +Scully analiza la estructura de rutas de su aplicación Angular compilada y genera una versión estática de cada página. + +## ¿Como lo uso? + +Scully proporciona una serie de utilidades para manipular páginas estáticas, como: + +- [Renderizar archivos .md como .html](/docs/learn/create-a-blog/add-blog-support) y [extraer datos de rutas generadas](/docs/learn/create-a-blog/use-blog-post-data-in-template) para usar en plantillas Angular a través de simples observable. +- Un [sistema de complementos flexible](/docs/learn/plugins/overview) para hornear tu propia funcionalidad en los procesos de Scully. +- Varios [Angular schematics](/docs/learn/schematics/create-scully-files-with-ng-add) para hacer su uso lo más fácil posible! + +
      + +
      diff --git a/docs/learn/legacy-support/angular-v8.md b/docs/learn/legacy-support/angular-v8.md new file mode 100644 index 000000000..d1982396b --- /dev/null +++ b/docs/learn/legacy-support/angular-v8.md @@ -0,0 +1,22 @@ +--- +title: Releasing an Angular v8.x.x Library +published: true +lang: en +--- + +# Releasing an Angular v8.x.x Library + +- Checkout the `angular-8` branch +- Remove version 9: `rm -fr node_modules` +- Install version 8: `npm i` +- Pull origin main branch: `git pull origin main` +- Fix any merge conflicts +- Make sure that `package.json` file has version 8 +- Build the application: `ng build @scullyio/ng-lib-v8` +- Run tests +- Pay attention to `package.json` to make sure you keep the 8 version +- If all tests are ok, rebuild the library: + - `ng build @scullyio/ng-lib-v8` +- Publish the application: + - `cd ./dist/scullyio/ng-lib-v8` +- Commit and push changes. diff --git a/docs/polyfills.md b/docs/learn/legacy-support/polyfills.md similarity index 73% rename from docs/polyfills.md rename to docs/learn/legacy-support/polyfills.md index 10db95d21..4b383e646 100644 --- a/docs/polyfills.md +++ b/docs/learn/legacy-support/polyfills.md @@ -1,24 +1,26 @@ --- title: Polyfills -order: 800 +published: true lang: en --- # Polyfills -Depending on the browser and environment that the application targets, some polyfills are -required. This page lists the recommended polyfills. +Depending on the browser and environment that the application targets, some polyfills are required. +This page lists the recommended polyfills. -## `Event()` constructor +### `Event()` constructor Scully uses [`Event`](https://developer.mozilla.org/en-US/docs/Web/API/Event/Event) to be aware of different points in the application's lifecycle. +### Internet Explorer 10+ + To make **Internet Explorer 10+** work, install and import the following polyfill: `npm install events-polyfill` -```ts +```typescript // src/polyfills.ts import 'events-polyfill/src/constructors/Event.js'; ``` diff --git a/docs/learn/plugins/built-in-plugins/adoc.md b/docs/learn/plugins/built-in-plugins/adoc.md new file mode 100644 index 000000000..6eba7feb7 --- /dev/null +++ b/docs/learn/plugins/built-in-plugins/adoc.md @@ -0,0 +1,12 @@ +--- +title: adoc Plugin +published: true +lang: en +navlist_textFormat_none: true +--- + +# `adoc` Plugin + +## Overview + +Adds capability to render adoc files as html. diff --git a/docs/learn/plugins/built-in-plugins/contentFolder.md b/docs/learn/plugins/built-in-plugins/contentFolder.md new file mode 100644 index 000000000..c1d7add9a --- /dev/null +++ b/docs/learn/plugins/built-in-plugins/contentFolder.md @@ -0,0 +1,60 @@ +--- +title: contentFolder Plugin +published: true +lang: en +navlist_textFormat_none: true +--- + +# `contentFolder` Plugin + + + +
      + +- [Overview](#overview) +- [Usage](#usage) + - [`router` Plugin](#router-plugin) + - [`render` Plugin](#render-plugin) + +## Overview + +The `contentFolder` plugin defines a **folder** in which Scully should look for content to render, and a **route with params** to associate rendered static files with. + +It is a combination of a [`router` plugin](/docs/learn/plugins/types/router) and [`render` plugin](/docs/learn/plugins/types/render), and is built into Scully. + +## Usage + +### `router` Plugin + +The `contentFolder` router plugin takes a config in the form of: + +```typescript +const contentFolderconfig = { + routes: { + '/blog/:slug': { + type: 'contentFolder', + slug: { + folder: './tests/assets/blog-files', + }, + }, + }, +}; +``` + +The config takes and handles only one parameter, called `folder` which is mandatory. It is a file's location relative to the project root. + +Scully traverses this folder, and its subfolders in order to make a `HandledRoute` for each file-extension known in there. +`.md`(markdown) and `adoc` (asciiDoc) are known out of the box. That route has a `templateFile` property with the full path to the file. The route reflects the folder structure. + +Furthermore, it parses out the date in the front-matter part, and it is added to the handledRoutes `data` property. + +### `render` Plugin + +The contentFolder render plugin takes the pre-rendered HTML and a `HandlerRoute` in order to read the file indicated by the `templateFile` property. +It extracts the Angular `_ngcontent` id. It looks for the file's extension in the fileHandler plugins, and it uses this plugin to convert the raw content into HTML. + +Finally, it adds the `_ngcontent` id to the generated HTML, so that components' style works as expected. + +This plugin finds the `` tag, and it injects the HTML as its previous sibling(s). diff --git a/docs/learn/plugins/built-in-plugins/ignored.md b/docs/learn/plugins/built-in-plugins/ignored.md new file mode 100644 index 000000000..e88c31630 --- /dev/null +++ b/docs/learn/plugins/built-in-plugins/ignored.md @@ -0,0 +1,16 @@ +--- +title: ignored Plugin +published: true +lang: en +navlist_textFormat_none: true +--- + +# `ignored` Plugin + + + +## Overview + +Adds support for ignoring routes. diff --git a/docs/plugin/jsonPlugin.md b/docs/learn/plugins/built-in-plugins/json.md similarity index 54% rename from docs/plugin/jsonPlugin.md rename to docs/learn/plugins/built-in-plugins/json.md index f3144d5f9..a91ac3330 100644 --- a/docs/plugin/jsonPlugin.md +++ b/docs/learn/plugins/built-in-plugins/json.md @@ -1,16 +1,29 @@ --- -title: Plugins - JSON Plugin -order: 730 +title: json Plugin +published: true lang: en +navlist_textFormat_none: true --- -# JSON Plugin +# `json` Plugin -The JSON Plugin fetches data from API endpoints during route discovery. Scully uses this data -to create a list of routes that contain route parameters. + -Imagine your app has an Angular route configured with the path `users/:userId`. Scully needs help understanding -the route parameter `:userId`. +
      + +- [Overview](#overview) +- [Usage](#usage) +- [Examples](#examples) + +## Overview + +The JSON Plugin fetches data from API endpoints during route discovery. Scully uses this data to create a list of routes that contain route parameters. + +## Usage + +Imagine your app has an Angular route configured with the path `users/:userId`. Scully needs help understanding the route parameter `:userId`. The following is an example of how you could use the `jsonPlugin` to get `userId`s from your server (`localhost:8200`) that Scully needs to pre-render the `user/:userId` routes. @@ -30,17 +43,13 @@ export const config: ScullyConfig = { }; ``` -The above example tells Scully to use the `json plugin` for fetching some JSON data via HTTP whenever it finds a route matching `/user/:userId`. -The `userId`'s value contains two pieces of data. First, the url that the JSON plugin should go to in order to get the required JSON. -Second, the `id` property. +The above example tells Scully to use the `json` plugin for fetching some JSON data via HTTP whenever it finds a route matching `/user/:userId`. The userId's value contains two pieces of data. First, the url that the JSON plugin should go to in order to get the required JSON. Second, the `id` property. -The JSON plugin plucks the provided property name from each of the items in the `HandledRoute[]` array. In other words, -the data array returned by the `jsonplaceholder` API, each containing an `id` property. Therefore, returning a list of `userIds` instead of a list -of users. +The JSON plugin plucks the provided property name from each of the items in the `HandledRoute[]` array. In other words, the data array returned by the `jsonplaceholder` API, each containing an `id` property. Therefore, returning a list of `userIds` instead of a list of users. The JSON plugin also accepts any header needed when making an API request. -##### Example: +## Examples ```typescript // scully.config.ts diff --git a/docs/learn/plugins/built-in-plugins/md.md b/docs/learn/plugins/built-in-plugins/md.md new file mode 100644 index 000000000..39d1b34d9 --- /dev/null +++ b/docs/learn/plugins/built-in-plugins/md.md @@ -0,0 +1,12 @@ +--- +title: md Plugin +published: true +lang: en +navlist_textFormat_none: true +--- + +# `md` Plugin + +## Overview + +Adds capability to render markdown files as html. diff --git a/docs/learn/plugins/built-in-plugins/router-.md b/docs/learn/plugins/built-in-plugins/router-.md new file mode 100644 index 000000000..8a2d30c8f --- /dev/null +++ b/docs/learn/plugins/built-in-plugins/router-.md @@ -0,0 +1,12 @@ +--- +title: router Plugin +published: true +lang: en +navlist_textFormat_none: true +--- + +# `router` Plugin + +## Overview + +Adds the route verbatim. Scully uses this plugin by default. diff --git a/docs/learn/plugins/built-in-plugins/seoHrefOptimize.md b/docs/learn/plugins/built-in-plugins/seoHrefOptimize.md new file mode 100644 index 000000000..929f78c92 --- /dev/null +++ b/docs/learn/plugins/built-in-plugins/seoHrefOptimize.md @@ -0,0 +1,12 @@ +--- +title: seoHrefOptimize Plugin +published: true +lang: en +navlist_textFormat_none: true +--- + +# `seoHrefOptimize` Plugin + +## Overview + +Adds a trailing slash (`/`) to all routes that are in the routeService. Increases SEO scoring. diff --git a/docs/learn/plugins/community-plugins/disableAngular.md b/docs/learn/plugins/community-plugins/disableAngular.md new file mode 100644 index 000000000..7ff3ad489 --- /dev/null +++ b/docs/learn/plugins/community-plugins/disableAngular.md @@ -0,0 +1,106 @@ +--- +title: disableAngular Plugin +published: true +lang: en +navlist_textFormat_none: true +--- + +# `disableAngular` Plugin + + + +
      + +- [Overview](#overview) +- [Installation](#installation) +- [Usage](#usage) +- [Clearing dynamic state](#clearing-dynamic-state) + +## Overview + +This `postRenderer` plugin for Scully removes the static assets that bootstrap the Angular application. Optionally you can also remove the dynamic transfer state from the HTML. + +If you are only using Angular to build a static / informational website with little extra functionality it could be overkill to still use Angular on the frontend. + +Disabling Angular on the frontend will speed up your loading times and mobile scores even more! + +## Installation + +To install this library with `npm` run: + +``` +$ npm install scully-plugin-disable-angular --save-dev +``` + +or with `yarn` + +``` +$ yarn add scully-plugin-disable-angular +``` + +## Usage + +Import and add the plugin to the `defaultPostRenderers` to execute it on all rendered pages or use the postRenderers on a route configuration to execute it for a specific route: + +**Important:** the current implementation of Scully is that if you provide a `postRenderers` option on a route level, it will ignore the configuration of the `defaultPostRenderers` option at the root level of the config. + +For more information, check out: [https://github.com/scullyio/scully/issues/595](https://github.com/scullyio/scully/issues/595) + +```typescript +const { RouteTypes } = require('@scullyio/scully'); +const { DisableAngular } = require('scully-plugin-disable-angular'); + +const postRenderers = [DisableAngular]; + +exports.config = { + projectRoot: './src/app', + defaultPostRenderers: postRenderers, // for all routes + routes: { + '/blog/:slug': { + type: RouteTypes.contentFolder, + slug: { + folder: './blog', + }, + postRenderers: postRenderers, // per route config + }, + }, +}; +``` + +Now build your app with the `--stats-json` flag enabled as the plugin needs to know which assets have been build for your app. Then just run the Scully command. + +``` +npm run build -- --prod --stats-json +npm run scully +``` + +## Clearing dynamic state + +When disabling Angular in your prerendered pages there is no point in keeping the dynamic state serialized in your HTML. By providing the option `removeState` to the configuration the plugin will remove this state from the HTML. + +```typescript +const { RouteTypes, setPluginConfig } = require('@scullyio/scully'); +const { DisableAngular } = require('scully-plugin-disable-angular'); + +const postRenderers = [DisableAngular]; + +setPluginConfig(DisableAngular, 'render', { + removeState: true, +}); + +exports.config = { + projectRoot: './src/app', + defaultPostRenderers: postRenderers, // for all routes + routes: { + '/blog/:slug': { + type: RouteTypes.contentFolder, + slug: { + folder: './blog', + }, + postRenderers: postRenderers, // per route config + }, + }, +}; +``` diff --git a/docs/learn/plugins/community-plugins/fouc.md b/docs/learn/plugins/community-plugins/fouc.md new file mode 100644 index 000000000..ed85e945b --- /dev/null +++ b/docs/learn/plugins/community-plugins/fouc.md @@ -0,0 +1,65 @@ +--- +title: fouc Plugin +published: true +lang: en +navlist_textFormat_none: true +--- + +# `fouc` Plugin + + + +
      + +- [Overview](#overview) +- [Installation](#installation) +- [Usage](#usage) + +## Overview + +`scully-plugin-fouc` is a `postRenderer` plugin for Scully to prevent flash of unstyled content. + +## Installation + +To install this plugin with `npm` run: + +```bash +$ npm install @notiz/scully-plugin-fouc --save-dev +``` + +## Usage + +Add the plugin to the defaultPostRenderers in your scully.config: + +```json +require("@notiz/scully-plugin-fouc"); + +exports.config = { + projectRoot: "./src/app", + defaultPostRenderers: ["fouc"], + routes: {} +}; +``` + +If you want to use the plugin for a specific route do: + +```typescript +require('@notiz/scully-plugin-fouc'); + +exports.config = { + ... + routes: { + '/blog/:slug': { + type: 'contentFolder', + slug: { + folder: './content/blog' + }, + postRenderers: ['fouc'] + } + } + ... +}; +``` diff --git a/docs/learn/plugins/community-plugins/http404.md b/docs/learn/plugins/community-plugins/http404.md new file mode 100644 index 000000000..e126a05fd --- /dev/null +++ b/docs/learn/plugins/community-plugins/http404.md @@ -0,0 +1,103 @@ +--- +title: http404 Plugin +published: true +lang: en +navlist_textFormat_none: true +--- + +# `http404` Plugin + + + +
      + +- [Overview](#overview) +- [Installation](#installation) +- [Usage](#usage) +- [Questions or Issues](#questions-or-issues) + +## Overview + +This `postRenderer` plugin for Scully will create a `/404.html` page for the configured `/404` route. This is handy for generating custom 404 error pages within your Angular application while maintaining compatibility with the [firebase hosting requirements](https://firebase.google.com/docs/hosting/full-config#404) for 404s. + +_Version 1.0.0 introduces breaking changes in the way the plugin is registered and configured. Please update your configurations_ + +## Installation + +To install this library with `npm` run: + +``` +$ npm install @gammastream/scully-plugin-http404 --save-dev +``` + +## Usage + +Create a 404 route in the root router: + +```typescript +RouterModule.forRoot([ + { + path: 'a', + component: PageComponent, + }, + { + path: 'b', + component: PageComponent, + }, + { + path: 'c', + component: PageComponent, + }, + { + path: '', + component: PageComponent, + }, + { + path: '404', + component: Http404Component, + }, + { + path: '**', + component: Http404Component, + }, +]); +``` + +Add the plugin to the `defaultPostRenderers` to execute it on the `/404` route: + +```typescript +import { ScullyConfig, setPluginConfig } from '@scullyio/scully'; +import { getHttp404Plugin } from '@gammastream/scully-plugin-http404'; + +const Http404Plugin = getHttp404Plugin(); + +export const config: ScullyConfig = { + projectRoot: './src', + projectName: 'scully-plugins', + outDir: './dist/static', + defaultPostRenderers: [Http404Plugin], + routes: { + '/products/:productId': { + type: 'json', + productId: { + url: 'http://localhost:4200/assets/products.json', + property: 'id', + }, + }, + }, +}; +``` + +Build app and run scully like normal. + +``` +npm run build +npm run scully +``` + +## Questions or Issues + +If you have any issues you can raise them here or contact me at: [GammaStream](https://gamma.stream/) diff --git a/docs/learn/plugins/community-plugins/lazyImages.md b/docs/learn/plugins/community-plugins/lazyImages.md new file mode 100644 index 000000000..04e542d9c --- /dev/null +++ b/docs/learn/plugins/community-plugins/lazyImages.md @@ -0,0 +1,67 @@ +--- +title: lazyImages Plugin +published: true +lang: en +navlist_textFormat_none: true +--- + +# `lazyImages` Plugin + + + +
      + +- [Overview](#overview) +- [Installation](#installation) +- [Usage](#usage) + +## Overview + +`scully-plugin-lazy-images` is a `postRenderer` plugin for Scully turning your images into lazy loading images using [lazyload](https://github.com/tuupola/lazyload). This will replace the `src` attribute with `data-src` and adds the class `lazyload` to the `img` tag. + +A browser [native approach](https://web.dev/native-lazy-loading/) would be to use `loading="lazy"` for each `img` tag. When it has broader [browser support](https://caniuse.com/#feat=loading-lazy-attr) we will switch to the native approach. + +## Installation + +To install this plugin with `npm` run: + +``` +$ npm install @notiz/scully-plugin-lazy-images --save-dev +``` + +## Usage + +Add the plugin to the defaultPostRenderers in your scully.config: + +```typescript +require('@notiz/scully-plugin-lazy-images'); + +exports.config = { + projectRoot: './src/app', + defaultPostRenderers: ['lazyImages'], + routes: {}, +}; +``` + +If you want to use the plugin for a specific route do: + +```typescript +require('@notiz/scully-plugin-lazy-images'); + +exports.config = { + ... + routes: { + '/blog/:slug': { + type: 'contentFolder', + slug: { + folder: './content/blog' + }, + postRenderers: ['lazyImages'] + } + } + ... +}; +``` diff --git a/docs/learn/plugins/community-plugins/mediumZoom.md b/docs/learn/plugins/community-plugins/mediumZoom.md new file mode 100644 index 000000000..d0839508e --- /dev/null +++ b/docs/learn/plugins/community-plugins/mediumZoom.md @@ -0,0 +1,65 @@ +--- +title: RSS Plugin +published: true +lang: en +navlist_textFormat_none: true +--- + +# `mediumZoom` Plugin + + + +
      + +- [Overview](#overview) +- [Installation](#installation) +- [Usage](#usage) + +## Overview + +`scully-plugin-medium-zoom` is a `postRenderer` plugin for [Scully](http://scully.io/) adding a medium style zoom to your images using [medium-zoom](https://github.com/francoischalifour/medium-zoom). This plugin adds `data-zoomable` attribute to each `img` tag in your route. + +## Installation + +To install this plugin with `npm` run + +``` +$ npm install @notiz/scully-plugin-medium-zoom --save-dev +``` + +## Usage + +Add the plugin to the `defaultPostRenderers` in your `scully.config`: + +```js +require('@notiz/scully-plugin-medium-zoom'); + +exports.config = { + projectRoot: './src/app', + defaultPostRenderers: ['mediumZoom'], + routes: {}, +}; +``` + +If you want to use the plugin for a specific route do: + +```js +require('@notiz/scully-plugin-medium-zoom'); + +exports.config = { + ... + routes: { + '/blog/:slug': { + type: 'contentFolder', + slug: { + folder: './content/blog' + }, + postRenderers: ['mediumZoom'] + } + } + ... +}; +``` diff --git a/docs/learn/plugins/community-plugins/minifyHtml.md b/docs/learn/plugins/community-plugins/minifyHtml.md new file mode 100644 index 000000000..97fcd6857 --- /dev/null +++ b/docs/learn/plugins/community-plugins/minifyHtml.md @@ -0,0 +1,150 @@ +--- +title: minifyHtml Plugin +published: true +lang: en +navlist_textFormat_none: true +--- + +# `minifyHtml` Plugin + + + +
      + +- [Overview](#overview) +- [Installation](#installation) +- [Usage](#usage) + - [Configuring the `html-minifier` options](#configuring-the-html-minifier-options) + +## Overview + +This `postRenderer` plugin for Scully will minify the HTML of your prerendered pages. + +Removing unnecessary code will decrease the size of your files. +This will speed up your loading times and mobile scores even more! + +## Installation + +To install this library with `npm` run + +``` +$ npm install scully-plugin-minify-html --save-dev +``` + +or with `yarn` + +``` +$ yarn add scully-plugin-minify-html +``` + +This package depends on the [`html-minifier`](https://www.npmjs.com/package/html-minifier) package. +It will be installed automatically when installing this package. + +## Usage + +Import and add the plugin to the `defaultPostRenderers` to execute it on all rendered pages +or use the `postRenderers` on a route configuration to execute it for a specific route. + +**Important:** the current implementation of Scully is that if you provide a `postRenderers` option +on a route level, it will ignore the configuration of the `defaultPostRenderers` option at +the root level of the config. + +For more information, check out: https://github.com/scullyio/scully/issues/595 + +```javascript +const { RouteTypes } = require('@scullyio/scully'); +const { MinifyHtml } = require('scully-plugin-minify-html'); + +const postRenderers = [MinifyHtml]; + +exports.config = { + projectRoot: './src/app', + defaultPostRenderers: postRenderers, // for all routes + routes: { + '/blog/:slug': { + type: RouteTypes.contentFolder, + slug: { + folder: './blog', + }, + postRenderers: postRenderers, // per route config + }, + }, +}; +``` + +Now build your app and then just run the Scully command. + +```shell script +npm run build --prod +npm run scully +``` + +### Configuring the `html-minifier` options + +The `MinifyHtml` plugin uses [html-minifier](https://www.npmjs.com/package/html-minifier) under the hood, so we can configure the minify options that are being used. +The available options can be found in the interface [`Options`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/main/types/html-minifier/index.d.ts) + +**The default configuration is currently set at:** + +```typescript +import { Options } from 'html-minifier'; + +const defaultMinifyOptions: Options = { + caseSensitive: true, + removeComments: true, + collapseWhitespace: true, + collapseBooleanAttributes: true, + removeRedundantAttributes: true, + useShortDoctype: true, + removeEmptyAttributes: true, + minifyCSS: true, + minifyJS: true, + removeScriptTypeAttributes: true, + removeStyleLinkTypeAttributes: true, + // don't remove attribute quotes, not all social media platforms can parse this over-optimization + removeAttributeQuotes: false, + // don't remove optional tags, like the head, not all social media platforms can parse this over-optimization + removeOptionalTags: false, + // scully specific HTML comments + // this will always be added in the final minifyOptions config + ignoreCustomComments: [/scullyContent-(begin|end)/], + // scully specific data injection + // this will always be added in the final minifyOptions config + ignoreCustomFragments: [/\/\*\* ___SCULLY_STATE_(START|END)___ \*\//], +}; +``` + +Configuring the options can be done via the `setPluginConfig` function. +You can specifiy a subset of the minification options that will override the default configuration. + +```javascript +const { RouteTypes, setPluginConfig } = require('@scullyio/scully'); +const { MinifyHtml, MinifyHtmlOptions } = require('scully-plugin-minify-html'); + +const postRenderers = [MinifyHtml]; + +const minifyHtmlOptions: MinifyHtmlOptions = { + minifyOptions: { + removeComments: false, + }, +}; +setPluginConfig(MinifyHtml, 'render', minifyHtmlOptions); +// or +// setPluginConfig(MinifyHtml, minifyHtmlOptions); + +exports.config = { + projectRoot: './src/app', + defaultPostRenderers: postRenderers, + routes: { + '/blog/:slug': { + type: RouteTypes.contentFolder, + slug: { + folder: './blog', + }, + postRenderers: postRenderers, + }, + }, +}; +``` diff --git a/docs/learn/plugins/community-plugins/regex.md b/docs/learn/plugins/community-plugins/regex.md new file mode 100644 index 000000000..706210e78 --- /dev/null +++ b/docs/learn/plugins/community-plugins/regex.md @@ -0,0 +1,97 @@ +--- +title: regex Plugin +published: true +lang: en +navlist_textFormat_none: true +--- + +# `regex` Plugin + + + +
      + +- [Overview](#overview) +- [Installation](#installation) +- [Usage](#usage) +- [Questions or Issues](#questions-or-issues) + +## Overview + +This `postRenderer` plugin for Scully will apply the configured regex replacements to your Scully rendered HTML. + +_Version 2.0.0 introduces breaking changes in the way the plugin is configured. It allows for a bit of decoupling from the main ScullyConfig_ + +## Installation + +To install this library with npm run: + +``` +$ npm install @gammastream/scully-plugin-regex --save-dev +``` + +## Usage + +Add the plugin to the defaultPostRenderers to execute it on all rendered pages: + +```typescript +import { ScullyConfig, setPluginConfig } from '@scullyio/scully'; +import { getRegexPlugin } from '@gammastream/scully-plugin-regex'; + +const RegexPlugin = getRegexPlugin(); +setPluginConfig(RegexPlugin, { + replacements: [ + { + from: 'foo', + to: 'foobar', + }, + { + from: new RegExp( + '([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+.[a-zA-Z0-9._-]+)', + 'gi' + ), + to: '$1', + }, + ], + routes: { + '/products/:productId': { + replacements: [ + { + from: 'foo', + to: 'foofoo', + }, + ], + }, + }, +}); + +export const config: ScullyConfig = { + projectRoot: './src', + projectName: 'scully-plugins', + outDir: './dist/static', + defaultPostRenderers: [RegexPlugin], + routes: { + '/products/:productId': { + type: 'json', + productId: { + url: 'http://localhost:4200/assets/products.json', + property: 'id', + }, + }, + }, +}; +``` + +Build app and run scully like normal. + +``` +npm run build +npm run scully +``` + +## Questions or Issues + +If you have any issues you can raise them here or contact me at: [GammaStream](https://gamma.stream/) diff --git a/docs/learn/plugins/community-plugins/rss.md b/docs/learn/plugins/community-plugins/rss.md new file mode 100644 index 000000000..0be3c3f27 --- /dev/null +++ b/docs/learn/plugins/community-plugins/rss.md @@ -0,0 +1,123 @@ +--- +title: RSS Plugin +published: true +lang: en +navlist_textFormat_none: true +--- + +# `rss` Plugin + + + +
      + +- [Overview](#overview) +- [Installation](#installation) +- [Usage](#usage) + +## Overview + +`scully-plugin-rss` is a `postRenderer` plugin for [Scully](http://scully.io/) adding creating a rss feed from your content using [feed](https://github.com/jpmonette/feed) and [showdown](https://github.com/showdownjs/showdown). + +The rss feed is available at: + +- your-domain.de/feed.json +- your-domain.de/feed.atom +- your-domain.de/feed.xml + +## Installation + +To install this plugin with `npm` run + +``` +$ npm install @notiz/scully-plugin-rss --save-dev +``` + +## Usage + +Add the plugin to the `defaultPostRenderers` in your `scully.config`: + +```js +require('@notiz/scully-plugin-rss'); + +exports.config = { + projectRoot: './src/app', + defaultPostRenderers: ['rss'], + routes: {}, +}; +``` + +If you want to use the plugin for a specific route do: + +```js +require('@notiz/scully-plugin-rss'); + +exports.config = { + ... + routes: { + '/blog/:slug': { + type: 'contentFolder', + slug: { + folder: './content/blog' + }, + postRenderers: ['rss'] + } + } + ... +}; +``` + +Create a `rss.config.json` in your root with the following properties: + +```json +{ + "title": "Your Title", + "description": "Page description", + "id": "https://your-domain.com", + "link": "https://your-domain.com", + "language": "en", + "image": "https://your-domain.com/featured.png", + "favicon": "https://you-domain.com/favicon.png", + "copyright": "2020 your-domain.com", + "generator": "Page description", + "feedLinks": { + "json": "https://your-domain.com/feed.json", + "atom": "https://your-domain.com/feed.atom" + }, + "outDir": "./dist/static", + "categories": ["Categories", "of", "your", "choice"] +} +``` + +Each RSS Feed item attributes are currently assigned by the following scully route attributes. + +| RSS Feed Item | Scully Route | +| ------------- | ---------------------------- | +| `title` | `title` | +| `id` | `slug` | +| `link` | Config Link + `slug` | +| `description` | `description` | +| `content` | `articleHTML` | +| `author` | `authors` | +| `contributor` | `authors` | +| `date` | `updatedAt` \| `publishedAt` | + +Your content should have the following frontmatter in your scully content: + +``` +--- +title: Martial Arts Training +description: Best Martial Arts Training +publishedAt: 2020-03-25T10:12:00.000Z +updatedAt: 2020-03-25T10:12:00.000Z +published: true +tags: + - training + - rss +authors: + - Bruce Lee +--- +``` diff --git a/docs/learn/plugins/community-plugins/sitemap.md b/docs/learn/plugins/community-plugins/sitemap.md new file mode 100644 index 000000000..71db0723d --- /dev/null +++ b/docs/learn/plugins/community-plugins/sitemap.md @@ -0,0 +1,117 @@ +--- +title: sitemap Plugin +published: true +lang: en +navlist_textFormat_none: true +--- + +# `sitemap` Plugin + + + +
      + +- [Overview](#overview) +- [Installation](#installation) +- [Usage](#usage) +- [Configuring Priority](#configuring-priority) +- [Notes](#notes) +- [Questions or Issues](#questions-or-issues) + +## Overview + +This `routeDiscoveryDone` plugin for Scully that will generate one or more sitemaps for your generated routes. + +_Version 1.0.0 introduces breaking changes as the plugin has been rewritten to take advantage of the new `routeDiscoveryDone` plugin type rather the old way of using a `render` plugin. This has the major benefit of only generating the sitemaps once per run – instead of after each page render._ + +## Installation + +To install this library with `npm` run: + +``` +$ npm install @gammastream/scully-plugin-sitemap --save-dev +``` + +## Usage + +Within your Scully config (typescript), get and configure the plugin like so: + +```typescript +import { ScullyConfig, setPluginConfig } from '@scullyio/scully'; +import { getSitemapPlugin } from '@gammastream/scully-plugin-sitemap'; + +const SitemapPlugin = getSitemapPlugin(); +setPluginConfig(SitemapPlugin, { + urlPrefix: 'https://gamma.stream', + sitemapFilename: 'sitemap.xml', + changeFreq: 'monthly', + priority: [ + '1.0', + '0.9', + '0.8', + '0.7', + '0.6', + '0.5', + '0.4', + '0.3', + '0.2', + '0.1', + '0.0', + ], + ignoredRoutes: ['/404'], + routes: { + '/products/:productId': { + changeFreq: 'daily', + priority: '0.9', + sitemapFilename: 'sitemap-products.xml', + }, + }, +}); + +export const config: ScullyConfig = { + projectRoot: './src', + projectName: 'scully-plugins', + outDir: './dist/static', + routes: { + '/products/:productId': { + type: 'json', + productId: { + url: 'http://localhost:4200/assets/products.json', + property: 'id', + }, + }, + }, +}; +``` + +Build app and run scully like normal. + +``` +npm run build +npm run scully +``` + +## Configuring Priority + +The priority of a route can be configured by setting the priority level based on the number of segments in a given route. + +```typescript +[ + '1.0', // `/` - [ '' ] (1 segment) + '0.9', // `/services` - [ '', 'services' ] (2 segments) + '0.8', // `/services/hosting` - [ '', 'services', 'hosting' ] + // etc... +]; +``` + +## Notes + +- Currently, the default priority (0.5) is assigned to all routes. Planned for a future update is the ability to assign a priority based on the number of segments in a route. (Completed in v0.0.4) +- Sitemap is regenerated with every route. At some time in the future, we expect Scully to support a class of plugins that run after it is finished generating all the routes. (Completed in v1.0.0) + +## Questions or Issues + +If you have any issues you can raise them here or contact me at: [GammaStream](https://gamma.stream/) diff --git a/docs/learn/plugins/community-plugins/toc.md b/docs/learn/plugins/community-plugins/toc.md new file mode 100644 index 000000000..9bd23c683 --- /dev/null +++ b/docs/learn/plugins/community-plugins/toc.md @@ -0,0 +1,83 @@ +--- +title: toc Table of Contents Plugin +published: true +lang: en +navlist_textFormat_none: true +--- + +# `toc` Plugin + + + +
      + +- [Overview](#overview) +- [Installation](#installation) +- [Usage](#usage) +- [Options](#options) + +## Overview + +This plugin for Scully provides a `postRenderer` to generate a **Table of Contents (TOC)** for the rendered route content. + +## Installation + +To install this library with npm run: + +``` +npm i scully-plugin-toc --save-dev +``` + +## Usage + +To use the plugin you should import it in your scully configuration file (`scully..config.ts`) and define it as a `postRenderer` for a route definition. You can configure the plugin by using the `toc` options: + +```typescript +import { ScullyConfig, setPluginConfig } from '@scullyio/scully'; +import { getTocPlugin, TocConfig } = from './scully-plugins/toc'; + +const tocOptions: TocConfig = { + blogAreaSelector: '.blog-content', + insertSelector: '#toc', + level: ['h2', 'h3'], +}; +const TocPlugin = getTocPlugin(); +setPluginConfig(TocPlugin, tocOptions); + +export const config: ScullyConfig = { + projectRoot: './src', + projectName: 'your-project-name', + outDir: './dist/static', + routes: { + '/blog/:slug': { + type: 'contentFolder', + postRenderers: ['toc'], + slug: { + folder: './blog', + }, + }, + }, +}; +``` + +The TOC is generated by analyzing the headings (`

      `, `

      `, etc.) generated by _Scully_. The above example configuration will look for a HTML element with the id `toc` and insert the TOC at this place generated for headings `

      ` and `

      `. + +```html +# my blog post + +
      +

      Table of contents

      +
      + +## heading 1 ### subheading 1 ## heading 2 ### subheading 2 +``` + +## Options + +You can configure the `scully-plugin-toc` by adding the `toc` options to your route configuration. The following table will explain the options in detail. + +- `blogAreaSelector`: This defines the area in which the scully-plugin-toc will search for headings. If you use for example `
      ` you should define `blogAreaSelector: ".blog"` to generate the TOC only from the blog content and not from the whole webpage. If the parameter is not set, the plugin will search for heading at the whole page. +- `insertSelector`: The selector defines the point where the `scully-plugin-toc` will inset the generated TOC. By default the plugin will use `#toc` as selector. It will skip the TOC generation when there is no selector match. In fact to insert the TOC in a blog post, you should at least add a `
      ` in your blog post and this is the place where the TOC will be inserted. +- `level`: This option defines the heading levels to include in the TOC. By default the value `level: ['h2', 'h3']` is used. Only valid HTML headings are supported (`h1`, `h2`, `h3`, `h4`, `h5` and `h6`). diff --git a/docs/learn/plugins/overview.md b/docs/learn/plugins/overview.md new file mode 100644 index 000000000..c01611fc5 --- /dev/null +++ b/docs/learn/plugins/overview.md @@ -0,0 +1,51 @@ +--- +title: plugins +published: true +lang: en +navlist_position: 1 +navlist_parentIndex: true +--- + +# Plugins + +## Overview + +Scully uses a plugin system which allows users to define new ways for Scully to pre-render an application. +It is simple to [register a new plugin](/docs/learn/plugins/register-a-new-plugin). + +## Types + +There are five main types of plugins which allow code to be injected into various stages of the Scully process lifecycle: + +
      + +- [`router`](#router) +- [`render`](#render) +- [`fileHandler`](#filehandler) +- [`routeDiscoveryDone`](#routediscoverydone) +- [`allDone`](#alldone) + +#### [`router`](/docs/learn/plugins/types/router) + +`router` plugins teach Scully how to get the required data to be pre-render pages from the route-params. + +#### [`render`](/docs/learn/plugins/types/render) + +`render` plugins are used to transform the rendered HTML. +After the Angular application renders, the HTML content is passed to a `render` plugin where it can be further modified. + +#### [`fileHandler`](/docs/learn/plugins/types/file-handler) + +`fileHandler` plugins are used by the [`contentFolder`](/docs/learn/plugins/built-in-plugins/contentFolder) plugin during the render process. The [`contentFolder`](/docs/learn/plugins/built-in-plugins/contentFolder) plugin processes the folders for markdown files or other file type the folders may contain. The render process processes any existing `fileHandler` plugin for any file extension type. + +#### [`routeDiscoveryDone`](/docs/learn/plugins/types/routeDiscoveryDone) + +`routeDiscoveryDone` plugins are called automatically after all routes have been collected and all router plugins have finished. + +#### [`allDone`](/docs/learn/plugins/types/allDone) + +`allDone` plugins are like `routeDiscoveryDone` plugins, except they are called _after_ Scully finishes executing all its processes. + + diff --git a/docs/learn/plugins/register-a-new-plugin.md b/docs/learn/plugins/register-a-new-plugin.md new file mode 100644 index 000000000..6b9c47374 --- /dev/null +++ b/docs/learn/plugins/register-a-new-plugin.md @@ -0,0 +1,81 @@ +--- +title: Register a new plugin +published: true +lang: en +navlist_position: 10 +--- + +# Register a new plugin + + + +## Overview + +The [`registerPlugin`](https://github.com/scullyio/scully/blob/main/libs/scully-schematics/src/add-plugin/index.ts) function adds a new plugin to Scully. This function has 5 parameters: + +
      + +- [`type:` _`string`_](#type-string) +- [`name:` _`string`_](#name-string) +- [`plugin:` _`any`_](#plugin-any) +- [`validator?:` _`function`_ `(optional)`](#validator-function-optional) +- [`options?:` _`<..>`_ `(optional)`](#options--optional) + +#### `type:` _`string`_ + +- Indicates the plugin's type. +- The existing types are: `router`, `render`, `fileHandler`, `allDone`, or `routeDiscoveryDone`. + +#### `name:` _`string`_ + +- The plugin's name. +- This must be unique for the type of plugin. +- To replace an existing plugin, set the `replaceExistingPlugin` option. + +#### `plugin:` _`any`_ + +- The plugin's function. +- Contains the plugin's logic. +- Plugin types are described in their own type descriptions + +#### `validator?:` _`function`_ `(optional)` + +- A validation function. +- It should return an array of errors. +- If there are no errors, it should return a `false` value. +- If it returns a `string`, those strings are displayed as errors, and the process is aborted. + +**Tip:** Add color to the validator errors by using the colors exported from Scully. +**Validator Example:** + +```typescript +import { yellow } from '@scullyio/scully'; + +// Omitted code ... + +const validator = async (options) => { + const errors = []; + + if (options.numberOfPages && typeof options.numberOfPages !== 'number') { + errors.push( + `my-custom-plugin numberOfPages should be a number, not a ${yellow( + typeof options.numberOfPages + )}` + ); + } + + return errors; +}; +``` + +#### `options?:` _`<..>`_ `(optional)` + +The `options` object can be used to set the plugin options. +At the moment, the only available option is `replaceExistingPlugin`. + + diff --git a/docs/learn/plugins/types/allDone.md b/docs/learn/plugins/types/allDone.md new file mode 100644 index 000000000..4ba74ecda --- /dev/null +++ b/docs/learn/plugins/types/allDone.md @@ -0,0 +1,13 @@ +--- +title: allDone Plugin Type +published: true +lang: en +navlist_position: 5 +navlist_textFormat_none: true +--- + +# `allDone` Plugin Type + +## Overview + +An `allDone` plugin is like a [`routeDiscoveryDone`](/docs/learn/plugins/types/routeDiscoveryDone) plugin, except it is called _after_ Scully finishes executing all its processes. diff --git a/docs/learn/plugins/types/fileHandler.md b/docs/learn/plugins/types/fileHandler.md new file mode 100644 index 000000000..34630934b --- /dev/null +++ b/docs/learn/plugins/types/fileHandler.md @@ -0,0 +1,62 @@ +--- +title: fileHandler Plugin Type +published: true +lang: en +navlist_position: 3 +navlist_textFormat_none: true +--- + +# `fileHandler` Plugin Type + +
      + +- [Overview](#overview) +- [Usage](#usage) +- [Interface](#interface) +- [Making A `fileHandler` Plugin](#making-a-filehandler-plugin) +- [Examples](#examples) + +## Overview + +A **`fileHandler` plugin** is used by the `contentFolder` plugin during the `render` process. The `contentFolder` +plugin processes the folders for markdown files or other file type the folders may contain. The `render` processes any existing `fileHandler` plugin for any file extension type. + +## Usage + +Scully comes with two built-in `fileHandler` plugins. The [markdown plugin](/docs/learn/plugins/built-in-plugins/md) and +the [asciidoc plugin](/docs/learn/plugins/built-in-plugins/adoc). These plugins handle and process the +content of those file types as they are read from the file system. + +If you want to support `.docx` files, or `.csv` files, or any other file type; a file handler for those file types need to be added. +The `contentFolder` plugin takes care of reading those files from the filesystem. However, if the files need to be transformed after the `contentFolder` plugin reads them; +A `fileHandler` plugin is required. + +## Interface + +A **`fileHandler` plugin** is a function that returns a `Promise`. The interface looks like follows: + +```typescript +function exampleFileHandlerPlugin(rawContent: string): Promise { + // Must return a promise +} +``` + +## Making A `fileHandler` Plugin + +The following **`fileHandler` plugin** example handles `.cvs` files by wrapping them into a code block. You could write a much more elaborate plugin that creates a table or a grid for the data. + +```typescript +function csvFilePlugin(raw) { + return Promise.resolve(`
      ${code}
      `); +} +// DO NOT FORGET TO REGISTER THE PLUGIN +registerPlugin('fileHandler', 'csv', { handler: csvFilePlugin }); +module.exports.csvFilePlugin = csvFilePlugin; +``` + +## Examples + +Here are some links to built-in **render plugins** in Scully: + +- [asciidoc plugin](/docs/learn/plugins/built-in-plugins/adoc) +- [markdown plugin](/docs/learn/plugins/built-in-plugins/md) diff --git a/docs/learn/plugins/types/overview-.md b/docs/learn/plugins/types/overview-.md new file mode 100644 index 000000000..50d66ad21 --- /dev/null +++ b/docs/learn/plugins/types/overview-.md @@ -0,0 +1,48 @@ +--- +title: Plugin types +published: true +lang: en +navlist_parentIndex: true +navlist_parentPosition: 3 +navlist_excludeSelf: true +--- + +# Plugin types + +## Overview + +Scully uses a plugin system which allows users to define new ways for Scully to pre-render an application. +There are five main types of plugins which allow code to be injected into various stages of the Scully process lifecycle: + +
      + +- [`router`](#router) +- [`render`](#render) +- [`fileHandler`](#filehandler) +- [`routeDiscoveryDone`](#routediscoverydone) +- [`allDone`](#alldone) + +#### [`router`](/docs/learn/plugins/types/router) + +`router` plugins teach Scully how to get the required data to be pre-render pages from the route-params. + +#### [`render`](/docs/learn/plugins/types/render) + +`render` plugins are used to transform the rendered HTML. +After the Angular application renders, the HTML content is passed to a `render` plugin where it can be further modified. + +#### [`fileHandler`](/docs/learn/plugins/types/file-handler) + +`fileHandler` plugins are used by the [`contentFolder`](/docs/learn/plugins/built-in-plugins/contentFolder) plugin during the render process. The [`contentFolder`](/docs/learn/plugins/built-in-plugins/contentFolder) plugin processes the folders for markdown files or other file type the folders may contain. The render process processes any existing `fileHandler` plugin for any file extension type. + +#### [`routeDiscoveryDone`](/docs/learn/plugins/types/routeDiscoveryDone) + +`routeDiscoveryDone` plugins are called automatically after all routes have been collected and all router plugins have finished. + +#### [`allDone`](/docs/learn/plugins/types/allDone) + +`allDone` plugins are like `routeDiscoveryDone` plugins, except they are called _after_ Scully finishes executing all its processes. + + diff --git a/docs/learn/plugins/types/render.md b/docs/learn/plugins/types/render.md new file mode 100644 index 000000000..90fe0150f --- /dev/null +++ b/docs/learn/plugins/types/render.md @@ -0,0 +1,78 @@ +--- +title: render Plugin Type +published: true +lang: en +navlist_position: 2 +navlist_textFormat_none: true +--- + +# `render` Plugin Type + +
      + +- [Overview](#overview) +- [Interface](#interface) +- [Making A `render` Plugin](#making-a-render-plugin) + +## Overview + +A **render plugin** is used to transform the rendered HTML. +After the Angular application renders, the HTML content is passed to a **render plugin** where it can be further modified. + +A **render plugin** could be used to transform a page containing markdown into a page that renders it. + +## Interface + +A **`render` plugin** is a function that returns a `Promise`. The string in the promise must be the transformed +HTML. The interface looks like this: + +```typescript +function exampleContentPlugin( + HTML: string, + route: HandledRoute +): Promise { + // Must return a promise +} +``` + +## Making A `render` Plugin + +The following **`render` plugin** example adds a title to the header to a page if it does not find one. + +```typescript +const { registerPlugin } = require('@scullyio/scully'); + +function defaultTitlePlugin(html, route) { + // If no title in the document + if (html.indexOf('The Truth Is Out There!`; + return Promise.resolve(`${begin}${defaultTitle}${splitter}${end}`); + } + return Promise.resolve(html); +} + +// DON NOT FORGET REGISTER THE PLUGIN +const validator = async (conf) => []; +registerPlugin('render', 'defaultTitle', defaultTitlePlugin, validator); + +module.exports.defaultTitlePlugin = defaultTitlePlugin; +``` + +In the above example, the Angular app's HTML content is transformed to include a title because anyone was found. + +The next example replaces any instances of `:)` with an smiley emoji. + +```typescript +const { registerPlugin } = require('@scullyio/scully'); + +function smileEmojiPlugin(html, route) { + return Promise.resolve(html.replace(/\:\)/g, '😊')); +} +// DON NOT FORGET REGISTER THE PLUGIN +const validator = async (conf) => []; +registerPlugin('render', 'smiles', smileEmojiPlugin, validator); + +module.exports.smileEmojiPlugin = smileEmojiPlugin; +``` diff --git a/docs/learn/plugins/types/routeDiscoveryDone.md b/docs/learn/plugins/types/routeDiscoveryDone.md new file mode 100644 index 000000000..b4722d427 --- /dev/null +++ b/docs/learn/plugins/types/routeDiscoveryDone.md @@ -0,0 +1,15 @@ +--- +title: routeDiscoveryDone Plugin Type +published: true +lang: en +navlist_textFormat_none: true +navlist_position: 4 +--- + +# `routeDiscoveryDone` Plugin Type + +## Overview + +This type of plugin is called automatically after all routes have been collected, and all router plugins have finished. + +It receives a shallow copy of the `handledRoute` array, and returns `void`. diff --git a/docs/learn/plugins/types/router.md b/docs/learn/plugins/types/router.md new file mode 100644 index 000000000..4a810093e --- /dev/null +++ b/docs/learn/plugins/types/router.md @@ -0,0 +1,224 @@ +--- +title: router Plugin Type +published: true +lang: en +navlist_position: 1 +navlist_textFormat_none: true +--- + +# `router` Plugin Type + +
      + +- [Overview](#overview) +- [Usage](#usage) +- [Making a `router` Plugin](#making-a-router-plugin) +- [Configuring a `router` Plugin](#configuring-a-router-plugin) +- [Interfaces](#interfaces) + - [`HandledRoute` Interface](#handledroute-interface) + - [`route: string`](#route-string) + - [`type: RoutesTypes`](#type-routestypes) + - [`defaultPostRenderers?: string[]`](#defaultpostrenderers-string) + - [`postRenderers?: string[]`](#postrenderers-string) + - [`templateFile?: string`](#templatefile-string) + - [`data?: RouteData`](#data-routedata) + - [Router Plugin Interface](#router-plugin-interface) + +## Overview + +Any route in the application that contains a router-parameter must be configured in a **router plugin**. The plugin teaches Scully how to get the required data to be pre-render in the web-pages from the route-params. + +## Usage + +Suppose the application has a route like this one: `{path: 'user/:userId', component: UserComponent}`. In order for Scully to pre-render the website, it needs to know the complete list of User IDs that will be used in that route parameter `:userId`. If the app had 5 users with the IDs 1, 2, 3, 4, and 5; Scully would need to render the following routes: + +``` +/user/1 +/user/2 +/user/3 +/user/4 +/user/5 +``` + +A **`router` plugin** is used to convert the raw route-config into a list of routes that Scully can then crawl/render. + +## Making a `router` Plugin + +Lets implement a **`router` plugin** that turns the raw route into five distinct `HandledRoutes` from an application containing the following route: `/user/:userId`. + +```javascript +const { registerPlugin } = require('@scullyio/scully'); + +function userIdPlugin(route: string, config = {}): Promise { + return Promise.resolve([ + { route: '/user/1' }, + { route: '/user/2' }, + { route: '/user/3' }, + { route: '/user/4' }, + { route: '/user/5' }, + ]); +} + +registerPlugin('router', 'userIds', userIdPlugin, validator); +``` + +After implementing the plugin, configure the `scully.config.ts` in order to use it. + +## Configuring a `router` Plugin + +The following configuration uses the `userIds` router plugin to get the `HandledRoute[]` for the above implementation: + +```typescript +// scully.config.ts +import './myPlugins/userIdPlugin'; +exports.config = { + // Add the following to your file + routes: { + '/user/:userId': { + type: 'userIds', + }, + }, +}; +``` + +## Interfaces + +### `HandledRoute` Interface + +```typescript +interface RouteConfig { + /** this route does a manual Idle check */ + manualIdleCheck?: boolean; + /** type of the route */ + type?: string; + /** + * an optional function that will be executed on render. + * Receives the route string, and the config of this route. + */ + preRenderer?: (route?: string, config?: RouteConfig) => Promise; + /** Allow in every other setting possible, depends on plugins */ + [key: string]: any; +} + +export interface HandledRoute { + /** the _complete_ route */ + route: string; + /** String, must be an existing plugin name */ + type: string; + /** the relevant part of the scully-config */ + config?: RouteConfig; + /** variables exposed to angular _while rendering only!_ */ + exposeToPage?: { + manualIdle?: boolean; + transferState?: Serializable; + [key: string]: Serializable; + }; + /** data will be injected into the static page */ + injectToPage?: { + [key: string]: Serializable; + }; + /** an array with render plugin names that will be executed */ + postRenderers?: string[]; + /** the path to the file for a content file */ + templateFile?: string; + /** + * additional data that will end up in scully.routes.json + * the frontMatter data will be added here too. + */ + data?: RouteData; +} +``` + +The `HandledRoute` interface provides the needed properties to develop your own plugin. + +#### `route: string` + +An application route to be handled by Scully. +This is the _fully qualified_ route info. That means there should be no variables left in there. +`#` are not allowed, and query parameters are ignored. + +#### `type: RoutesTypes` + +Indicates the type of plugin. Contains the name of the routing plugin that should handle this. + +This is a mandatory field that _must_ be provided. When the type doesn't exist, Scully will terminate, as it doesn't know what to do. + +#### `defaultPostRenderers?: string[]` + +Array with string ID's of the content-renderers that will be run on all routes. + +#### `postRenderers?: string[]` + +Array of plugin names to be executed after the initial page render. + +Each of the plugins in this array will be rendered in the order they appear, and they will receive the output HTML from the previous plugin. + +Moreover, this array _replaces_ the `defaultPostRenderers` array. + +```typescript +const defaultPostRenderers = ['seoHrefOptimise']; +const sampleConf: ScullyConfig = { + defaultPostRenderers, + routes: { + /** gets the default postrenderes */ + normalRoute: { + type: 'default', + }, + /** adds to the default postrenderes */ + someRoute: { + type: 'default', + postRenderers: [...defaultPostRenderers, 'myAddition'], + }, + /** removes the default postrenderes */ + someOtherRoute: { + type: 'default', + postRenderers: ['unique'], + }, + }, +}; +``` + +The `defaultPostRenderers` and `postRenderers` are designed this way in order to allow you to dispose of the default renderers. Moreover, the current design is versatile, flexible, and it makes it easy to opt-out. + +Do not forget to add the `defaultPostRenderers`! + +#### `templateFile?: string` + +The file's name containing the template to be rendered. **Unrelated to the Angular template!** + +This property is specific to `contentFolder`. It contains the full path to the file that should be used to generate the content. + +Remember that content will be inserted _after_ the initial rendering. + +#### `data?: RouteData` + +The data added to this property will be added to the routes data in `scully.routes.json` +This data will also be extended in `contentFolder` routes with the front-matter data out of the start of the templateFile. + +```typescript +export interface RouteData { + title?: string; + author?: string; + published?: boolean; + [prop: string]: any; +} +``` + +### Router Plugin Interface + +A **router plugin** is a function that returns a `Promise`. + +The `HandledRoute` interface is described above. It receives a string with the unhandled route, and the config for that specific route. + +A router plugin function should be as follows: + +```typescript +function exampleRouterPlugin( + route: string, + config: any +): Promise { + // Must return a promise +} +``` + +The `HandledRoute[]` gets it data added into the `scully-routes.json` file generated by the `npm run scully` command. diff --git a/docs/learn/schematics/create-blog-config.md b/docs/learn/schematics/create-blog-config.md new file mode 100644 index 000000000..5503bee13 --- /dev/null +++ b/docs/learn/schematics/create-blog-config.md @@ -0,0 +1,8 @@ +--- +title: create blog config +published: true +lang: en +navlist_position: 10 +--- + +# create blog config diff --git a/docs/learn/schematics/create-markdown-files-and-skeleton.md b/docs/learn/schematics/create-markdown-files-and-skeleton.md new file mode 100644 index 000000000..05cb7c36c --- /dev/null +++ b/docs/learn/schematics/create-markdown-files-and-skeleton.md @@ -0,0 +1,8 @@ +--- +title: create markdown files and skeleton +published: true +lang: en +navlist_position: 20 +--- + +# create markdown files and skeleton diff --git a/docs/learn/schematics/create-plugin-skeleton.md b/docs/learn/schematics/create-plugin-skeleton.md new file mode 100644 index 000000000..1ba24eab0 --- /dev/null +++ b/docs/learn/schematics/create-plugin-skeleton.md @@ -0,0 +1,8 @@ +--- +title: introduction +published: true +lang: en +navlist_position: 30 +--- + +# introduction diff --git a/docs/learn/schematics/create-scully-files-with-ng-add.md b/docs/learn/schematics/create-scully-files-with-ng-add.md new file mode 100644 index 000000000..d73b1f96f --- /dev/null +++ b/docs/learn/schematics/create-scully-files-with-ng-add.md @@ -0,0 +1,8 @@ +--- +title: create scully files with ng add +published: true +lang: en +navlist_position: 1 +--- + +# create scully files with ng add diff --git a/docs/learn/schematics/run-router-discovery.md b/docs/learn/schematics/run-router-discovery.md new file mode 100644 index 000000000..10eb38fbc --- /dev/null +++ b/docs/learn/schematics/run-router-discovery.md @@ -0,0 +1,8 @@ +--- +title: run router discovery +published: true +lang: en +navlist_position: 40 +--- + +# run router discovery diff --git a/docs/learn/utilities/github-actions/scully-publish.md b/docs/learn/utilities/github-actions/scully-publish.md new file mode 100644 index 000000000..0614335d5 --- /dev/null +++ b/docs/learn/utilities/github-actions/scully-publish.md @@ -0,0 +1,11 @@ +--- +title: Scully Publish Github Action +published: true +lang: en +--- + +# Scully Publish Github Action + +## Overview + +The Github Action [Scully Publish](https://github.com/marketplace/actions/scully-publish) lets you easily build and deploy your Scully site to [GitHub Pages](https://pages.github.com/). diff --git a/docs/learn/utilities/overview---.md b/docs/learn/utilities/overview---.md new file mode 100644 index 000000000..28f1e1ab6 --- /dev/null +++ b/docs/learn/utilities/overview---.md @@ -0,0 +1,18 @@ +--- +title: Utilities +published: true +lang: en +navlist_parentIndex: true +navlist_excludeSelf: true +--- + +# Utilities + +## Overview + +Scully works well in combination with other tools and utilities: + +- Github Actions: + - [Scully Publish](/docs/learn/utilities/github-actions/scully-publish) +- Syntax Highlighting: + - [PrismJS](/docs/learn/utilities/syntax-highlighting/prism-js) diff --git a/docs/util.md b/docs/learn/utilities/syntax-highlighting/prism-js.md similarity index 73% rename from docs/util.md rename to docs/learn/utilities/syntax-highlighting/prism-js.md index 03549bd37..03b80729e 100644 --- a/docs/util.md +++ b/docs/learn/utilities/syntax-highlighting/prism-js.md @@ -1,30 +1,30 @@ --- -title: Utilities -order: 8900 +title: Syntax Highlighting using PrismJS +published: true lang: en --- -# Utilities +# Syntax Highlighting with PrismJS -Scully works well in combination with other tools and utilities, for example: +
      -- [Utilities](#utilities) - - [Github Action: Scully Publish](#github-action-scully-publish) - - [Syntax Highlighting Using Prismjs](#syntax-highlighting-using-prismjs) +- [Overview](#overview) +- [How Scully Handles Code Blocks](#how-scully-handles-code-blocks) +- [Usage](#usage) -## Github Action: Scully Publish +## Overview -The Github Action [Scully Publish](https://github.com/marketplace/actions/scully-publish) let you easily build and deploy your Scully site to GitHub Pages. - -## Syntax Highlighting Using Prismjs - -Prism is a lightweight, extensible syntax highlighter that can be used when working with code blocks in markdown files in blog posts. +[Prism](https://prismjs.com/) is a lightweight, extensible syntax highlighter that can be used when working with code blocks in markdown files in blog posts. It is possible to define a language for the code to be used in the Scully code like this: -
      ```ts
      +
      
      +```typescript
       const foo = 'bar';
      -```
      +``` +
      + +## How Scully Handles Code Blocks Scully parses the markdown using [_marked_](https://www.npmjs.com/package/marked), and the parsed result looks like this: @@ -32,13 +32,15 @@ Scully parses the markdown using [_marked_](https://www.npmjs.com/package/marked const foo = - 'bar'; + 'bar' + ; ``` _marked_ uses the CSS class prefix `language-` to tag the code block with an appropriate language. +## Usage + To highlight the code blocks use [_prismjs_](https://prismjs.com) and create a service like this: ```bash @@ -48,7 +50,7 @@ ng g s highlight The service will include all languages needed. The code looks like this: -```ts +```typescript import { Injectable, Inject } from '@angular/core'; import { PLATFORM_ID } from '@angular/core'; @@ -68,7 +70,7 @@ import 'prismjs/components/prism-typescript'; declare var Prism: any; -@Injectable() +@Injectable({ providedIn: 'root' }) export class HighlightService { constructor(@Inject(PLATFORM_ID) private platformId: Object) {} @@ -80,9 +82,9 @@ export class HighlightService { } ``` -Now, it needs to inject the service in the `BlogComponent` that was generated by scully: +Now, it needs to inject the service in the `BlogComponent` that was generated by Scully: -```ts +```typescript import {/* ... */, AfterViewChecked} from '@angular/core'; import {HighlightService} from '../highlight.service'; /* ... */ diff --git a/docs/plugin/contentFolderPlugin.md b/docs/plugin/contentFolderPlugin.md deleted file mode 100644 index 31e1757db..000000000 --- a/docs/plugin/contentFolderPlugin.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: Plugins - contentFolder -order: 710 -lang: en ---- - -# contentFolder Plugin - -The contentFolder plugin exists out from a route plugin and from render plugin. - -## contentFolder Route plugin - -The route plugin takes a config in the form of: - -```typescript -const contentFolderconfig = { - routes: { - '/blog/:slug': { - type: 'contentFolder', - slug: { - folder: './tests/assets/blog-files' - } - } - } -}; -``` - -The config takes and handles only one parameter, called `folder` which is mandatory. It is a file's location relative to the project root. - -Scully traverses this folder, and its subfolders in order to make a `HandledRoute` for each file-extension known in there. -`.md`(markdown) and '`adoc` (asciiDoc) are known out of the box. That route has a `templateFile` property with the full path to the file. The route reflects the folder structure. -Furthermore, it parses out the date in the front-matter part, and it is added to the handledRoutes `data` property. - -## contentFolder Render Plugin. - -This plugin takes the pre-rendered HTML and a `HandlerRoute` in order to read the file indicated by the `templateFile` property. -It extracts the Angular `_ngcontent` id. It looks for the file's extension in the fileHandler plugins, and it uses this plugin to convert the raw content into HTML. -Finally, it adds the `_ngcontent` id to the generated HTML, so that components' style works as expected. - -This plugin finds the `` tag, and it injects the HTML as its previous sibling(s). diff --git a/docs/plugin/contentFolderPlugin_es.md b/docs/plugin/contentFolderPlugin_es.md deleted file mode 100644 index a9f1e46e9..000000000 --- a/docs/plugin/contentFolderPlugin_es.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: Plugins - contentFolder -order: 710 -lang: es ---- - -# contentFolder Plugin - -El plugin contentFolder permite salirse de un route plugin y/o de un render plugin. - -## contentFolder Route plugin - -El route plugin toma una configuración de la siguiente forma: - -```typescript -const contentFolderconfig = { - routes: { - '/blog/:slug': { - type: 'contentFolder', - slug: { - folder: './tests/assets/blog-files' - } - } - } -}; -``` - -La configuración recibe solamente un parámetro, llamado `folder` que és obligatorio. Es la ubicación relativa de un archivo con respecto a la raiz del proyecto. - -Scully recorre el folder y sus subfolders para crear un `HandledRoute` para cada file-extension conocida en el folder. -`.md`(markdown) y '`adoc` (asciiDoc) son soportados de manera automática. Esa ruta tiene una propiedad temporal llamada `templateFile` con el "path" completo del archivo. La ruta refleja la estructura del folder. -Además, hace el parse de la fecha en la parte front-matter y se agrega a la propiedad `data` de `handledRoutes`. - -## contentFolder Render Plugin. - -Este plugin toma el contenido estático en HTML y una `HandlerRoute` para leer los archivos indicados por la propiedad `templateFile`. -Extrae el id `_ngcontent` de Angular. Busca la extensión del archivo en los plugins `fileHandler` y el mismo para convertir el contenido en HTML. -Finalmente, agrega el id `_ngcontent` al HTML generado para que el estilo de los componentes de manera correcta. - -Este plugin busca el `` e inyecta el HTML a la altura de sus tags hermano(s). diff --git a/docs/plugin/ingoredPlugin.md b/docs/plugin/ingoredPlugin.md deleted file mode 100644 index aec73fcd6..000000000 --- a/docs/plugin/ingoredPlugin.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: Plugins - IgnoredPlugin -order: 720 -lang: en ---- - -# Ignored Plugin diff --git a/docs/plugin/ingoredPlugin_es.md b/docs/plugin/ingoredPlugin_es.md deleted file mode 100644 index ae8fdfabc..000000000 --- a/docs/plugin/ingoredPlugin_es.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: Plugins - IgnoredPlugin -order: 720 -lang: es ---- - -# Ignored Plugin diff --git a/docs/plugin/jsonPlugin_es.md b/docs/plugin/jsonPlugin_es.md deleted file mode 100644 index 96230be34..000000000 --- a/docs/plugin/jsonPlugin_es.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -title: Plugins - JSON Plugin -order: 730 -lang: es ---- - -# JSON Plugin - -El plugin JSON obtiene datos del endpoint de una API durante el descubrimiento de rutas. - -El siguiente ejemplo usa [jsonplaceholder](http://localhost:8200/) para obtener la lista de -IDs de usuario para la aplicación y usa el [Scully JSON Plugin](../scully/routerPlugins/jsonRoutePlugin.ts). - -```typescript -// scully.config.ts -export const config: ScullyConfig = { - // Agruegue lo siguiente a su archivo - routes: { - '/user/:userId': { - type: 'json', - userId: { - url: 'http://localhost:8200/users', - property: 'id' - } - } - } -}; -``` - -El ejemplo anterior le indica a Scully que use el `json plugin` para traer los datos JSON via HTTP cada vez que encuentre una ruta con esta forma `/user/:userId`. -Los valores de `userId` contienen dos pedazos de información. Primero, la url a la que el plugin JSON debe ir para poder obtener los datos JSON requeridos. -Segundo, la propiedad `id`. - -El plugin JSON plugin toma el nombre de la propiedad de cada handledRoute en el arreglo `HandledRoute[]`. En otras palabras, -el arreglo de datos que regresa la API`jsonplaceholder`, cada uno contiene una propiedad `id`. Por lo tanto, regresa la lista de `userIds`. - -Este plugin tambien acepta cualquier encabezado (header) necesario para hacer una petición a una API. - -##### Ejemplo: - -```typescript -// scully.config.ts -export const config: ScullyConfig = { - routes: { - '/todos/:todoId': { - type: 'json', - todoId: { - url: 'https://my-api.com/todos', - property: 'id', - headers: { - 'API-KEY': '0123456789' - } - } - } - } -}; -``` diff --git a/docs/plugins.md b/docs/plugins.md deleted file mode 100644 index 725c5b47c..000000000 --- a/docs/plugins.md +++ /dev/null @@ -1,373 +0,0 @@ ---- -title: Plugins -order: 700 -lang: en ---- - -# Plugins - -Scully uses a plugin system that allows users to define new ways for Scully to pre-render an application. There are five main -types of plugins: - -1. [Router Plugin](#router-plugin) -2. [Render Plugin](#render-plugin) -3. [File Handler Plugin](#file-handler-plugin) -4. [routeDiscoveryDone plugin](#routediscoverydone-plugin) -5. [allDone plugin](#alldone-plugin) - -You can find a list of available plugins in the [recommended plugins](recommended-plugins.md) documentation. - ---- - -## Registering a Plugin - -The `registerPlugin` function adds a new plugin to Scully. This function has 5 parameters: - -- type -- name -- plugin -- validator (optional) -- options (optional) - -### type: string - -`type` - Indicates the plugin's type. The existing types are: `router`, `render`, `fileHandler`, `allDone`, or `routeDiscoveryDone`. - -### name: string - -`name` - The plugin's name. This must be unique for the type of plugin. To replace an existing plugin, set the `replaceExistingPlugin` option. - -### plugin: any - -`plugin` - The plugin's function. It contains the plugin's logic. The plugin types are described in their own type descriptions - -### validator: function (optional) - -`validator` - A validation function. It should return an array of errors. if there are no errors, it should return a `false` value. If it returns a `string`, those strings are displayed as errors, and the process is aborted. - -> Tip: Add color to the validator errors by using the colors exported from Scully. - -##### Validator Example - -```typescript -import { yellow } from '@scullyio/scully'; - -// Omitted code ... - -const validator = async options => { - const errors = []; - - if (options.numberOfPages && typeof options.numberOfPages !== 'number') { - errors.push( - `my-custom-plugin numberOfPages should be a number, not a ${yellow( - typeof options.numberOfPages - )}` - ); - } - - return errors; -}; -``` - -### Options - -The `optinal` object can be used to set the plugin options. At the moment, the only available option is `replaceExistingPlugin`. - -## Router Plugin - -Any route in the application that contains a router-parameter must be configured in a **router plugin**. The plugin teaches Scully how to get the required data to be pre-render in the web-pages from the route-params. - -Suppose the application has a route like this one: `{path: 'user/:userId', component: UserComponent}`. In order for Scully to pre-render the website, it needs to know the complete list of User IDs that will be used in that route parameter `:userId`. If the app had 5 users with the IDs 1, 2, 3, 4, and 5; Scully would need to render the following routes: - -``` -/user/1 -/user/2 -/user/3 -/user/4 -/user/5 -``` - -A **router plugin** is used to convert the raw route-config into a list of routes that Scully can then crawl/render. - -### `HandledRoute` interface - -```typescript -interface RouteConfig { - /** this route does a manual Idle check */ - manualIdleCheck?: boolean; - /** type of the route */ - type?: string; - /** - * an optional function that will be executed on render. - * Receives the route string, and the config of this route. - */ - preRenderer?: (route: HandledRoute) => Promise; - /** Allow in every other setting possible, depends on plugins */ - [key: string]: any; -} - -export interface HandledRoute { - /** the _complete_ route */ - route: string; - /** String, must be an existing plugin name */ - type: string; - /** the relevant part of the scully-config */ - config?: RouteConfig; - /** variables exposed to angular _while rendering only!_ */ - exposeToPage?: { - manualIdle?: boolean; - transferState?: Serializable; - [key: string]: Serializable; - }; - /** data will be injected into the static page */ - injectToPage?: { - [key: string]: Serializable; - }; - /** an array with render plugin names that will be executed */ - postRenderers?: string[]; - /** the path to the file for a content file */ - templateFile?: string; - /** - * additional data that will end up in scully.routes.json - * the frontMatter data will be added here too. - */ - data?: RouteData; -} -``` - -The `HandledRoute` interface provides the needed properties to develop your own plugin. - -### route: string - -`route` - An application route to be handled by Scully. This is the _fully qualified_ route info. That means that there should be no variables left in there. Also no `#` are allowed, and query parameters are ignored. - -### type: RoutesTypes - -`type` - Indicates the type of plugin. Contains the name of the routing plugin that should handle this. This is a mandatory field that _must_ be provided. When the type doesn't exist, Scully will terminate, as it doesn't know what to do. - -### defaultPostRenderers?: string[] - -`defaultPostRenderers` - Array with string ID's of the content-renderers that will be run on all routes. - -### postRenderers?: string[] - -`postRenderers` - Array of plugin names to be executed after the initial page render. Each of the plugins in this array will be rendered in the order they appear, and they will receive the output HTML from the previous plugin. -Moreover, this array _replaces_ the `defaultPostRenderers` array. - -```typescript -const defaultPostRenderers = ['seoHrefOptimise']; -const sampleConf: ScullyConfig = { - defaultPostRenderers, - routes: { - /** gets the default postrenderes */ - normalRoute: { - type: 'default' - }, - /** adds to the default postrenderes */ - someRoute: { - type: 'default', - postRenderers: [...defaultPostRenderers, 'myAddition'] - }, - /** removes the default postrenderes */ - someOtherRoute: { - type: 'default', - postRenderers: ['unique'] - } - } -}; -``` - -The `defaultPostRenderers` and `postRenderers` are designed this way in order to allow you to dispose off the default renderers. -Moreover, the current design is versatile, flexible, and it makes it easy to opt-out. - -Do not forget to add the `defaultPostRenderers`! - -### templateFile?: string - -`templateFile` - Unrelated to the angular template!. The file's name containing the template to be rendered. This property is specific to contentFolder. It contains the full path to the file that should be used to generate the content. Remember that content will be inserted _after_ the initial rendering. - -### data?: RouteData - -`data` - The data added to this property will be added to the routes data in the `scully.routes.json`. This data will also be extended in contentFolder routes with the front-matter data out of the start of the templateFile. - -```typescript -export interface RouteData { - title?: string; - author?: string; - published?: boolean; - [prop: string]: any; -} -``` - -### Router Plugin Interface - -A **router plugin** is a function that returns a `Promise`. The `HandledRoute` interface is described above. It receives a string with the unhandled route, and the config for that specific route. - -A router plugin function should be as follows: - -```typescript -function exampleRouterPlugin( - route: string, - config: any -): Promise { - // Must return a promise -} -``` - -The `HandledRoute[]` gets its data added into the `scully-routes.json` file generated by the `npm run scully` command. - -### Making A Router Plugin - -Lets implement the **router plugin** that turns the raw route into five distinct HandledRoutes from the previous example of an application containing the following route: `/user/:userId`. - -```javascript -const { registerPlugin } = require('@scullyio/scully'); - -function userIdPlugin(route: string, config = {}): Promise { - return Promise.resolve([ - { route: '/user/1' }, - { route: '/user/2' }, - { route: '/user/3' }, - { route: '/user/4' }, - { route: '/user/5' } - ]); -} - -registerPlugin('router', 'userIds', userIdPlugin, validator); -``` - -After implementing the plugin, configure the `scully.config.ts` in order to use it. - -### Configuring a Router Plugin - -The following configuration uses the `userIds` router plugin to get the `HandledRoute[]` for the above implementation: - -```typescript -// scully.config.ts -import './myPlugins/userIdPlugin'; -exports.config = { - // Add the following to your file - routes: { - '/user/:userId': { - type: 'userIds' - } - } -}; -``` - -## Render Plugin - -A **render plugin** is used to transform the rendered HTML. - -After the Angular application renders, the HTML content is passed to a **render plugin** where it can be further modified. - -A render plugin could be used to transform a page containing markdown into a page that renders it. - -### Render Plugin Interface - -A **render plugin** is a function that returns a `Promise`. The string in the promise must be the transformed -HTML. The interface looks like this: - -```typescript -function exampleContentPlugin( - HTML: string, - route: HandledRoute -): Promise { - // Must return a promise -} -``` - -### Making A Render Plugin - -The following **render plugin** example adds a title to the header to a page if it does not find one. - -```typescript -const { registerPlugin } = require('@scullyio/scully'); - -function defaultTitlePlugin(html, route) { - // If no title in the document - if (html.indexOf('The Truth Is Out There!`; - return Promise.resolve(`${begin}${defaultTitle}${splitter}${end}`); - } - return Promise.resolve(html); -} - -// DON NOT FORGET REGISTER THE PLUGIN -const validator = async conf => []; -registerPlugin('render', 'defaultTitle', defaultTitlePlugin, validator); - -module.exports.defaultTitlePlugin = defaultTitlePlugin; -``` - -In the above example, the Angular app's HTML content is transformed to include a title because anyone was found. - -The next example replaces any instances of `:)` with an smiley emoji. - -```typescript -const { registerPlugin } = require('@scullyio/scully'); - -function smileEmojiPlugin(html, route) { - return Promise.resolve(html.replace(/\:\)/g, '😊')); -} -// DON NOT FORGET REGISTER THE PLUGIN -const validator = async conf => []; -registerPlugin('render', 'smiles', smileEmojiPlugin, validator); - -module.exports.smileEmojiPlugin = smileEmojiPlugin; -``` - ---- - -## File Handler Plugin - -A **file handler plugin** is used by the `contentFolder` plugin during the `render` process. The `contentFolder` -plugin processes the folders for markdown files or other file type the folders may contain. The `render` process any existing `fileHandler` plugin for any file extension type. - -Scully comes with two built-in `fileHandler` plugins. The [markdown plugin](../scully/fileHanderPlugins/markdown.ts) and -the [asciidoc plugin](../scully/fileHanderPlugins/asciidoc.ts). These plugins handle and process the -content of those file types as they are read from the file system. - -If you want to support `.docx` files, or `.csv` files, or any other file type; a file handler for those file types need to be added. -The `contentFolder` plugin takes care of reading those files from the filesystem. However, if the files need to be transformed after the `contentFolder` plugin reads them; -A `fileHandler` plugin is required. - -### File Handler Plugin Interface - -A **file handler plugin** is a function that returns a `Promise`. The interface looks like follows: - -```typescript -function exampleFileHandlerPlugin(rawContent: string): Promise { - // Must return a promise -} -``` - -### Making A File Handler Plugin - -The following **file handler plugin** example handles `.cvs` files by wrapping them into a code block. You could write a much more elaborate plugin that creates a table or a grid for the data. - -```typescript -function csvFilePlugin(raw) { - return Promise.resolve(`
      ${code}
      `); -} -// DO NOT FORGET TO REGISTER THE PLUGIN -registerPlugin('fileHandler', 'csv', { handler: csvFilePlugin }); -module.exports.csvFilePlugin = csvFilePlugin; -``` - -### File Handler Plugin Examples - -Here are some links to built-in **render plugins** in Scully: - -- [asciidoc Plugin](../scully/fileHanderPlugins/asciidoc.ts) -- [markdown Plugin](../scully/fileHanderPlugins/markdown.ts) - -## RouteDiscoveryDone Plugin - -This type of plugin is called automatically after all routes have been collected, and all router plugins have finished. It receives a shallow copy of the `handledRoute` array, and it returns `void`. - -## AllDone Plugin - -An `allDone` plugin is like a `routeDiscoveryDone` plugin, expect it is called _after_ Scully finishes executing all its processes. diff --git a/docs/plugins_es.md b/docs/plugins_es.md deleted file mode 100644 index 854112c20..000000000 --- a/docs/plugins_es.md +++ /dev/null @@ -1,373 +0,0 @@ ---- -title: Plugins -order: 700 -lang: es ---- - -# Plugins - -Scully utiliza un sistema de plugins que permite a los usuarios definir nuevas formas en las que Scully haga el pre-render de la aplicación. Hay cinco tipos -principales de plugins: - -1. [Router Plugin](#router-plugin) -2. [Render Plugin](#render-plugin) -3. [File Handler Plugin](#file-handler-plugin) -4. [routeDiscoveryDone plugin](#routediscoverydone-plugin) -5. [allDone plugin](#alldone-plugin) - -Puede encontrar una lista de plugins disponibles la documentación de [plugins recomendados ](recommended-plugins_es.md). - ---- - -## Cómo Registerar un Plugin - -La función `registerPlugin` agrega un nuevo plugin a Scully y tiene 5 parámetros: - -- type -- name -- plugin -- validator (optional) -- options (optional) - -### type: string - -`type` - Indica el tipo de the plugin. Los tipos existentes son: `router`, `render`, `fileHandler`, `allDone`, o `routeDiscoveryDone`. - -### name: string - -`name` - El nombre del plugin. Este debe ser único para el tipo de plugin. Para remplazar un plugin existente, agregue la opción `replaceExistingPlugin`. - -### plugin: any - -`plugin` - La función del plugin. Los tipos de plugins estan explicados en su propia descripción. - -### validator: función (optional) - -`validator` - Función de validación que debe regresar un arreglo de errores. Si no hay errores, debe regresar un valor `false`. Si regresa un `string`, esos strings son los erroresa mostrar y el proceso en ejecición es abortado. - -> Tip: Agregar color a los errores de validació utilizando la extensión de color de Scully. - -##### Ejemplo de un Validator - -```typescript -import { yellow } from '@scullyio/scully'; - -// Código omitido - -const validator = async options => { - const errors = []; - - if (options.numberOfPages && typeof options.numberOfPages !== 'number') { - errors.push( - `my-custom-plugin numberOfPages should be a number, not a ${yellow( - typeof options.numberOfPages - )}` - ); - } - - return errors; -}; -``` - -### Opciones - -El objeto `optinal` permite agregar las opciones del plugin. Por el momento, la única opción disponible es `replaceExistingPlugin`. - -## Router Plugin - -Cada ruta en la aplicación que contiene un parámetro de ruta debe ser configurado en un **router plugin**. El plugin enseña a Scully como obtener los datos que requiere para hacer el pre-render de las páginas provenientes de los parámetros de ruta. - -Suponga que la aplicación tiene una ruta como esta: `{path: 'user/:userId', component: UserComponent}`. Para que Scully haga el pre-render del sitio web, necesita la lista completa de los IDs de Usuario que serán usados el el parámetro de ruta `:userId`. Si la tuviera cinco usuarios con IDs 1, 2, 3, 4 y 5; Scully necesitaría mostrar las siguientes rutas: - -``` -/user/1 -/user/2 -/user/3 -/user/4 -/user/5 -``` - -Un **router plugin** se usa para convertir la configuración de ruta con una variable en una lista de rutas que Scully pueda mostrar. - -### Interface `HandledRoute` - -```typescript -interface RouteConfig { - /** esta ruta checa inactividad de manera manual */ - manualIdleCheck?: boolean; - /** tipo de la ruta */ - type?: string; - /** - * una función opcional que se ejecuta al mostrar la página. - * Recive el string de la ruta y su configuración. - */ - preRenderer?: (route: HandledRoute) => Promise; - /** Permitir en cualquier otra configuración posible, depende de los plugins */ - [key: string]: any; -} - -export interface HandledRoute { - /** La ruta _completa_ */ - route: string; - /** String, debe ser el nombre de un plugin existente */ - type: string; - /** la parte relevante de scully-config */ - config?: RouteConfig; - /** variables expuestas a angular _¡solo mientras se hace el render!_ */ - exposeToPage?: { - manualIdle?: boolean; - transferState?: Serializable; - [key: string]: Serializable; - }; - /** datos que serán inyectados en la página estática */ - injectToPage?: { - [key: string]: Serializable; - }; - /** arreglo con los nombres de los plugins que serán ejecutados */ - postRenderers?: string[]; - /** el "path" del archivo de contenido */ - templateFile?: string; - /** - * datos adicionales que terminarán en el archivo scully.routes.json - * los datos del frontMatter también serán agregados aquí. - */ - data?: RouteData; -} -``` - -La interface `HandledRoute` proporciona las propiedades necesarias para desarrollar su propio plugin. - -### route: string - -`route` - Una ruta de aplicación que será manejada por Scully. Esta es la información _completamente calificada_ de la route. Esto quiere decir que no debe haber variables restantes aquí. Además el símbolo `#` no está permitido y los parámetros query de ruta son ignorados. - -### type: RoutesTypes - -`type` - Indica el tipo de plugin. Contiene el nombre del plugin de ruta. Este campo es obligatorio y _debe_ ser proporcionado. Cuando el tipo no existe, Scully finaliza ya que no sabe que hacer. - -### defaultPostRenderers?: string[] - -`defaultPostRenderers` - Arreglo con ID's de tipo string con los content-renderers que serán ejecutados en todas las rutas. - -### postRenderers?: string[] - -`postRenderers` - Arreglo de nombres de plugins que se ejecutarán desplues de mostrar la página de inicio. Cada uno de los plugins en este arreglo se mostrarán en el orden en el que aparecen y recibiran el HTML resultante del plugin anterior. -Además, teste arreglo _reemplaza_ el arreglo `defaultPostRenderers`. - -```typescript -const defaultPostRenderers = ['seoHrefOptimise']; -const sampleConf: ScullyConfig = { - defaultPostRenderers, - routes: { - /** obtiene los postrenderes por defecto */ - normalRoute: { - type: 'default' - }, - /** agrega los postrenderes por defecto */ - someRoute: { - type: 'default', - postRenderers: [...defaultPostRenderers, 'myAddition'] - }, - /** remueve los postrenderes por de fecto */ - someOtherRoute: { - type: 'default', - postRenderers: ['unique'] - } - } -}; -``` - -Los `defaultPostRenderers` y los `postRenderers` están diseñados de esta manera con la finalidad de permitirle deshacerse de los renderers por defecto. -Además, este diseño actual de los renders se adapta fácilmente a los diversos casos de uso. - -!No olvide agregar los `defaultPostRenderers`! - -### templateFile?: string - -`templateFile` - ¡No relacionado con la plantilla Angular! El nombre del archivo que contiene la plantilla que se mostrará. Esta propiedad es específica del contentFolder. Contiene el "path" completo al archivo que debe ser utilizado para generar el contenido. Recuerde que dicho contenido será insertado _despues_ del render inicial. - -### data?: RouteData - -`data` - Los datos agregados a esta propiedad serán agregados a las rutas en `scully.routes.json`. Estos datos también serán extendidos en las rutas del contentFolder. - -```typescript -export interface RouteData { - title?: string; - author?: string; - published?: boolean; - [prop: string]: any; -} -``` - -### Interface Router Plugin - -Un **router plugin** es una función que regresa un `Promise`. La interface `HandledRoute` se describe en el código anterior. Recibe un string con la ruta aun no manejada y la configuración para esa ruta en específico. - -Una función de plugin de ruta se muestra a continuación: - -```typescript -function exampleRouterPlugin( - route: string, - config: any -): Promise { - // Debe regresar una promesa -} -``` - -Los datos del `HandledRoute[]` son agregados al archivo `scully-routes.json` generado por el comando `npm run scully`. - -### Creando un Router Plugin - -Se implementará un **router plugin** que regresa la ruta original en HandledRoutes distintas como se mostró en el ejemplo anterior que contiene la siguiente ruta: `/user/:userId`. - -```javascript -const { registerPlugin } = require('@scullyio/scully'); - -function userIdPlugin(route: string, config = {}): Promise { - return Promise.resolve([ - { route: '/user/1' }, - { route: '/user/2' }, - { route: '/user/3' }, - { route: '/user/4' }, - { route: '/user/5' } - ]); -} - -registerPlugin('router', 'userIds', userIdPlugin, validator); -``` - -Después de implementar el plugin, configure el archivo `scully.config.ts` para poder utilizarlo. - -### Configurando un Router Plugin - -La siguinte configuración usa el plugin de ruta `userIds` para obtener el `HandledRoute[]` para la configuración anterior: - -```typescript -// scully.config.ts -import './myPlugins/userIdPlugin'; -exports.config = { - // Agregue las siguientes rutas a su archivo - routes: { - '/user/:userId': { - type: 'userIds' - } - } -}; -``` - -## Render Plugin - -Un **render plugin** se usa para transformar el HTML que se muestra en las páginas. - -Después de que la aplicación de Angular se muestra, el contenido HTML pasa al **render plugin** donde puede seguir siendo modificado. - -Un render plugin podría ser utilizado también para transformar una página que contenga markdown en una web que muestre dicho contenido. - -### Render Plugin Interface - -A **render plugin** es una función que regresa `Promise`. El string en la promesa debe ser transformado a -HTML. La interface se muestra a continuación: - -```typescript -function exampleContentPlugin( - HTML: string, - route: HandledRoute -): Promise { - // Debe regresar una promesa -} -``` - -### Haciendo Un Render Plugin - -El siguiente ejemplo de **render plugin** agrega un título al encabezado de la página sí esta no tiene uno. - -```typescript -const { registerPlugin } = require('@scullyio/scully'); - -function defaultTitlePlugin(html, route) { - // Si el documento no tiene título - if (html.indexOf('The Truth Is Out There!`; - return Promise.resolve(`${begin}${defaultTitle}${splitter}${end}`); - } - return Promise.resolve(html); -} - -// NO OLVIDE REGISTRAR EL PLUGIN -const validator = async conf => []; -registerPlugin('render', 'defaultTitle', defaultTitlePlugin, validator); - -module.exports.defaultTitlePlugin = defaultTitlePlugin; -``` - -En el ejemplo anterior, el contenido HTML de la aplicación de Angular es transformado para incluir un título porque no se encontró ninguno. - -El siguiente ejemplo reemplaza cualquier instancia de `:)` por un emoji sonriente. - -```typescript -const { registerPlugin } = require('@scullyio/scully'); - -function smileEmojiPlugin(html, route) { - return Promise.resolve(html.replace(/\:\)/g, '😊')); -} -// NO OLVIDE REGISTRAR EL PLUGIN -const validator = async conf => []; -registerPlugin('render', 'smiles', smileEmojiPlugin, validator); - -module.exports.smileEmojiPlugin = smileEmojiPlugin; -``` - ---- - -## File Handler Plugin - -Un **file handler plugin** es usado por el plugin `contentFolder` durante el proceso de `render`. El plugin `contentFolder` -procesa las carpetas con archivos markdownu otro tipo de archivo que contenga. El `render` procesa cualquier plugin `fileHandler` existente para cualquier tipo de extensión de archivo. - -Scully tiene dos plugins `fileHandler`. El [markdown plugin](../scully/fileHanderPlugins/markdown.ts) y -el [asciidoc plugin](../scully/fileHanderPlugins/asciidoc.ts). Estos plugins manejan y procesan el -contenido de los archivos correspondientes a su tipo mientras leen los archivos del sistema. - -Si desea soportar archivos `.docx`, `.csv`, o de cualquier otro tipo; es necesario agregar un plugin que maneje esos tipos de archivos. -El plugin `contentFolder` se encarga de mostrar el contenido del tipo de archivo correspondiente. Sin embargo, si los archivos necesitan ser transformados despues de que el plugin `contentFolder` los muestre; -Es necesario un plugin de tipo `fileHandler`. - -### Interface File Handler Plugin - -Un **file handler plugin** es una función que regresa una `Promise`. La interface se muestra a continuación: - -```typescript -function exampleFileHandlerPlugin(rawContent: string): Promise { - // Debe regresar una promesa -} -``` - -### Haciendo Un File Handler Plugin - -El siguiente ejemplo de **file handler plugin** maneja archivos de tipo `.cvs` al envolverlos en un bloque de código. Se podría escribir un plugin mucho más elaborad que creara una tabla o una cuadrícula para los datos. - -```typescript -function csvFilePlugin(raw) { - return Promise.resolve(`
      ${code}
      `); -} -// NO OLVIDE REGISTRAR EL PLUGIN -registerPlugin('fileHandler', 'csv', { handler: csvFilePlugin }); -module.exports.csvFilePlugin = csvFilePlugin; -``` - -### Ejemplos deFile Handler Plugin - -Aquí hay algunos links de **render plugins** ya incluidos en Scully: - -- [asciidoc Plugin](../scully/fileHanderPlugins/asciidoc.ts) -- [markdown Plugin](../scully/fileHanderPlugins/markdown.ts) - -## RouteDiscoveryDone Plugin - -Este tipo de plugin es llamado automáticamente despues de que todas las rutas han sido recogidas y que todos los plugins de ruta hayan terminado. Reciben una copia del arreglo `handledRoute` y regresan `void`. - -## AllDone Plugin - -Un plugin de tipo `allDone` es parecido a un plugin `routeDiscoveryDone` con la expeción de que se llama _después_ de que Scully termina de ejecutar todos los procesos. diff --git a/docs/pre-requisites.md b/docs/pre-requisites.md deleted file mode 100644 index c678605b5..000000000 --- a/docs/pre-requisites.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -title: Prerequisites -order: 100 -lang: en ---- - -# Prerequisites - -You need an existing Angular application, or you can create a new one in order to use Scully. - -**NOTE:** Scully supports Angular versions: **v8.x.x** and **v9.x.x** - -## Creating a New Angular Application - -Install the Angular CLI globally with the following command: - -```bash -npm install -g @angular/cli -``` - -Then, create a new application. - -```bash -ng new my-scully-app -``` - -#### IMPORTANT: - -_Scully depends on the application's router module in order to generate the website's pages_ - -Add a router module with the following command: - -```bash -ng generate module app-routing --flat --module=app -``` - -Find more info about the Angular CLI here [👉 angular.io/cli](https://angular.io/cli) - -#### IMPORTANT: - -_Scully uses Chromium. Therefore, your Operating System, as well as its administrator rights must allow its installation and execution._ - -### Node version: - -- Scully supports Node.js 10 or higher. diff --git a/docs/pre-requisites_es.md b/docs/pre-requisites_es.md deleted file mode 100644 index 881248ab4..000000000 --- a/docs/pre-requisites_es.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -title: Requisitos Previos -order: 100 -lang: es ---- - -# Requisitos Previos - -Necesita una aplicación existente de Angular o puede crear una nueva para usar Scully. - -**NOTA:** Scully soporta las versiones: **v8.x.x** y **v9.x.x** de Angular. - -## Crear Una Nueva Applicación de Angular - -Instale Angular CLI de manera global con el siguiente comando: - -```bash -npm install -g @angular/cli -``` - -Ahora, haga una nueva aplicación. - -```bash -ng new my-scully-app -``` - -#### IMPORTANTE: - -_Scully depende del módulo de rutas de la aplicación para poder las páginas del citio web_ - -Agregue el módulo de rutas con el siguiente comando: - -```bash -ng generate module app-routing --flat --module=app -``` - -Puede encontrar más información acerca de Angular CLI aquí [👉 angular.io/cli](https://angular.io/cli) - -#### IMPORTANTE: - -_Scully utiliza Chromium. Por lo tanto, su sistema operativo, así como sus derechos de administrador deben permitir su instalación y ejecución._ - -### Versión de Node: - -- Scully soporta Node.js 10 o mayor. diff --git a/docs/recommended-plugins.md b/docs/recommended-plugins.md deleted file mode 100644 index 123adb925..000000000 --- a/docs/recommended-plugins.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: List of Plugins -order: 1200 -lang: en ---- - -# Recommended Plugins - -_If you would like to add a plugin to this list; edit the `docs/recommended-plugins.md` file_ and submit a PR. - -## Scully Official Plugins - -- `json` - Router plugin [example](/scully.sample-blog.config.js) - -``` -Adds an http get call into the configuration. -``` - -- `contentFolder` - Router and render plugin [example](/scully.sample-blog.config.js) - -``` -Reads content from folders. -``` - -- `ignored` - Router plugin [example](/scully.sample-blog.config.js) - -``` -Adds support for ignoring routes. -``` - -- `adoc` - Render plugin [example](/scully.sample-blog.config.js) - -``` -Adds cappability to render adoc files as html. -``` - -- `md` - Render plugin [example](/scully.sample-blog.config.js) - -``` -Adds cappability to render markdown files as html. -``` - -## Community Render Plugins - -- [minifyHtml](https://www.npmjs.com/package/scully-plugin-minify-html) -- [disableAngular](https://www.npmjs.com/package/scully-plugin-disable-angular) -- [toc](https://www.npmjs.com/package/scully-plugin-toc) -- [regexHtml](https://www.npmjs.com/package/@gammastream/scully-plugin-regex) -- [sitemap](https://www.npmjs.com/package/@gammastream/scully-plugin-sitemap) -- [http404](https://www.npmjs.com/package/@gammastream/scully-plugin-http404) -- [fouc](https://www.npmjs.com/package/@notiz/scully-plugin-fouc) -- [lazyImages](https://www.npmjs.com/package/@notiz/scully-plugin-lazy-images) -- [rss](https://www.npmjs.com/package/@notiz/scully-plugin-rss) -- [mediumZoom](https://www.npmjs.com/package/@notiz/scully-plugin-medium-zoom) diff --git a/docs/recommended-plugins_es.md b/docs/recommended-plugins_es.md deleted file mode 100644 index 958503936..000000000 --- a/docs/recommended-plugins_es.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: Lista de Plugins -order: 1200 -lang: es ---- - -# Plugins Recomendados - -_Si gusta agregar un plugin a esta lista; edite el archivo `docs/recommended-plugins.md`_ y haga un PR. - -## Plugins Oficiales de Scully - -- `json` - Router plugin [ejemplo](/scully.sample-blog.config.js) - -``` -Agrega una llamada GET de http en la configuración. -``` - -- `contentFolder` - Router y render plugin [ejemplo](/scully.sample-blog.config.js) - -``` -Lee contenido de carpetas. -``` - -- `ignored` - Router plugin [ejemplo](/scully.sample-blog.config.js) - -``` -Agrega soporte para ignorar rutas. -``` - -- `adoc` - Render plugin [ejemplo](/scully.sample-blog.config.js) - -``` -Agrega la capacidad de mostrar archivos adoc como html. -``` - -- `md` - Render plugin [example](/scully.sample-blog.config.js) - -``` -Agrega la capacidad de mostrar archivos markdown como html. -``` - -## Render Plugins de la Comunidad - -- [minifyHtml](https://www.npmjs.com/package/scully-plugin-minify-html) -- [disableAngular](https://www.npmjs.com/package/scully-plugin-disable-angular) -- [toc](https://www.npmjs.com/package/scully-plugin-toc) -- [regexHtml](https://www.npmjs.com/package/@gammastream/scully-plugin-regex) -- [sitemap](https://www.npmjs.com/package/@gammastream/scully-plugin-sitemap) -- [http404](https://www.npmjs.com/package/@gammastream/scully-plugin-http404) -- [fouc](https://www.npmjs.com/package/@notiz/scully-plugin-fouc) -- [lazyImages](https://www.npmjs.com/package/@notiz/scully-plugin-lazy-images) -- [rss](https://www.npmjs.com/package/@notiz/scully-plugin-rss) -- [mediumZoom](https://www.npmjs.com/package/@notiz/scully-plugin-medium-zoom) diff --git a/docs/release-for-v8.md b/docs/release-for-v8.md deleted file mode 100644 index c970c29d1..000000000 --- a/docs/release-for-v8.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -title: Angular v8.x.x Release -order: 1300 -lang: en ---- - -# Step for Releasing a v8.x.x library - -1. Checkout the `angular-8` branch -2. Remove version 9: `rm -fr node_modules` -3. Install version 8: `npm i` -4. Pull origin main branch: `git pull origin main` -5. Fix any merge conflicts -6. Make sure that `package.json` file has version 8 -7. Build the application: `ng build @scullyio/ng-lib-v8` -8. Run tests -9. Pay attention to `package.json` to make sure you keep the 8 version -10. If all tests are ok, rebuild the library: - - `ng build @scullyio/ng-lib-v8` -11. Publish the application: - - `cd ./dist/scullyio/ng-lib-v8` - - `npm publish --access=public` -12. Commit and push changes. diff --git a/docs/roadmap.md b/docs/roadmap.md deleted file mode 100644 index 7f0775eff..000000000 --- a/docs/roadmap.md +++ /dev/null @@ -1,21 +0,0 @@ -# roadmap / wishlist - -1. Rename file-plugin to content plugin because this type of plugin does not handle files. -2. Rename the contentFolder render plugin. -3. Add a way for router plugins to modify the post-render array for a _single route_. -4. Documentation for existing plugins. -5. Documentation for the plugin system. -6. Documentation for plugin config. -7. Well structured documentation. -8. Schematic support for Nx. -9. Scully support for Nx. -10. i18n support. -11. Plugin for rewriting base-href. -12. Sample TS plugin, including instructions to build it, as well as a schematic that puts it into place. -13. Content plugin that takes a string. -14. More plugins. -15. Google sheets integration for forms by adding a plugin list. Scully's showcases should be generated with this plugin. -16. Better and more complete samples like: Web-store with a cart. Moreover, the examples should be like code-labs. -17. Tutorials. -18. Screencap demos in the documentation. -19. Deep dive tutorials. diff --git a/docs/routeParameters.md b/docs/routeParameters.md deleted file mode 100644 index a7412ed64..000000000 --- a/docs/routeParameters.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -title: Route Parameters & Scully -order: 190 -lang: en -slug: routeParameters ---- - -# Route Parameters & Scully - -If you run Scully and the following warning is displayed, you need to teach Scully how to use the project's route parameters. - -```bash -No configuration for route `/user/:userId` found. Skipping -``` - -The above error is given because Scully does not know all the possible values for `:userId`. Teach Scully how to get the list of `:userId`s from your app. Scully can turn `/user/:userId` into a list of meaningful pre-renderable routes like so: - -```bash -/user/1 -/user/2 -/user/3 -... -/user/100 -``` - -Even small Angular projects have routes that contain route parameters. To stop Scully from skipping these routes, configure a route plugin. Route plugins teach Scully how to fetch data and merges it into routes using parameters. - -The easiest way to understand route plugin is by understanding the `jsonPlugin`. It simply fetches data from any API that you specify, and it returns a list of properties that can be used to replace the route parameter. Checkout the [jsonPlugin docs](./plugin/jsonPlugin.md) to see an example of how easy this configuration is. diff --git a/docs/scully-cmd-line.md b/docs/scully-cmd-line.md deleted file mode 100644 index 1017f24ff..000000000 --- a/docs/scully-cmd-line.md +++ /dev/null @@ -1,208 +0,0 @@ ---- -title: Command Line Options -order: 400 -lang: en ---- - -# Scully Command Line Options - -The Scully CLI has the following available options: - -[Scully command line options](#scully-command-line-options) - -- [Scully Command Line Options](#scully-command-line-options) - - [Serve](#serve) - - [Watch](#watch) - - [showBrowser](#showbrowser) - - [showGuessError](#showguesserror) - - [configFile](#configfile) - - [project](#project) - - [baseFilter](#basefilter) - - [routeFilter](#routefilter) - - [proxyConfig](#proxyconfig) - - [removeStaticDist](#removestaticdist) - - [open](#open) - - [scanRoutes](#scanroutes) - - [serverTimout](#servertimout) - - [ssl](#ssl) - - [ssl-cert](#ssl-cert) - - [ssl-key](#ssl-key) - - [tds](#tds) - - [pluginsError](#pluginserror) - - [pjFirst](#pjfirst) - - [404](#404) - - [prod](#prod) - -## Serve - -```bash -npx scully serve -``` - -Starts the scully server. This process does not _build_ the project. It only serves the Angular build files, and the Scully static files. - -## Watch - -```bash -npx scully --watch -``` - -By default, Scully has the watchMode in false. You need to add this flag to use Watch Mode. - -## showBrowser - -```bash -npx scully --showBrowser -``` - -Alias `--sb`. Chromium browser renders the application. - -## showGuessError - -```bash -npx scully --showGuessError -``` - -Alias `--sge`. Displays Guess-Parse's errors in the console. - -## configFile - -```bash -npx scully --configFile someName -``` - -Alias `--cf`. Loads a different config file. If it is used at the same time as the `--project` flag, the project flag takes precedence. - -## project - -```bash -npx scully --project someName -``` - -Alias `--pr`. It is used to select a different project. Scully uses the default project from generated by the the Angular CLI. - -## baseFilter - -```bash -npx scully --baseFilter /someRoute -``` - -Alias `--bf`. Enables Scully to start rendering a specific route. works on the raw routes, extracted from the app, or provided by extraRoutes. - -## routeFilter - -```bash -npx scully --routeFilter /user/*/post/1,/posts/1/user/* -``` - -Alias `--rf`. Enables Scully to start rendering a specific route. Uses the handledRoutes. You can use the `*` as a wildcard, and provide multiple routes seprated by a `,` - -## proxyConfig - -Alias `--proxy`. Takes a relative filename for a proxy config file. - -For more details look at [this](https://github.com/chimurai/http-proxy-middleware/blob/main/README.md). - -Scully uses the same config format as [webpackDevServer](https://webpack.js.org/configuration/dev-server/#devserverproxy). - -## removeStaticDist - -```bash -npx scully --removeStaticDist -``` - -Alias `--RSD`. Removes the static folder generated by Scully from previous renders. - -## open - -```bash -npx scully serve/watch --open -``` - -Alias `--o`. Opens the default browser and renders the dist folder generated by Scully. - -## scanRoutes - -Alias `--sr` or `--scan`. Scans the application again to find unhandled routes. This is normally done just once. When routes in the application are added or changed, use this flag to discover all the new routes. - -## serverTimout - -alias `--st` Time to wait for the Scully server to become available. Defaults to 10000 (10 seconds). If you experience timeout issues in your CI, you might wat to raise this number. (Scully needs to extract the routes, this might take longer in a CI environment) - -## ssl - -```bash -npx scully serve/watch --ssl -``` - -Runs the Scully server with ssl. - -## ssl-cert - -```bash -npx scully serve/watch --ssl --ssl-cert=./url/to/file -``` - -Adds a url to the ssl certificate file for a server with SSL. - -## ssl-key - -```bash -npx scully serve/watch --ssl --ssl-key=./url/to/file -``` - -Adds a url to an ssl key file for a server with SSL. - -## tds - -```bash -npx scully --tds -``` - -Launches the Test Data Server. This is only helpful for demos. - -The following APIs are supported on the test data server: - -- `/users` - Returns a list of users -- `/users/:id` - Returns just one user by id -- `/posts` - Returns a list of posts -- `/posts/:id` - Returns a post by id -- `/slow/:delay` - Returns 200 code after a delay has gone by. Eg: `/slow/2000` takes 2 seconds. - -## pluginsError - -```bash -npx scully --pluginsError=false -``` - -Alias `--pe` Show the error from the plugin, but continue rendering. -If you do not use the flag (by default is true) when you have an error in any plugin, the Scully will terminate. - -## pjFirst - -```bash -npx scully --pjFirst -``` - -might -Alias `--pjf`. In an project that has a different setup, you might want to use the location of the main `package.json` instead of the `angular.json` as the homeFolder default. This might be needed in some NX repo's as well. - -## 404 - -```bash -npx scully --404="" #default, no need to provide this -npx scully --040="index" -npx scully --040="404" -npx scully --040="none" -``` - -How routes that are not provided in the application are handled. -If the Scully server gets a request for a route(file) that does not exists on the file-system, this option amends ow that is handled. The default option is to render a 404 page, and raise a warning during rendering. the `index` and `404` will render the `index.html` or the `404.html` from the dist root folder. The `none` option will leave it up to the express software layer. And lastly, `baseOnly` will use the unhandled routes only - -## prod - -```bash -npx scully --prod -``` - -With the prod flag you can use a different config for your scully config and plugins. [example](https://github.com/scullyio/scully/blob/main/scully.scully-docs.config.ts#L15) diff --git a/docs/scully-configuration.md b/docs/scully-configuration.md deleted file mode 100644 index a8a37f35d..000000000 --- a/docs/scully-configuration.md +++ /dev/null @@ -1,248 +0,0 @@ ---- -title: Configuration -order: 300 -lang: en ---- - -# Scully Configuration - -The central part of a Scully project is the `scully..config.ts` file. This file exports the Scully build configuration for an application. - -If you are new to Scully, it is recommended to read the [Getting Started](getting-started.md) documentation. - - - -The `scully..config.ts` file's structure is shown below: - -- [Scully Configuration](#scully-configuration) - - [Scully Config Interface](#scully-config-interface) - - [scullyConfig File's Properties](#scullyconfig-files-properties) - - [projectRoot](#projectroot) - - [homeFolder](#homefolder) - - [outDir](#outdir) - - [outHostFolder](#outHostFolder) - - [logFileSeverity](#logfileseverity) - - [handle404](#handle404) - - [distFolder](#distfolder) - - [hostFolder](#hostFolder) - - [routes](#routes) - - [Unhandled Routes](#unhandled-routes) - - [Handled Routes](#handled-routes) - - [extraRoutes](#extraroutes) - - [appPort](#appport) - - [staticPort](#staticport) - - [proxyConfig](#proxyconfig) - - [puppeteerLaunchOptions](#puppeteerlaunchoptions) - - [hostName](#hostname) - - [hostUrl](#hosturl) - - [guessParserOptions](#guessparseroptions) - - [ignoreResourceTypes](#ignoreresourcetypes) - -## Scully Config Interface - -```ts -export interface ScullyConfig { - /** is this a bare project (without angular.json?) */ - bareProject?: boolean; - /** the name of the project we are using. Provided by Scully itself */ - projectName?: string; - /** the folder where project is. Can be any off the projects in a repo, read from angular.json */ - projectRoot?: string; - /** the folder where the project sources resides, read from angular.json */ - sourceRoot?: string; - /** Array with string ID's of the content-renderers that will be run on all routes */ - defaultPostRenderers?: (string | symbol)[]; - /** the root of the project (where angular.json lives) */ - homeFolder?: string; - /** the destination of the Scully generated files */ - outDir?: string; - /** the folder used by the scully server to serve the generated files. defaults to outDir */ - outHostFolder?: string; - /** the place where distribution files of the project are. Should be a subfolder of dist. */ - distFolder?: string; - /** the folder used to serve the angular distribution files, defaults to distFolder */ - hostFolder?: string; - /** transferState only inlined into page, and not written into separate data.json */ - inlineStateOnly?: boolean; - /** Set what is what is written to the logfile, defaults to warnings and errors */ - logFileSeverity?: LogSeverity; - /** routes that need additional processing have their configuration in here */ - routes: RouteConfig; - /** routes that are in the application but have no route in the router */ - extraRoutes?: string | string[] | Promise; - /** Port-number where the original application is served */ - appPort?: number; - /** Boolean that determines saving of site-tumbnails files */ - thumbnails?: boolean; - /** port-number where the Scully generated files are available */ - staticport?: number; - /** port for the live reload service */ - reloadPort?: number; - /** optional proxy config file, uses the same config file as the CLI */ - proxyConfig?: string; - /** optional launch-options for puppeteer */ - puppeteerLaunchOptions?: LaunchOptions; - /** hostname to use for local server, defaults to `localhost` */ - hostName?: string; - /** optional hostURL, if this is provided, we are going to use this server instead of the build-in one. */ - hostUrl?: string; - /** optional guessParserOptions, if this is provided we are going to pass those options to the guess parser. */ - guessParserOptions?: GuessParserOptions; - /** the maximum of concurrent puppeteer tabs open. defaults to the available amounts of cores */ - maxRenderThreads?: number; - /** the resource types to ignore when generating pages via Puppeteer */ - ignoreResourceTypes?: ResourceType[]; - /** how to handle 404 in Scully server */ - handle404?: string; -} -``` - -The `ScullyConfig` interface provides parameters for configuring how Scully works in a project. - -## scullyConfig File's Properties - -### projectRoot - -`projectRoot` - The project's from which Scully generates the static content. - -### homeFolder - -`homeFolder` - A reference to the Angular project's root folder. This property is for internal use, and it defaults to the angular.json file's location. - -### outDir - -`outDir` - The folder's path where Scully leaves the statics files. This should not be the same as the distFolder. - -### outHostFolder - -`outHostFolder` The folder that is used to host the static files, defaults to the outDir. You can use this when you need to change the baseHref of pages. - -The default path is: - -```URL -./dist/static -``` - -### logFileSeverity - -`logFileSeverity` - determine what of the Scully output will be written into the `scully.log` file in the root of the project. -options: - -- 0 logs everything -- 1 logs warnings and errors only -- 2 logs errors only - -### handle404 - -`handle404` - how routes that are not provided in the application are handled by the Scully server. When the server gets a request for a route(file) that does not exists on the file-system, this option amends ow that is handled. - -- "" (default) is to render a 404 page, and raise a waring during rendering. -- `index` will render the `index.html` from the dist root folder -- `baseOnly` will use express route matcher on unhandled routes only -- `404` will render the `404.html` from the dist root folder. -- `none` option will leave it up to the express software layer. - -### distFolder - -`distFolder` - Path to the Angular application's dist folder. Scully takes the `angular.json` file's default path. This option can be modify according to the needs. This folder will be used by Scully during rendering. - -### hostFolder - -`hostFolder` The folder that is used to host the Angular distribution files, defaults to the distFolder. You can use this when changed the base-href with the Angular-CLI. Make sure the folders are matching the base-href settings, otherwise Scully will not be able to render your site. - -### routes - -Scully has the two following types of routes: - -#### Unhandled Routes - -Routes with dynamic data. This are the routes as you would use them inside your app. Those routes can come from the automated route discovery, or from the extraRoutes property in the `scully..config.ts` - -Eg. - -```URL -/foo/:id -``` - -All unhandled routes with dynamic data need to be handled through plugins. When there is a route with dynamic data that has no configuration in the configs routes, it will be logged to screen and skipped during processing. - -**THIS MEANS THERE WILL BE NO STATIC FILES FOR ROUTES THAT HAVE DYNAMIC DATA BUT NO CONFIG** - -For more information about router plugins read the [Plugins](plugins.md) documentation. - -#### Handled Routes - -Routes with static params. - -Eg. - -```URL -/foo/1 -``` - -### extraRoutes - -`extraRoutes` - Allows developers to add an array of unhandled routes. These routes can exist in an AngularJS, React, or any other framework. - -It can handle `string`, `string[]`, `Promise` or `Promise` - -```typescript -extraRoutes: [ - '/foo/:id', - new Promise('/bar/:barId'), - new Promise(['/foo/:fooId', '/bar/:id']), -]; -``` - -### appPort - -Scully provides a server to to render the Angular application. - -`appPort` - Configure the port where the Angular application runs. - -The default port is: `1864` - -### staticPort - -Similar to _appPort_, `staticport` provides a server to to render the static files compiled by Scully. - -The default port is: `1668` - -## proxyConfig - -Takes a relative filename for a proxy config file. - -For more details look at [this](https://github.com/chimurai/http-proxy-middleware). - -Scully uses the same config format as [webpackDevServer](https://webpack.js.org/configuration/dev-server/#devserverproxy). - -This is an optional property, and it is also used by the [Angular CLI](https://angular.io/guide/build#proxying-to-a-backend-server) - -This can also be provided with the `--proxy filname` command line flag - -### puppeteerLaunchOptions - -If the application is in a restricted environment, puppeteer's default options may not work. In that case, -this option can be overwrite with settings that match a specific environment. - -Word of warning, some settings might interfere with the way Scully is working, creating inaccurate results. -Follow [this link](https://pptr.dev/#?product=Puppeteer&version=v2.0.0&show=api-puppeteerlaunchoptions) for more information. - -### hostName - -Allows to set a different name for the `localhost`. - -### hostUrl - -Connects your application to a different host. This is useful when using your own server. - -### guessParserOptions - -The`guessParserOptions` that get passed to the `guess-parser` library. Currently, the only supported property is -`excludedFiles`, and it excludes files from the `guess-parser` route discovery process. - -### ignoreResourceTypes - -The `ignoreResourceTypes` array that get passed to the `puppeteerRenderPlugin`. -Any `ResourceType` that is listed here will be ignored by the Puppeteer instance rendering the requested page. -For example if you add `image` and `font` all requests to images and fonts loaded on your pages will be ignored. diff --git a/docs/scully-lib-core.md b/docs/scully-lib-core.md deleted file mode 100644 index a6c88b2c8..000000000 --- a/docs/scully-lib-core.md +++ /dev/null @@ -1,160 +0,0 @@ ---- -title: Core -order: 500 -lang: en ---- - -# Scully Core - -This section covers Scully's core features, and they are listed below: - -- [Idle Monitor Service](#idle-monitor-service) -- [Router Service](#router-service) -- [Scully Content Component](#scully-content-component) -- [Transfer State Service](#transfer-state-service) -- [Utility Methods](#utility-methods) - -## Idle Monitor Service - -The `IdleMonitorService` hooks into Zonejs. When Angular goes idle (**more precisely, when all outgoing HTTP requests finish**) -Scully triggers Puppeteer in order to know when it is ready to render. This service is in the `ScullyLibModule`. - -If your content is loaded out of sight of zones, Scully scrapes the page before its ready. - -To disable Scully ready mechanism and add your custom mechanism - -- Put following config object in the forRoot config - -```typescript -ScullyLibModule.forRoot({ - useTransferState: true, - alwaysMonitor: false, - manualIdle: true -}); -``` - -This will cause Scully to fall-back to using a 25 seconds timeout, on every page rendered. - -- Then in your component, trigger the fireManualMyAppReadyEvent(). - -```typescript -export class ManualIdleComponent implements OnInit { - text = 'this text is displayed by automated detection'; - - constructor(private ims: IdleMonitorService) {} - - ngOnInit(): void { - setTimeout(() => (this.text = '__ManualIdle__'), 3 * 1000); - setTimeout(() => this.ims.fireManualMyAppReadyEvent(), 3.25 * 1000); - } -} -``` - -- To enable this for single route, provide "manualIdle:true" inside the config.ts file in the route configuration. - -```typescript -// scully.config.ts -export const config: ScullyConfig = { - routes: { - '/user/:userId': { - type: 'json', - // Add the following to your route - exposeToPage:{ - manualIdle: true - } - userId: { - url: 'http://localhost:8200/users', - property: 'id' - } - } - } -}; -``` - -## Router Service - -The `ScullyRoutesService` provides methods and observables that allow you to know the routes rendered by Scully. - -The observables and methods are listed below: - -- available\$ -- unPublished\$ -- topLevel\$ -- getCurrent() -- reload() - -#### available\$: _Observable_ - -`available$` - Returns routes containing the property `published` with a value of true. - -#### unPublished\$: _Observable_ - -`unPublished$` - Returns routes containing the property `published` with a value of false. - -#### topLevel\$: _Observable_ - -`topLevel$` - Returns the top-level routes. - -#### getCurrent(): _Observable<ScullyRoute>_ - -`getCurrent()` - A method that returns the current location. - -#### reload(): _void_ - -`reload` - A method that checks if new routes have been added to the `scully-routes.json` file. - -The `ScullyRoutesService`'s types come from the `ScullyRoute` interface, which is shown below: - -```typescript -export interface ScullyRoute { - route: string; - title?: string; - slugs?: string[]; - published?: boolean; - slug?: string; - [prop: string]: any; -} -``` - -## Scully Content Component - -The `scully-content` component inserts the render process' result into the HTML document. - -**NOTE:** The `scully-content` component does not work inside an `*ngIf` directive. - -## Transfer State Service - -The `TransferStateService` allows to transfer an Angular application's state into the static site rendered by Scully. -More over, it allows you to load the state on subsequent route changes after the initial page has been loaded. - -A route change fetches the next route's state from the page on the serve, and it is returned to the client. Hence, having a state consumed as part of the build despite any CMS content in production - -To get or set the application's state; use the two methods below: - -#### getState - -`getState` - This method returns an observable that fires once and then completes. It does executes after the page's navigation has finished. - -```typescript -getState(name: string): Observable -``` - -#### setState - -`setState` - This method sets values to the property key. - -```typescript -setState(name: string, val: T): void; -``` - -## utility-methods - -These methods provide useful information about Scully processes. - -##### isScullyRunning(): _boolean_ - -`isScullyRunning` - This method returns `true` or `false` if the Scully build is currently running. - -##### isScullyGenerated(): _boolean_ - -`isScullyGenerated` - This method returns `true` if the Scully build has run. diff --git a/docs/scully-provided-plugins.md b/docs/scully-provided-plugins.md deleted file mode 100644 index e8d71f7c3..000000000 --- a/docs/scully-provided-plugins.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: Scully system plugins -order: 700 -lang: en ---- - -# This document describes Scully's builtin plugins. - -## json (router) - -## ignored (router) - -## contentFolder (router+render) - -## seoHrefOptimise (render) - -Adds a trailing slash (`/`) to all routes that are in the routeService. Increases SEO scoring. - -## adoc (fileHandler) - -## md (fileHandler) - -## router (router) - -Adds the route verbatim. Scully uses this plugin by default. diff --git a/docs/scully.md b/docs/scully.md deleted file mode 100644 index a046bbf72..000000000 --- a/docs/scully.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: Introduction -order: 110 -lang: en -slug: Introduction ---- - -# Introduction (Alpha) - -## What is Scully? - -**Scully** is the best static site generator for Angular projects looking to embrace the JAMStack. - -### How does it work? - -Under the hood, Scully analyzes an Angular application, and it generates a static version of it. In addition, it is **EASY TO USE** because it provides several Angular schematics. - -Scully works on Windows, Linux and macOS. - -Visit one of the following topics: - -- [Pre-requisites](pre-requisites.md) -- [Getting Started](getting-started.md) -- [Scully Configuration](scully-configuration.md) -- [Scully command line options](scully-cmd-line.md) -- [Scully Core](scully-lib-core.md) -- [Adding Blog Support](blog.md) -- [Working with Plugins](plugins.md) -- [Polyfills](polyfills.md) -- [Code of Conduct](CODE_OF_CONDUCT.md) -- [Issues](issues.md) -- [Contribution Guideline](CONTRIBUTING.md) - ---- - -Join the Scully community on [Gitter](https://gitter.im/scullyio/community) - -Scully [Office Hours](https://meet.google.com/vcm-wekz-hsx?authuser=1) every Tuesday at noon MST - ---- - -### Do you want to collaborate to scully? - -The team would love your feedback and how you are using Scully with other tools. - -Want to share your experience with the community? Please check our [CONTRIBUTING](CONTRIBUTING.md) guidelines. diff --git a/docs/scully_es.md b/docs/scully_es.md deleted file mode 100644 index d054a18fa..000000000 --- a/docs/scully_es.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: Introducción -order: 110 -lang: es -slug: introduccion ---- - -# Introducción (Alfa) - -## ¿Qué es Scully? - -**Scully** el mejor generador de sitios estáticos para proyectos de Angular buscando adoptar JAMStack. - -### ¿Cómo funciona? - -Tras bambalinas, Scully analiza la plicación de Angular y genera una versión estática de esta. Además, es **FACIL DE USAR** porque proporciona varios esquemas (schematics) de Angular. - -Scully funciona en Windows, Linux y macOS. - -Visite uno de los siguientes temas: - -- [Prerrequisitos](pre-requisites.md) -- [Primeros Pasos](getting-started.md) -- [Configuración de Scully](scully-configuration.md) -- [Opciones de Linea de Comando de Scully](scully-cmd-line.md) -- [Scully Core](scully-lib-core.md) -- [Agregar Soporte para un Blog](blog.md) -- [Trabajando con Plugins](plugins.md) -- [Polyfills](polyfills.md) -- [Código de Conducta](CODE_OF_CONDUCT.md) -- [Issues](issues.md) -- [Guía de Contribución](CONTRIBUTING.md) - ---- - -Unase a la comunidad de Scully en [Gitter](https://gitter.im/scullyio/community) - -Scully [Horas de Oficina](https://meet.google.com/vcm-wekz-hsx?authuser=1) todos los martes al medio día MST. - ---- - -### ¿Le gustaría colaborar a Scully? - -El equipo aprecia su retroalimentación y nos gustaría conocer cómo está usando Scully en convinación con otras herramientas. - -¿Le gustaría compartir su experiencia con la comunidad? Por favor vea nuestra guía de [CONTRIBUCIÓN](CONTRIBUTING.md). diff --git a/docs/showcase.md b/docs/showcase.md deleted file mode 100644 index f8e922309..000000000 --- a/docs/showcase.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -title: Showcase -order: 9900 -lang: en ---- - -# Scully Showcase - -[![1-800 Contacts](/assets/1800contacts_logo_indigo.png)](https://www.1800contacts.com/) -
      - -[![ConfigCat Feature Flags](https://configcat.com/images/shared/configcat-logo-horiz.svg)](https://configcat.com) -
      - -[![Ledge DevOps](https://devops.phodal.com/assets/images/logo.svg)](https://devops.phodal.com/home) -
      - -[![Nicola Toledo Web developer & Trainer](https://www.nicolatoledo.dev/assets/logo-letter-black.png)](https://www.nicolatoledo.dev/) -
      - -[![Scully Website](/assets/logos/PNG/scullyio-logo.png)](https://scully.io/) -
      - -[![soloCoding Blog](https://github.com/s0l0c0ding/solocoding/blob/main/src/assets/favicon.png)](https://solocoding.dev/) -
      - -[![AppsAtEase](https://firebasestorage.googleapis.com/v0/b/uae-dev.appspot.com/o/apps-at-ease-full-white-bg.png?alt=media)](https://appsatease.com/) -
      - - diff --git a/libs/scully/src/lib/fileHanderPlugins/markdown.ts b/libs/scully/src/lib/fileHanderPlugins/markdown.ts index 7faaa703d..ad653d9e1 100644 --- a/libs/scully/src/lib/fileHanderPlugins/markdown.ts +++ b/libs/scully/src/lib/fileHanderPlugins/markdown.ts @@ -2,6 +2,31 @@ import { registerPlugin } from '../pluginManagement/pluginRepository'; import { getConfig, setConfig } from '../pluginManagement/pluginConfig'; const marked = require('marked'); +// ------------------------------ +// Syntax Highlighting + +const Prism = require('prismjs'); +import 'prismjs/components/prism-bash'; +import 'prismjs/components/prism-css'; +import 'prismjs/components/prism-javascript'; +import 'prismjs/components/prism-json'; +import 'prismjs/components/prism-markup'; +import 'prismjs/components/prism-markdown'; +import 'prismjs/components/prism-typescript'; + +const renderer = new marked.Renderer(); +// wrap code block the way Prism.js expects it +renderer.code = function (code, lang, escaped) { + code = this.options.highlight(code, lang); + if (!lang) { + return '
      ' + code + '
      '; + } + // e.g. "language-js" + const langClass = 'language-' + lang; + return '
      ' + code + '
      '; +}; +// ------------------------------ + export interface MarkedConfig { enableSyntaxHighlighting: boolean; } @@ -10,13 +35,13 @@ const markdownPlugin = async (raw: string) => { const config = getConfig(markdownPlugin); if (config.enableSyntaxHighlighting) { marked.setOptions({ - renderer: new marked.Renderer(), - highlight: (code, language) => { - const hljs = require('highlight.js'); - const validLanguage = hljs.getLanguage(language) - ? language - : 'plaintext'; - return hljs.highlight(validLanguage, code).value; + renderer, + highlight: (code, lang) => { + if (!Prism.languages[lang]) { + console.error(`Language '${lang}' is not available in Prism.js, ignoring syntax highlighting for this code block.`); + return code; + } + return Prism.highlight(code, Prism.languages[lang]); }, pedantic: false, gfm: true, @@ -24,7 +49,7 @@ const markdownPlugin = async (raw: string) => { sanitize: false, smartLists: true, smartypants: false, - xhtml: false + xhtml: false, }); } @@ -32,7 +57,7 @@ const markdownPlugin = async (raw: string) => { }; setConfig(markdownPlugin, { - enableSyntaxHighlighting: false + enableSyntaxHighlighting: false, }); registerPlugin('fileHandler', 'md', markdownPlugin, ['markdown']); diff --git a/libs/scully/src/lib/testData/users-testdata.ts b/libs/scully/src/lib/testData/users-testdata.ts index bdfeb265f..15e8c984a 100644 --- a/libs/scully/src/lib/testData/users-testdata.ts +++ b/libs/scully/src/lib/testData/users-testdata.ts @@ -43,16 +43,16 @@ export const users = [ zipcode: '92998-3874', geo: { lat: '-37.3159', - lng: '81.1496' - } + lng: '81.1496', + }, }, phone: '1-770-736-8031 x56442', website: 'hildegard.org', company: { name: 'Romaguera-Crona', catchPhrase: 'Multi-layered client-server neural-net', - bs: 'harness real-time e-markets' - } + bs: 'harness real-time e-markets', + }, }, { id: 2, @@ -66,16 +66,16 @@ export const users = [ zipcode: '90566-7771', geo: { lat: '-43.9509', - lng: '-34.4618' - } + lng: '-34.4618', + }, }, phone: '010-692-6593 x09125', website: 'anastasia.net', company: { name: 'Deckow-Crist', catchPhrase: 'Proactive didactic contingency', - bs: 'synergize scalable supply-chains' - } + bs: 'synergize scalable supply-chains', + }, }, { id: 3, @@ -89,16 +89,16 @@ export const users = [ zipcode: '59590-4157', geo: { lat: '-68.6102', - lng: '-47.0653' - } + lng: '-47.0653', + }, }, phone: '1-463-123-4447', website: 'ramiro.info', company: { name: 'Romaguera-Jacobson', catchPhrase: 'Face to face bifurcated interface', - bs: 'e-enable strategic applications' - } + bs: 'e-enable strategic applications', + }, }, { id: 4, @@ -112,16 +112,16 @@ export const users = [ zipcode: '53919-4257', geo: { lat: '29.4572', - lng: '-164.2990' - } + lng: '-164.2990', + }, }, phone: '493-170-9623 x156', website: 'kale.biz', company: { name: 'Robel-Corkery', catchPhrase: 'Multi-tiered zero tolerance productivity', - bs: 'transition cutting-edge web services' - } + bs: 'transition cutting-edge web services', + }, }, { id: 5, @@ -135,16 +135,16 @@ export const users = [ zipcode: '33263', geo: { lat: '-31.8129', - lng: '62.5342' - } + lng: '62.5342', + }, }, phone: '(254)954-1289', website: 'demarco.info', company: { name: 'Keebler LLC', catchPhrase: 'User-centric fault-tolerant solution', - bs: 'revolutionize end-to-end systems' - } + bs: 'revolutionize end-to-end systems', + }, }, { id: 6, @@ -158,16 +158,16 @@ export const users = [ zipcode: '23505-1337', geo: { lat: '-71.4197', - lng: '71.7478' - } + lng: '71.7478', + }, }, phone: '1-477-935-8478 x6430', website: 'ola.org', company: { name: 'Considine-Lockman', catchPhrase: 'Synchronised bottom-line interface', - bs: 'e-enable innovative applications' - } + bs: 'e-enable innovative applications', + }, }, { id: 7, @@ -181,16 +181,16 @@ export const users = [ zipcode: '58804-1099', geo: { lat: '24.8918', - lng: '21.8984' - } + lng: '21.8984', + }, }, phone: '210.067.6132', website: 'elvis.io', company: { name: 'Johns Group', catchPhrase: 'Configurable multimedia task-force', - bs: 'generate enterprise e-tailers' - } + bs: 'generate enterprise e-tailers', + }, }, { id: 8, @@ -204,16 +204,16 @@ export const users = [ zipcode: '45169', geo: { lat: '-14.3990', - lng: '-120.7677' - } + lng: '-120.7677', + }, }, phone: '586.493.6943 x140', website: 'jacynthe.com', company: { name: 'Abernathy Group', catchPhrase: 'Implemented secondary concept', - bs: 'e-enable extensible e-tailers' - } + bs: 'e-enable extensible e-tailers', + }, }, { id: 9, @@ -227,16 +227,16 @@ export const users = [ zipcode: '76495-3109', geo: { lat: '24.6463', - lng: '-168.8889' - } + lng: '-168.8889', + }, }, phone: '(775)976-6794 x41206', website: 'conrad.com', company: { name: 'Yost and Sons', catchPhrase: 'Switchable contextually-based project', - bs: 'aggregate real-time technologies' - } + bs: 'aggregate real-time technologies', + }, }, { id: 10, @@ -250,16 +250,16 @@ export const users = [ zipcode: '31428-2261', geo: { lat: '-38.2386', - lng: '57.2232' - } + lng: '57.2232', + }, }, phone: '024-648-3804', website: 'ambrose.net', company: { name: 'Hoeger LLC', catchPhrase: 'Centralized empowering task-force', - bs: 'target end-to-end models' - } + bs: 'target end-to-end models', + }, }, { id: 11, @@ -273,16 +273,16 @@ export const users = [ zipcode: '97851-9331', geo: { lat: '-46.0586', - lng: '-162.3510' - } + lng: '-162.3510', + }, }, phone: '(105) 694-7408', website: 'https://carey.net', company: { name: 'Witting, Zieme and Pfeffer', catchPhrase: 'Persevering leading edge migration', - bs: 'efficient architect platforms' - } + bs: 'efficient architect platforms', + }, }, { id: 12, @@ -296,16 +296,16 @@ export const users = [ zipcode: '89895', geo: { lat: '27.2413', - lng: '-151.6993' - } + lng: '-151.6993', + }, }, phone: '(713) 042-2473', website: 'http://shaun.com', company: { name: 'Miller, Russel and Turcotte', catchPhrase: 'Centralized high-level migration', - bs: 'cross-platform leverage partnerships' - } + bs: 'cross-platform leverage partnerships', + }, }, { id: 13, @@ -319,16 +319,16 @@ export const users = [ zipcode: '37867-9117', geo: { lat: '33.5768', - lng: '21.9073' - } + lng: '21.9073', + }, }, phone: '1-130-365-6055 x594', website: 'https://laurie.org', company: { name: 'Olson - Medhurst', catchPhrase: 'Versatile bifurcated conglomeration', - bs: 'dynamic maximize portals' - } + bs: 'dynamic maximize portals', + }, }, { id: 14, @@ -342,16 +342,16 @@ export const users = [ zipcode: '55398-9352', geo: { lat: '-7.2386', - lng: '16.8325' - } + lng: '16.8325', + }, }, phone: '(717) 628-7285 x76424', website: 'http://osvaldo.name', company: { name: 'Leannon - Fahey', catchPhrase: 'Decentralized systematic infrastructure', - bs: 'transparent implement bandwidth' - } + bs: 'transparent implement bandwidth', + }, }, { id: 15, @@ -365,16 +365,16 @@ export const users = [ zipcode: '05193', geo: { lat: '-34.2635', - lng: '-179.2794' - } + lng: '-179.2794', + }, }, phone: '802.857.0257', website: 'http://orin.biz', company: { name: 'Orn - Zboncak', catchPhrase: 'Cross-platform 5th generation budgetary management', - bs: '24/7 orchestrate platforms' - } + bs: '24/7 orchestrate platforms', + }, }, { id: 16, @@ -388,16 +388,16 @@ export const users = [ zipcode: '44883-7925', geo: { lat: '-72.7031', - lng: '1.7334' - } + lng: '1.7334', + }, }, phone: '625.959.9859 x899', website: 'https://reid.com', company: { name: 'Harber - Effertz', catchPhrase: 'Persevering bandwidth-monitored open architecture', - bs: 'plug-and-play orchestrate metrics' - } + bs: 'plug-and-play orchestrate metrics', + }, }, { id: 17, @@ -411,16 +411,16 @@ export const users = [ zipcode: '23692-9823', geo: { lat: '-75.7972', - lng: '158.2631' - } + lng: '158.2631', + }, }, phone: '(592) 720-9720 x490', website: 'http://will.org', company: { name: 'Koepp Group', catchPhrase: 'Multi-lateral logistical flexibility', - bs: 'vertical evolve deliverables' - } + bs: 'vertical evolve deliverables', + }, }, { id: 18, @@ -434,16 +434,16 @@ export const users = [ zipcode: '51343', geo: { lat: '2.5142', - lng: '29.6492' - } + lng: '29.6492', + }, }, phone: '1-832-480-1930 x1171', website: 'https://ernest.name', company: { name: 'Ledner LLC', catchPhrase: 'Realigned explicit definition', - bs: 'open-source integrate users' - } + bs: 'open-source integrate users', + }, }, { id: 19, @@ -457,16 +457,16 @@ export const users = [ zipcode: '98118', geo: { lat: '62.6765', - lng: '-141.6078' - } + lng: '-141.6078', + }, }, phone: '(048) 694-9301 x23075', website: 'http://eleazar.org', company: { name: 'Ferry LLC', catchPhrase: 'Pre-emptive hybrid standardization', - bs: 'plug-and-play productize action-items' - } + bs: 'plug-and-play productize action-items', + }, }, { id: 20, @@ -480,16 +480,16 @@ export const users = [ zipcode: '19043', geo: { lat: '74.5972', - lng: '-54.2272' - } + lng: '-54.2272', + }, }, phone: '(800) 931-0804 x334', website: 'https://elta.org', company: { name: 'Treutel, Corwin and Schiller', catchPhrase: 'Distributed local strategy', - bs: 'cutting-edge orchestrate solutions' - } + bs: 'cutting-edge orchestrate solutions', + }, }, { id: 21, @@ -503,16 +503,16 @@ export const users = [ zipcode: '29677-9600', geo: { lat: '-26.2908', - lng: '174.4526' - } + lng: '174.4526', + }, }, phone: '(989) 268-0291 x6435', website: 'https://vicky.biz', company: { name: "Marvin, Jaskolski and D'Amore", catchPhrase: 'Integrated discrete superstructure', - bs: 'killer reinvent e-tailers' - } + bs: 'killer reinvent e-tailers', + }, }, { id: 22, @@ -526,16 +526,16 @@ export const users = [ zipcode: '64535', geo: { lat: '-28.6150', - lng: '-68.4056' - } + lng: '-68.4056', + }, }, phone: '670-801-2255 x16743', website: 'https://leilani.name', company: { name: 'Oberbrunner - Wunsch', catchPhrase: 'Total client-driven budgetary management', - bs: 'one-to-one utilize mindshare' - } + bs: 'one-to-one utilize mindshare', + }, }, { id: 23, @@ -549,16 +549,16 @@ export const users = [ zipcode: '50368-3688', geo: { lat: '70.1008', - lng: '112.2983' - } + lng: '112.2983', + }, }, phone: '1-674-460-6546 x3376', website: 'https://ola.com', company: { name: 'Donnelly, Murray and Green', catchPhrase: 'Profit-focused real-time circuit', - bs: 'value-added aggregate eyeballs' - } + bs: 'value-added aggregate eyeballs', + }, }, { id: 24, @@ -572,16 +572,16 @@ export const users = [ zipcode: '60813', geo: { lat: '-69.4864', - lng: '-29.0886' - } + lng: '-29.0886', + }, }, phone: '(132) 710-4458', website: 'http://jairo.com', company: { name: 'Nikolaus Inc', catchPhrase: 'Re-engineered intangible service-desk', - bs: 'end-to-end visualize vortals' - } + bs: 'end-to-end visualize vortals', + }, }, { id: 25, @@ -595,16 +595,16 @@ export const users = [ zipcode: '38299', geo: { lat: '26.1032', - lng: '-73.8213' - } + lng: '-73.8213', + }, }, phone: '704-545-5660', website: 'http://jeff.net', company: { name: 'Hodkiewicz Inc', catchPhrase: 'Vision-oriented content-based function', - bs: 'clicks-and-mortar integrate relationships' - } + bs: 'clicks-and-mortar integrate relationships', + }, }, { id: 26, @@ -618,16 +618,16 @@ export const users = [ zipcode: '11339', geo: { lat: '80.3891', - lng: '179.9526' - } + lng: '179.9526', + }, }, phone: '1-228-129-3212 x840', website: 'https://jennifer.name', company: { name: 'Toy, Cartwright and Marquardt', catchPhrase: 'Realigned global hub', - bs: 'magnetic engineer models' - } + bs: 'magnetic engineer models', + }, }, { id: 27, @@ -641,16 +641,16 @@ export const users = [ zipcode: '97206', geo: { lat: '-8.9751', - lng: '-81.1578' - } + lng: '-81.1578', + }, }, phone: '198-894-9778', website: 'https://augustine.org', company: { name: 'Goodwin, Hirthe and Goodwin', catchPhrase: 'Assimilated fault-tolerant benchmark', - bs: 'world-class morph metrics' - } + bs: 'world-class morph metrics', + }, }, { id: 28, @@ -664,16 +664,16 @@ export const users = [ zipcode: '25757', geo: { lat: '-6.1308', - lng: '81.5314' - } + lng: '81.5314', + }, }, phone: '889-584-0651', website: 'http://dante.net', company: { name: 'Wunsch, Hansen and Johnson', catchPhrase: 'Automated actuating structure', - bs: 'seamless evolve e-tailers' - } + bs: 'seamless evolve e-tailers', + }, }, { id: 29, @@ -687,16 +687,16 @@ export const users = [ zipcode: '97848-2115', geo: { lat: '57.7614', - lng: '-125.7947' - } + lng: '-125.7947', + }, }, phone: '1-122-901-4691 x07113', website: 'https://jovani.name', company: { name: 'Borer Group', catchPhrase: 'Integrated asynchronous support', - bs: 'viral reinvent platforms' - } + bs: 'viral reinvent platforms', + }, }, { id: 30, @@ -710,16 +710,16 @@ export const users = [ zipcode: '11713-4163', geo: { lat: '-40.3686', - lng: '151.2520' - } + lng: '151.2520', + }, }, phone: '(697) 881-6389 x7079', website: 'http://dane.biz', company: { name: 'Marks - Rowe', catchPhrase: 'Universal coherent collaboration', - bs: 'web-enabled matrix metrics' - } + bs: 'web-enabled matrix metrics', + }, }, { id: 31, @@ -733,16 +733,16 @@ export const users = [ zipcode: '72538', geo: { lat: '10.2330', - lng: '29.8495' - } + lng: '29.8495', + }, }, phone: '849.909.3935', website: 'https://kaley.com', company: { name: 'Funk - Botsford', catchPhrase: 'Polarised non-volatile Graphical User Interface', - bs: 'bleeding-edge strategize web services' - } + bs: 'bleeding-edge strategize web services', + }, }, { id: 32, @@ -756,16 +756,16 @@ export const users = [ zipcode: '75917-5982', geo: { lat: '-6.5263', - lng: '-93.2028' - } + lng: '-93.2028', + }, }, phone: '712-037-1148 x7799', website: 'http://bobbie.net', company: { name: 'Glover and Sons', catchPhrase: 'Multi-tiered modular firmware', - bs: 'intuitive exploit e-business' - } + bs: 'intuitive exploit e-business', + }, }, { id: 33, @@ -779,16 +779,16 @@ export const users = [ zipcode: '39915-7153', geo: { lat: '70.1527', - lng: '125.9355' - } + lng: '125.9355', + }, }, phone: '(894) 353-7888', website: 'https://lupe.name', company: { name: 'Bogisich, Lang and Lehner', catchPhrase: 'Team-oriented regional encoding', - bs: 'intuitive scale web-readiness' - } + bs: 'intuitive scale web-readiness', + }, }, { id: 34, @@ -802,16 +802,16 @@ export const users = [ zipcode: '82956', geo: { lat: '38.2861', - lng: '-83.3990' - } + lng: '-83.3990', + }, }, phone: '417-536-7060 x0548', website: 'http://chadrick.com', company: { name: 'Turcotte - Donnelly', catchPhrase: 'Focused bottom-line Graphical User Interface', - bs: 'extensible whiteboard solutions' - } + bs: 'extensible whiteboard solutions', + }, }, { id: 35, @@ -825,16 +825,16 @@ export const users = [ zipcode: '25671', geo: { lat: '50.6832', - lng: '142.1650' - } + lng: '142.1650', + }, }, phone: '478-431-7446 x9364', website: 'https://terrance.org', company: { name: 'Kemmer, Emmerich and Hudson', catchPhrase: 'Stand-alone zero administration local area network', - bs: 'cross-platform mesh eyeballs' - } + bs: 'cross-platform mesh eyeballs', + }, }, { id: 36, @@ -848,16 +848,16 @@ export const users = [ zipcode: '74455', geo: { lat: '-76.6419', - lng: '-4.1966' - } + lng: '-4.1966', + }, }, phone: '650.804.6344 x9495', website: 'https://jackson.info', company: { name: 'Mann - Russel', catchPhrase: 'Balanced grid-enabled Graphic Interface', - bs: 'next-generation matrix channels' - } + bs: 'next-generation matrix channels', + }, }, { id: 37, @@ -871,16 +871,16 @@ export const users = [ zipcode: '11918-2490', geo: { lat: '-58.9677', - lng: '-88.4422' - } + lng: '-88.4422', + }, }, phone: '436.083.1023 x91915', website: 'https://malachi.net', company: { name: 'Schroeder - Klein', catchPhrase: 'Upgradable optimizing application', - bs: 'intuitive brand schemas' - } + bs: 'intuitive brand schemas', + }, }, { id: 38, @@ -894,16 +894,16 @@ export const users = [ zipcode: '71963', geo: { lat: '-75.9056', - lng: '15.0658' - } + lng: '15.0658', + }, }, phone: '1-890-765-9528 x7629', website: 'http://alycia.net', company: { name: 'Homenick - Botsford', catchPhrase: 'Sharable web-enabled instruction set', - bs: 'dot-com iterate platforms' - } + bs: 'dot-com iterate platforms', + }, }, { id: 39, @@ -917,16 +917,16 @@ export const users = [ zipcode: '71386-2283', geo: { lat: '65.1780', - lng: '151.4640' - } + lng: '151.4640', + }, }, phone: '1-691-051-0188 x291', website: 'https://angelina.info', company: { name: 'Crona - Langworth', catchPhrase: 'Enterprise-wide actuating collaboration', - bs: 'end-to-end implement schemas' - } + bs: 'end-to-end implement schemas', + }, }, { id: 40, @@ -940,16 +940,16 @@ export const users = [ zipcode: '05327-2214', geo: { lat: '87.9401', - lng: '58.0787' - } + lng: '58.0787', + }, }, phone: '416-493-9966 x3570', website: 'http://beth.name', company: { name: 'Klein, Mueller and Carroll', catchPhrase: 'Devolved global parallelism', - bs: 'bleeding-edge visualize networks' - } + bs: 'bleeding-edge visualize networks', + }, }, { id: 41, @@ -963,16 +963,16 @@ export const users = [ zipcode: '44639', geo: { lat: '54.0801', - lng: '-78.7654' - } + lng: '-78.7654', + }, }, phone: '1-810-232-0073 x3662', website: 'http://haylie.com', company: { name: 'Rau LLC', catchPhrase: 'Customizable attitude-oriented customer loyalty', - bs: 'virtual repurpose deliverables' - } + bs: 'virtual repurpose deliverables', + }, }, { id: 42, @@ -986,16 +986,16 @@ export const users = [ zipcode: '99581', geo: { lat: '-81.1645', - lng: '163.3187' - } + lng: '163.3187', + }, }, phone: '(418) 961-4210 x479', website: 'https://zander.net', company: { name: 'Monahan, Hane and Von', catchPhrase: 'Multi-channelled disintermediate Graphical User Interface', - bs: 'next-generation deploy e-tailers' - } + bs: 'next-generation deploy e-tailers', + }, }, { id: 43, @@ -1009,16 +1009,16 @@ export const users = [ zipcode: '65355-2552', geo: { lat: '24.9571', - lng: '-122.9256' - } + lng: '-122.9256', + }, }, phone: '1-721-096-1981 x20622', website: 'http://ian.net', company: { name: 'Kunde LLC', catchPhrase: 'Optional static local area network', - bs: 'end-to-end iterate supply-chains' - } + bs: 'end-to-end iterate supply-chains', + }, }, { id: 44, @@ -1032,16 +1032,16 @@ export const users = [ zipcode: '26288', geo: { lat: '-60.9624', - lng: '157.3311' - } + lng: '157.3311', + }, }, phone: '(029) 984-2910', website: 'https://hubert.org', company: { name: 'Lubowitz - Okuneva', catchPhrase: 'Open-architected optimizing approach', - bs: 'turn-key cultivate relationships' - } + bs: 'turn-key cultivate relationships', + }, }, { id: 45, @@ -1055,16 +1055,16 @@ export const users = [ zipcode: '63188', geo: { lat: '-11.2540', - lng: '-118.3803' - } + lng: '-118.3803', + }, }, phone: '(110) 478-9900', website: 'http://aida.biz', company: { name: 'Graham Inc', catchPhrase: 'Decentralized content-based utilisation', - bs: 'cutting-edge synthesize interfaces' - } + bs: 'cutting-edge synthesize interfaces', + }, }, { id: 46, @@ -1078,16 +1078,16 @@ export const users = [ zipcode: '84874-6470', geo: { lat: '-15.5007', - lng: '-48.7433' - } + lng: '-48.7433', + }, }, phone: '343-833-5972 x6638', website: 'http://zackery.org', company: { name: 'Lockman - Auer', catchPhrase: 'Adaptive coherent utilisation', - bs: 'customized innovate solutions' - } + bs: 'customized innovate solutions', + }, }, { id: 47, @@ -1101,16 +1101,16 @@ export const users = [ zipcode: '13713', geo: { lat: '-9.4504', - lng: '122.6305' - } + lng: '122.6305', + }, }, phone: '461.542.1366 x43498', website: 'https://emmanuelle.net', company: { name: 'Kertzmann - Hahn', catchPhrase: 'Extended reciprocal superstructure', - bs: 'value-added reinvent supply-chains' - } + bs: 'value-added reinvent supply-chains', + }, }, { id: 48, @@ -1124,16 +1124,16 @@ export const users = [ zipcode: '57634', geo: { lat: '1.1199', - lng: '-79.7680' - } + lng: '-79.7680', + }, }, phone: '066.438.9343 x72106', website: 'http://malika.name', company: { name: 'Jacobs Group', catchPhrase: 'Optimized even-keeled superstructure', - bs: 'leading-edge expedite content' - } + bs: 'leading-edge expedite content', + }, }, { id: 49, @@ -1147,16 +1147,16 @@ export const users = [ zipcode: '47256', geo: { lat: '-54.2540', - lng: '157.4875' - } + lng: '157.4875', + }, }, phone: '815.748.7879 x21098', website: 'http://tyrique.org', company: { name: 'Zboncak Inc', catchPhrase: 'Customer-focused asynchronous circuit', - bs: 'open-source maximize infomediaries' - } + bs: 'open-source maximize infomediaries', + }, }, { id: 50, @@ -1170,16 +1170,16 @@ export const users = [ zipcode: '10736', geo: { lat: '-59.6004', - lng: '39.9672' - } + lng: '39.9672', + }, }, phone: '1-291-876-8819', website: 'https://kim.org', company: { name: 'Leannon Inc', catchPhrase: 'Compatible coherent implementation', - bs: 'cutting-edge incubate content' - } + bs: 'cutting-edge incubate content', + }, }, { id: 51, @@ -1193,16 +1193,16 @@ export const users = [ zipcode: '38357', geo: { lat: '25.8318', - lng: '-39.5185' - } + lng: '-39.5185', + }, }, phone: '011-266-9929', website: 'https://noel.info', company: { name: 'Altenwerth Group', catchPhrase: 'Streamlined optimal encryption', - bs: 'dot-com e-enable markets' - } + bs: 'dot-com e-enable markets', + }, }, { id: 52, @@ -1216,16 +1216,16 @@ export const users = [ zipcode: '94442-6353', geo: { lat: '-37.2095', - lng: '-146.2360' - } + lng: '-146.2360', + }, }, phone: '(050) 347-6392', website: 'http://kyler.org', company: { name: 'Heathcote Inc', catchPhrase: 'Inverse foreground firmware', - bs: 'back-end leverage bandwidth' - } + bs: 'back-end leverage bandwidth', + }, }, { id: 53, @@ -1239,16 +1239,16 @@ export const users = [ zipcode: '51938', geo: { lat: '-5.9325', - lng: '51.2448' - } + lng: '51.2448', + }, }, phone: '061-461-9412', website: 'http://sophie.biz', company: { name: 'Kilback - Powlowski', catchPhrase: 'Robust logistical protocol', - bs: 'distributed innovate metrics' - } + bs: 'distributed innovate metrics', + }, }, { id: 54, @@ -1262,16 +1262,16 @@ export const users = [ zipcode: '80438-7555', geo: { lat: '-31.4682', - lng: '83.8541' - } + lng: '83.8541', + }, }, phone: '1-242-677-8629', website: 'https://stefanie.biz', company: { name: 'Murphy, Kozey and Beier', catchPhrase: 'Integrated user-facing definition', - bs: 'innovative scale markets' - } + bs: 'innovative scale markets', + }, }, { id: 55, @@ -1285,16 +1285,16 @@ export const users = [ zipcode: '96255-9375', geo: { lat: '0.6676', - lng: '-125.7758' - } + lng: '-125.7758', + }, }, phone: '1-666-807-7449 x37020', website: 'http://hayley.net', company: { name: 'Boehm, Medhurst and Emmerich', catchPhrase: 'Extended multimedia concept', - bs: 'one-to-one reinvent ROI' - } + bs: 'one-to-one reinvent ROI', + }, }, { id: 56, @@ -1308,16 +1308,16 @@ export const users = [ zipcode: '14341-8162', geo: { lat: '2.4191', - lng: '-5.5382' - } + lng: '-5.5382', + }, }, phone: '1-428-914-7039', website: 'https://triston.com', company: { name: 'Hirthe, Schuster and Bergstrom', catchPhrase: 'Networked dynamic collaboration', - bs: 'bricks-and-clicks orchestrate ROI' - } + bs: 'bricks-and-clicks orchestrate ROI', + }, }, { id: 57, @@ -1331,16 +1331,16 @@ export const users = [ zipcode: '76668', geo: { lat: '17.9818', - lng: '139.7036' - } + lng: '139.7036', + }, }, phone: '1-818-578-1097 x892', website: 'http://maximillia.info', company: { name: 'Klocko, Smith and Baumbach', catchPhrase: 'Realigned holistic project', - bs: '24/7 empower interfaces' - } + bs: '24/7 empower interfaces', + }, }, { id: 58, @@ -1354,16 +1354,16 @@ export const users = [ zipcode: '66668', geo: { lat: '-64.0817', - lng: '70.2417' - } + lng: '70.2417', + }, }, phone: '839.598.6835 x61625', website: 'https://mellie.name', company: { name: 'Jast Group', catchPhrase: 'Re-contextualized methodical database', - bs: 'B2C e-enable convergence' - } + bs: 'B2C e-enable convergence', + }, }, { id: 59, @@ -1377,16 +1377,16 @@ export const users = [ zipcode: '56836', geo: { lat: '2.5092', - lng: '-47.0640' - } + lng: '-47.0640', + }, }, phone: '(586) 683-5449 x10946', website: 'http://gunnar.info', company: { name: 'Bins - Reynolds', catchPhrase: 'Innovative grid-enabled analyzer', - bs: 'leading-edge extend synergies' - } + bs: 'leading-edge extend synergies', + }, }, { id: 60, @@ -1400,16 +1400,16 @@ export const users = [ zipcode: '87594-4539', geo: { lat: '39.4931', - lng: '83.3378' - } + lng: '83.3378', + }, }, phone: '1-300-405-2833', website: 'http://warren.com', company: { name: 'Bradtke - Johnson', catchPhrase: 'Compatible tertiary parallelism', - bs: 'customized synthesize systems' - } + bs: 'customized synthesize systems', + }, }, { id: 61, @@ -1423,16 +1423,16 @@ export const users = [ zipcode: '09110-4142', geo: { lat: '49.8334', - lng: '72.5923' - } + lng: '72.5923', + }, }, phone: '(950) 142-0999', website: 'http://angie.name', company: { name: 'Hackett, Boyer and Hand', catchPhrase: 'Future-proofed optimizing secured line', - bs: 'seamless extend e-business' - } + bs: 'seamless extend e-business', + }, }, { id: 62, @@ -1446,16 +1446,16 @@ export const users = [ zipcode: '26067', geo: { lat: '-83.6748', - lng: '175.7084' - } + lng: '175.7084', + }, }, phone: '677-943-6752 x938', website: 'http://rosanna.com', company: { name: 'Crooks LLC', catchPhrase: 'Diverse holistic policy', - bs: 'B2C redefine methodologies' - } + bs: 'B2C redefine methodologies', + }, }, { id: 63, @@ -1469,16 +1469,16 @@ export const users = [ zipcode: '93998-3579', geo: { lat: '79.9318', - lng: '69.0247' - } + lng: '69.0247', + }, }, phone: '075.252.9221 x0668', website: 'http://dina.org', company: { name: 'Bosco - Kunde', catchPhrase: 'Digitized methodical implementation', - bs: 'enterprise evolve e-commerce' - } + bs: 'enterprise evolve e-commerce', + }, }, { id: 64, @@ -1492,16 +1492,16 @@ export const users = [ zipcode: '93975', geo: { lat: '-78.0252', - lng: '70.0406' - } + lng: '70.0406', + }, }, phone: '764.879.6348 x450', website: 'http://theodora.biz', company: { name: 'Fritsch, Dare and Corkery', catchPhrase: 'Grass-roots real-time adapter', - bs: 'synergistic benchmark supply-chains' - } + bs: 'synergistic benchmark supply-chains', + }, }, { id: 65, @@ -1515,16 +1515,16 @@ export const users = [ zipcode: '35991', geo: { lat: '48.6667', - lng: '28.5284' - } + lng: '28.5284', + }, }, phone: '533.731.0164 x729', website: 'https://kelsie.name', company: { name: 'McCullough - Ernser', catchPhrase: 'Multi-tiered client-driven instruction set', - bs: 'strategic synthesize bandwidth' - } + bs: 'strategic synthesize bandwidth', + }, }, { id: 66, @@ -1538,16 +1538,16 @@ export const users = [ zipcode: '31639-4879', geo: { lat: '44.6876', - lng: '-17.8860' - } + lng: '-17.8860', + }, }, phone: '(939) 351-8055', website: 'https://cornell.org', company: { name: 'Flatley - Gutkowski', catchPhrase: 'Monitored regional firmware', - bs: 'distributed grow relationships' - } + bs: 'distributed grow relationships', + }, }, { id: 67, @@ -1561,16 +1561,16 @@ export const users = [ zipcode: '87977', geo: { lat: '-7.1538', - lng: '-58.5227' - } + lng: '-58.5227', + }, }, phone: '(362) 389-7148 x059', website: 'http://eldon.com', company: { name: 'Rice - Rogahn', catchPhrase: 'Polarised global complexity', - bs: 'virtual seize communities' - } + bs: 'virtual seize communities', + }, }, { id: 68, @@ -1584,16 +1584,16 @@ export const users = [ zipcode: '10550-7819', geo: { lat: '-53.7837', - lng: '60.8428' - } + lng: '60.8428', + }, }, phone: '127-552-2310 x106', website: 'http://madyson.biz', company: { name: 'Wyman, Carter and Larkin', catchPhrase: 'Business-focused logistical groupware', - bs: 'one-to-one syndicate partnerships' - } + bs: 'one-to-one syndicate partnerships', + }, }, { id: 69, @@ -1607,16 +1607,16 @@ export const users = [ zipcode: '23681-6463', geo: { lat: '-44.3125', - lng: '-66.4157' - } + lng: '-66.4157', + }, }, phone: '1-187-661-4873 x30480', website: 'http://luz.info', company: { name: 'Rempel - Larson', catchPhrase: 'Automated zero defect initiative', - bs: 'integrated cultivate infrastructures' - } + bs: 'integrated cultivate infrastructures', + }, }, { id: 70, @@ -1630,16 +1630,16 @@ export const users = [ zipcode: '92029', geo: { lat: '-39.4406', - lng: '-67.1580' - } + lng: '-67.1580', + }, }, phone: '(475) 504-1340 x2442', website: 'https://garth.info', company: { name: "Kuhic - O'Keefe", catchPhrase: 'Upgradable modular open system', - bs: 'seamless redefine networks' - } + bs: 'seamless redefine networks', + }, }, { id: 71, @@ -1653,16 +1653,16 @@ export const users = [ zipcode: '93007', geo: { lat: '-25.7175', - lng: '-77.5870' - } + lng: '-77.5870', + }, }, phone: '755.310.3047 x10786', website: 'https://jordon.name', company: { name: 'Howe, Emmerich and Zboncak', catchPhrase: 'Adaptive asymmetric artificial intelligence', - bs: 'B2C morph interfaces' - } + bs: 'B2C morph interfaces', + }, }, { id: 72, @@ -1676,16 +1676,16 @@ export const users = [ zipcode: '85563-2665', geo: { lat: '8.9526', - lng: '41.7475' - } + lng: '41.7475', + }, }, phone: '(326) 270-3467', website: 'https://elise.org', company: { name: 'Steuber - Fahey', catchPhrase: 'Total logistical function', - bs: 'frictionless integrate initiatives' - } + bs: 'frictionless integrate initiatives', + }, }, { id: 73, @@ -1699,16 +1699,16 @@ export const users = [ zipcode: '66382-6007', geo: { lat: '-60.5695', - lng: '129.6511' - } + lng: '129.6511', + }, }, phone: '(008) 603-8891', website: 'https://sigmund.org', company: { name: 'Turcotte Inc', catchPhrase: 'Persevering regional standardization', - bs: 'vertical facilitate technologies' - } + bs: 'vertical facilitate technologies', + }, }, { id: 74, @@ -1722,16 +1722,16 @@ export const users = [ zipcode: '31121', geo: { lat: '-70.7520', - lng: '-44.1630' - } + lng: '-44.1630', + }, }, phone: '(097) 991-2910 x456', website: 'http://fanny.org', company: { name: 'Bogisich - Volkman', catchPhrase: 'Proactive bandwidth-monitored secured line', - bs: 'collaborative scale relationships' - } + bs: 'collaborative scale relationships', + }, }, { id: 75, @@ -1745,16 +1745,16 @@ export const users = [ zipcode: '37070-7329', geo: { lat: '39.3925', - lng: '163.5900' - } + lng: '163.5900', + }, }, phone: '661.622.4291 x6974', website: 'http://martin.name', company: { name: 'Tremblay Inc', catchPhrase: 'Decentralized human-resource middleware', - bs: 'holistic productize eyeballs' - } + bs: 'holistic productize eyeballs', + }, }, { id: 76, @@ -1768,16 +1768,16 @@ export const users = [ zipcode: '17410-9181', geo: { lat: '39.2058', - lng: '75.4850' - } + lng: '75.4850', + }, }, phone: '085.748.0729 x8923', website: 'http://aiden.org', company: { name: 'Dibbert, Parisian and Considine', catchPhrase: 'Reverse-engineered optimal ability', - bs: 'B2C leverage e-tailers' - } + bs: 'B2C leverage e-tailers', + }, }, { id: 77, @@ -1791,16 +1791,16 @@ export const users = [ zipcode: '35183', geo: { lat: '1.8482', - lng: '149.7387' - } + lng: '149.7387', + }, }, phone: '(251) 669-3423', website: 'http://jensen.org', company: { name: 'West Inc', catchPhrase: 'De-engineered maximized moratorium', - bs: 'impactful optimize e-markets' - } + bs: 'impactful optimize e-markets', + }, }, { id: 78, @@ -1814,16 +1814,16 @@ export const users = [ zipcode: '47346', geo: { lat: '18.3271', - lng: '175.3485' - } + lng: '175.3485', + }, }, phone: '865-198-7305 x164', website: 'http://alena.biz', company: { name: 'Donnelly Group', catchPhrase: 'Business-focused maximized archive', - bs: 'sticky incentivize paradigms' - } + bs: 'sticky incentivize paradigms', + }, }, { id: 79, @@ -1837,16 +1837,16 @@ export const users = [ zipcode: '71176', geo: { lat: '-26.8935', - lng: '-66.6878' - } + lng: '-66.6878', + }, }, phone: '1-523-178-1641 x96345', website: 'https://peggie.org', company: { name: 'Daugherty, Douglas and Swift', catchPhrase: 'Monitored client-server utilisation', - bs: 'user-centric recontextualize schemas' - } + bs: 'user-centric recontextualize schemas', + }, }, { id: 80, @@ -1860,16 +1860,16 @@ export const users = [ zipcode: '55390-5433', geo: { lat: '-86.3407', - lng: '-45.6423' - } + lng: '-45.6423', + }, }, phone: '1-693-500-8412 x26104', website: 'https://martina.com', company: { name: 'Schoen Group', catchPhrase: 'Profound optimizing capability', - bs: 'open-source evolve architectures' - } + bs: 'open-source evolve architectures', + }, }, { id: 81, @@ -1883,16 +1883,16 @@ export const users = [ zipcode: '77963-8310', geo: { lat: '74.3440', - lng: '-12.4175' - } + lng: '-12.4175', + }, }, phone: '1-887-775-3111 x674', website: 'https://laney.info', company: { name: 'Schuppe Inc', catchPhrase: 'Fully-configurable attitude-oriented customer loyalty', - bs: 'real-time disintermediate e-commerce' - } + bs: 'real-time disintermediate e-commerce', + }, }, { id: 82, @@ -1906,16 +1906,16 @@ export const users = [ zipcode: '30264', geo: { lat: '42.2673', - lng: '95.6283' - } + lng: '95.6283', + }, }, phone: '724.583.2030', website: 'http://brendon.net', company: { name: 'Renner Inc', catchPhrase: 'Compatible radical data-warehouse', - bs: 'back-end reinvent portals' - } + bs: 'back-end reinvent portals', + }, }, { id: 83, @@ -1929,16 +1929,16 @@ export const users = [ zipcode: '47850', geo: { lat: '-70.5806', - lng: '138.1492' - } + lng: '138.1492', + }, }, phone: '205.629.4655 x973', website: 'http://mathew.net', company: { name: 'Fahey Group', catchPhrase: 'Devolved value-added access', - bs: 'magnetic transition portals' - } + bs: 'magnetic transition portals', + }, }, { id: 84, @@ -1952,16 +1952,16 @@ export const users = [ zipcode: '48417-0510', geo: { lat: '-83.6686', - lng: '47.2310' - } + lng: '47.2310', + }, }, phone: '(379) 990-5349 x928', website: 'https://agustina.org', company: { name: 'Reichel, Wisoky and Murray', catchPhrase: 'Customizable discrete hub', - bs: 'intuitive productize e-tailers' - } + bs: 'intuitive productize e-tailers', + }, }, { id: 85, @@ -1975,16 +1975,16 @@ export const users = [ zipcode: '42566-0446', geo: { lat: '70.1240', - lng: '-19.1863' - } + lng: '-19.1863', + }, }, phone: '1-371-939-6853 x073', website: 'http://xavier.org', company: { name: 'Abbott, Frami and Hamill', catchPhrase: 'Configurable multi-tasking concept', - bs: 'e-business envisioneer ROI' - } + bs: 'e-business envisioneer ROI', + }, }, { id: 86, @@ -1998,16 +1998,16 @@ export const users = [ zipcode: '98923-1993', geo: { lat: '-47.5117', - lng: '-80.9013' - } + lng: '-80.9013', + }, }, phone: '516-187-0532', website: 'https://dejah.name', company: { name: 'Volkman, Wisoky and Kovacek', catchPhrase: 'Fully-configurable 6th generation archive', - bs: 'revolutionary generate initiatives' - } + bs: 'revolutionary generate initiatives', + }, }, { id: 87, @@ -2021,16 +2021,16 @@ export const users = [ zipcode: '99240', geo: { lat: '-14.5556', - lng: '152.2515' - } + lng: '152.2515', + }, }, phone: '028-698-1612', website: 'http://dane.org', company: { name: 'Koelpin Group', catchPhrase: 'Multi-lateral national solution', - bs: 'integrated extend solutions' - } + bs: 'integrated extend solutions', + }, }, { id: 88, @@ -2044,16 +2044,16 @@ export const users = [ zipcode: '19141', geo: { lat: '-45.8523', - lng: '26.0794' - } + lng: '26.0794', + }, }, phone: '431.254.0960', website: 'http://kailey.org', company: { name: 'Koepp, Osinski and Hodkiewicz', catchPhrase: 'Seamless user-facing success', - bs: '24/365 morph paradigms' - } + bs: '24/365 morph paradigms', + }, }, { id: 89, @@ -2067,16 +2067,16 @@ export const users = [ zipcode: '17660-4830', geo: { lat: '-9.9426', - lng: '-131.0972' - } + lng: '-131.0972', + }, }, phone: '1-360-701-8590 x3147', website: 'http://valentin.net', company: { name: 'Jacobi LLC', catchPhrase: 'Focused impactful circuit', - bs: 'transparent drive functionalities' - } + bs: 'transparent drive functionalities', + }, }, { id: 90, @@ -2090,16 +2090,16 @@ export const users = [ zipcode: '71983-0108', geo: { lat: '74.1604', - lng: '140.0020' - } + lng: '140.0020', + }, }, phone: '915.047.4512', website: 'http://trudie.com', company: { name: 'Torphy - Ondricka', catchPhrase: 'Multi-channelled analyzing architecture', - bs: 'viral seize platforms' - } + bs: 'viral seize platforms', + }, }, { id: 91, @@ -2113,16 +2113,16 @@ export const users = [ zipcode: '14493-4079', geo: { lat: '-68.5953', - lng: '-40.8500' - } + lng: '-40.8500', + }, }, phone: '(258) 624-0911 x815', website: 'http://norwood.info', company: { name: 'Dickens, Tillman and Prohaska', catchPhrase: 'Programmable web-enabled artificial intelligence', - bs: 'innovative unleash action-items' - } + bs: 'innovative unleash action-items', + }, }, { id: 92, @@ -2136,16 +2136,16 @@ export const users = [ zipcode: '47203-9279', geo: { lat: '-51.5004', - lng: '23.0200' - } + lng: '23.0200', + }, }, phone: '1-992-477-6967', website: 'http://maci.com', company: { name: 'Heathcote and Sons', catchPhrase: 'Progressive 3rd generation firmware', - bs: '24/7 maximize deliverables' - } + bs: '24/7 maximize deliverables', + }, }, { id: 93, @@ -2159,16 +2159,16 @@ export const users = [ zipcode: '34673-6633', geo: { lat: '-2.9357', - lng: '-153.2520' - } + lng: '-153.2520', + }, }, phone: '748-004-3492', website: 'https://carmel.org', company: { name: 'Waelchi - Hegmann', catchPhrase: 'Future-proofed uniform toolset', - bs: 'out-of-the-box architect interfaces' - } + bs: 'out-of-the-box architect interfaces', + }, }, { id: 94, @@ -2182,16 +2182,16 @@ export const users = [ zipcode: '70671', geo: { lat: '-32.8648', - lng: '95.2491' - } + lng: '95.2491', + }, }, phone: '1-399-603-7560 x40162', website: 'http://kristoffer.com', company: { name: 'Stokes Group', catchPhrase: 'Virtual non-volatile data-warehouse', - bs: 'B2B implement channels' - } + bs: 'B2B implement channels', + }, }, { id: 95, @@ -2205,16 +2205,16 @@ export const users = [ zipcode: '64723', geo: { lat: '72.1719', - lng: '-21.4797' - } + lng: '-21.4797', + }, }, phone: '1-204-734-3652 x7995', website: 'https://deanna.info', company: { name: 'Langosh, Hessel and Sipes', catchPhrase: 'Profound reciprocal paradigm', - bs: 'visionary target e-tailers' - } + bs: 'visionary target e-tailers', + }, }, { id: 96, @@ -2228,16 +2228,16 @@ export const users = [ zipcode: '29057', geo: { lat: '8.4887', - lng: '51.6256' - } + lng: '51.6256', + }, }, phone: '671.336.5093 x4589', website: 'http://dovie.biz', company: { name: 'Rath - Ruecker', catchPhrase: 'Organic discrete website', - bs: 'value-added morph communities' - } + bs: 'value-added morph communities', + }, }, { id: 97, @@ -2251,16 +2251,16 @@ export const users = [ zipcode: '83213-1308', geo: { lat: '79.2264', - lng: '19.9387' - } + lng: '19.9387', + }, }, phone: '(765) 656-3115 x440', website: 'https://erica.name', company: { name: 'Trantow - Jakubowski', catchPhrase: 'Decentralized asynchronous framework', - bs: 'revolutionary deliver models' - } + bs: 'revolutionary deliver models', + }, }, { id: 98, @@ -2274,16 +2274,16 @@ export const users = [ zipcode: '92730', geo: { lat: '13.5824', - lng: '-55.8988' - } + lng: '-55.8988', + }, }, phone: '382.756.7967', website: 'https://felicia.biz', company: { name: 'Lueilwitz, Langworth and Towne', catchPhrase: 'Devolved scalable Graphic Interface', - bs: 'vertical innovate e-markets' - } + bs: 'vertical innovate e-markets', + }, }, { id: 99, @@ -2297,16 +2297,16 @@ export const users = [ zipcode: '38544-6642', geo: { lat: '33.0838', - lng: '133.5646' - } + lng: '133.5646', + }, }, phone: '417.206.3272 x013', website: 'https://arlene.com', company: { name: 'Lind - Nikolaus', catchPhrase: 'Secured non-volatile ability', - bs: 'user-centric transition web services' - } + bs: 'user-centric transition web services', + }, }, { id: 100, @@ -2320,16 +2320,16 @@ export const users = [ zipcode: '28943', geo: { lat: '-40.5770', - lng: '-135.2406' - } + lng: '-135.2406', + }, }, phone: '1-529-688-6475 x12668', website: 'https://tristin.name', company: { name: 'Bode - Ferry', catchPhrase: 'Universal encompassing contingency', - bs: 'cutting-edge repurpose ROI' - } + bs: 'cutting-edge repurpose ROI', + }, }, { id: 101, @@ -2343,16 +2343,16 @@ export const users = [ zipcode: '17766-6848', geo: { lat: '-13.6843', - lng: '70.7810' - } + lng: '70.7810', + }, }, phone: '(296) 126-4360 x2224', website: 'https://marta.com', company: { name: 'Littel - Senger', catchPhrase: 'Visionary uniform internet solution', - bs: 'clicks-and-mortar innovate partnerships' - } + bs: 'clicks-and-mortar innovate partnerships', + }, }, { id: 102, @@ -2366,16 +2366,16 @@ export const users = [ zipcode: '96708-9743', geo: { lat: '22.5033', - lng: '-102.7742' - } + lng: '-102.7742', + }, }, phone: '1-507-482-1297', website: 'http://norwood.name', company: { name: 'Jenkins - Gerlach', catchPhrase: 'Focused incremental concept', - bs: 'real-time facilitate platforms' - } + bs: 'real-time facilitate platforms', + }, }, { id: 103, @@ -2389,16 +2389,16 @@ export const users = [ zipcode: '06810', geo: { lat: '-68.2421', - lng: '-178.3178' - } + lng: '-178.3178', + }, }, phone: '(553) 432-6619', website: 'https://cary.name', company: { name: 'Cole Inc', catchPhrase: 'Stand-alone scalable concept', - bs: 'out-of-the-box empower methodologies' - } + bs: 'out-of-the-box empower methodologies', + }, }, { id: 104, @@ -2412,16 +2412,16 @@ export const users = [ zipcode: '53711-8947', geo: { lat: '-74.6790', - lng: '82.5843' - } + lng: '82.5843', + }, }, phone: '933-310-8512 x073', website: 'http://abigale.name', company: { name: 'Breitenberg Inc', catchPhrase: 'Reduced 4th generation productivity', - bs: 'wireless exploit platforms' - } + bs: 'wireless exploit platforms', + }, }, { id: 105, @@ -2435,16 +2435,16 @@ export const users = [ zipcode: '88606', geo: { lat: '-75.6395', - lng: '6.6038' - } + lng: '6.6038', + }, }, phone: '700-502-0620', website: 'http://reva.biz', company: { name: 'Donnelly, Little and Stoltenberg', catchPhrase: 'Face to face systematic groupware', - bs: 'bricks-and-clicks target infomediaries' - } + bs: 'bricks-and-clicks target infomediaries', + }, }, { id: 106, @@ -2458,16 +2458,16 @@ export const users = [ zipcode: '42701-0622', geo: { lat: '-29.4451', - lng: '140.4534' - } + lng: '140.4534', + }, }, phone: '991-451-9465', website: 'https://tess.org', company: { name: 'Mosciski and Sons', catchPhrase: 'Customizable upward-trending customer loyalty', - bs: 'ubiquitous incubate e-tailers' - } + bs: 'ubiquitous incubate e-tailers', + }, }, { id: 107, @@ -2481,16 +2481,16 @@ export const users = [ zipcode: '90020-9799', geo: { lat: '16.4053', - lng: '92.7847' - } + lng: '92.7847', + }, }, phone: '196.665.1727', website: 'https://marco.biz', company: { name: 'Nikolaus, Moore and Roberts', catchPhrase: 'Secured uniform circuit', - bs: 'killer maximize web-readiness' - } + bs: 'killer maximize web-readiness', + }, }, { id: 108, @@ -2504,16 +2504,16 @@ export const users = [ zipcode: '26592-1014', geo: { lat: '21.8363', - lng: '18.4790' - } + lng: '18.4790', + }, }, phone: '420.158.8244', website: 'https://katlyn.info', company: { name: 'DuBuque, Robel and Reichert', catchPhrase: 'Reverse-engineered motivating contingency', - bs: 'synergistic integrate action-items' - } + bs: 'synergistic integrate action-items', + }, }, { id: 109, @@ -2527,16 +2527,16 @@ export const users = [ zipcode: '82369', geo: { lat: '3.7958', - lng: '-125.6823' - } + lng: '-125.6823', + }, }, phone: '153.380.6588', website: 'http://perry.info', company: { name: 'Mann Group', catchPhrase: 'Balanced discrete array', - bs: 'back-end exploit niches' - } + bs: 'back-end exploit niches', + }, }, { id: 110, @@ -2550,16 +2550,16 @@ export const users = [ zipcode: '22172-1325', geo: { lat: '-65.8151', - lng: '-0.0631' - } + lng: '-0.0631', + }, }, phone: '874.284.2442 x781', website: 'http://dallas.info', company: { name: 'Fritsch - Collins', catchPhrase: 'Secured web-enabled policy', - bs: 'e-business visualize paradigms' - } + bs: 'e-business visualize paradigms', + }, }, { id: 111, @@ -2573,16 +2573,16 @@ export const users = [ zipcode: '71283-4210', geo: { lat: '-0.4917', - lng: '-70.9884' - } + lng: '-70.9884', + }, }, phone: '1-568-294-6766', website: 'https://danyka.name', company: { name: 'Cronin Inc', catchPhrase: 'Cross-platform holistic software', - bs: 'clicks-and-mortar iterate networks' - } + bs: 'clicks-and-mortar iterate networks', + }, }, { id: 112, @@ -2596,16 +2596,16 @@ export const users = [ zipcode: '63087-5474', geo: { lat: '38.3892', - lng: '-79.0954' - } + lng: '-79.0954', + }, }, phone: '567.183.2129 x42864', website: 'http://kathryn.net', company: { name: 'Weissnat LLC', catchPhrase: 'Reverse-engineered reciprocal migration', - bs: 'magnetic embrace users' - } + bs: 'magnetic embrace users', + }, }, { id: 113, @@ -2619,16 +2619,16 @@ export const users = [ zipcode: '65478-4451', geo: { lat: '54.5651', - lng: '142.5425' - } + lng: '142.5425', + }, }, phone: '086.387.4169 x211', website: 'https://maximillia.com', company: { name: 'Kuvalis Group', catchPhrase: 'Multi-tiered global benchmark', - bs: 'e-business enhance functionalities' - } + bs: 'e-business enhance functionalities', + }, }, { id: 114, @@ -2642,16 +2642,16 @@ export const users = [ zipcode: '07861-2741', geo: { lat: '-25.1232', - lng: '-105.0616' - } + lng: '-105.0616', + }, }, phone: '(853) 099-1884', website: 'https://silas.biz', company: { name: 'VonRueden, Langosh and Hoppe', catchPhrase: 'Exclusive local help-desk', - bs: 'sticky implement relationships' - } + bs: 'sticky implement relationships', + }, }, { id: 115, @@ -2665,16 +2665,16 @@ export const users = [ zipcode: '53160', geo: { lat: '55.7461', - lng: '174.0497' - } + lng: '174.0497', + }, }, phone: '1-914-184-8099', website: 'https://johnny.com', company: { name: 'Muller and Sons', catchPhrase: 'Secured local protocol', - bs: '24/7 visualize relationships' - } + bs: '24/7 visualize relationships', + }, }, { id: 116, @@ -2688,16 +2688,16 @@ export const users = [ zipcode: '83704', geo: { lat: '81.9094', - lng: '-35.6844' - } + lng: '-35.6844', + }, }, phone: '1-066-763-2103', website: 'https://daphnee.info', company: { name: 'Haag - Vandervort', catchPhrase: 'Quality-focused motivating function', - bs: 'robust synthesize e-services' - } + bs: 'robust synthesize e-services', + }, }, { id: 117, @@ -2711,16 +2711,16 @@ export const users = [ zipcode: '97175', geo: { lat: '59.8237', - lng: '150.3200' - } + lng: '150.3200', + }, }, phone: '555.165.4321 x2867', website: 'http://kavon.name', company: { name: 'Kris - Medhurst', catchPhrase: 'Customer-focused systemic toolset', - bs: 'transparent e-enable architectures' - } + bs: 'transparent e-enable architectures', + }, }, { id: 118, @@ -2734,16 +2734,16 @@ export const users = [ zipcode: '41975', geo: { lat: '6.7553', - lng: '-68.2703' - } + lng: '-68.2703', + }, }, phone: '(508) 930-1673', website: 'http://theo.biz', company: { name: "O'Kon, Jast and Luettgen", catchPhrase: 'Cross-group hybrid implementation', - bs: 'bleeding-edge leverage users' - } + bs: 'bleeding-edge leverage users', + }, }, { id: 119, @@ -2757,16 +2757,16 @@ export const users = [ zipcode: '53463', geo: { lat: '-36.6625', - lng: '-132.8805' - } + lng: '-132.8805', + }, }, phone: '849.670.5306', website: 'http://emmet.info', company: { name: 'Schowalter - Walter', catchPhrase: 'Persevering global circuit', - bs: 'rich transition e-commerce' - } + bs: 'rich transition e-commerce', + }, }, { id: 120, @@ -2780,16 +2780,16 @@ export const users = [ zipcode: '51016', geo: { lat: '-30.6892', - lng: '-170.1011' - } + lng: '-170.1011', + }, }, phone: '962-757-4645 x00273', website: 'http://khalil.info', company: { name: 'Kiehn - Blick', catchPhrase: 'Up-sized scalable moderator', - bs: 'magnetic streamline communities' - } + bs: 'magnetic streamline communities', + }, }, { id: 121, @@ -2803,16 +2803,16 @@ export const users = [ zipcode: '99724-6345', geo: { lat: '-43.2377', - lng: '-88.0741' - } + lng: '-88.0741', + }, }, phone: '1-805-488-8800 x6452', website: 'https://rogers.com', company: { name: 'Ferry - Brakus', catchPhrase: 'Organic leading edge focus group', - bs: 'clicks-and-mortar transition experiences' - } + bs: 'clicks-and-mortar transition experiences', + }, }, { id: 122, @@ -2826,16 +2826,16 @@ export const users = [ zipcode: '07592', geo: { lat: '72.5363', - lng: '82.8981' - } + lng: '82.8981', + }, }, phone: '000.119.1280', website: 'http://mitchel.org', company: { name: 'Metz and Sons', catchPhrase: 'Managed scalable focus group', - bs: 'bricks-and-clicks expedite models' - } + bs: 'bricks-and-clicks expedite models', + }, }, { id: 123, @@ -2849,16 +2849,16 @@ export const users = [ zipcode: '37950-6767', geo: { lat: '-37.3427', - lng: '157.5678' - } + lng: '157.5678', + }, }, phone: '(938) 804-2336', website: 'http://polly.info', company: { name: 'West - Nienow', catchPhrase: 'Virtual reciprocal flexibility', - bs: 'end-to-end implement interfaces' - } + bs: 'end-to-end implement interfaces', + }, }, { id: 124, @@ -2872,16 +2872,16 @@ export const users = [ zipcode: '94498-9238', geo: { lat: '-78.6177', - lng: '163.3573' - } + lng: '163.3573', + }, }, phone: '405.174.0466 x512', website: 'https://gino.net', company: { name: 'Baumbach - McGlynn', catchPhrase: 'Balanced background ability', - bs: 'bleeding-edge morph content' - } + bs: 'bleeding-edge morph content', + }, }, { id: 125, @@ -2895,16 +2895,16 @@ export const users = [ zipcode: '88172', geo: { lat: '86.7121', - lng: '-169.0396' - } + lng: '-169.0396', + }, }, phone: '1-488-147-8969 x786', website: 'http://hettie.net', company: { name: 'Price - Renner', catchPhrase: 'Polarised context-sensitive neural-net', - bs: 'intuitive recontextualize web-readiness' - } + bs: 'intuitive recontextualize web-readiness', + }, }, { id: 126, @@ -2918,16 +2918,16 @@ export const users = [ zipcode: '38229-5786', geo: { lat: '54.7461', - lng: '-89.0284' - } + lng: '-89.0284', + }, }, phone: '343.453.9981 x34551', website: 'http://erin.net', company: { name: 'Wilderman - Konopelski', catchPhrase: 'Integrated composite product', - bs: 'vertical recontextualize eyeballs' - } + bs: 'vertical recontextualize eyeballs', + }, }, { id: 127, @@ -2941,16 +2941,16 @@ export const users = [ zipcode: '96869-0185', geo: { lat: '3.2380', - lng: '-40.8033' - } + lng: '-40.8033', + }, }, phone: '1-342-371-8699 x00709', website: 'http://bennie.net', company: { name: 'Sauer LLC', catchPhrase: 'Seamless object-oriented intranet', - bs: 'global innovate e-services' - } + bs: 'global innovate e-services', + }, }, { id: 128, @@ -2964,16 +2964,16 @@ export const users = [ zipcode: '63438', geo: { lat: '-1.5387', - lng: '95.1295' - } + lng: '95.1295', + }, }, phone: '1-407-889-9658 x2833', website: 'http://jadyn.com', company: { name: 'Ward, Ondricka and Bergnaum', catchPhrase: 'Enterprise-wide optimizing focus group', - bs: 'global unleash convergence' - } + bs: 'global unleash convergence', + }, }, { id: 129, @@ -2987,16 +2987,16 @@ export const users = [ zipcode: '48557-5279', geo: { lat: '-45.3541', - lng: '92.9969' - } + lng: '92.9969', + }, }, phone: '395.315.2047', website: 'http://keira.biz', company: { name: 'Schaden and Sons', catchPhrase: 'Monitored local framework', - bs: 'sexy scale platforms' - } + bs: 'sexy scale platforms', + }, }, { id: 130, @@ -3010,16 +3010,16 @@ export const users = [ zipcode: '15425-8993', geo: { lat: '14.1489', - lng: '106.9870' - } + lng: '106.9870', + }, }, phone: '471-051-6237', website: 'https://verna.com', company: { name: 'Wolf LLC', catchPhrase: 'User-centric actuating definition', - bs: '24/365 engineer systems' - } + bs: '24/365 engineer systems', + }, }, { id: 131, @@ -3033,16 +3033,16 @@ export const users = [ zipcode: '73891-8066', geo: { lat: '52.9044', - lng: '85.1540' - } + lng: '85.1540', + }, }, phone: '1-035-110-4360 x19717', website: 'https://alberto.org', company: { name: 'Beier, Larson and Hyatt', catchPhrase: 'Synergistic next generation protocol', - bs: 'bricks-and-clicks generate portals' - } + bs: 'bricks-and-clicks generate portals', + }, }, { id: 132, @@ -3056,16 +3056,16 @@ export const users = [ zipcode: '43905', geo: { lat: '-23.4321', - lng: '65.2211' - } + lng: '65.2211', + }, }, phone: '295-026-6541 x68149', website: 'https://lora.biz', company: { name: 'Jacobs LLC', catchPhrase: 'Compatible tangible product', - bs: 'strategic scale networks' - } + bs: 'strategic scale networks', + }, }, { id: 133, @@ -3079,16 +3079,16 @@ export const users = [ zipcode: '70456-5818', geo: { lat: '-83.9300', - lng: '-118.7351' - } + lng: '-118.7351', + }, }, phone: '1-824-306-5967', website: 'https://alexandrea.org', company: { name: 'Jaskolski Inc', catchPhrase: 'Managed non-volatile database', - bs: 'proactive optimize applications' - } + bs: 'proactive optimize applications', + }, }, { id: 134, @@ -3102,16 +3102,16 @@ export const users = [ zipcode: '35847', geo: { lat: '-56.7484', - lng: '-130.1340' - } + lng: '-130.1340', + }, }, phone: '(980) 395-0514', website: 'https://nat.biz', company: { name: "Crona, O'Hara and Mante", catchPhrase: 'Object-based mobile secured line', - bs: 'front-end facilitate niches' - } + bs: 'front-end facilitate niches', + }, }, { id: 135, @@ -3125,16 +3125,16 @@ export const users = [ zipcode: '94726', geo: { lat: '2.9757', - lng: '-113.9569' - } + lng: '-113.9569', + }, }, phone: '148.284.3992 x6831', website: 'http://sheila.com', company: { name: 'Mayer - Huel', catchPhrase: 'De-engineered bandwidth-monitored model', - bs: 'clicks-and-mortar enable experiences' - } + bs: 'clicks-and-mortar enable experiences', + }, }, { id: 136, @@ -3148,16 +3148,16 @@ export const users = [ zipcode: '45254', geo: { lat: '-31.0835', - lng: '45.7616' - } + lng: '45.7616', + }, }, phone: '466.176.9041 x87775', website: 'http://ronny.biz', company: { name: 'Welch, Collier and Terry', catchPhrase: 'Front-line contextually-based budgetary management', - bs: 'robust benchmark communities' - } + bs: 'robust benchmark communities', + }, }, { id: 137, @@ -3171,16 +3171,16 @@ export const users = [ zipcode: '15987-3499', geo: { lat: '22.6235', - lng: '-60.6879' - } + lng: '-60.6879', + }, }, phone: '538.748.2893', website: 'http://aurore.name', company: { name: 'Ondricka - Corwin', catchPhrase: 'Reduced didactic algorithm', - bs: 'mission-critical reinvent synergies' - } + bs: 'mission-critical reinvent synergies', + }, }, { id: 138, @@ -3194,16 +3194,16 @@ export const users = [ zipcode: '21731-3857', geo: { lat: '17.1981', - lng: '-108.2013' - } + lng: '-108.2013', + }, }, phone: '1-283-675-6341', website: 'http://kraig.com', company: { name: 'Wilkinson, Corkery and Jones', catchPhrase: 'Customer-focused attitude-oriented solution', - bs: 'interactive grow architectures' - } + bs: 'interactive grow architectures', + }, }, { id: 139, @@ -3217,16 +3217,16 @@ export const users = [ zipcode: '90093-4014', geo: { lat: '39.5972', - lng: '-65.3742' - } + lng: '-65.3742', + }, }, phone: '1-672-898-3551', website: 'http://gage.biz', company: { name: 'Lang - Homenick', catchPhrase: 'Multi-lateral leading edge standardization', - bs: 'interactive benchmark web-readiness' - } + bs: 'interactive benchmark web-readiness', + }, }, { id: 140, @@ -3240,16 +3240,16 @@ export const users = [ zipcode: '00350-8359', geo: { lat: '47.5192', - lng: '-62.3623' - } + lng: '-62.3623', + }, }, phone: '435.303.8316 x5624', website: 'https://reanna.com', company: { name: 'Stoltenberg, Block and Cruickshank', catchPhrase: 'Optional client-server infrastructure', - bs: 'B2B synergize platforms' - } + bs: 'B2B synergize platforms', + }, }, { id: 141, @@ -3263,16 +3263,16 @@ export const users = [ zipcode: '06704', geo: { lat: '18.6376', - lng: '-119.4089' - } + lng: '-119.4089', + }, }, phone: '(580) 811-3875 x814', website: 'https://vallie.info', company: { name: 'Cole - Lubowitz', catchPhrase: 'Digitized tangible attitude', - bs: 'innovative empower portals' - } + bs: 'innovative empower portals', + }, }, { id: 142, @@ -3286,16 +3286,16 @@ export const users = [ zipcode: '67184-9727', geo: { lat: '58.9385', - lng: '-62.0907' - } + lng: '-62.0907', + }, }, phone: '406.396.8672 x6775', website: 'http://chloe.biz', company: { name: 'Ward - Bechtelar', catchPhrase: 'Business-focused high-level artificial intelligence', - bs: 'value-added scale users' - } + bs: 'value-added scale users', + }, }, { id: 143, @@ -3309,16 +3309,16 @@ export const users = [ zipcode: '69828-6915', geo: { lat: '-22.5376', - lng: '36.2871' - } + lng: '36.2871', + }, }, phone: '1-755-123-7309', website: 'http://stewart.net', company: { name: 'Reichel LLC', catchPhrase: 'Automated dedicated hardware', - bs: 'bricks-and-clicks incubate e-services' - } + bs: 'bricks-and-clicks incubate e-services', + }, }, { id: 144, @@ -3332,16 +3332,16 @@ export const users = [ zipcode: '45655', geo: { lat: '-26.6781', - lng: '72.0338' - } + lng: '72.0338', + }, }, phone: '1-943-849-3294 x3586', website: 'https://anissa.name', company: { name: 'Ferry - Weimann', catchPhrase: 'Profound leading edge info-mediaries', - bs: 'holistic embrace web-readiness' - } + bs: 'holistic embrace web-readiness', + }, }, { id: 145, @@ -3355,16 +3355,16 @@ export const users = [ zipcode: '11972', geo: { lat: '-55.9170', - lng: '108.3257' - } + lng: '108.3257', + }, }, phone: '1-329-470-1125 x4727', website: 'https://marge.org', company: { name: 'Dooley and Sons', catchPhrase: 'Decentralized object-oriented customer loyalty', - bs: 'e-business integrate e-markets' - } + bs: 'e-business integrate e-markets', + }, }, { id: 146, @@ -3378,16 +3378,16 @@ export const users = [ zipcode: '70104-2343', geo: { lat: '69.2596', - lng: '-168.5988' - } + lng: '-168.5988', + }, }, phone: '(100) 836-9083', website: 'http://estelle.biz', company: { name: 'Flatley, Kerluke and Gerhold', catchPhrase: 'Reverse-engineered clear-thinking synergy', - bs: 'turn-key deploy interfaces' - } + bs: 'turn-key deploy interfaces', + }, }, { id: 147, @@ -3401,16 +3401,16 @@ export const users = [ zipcode: '45779-3337', geo: { lat: '83.9748', - lng: '20.2482' - } + lng: '20.2482', + }, }, phone: '227-881-3130 x7653', website: 'http://ferne.org', company: { name: 'Armstrong - Ritchie', catchPhrase: 'Up-sized attitude-oriented methodology', - bs: '24/7 optimize networks' - } + bs: '24/7 optimize networks', + }, }, { id: 148, @@ -3424,16 +3424,16 @@ export const users = [ zipcode: '82540-4714', geo: { lat: '48.7404', - lng: '0.8910' - } + lng: '0.8910', + }, }, phone: '1-574-679-7694 x18266', website: 'https://nick.biz', company: { name: 'Hagenes LLC', catchPhrase: 'Cloned dynamic extranet', - bs: 'user-centric iterate technologies' - } + bs: 'user-centric iterate technologies', + }, }, { id: 149, @@ -3447,16 +3447,16 @@ export const users = [ zipcode: '89302-6437', geo: { lat: '40.9310', - lng: '25.2500' - } + lng: '25.2500', + }, }, phone: '263.976.6257 x37101', website: 'https://herbert.org', company: { name: 'Balistreri, Jacobi and Schultz', catchPhrase: 'Team-oriented neutral intranet', - bs: 'efficient matrix schemas' - } + bs: 'efficient matrix schemas', + }, }, { id: 150, @@ -3470,16 +3470,16 @@ export const users = [ zipcode: '40324-7530', geo: { lat: '36.0667', - lng: '107.2794' - } + lng: '107.2794', + }, }, phone: '1-430-995-5937 x09196', website: 'http://janelle.net', company: { name: 'Gleichner LLC', catchPhrase: 'Customizable multi-state process improvement', - bs: '24/365 visualize convergence' - } + bs: '24/365 visualize convergence', + }, }, { id: 151, @@ -3493,16 +3493,16 @@ export const users = [ zipcode: '13439-5660', geo: { lat: '39.5493', - lng: '-148.5845' - } + lng: '-148.5845', + }, }, phone: '779-542-9044', website: 'https://ada.net', company: { name: 'Collins, Auer and Rodriguez', catchPhrase: 'Fundamental directional hierarchy', - bs: 'end-to-end recontextualize ROI' - } + bs: 'end-to-end recontextualize ROI', + }, }, { id: 152, @@ -3516,16 +3516,16 @@ export const users = [ zipcode: '77946-5115', geo: { lat: '-44.7588', - lng: '139.9189' - } + lng: '139.9189', + }, }, phone: '(393) 500-1047', website: 'http://mabelle.com', company: { name: 'Donnelly - Von', catchPhrase: 'Grass-roots real-time strategy', - bs: 'bricks-and-clicks engineer partnerships' - } + bs: 'bricks-and-clicks engineer partnerships', + }, }, { id: 153, @@ -3539,16 +3539,16 @@ export const users = [ zipcode: '52126-3872', geo: { lat: '77.3056', - lng: '151.1867' - } + lng: '151.1867', + }, }, phone: '(117) 267-9628', website: 'http://jaclyn.org', company: { name: 'Schimmel, Friesen and Schuster', catchPhrase: 'Down-sized maximized parallelism', - bs: 'customized scale interfaces' - } + bs: 'customized scale interfaces', + }, }, { id: 154, @@ -3562,16 +3562,16 @@ export const users = [ zipcode: '73039', geo: { lat: '19.7944', - lng: '9.5775' - } + lng: '9.5775', + }, }, phone: '(062) 501-5282', website: 'http://roel.info', company: { name: 'Stracke LLC', catchPhrase: 'Networked clear-thinking hardware', - bs: 'cross-media unleash convergence' - } + bs: 'cross-media unleash convergence', + }, }, { id: 155, @@ -3585,16 +3585,16 @@ export const users = [ zipcode: '69473', geo: { lat: '-42.9244', - lng: '53.7400' - } + lng: '53.7400', + }, }, phone: '(858) 891-1422 x53358', website: 'https://elfrieda.net', company: { name: 'Lueilwitz - Ebert', catchPhrase: 'Universal asynchronous customer loyalty', - bs: 'transparent empower systems' - } + bs: 'transparent empower systems', + }, }, { id: 156, @@ -3608,16 +3608,16 @@ export const users = [ zipcode: '06087', geo: { lat: '-41.2555', - lng: '-113.8672' - } + lng: '-113.8672', + }, }, phone: '817.944.3327 x6321', website: 'https://nayeli.info', company: { name: 'Rolfson LLC', catchPhrase: 'Digitized cohesive archive', - bs: 'e-business synthesize ROI' - } + bs: 'e-business synthesize ROI', + }, }, { id: 157, @@ -3631,16 +3631,16 @@ export const users = [ zipcode: '78948', geo: { lat: '55.4576', - lng: '41.1028' - } + lng: '41.1028', + }, }, phone: '1-323-410-4409 x751', website: 'http://andres.org', company: { name: 'Yundt and Sons', catchPhrase: 'Expanded encompassing service-desk', - bs: 'e-business matrix eyeballs' - } + bs: 'e-business matrix eyeballs', + }, }, { id: 158, @@ -3654,16 +3654,16 @@ export const users = [ zipcode: '59804-7081', geo: { lat: '56.4961', - lng: '159.3972' - } + lng: '159.3972', + }, }, phone: '059.342.1975 x982', website: 'http://carol.org', company: { name: 'Hoeger - Parker', catchPhrase: 'Open-architected full-range access', - bs: 'global drive experiences' - } + bs: 'global drive experiences', + }, }, { id: 159, @@ -3677,16 +3677,16 @@ export const users = [ zipcode: '63208-6411', geo: { lat: '76.2114', - lng: '34.9024' - } + lng: '34.9024', + }, }, phone: '575-588-0776 x195', website: 'https://germaine.name', company: { name: 'Keeling, Jenkins and Schroeder', catchPhrase: 'Multi-tiered responsive utilisation', - bs: 'end-to-end reintermediate initiatives' - } + bs: 'end-to-end reintermediate initiatives', + }, }, { id: 160, @@ -3700,16 +3700,16 @@ export const users = [ zipcode: '05053', geo: { lat: '82.3032', - lng: '15.9626' - } + lng: '15.9626', + }, }, phone: '(116) 448-4912 x28534', website: 'https://obie.org', company: { name: 'Erdman Inc', catchPhrase: 'Function-based hybrid secured line', - bs: 'compelling reinvent channels' - } + bs: 'compelling reinvent channels', + }, }, { id: 161, @@ -3723,16 +3723,16 @@ export const users = [ zipcode: '00806', geo: { lat: '73.9526', - lng: '-163.5956' - } + lng: '-163.5956', + }, }, phone: '714.806.9898 x79451', website: 'https://price.name', company: { name: 'Maggio - Sipes', catchPhrase: 'Reverse-engineered mission-critical standardization', - bs: 'efficient repurpose synergies' - } + bs: 'efficient repurpose synergies', + }, }, { id: 162, @@ -3746,16 +3746,16 @@ export const users = [ zipcode: '94449', geo: { lat: '-45.8749', - lng: '64.8160' - } + lng: '64.8160', + }, }, phone: '407.681.1564', website: 'http://alison.org', company: { name: 'Gaylord LLC', catchPhrase: 'Business-focused optimal encryption', - bs: 'cross-media facilitate schemas' - } + bs: 'cross-media facilitate schemas', + }, }, { id: 163, @@ -3769,16 +3769,16 @@ export const users = [ zipcode: '11697', geo: { lat: '-29.8612', - lng: '-179.8903' - } + lng: '-179.8903', + }, }, phone: '1-835-750-0701 x52931', website: 'https://derick.org', company: { name: 'Balistreri, Connelly and Koch', catchPhrase: 'Enterprise-wide empowering intranet', - bs: 'interactive maximize niches' - } + bs: 'interactive maximize niches', + }, }, { id: 164, @@ -3792,16 +3792,16 @@ export const users = [ zipcode: '00572-7903', geo: { lat: '46.8386', - lng: '110.5840' - } + lng: '110.5840', + }, }, phone: '566.837.5772 x0943', website: 'https://cassidy.com', company: { name: 'Bradtke Inc', catchPhrase: 'Managed object-oriented monitoring', - bs: 'extensible unleash partnerships' - } + bs: 'extensible unleash partnerships', + }, }, { id: 165, @@ -3815,16 +3815,16 @@ export const users = [ zipcode: '91358-1759', geo: { lat: '-59.7036', - lng: '-121.0587' - } + lng: '-121.0587', + }, }, phone: '1-392-911-4993 x5231', website: 'https://mattie.info', company: { name: 'Konopelski, Mraz and Stokes', catchPhrase: 'Future-proofed background hardware', - bs: 'transparent utilize schemas' - } + bs: 'transparent utilize schemas', + }, }, { id: 166, @@ -3838,16 +3838,16 @@ export const users = [ zipcode: '58284-8114', geo: { lat: '83.0523', - lng: '-94.3037' - } + lng: '-94.3037', + }, }, phone: '1-020-732-2806 x8749', website: 'http://wilmer.info', company: { name: 'Fay - Braun', catchPhrase: 'Visionary maximized hardware', - bs: 'compelling engage schemas' - } + bs: 'compelling engage schemas', + }, }, { id: 167, @@ -3861,16 +3861,16 @@ export const users = [ zipcode: '72481', geo: { lat: '41.2824', - lng: '-30.1285' - } + lng: '-30.1285', + }, }, phone: '1-876-438-4207', website: 'https://brooks.name', company: { name: 'Nikolaus, Smitham and Pfannerstill', catchPhrase: 'Cross-group neutral projection', - bs: 'viral envisioneer initiatives' - } + bs: 'viral envisioneer initiatives', + }, }, { id: 168, @@ -3884,16 +3884,16 @@ export const users = [ zipcode: '18721', geo: { lat: '10.0884', - lng: '-130.8754' - } + lng: '-130.8754', + }, }, phone: '254-735-6646 x76295', website: 'http://jabari.biz', company: { name: 'Morissette Inc', catchPhrase: 'Polarised system-worthy moderator', - bs: 'sticky incentivize channels' - } + bs: 'sticky incentivize channels', + }, }, { id: 169, @@ -3907,16 +3907,16 @@ export const users = [ zipcode: '45646-4142', geo: { lat: '40.9422', - lng: '-106.8673' - } + lng: '-106.8673', + }, }, phone: '1-496-845-9326 x382', website: 'http://marcelino.net', company: { name: 'Bayer - Konopelski', catchPhrase: 'Sharable attitude-oriented solution', - bs: 'revolutionary innovate schemas' - } + bs: 'revolutionary innovate schemas', + }, }, { id: 170, @@ -3930,16 +3930,16 @@ export const users = [ zipcode: '56769-5357', geo: { lat: '-75.7996', - lng: '41.2861' - } + lng: '41.2861', + }, }, phone: '286.873.7062', website: 'https://vance.name', company: { name: 'Dare LLC', catchPhrase: 'Object-based actuating solution', - bs: 'best-of-breed strategize eyeballs' - } + bs: 'best-of-breed strategize eyeballs', + }, }, { id: 171, @@ -3953,16 +3953,16 @@ export const users = [ zipcode: '16368-6554', geo: { lat: '-58.6711', - lng: '26.1820' - } + lng: '26.1820', + }, }, phone: '405-712-9799 x793', website: 'https://kaley.biz', company: { name: "Rolfson, O'Hara and Ankunding", catchPhrase: 'Reactive methodical analyzer', - bs: 'vertical exploit technologies' - } + bs: 'vertical exploit technologies', + }, }, { id: 172, @@ -3976,16 +3976,16 @@ export const users = [ zipcode: '97927', geo: { lat: '80.6328', - lng: '112.7285' - } + lng: '112.7285', + }, }, phone: '615-331-7261 x6950', website: 'http://esta.info', company: { name: 'Senger, Stamm and Dare', catchPhrase: 'Focused systematic moderator', - bs: 'sticky visualize bandwidth' - } + bs: 'sticky visualize bandwidth', + }, }, { id: 173, @@ -3999,16 +3999,16 @@ export const users = [ zipcode: '07048', geo: { lat: '33.0609', - lng: '10.6203' - } + lng: '10.6203', + }, }, phone: '1-450-688-7531', website: 'http://celine.net', company: { name: 'Heaney, Bruen and Tremblay', catchPhrase: 'Organic value-added pricing structure', - bs: 'revolutionary transform portals' - } + bs: 'revolutionary transform portals', + }, }, { id: 174, @@ -4022,16 +4022,16 @@ export const users = [ zipcode: '85136', geo: { lat: '35.9491', - lng: '132.4839' - } + lng: '132.4839', + }, }, phone: '(724) 277-5055 x69380', website: 'https://general.biz', company: { name: 'Carter LLC', catchPhrase: 'Enterprise-wide homogeneous array', - bs: 'synergistic enable infomediaries' - } + bs: 'synergistic enable infomediaries', + }, }, { id: 175, @@ -4045,16 +4045,16 @@ export const users = [ zipcode: '90344', geo: { lat: '8.6937', - lng: '61.4071' - } + lng: '61.4071', + }, }, phone: '199.632.8355', website: 'https://cristobal.org', company: { name: 'VonRueden, Ebert and Runte', catchPhrase: 'Profit-focused bifurcated initiative', - bs: 'B2C evolve channels' - } + bs: 'B2C evolve channels', + }, }, { id: 176, @@ -4068,16 +4068,16 @@ export const users = [ zipcode: '73179', geo: { lat: '15.7517', - lng: '12.2993' - } + lng: '12.2993', + }, }, phone: '1-337-423-6275 x3220', website: 'https://adelia.org', company: { name: 'Carter - Ledner', catchPhrase: 'Enhanced even-keeled open system', - bs: 'e-business morph portals' - } + bs: 'e-business morph portals', + }, }, { id: 177, @@ -4091,16 +4091,16 @@ export const users = [ zipcode: '32993', geo: { lat: '87.1620', - lng: '-100.0199' - } + lng: '-100.0199', + }, }, phone: '904.402.9961 x49967', website: 'https://jayne.name', company: { name: 'Bradtke and Sons', catchPhrase: 'Realigned incremental standardization', - bs: 'plug-and-play syndicate channels' - } + bs: 'plug-and-play syndicate channels', + }, }, { id: 178, @@ -4114,16 +4114,16 @@ export const users = [ zipcode: '52293-7556', geo: { lat: '-32.1078', - lng: '-86.1287' - } + lng: '-86.1287', + }, }, phone: '906.721.7873 x83573', website: 'https://arjun.com', company: { name: 'Metz - Hills', catchPhrase: 'Optimized tertiary extranet', - bs: 'back-end innovate networks' - } + bs: 'back-end innovate networks', + }, }, { id: 179, @@ -4137,16 +4137,16 @@ export const users = [ zipcode: '25502-4104', geo: { lat: '-5.4851', - lng: '80.7066' - } + lng: '80.7066', + }, }, phone: '(807) 480-3197', website: 'https://constance.info', company: { name: "O'Keefe, Mitchell and Farrell", catchPhrase: 'Future-proofed 3rd generation implementation', - bs: 'back-end drive initiatives' - } + bs: 'back-end drive initiatives', + }, }, { id: 180, @@ -4160,16 +4160,16 @@ export const users = [ zipcode: '31715', geo: { lat: '-9.2629', - lng: '-176.3755' - } + lng: '-176.3755', + }, }, phone: '630-391-8741 x81738', website: 'http://daisy.net', company: { name: 'McCullough Inc', catchPhrase: 'Grass-roots dedicated matrices', - bs: 'scalable mesh models' - } + bs: 'scalable mesh models', + }, }, { id: 181, @@ -4183,16 +4183,16 @@ export const users = [ zipcode: '76139-4472', geo: { lat: '-39.2787', - lng: '32.3233' - } + lng: '32.3233', + }, }, phone: '278-488-3579', website: 'http://electa.org', company: { name: 'Stanton, Mosciski and Emmerich', catchPhrase: 'Mandatory scalable moderator', - bs: 'plug-and-play redefine architectures' - } + bs: 'plug-and-play redefine architectures', + }, }, { id: 182, @@ -4206,16 +4206,16 @@ export const users = [ zipcode: '80399-5677', geo: { lat: '16.2746', - lng: '-49.8443' - } + lng: '-49.8443', + }, }, phone: '158-355-0838 x43935', website: 'http://ricardo.name', company: { name: 'Satterfield LLC', catchPhrase: 'Virtual radical adapter', - bs: 'holistic exploit partnerships' - } + bs: 'holistic exploit partnerships', + }, }, { id: 183, @@ -4229,16 +4229,16 @@ export const users = [ zipcode: '05577-6650', geo: { lat: '62.5411', - lng: '-31.0369' - } + lng: '-31.0369', + }, }, phone: '(911) 388-9995 x84276', website: 'http://agustin.name', company: { name: 'Kuhn - Cummings', catchPhrase: 'Configurable full-range extranet', - bs: 'granular drive e-business' - } + bs: 'granular drive e-business', + }, }, { id: 184, @@ -4252,16 +4252,16 @@ export const users = [ zipcode: '50201-5742', geo: { lat: '-11.3137', - lng: '140.1615' - } + lng: '140.1615', + }, }, phone: '245.336.4428', website: 'http://jaida.biz', company: { name: 'Blanda - Gulgowski', catchPhrase: 'Synchronised upward-trending knowledge user', - bs: 'holistic synthesize technologies' - } + bs: 'holistic synthesize technologies', + }, }, { id: 185, @@ -4275,16 +4275,16 @@ export const users = [ zipcode: '90776-0129', geo: { lat: '4.2486', - lng: '-154.0635' - } + lng: '-154.0635', + }, }, phone: '832-277-4640', website: 'https://rafaela.info', company: { name: 'Feest, Tillman and Armstrong', catchPhrase: 'Inverse mobile knowledge user', - bs: 'magnetic iterate functionalities' - } + bs: 'magnetic iterate functionalities', + }, }, { id: 186, @@ -4298,16 +4298,16 @@ export const users = [ zipcode: '24541-7469', geo: { lat: '-78.5662', - lng: '-59.8986' - } + lng: '-59.8986', + }, }, phone: '1-900-085-1645', website: 'http://bryce.name', company: { name: 'Christiansen - Franecki', catchPhrase: 'Synchronised neutral portal', - bs: 'B2C iterate paradigms' - } + bs: 'B2C iterate paradigms', + }, }, { id: 187, @@ -4321,16 +4321,16 @@ export const users = [ zipcode: '38764', geo: { lat: '49.9800', - lng: '-106.0943' - } + lng: '-106.0943', + }, }, phone: '720-578-5019 x348', website: 'http://green.com', company: { name: 'Hoeger - Altenwerth', catchPhrase: 'Multi-lateral foreground portal', - bs: 'robust leverage paradigms' - } + bs: 'robust leverage paradigms', + }, }, { id: 188, @@ -4344,16 +4344,16 @@ export const users = [ zipcode: '55315', geo: { lat: '8.2022', - lng: '170.1033' - } + lng: '170.1033', + }, }, phone: '887-659-3910', website: 'http://felicita.biz', company: { name: 'Kunze and Sons', catchPhrase: 'Organic multimedia moratorium', - bs: 'open-source generate convergence' - } + bs: 'open-source generate convergence', + }, }, { id: 189, @@ -4367,16 +4367,16 @@ export const users = [ zipcode: '05349', geo: { lat: '-8.0788', - lng: '135.5021' - } + lng: '135.5021', + }, }, phone: '488.330.7200 x2892', website: 'http://claudia.net', company: { name: 'Connelly - Fritsch', catchPhrase: 'Quality-focused bottom-line open architecture', - bs: 'plug-and-play embrace channels' - } + bs: 'plug-and-play embrace channels', + }, }, { id: 190, @@ -4390,16 +4390,16 @@ export const users = [ zipcode: '78043', geo: { lat: '-59.3115', - lng: '17.9071' - } + lng: '17.9071', + }, }, phone: '423-295-3205', website: 'http://joey.com', company: { name: 'Kiehn, Bernier and Roberts', catchPhrase: 'Realigned high-level implementation', - bs: 'revolutionary orchestrate infomediaries' - } + bs: 'revolutionary orchestrate infomediaries', + }, }, { id: 191, @@ -4413,16 +4413,16 @@ export const users = [ zipcode: '30239', geo: { lat: '-22.7987', - lng: '-69.8897' - } + lng: '-69.8897', + }, }, phone: '(557) 163-9708 x5850', website: 'https://ben.org', company: { name: 'Rath and Sons', catchPhrase: 'Front-line systematic analyzer', - bs: 'back-end incentivize channels' - } + bs: 'back-end incentivize channels', + }, }, { id: 192, @@ -4436,16 +4436,16 @@ export const users = [ zipcode: '66614-3276', geo: { lat: '-31.7810', - lng: '151.1323' - } + lng: '151.1323', + }, }, phone: '942.434.7544 x430', website: 'https://marcelina.org', company: { name: 'Thompson Group', catchPhrase: 'Inverse modular standardization', - bs: 'clicks-and-mortar deploy infomediaries' - } + bs: 'clicks-and-mortar deploy infomediaries', + }, }, { id: 193, @@ -4459,16 +4459,16 @@ export const users = [ zipcode: '74583', geo: { lat: '21.5668', - lng: '-143.6273' - } + lng: '-143.6273', + }, }, phone: '236-422-5584 x349', website: 'http://hallie.net', company: { name: 'Beahan, Roob and Corkery', catchPhrase: 'Streamlined multi-tasking hub', - bs: 'virtual utilize convergence' - } + bs: 'virtual utilize convergence', + }, }, { id: 194, @@ -4482,16 +4482,16 @@ export const users = [ zipcode: '33090-8481', geo: { lat: '86.8576', - lng: '-72.2067' - } + lng: '-72.2067', + }, }, phone: '1-540-500-2568', website: 'http://cullen.com', company: { name: 'Daniel Group', catchPhrase: 'Profit-focused zero administration workforce', - bs: 'collaborative redefine e-services' - } + bs: 'collaborative redefine e-services', + }, }, { id: 195, @@ -4505,16 +4505,16 @@ export const users = [ zipcode: '26002', geo: { lat: '40.4537', - lng: '139.1726' - } + lng: '139.1726', + }, }, phone: '068-577-8321', website: 'http://emilie.name', company: { name: 'McKenzie - Nitzsche', catchPhrase: 'Streamlined stable standardization', - bs: 'e-business matrix solutions' - } + bs: 'e-business matrix solutions', + }, }, { id: 196, @@ -4528,16 +4528,16 @@ export const users = [ zipcode: '06705', geo: { lat: '-13.7147', - lng: '-132.8573' - } + lng: '-132.8573', + }, }, phone: '1-788-855-6963 x2172', website: 'http://paula.com', company: { name: 'Mueller - Reichel', catchPhrase: 'Self-enabling impactful challenge', - bs: 'dot-com whiteboard users' - } + bs: 'dot-com whiteboard users', + }, }, { id: 197, @@ -4551,16 +4551,16 @@ export const users = [ zipcode: '01081', geo: { lat: '-41.1464', - lng: '-115.3182' - } + lng: '-115.3182', + }, }, phone: '318-543-9882', website: 'http://kaylee.org', company: { name: 'Hermann, Ullrich and Toy', catchPhrase: 'Phased well-modulated policy', - bs: 'clicks-and-mortar embrace experiences' - } + bs: 'clicks-and-mortar embrace experiences', + }, }, { id: 198, @@ -4574,16 +4574,16 @@ export const users = [ zipcode: '02928-7824', geo: { lat: '-80.3112', - lng: '-32.8290' - } + lng: '-32.8290', + }, }, phone: '(775) 446-2597 x49511', website: 'https://lera.name', company: { name: 'Zulauf LLC', catchPhrase: 'Implemented responsive forecast', - bs: 'revolutionary empower paradigms' - } + bs: 'revolutionary empower paradigms', + }, }, { id: 199, @@ -4597,16 +4597,16 @@ export const users = [ zipcode: '86221', geo: { lat: '-57.6395', - lng: '18.6893' - } + lng: '18.6893', + }, }, phone: '1-429-953-3294 x04858', website: 'https://eveline.org', company: { name: 'Ledner - McCullough', catchPhrase: 'Quality-focused multimedia adapter', - bs: 'real-time productize content' - } + bs: 'real-time productize content', + }, }, { id: 200, @@ -4620,16 +4620,16 @@ export const users = [ zipcode: '91341', geo: { lat: '30.1134', - lng: '-141.7140' - } + lng: '-141.7140', + }, }, phone: '276.819.5988 x05966', website: 'https://elva.org', company: { name: 'Marks, Bradtke and Goldner', catchPhrase: 'Secured cohesive initiative', - bs: '24/365 incubate platforms' - } + bs: '24/365 incubate platforms', + }, }, { id: 201, @@ -4643,16 +4643,16 @@ export const users = [ zipcode: '67521', geo: { lat: '-22.6732', - lng: '79.4075' - } + lng: '79.4075', + }, }, phone: '(050) 614-5093 x14184', website: 'http://guillermo.org', company: { name: 'Frami, Will and Langosh', catchPhrase: 'Virtual homogeneous support', - bs: 'extensible mesh paradigms' - } + bs: 'extensible mesh paradigms', + }, }, { id: 202, @@ -4666,16 +4666,16 @@ export const users = [ zipcode: '21821-6586', geo: { lat: '-31.9923', - lng: '-22.9900' - } + lng: '-22.9900', + }, }, phone: '1-671-085-3882', website: 'http://giovanni.com', company: { name: 'Hettinger and Sons', catchPhrase: 'Customizable scalable monitoring', - bs: 'impactful matrix relationships' - } + bs: 'impactful matrix relationships', + }, }, { id: 203, @@ -4689,16 +4689,16 @@ export const users = [ zipcode: '76058', geo: { lat: '20.6223', - lng: '5.9444' - } + lng: '5.9444', + }, }, phone: '264.290.0688', website: 'https://coleman.name', company: { name: 'Smith, Jerde and Balistreri', catchPhrase: 'Pre-emptive bottom-line approach', - bs: 'plug-and-play mesh technologies' - } + bs: 'plug-and-play mesh technologies', + }, }, { id: 204, @@ -4712,16 +4712,16 @@ export const users = [ zipcode: '28971-0739', geo: { lat: '76.3505', - lng: '-105.2135' - } + lng: '-105.2135', + }, }, phone: '(659) 423-2728 x00734', website: 'https://matilde.net', company: { name: 'Turcotte, Robel and Cormier', catchPhrase: 'Fully-configurable 4th generation protocol', - bs: 'world-class cultivate eyeballs' - } + bs: 'world-class cultivate eyeballs', + }, }, { id: 205, @@ -4735,16 +4735,16 @@ export const users = [ zipcode: '89394-2495', geo: { lat: '-21.7984', - lng: '-66.3159' - } + lng: '-66.3159', + }, }, phone: '534-551-7347 x87018', website: 'https://judah.com', company: { name: 'Borer - Koss', catchPhrase: 'Realigned grid-enabled moderator', - bs: 'enterprise architect systems' - } + bs: 'enterprise architect systems', + }, }, { id: 206, @@ -4758,16 +4758,16 @@ export const users = [ zipcode: '10942-1074', geo: { lat: '62.1666', - lng: '-149.8147' - } + lng: '-149.8147', + }, }, phone: '1-721-674-9758 x5429', website: 'http://maegan.net', company: { name: 'Deckow - Harber', catchPhrase: 'Advanced multi-tasking emulation', - bs: 'user-centric e-enable architectures' - } + bs: 'user-centric e-enable architectures', + }, }, { id: 207, @@ -4781,16 +4781,16 @@ export const users = [ zipcode: '86172', geo: { lat: '32.3099', - lng: '-161.5277' - } + lng: '-161.5277', + }, }, phone: '424.663.3430 x87223', website: 'http://cristina.com', company: { name: 'Hermiston Group', catchPhrase: 'Persevering empowering project', - bs: 'global architect web-readiness' - } + bs: 'global architect web-readiness', + }, }, { id: 208, @@ -4804,16 +4804,16 @@ export const users = [ zipcode: '92954', geo: { lat: '11.2082', - lng: '-19.6557' - } + lng: '-19.6557', + }, }, phone: '(977) 080-7041', website: 'http://elta.info', company: { name: 'Kris - McClure', catchPhrase: 'Polarised human-resource alliance', - bs: 'efficient incentivize supply-chains' - } + bs: 'efficient incentivize supply-chains', + }, }, { id: 209, @@ -4827,16 +4827,16 @@ export const users = [ zipcode: '22794', geo: { lat: '-71.5564', - lng: '-40.2611' - } + lng: '-40.2611', + }, }, phone: '246-760-6486 x3444', website: 'http://isidro.name', company: { name: 'Kovacek - Farrell', catchPhrase: 'Managed methodical open architecture', - bs: 'customized monetize content' - } + bs: 'customized monetize content', + }, }, { id: 210, @@ -4850,16 +4850,16 @@ export const users = [ zipcode: '79549', geo: { lat: '11.6099', - lng: '-126.2545' - } + lng: '-126.2545', + }, }, phone: '757-858-8432 x269', website: 'https://monroe.net', company: { name: 'Mosciski and Sons', catchPhrase: 'Virtual composite alliance', - bs: 'cutting-edge embrace schemas' - } + bs: 'cutting-edge embrace schemas', + }, }, { id: 211, @@ -4873,16 +4873,16 @@ export const users = [ zipcode: '48467-5435', geo: { lat: '-75.8795', - lng: '-142.0066' - } + lng: '-142.0066', + }, }, phone: '328-855-7614 x26433', website: 'https://monty.org', company: { name: 'Kilback - Considine', catchPhrase: 'Versatile optimal ability', - bs: 'vertical e-enable architectures' - } + bs: 'vertical e-enable architectures', + }, }, { id: 212, @@ -4896,16 +4896,16 @@ export const users = [ zipcode: '95697', geo: { lat: '-16.4683', - lng: '152.0165' - } + lng: '152.0165', + }, }, phone: '(716) 508-8368 x076', website: 'https://meaghan.org', company: { name: 'Spinka - Lowe', catchPhrase: 'Right-sized tangible groupware', - bs: 'interactive synthesize web services' - } + bs: 'interactive synthesize web services', + }, }, { id: 213, @@ -4919,16 +4919,16 @@ export const users = [ zipcode: '21320', geo: { lat: '-45.6760', - lng: '116.0480' - } + lng: '116.0480', + }, }, phone: '682-636-7338', website: 'http://wilfred.biz', company: { name: 'Sipes Group', catchPhrase: 'Centralized modular policy', - bs: 'efficient recontextualize applications' - } + bs: 'efficient recontextualize applications', + }, }, { id: 214, @@ -4942,16 +4942,16 @@ export const users = [ zipcode: '91414', geo: { lat: '-38.3499', - lng: '-73.9195' - } + lng: '-73.9195', + }, }, phone: '508.252.6531', website: 'http://hassan.info', company: { name: 'Gerlach Inc', catchPhrase: 'Organized executive definition', - bs: 'granular generate functionalities' - } + bs: 'granular generate functionalities', + }, }, { id: 215, @@ -4965,16 +4965,16 @@ export const users = [ zipcode: '67185', geo: { lat: '-47.4026', - lng: '-159.6413' - } + lng: '-159.6413', + }, }, phone: '1-907-895-4873 x2135', website: 'https://anna.info', company: { name: 'Runolfsdottir, Stehr and Leuschke', catchPhrase: 'Pre-emptive composite intranet', - bs: 'collaborative benchmark e-business' - } + bs: 'collaborative benchmark e-business', + }, }, { id: 216, @@ -4988,16 +4988,16 @@ export const users = [ zipcode: '14392', geo: { lat: '61.8844', - lng: '119.0984' - } + lng: '119.0984', + }, }, phone: '728.256.3142 x3505', website: 'https://orin.net', company: { name: 'Rempel LLC', catchPhrase: 'Synchronised local success', - bs: 'impactful incubate eyeballs' - } + bs: 'impactful incubate eyeballs', + }, }, { id: 217, @@ -5011,16 +5011,16 @@ export const users = [ zipcode: '06208-3859', geo: { lat: '65.1833', - lng: '166.3896' - } + lng: '166.3896', + }, }, phone: '(181) 343-5318', website: 'https://london.org', company: { name: 'Smith and Sons', catchPhrase: 'Open-source executive moratorium', - bs: 'transparent target methodologies' - } + bs: 'transparent target methodologies', + }, }, { id: 218, @@ -5034,16 +5034,16 @@ export const users = [ zipcode: '79451-3005', geo: { lat: '83.0234', - lng: '-141.8884' - } + lng: '-141.8884', + }, }, phone: '1-409-381-3309', website: 'https://ally.com', company: { name: 'Boyle, Leuschke and Batz', catchPhrase: 'Versatile asynchronous functionalities', - bs: 'efficient transition deliverables' - } + bs: 'efficient transition deliverables', + }, }, { id: 219, @@ -5057,16 +5057,16 @@ export const users = [ zipcode: '84225-8168', geo: { lat: '-71.8295', - lng: '-54.4491' - } + lng: '-54.4491', + }, }, phone: '073-880-3795', website: 'http://logan.info', company: { name: 'Reinger Group', catchPhrase: 'Open-source attitude-oriented benchmark', - bs: 'intuitive empower communities' - } + bs: 'intuitive empower communities', + }, }, { id: 220, @@ -5080,16 +5080,16 @@ export const users = [ zipcode: '30039-7864', geo: { lat: '-70.2396', - lng: '-151.1070' - } + lng: '-151.1070', + }, }, phone: '252-588-2017 x28741', website: 'https://gerardo.biz', company: { name: 'Mann - Greenholt', catchPhrase: 'Optimized contextually-based definition', - bs: 'virtual streamline interfaces' - } + bs: 'virtual streamline interfaces', + }, }, { id: 221, @@ -5103,16 +5103,16 @@ export const users = [ zipcode: '40922', geo: { lat: '-77.6442', - lng: '68.0480' - } + lng: '68.0480', + }, }, phone: '309.100.9082', website: 'https://martina.com', company: { name: 'Legros Group', catchPhrase: 'Streamlined global throughput', - bs: 'ubiquitous empower eyeballs' - } + bs: 'ubiquitous empower eyeballs', + }, }, { id: 222, @@ -5126,16 +5126,16 @@ export const users = [ zipcode: '23327-6656', geo: { lat: '-69.8953', - lng: '-177.6575' - } + lng: '-177.6575', + }, }, phone: '550-502-4387 x19209', website: 'https://ernest.com', company: { name: 'Greenfelder - Hessel', catchPhrase: 'Synergistic leading edge extranet', - bs: 'global productize niches' - } + bs: 'global productize niches', + }, }, { id: 223, @@ -5149,16 +5149,16 @@ export const users = [ zipcode: '30736', geo: { lat: '53.9673', - lng: '-63.6877' - } + lng: '-63.6877', + }, }, phone: '269.240.9462 x6434', website: 'https://shirley.info', company: { name: 'Simonis and Sons', catchPhrase: 'Polarised intangible complexity', - bs: 'strategic implement schemas' - } + bs: 'strategic implement schemas', + }, }, { id: 224, @@ -5172,16 +5172,16 @@ export const users = [ zipcode: '64796', geo: { lat: '-45.4152', - lng: '100.6566' - } + lng: '100.6566', + }, }, phone: '894.977.8168 x1972', website: 'http://brandon.name', company: { name: 'Jacobson LLC', catchPhrase: 'Adaptive transitional adapter', - bs: 'ubiquitous revolutionize solutions' - } + bs: 'ubiquitous revolutionize solutions', + }, }, { id: 225, @@ -5195,16 +5195,16 @@ export const users = [ zipcode: '77922', geo: { lat: '32.5328', - lng: '144.8886' - } + lng: '144.8886', + }, }, phone: '1-420-195-5110 x99688', website: 'https://favian.com', company: { name: 'Stark and Sons', catchPhrase: 'Public-key client-server initiative', - bs: 'collaborative architect infrastructures' - } + bs: 'collaborative architect infrastructures', + }, }, { id: 226, @@ -5218,16 +5218,16 @@ export const users = [ zipcode: '01118', geo: { lat: '76.2920', - lng: '69.7666' - } + lng: '69.7666', + }, }, phone: '855.324.6052', website: 'https://claude.biz', company: { name: 'Collins and Sons', catchPhrase: 'Assimilated composite encryption', - bs: 'extensible transform methodologies' - } + bs: 'extensible transform methodologies', + }, }, { id: 227, @@ -5241,16 +5241,16 @@ export const users = [ zipcode: '56720-9494', geo: { lat: '-6.5939', - lng: '-134.0178' - } + lng: '-134.0178', + }, }, phone: '1-364-453-9645', website: 'http://erling.net', company: { name: 'Sipes - Brakus', catchPhrase: 'Cloned empowering open architecture', - bs: 'extensible monetize initiatives' - } + bs: 'extensible monetize initiatives', + }, }, { id: 228, @@ -5264,16 +5264,16 @@ export const users = [ zipcode: '40566-8336', geo: { lat: '40.1605', - lng: '-106.4633' - } + lng: '-106.4633', + }, }, phone: '(737) 423-2662', website: 'http://abner.com', company: { name: 'Braun Group', catchPhrase: 'Realigned analyzing structure', - bs: 'clicks-and-mortar exploit web-readiness' - } + bs: 'clicks-and-mortar exploit web-readiness', + }, }, { id: 229, @@ -5287,16 +5287,16 @@ export const users = [ zipcode: '56631', geo: { lat: '27.9275', - lng: '10.7197' - } + lng: '10.7197', + }, }, phone: '1-069-137-9883 x8100', website: 'https://elenora.org', company: { name: 'Price and Sons', catchPhrase: 'Synergized contextually-based neural-net', - bs: 'out-of-the-box reintermediate architectures' - } + bs: 'out-of-the-box reintermediate architectures', + }, }, { id: 230, @@ -5310,16 +5310,16 @@ export const users = [ zipcode: '98886', geo: { lat: '-47.1531', - lng: '-55.6781' - } + lng: '-55.6781', + }, }, phone: '583.087.6611 x3436', website: 'http://jaleel.net', company: { name: 'Lakin - Leffler', catchPhrase: 'Up-sized 5th generation task-force', - bs: 'frictionless extend bandwidth' - } + bs: 'frictionless extend bandwidth', + }, }, { id: 231, @@ -5333,16 +5333,16 @@ export const users = [ zipcode: '86554-8842', geo: { lat: '73.8764', - lng: '-124.3671' - } + lng: '-124.3671', + }, }, phone: '374-145-3293 x76822', website: 'http://filomena.biz', company: { name: 'Pagac - Mitchell', catchPhrase: 'Progressive homogeneous definition', - bs: 'transparent deliver synergies' - } + bs: 'transparent deliver synergies', + }, }, { id: 232, @@ -5356,16 +5356,16 @@ export const users = [ zipcode: '70313', geo: { lat: '-58.2511', - lng: '-153.5066' - } + lng: '-153.5066', + }, }, phone: '1-023-876-2465', website: 'http://lonie.net', company: { name: 'Torphy and Sons', catchPhrase: 'Advanced asynchronous interface', - bs: 'vertical matrix web-readiness' - } + bs: 'vertical matrix web-readiness', + }, }, { id: 233, @@ -5379,16 +5379,16 @@ export const users = [ zipcode: '69615-5671', geo: { lat: '-60.9076', - lng: '176.0982' - } + lng: '176.0982', + }, }, phone: '(220) 389-9506', website: 'https://jody.name', company: { name: 'Keebler - Toy', catchPhrase: 'Extended systemic paradigm', - bs: '24/7 optimize applications' - } + bs: '24/7 optimize applications', + }, }, { id: 234, @@ -5402,16 +5402,16 @@ export const users = [ zipcode: '54208', geo: { lat: '-4.8901', - lng: '-105.6503' - } + lng: '-105.6503', + }, }, phone: '434-570-9488', website: 'http://jermaine.info', company: { name: 'Moen Group', catchPhrase: 'Optional secondary capability', - bs: 'proactive synergize eyeballs' - } + bs: 'proactive synergize eyeballs', + }, }, { id: 235, @@ -5425,16 +5425,16 @@ export const users = [ zipcode: '32715', geo: { lat: '-42.4080', - lng: '-51.9988' - } + lng: '-51.9988', + }, }, phone: '306-830-9441 x452', website: 'https://chester.info', company: { name: 'Weimann, Ziemann and Rice', catchPhrase: 'Cross-group multi-state database', - bs: 'efficient disintermediate vortals' - } + bs: 'efficient disintermediate vortals', + }, }, { id: 236, @@ -5448,16 +5448,16 @@ export const users = [ zipcode: '08047-2765', geo: { lat: '-56.7558', - lng: '56.9722' - } + lng: '56.9722', + }, }, phone: '886-412-8843', website: 'http://eda.info', company: { name: 'Dicki - Spencer', catchPhrase: 'Decentralized bifurcated instruction set', - bs: 'clicks-and-mortar visualize channels' - } + bs: 'clicks-and-mortar visualize channels', + }, }, { id: 237, @@ -5471,16 +5471,16 @@ export const users = [ zipcode: '46199', geo: { lat: '50.9128', - lng: '111.4593' - } + lng: '111.4593', + }, }, phone: '369.216.3840 x22353', website: 'https://chasity.biz', company: { name: 'Douglas, Wilkinson and Flatley', catchPhrase: 'Extended static concept', - bs: 'mission-critical strategize e-business' - } + bs: 'mission-critical strategize e-business', + }, }, { id: 238, @@ -5494,16 +5494,16 @@ export const users = [ zipcode: '44322-9613', geo: { lat: '3.8729', - lng: '-1.4680' - } + lng: '-1.4680', + }, }, phone: '(231) 657-6906', website: 'http://price.net', company: { name: 'Veum - Williamson', catchPhrase: 'Advanced encompassing portal', - bs: 'strategic matrix architectures' - } + bs: 'strategic matrix architectures', + }, }, { id: 239, @@ -5517,16 +5517,16 @@ export const users = [ zipcode: '19549-7257', geo: { lat: '-19.8354', - lng: '-156.2347' - } + lng: '-156.2347', + }, }, phone: '(527) 166-3221 x500', website: 'http://zachery.com', company: { name: 'Wilkinson, Friesen and Larkin', catchPhrase: 'Multi-layered heuristic matrices', - bs: 'user-centric integrate experiences' - } + bs: 'user-centric integrate experiences', + }, }, { id: 240, @@ -5540,16 +5540,16 @@ export const users = [ zipcode: '60738-9202', geo: { lat: '-84.1387', - lng: '127.0543' - } + lng: '127.0543', + }, }, phone: '1-300-371-2512 x49511', website: 'https://damaris.biz', company: { name: 'Mills, Moore and Marquardt', catchPhrase: 'Front-line holistic flexibility', - bs: 'collaborative whiteboard content' - } + bs: 'collaborative whiteboard content', + }, }, { id: 241, @@ -5563,16 +5563,16 @@ export const users = [ zipcode: '58933-6108', geo: { lat: '-24.1676', - lng: '-73.5906' - } + lng: '-73.5906', + }, }, phone: '(263) 671-3861', website: 'http://reed.info', company: { name: 'Smitham, Willms and Jacobs', catchPhrase: 'Versatile directional projection', - bs: 'proactive brand paradigms' - } + bs: 'proactive brand paradigms', + }, }, { id: 242, @@ -5586,16 +5586,16 @@ export const users = [ zipcode: '99881', geo: { lat: '-26.3269', - lng: '-140.1168' - } + lng: '-140.1168', + }, }, phone: '574-862-5888', website: 'https://lauretta.org', company: { name: 'Schimmel Inc', catchPhrase: 'Implemented explicit Graphical User Interface', - bs: 'compelling redefine paradigms' - } + bs: 'compelling redefine paradigms', + }, }, { id: 243, @@ -5609,16 +5609,16 @@ export const users = [ zipcode: '76348', geo: { lat: '19.7655', - lng: '-4.6353' - } + lng: '-4.6353', + }, }, phone: '1-593-425-0225 x44913', website: 'http://mathilde.name', company: { name: 'Rippin - Jast', catchPhrase: 'Innovative explicit productivity', - bs: 'transparent optimize e-markets' - } + bs: 'transparent optimize e-markets', + }, }, { id: 244, @@ -5632,16 +5632,16 @@ export const users = [ zipcode: '51679-5937', geo: { lat: '3.2477', - lng: '105.6674' - } + lng: '105.6674', + }, }, phone: '(164) 771-5789 x4696', website: 'http://noel.name', company: { name: 'Breitenberg and Sons', catchPhrase: 'Reduced next generation frame', - bs: 'user-centric incentivize partnerships' - } + bs: 'user-centric incentivize partnerships', + }, }, { id: 245, @@ -5655,16 +5655,16 @@ export const users = [ zipcode: '74845-8397', geo: { lat: '-81.1142', - lng: '-126.0123' - } + lng: '-126.0123', + }, }, phone: '950-790-1352 x225', website: 'http://thea.info', company: { name: 'Kemmer, Altenwerth and Anderson', catchPhrase: 'Cross-group context-sensitive moderator', - bs: 'B2C benchmark web services' - } + bs: 'B2C benchmark web services', + }, }, { id: 246, @@ -5678,16 +5678,16 @@ export const users = [ zipcode: '76469-6532', geo: { lat: '-16.4519', - lng: '28.6246' - } + lng: '28.6246', + }, }, phone: '104-486-0843', website: 'http://ryann.name', company: { name: 'Schuster - Frami', catchPhrase: 'Diverse client-server groupware', - bs: 'seamless embrace paradigms' - } + bs: 'seamless embrace paradigms', + }, }, { id: 247, @@ -5701,16 +5701,16 @@ export const users = [ zipcode: '68176-5940', geo: { lat: '-55.5290', - lng: '-10.3866' - } + lng: '-10.3866', + }, }, phone: '(217) 567-5207 x15733', website: 'https://ed.info', company: { name: 'Effertz, Bashirian and Rath', catchPhrase: 'Networked homogeneous forecast', - bs: 'compelling revolutionize e-business' - } + bs: 'compelling revolutionize e-business', + }, }, { id: 248, @@ -5724,16 +5724,16 @@ export const users = [ zipcode: '22337-8333', geo: { lat: '3.6071', - lng: '-83.6533' - } + lng: '-83.6533', + }, }, phone: '819-908-6571 x976', website: 'https://ashly.name', company: { name: 'Bednar, Abshire and Gaylord', catchPhrase: 'Ergonomic 6th generation initiative', - bs: 'killer engage channels' - } + bs: 'killer engage channels', + }, }, { id: 249, @@ -5747,16 +5747,16 @@ export const users = [ zipcode: '09190', geo: { lat: '82.9694', - lng: '68.1262' - } + lng: '68.1262', + }, }, phone: '434-520-1056', website: 'http://savion.biz', company: { name: "O'Reilly - Skiles", catchPhrase: 'Digitized composite productivity', - bs: 'wireless reinvent supply-chains' - } + bs: 'wireless reinvent supply-chains', + }, }, { id: 250, @@ -5770,16 +5770,16 @@ export const users = [ zipcode: '56681-5785', geo: { lat: '-37.3127', - lng: '-170.3983' - } + lng: '-170.3983', + }, }, phone: '135-777-0536 x73043', website: 'http://dee.net', company: { name: 'Kemmer and Sons', catchPhrase: 'Advanced actuating artificial intelligence', - bs: 'magnetic integrate mindshare' - } + bs: 'magnetic integrate mindshare', + }, }, { id: 251, @@ -5793,16 +5793,16 @@ export const users = [ zipcode: '74956-3375', geo: { lat: '16.3672', - lng: '134.0877' - } + lng: '134.0877', + }, }, phone: '015-113-6282', website: 'http://alia.org', company: { name: 'Gutkowski and Sons', catchPhrase: 'Cross-group coherent artificial intelligence', - bs: 'web-enabled whiteboard supply-chains' - } + bs: 'web-enabled whiteboard supply-chains', + }, }, { id: 252, @@ -5816,16 +5816,16 @@ export const users = [ zipcode: '89394', geo: { lat: '-10.9085', - lng: '-148.1963' - } + lng: '-148.1963', + }, }, phone: '074-755-4592', website: 'http://robb.info', company: { name: 'Shields - Maggio', catchPhrase: 'Optimized value-added ability', - bs: 'next-generation incentivize architectures' - } + bs: 'next-generation incentivize architectures', + }, }, { id: 253, @@ -5839,16 +5839,16 @@ export const users = [ zipcode: '70731', geo: { lat: '-41.9036', - lng: '-82.7874' - } + lng: '-82.7874', + }, }, phone: '1-524-027-9799', website: 'http://donato.org', company: { name: 'Crona, Olson and Cronin', catchPhrase: 'Programmable well-modulated extranet', - bs: 'clicks-and-mortar enhance communities' - } + bs: 'clicks-and-mortar enhance communities', + }, }, { id: 254, @@ -5862,16 +5862,16 @@ export const users = [ zipcode: '17640', geo: { lat: '-46.2146', - lng: '-6.7396' - } + lng: '-6.7396', + }, }, phone: '(464) 657-0369 x019', website: 'http://josiane.info', company: { name: 'Tillman - Mraz', catchPhrase: 'Fully-configurable value-added contingency', - bs: 'e-business matrix channels' - } + bs: 'e-business matrix channels', + }, }, { id: 255, @@ -5885,16 +5885,16 @@ export const users = [ zipcode: '56887-9366', geo: { lat: '-86.1323', - lng: '-32.0898' - } + lng: '-32.0898', + }, }, phone: '590-700-6517', website: 'http://marilie.name', company: { name: 'Bogan LLC', catchPhrase: 'Future-proofed zero defect architecture', - bs: 'one-to-one streamline e-tailers' - } + bs: 'one-to-one streamline e-tailers', + }, }, { id: 256, @@ -5908,16 +5908,16 @@ export const users = [ zipcode: '72354-1887', geo: { lat: '17.3353', - lng: '-51.3526' - } + lng: '-51.3526', + }, }, phone: '(286) 043-2273', website: 'http://dangelo.name', company: { name: 'Glover - Glover', catchPhrase: 'Self-enabling leading edge monitoring', - bs: 'mission-critical grow systems' - } + bs: 'mission-critical grow systems', + }, }, { id: 257, @@ -5931,16 +5931,16 @@ export const users = [ zipcode: '47930-0146', geo: { lat: '-62.9733', - lng: '124.9248' - } + lng: '124.9248', + }, }, phone: '(958) 557-8041', website: 'http://junior.info', company: { name: 'Rippin, Hintz and Weber', catchPhrase: 'Profit-focused discrete Graphical User Interface', - bs: '24/365 facilitate deliverables' - } + bs: '24/365 facilitate deliverables', + }, }, { id: 258, @@ -5954,16 +5954,16 @@ export const users = [ zipcode: '69496-1915', geo: { lat: '-71.9534', - lng: '-100.7813' - } + lng: '-100.7813', + }, }, phone: '(175) 293-6529 x76222', website: 'http://rex.org', company: { name: 'Jacobson, Donnelly and Connelly', catchPhrase: 'Visionary systematic standardization', - bs: 'cutting-edge leverage models' - } + bs: 'cutting-edge leverage models', + }, }, { id: 259, @@ -5977,16 +5977,16 @@ export const users = [ zipcode: '80240-8100', geo: { lat: '-24.5506', - lng: '81.9888' - } + lng: '81.9888', + }, }, phone: '886-255-5753 x916', website: 'http://marilou.com', company: { name: 'Weimann Group', catchPhrase: 'Optional next generation synergy', - bs: 'cutting-edge innovate bandwidth' - } + bs: 'cutting-edge innovate bandwidth', + }, }, { id: 260, @@ -6000,16 +6000,16 @@ export const users = [ zipcode: '05821', geo: { lat: '65.4868', - lng: '-69.4114' - } + lng: '-69.4114', + }, }, phone: '205.627.0068', website: 'http://morris.net', company: { name: 'Hansen, Tremblay and Hayes', catchPhrase: 'Programmable system-worthy encryption', - bs: 'bricks-and-clicks e-enable architectures' - } + bs: 'bricks-and-clicks e-enable architectures', + }, }, { id: 261, @@ -6023,16 +6023,16 @@ export const users = [ zipcode: '59977-9305', geo: { lat: '28.5068', - lng: '-63.4440' - } + lng: '-63.4440', + }, }, phone: '952.455.6700 x39165', website: 'http://albert.name', company: { name: 'Gibson LLC', catchPhrase: 'Compatible zero administration capability', - bs: 'cross-media repurpose markets' - } + bs: 'cross-media repurpose markets', + }, }, { id: 262, @@ -6046,16 +6046,16 @@ export const users = [ zipcode: '30641', geo: { lat: '26.1022', - lng: '-13.3105' - } + lng: '-13.3105', + }, }, phone: '(440) 881-7812 x22570', website: 'https://abraham.com', company: { name: 'McCullough, Parisian and Frami', catchPhrase: 'Stand-alone analyzing analyzer', - bs: 'cross-media target action-items' - } + bs: 'cross-media target action-items', + }, }, { id: 263, @@ -6069,16 +6069,16 @@ export const users = [ zipcode: '60518-1444', geo: { lat: '-7.0791', - lng: '119.1136' - } + lng: '119.1136', + }, }, phone: '987-297-7204', website: 'https://craig.biz', company: { name: 'Orn, Tromp and Huel', catchPhrase: 'Ameliorated cohesive capability', - bs: 'magnetic extend niches' - } + bs: 'magnetic extend niches', + }, }, { id: 264, @@ -6092,16 +6092,16 @@ export const users = [ zipcode: '76692', geo: { lat: '-53.3826', - lng: '103.6707' - } + lng: '103.6707', + }, }, phone: '1-528-846-9696 x27962', website: 'https://lenore.org', company: { name: 'Moen and Sons', catchPhrase: 'Adaptive asymmetric alliance', - bs: 'e-business deliver e-tailers' - } + bs: 'e-business deliver e-tailers', + }, }, { id: 265, @@ -6115,16 +6115,16 @@ export const users = [ zipcode: '79742-0454', geo: { lat: '28.6390', - lng: '141.7310' - } + lng: '141.7310', + }, }, phone: '238.182.3641', website: 'http://taryn.name', company: { name: 'Renner, Collier and Christiansen', catchPhrase: 'Multi-channelled actuating structure', - bs: 'B2C mesh metrics' - } + bs: 'B2C mesh metrics', + }, }, { id: 266, @@ -6138,16 +6138,16 @@ export const users = [ zipcode: '56286', geo: { lat: '-74.2134', - lng: '107.5804' - } + lng: '107.5804', + }, }, phone: '1-066-630-2802 x577', website: 'http://clay.biz', company: { name: 'MacGyver - Bednar', catchPhrase: 'De-engineered modular project', - bs: 'viral embrace technologies' - } + bs: 'viral embrace technologies', + }, }, { id: 267, @@ -6161,16 +6161,16 @@ export const users = [ zipcode: '77075', geo: { lat: '44.6079', - lng: '-112.3936' - } + lng: '-112.3936', + }, }, phone: '704.629.3894 x5517', website: 'http://lourdes.name', company: { name: 'Swaniawski LLC', catchPhrase: 'Automated multimedia projection', - bs: 'open-source generate metrics' - } + bs: 'open-source generate metrics', + }, }, { id: 268, @@ -6184,16 +6184,16 @@ export const users = [ zipcode: '07981-7984', geo: { lat: '22.0039', - lng: '-98.1547' - } + lng: '-98.1547', + }, }, phone: '067.410.8040 x958', website: 'https://wellington.name', company: { name: 'Kerluke - Oberbrunner', catchPhrase: 'Fully-configurable reciprocal conglomeration', - bs: 'turn-key innovate e-business' - } + bs: 'turn-key innovate e-business', + }, }, { id: 269, @@ -6207,16 +6207,16 @@ export const users = [ zipcode: '18752-0623', geo: { lat: '48.1618', - lng: '127.0397' - } + lng: '127.0397', + }, }, phone: '(660) 091-8840 x7795', website: 'http://shannon.org', company: { name: 'Zieme - Moore', catchPhrase: 'Networked bi-directional alliance', - bs: 'end-to-end cultivate niches' - } + bs: 'end-to-end cultivate niches', + }, }, { id: 270, @@ -6230,16 +6230,16 @@ export const users = [ zipcode: '83478', geo: { lat: '-14.2495', - lng: '-175.5138' - } + lng: '-175.5138', + }, }, phone: '1-953-109-8971', website: 'https://jackie.net', company: { name: 'Heller - Schultz', catchPhrase: 'Face to face next generation contingency', - bs: 'global iterate supply-chains' - } + bs: 'global iterate supply-chains', + }, }, { id: 271, @@ -6253,16 +6253,16 @@ export const users = [ zipcode: '16495-6394', geo: { lat: '-13.7051', - lng: '51.2423' - } + lng: '51.2423', + }, }, phone: '1-191-933-3128', website: 'http://rusty.com', company: { name: 'Dickinson, Harber and Schoen', catchPhrase: 'Inverse object-oriented neural-net', - bs: 'integrated leverage action-items' - } + bs: 'integrated leverage action-items', + }, }, { id: 272, @@ -6276,16 +6276,16 @@ export const users = [ zipcode: '38559-3000', geo: { lat: '-66.8423', - lng: '70.3851' - } + lng: '70.3851', + }, }, phone: '656-886-0792 x6752', website: 'http://jayne.name', company: { name: 'Marvin, King and Blick', catchPhrase: 'Reactive global access', - bs: 'integrated syndicate web-readiness' - } + bs: 'integrated syndicate web-readiness', + }, }, { id: 273, @@ -6299,16 +6299,16 @@ export const users = [ zipcode: '07186-6377', geo: { lat: '86.9497', - lng: '-118.5594' - } + lng: '-118.5594', + }, }, phone: '(680) 558-3734 x104', website: 'https://ezekiel.info', company: { name: 'Stehr - Haley', catchPhrase: 'Cross-platform intermediate knowledge base', - bs: 'impactful matrix models' - } + bs: 'impactful matrix models', + }, }, { id: 274, @@ -6322,16 +6322,16 @@ export const users = [ zipcode: '30092', geo: { lat: '-10.9291', - lng: '-42.3380' - } + lng: '-42.3380', + }, }, phone: '1-985-393-2518', website: 'https://connor.info', company: { name: 'Maggio - Sauer', catchPhrase: 'User-centric methodical open architecture', - bs: 'real-time enhance content' - } + bs: 'real-time enhance content', + }, }, { id: 275, @@ -6345,16 +6345,16 @@ export const users = [ zipcode: '84709-0819', geo: { lat: '-14.2827', - lng: '136.7600' - } + lng: '136.7600', + }, }, phone: '645-399-1281 x010', website: 'https://reed.com', company: { name: "Rolfson, Mraz and O'Reilly", catchPhrase: 'Profound bandwidth-monitored challenge', - bs: 'holistic e-enable communities' - } + bs: 'holistic e-enable communities', + }, }, { id: 276, @@ -6368,16 +6368,16 @@ export const users = [ zipcode: '24540-2836', geo: { lat: '-47.2093', - lng: '178.4505' - } + lng: '178.4505', + }, }, phone: '983.698.7049 x8902', website: 'http://garett.name', company: { name: 'Jacobs Group', catchPhrase: 'Synergistic hybrid benchmark', - bs: 'cutting-edge iterate applications' - } + bs: 'cutting-edge iterate applications', + }, }, { id: 277, @@ -6391,16 +6391,16 @@ export const users = [ zipcode: '69010-3131', geo: { lat: '60.5638', - lng: '57.9052' - } + lng: '57.9052', + }, }, phone: '829-224-8362', website: 'http://krystel.org', company: { name: 'Turcotte - Fadel', catchPhrase: 'De-engineered bandwidth-monitored core', - bs: 'plug-and-play iterate methodologies' - } + bs: 'plug-and-play iterate methodologies', + }, }, { id: 278, @@ -6414,16 +6414,16 @@ export const users = [ zipcode: '20043', geo: { lat: '-54.1641', - lng: '-8.2305' - } + lng: '-8.2305', + }, }, phone: '796-830-4635 x574', website: 'http://guiseppe.org', company: { name: 'Wisoky - Pagac', catchPhrase: 'Re-contextualized upward-trending budgetary management', - bs: 'rich synthesize vortals' - } + bs: 'rich synthesize vortals', + }, }, { id: 279, @@ -6437,16 +6437,16 @@ export const users = [ zipcode: '82747', geo: { lat: '81.8267', - lng: '10.4304' - } + lng: '10.4304', + }, }, phone: '1-215-668-3311 x0244', website: 'https://rylan.com', company: { name: 'Schaefer LLC', catchPhrase: 'Devolved static capability', - bs: 'integrated grow partnerships' - } + bs: 'integrated grow partnerships', + }, }, { id: 280, @@ -6460,16 +6460,16 @@ export const users = [ zipcode: '63809-9149', geo: { lat: '65.6552', - lng: '-47.0860' - } + lng: '-47.0860', + }, }, phone: '1-488-304-5805 x58216', website: 'http://orpha.org', company: { name: 'Ebert and Sons', catchPhrase: 'Proactive logistical methodology', - bs: 'distributed transform users' - } + bs: 'distributed transform users', + }, }, { id: 281, @@ -6483,16 +6483,16 @@ export const users = [ zipcode: '89483-4174', geo: { lat: '88.1902', - lng: '145.8759' - } + lng: '145.8759', + }, }, phone: '963.998.4220 x62737', website: 'https://westley.org', company: { name: 'Goyette - Yundt', catchPhrase: 'Horizontal heuristic migration', - bs: 'compelling drive markets' - } + bs: 'compelling drive markets', + }, }, { id: 282, @@ -6506,16 +6506,16 @@ export const users = [ zipcode: '42217-6429', geo: { lat: '79.7407', - lng: '-161.0937' - } + lng: '-161.0937', + }, }, phone: '427.116.3311', website: 'http://lina.biz', company: { name: 'Gerhold and Sons', catchPhrase: 'User-centric optimizing extranet', - bs: 'bricks-and-clicks engage convergence' - } + bs: 'bricks-and-clicks engage convergence', + }, }, { id: 283, @@ -6529,16 +6529,16 @@ export const users = [ zipcode: '74442-9704', geo: { lat: '-16.1110', - lng: '-91.4801' - } + lng: '-91.4801', + }, }, phone: '546.517.8533 x826', website: 'http://lucie.org', company: { name: 'Nicolas - McCullough', catchPhrase: 'Programmable regional product', - bs: 'clicks-and-mortar grow applications' - } + bs: 'clicks-and-mortar grow applications', + }, }, { id: 284, @@ -6552,16 +6552,16 @@ export const users = [ zipcode: '22111-4191', geo: { lat: '-40.5977', - lng: '103.5374' - } + lng: '103.5374', + }, }, phone: '1-922-200-2335', website: 'http://turner.name', company: { name: 'Paucek, Hegmann and Rau', catchPhrase: 'Profit-focused even-keeled solution', - bs: 'frictionless synthesize systems' - } + bs: 'frictionless synthesize systems', + }, }, { id: 285, @@ -6575,16 +6575,16 @@ export const users = [ zipcode: '15000', geo: { lat: '-34.9022', - lng: '30.5660' - } + lng: '30.5660', + }, }, phone: '806.170.9226 x903', website: 'http://savannah.org', company: { name: 'Torphy - Pacocha', catchPhrase: 'Compatible background superstructure', - bs: 'dynamic disintermediate architectures' - } + bs: 'dynamic disintermediate architectures', + }, }, { id: 286, @@ -6598,16 +6598,16 @@ export const users = [ zipcode: '14855', geo: { lat: '-59.0589', - lng: '-120.2431' - } + lng: '-120.2431', + }, }, phone: '587-502-6991 x22214', website: 'http://issac.name', company: { name: 'Block and Sons', catchPhrase: 'Multi-layered well-modulated monitoring', - bs: 'dot-com transform methodologies' - } + bs: 'dot-com transform methodologies', + }, }, { id: 287, @@ -6621,16 +6621,16 @@ export const users = [ zipcode: '42916', geo: { lat: '14.3257', - lng: '-168.1642' - } + lng: '-168.1642', + }, }, phone: '630.483.5455', website: 'https://joyce.com', company: { name: 'Windler - Kemmer', catchPhrase: 'Synergistic composite extranet', - bs: 'impactful brand e-business' - } + bs: 'impactful brand e-business', + }, }, { id: 288, @@ -6644,16 +6644,16 @@ export const users = [ zipcode: '01852-0089', geo: { lat: '17.1727', - lng: '175.5318' - } + lng: '175.5318', + }, }, phone: '700-817-9203 x82048', website: 'https://elbert.biz', company: { name: 'Mitchell - Hamill', catchPhrase: 'Enterprise-wide explicit local area network', - bs: 'mission-critical harness markets' - } + bs: 'mission-critical harness markets', + }, }, { id: 289, @@ -6667,16 +6667,16 @@ export const users = [ zipcode: '71135', geo: { lat: '-26.7556', - lng: '14.8899' - } + lng: '14.8899', + }, }, phone: '(245) 857-5592 x924', website: 'http://timmy.biz', company: { name: 'Bartell LLC', catchPhrase: 'Right-sized 4th generation productivity', - bs: 'visionary morph eyeballs' - } + bs: 'visionary morph eyeballs', + }, }, { id: 290, @@ -6690,16 +6690,16 @@ export const users = [ zipcode: '24010-3420', geo: { lat: '-82.2817', - lng: '-80.1249' - } + lng: '-80.1249', + }, }, phone: '442-862-6463 x8860', website: 'http://katheryn.net', company: { name: 'Lockman - Parisian', catchPhrase: 'Robust encompassing time-frame', - bs: 'strategic utilize schemas' - } + bs: 'strategic utilize schemas', + }, }, { id: 291, @@ -6713,16 +6713,16 @@ export const users = [ zipcode: '81230-4289', geo: { lat: '88.9400', - lng: '-174.6731' - } + lng: '-174.6731', + }, }, phone: '664.700.5524 x24935', website: 'http://carleton.org', company: { name: 'Legros and Sons', catchPhrase: 'Enterprise-wide asymmetric superstructure', - bs: 'magnetic benchmark communities' - } + bs: 'magnetic benchmark communities', + }, }, { id: 292, @@ -6736,16 +6736,16 @@ export const users = [ zipcode: '78525-6982', geo: { lat: '0.2145', - lng: '-36.1442' - } + lng: '-36.1442', + }, }, phone: '1-479-000-8873 x50685', website: 'https://jaqueline.info', company: { name: 'Kuvalis LLC', catchPhrase: 'Optional zero tolerance encoding', - bs: 'viral visualize web services' - } + bs: 'viral visualize web services', + }, }, { id: 293, @@ -6759,16 +6759,16 @@ export const users = [ zipcode: '34413', geo: { lat: '54.1431', - lng: '23.4705' - } + lng: '23.4705', + }, }, phone: '(479) 995-5758 x87065', website: 'http://lloyd.org', company: { name: 'Harris, Waters and Schmeler', catchPhrase: 'Organic national help-desk', - bs: 'mission-critical innovate e-tailers' - } + bs: 'mission-critical innovate e-tailers', + }, }, { id: 294, @@ -6782,16 +6782,16 @@ export const users = [ zipcode: '17011-5581', geo: { lat: '31.9334', - lng: '-111.6437' - } + lng: '-111.6437', + }, }, phone: '(808) 475-1056', website: 'https://frank.net', company: { name: 'Altenwerth and Sons', catchPhrase: 'Down-sized value-added info-mediaries', - bs: 'interactive iterate initiatives' - } + bs: 'interactive iterate initiatives', + }, }, { id: 295, @@ -6805,16 +6805,16 @@ export const users = [ zipcode: '37057-8120', geo: { lat: '-11.9700', - lng: '-88.5606' - } + lng: '-88.5606', + }, }, phone: '557-197-5547', website: 'http://alana.info', company: { name: 'Morar, Pfeffer and Swaniawski', catchPhrase: 'Customizable asynchronous collaboration', - bs: 'magnetic empower e-markets' - } + bs: 'magnetic empower e-markets', + }, }, { id: 296, @@ -6828,16 +6828,16 @@ export const users = [ zipcode: '44788-0761', geo: { lat: '4.4801', - lng: '112.9171' - } + lng: '112.9171', + }, }, phone: '463.370.9673', website: 'http://dillon.info', company: { name: 'Hahn Inc', catchPhrase: 'Exclusive heuristic alliance', - bs: 'enterprise expedite vortals' - } + bs: 'enterprise expedite vortals', + }, }, { id: 297, @@ -6851,16 +6851,16 @@ export const users = [ zipcode: '88605-8152', geo: { lat: '-4.5528', - lng: '148.2043' - } + lng: '148.2043', + }, }, phone: '1-361-444-7419 x406', website: 'https://kristoffer.name', company: { name: 'Quitzon - Wiza', catchPhrase: 'Cloned 6th generation function', - bs: 'impactful recontextualize partnerships' - } + bs: 'impactful recontextualize partnerships', + }, }, { id: 298, @@ -6874,16 +6874,16 @@ export const users = [ zipcode: '31267', geo: { lat: '72.6836', - lng: '-74.6081' - } + lng: '-74.6081', + }, }, phone: '(479) 404-2673 x2485', website: 'http://furman.name', company: { name: 'Orn, Abshire and Wilderman', catchPhrase: 'Sharable uniform focus group', - bs: 'strategic mesh supply-chains' - } + bs: 'strategic mesh supply-chains', + }, }, { id: 299, @@ -6897,16 +6897,16 @@ export const users = [ zipcode: '85451', geo: { lat: '63.6311', - lng: '130.1638' - } + lng: '130.1638', + }, }, phone: '1-272-290-6727', website: 'https://durward.com', company: { name: "D'Amore Group", catchPhrase: 'Decentralized disintermediate interface', - bs: 'virtual drive ROI' - } + bs: 'virtual drive ROI', + }, }, { id: 300, @@ -6920,16 +6920,16 @@ export const users = [ zipcode: '15096', geo: { lat: '25.4560', - lng: '46.8287' - } + lng: '46.8287', + }, }, phone: '269-036-8073 x9587', website: 'https://saul.org', company: { name: 'Morar, Renner and Walsh', catchPhrase: 'Down-sized disintermediate function', - bs: 'enterprise embrace bandwidth' - } + bs: 'enterprise embrace bandwidth', + }, }, { id: 301, @@ -6943,16 +6943,16 @@ export const users = [ zipcode: '24478-9464', geo: { lat: '69.3373', - lng: '-92.5534' - } + lng: '-92.5534', + }, }, phone: '1-790-542-8172', website: 'http://sallie.org', company: { name: 'Lueilwitz LLC', catchPhrase: 'Secured demand-driven hierarchy', - bs: 'collaborative engage functionalities' - } + bs: 'collaborative engage functionalities', + }, }, { id: 302, @@ -6966,16 +6966,16 @@ export const users = [ zipcode: '53617-2528', geo: { lat: '-69.6130', - lng: '53.8009' - } + lng: '53.8009', + }, }, phone: '(438) 475-4913 x659', website: 'https://hannah.org', company: { name: 'Mann - Mante', catchPhrase: 'Adaptive background concept', - bs: 'distributed drive technologies' - } + bs: 'distributed drive technologies', + }, }, { id: 303, @@ -6989,16 +6989,16 @@ export const users = [ zipcode: '72984', geo: { lat: '41.7798', - lng: '-54.7890' - } + lng: '-54.7890', + }, }, phone: '254-815-8916', website: 'https://lawrence.net', company: { name: 'Jacobs - McKenzie', catchPhrase: 'Re-engineered eco-centric methodology', - bs: 'customized target communities' - } + bs: 'customized target communities', + }, }, { id: 304, @@ -7012,16 +7012,16 @@ export const users = [ zipcode: '09727-9547', geo: { lat: '60.8465', - lng: '167.7005' - } + lng: '167.7005', + }, }, phone: '1-019-591-2377', website: 'https://vanessa.info', company: { name: 'Hodkiewicz, Haley and Steuber', catchPhrase: 'Down-sized scalable local area network', - bs: 'world-class incentivize functionalities' - } + bs: 'world-class incentivize functionalities', + }, }, { id: 305, @@ -7035,16 +7035,16 @@ export const users = [ zipcode: '67009-2311', geo: { lat: '17.8439', - lng: '78.1985' - } + lng: '78.1985', + }, }, phone: '811-183-1283 x41169', website: 'https://kristopher.name', company: { name: 'Gutmann - Blanda', catchPhrase: 'Polarised discrete conglomeration', - bs: 'viral seize bandwidth' - } + bs: 'viral seize bandwidth', + }, }, { id: 306, @@ -7058,16 +7058,16 @@ export const users = [ zipcode: '91878-3095', geo: { lat: '-75.9808', - lng: '175.8067' - } + lng: '175.8067', + }, }, phone: '959.326.2798', website: 'http://justina.name', company: { name: 'Thompson Group', catchPhrase: 'Persistent static alliance', - bs: 'vertical synergize ROI' - } + bs: 'vertical synergize ROI', + }, }, { id: 307, @@ -7081,16 +7081,16 @@ export const users = [ zipcode: '33116-9460', geo: { lat: '25.5929', - lng: '-70.9553' - } + lng: '-70.9553', + }, }, phone: '1-368-170-0027 x449', website: 'https://assunta.org', company: { name: 'Miller - Kirlin', catchPhrase: 'Total mission-critical projection', - bs: 'value-added enhance portals' - } + bs: 'value-added enhance portals', + }, }, { id: 308, @@ -7104,16 +7104,16 @@ export const users = [ zipcode: '46462', geo: { lat: '81.2075', - lng: '-58.0649' - } + lng: '-58.0649', + }, }, phone: '(335) 313-7638', website: 'http://frederik.com', company: { name: 'Swaniawski, Fisher and Bednar', catchPhrase: 'Virtual context-sensitive pricing structure', - bs: 'one-to-one exploit e-services' - } + bs: 'one-to-one exploit e-services', + }, }, { id: 309, @@ -7127,16 +7127,16 @@ export const users = [ zipcode: '20053-4047', geo: { lat: '52.9881', - lng: '-56.7860' - } + lng: '-56.7860', + }, }, phone: '026.592.9883', website: 'https://melody.org', company: { name: 'Breitenberg - Kozey', catchPhrase: 'Progressive cohesive info-mediaries', - bs: 'visionary optimize schemas' - } + bs: 'visionary optimize schemas', + }, }, { id: 310, @@ -7150,16 +7150,16 @@ export const users = [ zipcode: '44147-2988', geo: { lat: '86.7332', - lng: '104.7476' - } + lng: '104.7476', + }, }, phone: '934.262.5943 x7762', website: 'https://fay.biz', company: { name: 'Gibson - Stark', catchPhrase: 'Realigned leading edge matrices', - bs: 'rich engineer ROI' - } + bs: 'rich engineer ROI', + }, }, { id: 311, @@ -7173,16 +7173,16 @@ export const users = [ zipcode: '02075', geo: { lat: '16.0618', - lng: '-90.1946' - } + lng: '-90.1946', + }, }, phone: '(167) 239-6184 x0639', website: 'http://joshua.name', company: { name: 'Bode - Kirlin', catchPhrase: 'Team-oriented bandwidth-monitored concept', - bs: 'value-added harness functionalities' - } + bs: 'value-added harness functionalities', + }, }, { id: 312, @@ -7196,16 +7196,16 @@ export const users = [ zipcode: '05620', geo: { lat: '18.9121', - lng: '21.0159' - } + lng: '21.0159', + }, }, phone: '530.559.6909', website: 'https://maurine.name', company: { name: 'Kunze Inc', catchPhrase: 'Assimilated interactive matrix', - bs: 'integrated harness mindshare' - } + bs: 'integrated harness mindshare', + }, }, { id: 313, @@ -7219,16 +7219,16 @@ export const users = [ zipcode: '12368-5062', geo: { lat: '-77.5718', - lng: '-29.8548' - } + lng: '-29.8548', + }, }, phone: '706-913-1002 x03698', website: 'http://leonor.info', company: { name: 'Hirthe, Brekke and Rippin', catchPhrase: 'Monitored grid-enabled product', - bs: 'viral reinvent partnerships' - } + bs: 'viral reinvent partnerships', + }, }, { id: 314, @@ -7242,16 +7242,16 @@ export const users = [ zipcode: '79228-1957', geo: { lat: '-69.1598', - lng: '-72.8155' - } + lng: '-72.8155', + }, }, phone: '(260) 226-0763', website: 'https://colby.org', company: { name: 'Grady - Botsford', catchPhrase: 'Adaptive object-oriented hardware', - bs: 'vertical engage solutions' - } + bs: 'vertical engage solutions', + }, }, { id: 315, @@ -7265,16 +7265,16 @@ export const users = [ zipcode: '22482', geo: { lat: '62.0534', - lng: '45.4103' - } + lng: '45.4103', + }, }, phone: '580-620-8811 x25508', website: 'http://dandre.info', company: { name: 'Moore LLC', catchPhrase: 'Profound holistic analyzer', - bs: 'strategic deploy metrics' - } + bs: 'strategic deploy metrics', + }, }, { id: 316, @@ -7288,16 +7288,16 @@ export const users = [ zipcode: '76080', geo: { lat: '-45.5583', - lng: '-58.3168' - } + lng: '-58.3168', + }, }, phone: '274.839.8481 x0017', website: 'http://kane.net', company: { name: 'Larkin, Bashirian and Olson', catchPhrase: 'Cloned scalable methodology', - bs: 'sexy redefine e-business' - } + bs: 'sexy redefine e-business', + }, }, { id: 317, @@ -7311,16 +7311,16 @@ export const users = [ zipcode: '39111', geo: { lat: '82.0888', - lng: '125.2144' - } + lng: '125.2144', + }, }, phone: '1-620-431-9224 x432', website: 'http://mittie.org', company: { name: 'Gutmann LLC', catchPhrase: 'Customizable asymmetric structure', - bs: 'clicks-and-mortar optimize partnerships' - } + bs: 'clicks-and-mortar optimize partnerships', + }, }, { id: 318, @@ -7334,16 +7334,16 @@ export const users = [ zipcode: '65662', geo: { lat: '53.5835', - lng: '155.2310' - } + lng: '155.2310', + }, }, phone: '(166) 555-7630 x244', website: 'http://nelda.com', company: { name: 'Schultz LLC', catchPhrase: 'Quality-focused real-time initiative', - bs: 'magnetic empower e-markets' - } + bs: 'magnetic empower e-markets', + }, }, { id: 319, @@ -7357,16 +7357,16 @@ export const users = [ zipcode: '85577-9253', geo: { lat: '-67.3788', - lng: '-68.7619' - } + lng: '-68.7619', + }, }, phone: '(229) 067-6367', website: 'https://isabelle.info', company: { name: 'Parker Group', catchPhrase: 'Horizontal web-enabled utilisation', - bs: 'synergistic target applications' - } + bs: 'synergistic target applications', + }, }, { id: 320, @@ -7380,16 +7380,16 @@ export const users = [ zipcode: '09718-3030', geo: { lat: '83.6415', - lng: '-93.7916' - } + lng: '-93.7916', + }, }, phone: '296-931-5903 x12575', website: 'http://samara.info', company: { name: 'Huel - Dietrich', catchPhrase: 'Total system-worthy time-frame', - bs: 'world-class exploit systems' - } + bs: 'world-class exploit systems', + }, }, { id: 321, @@ -7403,16 +7403,16 @@ export const users = [ zipcode: '67978-9291', geo: { lat: '-23.6751', - lng: '75.1569' - } + lng: '75.1569', + }, }, phone: '(890) 492-0832 x83366', website: 'https://novella.net', company: { name: 'Barrows Group', catchPhrase: 'Automated transitional leverage', - bs: 'synergistic integrate systems' - } + bs: 'synergistic integrate systems', + }, }, { id: 322, @@ -7426,16 +7426,16 @@ export const users = [ zipcode: '22549-5559', geo: { lat: '59.8045', - lng: '-6.9513' - } + lng: '-6.9513', + }, }, phone: '852.860.0806 x767', website: 'https://mohammad.net', company: { name: 'Nitzsche Group', catchPhrase: 'Face to face 4th generation policy', - bs: 'strategic orchestrate technologies' - } + bs: 'strategic orchestrate technologies', + }, }, { id: 323, @@ -7449,16 +7449,16 @@ export const users = [ zipcode: '03856', geo: { lat: '85.9156', - lng: '147.6200' - } + lng: '147.6200', + }, }, phone: '(798) 415-5607 x1093', website: 'https://brandy.net', company: { name: 'Quitzon, Maggio and Crist', catchPhrase: 'Customer-focused solution-oriented adapter', - bs: 'plug-and-play maximize channels' - } + bs: 'plug-and-play maximize channels', + }, }, { id: 324, @@ -7472,16 +7472,16 @@ export const users = [ zipcode: '65544', geo: { lat: '-84.3917', - lng: '-174.7448' - } + lng: '-174.7448', + }, }, phone: '009.150.4754', website: 'http://leonardo.org', company: { name: 'Hahn - Volkman', catchPhrase: 'Automated user-facing collaboration', - bs: 'virtual benchmark solutions' - } + bs: 'virtual benchmark solutions', + }, }, { id: 325, @@ -7495,16 +7495,16 @@ export const users = [ zipcode: '32174-1472', geo: { lat: '12.0355', - lng: '-148.7739' - } + lng: '-148.7739', + }, }, phone: '377-084-1001 x48888', website: 'http://flo.com', company: { name: 'Mayert - Quigley', catchPhrase: 'Open-architected radical success', - bs: 'vertical implement portals' - } + bs: 'vertical implement portals', + }, }, { id: 326, @@ -7518,16 +7518,16 @@ export const users = [ zipcode: '22734-0740', geo: { lat: '-69.8823', - lng: '24.8969' - } + lng: '24.8969', + }, }, phone: '269.500.7872 x9456', website: 'https://kamille.org', company: { name: 'McGlynn Group', catchPhrase: 'Managed cohesive toolset', - bs: 'user-centric incubate schemas' - } + bs: 'user-centric incubate schemas', + }, }, { id: 327, @@ -7541,16 +7541,16 @@ export const users = [ zipcode: '03386-9610', geo: { lat: '-71.4462', - lng: '150.1236' - } + lng: '150.1236', + }, }, phone: '174-932-2727 x4104', website: 'https://alek.info', company: { name: 'Wolf LLC', catchPhrase: 'Cloned regional synergy', - bs: 'holistic disintermediate methodologies' - } + bs: 'holistic disintermediate methodologies', + }, }, { id: 328, @@ -7564,16 +7564,16 @@ export const users = [ zipcode: '30979', geo: { lat: '28.2108', - lng: '-163.1794' - } + lng: '-163.1794', + }, }, phone: '1-259-234-5626 x953', website: 'http://desiree.org', company: { name: 'Ward - Hammes', catchPhrase: 'Optional zero administration internet solution', - bs: 'out-of-the-box repurpose portals' - } + bs: 'out-of-the-box repurpose portals', + }, }, { id: 329, @@ -7587,16 +7587,16 @@ export const users = [ zipcode: '40401-7874', geo: { lat: '61.7018', - lng: '-124.9934' - } + lng: '-124.9934', + }, }, phone: '572-081-7489', website: 'http://chad.info', company: { name: 'Johns LLC', catchPhrase: 'Realigned client-driven help-desk', - bs: 'front-end empower solutions' - } + bs: 'front-end empower solutions', + }, }, { id: 330, @@ -7610,16 +7610,16 @@ export const users = [ zipcode: '69053', geo: { lat: '67.6303', - lng: '-97.7904' - } + lng: '-97.7904', + }, }, phone: '1-498-106-1983 x66450', website: 'http://matilda.net', company: { name: 'Gerlach, Mann and Legros', catchPhrase: 'Cloned modular projection', - bs: 'bleeding-edge e-enable bandwidth' - } + bs: 'bleeding-edge e-enable bandwidth', + }, }, { id: 331, @@ -7633,16 +7633,16 @@ export const users = [ zipcode: '97975-5706', geo: { lat: '-50.2380', - lng: '77.3068' - } + lng: '77.3068', + }, }, phone: '(494) 545-8973 x336', website: 'https://jayce.net', company: { name: 'Paucek - Tromp', catchPhrase: 'Decentralized 5th generation database', - bs: 'collaborative visualize networks' - } + bs: 'collaborative visualize networks', + }, }, { id: 332, @@ -7656,16 +7656,16 @@ export const users = [ zipcode: '24969', geo: { lat: '10.9820', - lng: '112.0948' - } + lng: '112.0948', + }, }, phone: '1-780-589-5184 x598', website: 'http://delmer.com', company: { name: 'McCullough, Feest and Stark', catchPhrase: 'Multi-lateral hybrid throughput', - bs: 'intuitive synthesize e-tailers' - } + bs: 'intuitive synthesize e-tailers', + }, }, { id: 333, @@ -7679,16 +7679,16 @@ export const users = [ zipcode: '77619', geo: { lat: '66.7958', - lng: '-120.2662' - } + lng: '-120.2662', + }, }, phone: '1-843-179-0502', website: 'https://jerad.info', company: { name: 'Denesik Group', catchPhrase: 'Optional multi-state instruction set', - bs: 'out-of-the-box disintermediate e-commerce' - } + bs: 'out-of-the-box disintermediate e-commerce', + }, }, { id: 334, @@ -7702,16 +7702,16 @@ export const users = [ zipcode: '64449-8341', geo: { lat: '45.1699', - lng: '-74.2898' - } + lng: '-74.2898', + }, }, phone: '280-874-4355 x366', website: 'https://hulda.net', company: { name: "Johnson, O'Conner and Goldner", catchPhrase: 'Up-sized human-resource moratorium', - bs: 'best-of-breed empower infomediaries' - } + bs: 'best-of-breed empower infomediaries', + }, }, { id: 335, @@ -7725,16 +7725,16 @@ export const users = [ zipcode: '30029-2054', geo: { lat: '-9.6162', - lng: '23.7249' - } + lng: '23.7249', + }, }, phone: '143-593-5149', website: 'http://pamela.info', company: { name: "Kohler, O'Kon and Towne", catchPhrase: 'Managed client-server workforce', - bs: 'global target deliverables' - } + bs: 'global target deliverables', + }, }, { id: 336, @@ -7748,16 +7748,16 @@ export const users = [ zipcode: '77360', geo: { lat: '80.0020', - lng: '-137.7872' - } + lng: '-137.7872', + }, }, phone: '(085) 741-6101', website: 'https://zechariah.net', company: { name: 'Bruen - Wolf', catchPhrase: 'Managed bandwidth-monitored archive', - bs: 'granular grow synergies' - } + bs: 'granular grow synergies', + }, }, { id: 337, @@ -7771,16 +7771,16 @@ export const users = [ zipcode: '53917', geo: { lat: '14.1033', - lng: '26.1441' - } + lng: '26.1441', + }, }, phone: '897-465-9628 x887', website: 'https://jamison.name', company: { name: 'Harber - Hoppe', catchPhrase: 'Re-engineered impactful standardization', - bs: 'wireless redefine eyeballs' - } + bs: 'wireless redefine eyeballs', + }, }, { id: 338, @@ -7794,16 +7794,16 @@ export const users = [ zipcode: '66322-1207', geo: { lat: '53.5279', - lng: '-134.2883' - } + lng: '-134.2883', + }, }, phone: '323.857.8142', website: 'https://georgiana.name', company: { name: 'Cole - Kub', catchPhrase: 'Cross-group analyzing benchmark', - bs: 'customized optimize niches' - } + bs: 'customized optimize niches', + }, }, { id: 339, @@ -7817,16 +7817,16 @@ export const users = [ zipcode: '25594-2054', geo: { lat: '53.6064', - lng: '-102.6152' - } + lng: '-102.6152', + }, }, phone: '824.801.9169', website: 'http://theodore.net', company: { name: 'Dicki - Sauer', catchPhrase: 'Visionary next generation parallelism', - bs: 'rich extend channels' - } + bs: 'rich extend channels', + }, }, { id: 340, @@ -7840,16 +7840,16 @@ export const users = [ zipcode: '52371', geo: { lat: '53.6174', - lng: '115.6662' - } + lng: '115.6662', + }, }, phone: '(962) 350-7877 x4499', website: 'http://vance.biz', company: { name: 'Kunde, Block and Abbott', catchPhrase: 'Team-oriented dedicated utilisation', - bs: 'open-source synergize initiatives' - } + bs: 'open-source synergize initiatives', + }, }, { id: 341, @@ -7863,16 +7863,16 @@ export const users = [ zipcode: '24901-4218', geo: { lat: '47.5732', - lng: '-34.6228' - } + lng: '-34.6228', + }, }, phone: '285.736.8996', website: 'http://riley.biz', company: { name: 'Reichert, Herzog and Weissnat', catchPhrase: 'Streamlined needs-based analyzer', - bs: 'vertical integrate functionalities' - } + bs: 'vertical integrate functionalities', + }, }, { id: 342, @@ -7886,16 +7886,16 @@ export const users = [ zipcode: '25121-8673', geo: { lat: '-34.3948', - lng: '-146.2788' - } + lng: '-146.2788', + }, }, phone: '426-317-2046 x9029', website: 'http://christelle.net', company: { name: 'Jones - Casper', catchPhrase: 'Decentralized contextually-based concept', - bs: 'front-end integrate solutions' - } + bs: 'front-end integrate solutions', + }, }, { id: 343, @@ -7909,16 +7909,16 @@ export const users = [ zipcode: '28046-5181', geo: { lat: '69.1788', - lng: '101.9676' - } + lng: '101.9676', + }, }, phone: '162-270-4404 x84897', website: 'https://gino.name', company: { name: 'Keeling, Johnson and Gottlieb', catchPhrase: 'Programmable stable toolset', - bs: 'magnetic unleash portals' - } + bs: 'magnetic unleash portals', + }, }, { id: 344, @@ -7932,16 +7932,16 @@ export const users = [ zipcode: '03184-5905', geo: { lat: '-45.4006', - lng: '-20.7908' - } + lng: '-20.7908', + }, }, phone: '634.210.4944 x3108', website: 'http://annabell.org', company: { name: 'Rohan, Lemke and Hyatt', catchPhrase: 'Networked regional orchestration', - bs: 'robust strategize solutions' - } + bs: 'robust strategize solutions', + }, }, { id: 345, @@ -7955,16 +7955,16 @@ export const users = [ zipcode: '67189', geo: { lat: '-3.8262', - lng: '175.9543' - } + lng: '175.9543', + }, }, phone: '1-495-738-3945 x0632', website: 'https://citlalli.com', company: { name: 'Aufderhar and Sons', catchPhrase: 'Synergistic context-sensitive encryption', - bs: 'sexy synergize models' - } + bs: 'sexy synergize models', + }, }, { id: 346, @@ -7978,16 +7978,16 @@ export const users = [ zipcode: '97898-1649', geo: { lat: '-48.0286', - lng: '167.1960' - } + lng: '167.1960', + }, }, phone: '610.540.3099', website: 'http://colleen.com', company: { name: 'Toy - Wunsch', catchPhrase: 'Diverse needs-based solution', - bs: 'killer engage paradigms' - } + bs: 'killer engage paradigms', + }, }, { id: 347, @@ -8001,16 +8001,16 @@ export const users = [ zipcode: '96355', geo: { lat: '71.3381', - lng: '145.2017' - } + lng: '145.2017', + }, }, phone: '873.090.7447', website: 'http://harmony.com', company: { name: 'Rippin, Wilderman and Flatley', catchPhrase: 'Profound modular approach', - bs: 'holistic scale vortals' - } + bs: 'holistic scale vortals', + }, }, { id: 348, @@ -8024,16 +8024,16 @@ export const users = [ zipcode: '35876-5071', geo: { lat: '85.3333', - lng: '-178.1068' - } + lng: '-178.1068', + }, }, phone: '1-753-301-8022', website: 'https://june.name', company: { name: 'McClure and Sons', catchPhrase: 'Object-based secondary benchmark', - bs: 'synergistic engage niches' - } + bs: 'synergistic engage niches', + }, }, { id: 349, @@ -8047,16 +8047,16 @@ export const users = [ zipcode: '46632-7062', geo: { lat: '-59.5364', - lng: '-170.4360' - } + lng: '-170.4360', + }, }, phone: '(929) 204-0520 x2884', website: 'https://rosemarie.net', company: { name: 'Botsford - Ondricka', catchPhrase: 'Integrated multimedia encoding', - bs: 'integrated facilitate architectures' - } + bs: 'integrated facilitate architectures', + }, }, { id: 350, @@ -8070,16 +8070,16 @@ export const users = [ zipcode: '65852', geo: { lat: '-85.8928', - lng: '-134.6940' - } + lng: '-134.6940', + }, }, phone: '(073) 552-9233 x959', website: 'http://xzavier.com', company: { name: 'Aufderhar Inc', catchPhrase: 'Polarised even-keeled middleware', - bs: 'collaborative envisioneer ROI' - } + bs: 'collaborative envisioneer ROI', + }, }, { id: 351, @@ -8093,16 +8093,16 @@ export const users = [ zipcode: '64749-1698', geo: { lat: '2.2398', - lng: '9.2343' - } + lng: '9.2343', + }, }, phone: '160.873.7872', website: 'https://marjolaine.info', company: { name: 'Krajcik - Kessler', catchPhrase: 'Polarised national policy', - bs: 'holistic scale experiences' - } + bs: 'holistic scale experiences', + }, }, { id: 352, @@ -8116,16 +8116,16 @@ export const users = [ zipcode: '19465-6686', geo: { lat: '-61.9474', - lng: '-123.1270' - } + lng: '-123.1270', + }, }, phone: '1-030-093-4988 x85149', website: 'https://marty.net', company: { name: 'Eichmann, Herzog and Grant', catchPhrase: 'De-engineered 6th generation extranet', - bs: 'virtual deploy action-items' - } + bs: 'virtual deploy action-items', + }, }, { id: 353, @@ -8139,16 +8139,16 @@ export const users = [ zipcode: '00273', geo: { lat: '-18.3514', - lng: '51.1974' - } + lng: '51.1974', + }, }, phone: '935.497.5676', website: 'https://randall.biz', company: { name: 'Nader, Turner and Wintheiser', catchPhrase: 'Multi-channelled zero defect help-desk', - bs: 'revolutionary seize web services' - } + bs: 'revolutionary seize web services', + }, }, { id: 354, @@ -8162,16 +8162,16 @@ export const users = [ zipcode: '30644', geo: { lat: '21.0872', - lng: '19.6209' - } + lng: '19.6209', + }, }, phone: '042-133-2930', website: 'http://jon.name', company: { name: 'Hegmann Inc', catchPhrase: 'Profit-focused mobile concept', - bs: 'synergistic deliver communities' - } + bs: 'synergistic deliver communities', + }, }, { id: 355, @@ -8185,16 +8185,16 @@ export const users = [ zipcode: '11142-6423', geo: { lat: '58.1364', - lng: '-32.0446' - } + lng: '-32.0446', + }, }, phone: '355-175-5770 x846', website: 'http://aaron.com', company: { name: 'King - Gerlach', catchPhrase: 'User-friendly coherent architecture', - bs: 'end-to-end benchmark eyeballs' - } + bs: 'end-to-end benchmark eyeballs', + }, }, { id: 356, @@ -8208,16 +8208,16 @@ export const users = [ zipcode: '44737-4655', geo: { lat: '-9.6148', - lng: '-71.2461' - } + lng: '-71.2461', + }, }, phone: '607.745.5182', website: 'http://brisa.com', company: { name: 'Kessler, Ortiz and McClure', catchPhrase: 'Phased high-level secured line', - bs: 'web-enabled unleash web-readiness' - } + bs: 'web-enabled unleash web-readiness', + }, }, { id: 357, @@ -8231,16 +8231,16 @@ export const users = [ zipcode: '58621', geo: { lat: '88.1660', - lng: '17.4583' - } + lng: '17.4583', + }, }, phone: '(571) 263-8323 x5965', website: 'https://cathryn.org', company: { name: 'Okuneva Inc', catchPhrase: 'Centralized 4th generation instruction set', - bs: 'clicks-and-mortar benchmark vortals' - } + bs: 'clicks-and-mortar benchmark vortals', + }, }, { id: 358, @@ -8254,16 +8254,16 @@ export const users = [ zipcode: '63907-2103', geo: { lat: '-1.9937', - lng: '-138.9381' - } + lng: '-138.9381', + }, }, phone: '(688) 603-6615', website: 'http://isabelle.name', company: { name: 'Pacocha, Ankunding and Lehner', catchPhrase: 'Stand-alone coherent data-warehouse', - bs: 'turn-key incentivize experiences' - } + bs: 'turn-key incentivize experiences', + }, }, { id: 359, @@ -8277,16 +8277,16 @@ export const users = [ zipcode: '36393-3997', geo: { lat: '36.9266', - lng: '36.2638' - } + lng: '36.2638', + }, }, phone: '(129) 387-6619', website: 'http://abraham.name', company: { name: 'Erdman, Zemlak and Effertz', catchPhrase: 'Cloned stable capacity', - bs: 'impactful target solutions' - } + bs: 'impactful target solutions', + }, }, { id: 360, @@ -8300,16 +8300,16 @@ export const users = [ zipcode: '97453-4262', geo: { lat: '75.3074', - lng: '-12.2659' - } + lng: '-12.2659', + }, }, phone: '121-626-2942 x868', website: 'http://iliana.name', company: { name: 'Heaney - Schaden', catchPhrase: 'Stand-alone mission-critical open architecture', - bs: 'best-of-breed redefine schemas' - } + bs: 'best-of-breed redefine schemas', + }, }, { id: 361, @@ -8323,16 +8323,16 @@ export const users = [ zipcode: '03814', geo: { lat: '-15.9588', - lng: '123.6253' - } + lng: '123.6253', + }, }, phone: '424.298.2712 x145', website: 'https://aurelio.org', company: { name: 'Brown, Schumm and Krajcik', catchPhrase: 'Re-contextualized mobile migration', - bs: 'value-added benchmark ROI' - } + bs: 'value-added benchmark ROI', + }, }, { id: 362, @@ -8346,16 +8346,16 @@ export const users = [ zipcode: '15877-4938', geo: { lat: '-0.3138', - lng: '114.9306' - } + lng: '114.9306', + }, }, phone: '991-421-7928 x026', website: 'https://murphy.org', company: { name: 'Durgan - Reichert', catchPhrase: 'Mandatory tertiary budgetary management', - bs: 'innovative enable supply-chains' - } + bs: 'innovative enable supply-chains', + }, }, { id: 363, @@ -8369,16 +8369,16 @@ export const users = [ zipcode: '50128-6883', geo: { lat: '-12.4782', - lng: '136.1240' - } + lng: '136.1240', + }, }, phone: '226.046.7261 x2300', website: 'https://dasia.name', company: { name: 'Predovic - Paucek', catchPhrase: 'Grass-roots directional database', - bs: 'viral harness e-commerce' - } + bs: 'viral harness e-commerce', + }, }, { id: 364, @@ -8392,16 +8392,16 @@ export const users = [ zipcode: '66607', geo: { lat: '49.0022', - lng: '-175.7304' - } + lng: '-175.7304', + }, }, phone: '737-166-6019 x48478', website: 'http://jedidiah.net', company: { name: 'Schowalter, Schuster and Hegmann', catchPhrase: 'Profound mobile paradigm', - bs: 'sticky engage e-business' - } + bs: 'sticky engage e-business', + }, }, { id: 365, @@ -8415,16 +8415,16 @@ export const users = [ zipcode: '49569', geo: { lat: '-72.8492', - lng: '2.6008' - } + lng: '2.6008', + }, }, phone: '1-514-387-5022 x124', website: 'http://althea.com', company: { name: 'Dooley Group', catchPhrase: 'Synergized multimedia success', - bs: 'customized harness synergies' - } + bs: 'customized harness synergies', + }, }, { id: 366, @@ -8438,16 +8438,16 @@ export const users = [ zipcode: '42131', geo: { lat: '-42.8070', - lng: '39.0174' - } + lng: '39.0174', + }, }, phone: '353.793.4823 x882', website: 'http://otha.info', company: { name: 'Weissnat, Kub and Johnston', catchPhrase: 'Ameliorated uniform attitude', - bs: 'out-of-the-box enable platforms' - } + bs: 'out-of-the-box enable platforms', + }, }, { id: 367, @@ -8461,16 +8461,16 @@ export const users = [ zipcode: '38174-5530', geo: { lat: '-57.7612', - lng: '-175.5691' - } + lng: '-175.5691', + }, }, phone: '060-032-7940', website: 'http://jerrold.com', company: { name: 'Yost, Stamm and Renner', catchPhrase: 'Profound stable archive', - bs: 'plug-and-play unleash e-commerce' - } + bs: 'plug-and-play unleash e-commerce', + }, }, { id: 368, @@ -8484,16 +8484,16 @@ export const users = [ zipcode: '56872-9115', geo: { lat: '67.8103', - lng: '43.8374' - } + lng: '43.8374', + }, }, phone: '(630) 298-3589', website: 'https://alvena.com', company: { name: 'Turcotte Group', catchPhrase: 'Mandatory 6th generation frame', - bs: 'robust syndicate schemas' - } + bs: 'robust syndicate schemas', + }, }, { id: 369, @@ -8507,16 +8507,16 @@ export const users = [ zipcode: '96214', geo: { lat: '40.0014', - lng: '-63.9710' - } + lng: '-63.9710', + }, }, phone: '(141) 101-8886 x76851', website: 'http://august.biz', company: { name: 'Haley LLC', catchPhrase: 'Cloned client-server knowledge user', - bs: 'bleeding-edge expedite platforms' - } + bs: 'bleeding-edge expedite platforms', + }, }, { id: 370, @@ -8530,16 +8530,16 @@ export const users = [ zipcode: '79467-9817', geo: { lat: '53.1749', - lng: '-119.6243' - } + lng: '-119.6243', + }, }, phone: '1-617-057-4760 x1680', website: 'https://jerome.name', company: { name: 'VonRueden Group', catchPhrase: 'Advanced multi-state functionalities', - bs: 'interactive harness metrics' - } + bs: 'interactive harness metrics', + }, }, { id: 371, @@ -8553,16 +8553,16 @@ export const users = [ zipcode: '29529-2311', geo: { lat: '-5.9705', - lng: '-97.9131' - } + lng: '-97.9131', + }, }, phone: '326.253.6771 x686', website: 'https://winston.name', company: { name: 'Breitenberg - Bahringer', catchPhrase: 'Streamlined 6th generation matrices', - bs: 'next-generation embrace bandwidth' - } + bs: 'next-generation embrace bandwidth', + }, }, { id: 372, @@ -8576,16 +8576,16 @@ export const users = [ zipcode: '82176-6142', geo: { lat: '-36.3446', - lng: '122.7345' - } + lng: '122.7345', + }, }, phone: '(099) 361-9152 x6688', website: 'https://quincy.net', company: { name: 'Thiel, Jerde and Wunsch', catchPhrase: 'Versatile heuristic encryption', - bs: 'killer envisioneer communities' - } + bs: 'killer envisioneer communities', + }, }, { id: 373, @@ -8599,16 +8599,16 @@ export const users = [ zipcode: '88438-4123', geo: { lat: '-38.9195', - lng: '-34.5548' - } + lng: '-34.5548', + }, }, phone: '356-894-2936', website: 'https://corbin.net', company: { name: 'Price Inc', catchPhrase: 'Future-proofed exuding secured line', - bs: 'vertical synthesize communities' - } + bs: 'vertical synthesize communities', + }, }, { id: 374, @@ -8622,16 +8622,16 @@ export const users = [ zipcode: '84505', geo: { lat: '-39.2725', - lng: '165.2097' - } + lng: '165.2097', + }, }, phone: '(039) 885-4233 x3532', website: 'https://gerry.com', company: { name: 'Koch - Marvin', catchPhrase: 'Streamlined dedicated structure', - bs: 'robust morph action-items' - } + bs: 'robust morph action-items', + }, }, { id: 375, @@ -8645,16 +8645,16 @@ export const users = [ zipcode: '33139-3202', geo: { lat: '-38.2931', - lng: '-119.1934' - } + lng: '-119.1934', + }, }, phone: '(259) 020-1359 x02333', website: 'http://loyal.biz', company: { name: 'McCullough Inc', catchPhrase: 'Programmable contextually-based standardization', - bs: 'dot-com repurpose e-commerce' - } + bs: 'dot-com repurpose e-commerce', + }, }, { id: 376, @@ -8668,16 +8668,16 @@ export const users = [ zipcode: '85724-3540', geo: { lat: '-53.1477', - lng: '-80.8137' - } + lng: '-80.8137', + }, }, phone: '690.291.0052 x703', website: 'http://gisselle.org', company: { name: 'Kshlerin Inc', catchPhrase: 'Expanded directional process improvement', - bs: 'world-class grow methodologies' - } + bs: 'world-class grow methodologies', + }, }, { id: 377, @@ -8691,16 +8691,16 @@ export const users = [ zipcode: '85386-9775', geo: { lat: '-58.2659', - lng: '-135.6136' - } + lng: '-135.6136', + }, }, phone: '137-278-0194', website: 'http://bradford.info', company: { name: 'Murazik - Schmeler', catchPhrase: 'Decentralized encompassing artificial intelligence', - bs: 'innovative reintermediate e-business' - } + bs: 'innovative reintermediate e-business', + }, }, { id: 378, @@ -8714,16 +8714,16 @@ export const users = [ zipcode: '34025-9449', geo: { lat: '-10.1769', - lng: '-51.9973' - } + lng: '-51.9973', + }, }, phone: '1-210-812-4838', website: 'https://keven.biz', company: { name: 'Robel - Langosh', catchPhrase: 'Optimized client-driven collaboration', - bs: 'sexy architect web services' - } + bs: 'sexy architect web services', + }, }, { id: 379, @@ -8737,16 +8737,16 @@ export const users = [ zipcode: '81989-5600', geo: { lat: '22.6871', - lng: '-70.2400' - } + lng: '-70.2400', + }, }, phone: '1-873-826-1933 x5436', website: 'https://imelda.info', company: { name: 'Haag, Wiza and Hoeger', catchPhrase: 'Realigned directional encoding', - bs: 'robust strategize e-business' - } + bs: 'robust strategize e-business', + }, }, { id: 380, @@ -8760,16 +8760,16 @@ export const users = [ zipcode: '52878-5683', geo: { lat: '27.4722', - lng: '-151.5301' - } + lng: '-151.5301', + }, }, phone: '645.132.9039', website: 'https://dion.info', company: { name: 'Osinski - Kuphal', catchPhrase: 'Multi-layered scalable support', - bs: 'efficient iterate partnerships' - } + bs: 'efficient iterate partnerships', + }, }, { id: 381, @@ -8783,16 +8783,16 @@ export const users = [ zipcode: '66497', geo: { lat: '81.7273', - lng: '-119.7930' - } + lng: '-119.7930', + }, }, phone: '(786) 479-4047', website: 'http://marquis.org', company: { name: 'Zemlak - Pfannerstill', catchPhrase: 'Virtual secondary firmware', - bs: 'robust monetize e-business' - } + bs: 'robust monetize e-business', + }, }, { id: 382, @@ -8806,16 +8806,16 @@ export const users = [ zipcode: '16152', geo: { lat: '-78.5066', - lng: '-14.5706' - } + lng: '-14.5706', + }, }, phone: '1-310-808-1407', website: 'https://emanuel.net', company: { name: 'Connelly, Hagenes and Davis', catchPhrase: 'Profound high-level challenge', - bs: 'real-time syndicate infrastructures' - } + bs: 'real-time syndicate infrastructures', + }, }, { id: 383, @@ -8829,16 +8829,16 @@ export const users = [ zipcode: '66923-3387', geo: { lat: '-27.9889', - lng: '7.1022' - } + lng: '7.1022', + }, }, phone: '(457) 643-7576', website: 'https://moses.net', company: { name: 'Reichel - Ebert', catchPhrase: 'Networked system-worthy encryption', - bs: 'frictionless revolutionize supply-chains' - } + bs: 'frictionless revolutionize supply-chains', + }, }, { id: 384, @@ -8852,16 +8852,16 @@ export const users = [ zipcode: '41752', geo: { lat: '-29.5259', - lng: '9.1211' - } + lng: '9.1211', + }, }, phone: '041-976-0507', website: 'https://damon.info', company: { name: 'Bernhard - Powlowski', catchPhrase: 'Cross-platform intermediate workforce', - bs: 'innovative aggregate portals' - } + bs: 'innovative aggregate portals', + }, }, { id: 385, @@ -8875,16 +8875,16 @@ export const users = [ zipcode: '65614-0100', geo: { lat: '-50.7234', - lng: '-146.3991' - } + lng: '-146.3991', + }, }, phone: '1-277-603-0966', website: 'http://alford.biz', company: { name: 'Cormier, Johnson and White', catchPhrase: 'Automated optimizing attitude', - bs: 'world-class transform portals' - } + bs: 'world-class transform portals', + }, }, { id: 386, @@ -8898,16 +8898,16 @@ export const users = [ zipcode: '81695-8663', geo: { lat: '-23.3826', - lng: '-166.0328' - } + lng: '-166.0328', + }, }, phone: '(088) 350-4284 x8429', website: 'https://bradley.org', company: { name: 'Wunsch, Cole and Connelly', catchPhrase: 'Managed 6th generation ability', - bs: 'B2C extend bandwidth' - } + bs: 'B2C extend bandwidth', + }, }, { id: 387, @@ -8921,16 +8921,16 @@ export const users = [ zipcode: '98228', geo: { lat: '-12.0540', - lng: '102.0511' - } + lng: '102.0511', + }, }, phone: '244.486.8815', website: 'https://annamae.com', company: { name: 'Bailey, Gislason and Littel', catchPhrase: 'Distributed context-sensitive utilisation', - bs: 'open-source syndicate portals' - } + bs: 'open-source syndicate portals', + }, }, { id: 388, @@ -8944,16 +8944,16 @@ export const users = [ zipcode: '24436', geo: { lat: '61.5661', - lng: '145.5953' - } + lng: '145.5953', + }, }, phone: '1-710-252-7037', website: 'https://alexa.com', company: { name: 'Becker, Mitchell and Predovic', catchPhrase: 'Team-oriented fault-tolerant orchestration', - bs: 'ubiquitous synthesize synergies' - } + bs: 'ubiquitous synthesize synergies', + }, }, { id: 389, @@ -8967,16 +8967,16 @@ export const users = [ zipcode: '49604', geo: { lat: '34.0704', - lng: '-19.1197' - } + lng: '-19.1197', + }, }, phone: '(907) 582-3251 x40363', website: 'https://gunnar.com', company: { name: 'Bailey Group', catchPhrase: 'Vision-oriented demand-driven capability', - bs: 'killer drive supply-chains' - } + bs: 'killer drive supply-chains', + }, }, { id: 390, @@ -8990,16 +8990,16 @@ export const users = [ zipcode: '41420', geo: { lat: '65.1494', - lng: '-107.6246' - } + lng: '-107.6246', + }, }, phone: '(159) 765-7265', website: 'http://tiffany.org', company: { name: 'Walter Inc', catchPhrase: 'Multi-layered non-volatile emulation', - bs: '24/365 enhance solutions' - } + bs: '24/365 enhance solutions', + }, }, { id: 391, @@ -9013,16 +9013,16 @@ export const users = [ zipcode: '82492-1156', geo: { lat: '-83.9956', - lng: '-32.7030' - } + lng: '-32.7030', + }, }, phone: '(717) 346-7821 x31551', website: 'http://earlene.biz', company: { name: 'Johns - Rippin', catchPhrase: 'Compatible impactful adapter', - bs: 'rich deploy portals' - } + bs: 'rich deploy portals', + }, }, { id: 392, @@ -9036,16 +9036,16 @@ export const users = [ zipcode: '54321-3159', geo: { lat: '-83.4114', - lng: '-112.6474' - } + lng: '-112.6474', + }, }, phone: '097-173-3919 x456', website: 'https://frieda.name', company: { name: 'Flatley - Reichel', catchPhrase: 'Mandatory intermediate customer loyalty', - bs: 'customized expedite deliverables' - } + bs: 'customized expedite deliverables', + }, }, { id: 393, @@ -9059,16 +9059,16 @@ export const users = [ zipcode: '94505-5293', geo: { lat: '82.2912', - lng: '-28.0849' - } + lng: '-28.0849', + }, }, phone: '1-341-832-2102 x6935', website: 'http://hayden.com', company: { name: 'Bashirian, Funk and Goodwin', catchPhrase: 'Managed motivating function', - bs: 'ubiquitous reintermediate web services' - } + bs: 'ubiquitous reintermediate web services', + }, }, { id: 394, @@ -9082,16 +9082,16 @@ export const users = [ zipcode: '66326', geo: { lat: '-79.7629', - lng: '-57.2086' - } + lng: '-57.2086', + }, }, phone: '(849) 851-6117 x78931', website: 'https://allison.com', company: { name: 'Bosco - Walsh', catchPhrase: 'Customer-focused national attitude', - bs: 'rich enhance supply-chains' - } + bs: 'rich enhance supply-chains', + }, }, { id: 395, @@ -9105,16 +9105,16 @@ export const users = [ zipcode: '59125', geo: { lat: '-50.1924', - lng: '93.4000' - } + lng: '93.4000', + }, }, phone: '(891) 139-1115', website: 'http://armani.info', company: { name: 'McDermott Group', catchPhrase: 'Devolved interactive matrix', - bs: 'B2C reintermediate interfaces' - } + bs: 'B2C reintermediate interfaces', + }, }, { id: 396, @@ -9128,16 +9128,16 @@ export const users = [ zipcode: '37566-4425', geo: { lat: '38.0233', - lng: '153.9400' - } + lng: '153.9400', + }, }, phone: '(656) 040-5212', website: 'http://lizeth.com', company: { name: 'Emmerich - Rosenbaum', catchPhrase: 'Organic intangible interface', - bs: 'dynamic empower eyeballs' - } + bs: 'dynamic empower eyeballs', + }, }, { id: 397, @@ -9151,16 +9151,16 @@ export const users = [ zipcode: '29558-8017', geo: { lat: '35.4593', - lng: '-57.6929' - } + lng: '-57.6929', + }, }, phone: '1-205-080-5255', website: 'http://wendell.net', company: { name: 'Hessel Inc', catchPhrase: 'Monitored directional secured line', - bs: 'cross-media repurpose e-commerce' - } + bs: 'cross-media repurpose e-commerce', + }, }, { id: 398, @@ -9174,16 +9174,16 @@ export const users = [ zipcode: '33743', geo: { lat: '45.8983', - lng: '168.2938' - } + lng: '168.2938', + }, }, phone: '1-487-354-2660', website: 'http://dangelo.org', company: { name: 'Johns and Sons', catchPhrase: 'Open-source methodical standardization', - bs: 'magnetic productize markets' - } + bs: 'magnetic productize markets', + }, }, { id: 399, @@ -9197,16 +9197,16 @@ export const users = [ zipcode: '19864', geo: { lat: '88.9771', - lng: '164.8901' - } + lng: '164.8901', + }, }, phone: '(549) 350-3509 x7278', website: 'http://earl.biz', company: { name: 'Conn - Schmitt', catchPhrase: 'Diverse actuating time-frame', - bs: 'magnetic mesh initiatives' - } + bs: 'magnetic mesh initiatives', + }, }, { id: 400, @@ -9220,16 +9220,16 @@ export const users = [ zipcode: '73420-0930', geo: { lat: '6.0647', - lng: '-91.5507' - } + lng: '-91.5507', + }, }, phone: '1-199-453-7393', website: 'http://rex.net', company: { name: 'Balistreri - Dare', catchPhrase: 'Multi-tiered user-facing website', - bs: 'global visualize models' - } + bs: 'global visualize models', + }, }, { id: 401, @@ -9243,16 +9243,16 @@ export const users = [ zipcode: '24841-5424', geo: { lat: '-27.0661', - lng: '135.8055' - } + lng: '135.8055', + }, }, phone: '(957) 562-3025 x991', website: 'https://claudine.org', company: { name: 'Kovacek and Sons', catchPhrase: 'Switchable 3rd generation initiative', - bs: 'ubiquitous expedite eyeballs' - } + bs: 'ubiquitous expedite eyeballs', + }, }, { id: 402, @@ -9266,16 +9266,16 @@ export const users = [ zipcode: '39952-7746', geo: { lat: '57.2712', - lng: '9.6289' - } + lng: '9.6289', + }, }, phone: '1-647-659-2707', website: 'https://stone.net', company: { name: 'Dach - Berge', catchPhrase: 'Pre-emptive explicit support', - bs: 'front-end strategize e-services' - } + bs: 'front-end strategize e-services', + }, }, { id: 403, @@ -9289,16 +9289,16 @@ export const users = [ zipcode: '72530-8634', geo: { lat: '-32.0230', - lng: '-118.0494' - } + lng: '-118.0494', + }, }, phone: '396.718.7436 x27661', website: 'https://adrian.net', company: { name: 'Rath Inc', catchPhrase: 'Operative even-keeled migration', - bs: 'end-to-end disintermediate architectures' - } + bs: 'end-to-end disintermediate architectures', + }, }, { id: 404, @@ -9312,16 +9312,16 @@ export const users = [ zipcode: '40692-0310', geo: { lat: '28.0522', - lng: '79.9487' - } + lng: '79.9487', + }, }, phone: '(954) 531-0855 x478', website: 'http://silas.com', company: { name: 'Rath, Klein and Aufderhar', catchPhrase: 'Grass-roots maximized application', - bs: 'strategic utilize architectures' - } + bs: 'strategic utilize architectures', + }, }, { id: 405, @@ -9335,16 +9335,16 @@ export const users = [ zipcode: '09218', geo: { lat: '-54.3015', - lng: '173.3589' - } + lng: '173.3589', + }, }, phone: '347.608.1344', website: 'https://tracy.biz', company: { name: 'Hodkiewicz Group', catchPhrase: 'Decentralized local moratorium', - bs: 'seamless streamline models' - } + bs: 'seamless streamline models', + }, }, { id: 406, @@ -9358,16 +9358,16 @@ export const users = [ zipcode: '63713', geo: { lat: '-66.4304', - lng: '-129.4175' - } + lng: '-129.4175', + }, }, phone: '1-689-026-1994 x2217', website: 'https://destin.com', company: { name: 'Medhurst Group', catchPhrase: 'Integrated bi-directional framework', - bs: 'back-end implement ROI' - } + bs: 'back-end implement ROI', + }, }, { id: 407, @@ -9381,16 +9381,16 @@ export const users = [ zipcode: '30372-0133', geo: { lat: '-15.1653', - lng: '-158.5882' - } + lng: '-158.5882', + }, }, phone: '1-054-599-7090', website: 'https://emelia.biz', company: { name: 'Torp - Legros', catchPhrase: 'Function-based uniform moderator', - bs: 'innovative grow mindshare' - } + bs: 'innovative grow mindshare', + }, }, { id: 408, @@ -9404,16 +9404,16 @@ export const users = [ zipcode: '75222', geo: { lat: '11.8808', - lng: '168.8082' - } + lng: '168.8082', + }, }, phone: '(345) 685-0105', website: 'http://destiny.com', company: { name: 'Parisian, Haley and Bergstrom', catchPhrase: 'Implemented composite open architecture', - bs: '24/365 expedite technologies' - } + bs: '24/365 expedite technologies', + }, }, { id: 409, @@ -9427,16 +9427,16 @@ export const users = [ zipcode: '72523-9109', geo: { lat: '-56.1787', - lng: '8.3924' - } + lng: '8.3924', + }, }, phone: '134.207.5560 x7465', website: 'https://gracie.biz', company: { name: 'Prohaska Group', catchPhrase: 'Monitored analyzing project', - bs: 'strategic facilitate interfaces' - } + bs: 'strategic facilitate interfaces', + }, }, { id: 410, @@ -9450,16 +9450,16 @@ export const users = [ zipcode: '31756-0449', geo: { lat: '24.1579', - lng: '61.5527' - } + lng: '61.5527', + }, }, phone: '257.204.2672 x014', website: 'http://jeremy.biz', company: { name: 'Runte and Sons', catchPhrase: 'Down-sized secondary emulation', - bs: '24/365 aggregate platforms' - } + bs: '24/365 aggregate platforms', + }, }, { id: 411, @@ -9473,16 +9473,16 @@ export const users = [ zipcode: '57792', geo: { lat: '22.4595', - lng: '179.7560' - } + lng: '179.7560', + }, }, phone: '(777) 211-7686 x789', website: 'https://everardo.net', company: { name: 'Parker and Sons', catchPhrase: 'Triple-buffered interactive product', - bs: 'extensible innovate e-tailers' - } + bs: 'extensible innovate e-tailers', + }, }, { id: 412, @@ -9496,16 +9496,16 @@ export const users = [ zipcode: '42669-8235', geo: { lat: '-1.2824', - lng: '-8.0160' - } + lng: '-8.0160', + }, }, phone: '1-260-376-5795 x86622', website: 'https://charley.com', company: { name: "O'Conner and Sons", catchPhrase: 'Cross-platform demand-driven flexibility', - bs: 'clicks-and-mortar monetize functionalities' - } + bs: 'clicks-and-mortar monetize functionalities', + }, }, { id: 413, @@ -9519,16 +9519,16 @@ export const users = [ zipcode: '54247', geo: { lat: '51.2012', - lng: '-66.3774' - } + lng: '-66.3774', + }, }, phone: '558-435-2965 x43641', website: 'https://ernestina.org', company: { name: 'Yundt Inc', catchPhrase: 'Team-oriented cohesive emulation', - bs: 'robust reinvent partnerships' - } + bs: 'robust reinvent partnerships', + }, }, { id: 414, @@ -9542,16 +9542,16 @@ export const users = [ zipcode: '84082-0411', geo: { lat: '44.9919', - lng: '-54.4929' - } + lng: '-54.4929', + }, }, phone: '1-952-873-2461 x3546', website: 'https://dylan.info', company: { name: 'Terry - Ortiz', catchPhrase: 'Centralized contextually-based pricing structure', - bs: 'efficient transform web services' - } + bs: 'efficient transform web services', + }, }, { id: 415, @@ -9565,16 +9565,16 @@ export const users = [ zipcode: '09911-1591', geo: { lat: '-6.1017', - lng: '-40.1449' - } + lng: '-40.1449', + }, }, phone: '(899) 498-1190 x6692', website: 'https://tessie.info', company: { name: 'Osinski Group', catchPhrase: 'Virtual secondary Graphic Interface', - bs: 'revolutionary enhance paradigms' - } + bs: 'revolutionary enhance paradigms', + }, }, { id: 416, @@ -9588,16 +9588,16 @@ export const users = [ zipcode: '96199-4122', geo: { lat: '49.4435', - lng: '49.3278' - } + lng: '49.3278', + }, }, phone: '014.258.0154', website: 'http://geraldine.info', company: { name: 'Kertzmann, Keebler and Tremblay', catchPhrase: 'Quality-focused zero tolerance interface', - bs: 'synergistic synthesize convergence' - } + bs: 'synergistic synthesize convergence', + }, }, { id: 417, @@ -9611,16 +9611,16 @@ export const users = [ zipcode: '66517-9258', geo: { lat: '-63.2637', - lng: '82.6427' - } + lng: '82.6427', + }, }, phone: '995-842-7461 x439', website: 'http://lamar.info', company: { name: 'Feil, Boyer and Schaefer', catchPhrase: 'Optional 24/7 definition', - bs: 'scalable deploy portals' - } + bs: 'scalable deploy portals', + }, }, { id: 418, @@ -9634,16 +9634,16 @@ export const users = [ zipcode: '11877-3741', geo: { lat: '-87.3065', - lng: '71.1858' - } + lng: '71.1858', + }, }, phone: '456-040-4710', website: 'https://sheldon.biz', company: { name: 'Schowalter, Runolfsdottir and Gibson', catchPhrase: 'Reduced bottom-line policy', - bs: 'front-end synthesize convergence' - } + bs: 'front-end synthesize convergence', + }, }, { id: 419, @@ -9657,16 +9657,16 @@ export const users = [ zipcode: '97676-2635', geo: { lat: '-72.8454', - lng: '-69.6644' - } + lng: '-69.6644', + }, }, phone: '281.317.9063 x9648', website: 'http://ila.org', company: { name: 'Kunze and Sons', catchPhrase: 'Switchable explicit instruction set', - bs: 'B2B leverage e-services' - } + bs: 'B2B leverage e-services', + }, }, { id: 420, @@ -9680,16 +9680,16 @@ export const users = [ zipcode: '38664', geo: { lat: '69.1834', - lng: '-52.5046' - } + lng: '-52.5046', + }, }, phone: '975.330.9627 x36011', website: 'http://kris.biz', company: { name: 'Luettgen - Runolfsson', catchPhrase: 'Innovative client-server utilisation', - bs: 'strategic iterate e-tailers' - } + bs: 'strategic iterate e-tailers', + }, }, { id: 421, @@ -9703,16 +9703,16 @@ export const users = [ zipcode: '00559', geo: { lat: '-40.5713', - lng: '-35.7884' - } + lng: '-35.7884', + }, }, phone: '1-615-531-1927 x193', website: 'http://quinten.net', company: { name: 'Watsica, Hand and Dibbert', catchPhrase: 'Front-line executive database', - bs: 'transparent architect content' - } + bs: 'transparent architect content', + }, }, { id: 422, @@ -9726,16 +9726,16 @@ export const users = [ zipcode: '42491', geo: { lat: '-14.3356', - lng: '161.2175' - } + lng: '161.2175', + }, }, phone: '(978) 706-4512', website: 'http://mark.com', company: { name: 'Littel - Hettinger', catchPhrase: 'Centralized local website', - bs: 'robust enhance synergies' - } + bs: 'robust enhance synergies', + }, }, { id: 423, @@ -9749,16 +9749,16 @@ export const users = [ zipcode: '96286-4850', geo: { lat: '-61.5164', - lng: '78.0393' - } + lng: '78.0393', + }, }, phone: '512-422-4770 x59815', website: 'https://shanon.net', company: { name: 'Emmerich LLC', catchPhrase: 'Mandatory local complexity', - bs: 'wireless facilitate convergence' - } + bs: 'wireless facilitate convergence', + }, }, { id: 424, @@ -9772,16 +9772,16 @@ export const users = [ zipcode: '41955-5666', geo: { lat: '-42.7307', - lng: '-141.2333' - } + lng: '-141.2333', + }, }, phone: '086.072.3649 x628', website: 'https://celestine.net', company: { name: 'Zulauf and Sons', catchPhrase: 'Optimized directional Graphical User Interface', - bs: 'customized enable solutions' - } + bs: 'customized enable solutions', + }, }, { id: 425, @@ -9795,16 +9795,16 @@ export const users = [ zipcode: '11564', geo: { lat: '16.7794', - lng: '21.4084' - } + lng: '21.4084', + }, }, phone: '066.741.1165 x8329', website: 'https://janessa.com', company: { name: 'Senger, Doyle and Sauer', catchPhrase: 'Front-line even-keeled attitude', - bs: 'cutting-edge incentivize e-services' - } + bs: 'cutting-edge incentivize e-services', + }, }, { id: 426, @@ -9818,16 +9818,16 @@ export const users = [ zipcode: '05649-4756', geo: { lat: '-42.7436', - lng: '-178.5013' - } + lng: '-178.5013', + }, }, phone: '1-622-321-7820 x66488', website: 'https://dewayne.biz', company: { name: 'Marvin - Lesch', catchPhrase: 'Stand-alone responsive ability', - bs: '24/7 incubate partnerships' - } + bs: '24/7 incubate partnerships', + }, }, { id: 427, @@ -9841,16 +9841,16 @@ export const users = [ zipcode: '20131', geo: { lat: '-40.1392', - lng: '46.2822' - } + lng: '46.2822', + }, }, phone: '1-103-523-2069', website: 'http://adolphus.com', company: { name: 'Quigley - Rutherford', catchPhrase: 'User-centric 24/7 standardization', - bs: 'B2C innovate technologies' - } + bs: 'B2C innovate technologies', + }, }, { id: 428, @@ -9864,16 +9864,16 @@ export const users = [ zipcode: '60220', geo: { lat: '-19.4450', - lng: '-177.9313' - } + lng: '-177.9313', + }, }, phone: '(614) 957-2365 x780', website: 'https://berry.net', company: { name: 'Koelpin, Keebler and Breitenberg', catchPhrase: 'Organic secondary complexity', - bs: 'plug-and-play leverage infomediaries' - } + bs: 'plug-and-play leverage infomediaries', + }, }, { id: 429, @@ -9887,16 +9887,16 @@ export const users = [ zipcode: '88874-5214', geo: { lat: '-29.1461', - lng: '52.7855' - } + lng: '52.7855', + }, }, phone: '228-478-6116 x7619', website: 'http://christine.info', company: { name: 'Romaguera Inc', catchPhrase: 'Progressive non-volatile migration', - bs: 'integrated empower vortals' - } + bs: 'integrated empower vortals', + }, }, { id: 430, @@ -9910,16 +9910,16 @@ export const users = [ zipcode: '74933-7416', geo: { lat: '-28.7572', - lng: '89.9592' - } + lng: '89.9592', + }, }, phone: '1-026-255-5563', website: 'http://idell.net', company: { name: 'Abshire Inc', catchPhrase: 'Business-focused coherent service-desk', - bs: 'granular revolutionize mindshare' - } + bs: 'granular revolutionize mindshare', + }, }, { id: 431, @@ -9933,16 +9933,16 @@ export const users = [ zipcode: '00059-8861', geo: { lat: '-61.9965', - lng: '-27.4867' - } + lng: '-27.4867', + }, }, phone: '(484) 805-7253 x12234', website: 'http://cara.net', company: { name: 'Reilly - Donnelly', catchPhrase: 'Seamless 5th generation hub', - bs: 'sticky productize systems' - } + bs: 'sticky productize systems', + }, }, { id: 432, @@ -9956,16 +9956,16 @@ export const users = [ zipcode: '70228-9462', geo: { lat: '-44.8127', - lng: '-163.6245' - } + lng: '-163.6245', + }, }, phone: '832-776-6491 x04090', website: 'http://eden.info', company: { name: 'Gleason - Huel', catchPhrase: 'Function-based explicit implementation', - bs: 'B2B mesh bandwidth' - } + bs: 'B2B mesh bandwidth', + }, }, { id: 433, @@ -9979,16 +9979,16 @@ export const users = [ zipcode: '55599', geo: { lat: '-63.8889', - lng: '-137.7320' - } + lng: '-137.7320', + }, }, phone: '996-210-1789 x5197', website: 'https://coralie.info', company: { name: 'Wuckert - Green', catchPhrase: 'Face to face neutral open architecture', - bs: 'viral streamline experiences' - } + bs: 'viral streamline experiences', + }, }, { id: 434, @@ -10002,16 +10002,16 @@ export const users = [ zipcode: '46646-1644', geo: { lat: '88.1237', - lng: '-19.2206' - } + lng: '-19.2206', + }, }, phone: '1-183-281-8042 x24151', website: 'https://josh.net', company: { name: 'Towne - Dach', catchPhrase: 'Networked responsive adapter', - bs: 'B2B deploy systems' - } + bs: 'B2B deploy systems', + }, }, { id: 435, @@ -10025,16 +10025,16 @@ export const users = [ zipcode: '55613-0282', geo: { lat: '-77.4616', - lng: '6.5882' - } + lng: '6.5882', + }, }, phone: '010-341-8819 x7522', website: 'http://bret.biz', company: { name: 'Schimmel, Ortiz and Stehr', catchPhrase: 'Optimized mission-critical customer loyalty', - bs: 'turn-key optimize applications' - } + bs: 'turn-key optimize applications', + }, }, { id: 436, @@ -10048,16 +10048,16 @@ export const users = [ zipcode: '70318-5713', geo: { lat: '-83.6109', - lng: '135.7837' - } + lng: '135.7837', + }, }, phone: '1-699-800-1439 x28479', website: 'https://pauline.com', company: { name: 'Cronin, VonRueden and Paucek', catchPhrase: 'Inverse asymmetric array', - bs: 'robust enhance technologies' - } + bs: 'robust enhance technologies', + }, }, { id: 437, @@ -10071,16 +10071,16 @@ export const users = [ zipcode: '64184-5172', geo: { lat: '49.6551', - lng: '-127.9656' - } + lng: '-127.9656', + }, }, phone: '810.876.7485', website: 'https://jayme.net', company: { name: 'Harvey - Mueller', catchPhrase: 'Public-key actuating throughput', - bs: 'leading-edge seize users' - } + bs: 'leading-edge seize users', + }, }, { id: 438, @@ -10094,16 +10094,16 @@ export const users = [ zipcode: '50794', geo: { lat: '0.8908', - lng: '173.9015' - } + lng: '173.9015', + }, }, phone: '661-503-1773', website: 'https://darien.net', company: { name: 'Herzog LLC', catchPhrase: 'Seamless empowering forecast', - bs: 'scalable syndicate methodologies' - } + bs: 'scalable syndicate methodologies', + }, }, { id: 439, @@ -10117,16 +10117,16 @@ export const users = [ zipcode: '35438-0565', geo: { lat: '39.8205', - lng: '-174.4526' - } + lng: '-174.4526', + }, }, phone: '089-072-4833 x9465', website: 'https://kaley.org', company: { name: 'Herzog and Sons', catchPhrase: 'Distributed regional system engine', - bs: 'virtual whiteboard bandwidth' - } + bs: 'virtual whiteboard bandwidth', + }, }, { id: 440, @@ -10140,16 +10140,16 @@ export const users = [ zipcode: '11264', geo: { lat: '82.6998', - lng: '-121.1221' - } + lng: '-121.1221', + }, }, phone: '1-698-572-4682', website: 'http://lulu.org', company: { name: 'Veum - Swaniawski', catchPhrase: 'Proactive reciprocal capacity', - bs: 'transparent drive portals' - } + bs: 'transparent drive portals', + }, }, { id: 441, @@ -10163,16 +10163,16 @@ export const users = [ zipcode: '11053', geo: { lat: '-84.7690', - lng: '154.0188' - } + lng: '154.0188', + }, }, phone: '200.299.3800', website: 'https://lavinia.name', company: { name: "O'Conner - Funk", catchPhrase: 'Implemented bandwidth-monitored projection', - bs: 'strategic reinvent functionalities' - } + bs: 'strategic reinvent functionalities', + }, }, { id: 442, @@ -10186,16 +10186,16 @@ export const users = [ zipcode: '70357', geo: { lat: '-49.2726', - lng: '-158.8679' - } + lng: '-158.8679', + }, }, phone: '795-097-2411 x6357', website: 'http://catherine.biz', company: { name: 'Eichmann Group', catchPhrase: 'Robust multi-tasking open architecture', - bs: 'efficient evolve content' - } + bs: 'efficient evolve content', + }, }, { id: 443, @@ -10209,16 +10209,16 @@ export const users = [ zipcode: '81320-9408', geo: { lat: '39.4499', - lng: '96.7835' - } + lng: '96.7835', + }, }, phone: '213.385.5891 x33651', website: 'https://bruce.name', company: { name: 'Swaniawski, Thiel and Volkman', catchPhrase: 'Innovative even-keeled support', - bs: 'best-of-breed transition web-readiness' - } + bs: 'best-of-breed transition web-readiness', + }, }, { id: 444, @@ -10232,16 +10232,16 @@ export const users = [ zipcode: '11536', geo: { lat: '76.9876', - lng: '-81.6082' - } + lng: '-81.6082', + }, }, phone: '773-708-4599', website: 'https://clarissa.name', company: { name: 'Dare and Sons', catchPhrase: 'Multi-layered modular secured line', - bs: '24/7 target vortals' - } + bs: '24/7 target vortals', + }, }, { id: 445, @@ -10255,16 +10255,16 @@ export const users = [ zipcode: '21434-4500', geo: { lat: '2.0281', - lng: '12.8816' - } + lng: '12.8816', + }, }, phone: '454-399-5009', website: 'http://june.net', company: { name: 'Gottlieb, Kozey and Conroy', catchPhrase: 'Re-contextualized scalable product', - bs: 'efficient leverage models' - } + bs: 'efficient leverage models', + }, }, { id: 446, @@ -10278,16 +10278,16 @@ export const users = [ zipcode: '45019-9358', geo: { lat: '76.5261', - lng: '79.3561' - } + lng: '79.3561', + }, }, phone: '324-376-3978 x4072', website: 'https://adriel.com', company: { name: 'Yost - Botsford', catchPhrase: 'Mandatory client-server utilisation', - bs: 'efficient benchmark portals' - } + bs: 'efficient benchmark portals', + }, }, { id: 447, @@ -10301,16 +10301,16 @@ export const users = [ zipcode: '72830', geo: { lat: '57.7711', - lng: '-12.7775' - } + lng: '-12.7775', + }, }, phone: '(775) 084-6337 x3596', website: 'https://murray.net', company: { name: 'Olson - Grady', catchPhrase: 'Enterprise-wide impactful frame', - bs: 'bricks-and-clicks reinvent methodologies' - } + bs: 'bricks-and-clicks reinvent methodologies', + }, }, { id: 448, @@ -10324,16 +10324,16 @@ export const users = [ zipcode: '27078-7347', geo: { lat: '-0.7181', - lng: '-135.2545' - } + lng: '-135.2545', + }, }, phone: '716-277-3546', website: 'https://cooper.info', company: { name: 'Denesik, Mohr and Franecki', catchPhrase: 'Compatible maximized Graphic Interface', - bs: 'robust utilize e-business' - } + bs: 'robust utilize e-business', + }, }, { id: 449, @@ -10347,16 +10347,16 @@ export const users = [ zipcode: '60545-5577', geo: { lat: '-81.0962', - lng: '22.3021' - } + lng: '22.3021', + }, }, phone: '1-762-420-2815', website: 'http://carmine.name', company: { name: 'Larson Inc', catchPhrase: 'Centralized demand-driven archive', - bs: 'revolutionary drive applications' - } + bs: 'revolutionary drive applications', + }, }, { id: 450, @@ -10370,16 +10370,16 @@ export const users = [ zipcode: '40640', geo: { lat: '-78.9400', - lng: '-31.1407' - } + lng: '-31.1407', + }, }, phone: '(969) 058-3392', website: 'https://gladyce.org', company: { name: 'Kuphal, Spencer and Stracke', catchPhrase: 'Switchable dedicated leverage', - bs: 'visionary envisioneer infrastructures' - } + bs: 'visionary envisioneer infrastructures', + }, }, { id: 451, @@ -10393,16 +10393,16 @@ export const users = [ zipcode: '65249-4339', geo: { lat: '-14.7425', - lng: '-47.1771' - } + lng: '-47.1771', + }, }, phone: '1-566-584-5614 x65568', website: 'http://darrell.com', company: { name: 'Aufderhar, Hyatt and Waelchi', catchPhrase: 'Networked global flexibility', - bs: 'granular expedite channels' - } + bs: 'granular expedite channels', + }, }, { id: 452, @@ -10416,16 +10416,16 @@ export const users = [ zipcode: '12052-3201', geo: { lat: '66.5104', - lng: '-175.9272' - } + lng: '-175.9272', + }, }, phone: '726.033.5644', website: 'https://karolann.com', company: { name: 'Moen, Gaylord and Rodriguez', catchPhrase: 'Cloned client-driven ability', - bs: 'customized embrace supply-chains' - } + bs: 'customized embrace supply-chains', + }, }, { id: 453, @@ -10439,16 +10439,16 @@ export const users = [ zipcode: '19579', geo: { lat: '54.5886', - lng: '91.8705' - } + lng: '91.8705', + }, }, phone: '(690) 999-8955', website: 'https://shakira.net', company: { name: 'Schinner Group', catchPhrase: 'Cross-platform zero defect focus group', - bs: 'distributed facilitate e-markets' - } + bs: 'distributed facilitate e-markets', + }, }, { id: 454, @@ -10462,16 +10462,16 @@ export const users = [ zipcode: '29206-2914', geo: { lat: '-2.8180', - lng: '-40.6726' - } + lng: '-40.6726', + }, }, phone: '797.292.2017 x44615', website: 'http://alexane.org', company: { name: 'Huel, Jerde and Breitenberg', catchPhrase: 'Innovative web-enabled functionalities', - bs: 'user-centric extend relationships' - } + bs: 'user-centric extend relationships', + }, }, { id: 455, @@ -10485,16 +10485,16 @@ export const users = [ zipcode: '50213', geo: { lat: '-46.6755', - lng: '139.9552' - } + lng: '139.9552', + }, }, phone: '(238) 764-9975 x2100', website: 'http://fletcher.name', company: { name: 'Gerhold Group', catchPhrase: 'Optional value-added paradigm', - bs: 'back-end embrace supply-chains' - } + bs: 'back-end embrace supply-chains', + }, }, { id: 456, @@ -10508,16 +10508,16 @@ export const users = [ zipcode: '30208-3467', geo: { lat: '25.0508', - lng: '-74.2926' - } + lng: '-74.2926', + }, }, phone: '600-806-3865 x1647', website: 'http://katelin.name', company: { name: 'Weissnat, Rogahn and Roob', catchPhrase: 'Balanced tertiary benchmark', - bs: 'interactive iterate channels' - } + bs: 'interactive iterate channels', + }, }, { id: 457, @@ -10531,16 +10531,16 @@ export const users = [ zipcode: '17395', geo: { lat: '-26.3264', - lng: '-100.3505' - } + lng: '-100.3505', + }, }, phone: '297-931-2534 x6770', website: 'http://pasquale.net', company: { name: 'Beier, Kutch and Gottlieb', catchPhrase: 'Digitized discrete workforce', - bs: 'enterprise benchmark e-tailers' - } + bs: 'enterprise benchmark e-tailers', + }, }, { id: 458, @@ -10554,16 +10554,16 @@ export const users = [ zipcode: '93722', geo: { lat: '79.2702', - lng: '-7.0729' - } + lng: '-7.0729', + }, }, phone: '916.558.3802 x364', website: 'http://dejah.name', company: { name: 'Rippin, Effertz and Ortiz', catchPhrase: 'Realigned human-resource time-frame', - bs: 'wireless revolutionize convergence' - } + bs: 'wireless revolutionize convergence', + }, }, { id: 459, @@ -10577,16 +10577,16 @@ export const users = [ zipcode: '49952-2667', geo: { lat: '51.4634', - lng: '-28.7476' - } + lng: '-28.7476', + }, }, phone: '570.989.8577 x36133', website: 'http://gerda.info', company: { name: 'Hermiston Inc', catchPhrase: 'Focused coherent methodology', - bs: 'e-business drive applications' - } + bs: 'e-business drive applications', + }, }, { id: 460, @@ -10600,16 +10600,16 @@ export const users = [ zipcode: '79100', geo: { lat: '-85.6009', - lng: '-65.3234' - } + lng: '-65.3234', + }, }, phone: '812-778-2760', website: 'http://blaise.net', company: { name: 'Kshlerin - Krajcik', catchPhrase: 'Proactive bottom-line contingency', - bs: 'bricks-and-clicks architect metrics' - } + bs: 'bricks-and-clicks architect metrics', + }, }, { id: 461, @@ -10623,16 +10623,16 @@ export const users = [ zipcode: '09965-8228', geo: { lat: '78.6712', - lng: '-117.0687' - } + lng: '-117.0687', + }, }, phone: '1-876-707-9862', website: 'http://macy.com', company: { name: 'Fisher, Wilderman and Kunde', catchPhrase: 'Business-focused optimizing toolset', - bs: 'enterprise deploy methodologies' - } + bs: 'enterprise deploy methodologies', + }, }, { id: 462, @@ -10646,16 +10646,16 @@ export const users = [ zipcode: '09279', geo: { lat: '-54.1081', - lng: '-171.0259' - } + lng: '-171.0259', + }, }, phone: '749.976.6946 x3006', website: 'https://cortez.name', company: { name: 'Graham, Schoen and Huel', catchPhrase: 'Multi-tiered actuating utilisation', - bs: '24/365 envisioneer markets' - } + bs: '24/365 envisioneer markets', + }, }, { id: 463, @@ -10669,16 +10669,16 @@ export const users = [ zipcode: '75819', geo: { lat: '73.1561', - lng: '-77.1391' - } + lng: '-77.1391', + }, }, phone: '1-842-167-6048', website: 'http://jenifer.com', company: { name: 'Wehner, Schumm and Rath', catchPhrase: 'Profit-focused motivating collaboration', - bs: 'cross-media empower initiatives' - } + bs: 'cross-media empower initiatives', + }, }, { id: 464, @@ -10692,16 +10692,16 @@ export const users = [ zipcode: '09319-2911', geo: { lat: '45.1811', - lng: '41.6515' - } + lng: '41.6515', + }, }, phone: '(747) 755-9907', website: 'http://darrick.org', company: { name: "O'Keefe, Wilkinson and Bogisich", catchPhrase: 'Fundamental encompassing local area network', - bs: 'cross-platform generate ROI' - } + bs: 'cross-platform generate ROI', + }, }, { id: 465, @@ -10715,16 +10715,16 @@ export const users = [ zipcode: '69113', geo: { lat: '39.1186', - lng: '65.3017' - } + lng: '65.3017', + }, }, phone: '1-580-108-5576 x9471', website: 'http://karli.info', company: { name: 'Hickle - Volkman', catchPhrase: 'Synergized real-time time-frame', - bs: 'killer reinvent e-commerce' - } + bs: 'killer reinvent e-commerce', + }, }, { id: 466, @@ -10738,16 +10738,16 @@ export const users = [ zipcode: '57500-4097', geo: { lat: '-23.5474', - lng: '88.7904' - } + lng: '88.7904', + }, }, phone: '386.257.1206 x5390', website: 'https://murphy.name', company: { name: 'Kutch LLC', catchPhrase: 'Persevering coherent leverage', - bs: 'synergistic leverage interfaces' - } + bs: 'synergistic leverage interfaces', + }, }, { id: 467, @@ -10761,16 +10761,16 @@ export const users = [ zipcode: '27471-2774', geo: { lat: '55.5143', - lng: '15.7286' - } + lng: '15.7286', + }, }, phone: '534-260-7768', website: 'https://muriel.biz', company: { name: 'Fritsch, Botsford and Heathcote', catchPhrase: 'Front-line optimizing system engine', - bs: 'distributed optimize partnerships' - } + bs: 'distributed optimize partnerships', + }, }, { id: 468, @@ -10784,16 +10784,16 @@ export const users = [ zipcode: '00143', geo: { lat: '-36.8795', - lng: '3.6216' - } + lng: '3.6216', + }, }, phone: '246.035.1369', website: 'http://martin.biz', company: { name: 'Windler, Carter and Collier', catchPhrase: 'Polarised reciprocal product', - bs: 'value-added redefine architectures' - } + bs: 'value-added redefine architectures', + }, }, { id: 469, @@ -10807,16 +10807,16 @@ export const users = [ zipcode: '81968-7548', geo: { lat: '-33.6292', - lng: '68.6054' - } + lng: '68.6054', + }, }, phone: '508.345.0764', website: 'https://imani.info', company: { name: 'Kassulke, Howell and Feest', catchPhrase: 'Compatible web-enabled orchestration', - bs: '24/365 facilitate action-items' - } + bs: '24/365 facilitate action-items', + }, }, { id: 470, @@ -10830,16 +10830,16 @@ export const users = [ zipcode: '04450-5791', geo: { lat: '81.7967', - lng: '-0.3889' - } + lng: '-0.3889', + }, }, phone: '(883) 737-2588 x11448', website: 'https://claire.org', company: { name: 'Waters and Sons', catchPhrase: 'Front-line zero defect emulation', - bs: 'vertical orchestrate platforms' - } + bs: 'vertical orchestrate platforms', + }, }, { id: 471, @@ -10853,16 +10853,16 @@ export const users = [ zipcode: '98323-6420', geo: { lat: '-10.9408', - lng: '-83.0334' - } + lng: '-83.0334', + }, }, phone: '1-241-133-6128 x17671', website: 'https://brisa.name', company: { name: 'Stiedemann, Douglas and Weissnat', catchPhrase: 'Adaptive mission-critical interface', - bs: 'clicks-and-mortar deploy eyeballs' - } + bs: 'clicks-and-mortar deploy eyeballs', + }, }, { id: 472, @@ -10876,16 +10876,16 @@ export const users = [ zipcode: '33016', geo: { lat: '74.1198', - lng: '124.4532' - } + lng: '124.4532', + }, }, phone: '(059) 254-3417', website: 'http://loy.com', company: { name: 'Stiedemann, Veum and Gutkowski', catchPhrase: 'Reverse-engineered methodical forecast', - bs: 'cutting-edge revolutionize portals' - } + bs: 'cutting-edge revolutionize portals', + }, }, { id: 473, @@ -10899,16 +10899,16 @@ export const users = [ zipcode: '08077-1239', geo: { lat: '-9.6943', - lng: '104.6056' - } + lng: '104.6056', + }, }, phone: '983-887-2135 x7571', website: 'http://alda.name', company: { name: 'Mraz - Morar', catchPhrase: 'Open-source responsive utilisation', - bs: 'robust transition networks' - } + bs: 'robust transition networks', + }, }, { id: 474, @@ -10922,16 +10922,16 @@ export const users = [ zipcode: '34403', geo: { lat: '-46.0876', - lng: '-66.1116' - } + lng: '-66.1116', + }, }, phone: '613-673-3814', website: 'https://brant.name', company: { name: 'Kozey LLC', catchPhrase: 'Programmable full-range standardization', - bs: 'wireless empower action-items' - } + bs: 'wireless empower action-items', + }, }, { id: 475, @@ -10945,16 +10945,16 @@ export const users = [ zipcode: '37306-1541', geo: { lat: '-35.4420', - lng: '1.9303' - } + lng: '1.9303', + }, }, phone: '1-462-294-8481 x68106', website: 'https://santino.net', company: { name: 'Schaefer - Ullrich', catchPhrase: 'Business-focused analyzing capability', - bs: 'best-of-breed synthesize architectures' - } + bs: 'best-of-breed synthesize architectures', + }, }, { id: 476, @@ -10968,16 +10968,16 @@ export const users = [ zipcode: '19117-4669', geo: { lat: '79.6125', - lng: '-39.7697' - } + lng: '-39.7697', + }, }, phone: '177.895.9526 x32231', website: 'http://kali.com', company: { name: 'Sporer - Dickinson', catchPhrase: 'Up-sized didactic utilisation', - bs: 'vertical harness networks' - } + bs: 'vertical harness networks', + }, }, { id: 477, @@ -10991,16 +10991,16 @@ export const users = [ zipcode: '08211', geo: { lat: '-66.5991', - lng: '56.6347' - } + lng: '56.6347', + }, }, phone: '(827) 690-4300 x5837', website: 'https://earline.net', company: { name: 'Parisian, Toy and Parisian', catchPhrase: 'Versatile national Graphic Interface', - bs: 'killer extend technologies' - } + bs: 'killer extend technologies', + }, }, { id: 478, @@ -11014,16 +11014,16 @@ export const users = [ zipcode: '47517', geo: { lat: '-87.1460', - lng: '121.2937' - } + lng: '121.2937', + }, }, phone: '900-828-3742 x1653', website: 'http://felipe.name', company: { name: 'Kunze - Pfeffer', catchPhrase: 'Expanded fault-tolerant info-mediaries', - bs: 'enterprise exploit relationships' - } + bs: 'enterprise exploit relationships', + }, }, { id: 479, @@ -11037,16 +11037,16 @@ export const users = [ zipcode: '12550-9178', geo: { lat: '25.0916', - lng: '15.2878' - } + lng: '15.2878', + }, }, phone: '914-818-6718 x977', website: 'https://judd.name', company: { name: 'Jakubowski Inc', catchPhrase: 'Down-sized holistic function', - bs: '24/365 deliver initiatives' - } + bs: '24/365 deliver initiatives', + }, }, { id: 480, @@ -11060,16 +11060,16 @@ export const users = [ zipcode: '86429-4026', geo: { lat: '-15.7790', - lng: '120.7414' - } + lng: '120.7414', + }, }, phone: '1-348-548-2058 x72522', website: 'http://general.name', company: { name: 'McGlynn LLC', catchPhrase: 'Secured exuding approach', - bs: 'enterprise visualize models' - } + bs: 'enterprise visualize models', + }, }, { id: 481, @@ -11083,16 +11083,16 @@ export const users = [ zipcode: '05549-5609', geo: { lat: '3.1820', - lng: '62.0804' - } + lng: '62.0804', + }, }, phone: '(777) 705-2919', website: 'https://imelda.org', company: { name: 'Kiehn Inc', catchPhrase: 'Team-oriented client-server core', - bs: '24/365 repurpose functionalities' - } + bs: '24/365 repurpose functionalities', + }, }, { id: 482, @@ -11106,16 +11106,16 @@ export const users = [ zipcode: '99382', geo: { lat: '44.8479', - lng: '16.4334' - } + lng: '16.4334', + }, }, phone: '881-968-3854', website: 'https://salma.name', company: { name: 'Jaskolski Inc', catchPhrase: 'Horizontal national forecast', - bs: 'scalable incentivize partnerships' - } + bs: 'scalable incentivize partnerships', + }, }, { id: 483, @@ -11129,16 +11129,16 @@ export const users = [ zipcode: '70638-0254', geo: { lat: '-56.1766', - lng: '153.4432' - } + lng: '153.4432', + }, }, phone: '(797) 899-2968 x4538', website: 'https://guido.biz', company: { name: 'Kihn, Beier and Franecki', catchPhrase: 'Integrated regional forecast', - bs: 'open-source enable web services' - } + bs: 'open-source enable web services', + }, }, { id: 484, @@ -11152,16 +11152,16 @@ export const users = [ zipcode: '27019', geo: { lat: '47.3422', - lng: '-80.3874' - } + lng: '-80.3874', + }, }, phone: '1-079-276-7886 x4116', website: 'https://mckenzie.name', company: { name: 'Murazik, Ortiz and Lindgren', catchPhrase: 'Enhanced didactic architecture', - bs: 'out-of-the-box utilize relationships' - } + bs: 'out-of-the-box utilize relationships', + }, }, { id: 485, @@ -11175,16 +11175,16 @@ export const users = [ zipcode: '65212', geo: { lat: '20.4382', - lng: '118.8625' - } + lng: '118.8625', + }, }, phone: '154.006.3958 x455', website: 'https://hannah.org', company: { name: 'Feest, Boyle and Dibbert', catchPhrase: 'Horizontal contextually-based archive', - bs: 'strategic enable communities' - } + bs: 'strategic enable communities', + }, }, { id: 486, @@ -11198,16 +11198,16 @@ export const users = [ zipcode: '36174', geo: { lat: '24.2536', - lng: '-50.1005' - } + lng: '-50.1005', + }, }, phone: '882.476.2052 x618', website: 'http://cory.biz', company: { name: 'Tremblay and Sons', catchPhrase: 'Innovative 5th generation instruction set', - bs: 'world-class unleash channels' - } + bs: 'world-class unleash channels', + }, }, { id: 487, @@ -11221,16 +11221,16 @@ export const users = [ zipcode: '15511', geo: { lat: '5.7571', - lng: '118.3573' - } + lng: '118.3573', + }, }, phone: '1-186-092-1499', website: 'https://yesenia.biz', company: { name: 'Parker LLC', catchPhrase: 'Focused didactic model', - bs: 'transparent enable paradigms' - } + bs: 'transparent enable paradigms', + }, }, { id: 488, @@ -11244,16 +11244,16 @@ export const users = [ zipcode: '07016-1413', geo: { lat: '37.3540', - lng: '-12.3160' - } + lng: '-12.3160', + }, }, phone: '1-033-079-7577 x22844', website: 'https://eldridge.name', company: { name: 'Sawayn - Swaniawski', catchPhrase: 'Enhanced directional emulation', - bs: 'real-time iterate synergies' - } + bs: 'real-time iterate synergies', + }, }, { id: 489, @@ -11267,16 +11267,16 @@ export const users = [ zipcode: '03782-6064', geo: { lat: '-57.3843', - lng: '44.0033' - } + lng: '44.0033', + }, }, phone: '596.717.0282', website: 'http://elliott.net', company: { name: 'Heathcote - Aufderhar', catchPhrase: 'Automated interactive open architecture', - bs: 'dot-com reintermediate applications' - } + bs: 'dot-com reintermediate applications', + }, }, { id: 490, @@ -11290,16 +11290,16 @@ export const users = [ zipcode: '71693', geo: { lat: '-3.8121', - lng: '-73.9450' - } + lng: '-73.9450', + }, }, phone: '1-037-736-7061 x087', website: 'https://jayden.org', company: { name: 'Mitchell and Sons', catchPhrase: 'User-centric cohesive definition', - bs: 'virtual utilize e-business' - } + bs: 'virtual utilize e-business', + }, }, { id: 491, @@ -11313,16 +11313,16 @@ export const users = [ zipcode: '23525-8984', geo: { lat: '65.7287', - lng: '-107.0103' - } + lng: '-107.0103', + }, }, phone: '(392) 508-4173 x11194', website: 'https://bell.info', company: { name: 'Hoeger - Macejkovic', catchPhrase: 'Cross-group secondary complexity', - bs: 'world-class streamline functionalities' - } + bs: 'world-class streamline functionalities', + }, }, { id: 492, @@ -11336,16 +11336,16 @@ export const users = [ zipcode: '16346-3744', geo: { lat: '-3.6328', - lng: '-150.2528' - } + lng: '-150.2528', + }, }, phone: '123-376-1425 x49331', website: 'http://america.net', company: { name: 'Kshlerin LLC', catchPhrase: 'Expanded demand-driven architecture', - bs: 'bricks-and-clicks monetize supply-chains' - } + bs: 'bricks-and-clicks monetize supply-chains', + }, }, { id: 493, @@ -11359,16 +11359,16 @@ export const users = [ zipcode: '62995-9229', geo: { lat: '18.9479', - lng: '-0.5649' - } + lng: '-0.5649', + }, }, phone: '(163) 970-9301 x1720', website: 'http://nelson.com', company: { name: 'Pollich, Shields and Lindgren', catchPhrase: 'Stand-alone upward-trending info-mediaries', - bs: 'magnetic embrace bandwidth' - } + bs: 'magnetic embrace bandwidth', + }, }, { id: 494, @@ -11382,16 +11382,16 @@ export const users = [ zipcode: '98272', geo: { lat: '-61.1486', - lng: '83.0204' - } + lng: '83.0204', + }, }, phone: '623.406.9766', website: 'https://florian.info', company: { name: 'Leffler and Sons', catchPhrase: 'Fundamental scalable internet solution', - bs: 'sticky maximize portals' - } + bs: 'sticky maximize portals', + }, }, { id: 495, @@ -11405,16 +11405,16 @@ export const users = [ zipcode: '93641-0185', geo: { lat: '59.8530', - lng: '42.1418' - } + lng: '42.1418', + }, }, phone: '499-665-2259', website: 'https://nels.com', company: { name: 'Conn, Ebert and Spinka', catchPhrase: 'Proactive zero tolerance website', - bs: 'virtual monetize infomediaries' - } + bs: 'virtual monetize infomediaries', + }, }, { id: 496, @@ -11428,16 +11428,16 @@ export const users = [ zipcode: '71014-0296', geo: { lat: '18.3528', - lng: '40.4497' - } + lng: '40.4497', + }, }, phone: '1-104-732-9383', website: 'http://dillon.com', company: { name: 'Schuppe, Schroeder and Runte', catchPhrase: 'Operative cohesive hub', - bs: 'robust scale interfaces' - } + bs: 'robust scale interfaces', + }, }, { id: 497, @@ -11451,16 +11451,16 @@ export const users = [ zipcode: '64094-9314', geo: { lat: '-19.6607', - lng: '-42.4235' - } + lng: '-42.4235', + }, }, phone: '497-997-1190', website: 'http://kamron.name', company: { name: 'Rutherford, Kertzmann and Kerluke', catchPhrase: 'Enhanced modular algorithm', - bs: 'real-time incentivize web-readiness' - } + bs: 'real-time incentivize web-readiness', + }, }, { id: 498, @@ -11474,16 +11474,16 @@ export const users = [ zipcode: '13121-0246', geo: { lat: '-66.0568', - lng: '-63.3366' - } + lng: '-63.3366', + }, }, phone: '(112) 666-1967', website: 'http://jerel.org', company: { name: 'Fisher, Blick and Kassulke', catchPhrase: 'Profound high-level superstructure', - bs: 'cross-platform engage platforms' - } + bs: 'cross-platform engage platforms', + }, }, { id: 499, @@ -11497,16 +11497,16 @@ export const users = [ zipcode: '32964-4297', geo: { lat: '12.1526', - lng: '32.1351' - } + lng: '32.1351', + }, }, phone: '918.763.9395', website: 'https://keaton.org', company: { name: 'Boyer, Dicki and Kautzer', catchPhrase: 'Re-engineered reciprocal firmware', - bs: 'mission-critical generate relationships' - } + bs: 'mission-critical generate relationships', + }, }, { id: 500, @@ -11520,16 +11520,16 @@ export const users = [ zipcode: '66496-4281', geo: { lat: '-45.9416', - lng: '18.1914' - } + lng: '18.1914', + }, }, phone: '(179) 903-1675 x8129', website: 'https://shakira.name', company: { name: 'Christiansen, Erdman and Gaylord', catchPhrase: 'User-friendly human-resource model', - bs: 'end-to-end optimize partnerships' - } + bs: 'end-to-end optimize partnerships', + }, }, { id: 501, @@ -11543,15 +11543,15 @@ export const users = [ zipcode: '02011-1860', geo: { lat: '46.9203', - lng: '58.4892' - } + lng: '58.4892', + }, }, phone: '259-206-6911 x33711', website: 'https://jorge.com', company: { name: 'Simonis, Wisozk and Walker', catchPhrase: 'Customizable responsive artificial intelligence', - bs: 'one-to-one seize platforms' - } - } + bs: 'one-to-one seize platforms', + }, + }, ]; diff --git a/package-lock.json b/package-lock.json index fba129969..5f7409627 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11936,6 +11936,17 @@ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==" }, + "clipboard": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.6.tgz", + "integrity": "sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==", + "optional": true, + "requires": { + "good-listener": "^1.2.2", + "select": "^1.1.2", + "tiny-emitter": "^2.0.0" + } + }, "cliui": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", @@ -13781,6 +13792,12 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, + "delegate": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", + "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==", + "optional": true + }, "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -16537,6 +16554,15 @@ "integrity": "sha1-8g6jbbEDv8KSNDkh8fkeg8NGdok=", "dev": true }, + "good-listener": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", + "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", + "optional": true, + "requires": { + "delegate": "^3.1.2" + } + }, "got": { "version": "9.6.0", "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", @@ -24654,6 +24680,14 @@ } } }, + "prismjs": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.20.0.tgz", + "integrity": "sha512-AEDjSrVNkynnw6A+B1DsFkd6AVdTnp+/WoUixFRULlCLZVRZlVQMVWio/16jv7G1FscUxQxOQhWwApgbnxr6kQ==", + "requires": { + "clipboard": "^2.0.0" + } + }, "private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", @@ -26474,6 +26508,12 @@ "resolved": "https://registry.npmjs.org/scully-plugin-disable-angular/-/scully-plugin-disable-angular-4.0.2.tgz", "integrity": "sha512-UQ4boaHwyJh4ie2kqOSeMlBbhxQ3PqOpUpKiDmT1WGcn76398S8c2Entp09p8qrjGs8IP/klPsnNC/R1nUz7Tg==" }, + "select": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", + "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=", + "optional": true + }, "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -28317,6 +28357,12 @@ "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", "dev": true }, + "tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", + "optional": true + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", diff --git a/package.json b/package.json index 4c78f9ad4..82ce04867 100644 --- a/package.json +++ b/package.json @@ -79,16 +79,17 @@ "core-js": "^3.6.5", "cors": "^2.8.5", "cz-customizable": "^6.2.0", + "express": "4.17.1", "js-yaml": "^3.14.0", "jsdom": "^16.2.2", "minimatch": "^3.0.4", "npm-run-all": "^4.1.5", + "prismjs": "1.20.0", "rxjs": "^6.5.5", "scully-plugin-disable-angular": "^4.0.2", "semver": "^7.3.2", "ws": "^7.3.0", - "zone.js": "^0.10.3", - "express": "4.17.1" + "zone.js": "^0.10.3" }, "devDependencies": { "@angular-devkit/build-angular": "^0.901.9", diff --git a/tests/jest/src/__tests__/__snapshots__/blog-index.spec.ts.snap b/tests/jest/src/__tests__/__snapshots__/blog-index.spec.ts.snap index 1245b8e09..63faf443d 100644 --- a/tests/jest/src/__tests__/__snapshots__/blog-index.spec.ts.snap +++ b/tests/jest/src/__tests__/__snapshots__/blog-index.spec.ts.snap @@ -72,46 +72,103 @@ exports[`ContentFolder: Test blog/page-1 Check contentPlugin render 1`] = ` > or, how to do interesting blog things

      -
      +            
                     
      -                
                         console
                       
      -                .log(
      -                
      +                  .
      +                
      +                
      +                  log
      +                
      +                
      +                  (
      +                
      +                
                         'hello world'
                       
      -                );
      -                
      +                  )
      +                
      +                
      +                  ;
      +                
      +                
                         console
                       
      -                .log(
      -                
      +                  .
      +                
      +                
      +                  log
      +                
      +                
      +                  (
      +                
      +                
                         'yah'
                       
      -                );
      -                
      +                  )
      +                
      +                
      +                  ;
      +                
      +                
                         const
                       
      -                x =
      -                
      +                  =
      +                
      +                
                         123
                       
      -                ;
      +                
      +                  ;
      +                
                     
                   

      diff --git a/tests/jest/src/__tests__/__snapshots__/docsThere.spec.ts.snap b/tests/jest/src/__tests__/__snapshots__/docsThere.spec.ts.snap index 5a3a71683..a6f2f3276 100644 --- a/tests/jest/src/__tests__/__snapshots__/docsThere.spec.ts.snap +++ b/tests/jest/src/__tests__/__snapshots__/docsThere.spec.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`docsSite should have content for all markdown files check html for markdown docs/CODE_OF_CONDUCT 1`] = ` +exports[`docsSite should have content for all markdown files check html for markdown docs/community/code-of-conduct 1`] = ` @@ -18,36 +18,8 @@ exports[`docsSite should have content for all markdown files check html for mark href="favicon.ico" > - - - - - - - beta - - scullyLogo + beta -

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

      + + + +
      + + + +
      +

      Code of Conduct

      -

      +

      As contributors and maintainers of the Scully project, we pledge to respect everyone who contributes by posting issues, updating documentation, submitting pull requests, providing feedback in comments, and any other activities.

      -

      +

      Communication through any of Scully's channels (GitHub, Gitter, Twitter, etc.) must be constructive and never resort to personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.

      -

      +

      We promise to extend courtesy and respect to everyone involved in this project regardless of gender, gender identity, sexual orientation, disability, age, race, ethnicity, religion, or level of experience. We expect anyone contributing to the Scully project to do the same.

      -

      +

      If any member of the community violates this code of conduct, the maintainers of the Scully project may take action, removing issues, comments, and PRs or blocking accounts as deemed appropriate.

      -

      +

      If you are subject to or witness unacceptable behavior, or have any other concerns, please email us at - + coc@hero.dev .

      - + - -

      -
      -
      -
      -
      - + + + + + `; -exports[`docsSite should have content for all markdown files check html for markdown docs/CODE_OF_CONDUCT_es 1`] = ` +exports[`docsSite should have content for all markdown files check html for markdown docs/community/contributing 1`] = ` @@ -547,36 +1179,8 @@ exports[`docsSite should have content for all markdown files check html for mark href="favicon.ico" > - - - - - - - beta - - scullyLogo + beta - -
      - - - - - - - - - - -
      - - - -

      - Código de Conducta -

      -

      - Como contribuyentes y mantenedores del proyecto Scully, nos comprometemos a respetar a todos los que contribuyen mediante la publicación de problemas, la actualización de la documentación, el envío de solicitudes de extracción, la retroalimentación en los comentarios y cualquier otra actividad. -La comunicación a través de cualquiera de los canales de Scully (GitHub, Gitter, Twitter, etc.) debe ser constructiva y nunca recurrir a ataques personales, trolling, acoso público o privado, insultos u otra conducta no profesional. -Prometemos extender la cortesía y el respeto a todos los involucrados en este proyecto, independientemente de su género, identidad de género, orientación sexual, discapacidad, edad, raza, etnia, religión o nivel de experiencia. Esperamos que cualquiera que contribuya al proyecto Scully haga lo mismo. -Si algún miembro de la comunidad viola este código de conducta, los encargados del proyecto Scully pueden tomar medidas, eliminar problemas, comentarios y relaciones públicas o bloquear cuentas, según se considere apropiado. -Si está sujeto o es testigo de un comportamiento inaceptable, o tiene alguna otra inquietud, envíenos un correo electrónico a [ - +

    1. + + + +
    2. + + +
      + + + +
      +

      + Contributing +

      +

      + Do you want to contribute to Scully or share your experience with the community? +
      + Please check our + + CONTRIBUTING - ). + guidelines. +

      +

      + The team would love your feedback and to hear how you're using Scully with other tools!

      - + - -
      -
      -
      -
      -
      - + + + + +
      `; -exports[`docsSite should have content for all markdown files check html for markdown docs/CONTRIBUTING 1`] = ` +exports[`docsSite should have content for all markdown files check html for markdown docs/community/issues 1`] = ` @@ -1072,36 +2333,8 @@ exports[`docsSite should have content for all markdown files check html for mark href="favicon.ico" > - - - - - - - beta - - scullyLogo + beta - -
      - - - - - - - - - - -
      - - - -

      - Contributing to Scully + + + +
      + + + +
      +

      + Issues

      -

      - We would love for you to contribute to Scully and help make it even better than it is -today! As a contributor, here are the guidelines we would like you to follow: +

      + To create a bug report, use the + + Scully Bug template. +

      -
      + +
      +
      + + + + +`; + +exports[`docsSite should have content for all markdown files check html for markdown docs/community/showcase 1`] = ` + + + + + + + ScullyDocs + + + + + + + + + + beta + +
      +

      - -
    3. -

      - Create your patch, - - including appropriate test cases - - . -

      -
    4. -
    5. -

      - Commit your changes using a descriptive commit message that follows our - + + Register a new plugin + + +

    6. +
    7. - commit message conventions - - . Adherence to these conventions -is necessary run the command - - npm run commit - - (this add all the files using - - git add . - - ) or -if you need only add some files, you can need run the command - - npm run commit:select - - . -

      -
    8. -
    9. -

      - Push your branch to GitHub: -

      -
      -                    
      +                        
      +                          Types
      +                        
      +                      
      +                      
      +                      
      +                      
      +                    
    10. +
    11. - git push origin my-fix-branch - - -
    12. -
    13. -

      - In GitHub, send a pull request to - - scully:main - - . -

      -
    14. -
    - - -

    - That's it! Thank you for your contribution! -

    -

    - After your pull request is merged -

    -

    - After your pull request is merged, you can safely delete your branch and pull the changes -from the main (upstream) repository: -

    - -
  • -

    - Update your main with the latest upstream version: -

    -
    -                    
    +                  
    +                    
    +                      Utilities
    +                    
    +                  
    +                  
    +                  
    +                  
      +
    • - git pull --ff upstream main - -
    + + + +
  • +
  • + + + +
  • + -

    +
  • + - - - Commit Message Guidelines -
  • -

    - We have very precise rules over how our git commit messages can be formatted. This leads to - - more -readable messages - - that are easy to follow when looking through the - - project history - - . -

    -

    - Commit Message Format -

    -

    - Each commit message consists of a - - header - - , a - - body - - and a - - footer - - . The header has a special -format that includes a - - type - - , a - - scope - - and a - - subject - - : -

    -

    - - The command - - npm run commit - - was previously configured to use all these rules - -

    -
    -                
    -                  <type>(<scope>): <subject>
    -<BLANK LINE>
    -<body>
    -<BLANK LINE>
    -<footer>
    -                
    -              
    -

    - The - - header - - is mandatory and the - - scope - - of the header is optional. -

    -

    - Any line of the commit message cannot be longer 100 characters! This allows the message to be easier -to read on GitHub as well as in various git tools. -

    -

    - The footer should contain a - - closing reference to an issue - - if any. -

    -

    - Samples from Angular Repository: (even more - - samples - - ) -

    -
    -                
    -                  docs(changelog): update changelog to beta.5
    -                
    -              
    -
    -                
    -                  fix(release): need to depend on latest ng-lib
    -
    -The version in our package.json gets copied to the one we publish, and users need the latest of these.
    -                
    -              
    -

    - Type -

    -

    - Must be one of the following: -

    -
      -
    • - - build - - : Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm) -
    • -
    • - - docs - - : Documentation only changes -
    • -
    • - - feat - - : A new feature -
    • -
    • - - fix - - : A bug fix -
    • -
    • - - perf - - : A code change that improves performance -
    • -
    • - - refactor - - : A code change that neither fixes a bug nor adds a feature -
    • -
    • - - style - - : Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc) -
    • -
    • - - test - - : Adding missing tests or correcting existing tests -
    • -
    -

    - Scope -

    -

    - The scope should be the name of the npm package affected (as perceived by the person reading the changelog generated from commit messages). -

    -

    - The following is the list of supported scopes: -

    -
      -
    • - - scully - -
    • -
    • - - ng-lib - -
    • -
    • - - schematics - -
    • -
    -

    - Subject -

    -

    - The subject contains a succinct description of the change: -

    -
      -
    • - use the imperative, present tense: "change" not "changed" nor "changes" +
      +
      + + Community + + + -

      - Body -

      -

      - Just as in the - - subject - - , use the imperative, present tense: "change" not "changed" nor "changes". -The body should include the motivation for the change and contrast this with previous behavior. -

      - -

      - The footer should contain any information about - - Breaking Changes - - and is also the place to -reference GitHub issues that this commit - - Closes - - . -

      -

      - - Breaking Changes - - should start with the word - - BREAKING CHANGE: - - with a space or two newlines. The rest of the commit message is then used for this. -

      -

      - Signing the CLA -

      -

      - Please sign our Contributor License Agreement (CLA) before sending pull requests. For any code changes to be accepted, the CLA must be signed. It's a quick process, we promise! -

      - - +
    • +
    + +
    + + + +
    +

    + Scully site Showcase +

    + + - - -
    -
    - - - +
    + +
    +
    + `; -exports[`docsSite should have content for all markdown files check html for markdown docs/Introduction 1`] = ` +exports[`docsSite should have content for all markdown files check html for markdown docs/community/support 1`] = ` @@ -2327,36 +4666,8 @@ exports[`docsSite should have content for all markdown files check html for mark href="favicon.ico" > - - - - - - - beta - - scullyLogo + beta - -
    - - - - - - - - - - -
    - - - -

    - Introduction (Alpha) + + + +
    + + + +
    +

    + Support

    -

    - What is Scully? -

    -

    - - Scully - - is the best static site generator for Angular projects looking to embrace the JAMStack. -

    -

    - How does it work? -

    -

    - Under the hood, Scully analyzes an Angular application, and it generates a static version of it. In addition, it is - - EASY TO USE - - because it provides several Angular schematics. -

    -

    - Scully works on Windows, Linux and macOS. -

    -

    - Visit one of the following topics: -

    - -
    -

    +

    Join the Scully community on - + Gitter + .

    -

    +

    Scully - + Office Hours - every Tuesday at noon MST -

    -
    -

    - Do you want to collaborate to scully? -

    -

    - The team would love your feedback and how you are using Scully with other tools. -

    -

    - Want to share your experience with the community? Please check our - - CONTRIBUTING - - guidelines. + Google Meet every Tuesday at noon MST.

    - + - -

    -
    -
    -
    -
    - -
    + + + + + + `; -exports[`docsSite should have content for all markdown files check html for markdown docs/blog 1`] = ` +exports[`docsSite should have content for all markdown files check html for markdown docs/learn/command-line-options 1`] = ` @@ -2979,36 +5822,8 @@ exports[`docsSite should have content for all markdown files check html for mark href="favicon.ico" > - - - - - - - beta - - scullyLogo + beta - -
    - - - - - - - - - - -
    - - - -

    - Creating a Blog -

    -

    - Scully is the best option for moving a blog to Angular! It provides a schematic that enables Angular applications to use markdown files for blog's content. -

    -

    - This guide covers the following topics: -

    -
      -
    1. +
    2. + + + baseFilter + + +
    3. +
    4. - Adding Blog Support + + proxyConfig +
    5. -
    6. +
    7. - Generating New Blog Posts + + removeStaticDist +
    8. -
    -

    - - IMPORTANT: +

  • + + + open + + +
  • +
  • + + + scanRoutes + + +
  • +
  • + + + ssl + + +
  • +
  • + + + ssl-cert + + +
  • +
  • + + + ssl-key + + +
  • +
  • + + + highlight + + +
  • +
  • + + + tds + + +
  • +
  • + + + pluginsError + + +
  • + +

    + + serve + +

    +
    +                
    +                  npx scully serve
    +                
    +              
    +

    + Starts the scully server. This process does not + + build - If you do not have an Angular app with Scully, please check the - - getting started - - guide first. + the project. It only serves the Angular build files, and the Scully static files.

    -

    - Adding Blog Support -

    -

    - Add blog support by running the following command: +

    + + watch + +

    +
    +                
    +                  npx scully --watch
    +                
    +              
    +

    + By default, Scully has the watchMode in false. You need to add this flag to use Watch Mode.

    -
    -                
    -                  ng generate @scullyio/init:blog
    +              

    + + showBrowser + +

    +
    +                
    +                  npx scully --showBrowser
                     
                   
    -

    - The above command adds the blog modules' routes to the Angular application. In addition, it creates a - - ./blog +

    + Alias + + --sb - folder for the blog's markdown files. In case you want to use a different folder name, run the following command: + . Chromium browser renders the application.

    -
    -                
    -                  ng generate @scullyio/init:markdown
    +              

    + + showGuessError + +

    +
    +                
    +                  npx scully --showGuessError
                     
                   
    -

    - You will be prompted with the following questions; +

    + Alias + + --sge + + . Displays Guess-Parse's errors in the console.

    -
    -                
    -                  ? What name
    -                  
    -                    do
    -                  
    -                  you want to use
    -                  
    -                    for
    -                  
    -                  the module? blog
    -? What slug
    -                  
    -                    do
    -                  
    -                  you want
    -                  
    -                    for
    -                  
    -                  the markdown file? title
    -? Where
    -                  
    -                    do
    -                  
    -                  you want to store your markdown files? mdblog
    -? Under
    -                  
    -                    which
    -                  
    -                  route
    -                  
    -                    do
    -                  
    -                  you want your files to be requested? blog
    +              

    + + configFile + +

    +
    +                
    +                  npx scully --configFile someName
                     
                   
    -

    - After adding the blog support, you should see the following message: +

    + Alias + + --cf + + . Loads a different config file. If it is used at the same time as the + + --project + + flag, the project flag takes precedence.

    -
    -                
    -                  ✅️ Update scully.{{yourApp}}.config.js
    -UPDATE scully.{{yourApp}}.config.js (653 bytes)
    -UPDATE src/app/app-routing.module.ts (726 bytes)
    -UPDATE src/app/blog/blog-routing.module.ts (429 bytes)
    -UPDATE src/app/blog/blog.component.css (157 bytes)
    -UPDATE src/app/blog/blog.component.html (160 bytes)
    -UPDATE src/app/blog/blog.component.spec.ts (639 bytes)
    -UPDATE src/app/blog/blog.component.ts (508 bytes)
    -UPDATE src/app/blog/blog.module.ts (391 bytes)
    -    ✅️ Blog ./mdblog/2020-03-24-blog.md file created
    -CREATE mdblog/2020-03-24-blog.md (95 bytes)
    +              

    + + project + +

    +
    +                
    +                  npx scully --project someName
                     
                   
    -

    - Alternatively, it is possible to run the - - @scullyio/init:markdown +

    + Alias + + --pr - command with flags to avoid the prompts as follows: + . It is used to select a different project. Scully uses the default project from generated by the the Angular CLI.

    -
    -                
    -                  ng generate @scullyio/init:markdown --name=
    -                  
    -                    "blog"
    -                  
    -                  --slug=
    -                  
    -                    "title"
    -                  
    -                  --
    -                  
    -                    source
    -                  
    -                  -dir=
    -                  
    -                    "mdblog"
    -                  
    -                  --route=
    -                  
    -                    "blog"
    -                  
    +              

    + + baseFilter + +

    +
    +                
    +                  npx scully --baseFilter /someRoute
                     
                   
    -

    - The following table shows all available options: +

    + Alias + + --bf + + . Enables Scully to start rendering a specific route.

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Option - - Description - - Default -
    - - name - - - Defines the name for the created module - - 'blog' -
    - - slug - - - Defines the name for the url matcher file. - - :slug - - - 'id' -
    - - routingScope - - - Sets a routing scope ( - - Root - - or - - Child - - ) - - Child -
    - - sourceDir - - - Defines a source directory name (default: - - name - - ) - - value from - - name - - option -
    - - route - - - Defines a route path before the - - :slug - - (default: - - name - - ) - - value from - - name - - option -
    -

    - Scully works well in combination with other tools and - - utilities +

    + + proxyConfig + +

    +

    + Alias + + --proxy + + . Takes a relative filename for a proxy config file. +

    +

    + For more details look at + + http-proxy-middleware .

    -

    - For instance, if the markdown content includes code blocks, and you want to highlight them; use a utility. +

    + Scully uses the same config format as + + webpackDevServer + + .

    -

    - Generating New Blog Posts -

    -

    - To create a new blog post, run the following command: +

    + + removeStaticDist + +

    +
    +                
    +                  npx scully --removeStaticDist
    +                
    +              
    +

    + Alias + + --RSD + + . Removes the static folder generated by Scully from previous renders.

    -
    -                
    -                  ng generate @scullyio/init:post --name=
    -                  
    -                    "This is my post"
    +              

    + + open + +

    +
    +                
    +                  npx scully serve/watch --open
    +                
    +              
    +

    + Alias + + --o + + . Opens the default browser and renders the dist folder generated by Scully. +

    +

    + + scanRoutes + +

    +

    + Alias + + --sr + + or + + --scan + + . Scans the application again to find unhandled routes. This is normally done just once. When routes in the application are added or changed, use this flag to discover all the new routes. +

    +

    + + ssl + +

    +
    +                
    +                  npx scully serve/watch --ssl
    +                
    +              
    +

    + Runs the Scully server with ssl. +

    +

    + + ssl-cert + +

    +
    +                
    +                  npx scully serve/watch --ssl --ssl-cert
    +                  
    +                    =
                       
    +                  ./url/to/file
                     
                   
    -

    - The following table shows all available options: +

    + Adds a url to the ssl certificate file for a server with SSL.

    - - - - -
    - option - - description +

    + + ssl-key + +

    +
    +                
    +                  npx scully serve/watch --ssl --ssl-key
    +                  
    +                    =
    +                  
    +                  ./url/to/file
    +                
    +              
    +

    + Adds a url to an ssl key file for a server with SSL. +

    +

    + + highlight + +

    +
    +                
    +                  npx scully serve/watch --hl
    +                
    +              
    +

    + Add highlight.js to render into the markdown's files. +

    +

    + If you use this flag, you need to add the css into the index.html: +

    +
    +                
    +                  
    +                    
    +                      
    +                        <
    +                      
    +                      link
    +                    
    +                    
    +                      rel
    +                    
    +                    
    +                      
    +                        =
    +                      
    +                      
    +                        "
    +                      
    +                      stylesheet
    +                      
    +                        "
    +                      
    +                    
    +                    
    +                      href
    +                    
    +                    
    +                      
    +                        =
    +                      
    +                      
    +                        "
    +                      
    +                      //cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/styles/default.min.css
    +                      
    +                        "
    +                      
    +                    
    +                    
    +                      />
    +                    
    +                  
    +                
    +              
    +

    + + tds + +

    +
    +                
    +                  npx scully --tds
    +                
    +              
    +

    + Launches the Test Data Server. This is only helpful for demos. +

    +

    + The following APIs are supported on the test data server: +

    + + + + - - - - + + - - - - + - - + + + - - + - - + + +
    + api - default + + returns
    - - name +
    + + /users - Define the name for the created post - - 'blog-X' + + A list of users
    - - target +
    + + /users/:id - Define the target directory for the new post file + + Just one user by id - 'blog' +
    + + /posts + + + A list of posts
    - - metaDataFile +
    + + /posts/:id - Use a meta data yaml template from a file for the post + + A post by id - undefined +
    + + /slow/:delay + + + 200 code after a delay has gone by. Eg: + + /slow/2000 + + takes 2 seconds.
    -

    - New blog post example -

    -

    - Let's look at an example. We want to create a new blog post so we type the following in the terminal - - ng generate @scullyio/init:post --name="Angular tutorial" - - . This triggers the following output: -

    -
    -                
    -                  ng generate @scullyio/init:post --name="Angular tutorial"
    -? What's the target folder for this post? blog
    -    ✅️ Blog ./blog/angular-tutorial.md file created
    -CREATE blog/angular-tutorial.md (99 bytes)
    -                
    -              
    -

    - Above you are prompted where you want to place your blog post. You go with default, which is the - - blog/ - - directory. You can then see above how the file - - angular-tutorial.md - - is created with this message: -

    -
    -                
    -                  CREATE blog/angular-tutorial.md
    -                
    -              
    -

    - Let's have a look at the generated - - angular-tutorial.md +

    + + pluginsError - : -

    -
    -                
    -                  ---
    -title: Angular tutorial
    -description: blog description
    -                  
    -                    published: false
    ----
    -                  
    -                  
    -                    # Angular tutorial
    +              

    +
    +                
    +                  npx scully --pluginsError
    +                  
    +                    =
                       
    +                  false
                     
                   
    -

    - At the top of the file there is a frontmatter, a set of instructions Scully is using. Those are: +

    + Show the error from the plugin, but continue rendering. +If you do not use the flag (by default is true) when you have an error into any plugin, the scully's run exit.

    -
      -
    • - - title - - , this is the title of the blog post -
    • -
    • - - description - - , this is the description -
    • -
    • - - published - - , this is a property representing whether the blog post is published or not. It takes a - - true - - or - - false - - . -
    • -
    -

    - Generating the blog post route -

    -

    - Next you want to build Scully to generate the route. Type the following in the terminal: -

    -
    -                
    -                  npm run scully
    -                
    -              
    -

    - The above will start a process that will generate pages. Have a look at your - - angular-tutorial.md - - file again, it has changed. Now the file contains the following: -

    -
    -                
    -                  ---
    -title: 'Angular tutorial'
    -description: 'blog description'
    -published: false
    -slugs:
    -                  
    -                    -
    -                  
    -                  
    -                    __
    -                    
    -                      _UNPUBLISHED
    -                      
    -                        __
    -                        
    -                          _kao8mvda_
    -                        
    -                        pmldPr7aN7owPpStZiuDXFZ1ILfpcv5Z
    ----# Angular tutorial
    -                      
    -                    
    -                  
    -                
    -              
    -

    - The property - - slugs - - have been added to the frontmatter above. - - slugs - - contains an anonymous URL as long as the property - - published - - is set to - - false - - . This is a URL that you can share with others to for example get feedback on your blog post before it goes live. -

    -
    -

    - NOTE, when you gave the command to build Scully the blog post you just created in Markdown was converted to HTML and placed in the directory - - dist/static/blog/<anonymous slug value>/index.html - - . -

    -
    -

    - Serve the website -

    -

    - Now that page and the route has been generated, let's serve up the application and ensure it works. Type the following command to serve the static site built by Scully: -

    -
    -                
    -                  npm run scully serve
    -                
    -              
    -

    - The command will give an output looking like so: -

    -
    -                
    -                  Angular distribution server started on "http://localhost:1864/"
    -Scully static server started on "http://localhost:1668/"
    -                
    -              
    -

    - Open up a browser window and navigate to the URL - - http://localhost:1668/ - - : -

    -

    - Your blog post can be found on the URL - - http://localhost:1668/blog/<anonymous slug> - - , which if you check the frontmatter above means the following URL - - http://localhost:1668/blog/___UNPUBLISHED___kao8mvda_pmldPr7aN7owPpStZiuDXFZ1ILfpcv5Z - - . -

    -

    - You should now see the following output in the browser: -

    -
    -                
    -                  ScullyIo content
    -Angular tutorial
    -End of content
    -                
    -              
    -

    - Going live -

    -

    - At some point you are happy about the blog post you just authored. At this point you want to open up - - angular-tutorial.md - - and change the - - published - - property to - - true - - to publish it. Also clear the - - slugs - - property so it no longer has the anonymous slug value. The file should now look like this: -

    -
    -                
    -                  ---
    -title: 'Angular tutorial'
    -description: 'blog description'
    -                  
    -                    published: true
    ----
    -                  
    -                  
    -                    # Angular tutorial
    -                  
    -                
    -              
    -

    - Run the following command: -

    -
    -                
    -                  npm run scully
    -                
    -              
    -

    - This time around it will render a different route. By default Scully will create a route with the same name as the markdown file minus the extension. Have a look at - - dist/static/blog - - and you will see it looks like so: -

    -
    -                
    -                  --| dist
    -----| static
    -------| blog
    ---------| angular-tutorial
    -----------| index.html
    -                
    -              
    -

    - Let's serve this up with the command: -

    -
    -                
    -                  npm run scully serve
    -                
    -              
    -

    - Open up your browser and navigate to the URL - - http://localhost:1668/blog/angular-tutorial - - . -

    -

    - Overriding the slug -

    -

    - If you are - - not - - happy with Scully's convention of creating the slug based on the filename, you can change that by introducing the - - slug - - property in the frontmatter of the markdown file. Change the - - angular-tutorial.md - - file to the following: -

    -
    -                
    -                  ---
    -title: 'Angular tutorial'
    -description: 'blog description'
    -published: true
    -                  
    -                    slug: angularjs-still-rocks
    ----
    -                  
    -                  
    -                    # Angular tutorial
    -                  
    -                
    -              
    -

    - Above the - - slug - - property has been added and assigned the value - - angularjs-still-rocks - - . This will instruct Scully to use this as the route instead. Now generate the routes anew with this command: -

    -
    -                
    -                  npm run scully
    -                
    -              
    -

    - Note how the - - dist/static/blog - - folder now has a new entry, namely - - angular-js-still-rocks/index.html - - . -

    -

    - Serving up the static app with: -

    -
    -                
    -                  npm run scully serve
    -                
    -              
    -

    - The blog post can now be found at - - http://localhost:1668/blog/angularjs-still-rocks - - . -

    - + - - -
    -
    - - - + + + + + `; -exports[`docsSite should have content for all markdown files check html for markdown docs/blog_es 1`] = ` +exports[`docsSite should have content for all markdown files check html for markdown docs/learn/config 1`] = ` @@ -4295,36 +7526,8 @@ exports[`docsSite should have content for all markdown files check html for mark href="favicon.ico" > - - - - - - - beta - - scullyLogo + beta - -
    - - - - - - - - - - -
    - - - -

    - Crear un blog -

    -

    - Scully es la mejor opción para mover tu blog a Angular! -

    -

    - Tiene un schematic que permite que las aplicaciones de Angular utilicen archivos de markdown para el contenido del blog. -

    -
      -
    1. +
    2. - Agregar soporte de Blog + Interface
    3. -
    4. +
    5. - Generar una nueva publicacion de blog + Properties +
    6. -
    -

    - - IMPORTANTE: - - Solo necesita una aplicación Angular con Scully, si no la tiene, puedes verificarlos en - - Comenzando - - . -

    -

    - Agregar soporte de Blog + +

    + Overview

    -

    - Para agregar soporte de blog a su aplicación, ejecute el siguiente comando: -

    -
    -                
    -                  ng generate @scullyio/init:blog
    -                
    -              
    -

    - Este comando agrega el módulo y las funciones de blog a su aplicación. Además, crea una carpeta - - ./blog +

    + The central part of a Scully project is the + + scully.<projectname>.config.ts - para los archivos de markdown del blog. + file. This file exports the Scully build configuration for an application.

    -

    - Para crear una carpeta con un nombre diferente, ejecute el siguiente comando: +

    + If you are new to Scully, it is recommended to read the + + Getting Started + + documentation.

    -
    -                
    -                  ng generate @scullyio/init:markdown
    +              

    + The + + scully.<projectname>.config.ts -

    -

    - Y va a aparecer una serie de preguntas, para que completes: + file's structure is shown below:

    -
    -                
    -                  ? What name
    -                  
    -                    do
    +              

    + Interface +

    +
    +                
    +                  
    +                    export
                       
    -                  you want to use
    -                  
    -                    for
    +                  
    +                    interface
                       
    -                  the module? blog
    -? What slug
    -                  
    -                    do
    +                  
    +                    ScullyConfig
                       
    -                  you want
    -                  
    -                    for
    +                  
    +                    {
                       
    -                  the markdown file? title
    -? Where
    -                  
    -                    do
    +                  
    +                    /** is this a bare project (without angular.json?) */
                       
    -                  you want to store your markdown files? mdblog
    -? Under
    -                  
    -                    which
    +                  bareProject
    +                  
    +                    ?
                       
    -                  route
    -                  
    -                    do
    +                  
    +                    :
                       
    -                  you want your files to be requested? blog
    -                
    -              
    -

    - o puedes hacerlo manualmente -

    -
    -                
    -                  ng generate @scullyio/init:markdown --name=
    -                  
    -                    "blog"
    +                  
    +                    boolean
                       
    -                  --slug=
    -                  
    -                    "title"
    +                  
    +                    ;
                       
    -                  --
    -                  
    -                    source
    +                  
    +                    /** the name of the project we are using. Provided by Scully itself */
                       
    -                  -dir=
    -                  
    -                    "mdblog"
    +                  projectName
    +                  
    +                    ?
                       
    -                  --route=
    -                  
    -                    "blog"
    +                  
    +                    :
                       
    -                
    -              
    -

    - Y el resultado es: -

    -
    -                
    -                  ✅️ Update scully.{{yourApp}}.config.js
    -UPDATE scully.{{yourApp}}.config.js (653 bytes)
    -UPDATE src/app/app-routing.module.ts (726 bytes)
    -UPDATE src/app/blog/blog-routing.module.ts (429 bytes)
    -UPDATE src/app/blog/blog.component.css (157 bytes)
    -UPDATE src/app/blog/blog.component.html (160 bytes)
    -UPDATE src/app/blog/blog.component.spec.ts (639 bytes)
    -UPDATE src/app/blog/blog.component.ts (508 bytes)
    -UPDATE src/app/blog/blog.module.ts (391 bytes)
    -    ✅️ Blog ./mdblog/2020-03-24-blog.md file created
    -CREATE mdblog/2020-03-24-blog.md (95 bytes)
    -                
    -              
    -

    - - NOTA: - - Slug es el nombre del url matcher para buscar el archivo. -

    -

    - La siguiente tabla muestra todas las opciones disponibles: -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Opcion - - Descripcion - - Defecto -
    - - name - - - Define el nombre del modulo - - 'blog' -
    - - slug - - - Define el nombre del slug - - :slug - - - 'id' -
    - - routingScope - - - Setea el routing scope ( - - Root - - o - - Child - - ) - - Child -
    - - sourceDir - - - Define el nombre de source directory (defecto: - - name - - ) - - value from - - name - - option -
    - - route - - - Define el path route antes del - - :slug - - (defecto: - - name - - ) - - value from - - name - - option -
    -

    - Scully funciona bien en combinación con otras herramientas y - - utilidades - - . -

    -

    - Por ejemplo, si el contenido de markdown incluye bloques de código, y desea resaltarlo, puedes usar una utilidad. -

    -

    - Generar una nueva publicacion de blog -

    -

    - Para crear una nueva publicación de blog, ejecute el siguiente comando: -

    -
    -                
    -                  ng generate @scullyio/init:post --name=
    -                  
    -                    "This is my post"
    +                  
    +                    string
                       
    -                
    -              
    -

    - La siguiente tabla muestra todas las opciones disponibles: -

    - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Opcion - - Descripcion - - Defecto -
    - - name - - - Define el nombre para el post creado - - 'blog-X' -
    - - target - - - Defina el directorio de destino para el nuevo archivo de publicación - - 'blog' -
    - - metaDataFile - - - Utilice una plantilla de metadatos yaml de un archivo para la publicación - - undefined -
    - - - -
    -
    -
    -
    -
    - -
    - - -`; - -exports[`docsSite should have content for all markdown files check html for markdown docs/faq 1`] = ` - - - - - - - ScullyDocs - - - - - - - - - - - - - - - beta - - scullyLogo - -
    - - - - - - - -
    - - - -

    - Frequently Asked Questions -

    -
    - - language in route? - -
    -

    - In my project i have a routing like this: -
    - /:lang -
    - /:lang/page1 -
    - /:lang/page2 -
    - etc... -
    -

    -

    - It's very simple. :lang can have few values (it, en...) and If possible I prefer to store it in the config, without have -an endpoint dedicated. -
    - How can I solve this? -

    -
    -

    - As the Scully config file is typescript, you can post-process the routing object. a very crude solution would be something like this: -

    -
    -                  
    -                    
    -                      import
    -                    
    -                    { ScullyConfig }
    -                    
    -                      from
    -                    
    -                    
    -                      '@scullyio/scully'
    -                    
    +                  
                         ;
    -                    
    -                      const
    -                    
    -                    preLangConfig: ScullyConfig = {
    -                    
    -                      /** settngs */
    -                    
    -                    routes: {
    -                    
    -                      ':lang/route1'
    -                    
    -                    : {
    -                    
    -                      type
    -                    
    +                  
    +                  
    +                    /** the folder where project is. Can be any off the projects in a repo, read from angular.json */
    +                  
    +                  projectRoot
    +                  
    +                    ?
    +                  
    +                  
                         :
    -                    
    -                      'default'
    -                    
    -                    },
    -                    
    -                      ':lang/route2'
    -                    
    -                    : {
    -                    
    -                      type
    -                    
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /** the folder where the project sources resides, read from angular.json */
    +                  
    +                  sourceRoot
    +                  
    +                    ?
    +                  
    +                  
                         :
    -                    
    -                      'default'
    -                    
    -                    },
    -                    
    -                      ':lang/route3'
    -                    
    -                    : {
    -                    
    -                      type
    -                    
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /** Array with string ID's of the content-renderers that will be run on all routes */
    +                  
    +                  defaultPostRenderers
    +                  
    +                    ?
    +                  
    +                  
                         :
    -                    
    -                      'default'
    -                    
    -                    },
    -                    
    -                      ':lang/route4'
    -                    
    -                    : {
    -                    
    -                      type
    -                    
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    [
    +                  
    +                  
    +                    ]
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /** the root of the project (where angular.json lives) */
    +                  
    +                  homeFolder
    +                  
    +                    ?
    +                  
    +                  
                         :
    -                    
    -                      'default'
    -                    
    -                    },
    -  },
    -};
    -                    
    -                      export
    -                    
    -                    
    -                      const
    -                    
    -                    config = {
    -  ...preLangConfig,
    -  routes:
    -                    
    -                      Object
    -                    
    -                    .fromEntries(
    -                    
    -                      // make sure you use a node-version that supports this, or use a reduce.
    -                    
    -                    
    -                      Object
    -                    
    -                    .entries(preLangConfig.routes).reduce(
    -                    
    -                      (
    -                      
    -                        all, [route, config]
    -                      
    -                      ) =>
    -                    
    -                    {
    -                    
    -                      if
    -                    
    -                    (route.includes(
    -                    
    -                      ':lang'
    -                    
    -                    )) {
    -        [
    -                    
    -                      'it'
    -                    
    -                    ,
    -                    
    -                      'en'
    -                    
    -                    ,
    -                    
    -                      'nl'
    -                    
    -                    ,
    -                    
    -                      'sp'
    -                    
    -                    ].forEach(
    -                    
    -                      (
    -                      
    -                        lang // <-- language array
    -                      
    -                      ) =>
    -                    
    -                    all.push([route.split(
    -                    
    -                      ':lang'
    -                    
    -                    ).join(lang), config]));
    -      }
    -                    
    -                      else
    -                    
    -                    {
    -        all.push([route, config]);
    -      }
    -                    
    -                      return
    -                    
    -                    all;
    -    }, [])
    -  ),
    -};
    -                    
    -                      console
    -                    
    -                    .log(config.routes);
    -                  
    -                
    -

    - It takes the - - preLangConfig - - and iterates over all the routes. When it finds the - - :lang - - parameter, it creates an entry with every value provided in the language array. That way the final config will have a route for every language available. -

    -
    -
    - - Ignore routes without config? - -
    -

    - In my app I have a lot of routes I don't want scully to handle. How can I deal with that. -

    -
    -

    - Scully will use the - - default - - plugin for any route that is not specified. When you want to have another way to handle defaults, you can replace this plugin with another one. -For example, if you want to ignore all undefined routes you can do: -

    -
    -                  
    -                    registerPlugin(
    -                    
    -                      'router'
    -                    
    -                    ,
    -                    
    -                      'default'
    -                    
    -                    , findPlugin(
    -                    
    -                      'ignored'
    -                    
    -                    ));
    -                  
    -                
    -

    - In case you want to have some more control, you can create a custom plugin: -

    -
    -                  
    -                    registerPlugin(
    -                    
    -                      'router'
    -                    
    -                    ,
    -                    
    -                      'default'
    -                    
    -                    ,
    -                    
    -                      async
    -                    
    -                    (route:
    -                    
    -                      string
    -                    
    -                    ):
    -                    
    -                      Promise
    -                    
    -                    <HandledRoute[]> => {
    -                    
    -                      if
    -                    
    -                    (route ===
    -                    
    -                      'somethingSpecial'
    -                    
    -                    ) {
    -                    
    -                      return
    -                    
    -                    [{ route,
    -                    
    -                      type
    -                    
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /** the destination of the Scully generated files */
    +                  
    +                  outDir
    +                  
    +                    ?
    +                  
    +                  
                         :
    -                    
    -                      'somethingElse'
    -                    
    -                    }];
    -    }
    -                    
    -                      if
    -                    
    -                    (route ===
    -                    
    -                      'somethingSpecial/:id'
    -                    
    -                    ) {
    -                    
    -                      const
    -                    
    -                    data = httpGetJson(
    -                    
    -                      'someEndPoint'
    -                    
    -                    );
    -                    
    -                      // fetch some json
    -                    
    -                    
    -                      const
    -                    
    -                    { createPath } = routeSplit(route);
    -                    
    -                      const
    -                    
    -                    routes: HandledRoutes[] = [];
    -                    
    -                      for
    -                    
    -                    (
    -                    
    -                      const
    -                    
    -                    row
    -                    
    -                      of
    -                    
    -                    data) {
    -        routes.push({ route: createPath(row.id),
    -                    
    -                      type
    -                    
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /** the place where distribution files of the project are. Should be a subfolder of dist. */
    +                  
    +                  distFolder
    +                  
    +                    ?
    +                  
    +                  
                         :
    -                    
    -                      'default'
    -                    
    -                    });
    -      }
    -                    
    -                      return
    -                    
    -                    routes;
    -    }
    -                    
    -                      return
    -                    
    -                    [];
    -  },
    -                    
    -                      undefined
    -                    
    -                    ,
    -  { replaceExistingPlugin:
    -                    
    -                      true
    -                    
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /** transferState only inlined into page, and not written into separate data.json */
    +                  
    +                  inlineStateOnly
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    boolean
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /** Set what is what is written to the logfile, defaults to warnings and errors */
    +                  
    +                  logFileSeverity
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  LogSeverity
    +                  
    +                    ;
    +                  
    +                  
    +                    /** routes that need additional processing have their configuration in here */
    +                  
    +                  routes
    +                  
    +                    :
    +                  
    +                  RouteConfig
    +                  
    +                    ;
    +                  
    +                  
    +                    /** routes that are in the application but have no route in the router */
    +                  
    +                  extraRoutes
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    |
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    [
    +                  
    +                  
    +                    ]
    +                  
    +                  
    +                    |
    +                  
    +                  
    +                    Promise
    +                  
    +                  
    +                    <
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    [
    +                  
    +                  
    +                    ]
    +                  
    +                  
    +                    |
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    >
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /** Port-number where the original application is served */
    +                  
    +                  appPort
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    number
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /** Boolean that determines saving of site-tumbnails files */
    +                  
    +                  thumbnails
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    boolean
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /** port-number where the Scully generated files are available */
    +                  
    +                  staticport
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    number
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /** port for the live reload service */
    +                  
    +                  reloadPort
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    number
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /** optional proxy config file, uses the same config file as the CLI */
    +                  
    +                  proxyConfig
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /** optional launch-options for puppeteer */
    +                  
    +                  puppeteerLaunchOptions
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  LaunchOptions
    +                  
    +                    ;
    +                  
    +                  
    +                    /** hostname to use for local server, defaults to \`localhost\` */
    +                  
    +                  hostName
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /** optional hostURL, if this is provided, we are going to use this server instead of the build-in one. */
    +                  
    +                  hostUrl
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /** optional guessParserOptions, if this is provided we are going to pass those options to the guess parser. */
    +                  
    +                  guessParserOptions
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  GuessParserOptions
    +                  
    +                    ;
    +                  
    +                  
    +                    /** the maximum of concurrent puppeteer tabs open. defaults to the available amounts of cores */
    +                  
    +                  maxRenderThreads
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    number
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /** the resource types to ignore when generating pages via Puppeteer */
    +                  
    +                  ignoreResourceTypes
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  ResourceType
    +                  
    +                    [
    +                  
    +                  
    +                    ]
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /** how to handle 404 in Scully server */
    +                  
    +                  handle404
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ;
    +                  
    +                  
                         }
    -);
    -                  
    -                
    -
    -
    - - How do I fix plugin build errors related to the \`express-serve-static-core\` module? - -

    - Building a plugin results in a fatal error - - Cannot find module 'express-serve-static-core' - - , originating from - - node_modules/@scullyio/scully/lib/utils/serverstuff/staticServer.d.ts + + + +

    + Properties +

    +

    + The + + ScullyConfig + + interface provides parameters for configuring how Scully works in a project. +

    +

    + + projectRoot?: + + + + string -

    -

    - To correct this, add the - - skipLibCheck + +

    +

    + The project's from which Scully generates the static content. +

    +

    + + homeFolder?: + + + + string - and - - skipDefaultLibCheck + +

    +

    + A reference to the Angular project's root folder. +
    + This property is for internal use, and it defaults to the angular.json file's location. +

    +

    + + outDir?: + + + + string - flags to your - - tsconfig.json + +

    +

    + The folder's path where Scully leaves the statics files. +
    + This should not be the same as the + + distFolder + + . +The default path is: +

    +
    +                
    +                  ./dist/static
    +                
    +              
    +

    + + distFolder?: + + + + string - => - - compilerOptions + +

    +

    + Path to the Angular application's dist folder. +
    + Scully takes the + + angular.json + + file's default path, and will use this folder during rendering. +
    + This option can be modified according to your needs. +

    +

    + + logFileSeverity: + + + + LogSeverity - like this: -

    -
    -                  
    -                    {
    -                    
    -                      "compileOnSave"
    -                    
    -                    :
    -                    
    -                      false
    -                    
    -                    ,
    -                    
    -                      "compilerOptions"
    -                    
    -                    : {
    -                    
    -                      "skipLibCheck"
    -                    
    -                    :
    -                    
    -                      true
    -                    
    -                    ,
    -                    
    -                      "skipDefaultLibCheck"
    -                    
    -                    :
    -                    
    -                      true
    -                    
    -                    }
    -}
    -                  
    -                
    -

    - - - -
    -
    -
    -
    -
    -
    - -
    - - -`; - -exports[`docsSite should have content for all markdown files check html for markdown docs/features 1`] = ` - - - - - - - ScullyDocs - - - - - - - - - - - - - - - beta - - scullyLogo - -
    - - - - - - - -
    - - - -

    - Scully's Features -

    -

    - Under the hood, Scully analyzes an Angular application and generates a static -version of it. It provides several Angular schematics to make -its usage AS EASY AS POSSIBLE! + + +

    + Determines what of the Scully output will be written into the + + scully.log + + file in the root of the project.

    -

    - - Core Features - + + + + + + + + + + + + + + + + + + + + + +
    + option + + result +
    + + 0 + + + Logs everything +
    + + 1 + + + Logs warnings and errors only +
    + + 2 + + + Logs errors only +
    +

    + + routes: + + + + RouteConfig + + +

    +

    + Scully has two types of routes, + + unhandled routes + + and + + handled routes + :

    -
      -
    • - Idle Monitor Service -
    • -
    • - Router Service -
    • -
    • - Scully Content Component -
    • -
    • - Transfer State Service -
    • -
    • - Utility Methods -
    • -
    -

    - - Plugins System - - : +

    + Unhandled Routes +
    +

    + Routes with dynamic data. This are the routes as you would use them inside your app. Those routes can come from the automated route discovery, or from the extraRoutes property in the + + scully.<projectname>.config.ts + + . Eg:

    -
      -
    • - Router Plugins -
    • -
    • - Render Plugins -
    • -
    • - File Handler Plugins -
    • -
    • - AllDone Plugins -
    • -
    • - routeDiscoveryDone Plugins -
    • -
    -

    - - Schematics +

    +                
    +                  /foo/:id
    +                
    +              
    +

    + All unhandled routes with dynamic data need to be handled through plugins. When there is a route with dynamic data that has no configuration in the configs routes, it will be logged to screen and skipped during processing. +

    +

    + + This means there will be NO STATIC FILES for ROUTES which HAVE DYNAMIC DATA but NO CONFIG + +

    +

    + For more information about router plugins read the + + Plugins - : + documentation.

    -
      -
    • - Install and create files for Scully (ng-add). -
    • -
    • - Creating a blog config for Scully & Angular. -
    • -
    • - Generate a plugin's skeleton. -
    • -
    • - Run the router discovery. -
    • -
    • - Create markdown files and skeleton. -
    • -
    - - - -
    -
    -
    - -
    - +
    + Handled Routes +
    +

    + Routes with static params. Eg: +

    +
    +                
    +                  /foo/1
    +                
    +              
    +

    + + extraRoutes?: + + + + string | string[] | Promise<string[] | string> + + +

    +

    + Allows developers to add an array of unhandled routes. These routes can exist in AngularJS, React, or any other framework. +

    +
    +                
    +                  extraRoutes
    +                  
    +                    :
    +                  
    +                  
    +                    [
    +                  
    +                  
    +                    '/foo/:id'
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    new
    +                  
    +                  
    +                    Promise
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    '/bar/:barId'
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    new
    +                  
    +                  
    +                    Promise
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    [
    +                  
    +                  
    +                    '/foo/:fooId'
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    '/bar/:id'
    +                  
    +                  
    +                    ]
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    ]
    +                  
    +                  
    +                    ;
    +                  
    +                
    +              
    +

    + + appPort?: + + + + number + + +

    +

    + Scully provides a server to to render the Angular application. +

    +

    + Configure the port where the Angular application runs. +

    +

    + The default port is: + + 1864 + +

    +

    + + staticPort?: + + + + number + + +

    +

    + Similar to + + + + appPort + + + + , + + staticport + + provides a server to to render the static files compiled by Scully. +

    +

    + The default port is: + + 1668 + +

    +

    + + proxyConfig?: + + + + string + + +

    +

    + Takes a relative filename for a proxy config file. +

    +

    + For more details look at + + http-proxy-middleware + +
    + Scully uses the same config format as + + webpackDevServer + +
    + This is an optional property, and it is also used by the + + Angular CLI + +

    +

    + This can also be provided with the + + --proxy filname + + command line flag +

    +

    + + puppeteerLaunchOptions?: + + + + LaunchOptions + + +

    +

    + If the application is in a restricted environment, puppeteer's default options may not work. In that case, +this option can be overwrite with settings that match a specific environment. +

    +

    + + A word of warning, + + some settings might interfere with the way Scully is working, creating inaccurate results. +
    + Read about + + puppeteerlaunchoptions + + for more information. +

    +

    + + hostName?: + + + + string + + +

    +

    + Allows to set a different name for the + + localhost + + . +

    +

    + + hostUrl?: + + + + string + + +

    +

    + Connects your application to a different host. This is useful when using your own server. +

    +

    + + guessParserOptions?: + + + + GuessParserOptions + + +

    +

    + The + + guessParserOptions + + that get passed to the + + guess-parser + + library. +

    +

    + Currently, the only supported property is + + excludedFiles + + , and it excludes files from the + + guess-parser + + route discovery process. +

    +

    + + ignoreResourceTypes?: + + + + ResourceType[] + + +

    +

    + The + + ignoreResourceTypes + + array that get passed to the + + puppeteerRenderPlugin + + . +Any + + ResourceType + + that is listed here will be ignored by the Puppeteer instance rendering the requested page. +
    + For example if you add + + image + + and + + font + + all requests to images and fonts loaded on your pages will be ignored. +

    +

    + + handle404?: + + + + string + + +

    +

    + How routes which are + + not + + provided in the application, are handled by the Scully server. +
    + When the server gets a request for a route (file) that does not exist on the file-system, this option amends how that route is handled. +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + option + + result +
    + + "" + + (default) + + Will render a 404 page, and raise a waring during rendering. +
    + + index + + + Will render the + + index.html + + from the dist root folder. +
    + + baseOnly + + + Will use express route matcher on unhandled routes only. +
    + + 404 + + + Will render the + + 404.html + + from the dist root folder. +
    + + none + + + Will leave it up to the express software layer. +
    + + + + + + + `; -exports[`docsSite should have content for all markdown files check html for markdown docs/features_es 1`] = ` +exports[`docsSite should have content for all markdown files check html for markdown docs/learn/core-features/idle-monitor-service 1`] = ` @@ -6870,36 +10007,8 @@ exports[`docsSite should have content for all markdown files check html for mark href="favicon.ico" > - - - - - - - beta - - scullyLogo + beta - -
    - - - - - - - - - - -
    - - - -

    - Caracteristicas de Scully + + + +
    + + + +
    +

    + + IdleMonitorService +

    -

    - Tras bambalinas, Scully analiza la aplicación de Angular y genera una versión estática de esta. Proporciona varios esquemas (schematics) de Angular para -hacer su uso LO MÁS SENCILLO POSIBLE! -

    -

    - - Características Principales - - : -

    -
      -
    • - Servicio de Monitor Sin Utilizar (Idle Monitor Service) -
    • -
    • - Servico de Rutas (Router Service) -
    • -
    • - Componente de Contenido de Scully (Scully Content Component) -
    • -
    • - Servicio de Transferencia de Estado (Transfer State Service) -
    • -
    • - Métodos de Utilería (Utility Methods) -
    • -
    -

    - - Sistema de Plugins - - : -

    -
      -
    • - Router Plugins -
    • -
    • - Render Plugins -
    • -
    • - File Handler Plugins -
    • -
    • - AllDone Plugins -
    • -
    • - routeDiscoveryDone Plugins -
    • -
    -

    - + - Schematics - : -

    -
      -
    • - Instalar y crear archivos para Scully (ng-add). -
    • -
    • - Crear y cnfigurar un blog config para Scully & Angular. -
    • -
    • - Generar el esqueleto de un plugin. -
    • -
    • - Correr el descubrimiento de rutas. -
    • -
    • - Crear esqueletos de archivos markdown. -
    • -
    - - - -

    -
    -
    -
    -
    - -
    - - -`; - -exports[`docsSite should have content for all markdown files check html for markdown docs/getting-started 1`] = ` - - - - - - - ScullyDocs - - - - - - - - - - - - - - - beta - - scullyLogo - -
    - - - - - - - -
    - - - -

    - Getting Started with Scully -

    -

    - Welcome to Scully! -

    -

    - Before getting started, please read the - - Prerequisites +

    + Overview +

    +

    + The + + + IdleMonitorService + + + hooks into Zonejs. It is located in the + + + ScullyLibModule + .

    -

    - - - All about Scully in one video - +

    + When Angular goes idle + + (more precisely, when all outgoing HTTP requests finish) - : - - Building the Fastest Angular Apps Possible - + Scully triggers Puppeteer in order to know when it is ready to render.

    -

    - This getting started guide covers the following topics: +

    + If your content is loaded out of sight of zones, Scully scrapes the page before its ready.

    -
      -
    1. - - Installation - -
    2. -
    3. - - Building - -
    4. -
    5. - - Serving - -
    6. -
    7. - - Tips for Testing - -
    8. -
    -
    -

    - Installation +

    + Adding Custom Mechanisms

    -

    - - Before adding Scully to your Angular project; make sure that -your project has at least one route set up. If you have questions about adding -routes, see the - - Angular routing docs - - . - -

    -

    - Adding Scully to your project is as simple as running one command: -

    -
    -                
    -                  ng add @scullyio/init
    -                
    -              
    -

    - If you have an Angular workspace, Scully by default take the default project from your - - angular.json - - , if you want to install Scully in another project run: -

    -
    -                
    -                  ng add @scullyio/init --project=<projectName>
    -                
    -              
    -

    - If you are using a - - NX +

    + To disable Scully ready mechanism and add a custom mechanism, put following config object in the + + forRoot - vanilla workspaces (non Angular workspace) + config:

    -
    -                
    -                  npm install @scullyio/init
    -nx g @scullyio/init:install -- --project=<projectName>
    +              
    +                
    +                  ScullyLibModule
    +                  
    +                    .
    +                  
    +                  
    +                    forRoot
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    {
    +                  
    +                  useTransferState
    +                  
    +                    :
    +                  
    +                  
    +                    true
    +                  
    +                  
    +                    ,
    +                  
    +                  alwaysMonitor
    +                  
    +                    :
    +                  
    +                  
    +                    false
    +                  
    +                  
    +                    ,
    +                  
    +                  manualIdle
    +                  
    +                    :
    +                  
    +                  
    +                    true
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    ;
    +                  
                     
                   
    -

    - - NOTE - - : After installation, if you were serving the app during the installation; you need to restart - - ng serve - - . -

    -

    - Running the - - @scullyio/init - - schematic makes all the necessary changes the Angular -project, so you do not need to go through a lengthy setup process. +

    + This will cause Scully to fall-back to using a 25 second timeout, on every page rendered.

    -

    - The command above creates a Scully config file named - - scully.<projectName>.config.ts +

    + Then in your component, trigger the + + fireManualMyAppReadyEvent() - , where the - - projectName - - is the name of your Angular project. This file looks like this:

    -
    -                
    -                  
    -                    import
    +              
    +                
    +                  
    +                    export
                       
    -                  { ScullyConfig }
    -                  
    -                    from
    +                  
    +                    class
                       
    -                  
    -                    '@scullyio/scully'
    +                  
    +                    ManualIdleComponent
                       
    -                  ;
    -                  
    -                    export
    +                  
    +                    implements
                       
    -                  
    -                    const
    +                  
    +                    OnInit
                       
    -                  config: ScullyConfig = {
    -  projectRoot:
    -                  
    -                    './src'
    +                  
    +                    {
                       
    -                  ,
    -  projectName:
    -                  
    -                    '<projectName>'
    +                  text
    +                  
    +                    =
                       
    -                  ,
    -  outDir:
    -                  
    -                    './dist/static'
    +                  
    +                    'this text is displayed by automated detection'
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    constructor
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    
    +                      private
    +                    
    +                    ims
    +                    
    +                      :
    +                    
    +                    IdleMonitorService
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    {
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    ngOnInit
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    void
    +                  
    +                  
    +                    {
    +                  
    +                  
    +                    setTimeout
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    =>
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    this
    +                  
    +                  
    +                    .
    +                  
    +                  text
    +                  
    +                    =
    +                  
    +                  
    +                    '__ManualIdle__'
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    3
    +                  
    +                  
    +                    *
    +                  
    +                  
    +                    1000
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    setTimeout
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    =>
    +                  
    +                  
    +                    this
    +                  
    +                  
    +                    .
    +                  
    +                  ims
    +                  
    +                    .
    +                  
    +                  
    +                    fireManualMyAppReadyEvent
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    3.25
    +                  
    +                  
    +                    *
    +                  
    +                  
    +                    1000
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    }
                       
    -                  ,
    -  routes: {},
    -};
    -                
    -              
    -

    - Even with this basic config, you are now ready to build your Angular app using Scully for the first time! -

    -

    - - NOTE - - : It is important to know that any routes in the Angular project that contain route parameters -will not be pre-rendered until you modify the above config to account for those parameters. -

    -

    - - HERE - - is an example of how to configure route parameters with Scully. -

    -
    -

    - Building the Scully Application -

    -

    - Running Scully for the first time is exciting. Congrats on making it here! -

    -

    - Before Scully can run you need to build your Angular project. Most projects' built is: -

    -
    -                
    -                  ng build
                     
                   
    -

    - Now that the Angular project is built, Scully can do its work. Run Scully with the following command: -

    -
    -                
    -                  npm run scully
    +              

    + To enable this for single route, provide + + manualIdle: true -

    -

    - You did it! You have turned your Angular app into a wicked fast pre-rendered static site thanks to Scully. -

    -

    - The Scully-built version of the project is located in the - - ./dist/static + inside the + + config.ts - folder. It contains all the static pages in the project. -

    -

    - - NOTE - - : In case of any errors or warnings during the build process, please follow the instructions in the errors/warnings section or - - submit an issue - - . -

    -

    - - NOTE - - : The following is a common error when building with Scully for the first time: + file in the route configuration:

    -
    -                
    -                  No configuration
    -                  
    -                    for
    +              
    +                
    +                  
    +                    // scully.config.ts
    +                  
    +                  
    +                    export
    +                  
    +                  
    +                    const
    +                  
    +                  config
    +                  
    +                    :
    +                  
    +                  ScullyConfig
    +                  
    +                    =
    +                  
    +                  
    +                    {
    +                  
    +                  routes
    +                  
    +                    :
    +                  
    +                  
    +                    {
    +                  
    +                  
    +                    '/user/:userId'
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    {
    +                  
    +                  
    +                    type
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    'json'
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    // Add the following to your route
    +                  
    +                  exposeToPage
    +                  
    +                    :
    +                  
    +                  
    +                    {
    +                  
    +                  manualIdle
    +                  
    +                    :
    +                  
    +                  
    +                    true
    +                  
    +                  
    +                    }
    +                  
    +                  userId
    +                  
    +                    :
    +                  
    +                  
    +                    {
    +                  
    +                  url
    +                  
    +                    :
    +                  
    +                  
    +                    'http://localhost:8200/users'
    +                  
    +                  
    +                    ,
    +                  
    +                  property
    +                  
    +                    :
    +                  
    +                  
    +                    'id'
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    ;
                       
    -                  route \`/user/:userId\` found. Skipping
    -                
    -              
    -

    - This message indicates that Scully has skept any unconfigured routes. Read more about - - Route Parameters & Scully - - . -

    -
    -

    - Serving -

    -

    - Once the app is built with Scully, see the output and test how it runs as a statically generated webpage. -

    -

    - To see the pre-rendered site, open the - - /dist/static - - folder where you can find one - - index.html - - for every route in your app. Hence, if the application has 1000 routes, there should be 1000 - - index.html - - files in the - - dist/static - - folder. -These - - index.html - - files are jamstack-packed with HTML and CSS. This means that Scully built successfully, and that your site is now pre-rendered. -

    -

    - Scully provides a server, so that you can test out your jamstack site after the Scully build. To launch Scully's test server, run the following command: -

    -
    -                
    -                  npm run scully:serve
    -                
    -              
    -

    - This command actually launches - - 2 (two) - - servers. The first one is hosting the results of - - ng build - - , and the second server hosts the results of the Scully build. This allows you to test both versions of your built app. Very cool! -

    -
    -

    - Tips for Testing -

    -

    - Only rebuild Angular if you change Angular -

    -

    - Although this may seem evident; if this is your first time using Scully, it is easy rebuild Angular even if it is not needed. When writing Scully plugins OR modifying your blog's markdown files, you DO NOT need to - - ng build - - the app each time you re-run Scully. Again, - - ng build - - Angular if the Angular app changes. -

    -

    - Whenever you are confused about re-running the Angular build, just ask yourself: Did I change the Angular code, or the Scully code? -

    -

    - Scully Serve -

    -

    - Running - - npm run scully - - pre-builds your project with Scully. Any time a plugin or a markdown file change, re-run this process. In addition, if any of the content that the Angular app depends on changes, you need to re-run the Scully build. -

    -

    - To make the - - serve - - process easier run the following command: -

    -
    -                
    -                  npm run scully -- --watch
                     
                   
    -

    - Running Scully build with the - - --watch - - option live-reloads the Scully build. In other words, It watches for any changes from the Angular build or from any of the markdown files. If any of those change, the Scully build re-executes, and it serves the new results in realtime. -

    -

    - - NOTE - - : This is ideal for a faster development, but DO NOT use the - - --watch - - option during production or any devops proccess or the build will never finish. -

    - + - -
    -
    -
    -
    -
    - + + + + +
    `; -exports[`docsSite should have content for all markdown files check html for markdown docs/getting-started_es 1`] = ` +exports[`docsSite should have content for all markdown files check html for markdown docs/learn/core-features/scully-content-component 1`] = ` @@ -8389,36 +11586,8 @@ exports[`docsSite should have content for all markdown files check html for mark href="favicon.ico" > - - - - - - - beta - - scullyLogo + beta - -
    - - - - - - - - - - -
    - - - -

    - Iniciando con Scully + + + +
    + + + +
    +

    + + ScullyContentComponent +

    -

    - ¡Bienvenido a Scully! -

    -

    - Antes de iniciar, por favor lea los - + - Prerrequisitos - . + +

    + Overview +

    +

    + The + + + scully-content + + + component inserts the render process' result into the HTML document.

    -

    - - - Todo acerca de Scully en un video - +

    + + NOTE: - : - - Construyendo las Apps de Angular más rápidas + The + + + scully-content + -

    -

    - La guia de inicio cubre los siguientes temas: -

    -
      -
    1. - - Instalación - -
    2. -
    3. - - Construcción - -
    4. -
    -

    - Instalación -

    -

    - Primero, abra abra la ruta de su aplicación de Angular en una terminal y corra el siguiente comando: -

    -
    -                
    -                  ng add @scullyio/init
    +                component does not work inside an
    +                
    +                  *ngIf
                     
    -              
    -

    - Una ves se ha instalado exitosamente se mostrará el siguiente mensaje: -

    -
    -                
    -                  Installing packages
    -                  
    -                    for
    -                  
    -                  tooling via npm.
    -Installed packages
    -                  
    -                    for
    -                  
    -                  tooling via npm.
    -    Install ng-lib
    -                  
    -                    for
    -                  
    -                  Angular v9
    -    ✅️ Added dependency
    -UPDATE src/app/app.module.ts (466 bytes)
    -UPDATE src/polyfills.ts (3031 bytes)
    -UPDATE package.json (1378 bytes)
    -√ Packages installed successfully.
    -    ✅️ Update package.json
    -    ✅️ Created scully configuration file
    -                  
    -                    in
    -                  
    -                  scully.{{yourApp}}.config.js
    -CREATE scully.{{yourApp}}.config.js (109 bytes)
    -UPDATE package.json (1438 bytes)
    -                
    -              
    -

    - Generar un Blog -

    -

    - Corra el siguiente comando para generar un módulo de blog. + directive.

    -

    - - más información aquí + + +

    + +
    +
    + + + + +`; + +exports[`docsSite should have content for all markdown files check html for markdown docs/learn/core-features/scully-routes-service 1`] = ` + + + + + + + ScullyDocs + + + + + + + + + + beta + +
    +

    -

    - Crear un - - Módule de Inicio - - con las rutas configuradas y con un - - Componente de Inicio - - ; con el siguiente comando: -

    -
    -                
    -                  ng generate module home --route=home --module=app-routing
    -                
    -              
    -

    - - Scully depende del - - punto de entrada de las rutas (route entry point) - - . - -

    -

    + Learn + + + - Configurar el Módulo de Inicio como la Raíz del Proyecto -

    -

    - Abra el archivo - - app-routing.module.ts - - y agregue un atributo de ruta de inicio, como se muestra a continuación: -

    -
    -                
    +                
    +
    + +
      +
    • + + + Introduction + + +
    • +
    • - - const - - routes: Routes = [ - - // ... - - { - path: - - '' - - , - loadChildren: - - () => - - - import - - ( - - './home/home.module' - - ).then( - - - m + + Getting started - => - - m.HomeModule) - } -]; - -
    -

    - Inyectando el Servicio de Rutas de Scully -

    -

    - Scully proporciona un servicio para acceder a las rutas generadas de una manera sencilla. -

    -

    - Abra el archivo - - home.component.ts - - y agregue el siguiente código: -

    -
    -                
    +                  
    +                  
    +                  
    +                
    +                
  • - - import - - { ScullyRoutesService } - + Create a blog + + + + + +
  • +
  • + - from - - + Config + + +
  • +
  • + - '@scullyio/ng-lib' - - ; - + Command line options + + +
  • +
  • + - import - - { Observable } - + FAQ + + +
  • +
  • + - from - - - 'rxjs' - - ; - + + + Core features + + + +
  • +
  • + - @Component - - () - - //... - - + + + Legacy support + + + +
  • +
  • + - export - - - class - - HomeComponent - - implements - - OnInit { - links$: Observable< - - any - - > = - - this - - .scully.available$; - - constructor - - ( - - - private + + Plugins - scully: ScullyRoutesService - - ) {} - - ngOnInit() { - - // debug current pages - - - this - - .links$.subscribe( - - + + +
      +
    • - links - - => - - { - - console - - .log(links); - }); - } -} - -
  • -

    - Ahora es posible iterar a través de los links dentro de la plantilla al abrir el archivo - - home.component.html - - y agregando el siguiente código: -

    -
    -                
    +                        
    +                          Overview
    +                        
    +                      
    +                    
    +                    
  • + + + Register a new plugin + + +
  • +
  • + + + Types + + + + + +
  • +
  • + + + +
  • +
  • + + + +
  • + + +
  • - - < - - p - - > - - home works! - - </ - - p +
    +
    + + Schematics - > -
    - - < - + +
  • +
  • + + + Utilities - = - + + + +
  • + + +
  • + + +
  • -

    - - NOTA: - - Si no se agrega el servicio de rutas de Scully, las páginas no se procesarán y no se mostrarán. -

    -

    - Construyendo la Aplicación de Scully -

    -

    - En este punto el proyecto de Angular con Scully está listo. -

    -

    - Primero, construya la aplicación de Angular con el comando: -

    -
    -                
    +                
    +                
  • - ng build - -
  • -

    - Ahora, construya con Scully para convertir la ap de Angular en un citio estático preprocesado. -

    -
    -                
    +                    
    +                      Showcase
    +                    
    +                  
    +                
    +                
  • - npm run scully - -
  • -

    - ¡Felicidades! Ha convertido su aplicación de Angular en un sitio estatico extremadamente rápido gracias a Scully. -

    -

    - La versión estática del sitio se localiza en el archivo - - ./dist/static + + + Support + + + + + + + +

    + + + +
    +

    + + ScullyRoutesService - . Contiene todas las páginas estáticas. -

    -

    - - NOTA: - - En caso de cualquier error o advertencia durante el proceso de construcción, por favor siga las instrucciones en la saección de errores/advertencias o - +

    +
    +
    + +

    + Overview +

    +

    + The + + + ScullyRoutesService + + + provides methods and observables that allow you to know the routes rendered by Scully.

    -

    - Servir el Sitio Estático +

    + Interface

    -

    - Sirva el contenido del sitio estático con el comando: +

    + The + + + ScullyRoutesService + + + 's types come from the + + + ScullyRoute + + + interface:

    -
    -                
    -                  npm run scully serve
    +              
    +                
    +                  
    +                    export
    +                  
    +                  
    +                    interface
    +                  
    +                  
    +                    ScullyRoute
    +                  
    +                  
    +                    {
    +                  
    +                  route
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ;
    +                  
    +                  title
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ;
    +                  
    +                  slugs
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    [
    +                  
    +                  
    +                    ]
    +                  
    +                  
    +                    ;
    +                  
    +                  published
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    boolean
    +                  
    +                  
    +                    ;
    +                  
    +                  slug
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    [
    +                  
    +                  prop
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ]
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    any
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    }
    +                  
                     
                   
    -

    - Este comando crea dos servidores web, uno para la aplicación de Angular y uno para la ap de Scully. +

    + Observables & Methods +

    +

    + + available$: + + + + Observable<ScullyRoute[]> + + +

    +

    + Returns routes containing the property + + published + + with a value of true.

    -

    - Deshabilitando JS -

    -

    - - Extra - - : Mientras se está sirviendo la ap de Scully, - - deshabilite JavaScript - - y la navegación del sitio aun funciona. Pero sobre todo, la mayor parte del sitio aun funciona a pesar de que JS ha sido deshabilitado. +

    + + unPublished$: + + + + Observable<ScullyRoute[]> + + +

    +

    + Returns routes containing the property + + published + + with a value of false.

    -

    - Debugging de la Aplicación de Scully -

    -

    - - Extra - - : Para poder hacer debug en la aplicación de Scully con ngServe, asegúrese de correr: +

    + + topLevel$: + + + + Observable<ScullyRoute[]> + + +

    +

    + Returns the top-level routes.

    -
    -                
    -                  npm run scully
    +              

    + + getCurrent(): -

    -

    - Ahora, inicie el servidor: + + + Observable<ScullyRoute> + + + +

    + A method that returns the current location.

    -
    -                
    -                  npm run scully:serve
    +              

    + + reload(): -

    -

    - Scully usa el HTML generado para llenar el contenido de la sesión - - ng serve + + + void + + + +

    + A method that checks if new routes have been added to the + + scully-routes.json - . + file.

    - + - -
    -
    -
    -
    -
    - + + + + +
    `; -exports[`docsSite should have content for all markdown files check html for markdown docs/introduccion 1`] = ` +exports[`docsSite should have content for all markdown files check html for markdown docs/learn/core-features/transfer-state-service 1`] = ` @@ -9506,36 +14328,8 @@ exports[`docsSite should have content for all markdown files check html for mark href="favicon.ico" > - - - - - - - beta - - scullyLogo + beta - -
    - - - - - - - - - - -
    - - - -

    - Introducción (Alfa) -

    -

    +
  • + - ¿Qué es Scully? -
  • -

    - - Scully - - el mejor generador de sitios estáticos para proyectos de Angular buscando adoptar JAMStack. -

    -

    - ¿Cómo funciona? -

    -

    - Tras bambalinas, Scully analiza la plicación de Angular y genera una versión estática de esta. Además, es - - FACIL DE USAR - - porque proporciona varios esquemas (schematics) de Angular. -

    -

    - Scully funciona en Windows, Linux y macOS. -

    -

    - Visite uno de los siguientes temas: -

    -
    -
    -
    -
    -
    - + + + + +
    `; -exports[`docsSite should have content for all markdown files check html for markdown docs/issues 1`] = ` +exports[`docsSite should have content for all markdown files check html for markdown docs/learn/core-features/utility-methods 1`] = ` @@ -10156,36 +15644,8 @@ exports[`docsSite should have content for all markdown files check html for mark href="favicon.ico" > - - - - - - - beta - - scullyLogo + beta - -
    - - - - - - - - - - -
    - - - -

    - Issues -

    -

    - To create a bug report: Go to - - Scully Bug template - - . +

    + Overview +

    +

    + These methods provide useful information about Scully processes.

    -

    - To propose a new feature: Go to - - Scully Feature request - +

    + + isScullyRunning(): + + + + boolean + + +

    +

    + This method returns + + true + + or + + false + + if the Scully build is currently running.

    -

    - The Scully team is working on better documentation for creating issues. +

    + + isScullyGenerated(): + + + + boolean + + +

    +

    + This method returns + + true + + if the Scully build has run.

    - + -
    -
    -
    -
    -
    -
    - + + + + +
    `; -exports[`docsSite should have content for all markdown files check html for markdown docs/plugins 1`] = ` +exports[`docsSite should have content for all markdown files check html for markdown docs/learn/create-a-blog/add-blog-support 1`] = ` @@ -10684,36 +16869,8 @@ exports[`docsSite should have content for all markdown files check html for mark href="favicon.ico" > - - - - - - - beta - - scullyLogo + beta - -
    - - - - - - - - - - -
    - - - -

    - Plugins -

    -

    - Scully uses a plugin system that allows users to define new ways for Scully to pre-render an application. There are five main -types of plugins: -

    -
      -
    1. - - Router Plugin - -
    2. -
    3. - - Render Plugin - -
    4. -
    5. - - File Handler Plugin - -
    6. -
    7. - - routeDiscoveryDone plugin - -
    8. -
    9. - - allDone plugin + + Plugins + + + +
    10. -
    -

    - You can find a list of available plugins in the - - recommended plugins - - documentation. -

    -
    -

    - Registering a Plugin -

    -

    - The - - registerPlugin - - function adds a new plugin to Scully. This function has 5 parameters: -

    - -

    - type: string -

    -

    - - type - - - Indicates the plugin's type. The existing types are: - - router - - , - - render - - , - - fileHandler - - , - - allDone - - , or - - routeDiscoveryDone - - . -

    -

    - name: string -

    -

    - - name - - - The plugin's name. This must be unique for the type of plugin. To replace an existing plugin, set the - - replaceExistingPlugin - - option. -

    -

    - plugin: any -

    -

    - - plugin - - - The plugin's function. It contains the plugin's logic. The plugin types are described in their own type descriptions -

    -

    +
  • + - validator: function (optional) -
  • -

    - - validator - - - A validation function. It should return an array of errors. if there are no errors, it should return a - - false - - value. If it returns a - - string<array> - - , those strings are displayed as errors, and the process is aborted. -

    -
    -

    - Tip: Add color to the validator errors by using the colors exported from Scully. -

    -
    -
    - Validator Example -
    -
    -                
    +                
    +                
    +                  Community
    +                
    +              
    +              
    +            
    +          
    +        
    +        
    + + + +
    +

    + Adding blog support +

    +
    +
    +
    -

    - Options -

    -

    - The - - optinal - - object can be used to set the plugin options. At the moment, the only available option is - - replaceExistingPlugin - - . -

    -

    - Router Plugin + Extending functionality + + + +

    + Overview

    -

    - Any route in the application that contains a router-parameter must be configured in a - - router plugin +

    + Scully is the best option for moving a blog to Angular! +It provides a schematic that enables Angular applications to use markdown files for your blog's content. +

    +

    + + IMPORTANT: - . The plugin teaches Scully how to get the required data to be pre-render in the web-pages from the route-params. + If you don't have an Angular app with Scully, please check the + + Getting Started guide + + first.

    -

    - Suppose the application has a route like this one: - - {path: 'user/:userId', component: UserComponent} +

    + Usage +

    +

    + Add blog support by running the following command: +

    +
    +                
    +                  ng generate @scullyio/init:blog
                     
    -                . In order for Scully to pre-render the website, it needs to know the complete list of User IDs that will be used in that route parameter
    -                
    -                  :userId
    +              
    +

    + The above command adds the blog modules' routes to the Angular application. +
    + In addition, it creates a + + ./blog - . If the app had 5 users with the IDs 1, 2, 3, 4, and 5; Scully would need to render the following routes: + folder for the blog's markdown files.

    -
    -                
    -                  /user/1
    -/user/2
    -/user/3
    -/user/4
    -/user/5
    +              

    + In case you want to use a different folder name, run the following command: +

    +
    +                
    +                  ng generate @scullyio/init:markdown
                     
                   
    -

    - A - - router plugin - - is used to convert the raw route-config into a list of routes that Scully can then crawl/render. +

    + You will be prompted with the following questions:

    -

    - - HandledRoute - - interface -

    -
    -                
    -                  
    -                    interface
    -                  
    -                  RouteConfig {
    -                  
    -                    /** this route does a manual Idle check */
    -                  
    -                  manualIdleCheck?:
    -                  
    -                    boolean
    -                  
    -                  ;
    -                  
    -                    /** type of the route  */
    -                  
    -                  
    -                    type
    -                  
    -                  ?:
    -                  
    -                    string
    -                  
    -                  ;
    -                  
    -                    /**
    -   * an optional function that will be executed on render.
    -   * Receives the route string, and the config of this route.
    -   */
    -                  
    -                  preRenderer?:
    -                  
    -                    (
    -                    
    -                      route: HandledRoute
    -                    
    -                    ) =>
    -                  
    -                  
    -                    Promise
    -                  
    -                  <
    -                  
    -                    void
    -                  
    -                  |
    -                  
    -                    false
    -                  
    -                  >;
    -                  
    -                    /** Allow in every other setting possible, depends on plugins */
    -                  
    -                  [key:
    -                  
    -                    string
    -                  
    -                  ]:
    -                  
    -                    any
    -                  
    -                  ;
    -}
    -                  
    -                    export
    -                  
    -                  
    -                    interface
    -                  
    -                  HandledRoute {
    -                  
    -                    /** the _complete_ route */
    -                  
    -                  route:
    -                  
    -                    string
    +              
    +                
    +                  ? What name
    +                  
    +                    do
                       
    -                  ;
    -                  
    -                    /** String, must be an existing plugin name */
    +                  you want to use
    +                  
    +                    for
                       
    -                  
    -                    type
    +                  the module? blog
    +? What slug
    +                  
    +                    do
                       
    -                  :
    -                  
    -                    string
    +                  you want
    +                  
    +                    for
                       
    -                  ;
    -                  
    -                    /** the relevant part of the scully-config  */
    +                  the markdown file? title
    +? Where
    +                  
    +                    do
                       
    -                  config?: RouteConfig;
    -                  
    -                    /** variables exposed to angular _while rendering only!_ */
    +                  you want to store your markdown files? mdblog
    +? Under
    +                  
    +                    which
                       
    -                  exposeToPage?: {
    -    manualIdle?:
    -                  
    -                    boolean
    +                  route
    +                  
    +                    do
                       
    -                  ;
    -    transferState?: Serializable;
    -    [key:
    -                  
    -                    string
    +                  you want your files to be requested? blog
    +                
    +              
    +

    + After adding the blog support, you should see the following message: +

    +
    +                
    +                  ✅️ Update scully.{{yourApp}}.config.js
    +UPDATE scully.{{yourApp}}.config.js (653 bytes)
    +UPDATE src/app/app-routing.module.ts (726 bytes)
    +UPDATE src/app/blog/blog-routing.module.ts (429 bytes)
    +UPDATE src/app/blog/blog.component.css (157 bytes)
    +UPDATE src/app/blog/blog.component.html (160 bytes)
    +UPDATE src/app/blog/blog.component.spec.ts (639 bytes)
    +UPDATE src/app/blog/blog.component.ts (508 bytes)
    +UPDATE src/app/blog/blog.module.ts (391 bytes)
    +    ✅️ Blog ./mdblog/2020-03-24-blog.md file created
    +CREATE mdblog/2020-03-24-blog.md (95 bytes)
    +                
    +              
    +

    + Alternatively, it is possible to run the + + @scullyio/init:markdown + + command with flags to avoid the prompts as follows: +

    +
    +                
    +                  ng generate @scullyio/init:markdown --name
    +                  
    +                    =
                       
    -                  ]: Serializable;
    -  };
    -                  
    -                    /** data will be injected into the static page */
    +                  
    +                    "blog"
                       
    -                  injectToPage?: {
    -    [key:
    -                  
    -                    string
    +                  --slug
    +                  
    +                    =
                       
    -                  ]: Serializable;
    -  };
    -                  
    -                    /** an array with render plugin names that will be executed */
    +                  
    +                    "title"
                       
    -                  postRenderers?:
    -                  
    -                    string
    +                  --source-dir
    +                  
    +                    =
                       
    -                  [];
    -                  
    -                    /** the path to the file for a content file */
    +                  
    +                    "mdblog"
                       
    -                  templateFile?:
    -                  
    -                    string
    +                  --route
    +                  
    +                    =
                       
    -                  ;
    -                  
    -                    /**
    -   * additional data that will end up in scully.routes.json
    -   * the frontMatter data will be added here too.
    -   */
    +                  
    +                    "blog"
                       
    -                  data?: RouteData;
    -}
                     
                   
    -

    - The - - HandledRoute - - interface provides the needed properties to develop your own plugin. -

    -

    - route: string -

    -

    - - route - - - An application route to be handled by Scully. This is the - - fully qualified - - route info. That means that there should be no variables left in there. Also no - - # - - are allowed, and query parameters are ignored. -

    -

    - type: RoutesTypes -

    -

    - - type - - - Indicates the type of plugin. Contains the name of the routing plugin that should handle this. This is a mandatory field that - - must - - be provided. When the type doesn't exist, Scully will terminate, as it doesn't know what to do. +

    + Available options +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Option + + Description + + Default +
    + + name + + + Defines the name for the created module + + 'blog' +
    + + slug + + + Defines the name for the url matcher file. + + :slug + + + 'id' +
    + + routingScope + + + Sets a routing scope ( + + Root + + or + + Child + + ) + + + Child + +
    + + sourceDir + + + Defines a source directory name (default: + + name + + ) + + value from + + name + + option +
    + + route + + + Defines a route path before the + + :slug + + (default: + + name + + ) + + value from + + name + + option +
    +

    + Create an entry point (Home page) +

    +

    + Create a + + Home Module + + with routes configured and with a + + Home Component + + with the following command:

    -

    - defaultPostRenderers?: string[] -

    -

    - - defaultPostRenderers +

    +                
    +                  ng generate module home --route
    +                  
    +                    =
    +                  
    +                  home --module
    +                  
    +                    =
    +                  
    +                  app-routing
                     
    -                - Array with string ID's of the content-renderers that will be run on all routes.
    +              
    +

    + + Scully depends on the + + route entry point + + . +

    -

    - postRenderers?: string[] -

    -

    - - postRenderers - - - Array of plugin names to be executed after the initial page render. Each of the plugins in this array will be rendered in the order they appear, and they will receive the output HTML from the previous plugin. -Moreover, this array - - replaces - - the - - defaultPostRenderers +

    + Configure entry point Module as project Root +

    +

    + Open the + + app-routing.module.ts - array. + file and set an empty path attribute for the home route as shown below:

    -
    -                
    -                  
    +              
    +                
    +                  
                         const
                       
    -                  defaultPostRenderers = [
    -                  
    -                    'seoHrefOptimise'
    +                  routes
    +                  
    +                    :
                       
    -                  ];
    -                  
    -                    const
    +                  Routes
    +                  
    +                    =
                       
    -                  sampleConf: ScullyConfig = {
    -  defaultPostRenderers,
    -  routes: {
    -                  
    -                    /** gets the default postrenderes */
    +                  
    +                    [
                       
    -                  normalRoute: {
    -                  
    -                    type
    +                  
    +                    // ...
                       
    -                  :
    -                  
    -                    'default'
    +                  
    +                    {
                       
    -                  },
    -                  
    -                    /** adds to the default postrenderes */
    +                  path
    +                  
    +                    :
                       
    -                  someRoute: {
    -                  
    -                    type
    +                  
    +                    ''
                       
    -                  :
    -                  
    -                    'default'
    +                  
    +                    ,
                       
    -                  ,
    -      postRenderers: [...defaultPostRenderers,
    -                  
    -                    'myAddition'
    +                  
    +                    loadChildren
                       
    -                  ]
    -    },
    -                  
    -                    /** removes the default postrenderes */
    +                  
    +                    :
                       
    -                  someOtherRoute: {
    -                  
    -                    type
    +                  
    +                    (
                       
    -                  :
    -                  
    -                    'default'
    +                  
    +                    )
                       
    -                  ,
    -      postRenderers: [
    -                  
    -                    'unique'
    +                  
    +                    =>
                       
    -                  ]
    -    }
    -  }
    -};
    -                
    -              
    -

    - The - - defaultPostRenderers - - and - - postRenderers - - are designed this way in order to allow you to dispose off the default renderers. -Moreover, the current design is versatile, flexible, and it makes it easy to opt-out. -

    -

    - Do not forget to add the - - defaultPostRenderers - - ! -

    -

    - templateFile?: string -

    -

    - - templateFile - - - Unrelated to the angular template!. The file's name containing the template to be rendered. This property is specific to contentFolder. It contains the full path to the file that should be used to generate the content. Remember that content will be inserted - - after - - the initial rendering. -

    -

    - data?: RouteData -

    -

    - - data - - - The data added to this property will be added to the routes data in the - - scully.routes.json - - . This data will also be extended in contentFolder routes with the front-matter data out of the start of the templateFile. -

    -
    -                
    -                  
    -                    export
    +                  
    +                    import
                       
    -                  
    -                    interface
    +                  
    +                    (
                       
    -                  RouteData {
    -  title?:
    -                  
    -                    string
    +                  
    +                    './home/home.module'
                       
    -                  ;
    -  author?:
    -                  
    -                    string
    +                  
    +                    )
                       
    -                  ;
    -  published?:
    -                  
    -                    boolean
    +                  
    +                    .
                       
    -                  ;
    -  [prop:
    -                  
    -                    string
    +                  
    +                    then
                       
    -                  ]:
    -                  
    -                    any
    +                  
    +                    (
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    m
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    =>
    +                  
    +                  m
    +                  
    +                    .
    +                  
    +                  HomeModule
    +                  
    +                    )
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    ]
    +                  
    +                  
    +                    ;
                       
    -                  ;
    -}
                     
                   
    -

    - Router Plugin Interface -

    -

    - A - - router plugin - - is a function that returns a - - Promise<HandledRoute[]> - - . The - - HandledRoute - - interface is described above. It receives a string with the unhandled route, and the config for that specific route. +

    + Extending functionality +

    +

    + Scully works well in combination with other tools and + + utilities + + .

    -

    - A router plugin function should be as follows: +

    + For instance, if the markdown content includes code blocks, and you want to highlight them; use a utility.

    -
    -                
    +                
    +              
    +              
    +              
    +            
    +            
    -

    - The - - HandledRoute[] - - gets its data added into the - - scully-routes.json - - file generated by the - - npm run scully - - command. -

    -

    - Making A Router Plugin -

    -

    - Lets implement the - - router plugin - - that turns the raw route into five distinct HandledRoutes from the previous example of an application containing the following route: - - /user/:userId - - . -

    -
    -                
    -                  const { registerPlugin } = require('@scullyio/scully');
    -
    -function userIdPlugin(route: string, config = {}): Promise<HandledRoute[]> {
    -  return Promise.resolve([
    -    { route: '/user/1' },
    -    { route: '/user/2' },
    -    { route: '/user/3' },
    -    { route: '/user/4' },
    -    { route: '/user/5' }
    -  ]);
    -}
    +                      Contribute
    +                    
    +                  
    +                  
  • + + Gitter Channel + +
  • +
  • + + Twitter + +
  • + + +
    +

    + Organization +

    + +
    + + + + + + + +`; -registerPlugin('router', 'userIds', userIdPlugin, validator); -
    -
    -

    - After implementing the plugin, configure the - - scully.config.ts - - in order to use it. -

    -

    - Configuring a Router Plugin -

    -

    - The following configuration uses the - - userIds - - router plugin to get the - - HandledRoute[] - - for the above implementation: -

    -
    -                
    +
    +  
    +    
    +    
    +    
    +      ScullyDocs
    +    
    +    
    +    
    +    
    +    
    +    
    +  
    +  
    +    
    +      beta
    +      
    +      
    -

    + + + +

    -

    - A - - render plugin - - is used to transform the rendered HTML. -

    -

    - After the Angular application renders, the HTML content is passed to a - - render plugin - - where it can be further modified. -

    -

    - A render plugin could be used to transform a page containing markdown into a page that renders it. -

    -

    + Learn + + + - Render Plugin Interface -

    -

    - A - - render plugin - - is a function that returns a - - Promise<String> - - . The string in the promise must be the transformed -HTML. The interface looks like this: -

    -
    -                
    +                
    +
    + +
      +
    • + + + Introduction + + +
    • +
    • - - - function + + Getting started - + + +
        +
      • - exampleContentPlugin - - ( - + + Requirements + + +
      • +
      • - HTML: - - string - - , - route: HandledRoute - - ): - + Installation + + +
      • +
      • - Promise - - < - + + Building + + +
      • +
      • - string - - > - - { - - // Must return a promise - - } - -
    -

    - Making A Render Plugin -

    -

    - The following - - render plugin - - example adds a title to the header to a page if it does not find one. -

    -
    -                
    +                        
    +                          Serving
    +                        
    +                      
    +                    
    +                    
  • + + + Tips for testing + + +
  • + + +
  • - - const - - { registerPlugin } = - - require - - ( - - '@scullyio/scully' - - ); - - - function + + Create a blog - + + +
      +
    • - defaultTitlePlugin - - ( - + + Add blog support + + +
    • +
    • - html, route - - ) - - { - - // If no title in the document - - + + Generate new blog posts + + +
    • +
    • + + + Use blog post data in template + + +
    • +
    +
  • +
  • + - if - - (html.indexOf( - + Config + + +
  • +
  • + - '<title' - - ) < - + Command line options + + +
  • +
  • + - 0 - - ) { - + FAQ + + +
  • +
  • + - const - - splitter = - - '</head>' - - ; - - const - - [begin, end] = html.split(splitter); - - const - - defaultTitle = - - \`<title>The Truth Is Out There!</title>\` - - ; - - return - - - Promise - - .resolve( - - \` - - \${begin} +
    +
    + + Core features - +
      +
    • - \${defaultTitle} - - + + Idle Monitor Service + + +
    • +
    • - \${splitter} - - + + Scully Content Component + + +
    • +
    • - \${end} - - \` - - ); - } - - return - - - Promise - - .resolve(html); -} - - // DON NOT FORGET REGISTER THE PLUGIN - - - const - - validator = - - async - - conf => []; -registerPlugin( - - 'render' - - , - - 'defaultTitle' - - , defaultTitlePlugin, validator); - - module - - . - - exports - - .defaultTitlePlugin = defaultTitlePlugin; - -
  • -

    - In the above example, the Angular app's HTML content is transformed to include a title because anyone was found. -

    -

    - The next example replaces any instances of - - :) - - with an smiley emoji. -

    -
    -                
    +                        
    +                          Scully Routes Service
    +                        
    +                      
    +                    
    +                    
  • + + + Transfer State Service + + +
  • +
  • + + + Utility methods + + +
  • + + +
  • - - const - - { registerPlugin } = - - require - - ( - - '@scullyio/scully' - - ); - - - function +
    +
    + + Legacy support - +
      +
    • - smileEmojiPlugin - - ( - + + Angular v8 + + +
    • +
    • - html, route - - ) - - { - - return - - - Promise - - .resolve(html.replace( - - /\\:\\)/g - - , - - '😊' - - )); -} - - // DON NOT FORGET REGISTER THE PLUGIN - - - const - - validator = - - async - - conf => []; -registerPlugin( - - 'render' - - , - - 'smiles' - - , smileEmojiPlugin, validator); - - module - - . - - exports - - .smileEmojiPlugin = smileEmojiPlugin; - -
  • -
    -

    - File Handler Plugin -

    -

    - A - - file handler plugin - - is used by the - - contentFolder - - plugin during the - - render - - process. The - - contentFolder - - plugin processes the folders for markdown files or other file type the folders may contain. The - - render - - process any existing - - fileHandler - - plugin for any file extension type. -

    -

    - Scully comes with two built-in - - fileHandler - - plugins. The - - markdown plugin - - and -the - - asciidoc plugin - - . These plugins handle and process the -content of those file types as they are read from the file system. -

    -

    - If you want to support - - .docx - - files, or - - .csv - - files, or any other file type; a file handler for those file types need to be added. -The - - contentFolder - - plugin takes care of reading those files from the filesystem. However, if the files need to be transformed after the - - contentFolder - - plugin reads them; -A - - fileHandler - - plugin is required. -

    -

    - File Handler Plugin Interface -

    -

    - A - - file handler plugin - - is a function that returns a - - Promise<string> - - . The interface looks like follows: -

    -
    -                
    +                        
    +                          Polyfills
    +                        
    +                      
    +                    
    +                  
    +                
    +                
  • - - - function + + Plugins - + + +
  • -

    - Making A File Handler Plugin -

    -

    - The following - - file handler plugin - - example handles - - .cvs - - files by wrapping them into a code block. You could write a much more elaborate plugin that creates a table or a grid for the data. -

    -
    -                
    +                      
    +                      
    +                    
    +                    
  • + + + +
  • + + +
  • - - - function +
  • +
  • + + + Utilities - ( - + + + +
  • + + +
  • + + + +
  • + + +
    + + + +
    +

    + Generating new blog posts +

    +
    +
    +
    -

    - File Handler Plugin Examples -

    -

    - Here are some links to built-in - - render plugins - - in Scully: -

    -
    -

    - RouteDiscoveryDone Plugin +

    + Overview

    -

    - This type of plugin is called automatically after all routes have been collected, and all router plugins have finished. It receives a shallow copy of the - - handledRoute - - array, and it returns - - void - - . +

    + To create a new blog post, run the following command:

    -

    - AllDone Plugin -

    -

    - An - - allDone - - plugin is like a - - routeDiscoveryDone +

    +                
    +                  ng generate @scullyio/init:post --name
    +                  
    +                    =
    +                  
    +                  
    +                    "This is my post"
    +                  
                     
    -                plugin, expect it is called
    -                
    -                  after
    -                
    -                Scully finishes executing all its processes.
    -              

    - - - -
    -
    -
    -
    -
    - -
    - - -`; - -exports[`docsSite should have content for all markdown files check html for markdown docs/plugins_es 1`] = ` - - - - - - - ScullyDocs - - - - - - - - - - - - - - - beta - - scullyLogo - -
    - - - - - - - -
    - - - -

    - Plugins -

    -

    - Scully utiliza un sistema de plugins que permite a los usuarios definir nuevas formas en las que Scully haga el pre-render de la aplicación. Hay cinco tipos -principales de plugins: -

    -
      -
    1. - - Router Plugin - -
    2. -
    3. - - Render Plugin - -
    4. -
    5. - - File Handler Plugin - -
    6. -
    7. - - routeDiscoveryDone plugin - -
    8. -
    9. - - allDone plugin - -
    10. -
    -

    - Puede encontrar una lista de plugins disponibles la documentación de - - plugins recomendados - - . -

    -
    -

    - Cómo Registerar un Plugin + +

    + Available Options

    -

    - La función - - registerPlugin + + + + + + + + + + + + + + + + + + + + + + + + + +
    + option + + description + + default +
    + + name + + + Define the name for the created post + + 'blog-X' +
    + + target + + + Define the target directory for the new post file + + 'blog' +
    + + metaDataFile + + + Use a meta data yaml template from a file for the post + + undefined +
    +

    + Usage +

    +

    + Let's look at an example. We want to create a new blog post so we type the following in the terminal + + ng generate @scullyio/init:post --name="Angular tutorial" - agrega un nuevo plugin a Scully y tiene 5 parámetros: + . This triggers the following output:

    -
      -
    • - type -
    • -
    • - name -
    • -
    • - plugin -
    • -
    • - validator (optional) -
    • -
    • - options (optional) -
    • -
    -

    - type: string -

    -

    - - type - - - Indica el tipo de the plugin. Los tipos existentes son: - - router +

    +                
    +                  ng generate @scullyio/init:post --name="Angular tutorial"
    +? What's the target folder for this post? blog
    +    ✅️ Blog ./blog/angular-tutorial.md file created
    +CREATE blog/angular-tutorial.md (99 bytes)
                     
    -                ,
    -                
    -                  render
    +              
    +

    + Above you are prompted where you want to place your blog post. You go with default, which is the + + blog/ - , - - fileHandler + directory. You can then see above how the file + + angular-tutorial.md - , - - allDone + is created with this message: +

    +
    +                
    +                  CREATE blog/angular-tutorial.md
                     
    -                , o
    -                
    -                  routeDiscoveryDone
    +              
    +

    + Let's have a look at the generated + + angular-tutorial.md - . + :

    -

    - name: string -

    -

    - - name - - - El nombre del plugin. Este debe ser único para el tipo de plugin. Para remplazar un plugin existente, agregue la opción - - replaceExistingPlugin +

    +                
    +                  
    +                    ---
    +                  
    +                  title: Angular tutorial
    +description: blog description
    +                  
    +                    published: false
    +                    
    +                      ---
    +                    
    +                  
    +                  
    +                    
    +                      #
    +                    
    +                    Angular tutorial
    +                  
                     
    -                .
    +              
    +

    + At the top of the file there is a frontmatter, a set of instructions Scully is using. Those are:

    -

    - plugin: any -

    -

    - - plugin - - - La función del plugin. Los tipos de plugins estan explicados en su propia descripción. +

      +
    • + + title + + , this is the title of the blog post +
    • +
    • + + description + + , this is the description +
    • +
    • + + published + + , this is a property representing whether the blog post is published or not. It takes a + + true + + or + + false + + . +
    • +
    +

    + Generating the blog post route +

    +

    + Next you want to build Scully to generate the route. Type the following in the terminal:

    -

    - validator: función (optional) -

    -

    - - validator - - - Función de validación que debe regresar un arreglo de errores. Si no hay errores, debe regresar un valor - - false +

    +                
    +                  
    +                    npm
    +                  
    +                  run scully
                     
    -                . Si regresa un
    -                
    -                  string<array>
    +              
    +

    + The above will start a process that will generate pages. Have a look at your + + angular-tutorial.md - , esos strings son los erroresa mostrar y el proceso en ejecición es abortado. + file again, it has changed. Now the file contains the following:

    -
    -

    - Tip: Agregar color a los errores de validació utilizando la extensión de color de Scully. -

    -
    -
    - Ejemplo de un Validator -
    -
    -                
    -                  
    -                    import
    -                  
    -                  { yellow }
    -                  
    -                    from
    -                  
    -                  
    -                    '@scullyio/scully'
    -                  
    -                  ;
    -                  
    -                    // Código omitido
    -                  
    -                  
    -                    const
    -                  
    -                  validator =
    -                  
    -                    async
    -                  
    -                  options => {
    -                  
    -                    const
    -                  
    -                  errors = [];
    -                  
    -                    if
    -                  
    -                  (options.numberOfPages &&
    -                  
    -                    typeof
    -                  
    -                  options.numberOfPages !==
    -                  
    -                    'number'
    +              
    +                
    +                  
    +                    ---
                       
    -                  ) {
    -    errors.push(
    -                  
    -                    \`my-custom-plugin numberOfPages should be a number, not a
    -                    
    -                      \${yellow(
    -                      
    -                        typeof
    -                      
    -                      options.numberOfPages
    -      )}
    +                  title: 'Angular tutorial'
    +description: 'blog description'
    +published: false
    +slugs:
    +                  
    +                    - ___UNPUBLISHED___kao8mvda_pmldPr7aN7owPpStZiuDXFZ1ILfpcv5Z
    +                    
    +                      ---
                         
    -                    \`
                       
    -                  );
    -  }
    -                  
    -                    return
    +                  
    +                    
    +                      #
    +                    
    +                    Angular tutorial
                       
    -                  errors;
    -};
                     
                   
    -

    - Opciones -

    -

    - El objeto - - optinal +

    + The property + + slugs - permite agregar las opciones del plugin. Por el momento, la única opción disponible es - - replaceExistingPlugin + have been added to the frontmatter above. + + slugs - . + contains an anonymous URL as long as the property + + published + + is set to + + false + + . This is a URL that you can share with others to for example get feedback on your blog post before it goes live.

    -

    - Router Plugin +
    +

    + NOTE, when you gave the command to build Scully the blog post you just created in Markdown was converted to HTML and placed in the directory + + dist/static/blog/<anonymous slug value>/index.html + + . +

    +
    +

    + Serve the website

    -

    - Cada ruta en la aplicación que contiene un parámetro de ruta debe ser configurado en un - - router plugin - - . El plugin enseña a Scully como obtener los datos que requiere para hacer el pre-render de las páginas provenientes de los parámetros de ruta. +

    + Now that page and the route has been generated, let's serve up the application and ensure it works. Type the following command to serve the static site built by Scully:

    -

    - Suponga que la aplicación tiene una ruta como esta: - - {path: 'user/:userId', component: UserComponent} - - . Para que Scully haga el pre-render del sitio web, necesita la lista completa de los IDs de Usuario que serán usados el el parámetro de ruta - - :userId +

    +                
    +                  
    +                    npm
    +                  
    +                  run scully serve
                     
    -                . Si la tuviera cinco usuarios con IDs 1, 2, 3, 4 y 5; Scully necesitaría mostrar las siguientes rutas:
    +              
    +

    + The command will give an output looking like so:

    -
    -                
    -                  /user/1
    -/user/2
    -/user/3
    -/user/4
    -/user/5
    +              
    +                
    +                  Angular distribution server started on "http://localhost:1864/"
    +Scully static server started on "http://localhost:1668/"
                     
                   
    -

    - Un - - router plugin - - se usa para convertir la configuración de ruta con una variable en una lista de rutas que Scully pueda mostrar. +

    + Open up a browser window and navigate to the URL + + http://localhost:1668/ + + :

    -

    - Interface - - HandledRoute +

    + Your blog post can be found on the URL + + http://localhost:1668/blog/<anonymous slug> -

    -
    -                
    -                  
    -                    interface
    +                , which if you check the frontmatter above means the following URL
    +                
    +                  http://localhost:1668/blog/___UNPUBLISHED___kao8mvda_pmldPr7aN7owPpStZiuDXFZ1ILfpcv5Z
    +                
    +                .
    +              

    +

    + You should now see the following output in the browser: +

    +
    +                
    +                  ScullyIo content
    +Angular tutorial
    +End of content
    +                
    +              
    +

    + Going live +

    +

    + At some point you are happy about the blog post you just authored. At this point you want to open up + + angular-tutorial.md + + and change the + + published + + property to + + true + + to publish it. Also clear the + + slugs + + property so it no longer has the anonymous slug value. The file should now look like this: +

    +
    +                
    +                  
    +                    ---
                       
    -                  RouteConfig {
    -                  
    -                    /** esta ruta checa inactividad de manera manual */
    +                  title: 'Angular tutorial'
    +description: 'blog description'
    +                  
    +                    published: true
    +                    
    +                      ---
    +                    
                       
    -                  manualIdleCheck?:
    -                  
    -                    boolean
    +                  
    +                    
    +                      #
    +                    
    +                    Angular tutorial
                       
    -                  ;
    -                  
    -                    /** tipo de la ruta */
    +                
    +              
    +

    + Run the following command: +

    +
    +                
    +                  
    +                    npm
                       
    -                  
    -                    type
    +                  run scully
    +                
    +              
    +

    + This time around it will render a different route. By default Scully will create a route with the same name as the markdown file minus the extension. Have a look at + + dist/static/blog + + and you will see it looks like so: +

    +
    +                
    +                  --| dist
    +----| static
    +------| blog
    +--------| angular-tutorial
    +----------| index.html
    +                
    +              
    +

    + Let's serve this up with the command: +

    +
    +                
    +                  
    +                    npm
                       
    -                  ?:
    -                  
    -                    string
    +                  run scully serve
    +                
    +              
    +

    + Open up your browser and navigate to the URL + + http://localhost:1668/blog/angular-tutorial + + . +

    +

    + Overriding the slug +

    +

    + If you are + + not + + happy with Scully's convention of creating the slug based on the filename, you can change that by introducing the + + slug + + property in the frontmatter of the markdown file. Change the + + angular-tutorial.md + + file to the following: +

    +
    +                
    +                  
    +                    ---
                       
    -                  ;
    -                  
    -                    /**
    -   * una función opcional que se ejecuta al mostrar la página.
    -   * Recive el string de la ruta y su configuración.
    -   */
    +                  title: 'Angular tutorial'
    +description: 'blog description'
    +published: true
    +                  
    +                    slug: angularjs-still-rocks
    +                    
    +                      ---
    +                    
                       
    -                  preRenderer?:
    -                  
    -                    (
    -                    
    -                      route: HandledRoute
    +                  
    +                    
    +                      #
                         
    -                    ) =>
    +                    Angular tutorial
                       
    -                  
    -                    Promise
    +                
    +              
    +

    + Above the + + slug + + property has been added and assigned the value + + angularjs-still-rocks + + . This will instruct Scully to use this as the route instead. Now generate the routes anew with this command: +

    +
    +                
    +                  
    +                    npm
                       
    -                  <
    -                  
    -                    void
    -                  
    -                  |
    -                  
    -                    false
    -                  
    -                  >;
    -                  
    -                    /** Permitir en cualquier otra configuración posible, depende de los plugins */
    -                  
    -                  [key:
    -                  
    -                    string
    -                  
    -                  ]:
    -                  
    -                    any
    -                  
    -                  ;
    -}
    -                  
    -                    export
    -                  
    -                  
    -                    interface
    -                  
    -                  HandledRoute {
    -                  
    -                    /** La ruta _completa_ */
    -                  
    -                  route:
    -                  
    -                    string
    -                  
    -                  ;
    -                  
    -                    /** String, debe ser el nombre de un plugin existente */
    -                  
    -                  
    -                    type
    -                  
    -                  :
    -                  
    -                    string
    -                  
    -                  ;
    -                  
    -                    /** la parte relevante de scully-config  */
    -                  
    -                  config?: RouteConfig;
    -                  
    -                    /** variables expuestas a angular _¡solo mientras se hace el render!_ */
    -                  
    -                  exposeToPage?: {
    -    manualIdle?:
    -                  
    -                    boolean
    -                  
    -                  ;
    -    transferState?: Serializable;
    -    [key:
    -                  
    -                    string
    -                  
    -                  ]: Serializable;
    -  };
    -                  
    -                    /** datos que serán inyectados en la página estática */
    -                  
    -                  injectToPage?: {
    -    [key:
    -                  
    -                    string
    -                  
    -                  ]: Serializable;
    -  };
    -                  
    -                    /** arreglo con los nombres de los plugins que serán ejecutados */
    -                  
    -                  postRenderers?:
    -                  
    -                    string
    -                  
    -                  [];
    -                  
    -                    /** el "path" del archivo de contenido */
    -                  
    -                  templateFile?:
    -                  
    -                    string
    -                  
    -                  ;
    -                  
    -                    /**
    -   * datos adicionales que terminarán en el archivo scully.routes.json
    -   * los datos del frontMatter también serán agregados aquí.
    -   */
    -                  
    -                  data?: RouteData;
    -}
    +                  run scully
                     
                   
    -

    - La interface - - HandledRoute - - proporciona las propiedades necesarias para desarrollar su propio plugin. -

    -

    - route: string -

    -

    - - route - - - Una ruta de aplicación que será manejada por Scully. Esta es la información - - completamente calificada - - de la route. Esto quiere decir que no debe haber variables restantes aquí. Además el símbolo - - # +

    + Note how the + + dist/static/blog - no está permitido y los parámetros query de ruta son ignorados. -

    -

    - type: RoutesTypes -

    -

    - - type + folder now has a new entry, namely + + angular-js-still-rocks/index.html - - Indica el tipo de plugin. Contiene el nombre del plugin de ruta. Este campo es obligatorio y - - debe - - ser proporcionado. Cuando el tipo no existe, Scully finaliza ya que no sabe que hacer. + .

    -

    - defaultPostRenderers?: string[] -

    -

    - - defaultPostRenderers - - - Arreglo con ID's de tipo string con los content-renderers que serán ejecutados en todas las rutas. +

    + Serving up the static app with:

    -

    - postRenderers?: string[] -

    -

    - - postRenderers +

    +                
    +                  
    +                    npm
    +                  
    +                  run scully serve
                     
    -                - Arreglo de nombres de plugins que se ejecutarán desplues de mostrar la página de inicio. Cada uno de los plugins en este arreglo se mostrarán en el orden en el que aparecen y recibiran el HTML resultante del plugin anterior.
    -Además, teste arreglo
    -                
    -                  reemplaza
    -                
    -                el arreglo
    -                
    -                  defaultPostRenderers
    +              
    +

    + The blog post can now be found at + + http://localhost:1668/blog/angularjs-still-rocks .

    -
    -                
    +                
    +              
    +              
    +              
    +            
    +            
    +          
    +        
    +      
    +    
    +  
    +
    +`;
    +
    +exports[`docsSite should have content for all markdown files check html for markdown docs/learn/create-a-blog/use-blog-post-data-in-template 1`] = `
    +
    +
    +  
    +    
    +    
    +    
    +      ScullyDocs
    +    
    +    
    +    
    +    
    +    
    +    
    +  
    +  
    +    
    +      beta
    +      
    +      
    -

    - Los - - defaultPostRenderers - - y los - - postRenderers - - están diseñados de esta manera con la finalidad de permitirle deshacerse de los renderers por defecto. -Además, este diseño actual de los renders se adapta fácilmente a los diversos casos de uso. -

    -

    - !No olvide agregar los - - defaultPostRenderers - - ! -

    -

    - templateFile?: string -

    -

    - - templateFile - - - ¡No relacionado con la plantilla Angular! El nombre del archivo que contiene la plantilla que se mostrará. Esta propiedad es específica del contentFolder. Contiene el "path" completo al archivo que debe ser utilizado para generar el contenido. Recuerde que dicho contenido será insertado - - despues - - del render inicial. -

    -

    - data?: RouteData -

    -

    - - data - - - Los datos agregados a esta propiedad serán agregados a las rutas en - - scully.routes.json - - . Estos datos también serán extendidos en las rutas del contentFolder. -

    -
    -                
    -                  
    -                    export
    -                  
    -                  
    -                    interface
    -                  
    -                  RouteData {
    -  title?:
    -                  
    -                    string
    -                  
    -                  ;
    -  author?:
    -                  
    -                    string
    -                  
    -                  ;
    -  published?:
    -                  
    -                    boolean
    -                  
    -                  ;
    -  [prop:
    -                  
    -                    string
    -                  
    -                  ]:
    -                  
    -                    any
    -                  
    -                  ;
    -}
    -                
    -              
    -

    - Interface Router Plugin -

    -

    - Un - - router plugin - - es una función que regresa un - - Promise<HandledRoute[]> - - . La interface - - HandledRoute - - se describe en el código anterior. Recibe un string con la ruta aun no manejada y la configuración para esa ruta en específico. -

    -

    - Una función de plugin de ruta se muestra a continuación: -

    -
    -                
    -                  
    -                    
    -                      function
    +                    
    +
    + + Core features - +
      +
    • - exampleRouterPlugin - - ( - + + Idle Monitor Service + + +
    • +
    • - route: - - string - - , - config: - + Scully Content Component + + +
    • +
    • + - any - - - ): - + Scully Routes Service + + +
    • +
    • - Promise - - < - + + Transfer State Service + + +
    • +
    • - HandledRoute - - []> - - { - - // Debe regresar una promesa - - } - -
    -

    - Los datos del - - HandledRoute[] - - son agregados al archivo - - scully-routes.json - - generado por el comando - - npm run scully - - . -

    -

    - Creando un Router Plugin -

    -

    - Se implementará un - - router plugin - - que regresa la ruta original en HandledRoutes distintas como se mostró en el ejemplo anterior que contiene la siguiente ruta: - - /user/:userId - - . -

    -
    -                
    -                  const { registerPlugin } = require('@scullyio/scully');
    -
    -function userIdPlugin(route: string, config = {}): Promise<HandledRoute[]> {
    -  return Promise.resolve([
    -    { route: '/user/1' },
    -    { route: '/user/2' },
    -    { route: '/user/3' },
    -    { route: '/user/4' },
    -    { route: '/user/5' }
    -  ]);
    -}
    -
    -registerPlugin('router', 'userIds', userIdPlugin, validator);
    -                
    -              
    -

    - Después de implementar el plugin, configure el archivo - - scully.config.ts - - para poder utilizarlo. -

    -

    - Configurando un Router Plugin -

    -

    - La siguinte configuración usa el plugin de ruta - - userIds - - para obtener el - - HandledRoute[] - - para la configuración anterior: -

    -
    -                
    +                        
    +                          Utility methods
    +                        
    +                      
    +                    
    +                  
    +                
    +                
  • - - // scully.config.ts - - - import - - - './myPlugins/userIdPlugin' - - ; - - exports - - .config = { - - // Agregue las siguientes rutas a su archivo - - routes: { - - '/user/:userId' - - : { - - type - - : - - 'userIds' - - } - } -}; - -
  • -

    - Render Plugin -

    -

    - Un - - render plugin - - se usa para transformar el HTML que se muestra en las páginas. -

    -

    - Después de que la aplicación de Angular se muestra, el contenido HTML pasa al - - render plugin - - donde puede seguir siendo modificado. -

    -

    - Un render plugin podría ser utilizado también para transformar una página que contenga markdown en una web que muestre dicho contenido. -

    -

    - Render Plugin Interface -

    -

    - A - - render plugin - - es una función que regresa - - Promise<String> - - . El string en la promesa debe ser transformado a -HTML. La interface se muestra a continuación: -

    -
    -                
    -                  
    -                    
    -                      function
    -                    
    -                    
    -                      exampleContentPlugin
    +                    
    +
    + + Legacy support - ( - +
      +
    • - HTML: - - string - - , - route: HandledRoute - - ): - - Promise - - < - + Angular v8 + + +
    • +
    • - string - - > - - { - - // Debe regresar una promesa - - } - -
    -

    - Haciendo Un Render Plugin -

    -

    - El siguiente ejemplo de - - render plugin - - agrega un título al encabezado de la página sí esta no tiene uno. -

    -
    -                
    +                        
    +                          Polyfills
    +                        
    +                      
    +                    
    +                  
    +                
    +                
  • - - const - - { registerPlugin } = - - require - - ( - - '@scullyio/scully' - - ); - - - function + + Plugins - + + + +
  • +
  • + - Promise - - .resolve( - - \` - - \${begin} +
    +
    + + Schematics - + +
  • +
  • + + + Utilities - + + + +
  • + + +
  • + + + +
  • + + +
    + + + +
    +

    + Using blog data in an Angular template +

    +
    +
    + +

    + Injecting Scully's + + Route Service + +

    +

    + Scully provides a service for accessing generated routes with ease. To use it, open the + + home.component.ts + + file we made earlier and add the following code: +

    +
    +                
    +                  
    +                    import
                       
    -                  ,
    -                  
    -                    'defaultTitle'
    +                  
    +                    {
                       
    -                  , defaultTitlePlugin, validator);
    -                  
    -                    module
    +                  ScullyRoutesService
    +                  
    +                    ,
                       
    -                  .
    -                  
    -                    exports
    +                  ScullyRoute
    +                  
    +                    }
                       
    -                  .defaultTitlePlugin = defaultTitlePlugin;
    -                
    -              
    -

    - En el ejemplo anterior, el contenido HTML de la aplicación de Angular es transformado para incluir un título porque no se encontró ninguno. -

    -

    - El siguiente ejemplo reemplaza cualquier instancia de - - :) - - por un emoji sonriente. -

    -
    -                
    -                  
    -                    const
    +                  
    +                    from
                       
    -                  { registerPlugin } =
    -                  
    -                    require
    +                  
    +                    '@scullyio/ng-lib'
                       
    -                  (
    -                  
    -                    '@scullyio/scully'
    +                  
    +                    ;
                       
    -                  );
    -                  
    -                    
    -                      function
    -                    
    -                    
    -                      smileEmojiPlugin
    -                    
    +                  
    +                    import
    +                  
    +                  
    +                    {
    +                  
    +                  Observable
    +                  
    +                    }
    +                  
    +                  
    +                    from
    +                  
    +                  
    +                    'rxjs'
    +                  
    +                  
    +                    ;
    +                  
    +                  @
    +                  
    +                    Component
    +                  
    +                  
                         (
    -                    
    -                      html, route
    -                    
    +                  
    +                  
                         )
                       
    -                  {
    -                  
    -                    return
    +                  
    +                    //...
                       
    -                  
    -                    Promise
    +                  
    +                    export
                       
    -                  .resolve(html.replace(
    -                  
    -                    /\\:\\)/g
    +                  
    +                    class
                       
    -                  ,
    -                  
    -                    '😊'
    +                  
    +                    HomeComponent
                       
    -                  ));
    -}
    -                  
    -                    // NO OLVIDE REGISTRAR EL PLUGIN
    +                  
    +                    implements
                       
    -                  
    -                    const
    +                  
    +                    OnInit
                       
    -                  validator =
    -                  
    -                    async
    +                  
    +                    {
                       
    -                  conf => [];
    -registerPlugin(
    -                  
    -                    'render'
    +                  links$
    +                  
    +                    :
                       
    -                  ,
    -                  
    -                    'smiles'
    +                  Observable
    +                  
    +                    <
                       
    -                  , smileEmojiPlugin, validator);
    -                  
    -                    module
    +                  ScullyRoute
    +                  
    +                    [
                       
    -                  .
    -                  
    -                    exports
    +                  
    +                    ]
                       
    -                  .smileEmojiPlugin = smileEmojiPlugin;
    -                
    -              
    -
    -

    - File Handler Plugin -

    -

    - Un - - file handler plugin - - es usado por el plugin - - contentFolder - - durante el proceso de - - render - - . El plugin - - contentFolder - - procesa las carpetas con archivos markdownu otro tipo de archivo que contenga. El - - render - - procesa cualquier plugin - - fileHandler - - existente para cualquier tipo de extensión de archivo. -

    -

    - Scully tiene dos plugins - - fileHandler - - . El - - markdown plugin - - y -el - - asciidoc plugin - - . Estos plugins manejan y procesan el -contenido de los archivos correspondientes a su tipo mientras leen los archivos del sistema. -

    -

    - Si desea soportar archivos - - .docx - - , - - .csv - - , o de cualquier otro tipo; es necesario agregar un plugin que maneje esos tipos de archivos. -El plugin - - contentFolder - - se encarga de mostrar el contenido del tipo de archivo correspondiente. Sin embargo, si los archivos necesitan ser transformados despues de que el plugin - - contentFolder - - los muestre; -Es necesario un plugin de tipo - - fileHandler - - . -

    -

    - Interface File Handler Plugin -

    -

    - Un - - file handler plugin - - es una función que regresa una - - Promise<string> - - . La interface se muestra a continuación: -

    -
    -                
    -                  
    -                    
    -                      function
    -                    
    -                    
    -                      exampleFileHandlerPlugin
    -                    
    -                    (
    -                    
    -                      rawContent:
    -                      
    -                        string
    -                      
    -                    
    -                    ):
    -                    
    -                      Promise
    -                    
    -                    <
    -                    
    -                      string
    -                    
    +                  
                         >
                       
    -                  {
    -                  
    -                    // Debe regresar una promesa
    +                  
    +                    =
                       
    -                  }
    -                
    -              
    -

    - Haciendo Un File Handler Plugin -

    -

    - El siguiente ejemplo de - - file handler plugin - - maneja archivos de tipo - - .cvs - - al envolverlos en un bloque de código. Se podría escribir un plugin mucho más elaborad que creara una tabla o una cuadrícula para los datos. -

    -
    -                
    -                  
    -                    
    -                      function
    +                  
    +                    this
    +                  
    +                  
    +                    .
    +                  
    +                  scully
    +                  
    +                    .
    +                  
    +                  available$
    +                  
    +                    ;
    +                  
    +                  
    +                    constructor
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    
    +                      private
                         
    -                    
    -                      csvFilePlugin
    +                    scully
    +                    
    +                      :
                         
    +                    ScullyRoutesService
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    {
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    ngOnInit
    +                  
    +                  
                         (
    -                    
    -                      raw
    -                    
    +                  
    +                  
                         )
                       
    -                  {
    -                  
    -                    return
    +                  
    +                    {
                       
    -                  
    -                    Promise
    +                  
    +                    // debug current pages
                       
    -                  .resolve(
    -                  
    -                    \`<pre><code>
    -                    
    -                      \${code}
    -                    
    -                    </code></pre>\`
    +                  
    +                    this
                       
    -                  );
    -}
    -                  
    -                    // NO OLVIDE REGISTRAR EL PLUGIN
    +                  
    +                    .
                       
    -                  registerPlugin(
    -                  
    -                    'fileHandler'
    +                  links$
    +                  
    +                    .
                       
    -                  ,
    -                  
    -                    'csv'
    +                  
    +                    subscribe
                       
    -                  , { handler: csvFilePlugin });
    -                  
    -                    module
    +                  
    +                    (
                       
    -                  .
    -                  
    -                    exports
    +                  
    +                    (
    +                  
    +                  
    +                    links
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    =>
    +                  
    +                  
    +                    {
    +                  
    +                  
    +                    console
    +                  
    +                  
    +                    .
    +                  
    +                  
    +                    log
    +                  
    +                  
    +                    (
    +                  
    +                  links
    +                  
    +                    )
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    }
                       
    -                  .csvFilePlugin = csvFilePlugin;
                     
                   
    -

    - Ejemplos deFile Handler Plugin -

    -

    - Aquí hay algunos links de - - render plugins - - ya incluidos en Scully: -

    - -

    - RouteDiscoveryDone Plugin -

    -

    - Este tipo de plugin es llamado automáticamente despues de que todas las rutas han sido recogidas y que todos los plugins de ruta hayan terminado. Reciben una copia del arreglo - - handledRoute - - y regresan - - void - - . -

    -

    - AllDone Plugin -

    -

    - Un plugin de tipo - - allDone +

    + We can see + + ScullyRoutesService.available$ - es parecido a un plugin - - routeDiscoveryDone - - con la expeción de que se llama - - después - - de que Scully termina de ejecutar todos los procesos. + returns an Observable of an array of + + + ScullyRoute + + + s, the interface of which looks like this:

    - - - -
    -
    -
    -
    -
    - -
    - - -`; - -exports[`docsSite should have content for all markdown files check html for markdown docs/polyfills 1`] = ` +
    +                
    +                  
    +                    export
    +                  
    +                  
    +                    interface
    +                  
    +                  
    +                    ScullyRoute
    +                  
    +                  
    +                    {
    +                  
    +                  route
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ;
    +                  
    +                  title
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ;
    +                  
    +                  slugs
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    [
    +                  
    +                  
    +                    ]
    +                  
    +                  
    +                    ;
    +                  
    +                  published
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    boolean
    +                  
    +                  
    +                    ;
    +                  
    +                  slug
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ;
    +                  
    +                  sourceFile
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    [
    +                  
    +                  prop
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ]
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    any
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    }
    +                  
    +                
    +              
    +

    + To extract data from the available + + links$ + + Scully has rendered, we can loop through them inside the template by opening the + + home.component.html + + file and adding the following code: +

    +
    +                
    +                  
    +                    
    +                      
    +                        <
    +                      
    +                      p
    +                    
    +                    
    +                      >
    +                    
    +                  
    +                  home works!
    +                  
    +                    
    +                      
    +                        </
    +                      
    +                      p
    +                    
    +                    
    +                      >
    +                    
    +                  
    +                  
    +                    
    +                      
    +                        <
    +                      
    +                      ul
    +                    
    +                    
    +                      >
    +                    
    +                  
    +                  
    +                    
    +                      
    +                        <
    +                      
    +                      li
    +                    
    +                    
    +                      *ngFor
    +                    
    +                    
    +                      
    +                        =
    +                      
    +                      
    +                        "
    +                      
    +                      let page of links$ | async
    +                      
    +                        "
    +                      
    +                    
    +                    
    +                      >
    +                    
    +                  
    +                  {{ page.route }}
    +                  
    +                    
    +                      
    +                        </
    +                      
    +                      li
    +                    
    +                    
    +                      >
    +                    
    +                  
    +                  
    +                    
    +                      
    +                        </
    +                      
    +                      ul
    +                    
    +                    
    +                      >
    +                    
    +                  
    +                
    +              
    +

    + + NOTE: + + If you don't add any route, Scully will pre-render 0 pages. +

    +

    + Adding metadata to ScullyRoutes +

    +

    + At the very top of each + + .md + + blog post file, between the opening and closing + + --- + + indicators, each line of text corresponds to a property we can pull out of + + ScullyRoutesService.available$ + + . +

    +

    + For example, a + + .md + + file beginning with: +

    +
    +                
    +                  ---
    +title: blog title
    +description: blog description
    +published: true
    +arbitraryValue: single value
    +arbitraryArray: [first item, second item]
    +---
    +                
    +              
    +

    + ... lets us use these values in our template like this: +

    +
    +                
    +                  
    +                    
    +                      
    +                        <
    +                      
    +                      ul
    +                    
    +                    
    +                      >
    +                    
    +                  
    +                  
    +                    
    +                      
    +                        <
    +                      
    +                      li
    +                    
    +                    
    +                      *ngFor
    +                    
    +                    
    +                      
    +                        =
    +                      
    +                      
    +                        "
    +                      
    +                      let page of links$ | async
    +                      
    +                        "
    +                      
    +                    
    +                    
    +                      >
    +                    
    +                  
    +                  {{ page.route }} {{ page.arbitraryValue }}
    +                  
    +                    
    +                      
    +                        <
    +                      
    +                      span
    +                    
    +                    
    +                      *ngFor
    +                    
    +                    
    +                      
    +                        =
    +                      
    +                      
    +                        "
    +                      
    +                      let arrayItem of page.arbitraryArray
    +                      
    +                        "
    +                      
    +                    
    +                    
    +                      >
    +                    
    +                  
    +                  {{ arrayItem }}
    +                  
    +                    
    +                      
    +                        </
    +                      
    +                      span
    +                    
    +                    
    +                      >
    +                    
    +                  
    +                  
    +                    
    +                      
    +                        </
    +                      
    +                      li
    +                    
    +                    
    +                      >
    +                    
    +                  
    +                  
    +                    
    +                      
    +                        </
    +                      
    +                      ul
    +                    
    +                    
    +                      >
    +                    
    +                  
    +                
    +              
    + + + + + + + + + + + +`; + +exports[`docsSite should have content for all markdown files check html for markdown docs/learn/faq 1`] = ` @@ -15188,36 +21947,8 @@ exports[`docsSite should have content for all markdown files check html for mark href="favicon.ico" > - - - - - - - beta - - scullyLogo + beta - -
    - - - - - - - - - - -
    - - - -

    - Polyfills -

    -

    - Depending on the browser and environment that the application targets, some polyfills are -required. This page lists the recommended polyfills. -

    -

    - - Event() - - constructor +

    + Ignoring Routes

    -

    - Scully uses - - - Event +

    + + Ignore routes without config + +
    +

    + I have a lot of routes I don't want Scully to handle. +
    + How can I deal with this? +

    +
    +

    + Scully will use the + + default - - to be aware of different points in the application's lifecycle. -

    -

    - To make - - Internet Explorer 10+ - - work, install and import the following polyfill: -

    -

    - - npm install events-polyfill - -

    -
    -                
    -                  
    -                    // src/polyfills.ts
    -                  
    -                  
    -                    import
    -                  
    -                  
    -                    'events-polyfill/src/constructors/Event.js'
    -                  
    -                  ;
    -                
    -              
    - - - -
    -
    -
    -
    -
    - -
    - - -`; - -exports[`docsSite should have content for all markdown files check html for markdown docs/pre-requisites 1`] = ` - - - - - - - ScullyDocs - - - - - - - - - - - - - - - beta - - scullyLogo - -
    - - - - - - - -
    - - - -

    - Prerequisites -

    -

    - You need an existing Angular application, or you can create a new one in order to use Scully. -

    -

    - - NOTE: - - Scully supports Angular versions: - - v8.x.x - - and - - v9.x.x - -

    -

    - Creating a New Angular Application -

    -

    - Install the Angular CLI globally with the following command: -

    -
    -                
    -                  npm install -g @angular/cli
    -                
    -              
    -

    - Then, create a new application. -

    -
    -                
    -                  ng new my-scully-app
    -                
    -              
    -

    - IMPORTANT: -

    -

    - - Scully depends on the application's router module in order to generate the website's pages - -

    -

    - Add a router module with the following command: -

    -
    -                
    -                  ng generate module app-routing --flat --module=app
    -                
    -              
    -

    - Find more info about the Angular CLI here - - 👉 angular.io/cli - -

    -

    - IMPORTANT: -

    -

    - - Scully uses Chromium. Therefore, your Operating System, as well as its administrator rights must allow its installation and execution. - -

    -

    - Node version: -

    -
    -
    -
    -
    -
    - + + + + +
    `; -exports[`docsSite should have content for all markdown files check html for markdown docs/pre-requisites_es 1`] = ` +exports[`docsSite should have content for all markdown files check html for markdown docs/learn/plugins/types/allDone 1`] = ` @@ -16350,36 +62447,8 @@ exports[`docsSite should have content for all markdown files check html for mark href="favicon.ico" > - - - - - - - beta - - scullyLogo + beta - -
    - - - - - - - - - - -
    - - - -

    - Requisitos Previos -

    -

    - Necesita una aplicación existente de Angular o puede crear una nueva para usar Scully. -

    -

    - - NOTA: - - Scully soporta las versiones: - - v8.x.x - - y - - v9.x.x - - de Angular. -

    -

    - Crear Una Nueva Applicación de Angular -

    -

    - Instale Angular CLI de manera global con el siguiente comando: -

    -
    -                
    -                  npm install -g @angular/cli
    -                
    -              
    -

    - Ahora, haga una nueva aplicación. -

    -
    -                
    -                  ng new my-scully-app
    +                  
    +                    
    +                      Support
    +                    
    +                  
    +                
    +              
    +            
    +          
    +        
    +        
    + + + +
    +

    + + allDone -

    -

    - IMPORTANTE: -

    -

    - - Scully depende del módulo de rutas de la aplicación para poder las páginas del citio web - -

    -

    - Agregue el módulo de rutas con el siguiente comando: -

    -
    -                
    -                  ng generate module app-routing --flat --module=app
    +                Plugin Type
    +              
    +              

    + Overview +

    +

    + An + + allDone -

    -

    - Puede encontrar más información acerca de Angular CLI aquí - - 👉 angular.io/cli + plugin is like a + + + routeDiscoveryDone + -

    -

    - IMPORTANTE: -

    -

    - - Scully utiliza Chromium. Por lo tanto, su sistema operativo, así como sus derechos de administrador deben permitir su instalación y ejecución. + plugin, except it is called + + after + Scully finishes executing all its processes.

    -

    - Versión de Node: -

    -
      -
    • - Scully soporta Node.js 10 o mayor. -
    • -
    - + -
    -
    -
    -
    -
    -
    - + + + + +
    `; -exports[`docsSite should have content for all markdown files check html for markdown docs/recommended-plugins 1`] = ` +exports[`docsSite should have content for all markdown files check html for markdown docs/learn/plugins/types/fileHandler 1`] = ` @@ -16946,36 +63614,8 @@ exports[`docsSite should have content for all markdown files check html for mark href="favicon.ico" > - - - - - - - beta - - scullyLogo + beta - -
    - - - - - - - - - - -
    - - - -

    - Recommended Plugins -

    -

    - - If you would like to add a plugin to this list; edit the - - docs/recommended-plugins.md +

    + Overview +

    +

    + A + + + fileHandler - file - - and submit a PR. + plugin + + is used by the + + contentFolder + + plugin during the + + render + + process. The + + contentFolder + + plugin processes the folders for markdown files or other file type the folders may contain. The + + render + + processes any existing + + fileHandler + + plugin for any file extension type.

    -

    - Scully Official Plugins +

    + Usage

    - -
    -                
    -                  Adds an http get call into the configuration.
    +              

    + Scully comes with two built-in + + fileHandler -

    -
      -
    • - - contentFolder - - - Router and render plugin - - example - -
    • -
    -
    -                
    -                  Reads content from folders.
    +                plugins. The
    +                
    +                  markdown plugin
    +                
    +                and
    +the
    +                
    +                  asciidoc plugin
    +                
    +                . These plugins handle and process the
    +content of those file types as they are read from the file system.
    +              

    +

    + If you want to support + + .docx -

    - -
    -                
    -                  Adds support for ignoring routes.
    +                files, or
    +                
    +                  .csv
                     
    -              
    -
      -
    • - - adoc + files, or any other file type; a file handler for those file types need to be added. +The + + contentFolder + + plugin takes care of reading those files from the filesystem. However, if the files need to be transformed after the + + contentFolder + + plugin reads them; +A + + fileHandler + + plugin is required. +

      +

      + Interface +

      +

      + A + + + fileHandler - - Render plugin - - example - -

    • -
    -
    -                
    -                  Adds cappability to render adoc files as html.
    +                  plugin
    +                
    +                is a function that returns a
    +                
    +                  Promise<string>
    +                
    +                . The interface looks like follows:
    +              

    +
    +                
    +                  
    +                    function
    +                  
    +                  
    +                    exampleFileHandlerPlugin
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    rawContent
    +                    
    +                      :
    +                    
    +                    
    +                      string
    +                    
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    Promise
    +                  
    +                  
    +                    <
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    >
    +                  
    +                  
    +                    {
    +                  
    +                  
    +                    // Must return a promise
    +                  
    +                  
    +                    }
    +                  
                     
                   
    -
      -
    • - - md +

      + Making A + + fileHandler + + Plugin +

      +

      + The following + + + fileHandler - - Render plugin - - example - -

    • -
    -
    -                
    -                  Adds cappability to render markdown files as html.
    +                  plugin
    +                
    +                example handles
    +                
    +                  .cvs
    +                
    +                files by wrapping them into a code block. You could write a much more elaborate plugin that creates a table or a grid for the data.
    +              

    +
    +                
    +                  
    +                    function
    +                  
    +                  
    +                    csvFilePlugin
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    raw
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    {
    +                  
    +                  
    +                    return
    +                  
    +                  
    +                    Promise
    +                  
    +                  
    +                    .
    +                  
    +                  
    +                    resolve
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    
    +                      \`
    +                    
    +                    
    +                      <pre><code>
    +                    
    +                    
    +                      
    +                        \${
    +                      
    +                      code
    +                      
    +                        }
    +                      
    +                    
    +                    
    +                      </code></pre>
    +                    
    +                    
    +                      \`
    +                    
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    // DO NOT FORGET TO REGISTER THE PLUGIN
    +                  
    +                  
    +                    registerPlugin
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    'fileHandler'
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    'csv'
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    {
    +                  
    +                  handler
    +                  
    +                    :
    +                  
    +                  csvFilePlugin
    +                  
    +                    }
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    module
    +                  
    +                  
    +                    .
    +                  
    +                  exports
    +                  
    +                    .
    +                  
    +                  csvFilePlugin
    +                  
    +                    =
    +                  
    +                  csvFilePlugin
    +                  
    +                    ;
    +                  
                     
                   
    -

    - Community Render Plugins +

    + Examples

    -
    -
    -
    -
    -
    - + + + + +
    `; -exports[`docsSite should have content for all markdown files check html for markdown docs/recommended-plugins_es 1`] = ` +exports[`docsSite should have content for all markdown files check html for markdown docs/learn/plugins/types/overview- 1`] = ` @@ -17636,36 +65116,8 @@ exports[`docsSite should have content for all markdown files check html for mark href="favicon.ico" > - - - - - - - beta - - scullyLogo + beta - -
    - - - - - - - - - - -
    - - - -

    - Plugins Recomendados -

    -

    - - Si gusta agregar un plugin a esta lista; edite el archivo - - docs/recommended-plugins.md - - - y haga un PR. -

    -

    +
  • + - Plugins Oficiales de Scully -
  • - + +
    + + + +
    +

    + Plugin types +

    +

    + Overview

    -
    -
    -
    -
    -
    - + + + + +
    `; -exports[`docsSite should have content for all markdown files check html for markdown docs/release-for-v8 1`] = ` +exports[`docsSite should have content for all markdown files check html for markdown docs/learn/plugins/types/render 1`] = ` @@ -18323,36 +66419,8 @@ exports[`docsSite should have content for all markdown files check html for mark href="favicon.ico" > - - - - - - - beta - - scullyLogo + beta - -
    - - - - - - - - - - -
    - - - -

    - Step for Releasing a v8.x.x library -

    -
      -
    1. - Checkout the - - angular-8 - - branch -
    2. -
    3. - Remove version 9: - - rm -fr node_modules - -
    4. -
    5. - Install version 8: - - npm i - -
    6. -
    7. - Pull origin main branch: - - git pull origin main - -
    8. -
    9. - Fix any merge conflicts -
    10. -
    11. - Make sure that - - package.json - - file has version 8 -
    12. -
    13. - Build the application: - - ng build @scullyio/ng-lib-v8 +

      + Overview +

      +

      + A + + render plugin + + is used to transform the rendered HTML. +
      + After the Angular application renders, the HTML content is passed to a + + render plugin + + where it can be further modified. +

      +

      + A + + render plugin + + could be used to transform a page containing markdown into a page that renders it. +

      +

      + Interface +

      +

      + A + + + render -

    14. -
    15. - Run tests -
    16. -
    17. - Pay attention to - - package.json + plugin + + is a function that returns a + + Promise<String> + + . The string in the promise must be the transformed +HTML. The interface looks like this: +

      +
      +                
      +                  
      +                    function
      +                  
      +                  
      +                    exampleContentPlugin
      +                  
      +                  
      +                    (
      +                  
      +                  
      +                    
      +                      HTML
      +                    
      +                    
      +                      :
      +                    
      +                    
      +                      string
      +                    
      +                    
      +                      ,
      +                    
      +                    route
      +                    
      +                      :
      +                    
      +                    HandledRoute
      +                  
      +                  
      +                    )
      +                  
      +                  
      +                    :
      +                  
      +                  
      +                    Promise
      +                  
      +                  
      +                    <
      +                  
      +                  
      +                    string
      +                  
      +                  
      +                    >
      +                  
      +                  
      +                    {
      +                  
      +                  
      +                    // Must return a promise
      +                  
      +                  
      +                    }
      +                  
      +                
      +              
      +

      + Making A + + render + + Plugin +

      +

      + The following + + + render - to make sure you keep the 8 version -

    18. -
    19. - If all tests are ok, rebuild the library: -
        -
      • - - ng build @scullyio/ng-lib-v8 - -
      • -
      -
    20. -
    21. - Publish the application: -
        -
      • - - cd ./dist/scullyio/ng-lib-v8 - -
      • -
      • - - npm publish --access=public - -
      • -
      -
    22. -
    23. - Commit and push changes. -
    24. -
    - + plugin + + example adds a title to the header to a page if it does not find one. +

    +
    +                
    +                  
    +                    const
    +                  
    +                  
    +                    {
    +                  
    +                  registerPlugin
    +                  
    +                    }
    +                  
    +                  
    +                    =
    +                  
    +                  
    +                    require
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    '@scullyio/scully'
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    function
    +                  
    +                  
    +                    defaultTitlePlugin
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    html
    +                    
    +                      ,
    +                    
    +                    route
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    {
    +                  
    +                  
    +                    // If no title in the document
    +                  
    +                  
    +                    if
    +                  
    +                  
    +                    (
    +                  
    +                  html
    +                  
    +                    .
    +                  
    +                  
    +                    indexOf
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    '<title'
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    <
    +                  
    +                  
    +                    0
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    {
    +                  
    +                  
    +                    const
    +                  
    +                  splitter
    +                  
    +                    =
    +                  
    +                  
    +                    '</head>'
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    const
    +                  
    +                  
    +                    [
    +                  
    +                  begin
    +                  
    +                    ,
    +                  
    +                  end
    +                  
    +                    ]
    +                  
    +                  
    +                    =
    +                  
    +                  html
    +                  
    +                    .
    +                  
    +                  
    +                    split
    +                  
    +                  
    +                    (
    +                  
    +                  splitter
    +                  
    +                    )
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    const
    +                  
    +                  defaultTitle
    +                  
    +                    =
    +                  
    +                  
    +                    
    +                      \`
    +                    
    +                    
    +                      <title>The Truth Is Out There!</title>
    +                    
    +                    
    +                      \`
    +                    
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    return
    +                  
    +                  
    +                    Promise
    +                  
    +                  
    +                    .
    +                  
    +                  
    +                    resolve
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    
    +                      \`
    +                    
    +                    
    +                      
    +                        \${
    +                      
    +                      begin
    +                      
    +                        }
    +                      
    +                    
    +                    
    +                      
    +                        \${
    +                      
    +                      defaultTitle
    +                      
    +                        }
    +                      
    +                    
    +                    
    +                      
    +                        \${
    +                      
    +                      splitter
    +                      
    +                        }
    +                      
    +                    
    +                    
    +                      
    +                        \${
    +                      
    +                      end
    +                      
    +                        }
    +                      
    +                    
    +                    
    +                      \`
    +                    
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    return
    +                  
    +                  
    +                    Promise
    +                  
    +                  
    +                    .
    +                  
    +                  
    +                    resolve
    +                  
    +                  
    +                    (
    +                  
    +                  html
    +                  
    +                    )
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    // DON NOT FORGET REGISTER THE PLUGIN
    +                  
    +                  
    +                    const
    +                  
    +                  
    +                    validator
    +                  
    +                  
    +                    =
    +                  
    +                  
    +                    async
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    conf
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    =>
    +                  
    +                  
    +                    [
    +                  
    +                  
    +                    ]
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    registerPlugin
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    'render'
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    'defaultTitle'
    +                  
    +                  
    +                    ,
    +                  
    +                  defaultTitlePlugin
    +                  
    +                    ,
    +                  
    +                  validator
    +                  
    +                    )
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    module
    +                  
    +                  
    +                    .
    +                  
    +                  exports
    +                  
    +                    .
    +                  
    +                  defaultTitlePlugin
    +                  
    +                    =
    +                  
    +                  defaultTitlePlugin
    +                  
    +                    ;
    +                  
    +                
    +              
    +

    + In the above example, the Angular app's HTML content is transformed to include a title because anyone was found. +

    +

    + The next example replaces any instances of + + :) + + with an smiley emoji. +

    +
    +                
    +                  
    +                    const
    +                  
    +                  
    +                    {
    +                  
    +                  registerPlugin
    +                  
    +                    }
    +                  
    +                  
    +                    =
    +                  
    +                  
    +                    require
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    '@scullyio/scully'
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    function
    +                  
    +                  
    +                    smileEmojiPlugin
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    html
    +                    
    +                      ,
    +                    
    +                    route
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    {
    +                  
    +                  
    +                    return
    +                  
    +                  
    +                    Promise
    +                  
    +                  
    +                    .
    +                  
    +                  
    +                    resolve
    +                  
    +                  
    +                    (
    +                  
    +                  html
    +                  
    +                    .
    +                  
    +                  
    +                    replace
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    /\\:\\)/g
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    '😊'
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    // DON NOT FORGET REGISTER THE PLUGIN
    +                  
    +                  
    +                    const
    +                  
    +                  
    +                    validator
    +                  
    +                  
    +                    =
    +                  
    +                  
    +                    async
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    conf
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    =>
    +                  
    +                  
    +                    [
    +                  
    +                  
    +                    ]
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    registerPlugin
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    'render'
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    'smiles'
    +                  
    +                  
    +                    ,
    +                  
    +                  smileEmojiPlugin
    +                  
    +                    ,
    +                  
    +                  validator
    +                  
    +                    )
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    module
    +                  
    +                  
    +                    .
    +                  
    +                  exports
    +                  
    +                    .
    +                  
    +                  smileEmojiPlugin
    +                  
    +                    =
    +                  
    +                  smileEmojiPlugin
    +                  
    +                    ;
    +                  
    +                
    +              
    + -
    -
    -
    -
    -
    -
    - + + + + +
    `; -exports[`docsSite should have content for all markdown files check html for markdown docs/roadmap 1`] = ` +exports[`docsSite should have content for all markdown files check html for markdown docs/learn/plugins/types/routeDiscoveryDone 1`] = ` @@ -18912,36 +68240,8 @@ exports[`docsSite should have content for all markdown files check html for mark href="favicon.ico" > - - - - - - - beta - - scullyLogo + beta - -
    - - - - - - - - - - -
    - - - -

    - roadmap / wishlist + + + +
    + + + +
    +

    + + routeDiscoveryDone + + Plugin Type

    -
      -
    1. - Rename file-plugin to content plugin because this type of plugin does not handle files. -
    2. -
    3. - Rename the contentFolder render plugin. -
    4. -
    5. - Add a way for router plugins to modify the post-render array for a - - single route - - . -
    6. -
    7. - Documentation for existing plugins. -
    8. -
    9. - Documentation for the plugin system. -
    10. -
    11. - Documentation for plugin config. -
    12. -
    13. - Well structured documentation. -
    14. -
    15. - Schematic support for Nx. -
    16. -
    17. - Scully support for Nx. -
    18. -
    19. - i18n support. -
    20. -
    21. - Plugin for rewriting base-href. -
    22. -
    23. - Sample TS plugin, including instructions to build it, as well as a schematic that puts it into place. -
    24. -
    25. - Content plugin that takes a string. -
    26. -
    27. - More plugins. -
    28. -
    29. - Google sheets integration for forms by adding a plugin list. Scully's showcases should be generated with this plugin. -
    30. -
    31. - Better and more complete samples like: Web-store with a cart. Moreover, the examples should be like code-labs. -
    32. -
    33. - Tutorials. -
    34. -
    35. - Screencap demos in the documentation. -
    36. -
    37. - Deep dive tutorials. -
    38. -
    - +

    + Overview +

    +

    + This type of plugin is called automatically after all routes have been collected, and all router plugins have finished. +

    +

    + It receives a shallow copy of the + + handledRoute + + array, and returns + + void + + . +

    + - -

    -
    -
    -
    -
    - + + + + +
    `; -exports[`docsSite should have content for all markdown files check html for markdown docs/routeParameters 1`] = ` +exports[`docsSite should have content for all markdown files check html for markdown docs/learn/plugins/types/router 1`] = ` @@ -19481,36 +69404,8 @@ exports[`docsSite should have content for all markdown files check html for mark href="favicon.ico" > - - - - - - - beta - - scullyLogo + beta - -
    - - - - - - - - - - -
    - - - -

    - Route Parameters & Scully -

    -

    - If you run Scully and the following warning is displayed, you need to teach Scully how to use the project's route parameters. +

    + Overview +

    +

    + Any route in the application that contains a router-parameter must be configured in a + + router plugin + + . The plugin teaches Scully how to get the required data to be pre-render in the web-pages from the route-params. +

    +

    + Usage +

    +

    + Suppose the application has a route like this one: + + {path: 'user/:userId', component: UserComponent} + + . In order for Scully to pre-render the website, it needs to know the complete list of User IDs that will be used in that route parameter + + :userId + + . If the app had 5 users with the IDs 1, 2, 3, 4, and 5; Scully would need to render the following routes: +

    +
    +                
    +                  /user/1
    +/user/2
    +/user/3
    +/user/4
    +/user/5
    +                
    +              
    +

    + A + + + router + + plugin + + is used to convert the raw route-config into a list of routes that Scully can then crawl/render. +

    +

    + Making a + + router + + Plugin +

    +

    + Lets implement a + + + router + + plugin + + that turns the raw route into five distinct + + HandledRoutes + + from an application containing the following route: + + /user/:userId + + . +

    +
    +                
    +                  
    +                    const
    +                  
    +                  
    +                    {
    +                  
    +                  registerPlugin
    +                  
    +                    }
    +                  
    +                  
    +                    =
    +                  
    +                  
    +                    require
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    '@scullyio/scully'
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    function
    +                  
    +                  
    +                    userIdPlugin
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    route
    +                    
    +                      :
    +                    
    +                    string
    +                    
    +                      ,
    +                    
    +                    config
    +                    
    +                      =
    +                    
    +                    
    +                      {
    +                    
    +                    
    +                      }
    +                    
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    :
    +                  
    +                  Promise
    +                  
    +                    <
    +                  
    +                  HandledRoute
    +                  
    +                    [
    +                  
    +                  
    +                    ]
    +                  
    +                  
    +                    >
    +                  
    +                  
    +                    {
    +                  
    +                  
    +                    return
    +                  
    +                  Promise
    +                  
    +                    .
    +                  
    +                  
    +                    resolve
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    [
    +                  
    +                  
    +                    {
    +                  
    +                  route
    +                  
    +                    :
    +                  
    +                  
    +                    '/user/1'
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    {
    +                  
    +                  route
    +                  
    +                    :
    +                  
    +                  
    +                    '/user/2'
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    {
    +                  
    +                  route
    +                  
    +                    :
    +                  
    +                  
    +                    '/user/3'
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    {
    +                  
    +                  route
    +                  
    +                    :
    +                  
    +                  
    +                    '/user/4'
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    {
    +                  
    +                  route
    +                  
    +                    :
    +                  
    +                  
    +                    '/user/5'
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    ]
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    registerPlugin
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    'router'
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    'userIds'
    +                  
    +                  
    +                    ,
    +                  
    +                  userIdPlugin
    +                  
    +                    ,
    +                  
    +                  validator
    +                  
    +                    )
    +                  
    +                  
    +                    ;
    +                  
    +                
    +              
    +

    + After implementing the plugin, configure the + + scully.config.ts + + in order to use it. +

    +

    + Configuring a + + router + + Plugin +

    +

    + The following configuration uses the + + userIds + + router plugin to get the + + HandledRoute[] + + for the above implementation: +

    +
    +                
    +                  
    +                    // scully.config.ts
    +                  
    +                  
    +                    import
    +                  
    +                  
    +                    './myPlugins/userIdPlugin'
    +                  
    +                  
    +                    ;
    +                  
    +                  exports
    +                  
    +                    .
    +                  
    +                  config
    +                  
    +                    =
    +                  
    +                  
    +                    {
    +                  
    +                  
    +                    // Add the following to your file
    +                  
    +                  routes
    +                  
    +                    :
    +                  
    +                  
    +                    {
    +                  
    +                  
    +                    '/user/:userId'
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    {
    +                  
    +                  
    +                    type
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    'userIds'
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    ;
    +                  
    +                
    +              
    +

    + Interfaces +

    +

    + + HandledRoute + + Interface +

    +
    +                
    +                  
    +                    interface
    +                  
    +                  
    +                    RouteConfig
    +                  
    +                  
    +                    {
    +                  
    +                  
    +                    /** this route does a manual Idle check */
    +                  
    +                  manualIdleCheck
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    boolean
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /** type of the route  */
    +                  
    +                  
    +                    type
    +                  
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /**
    +   * an optional function that will be executed on render.
    +   * Receives the route string, and the config of this route.
    +   */
    +                  
    +                  preRenderer
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    route
    +                    
    +                      ?
    +                    
    +                    
    +                      :
    +                    
    +                    
    +                      string
    +                    
    +                    
    +                      ,
    +                    
    +                    config
    +                    
    +                      ?
    +                    
    +                    
    +                      :
    +                    
    +                    RouteConfig
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    =>
    +                  
    +                  
    +                    Promise
    +                  
    +                  
    +                    <
    +                  
    +                  
    +                    void
    +                  
    +                  
    +                    |
    +                  
    +                  
    +                    false
    +                  
    +                  
    +                    >
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /** Allow in every other setting possible, depends on plugins */
    +                  
    +                  
    +                    [
    +                  
    +                  key
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ]
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    any
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    export
    +                  
    +                  
    +                    interface
    +                  
    +                  
    +                    HandledRoute
    +                  
    +                  
    +                    {
    +                  
    +                  
    +                    /** the _complete_ route */
    +                  
    +                  route
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /** String, must be an existing plugin name */
    +                  
    +                  
    +                    type
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /** the relevant part of the scully-config  */
    +                  
    +                  config
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  RouteConfig
    +                  
    +                    ;
    +                  
    +                  
    +                    /** variables exposed to angular _while rendering only!_ */
    +                  
    +                  exposeToPage
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    {
    +                  
    +                  manualIdle
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    boolean
    +                  
    +                  
    +                    ;
    +                  
    +                  transferState
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  Serializable
    +                  
    +                    ;
    +                  
    +                  
    +                    [
    +                  
    +                  key
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ]
    +                  
    +                  
    +                    :
    +                  
    +                  Serializable
    +                  
    +                    ;
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /** data will be injected into the static page */
    +                  
    +                  injectToPage
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    {
    +                  
    +                  
    +                    [
    +                  
    +                  key
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ]
    +                  
    +                  
    +                    :
    +                  
    +                  Serializable
    +                  
    +                    ;
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /** an array with render plugin names that will be executed */
    +                  
    +                  postRenderers
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    [
    +                  
    +                  
    +                    ]
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /** the path to the file for a content file */
    +                  
    +                  templateFile
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    /**
    +   * additional data that will end up in scully.routes.json
    +   * the frontMatter data will be added here too.
    +   */
    +                  
    +                  data
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  RouteData
    +                  
    +                    ;
    +                  
    +                  
    +                    }
    +                  
    +                
    +              
    +

    + The + + HandledRoute + + interface provides the needed properties to develop your own plugin.

    -
    -                
    -                  No configuration
    -                  
    -                    for
    +              

    + + route: string + +

    +

    + An application route to be handled by Scully. +
    + This is the + + fully qualified + + route info. That means there should be no variables left in there. +
    + + # + + are not allowed, and query parameters are ignored. +

    +

    + + type: RoutesTypes + +

    +

    + Indicates the type of plugin. Contains the name of the routing plugin that should handle this. +

    +

    + This is a mandatory field that + + must + + be provided. When the type doesn't exist, Scully will terminate, as it doesn't know what to do. +

    +

    + + defaultPostRenderers?: string[] + +

    +

    + Array with string ID's of the content-renderers that will be run on all routes. +

    +

    + + postRenderers?: string[] + +

    +

    + Array of plugin names to be executed after the initial page render. +

    +

    + Each of the plugins in this array will be rendered in the order they appear, and they will receive the output HTML from the previous plugin. +

    +

    + Moreover, this array + + replaces + + the + + defaultPostRenderers + + array. +

    +
    +                
    +                  
    +                    const
    +                  
    +                  defaultPostRenderers
    +                  
    +                    =
    +                  
    +                  
    +                    [
    +                  
    +                  
    +                    'seoHrefOptimise'
    +                  
    +                  
    +                    ]
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    const
    +                  
    +                  sampleConf
    +                  
    +                    :
    +                  
    +                  ScullyConfig
    +                  
    +                    =
    +                  
    +                  
    +                    {
    +                  
    +                  defaultPostRenderers
    +                  
    +                    ,
    +                  
    +                  routes
    +                  
    +                    :
    +                  
    +                  
    +                    {
    +                  
    +                  
    +                    /** gets the default postrenderes */
    +                  
    +                  normalRoute
    +                  
    +                    :
    +                  
    +                  
    +                    {
    +                  
    +                  
    +                    type
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    'default'
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    /** adds to the default postrenderes */
    +                  
    +                  someRoute
    +                  
    +                    :
    +                  
    +                  
    +                    {
    +                  
    +                  
    +                    type
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    'default'
    +                  
    +                  
    +                    ,
    +                  
    +                  postRenderers
    +                  
    +                    :
    +                  
    +                  
    +                    [
    +                  
    +                  
    +                    ...
    +                  
    +                  defaultPostRenderers
    +                  
    +                    ,
    +                  
    +                  
    +                    'myAddition'
    +                  
    +                  
    +                    ]
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    /** removes the default postrenderes */
    +                  
    +                  someOtherRoute
    +                  
    +                    :
    +                  
    +                  
    +                    {
    +                  
    +                  
    +                    type
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    'default'
    +                  
    +                  
    +                    ,
    +                  
    +                  postRenderers
    +                  
    +                    :
    +                  
    +                  
    +                    [
    +                  
    +                  
    +                    'unique'
    +                  
    +                  
    +                    ]
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    ,
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    ;
                       
    -                  route \`/user/:userId\` found. Skipping
                     
                   
    -

    - The above error is given because Scully does not know all the possible values for - - :userId +

    + The + + defaultPostRenderers - . Teach Scully how to get the list of - - :userId + and + + postRenderers - s from your app. Scully can turn - - /user/:userId + are designed this way in order to allow you to dispose of the default renderers. Moreover, the current design is versatile, flexible, and it makes it easy to opt-out. +

    +

    + Do not forget to add the + + defaultPostRenderers - into a list of meaningful pre-renderable routes like so: + !

    -
    -                
    -                  /user/1
    -/user/2
    -/user/3
    -...
    -/user/100
    +              

    + + templateFile?: string + +

    +

    + The file's name containing the template to be rendered. + + Unrelated to the Angular template! + +

    +

    + This property is specific to + + contentFolder + + . It contains the full path to the file that should be used to generate the content. +

    +

    + Remember that content will be inserted + + after + + the initial rendering. +

    +

    + + data?: RouteData + +

    +

    + The data added to this property will be added to the routes data in + + scully.routes.json + +
    + This data will also be extended in + + contentFolder + + routes with the front-matter data out of the start of the templateFile. +

    +
    +                
    +                  
    +                    export
    +                  
    +                  
    +                    interface
    +                  
    +                  
    +                    RouteData
    +                  
    +                  
    +                    {
    +                  
    +                  title
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ;
    +                  
    +                  author
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ;
    +                  
    +                  published
    +                  
    +                    ?
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    boolean
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    [
    +                  
    +                  prop
    +                  
    +                    :
    +                  
    +                  
    +                    string
    +                  
    +                  
    +                    ]
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    any
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    }
    +                  
                     
                   
    -

    - Even small Angular projects have routes that contain route parameters. To stop Scully from skipping these routes, configure a route plugin. Route plugins teach Scully how to fetch data and merges it into routes using parameters. +

    + Router Plugin Interface +

    +

    + A + + router plugin + + is a function that returns a + + Promise<HandledRoute[]> + + .

    -

    - The easiest way to understand route plugin is by understanding the - - jsonPlugin +

    + The + + HandledRoute - . It simply fetches data from any API that you specify, and it returns a list of properties that can be used to replace the route parameter. Checkout the - - jsonPlugin docs - - to see an example of how easy this configuration is. + interface is described above. It receives a string with the unhandled route, and the config for that specific route. +

    +

    + A router plugin function should be as follows: +

    +
    +                
    +                  
    +                    function
    +                  
    +                  
    +                    exampleRouterPlugin
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    route
    +                    
    +                      :
    +                    
    +                    
    +                      string
    +                    
    +                    
    +                      ,
    +                    
    +                    config
    +                    
    +                      :
    +                    
    +                    
    +                      any
    +                    
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    :
    +                  
    +                  
    +                    Promise
    +                  
    +                  
    +                    <
    +                  
    +                  HandledRoute
    +                  
    +                    [
    +                  
    +                  
    +                    ]
    +                  
    +                  
    +                    >
    +                  
    +                  
    +                    {
    +                  
    +                  
    +                    // Must return a promise
    +                  
    +                  
    +                    }
    +                  
    +                
    +              
    +

    + The + + HandledRoute[] + + gets it data added into the + + scully-routes.json + + file generated by the + + npm run scully + + command.

    - + - -
    -
    -
    -
    -
    - + + + + +
    `; -exports[`docsSite should have content for all markdown files check html for markdown docs/scully-cmd-line 1`] = ` +exports[`docsSite should have content for all markdown files check html for markdown docs/learn/schematics/create-blog-config 1`] = ` @@ -20045,38 +71921,10 @@ exports[`docsSite should have content for all markdown files check html for mark - - - - - - - + > + - beta - - scullyLogo + beta - -
    - - - - - - - - - - -
    - - - -

    - Scully Command Line Options -

    -

    - The Scully CLI has the following available options: -

    -

    - - Scully command line options - -

    -
    -
    -
    -
    -
    - + + + + +
    `; -exports[`docsSite should have content for all markdown files check html for markdown docs/scully-configuration 1`] = ` +exports[`docsSite should have content for all markdown files check html for markdown docs/learn/schematics/create-markdown-files-and-skeleton 1`] = ` @@ -21241,36 +73066,8 @@ exports[`docsSite should have content for all markdown files check html for mark href="favicon.ico" > - - - - - - - beta - - scullyLogo + beta - -
    - - - - - - - - - - -
    - - - -

    - Scully Configuration -

    -

    - The central part of a Scully project is the - - scully.<projectname>.config.ts - - file. This file exports the Scully build configuration for an application. -

    -

    - If you are new to Scully, it is recommended to read the - - Getting Started - - documentation. -

    -

    - The - - scully.<projectname>.config.ts - - file's structure is shown below: -

    - + +
    + + + +
    +

    + create markdown files and skeleton +

    + + +
    + +
    +
    + + + + +`; + +exports[`docsSite should have content for all markdown files check html for markdown docs/learn/schematics/create-plugin-skeleton 1`] = ` + + + + + + + ScullyDocs + + + + + + + + + + beta + + + + Core features + + + + +
  • + - /** how to handle 404 in Scully server */ - - handle404?: - - string - - ; -} - - -

    - The - - ScullyConfig - - interface provides parameters for configuring how Scully works in a project. -

    -

    - scullyConfig File's Properties -

    -

    - projectRoot -

    -

    - - projectRoot - - - The project's from which Scully generates the static content. -

    -

    - homeFolder -

    -

    - - homeFolder - - - A reference to the Angular project's root folder. This property is for internal use, and it defaults to the angular.json file's location. -

    -

    - outDir -

    -

    - - outDir - - - The folder's path where Scully leaves the statics files. This should not be the same as the distFolder. -

    -

    - outHostFolder -

    -

    - - outHostFolder - - The folder that is used to host the static files, defaults to the outDir. You can use this when you need to change the baseHref of pages. -

    -

    - The default path is: -

    -
    -                
    +                    
    +                    
    +                      Legacy support
    +                    
    +                  
    +                  
    +                
  • +
  • - ./dist/static - - -

    - logFileSeverity -

    -

    - - logFileSeverity - - - determine what of the Scully output will be written into the - - scully.log - - file in the root of the project. -options: -

    - -

    +
  • + - handle404 -
  • -

    - - handle404 - - - how routes that are not provided in the application are handled by the Scully server. When the server gets a request for a route(file) that does not exists on the file-system, this option amends ow that is handled. -

    -
      -
    • - "" (default) is to render a 404 page, and raise a waring during rendering. + + -

      - distFolder -

      -

      - - distFolder - - - Path to the Angular application's dist folder. Scully takes the - - angular.json - - file's default path. This option can be modify according to the needs. This folder will be used by Scully during rendering. -

      -

      +

    + +
    + + + +
    +

    + introduction +

    + + +
    + +
    +
    + + + + +`; + +exports[`docsSite should have content for all markdown files check html for markdown docs/learn/schematics/create-scully-files-with-ng-add 1`] = ` + + + + + + + ScullyDocs + + + + + + + + + + beta + +
    +
    + + +
  • +
  • + - guessParserOptions - -

    - The - - guessParserOptions - - that get passed to the - - guess-parser - - library. Currently, the only supported property is - - excludedFiles - - , and it excludes files from the - - guess-parser - - route discovery process. -

    -

    - ignoreResourceTypes -

    -

    - The - - ignoreResourceTypes - - array that get passed to the - - puppeteerRenderPlugin - - . -Any - - ResourceType - - that is listed here will be ignored by the Puppeteer instance rendering the requested page. -For example if you add - - image - - and - - font - - all requests to images and fonts loaded on your pages will be ignored. -

    - +
    +
    + + Community + + + +
  • + + +
    + + + +
    +

    + create scully files with ng add +

    + - -
    -
    -
    -
    -
    - + + + + +
    `; -exports[`docsSite should have content for all markdown files check html for markdown docs/scully-lib-core 1`] = ` +exports[`docsSite should have content for all markdown files check html for markdown docs/learn/schematics/run-router-discovery 1`] = ` @@ -22785,36 +76495,8 @@ exports[`docsSite should have content for all markdown files check html for mark href="favicon.ico" > - - - - - - - beta - - scullyLogo + beta - -
    - - - - - - - - - - -
    - - - -

    - Scully Core -

    -

    - This section covers Scully's core features, and they are listed below: -

    - -

    - Idle Monitor Service -

    -

    - The - - IdleMonitorService - - hooks into Zonejs. When Angular goes idle ( - - more precisely, when all outgoing HTTP requests finish - - ) -Scully triggers Puppeteer in order to know when it is ready to render. This service is in the - - ScullyLibModule - - . -

    -

    - If your content is loaded out of sight of zones, Scully scrapes the page before its ready. -

    -

    - To disable Scully ready mechanism and add your custom mechanism -

    -
      -
    • - Put following config object in the forRoot config -
    • -
    -
    -                
    -                  ScullyLibModule.forRoot({
    -  useTransferState:
    -                  
    -                    true
    -                  
    -                  ,
    -  alwaysMonitor:
    -                  
    -                    false
    -                  
    -                  ,
    -  manualIdle:
    -                  
    -                    true
    -                  
    -                  });
    -                
    -              
    -

    - This will cause Scully to fall-back to using a 25 seconds timeout, on every page rendered. -

    - -
    -                
    -                  
    -                    export
    -                  
    -                  
    -                    class
    -                  
    -                  ManualIdleComponent
    -                  
    -                    implements
    -                  
    -                  OnInit {
    -  text =
    -                  
    -                    'this text is displayed by automated detection'
    -                  
    -                  ;
    -                  
    -                    constructor
    -                  
    -                  (
    -                  
    -                    
    -                      private
    +                    
    +
    + + Legacy support - ims: IdleMonitorService -
    - ) {} - - ngOnInit(): - - void - - { - - setTimeout - - ( - - () => - - ( - - this - - .text = - - '__ManualIdle__' - - ), - - 3 - - * - - 1000 - - ); - - setTimeout - - ( - - () => - - - this - - .ims.fireManualMyAppReadyEvent(), - - 3.25 - - * - + + +
  • + - 1000 - - ); - } -} - -
  • - -
    -                
    -                  
    -                    // scully.config.ts
    -                  
    -                  
    -                    export
    -                  
    -                  
    -                    const
    -                  
    -                  config: ScullyConfig = {
    -  routes: {
    -                  
    -                    '/user/:userId'
    -                  
    -                  : {
    -                  
    -                    type
    -                  
    -                  :
    -                  
    -                    'json'
    -                  
    -                  ,
    -                  
    -                    // Add the following to your route
    -                  
    -                  exposeToPage:{
    -        manualIdle:
    -                  
    -                    true
    -                  
    -                  }
    -      userId: {
    -        url:
    -                  
    -                    'http://localhost:8200/users'
    -                  
    -                  ,
    -        property:
    -                  
    -                    'id'
    -                  
    -                  }
    -    }
    -  }
    -};
    -                
    -              
    -

    - Router Service -

    -

    - The - - ScullyRoutesService - - provides methods and observables that allow you to know the routes rendered by Scully. -

    -

    - The observables and methods are listed below: -

    - -

    - available$: - - Observable<ScullyRoute[]> - -

    -

    - - available$ - - - Returns routes containing the property - - published - - with a value of true. -

    -

    - unPublished$: - - Observable<ScullyRoute[]> - -

    -

    - - unPublished$ - - - Returns routes containing the property - - published - - with a value of false. -

    -

    - topLevel$: - - Observable<ScullyRoute[]> - -

    -

    - - topLevel$ - - - Returns the top-level routes. -

    -

    - getCurrent(): - - Observable<ScullyRoute> - -

    -

    - - getCurrent() - - - A method that returns the current location. -

    -

    - reload(): - - void - -

    -

    - - reload - - - A method that checks if new routes have been added to the - - scully-routes.json - - file. -

    -

    - The - - ScullyRoutesService - - 's types come from the - - ScullyRoute - - interface, which is shown below: -

    -
    -                
    -                  
    -                    export
    -                  
    -                  
    -                    interface
    -                  
    -                  ScullyRoute {
    -  route:
    -                  
    -                    string
    -                  
    -                  ;
    -  title?:
    -                  
    -                    string
    -                  
    -                  ;
    -  slugs?:
    -                  
    -                    string
    -                  
    -                  [];
    -  published?:
    -                  
    -                    boolean
    -                  
    -                  ;
    -  slug?:
    -                  
    -                    string
    -                  
    -                  ;
    -  [prop:
    -                  
    -                    string
    -                  
    -                  ]:
    -                  
    -                    any
    -                  
    -                  ;
    -}
    -                
    -              
    -

    - Scully Content Component -

    -

    - The - - scully-content - - component inserts the render process' result into the HTML document. -

    -

    - - NOTE: - - The - - scully-content - - component does not work inside an - - *ngIf - - directive. -

    -

    - Transfer State Service -

    -

    - The - - TransferStateService - - allows to transfer an Angular application's state into the static site rendered by Scully. -More over, it allows you to load the state on subsequent route changes after the initial page has been loaded. -

    -

    - A route change fetches the next route's state from the page on the serve, and it is returned to the client. Hence, having a state consumed as part of the build despite any CMS content in production -

    -

    - To get or set the application's state; use the two methods below: -

    -

    - getState -

    -

    - - getState - - - This method returns an observable that fires once and then completes. It does executes after the page's navigation has finished. -

    -
    -                
    -                  getState<T>(name:
    -                  
    -                    string
    -                  
    -                  ): Observable<T>
    -                
    -              
    -

    - setState -

    -

    - - setState - - - This method sets values to the property key. -

    -
    -                
    -                  setState<T>(name:
    -                  
    -                    string
    -                  
    -                  , val: T):
    -                  
    -                    void
    -                  
    -                  ;
    -                
    -              
    -

    - utility-methods -

    -

    - These methods provide useful information about Scully processes. -

    -
    - isScullyRunning(): - - boolean - -
    -

    - - isScullyRunning - - - This method returns - - true - - or - - false - - if the Scully build is currently running. -

    -
    - isScullyGenerated(): - - boolean - -
    -

    - - isScullyGenerated - - - This method returns - - true - - if the Scully build has run. -

    - - -
    -
    -
    -
    -
    -
    - + + + + + + +
    + + + +
    +

    + run router discovery +

    + + +
    + +
    +
    +
    `; -exports[`docsSite should have content for all markdown files check html for markdown docs/scully-provided-plugins 1`] = ` +exports[`docsSite should have content for all markdown files check html for markdown docs/learn/utilities/github-actions/scully-publish 1`] = ` @@ -23943,36 +77638,8 @@ exports[`docsSite should have content for all markdown files check html for mark href="favicon.ico" > - - - - - - - beta - - scullyLogo + beta - -
    - - - - - - - - - - -
    - - - -

    - This document describes Scully's builtin plugins. + + + +
    + + + +
    +

    + Scully Publish Github Action

    -

    - json (router) -

    -

    - ignored (router) -

    -

    - contentFolder (router+render) -

    -

    - seoHrefOptimise (render) -

    -

    - Adds a trailing slash ( - - / - - ) to all routes that are in the routeService. Increases SEO scoring. -

    -

    - adoc (fileHandler) +

    + Overview

    -

    - md (fileHandler) -

    -

    - router (router) -

    -

    - Adds the route verbatim. Scully uses this plugin by default. +

    + The Github Action + + Scully Publish + + lets you easily build and deploy your Scully site to + + GitHub Pages + + .

    - + - -

    -
    -
    -
    -
    - + + + + +
    `; -exports[`docsSite should have content for all markdown files check html for markdown docs/showcase 1`] = ` +exports[`docsSite should have content for all markdown files check html for markdown docs/learn/utilities/overview--- 1`] = ` @@ -24496,36 +78796,8 @@ exports[`docsSite should have content for all markdown files check html for mark href="favicon.ico" > - - - - - - - beta - - scullyLogo + beta - -
    - - - - - - - - - - -
    - - - -

    - Scully Showcase -

    -

    - - 1-800 Contacts - -
    -

    -

    - - ConfigCat Feature Flags - -
    -

    -

    - +

  • + + + +
  • + + +
    + + + +
    +

    + Utilities +

    +

    + Overview +

    +

    + Scully works well in combination with other tools and utilities:

    -

    - - AppsAtEase - -
    -

    - - + + - -
    -
    -
    -
    -
    - + + + + +
    `; -exports[`docsSite should have content for all markdown files check html for markdown docs/util 1`] = ` +exports[`docsSite should have content for all markdown files check html for markdown docs/learn/utilities/syntax-highlighting/prism-js 1`] = ` @@ -25088,36 +79967,8 @@ exports[`docsSite should have content for all markdown files check html for mark href="favicon.ico" > - - - - - - - beta - - scullyLogo + beta - -
    - - - - - - - - - - -
    - - - -

    - Utilities -

    -

    - Scully works well in combination with other tools and utilities, for example: -

    - -

    - Github Action: Scully Publish +

    + Overview

    -

    - The Github Action - - Scully Publish +

    + + Prism - let you easily build and deploy your Scully site to GitHub Pages. -

    -

    - Syntax Highlighting Using Prismjs -

    -

    - Prism is a lightweight, extensible syntax highlighter that can be used when working with code blocks in markdown files in blog posts. + is a lightweight, extensible syntax highlighter that can be used when working with code blocks in markdown files in blog posts.

    -

    +

    It is possible to define a language for the code to be used in the Scully code like this:

    -
    -                
    -                  \`\`\`ts
    +              
    +                
    +                  \`\`\`typescript
     const foo = 'bar';
     \`\`\`
                     
                   
    -

    +

    + How Scully Handles Code Blocks +

    +

    Scully parses the markdown using - - + + marked , and the parsed result looks like this:

    -
    -                
    -                  
    -                    <
    -                    
    +              
    +                
    +                  
    +                    
    +                      
    +                        <
    +                      
                           code
                         
    -                    
    +                    
                           class
                         
    -                    =
    -                    
    -                      "language-ts"
    +                    
    +                      
    +                        =
    +                      
    +                      
    +                        "
    +                      
    +                      language-ts
    +                      
    +                        "
    +                      
    +                    
    +                    
    +                      >
                         
    -                    >
                       
    -                  
    -                    <
    -                    
    +                  
    +                    
    +                      
    +                        <
    +                      
                           span
                         
    -                    
    +                    
                           class
                         
    -                    =
    -                    
    -                      "token keyword"
    +                    
    +                      
    +                        =
    +                      
    +                      
    +                        "
    +                      
    +                      token keyword
    +                      
    +                        "
    +                      
    +                    
    +                    
    +                      >
                         
    -                    >
                       
                       const
    -                  
    -                    </
    -                    
    +                  
    +                    
    +                      
    +                        </
    +                      
                           span
                         
    -                    >
    +                    
    +                      >
    +                    
                       
                       foo
    -                  
    -                    <
    -                    
    +                  
    +                    
    +                      
    +                        <
    +                      
                           span
                         
    -                    
    +                    
                           class
                         
    -                    =
    -                    
    -                      "token operator"
    +                    
    +                      
    +                        =
    +                      
    +                      
    +                        "
    +                      
    +                      token operator
    +                      
    +                        "
    +                      
    +                    
    +                    
    +                      >
                         
    -                    >
                       
                       =
    -                  
    -                    </
    -                    
    +                  
    +                    
    +                      
    +                        </
    +                      
                           span
                         
    -                    >
    +                    
    +                      >
    +                    
                       
    -                  
    -                    <
    -                    
    +                  
    +                    
    +                      
    +                        <
    +                      
                           span
                         
    -                    
    +                    
                           class
                         
    -                    =
    -                    
    -                      "token string"
    +                    
    +                      
    +                        =
    +                      
    +                      
    +                        "
    +                      
    +                      token string
    +                      
    +                        "
    +                      
    +                    
    +                    
    +                      >
                         
    -                    >
                       
                       'bar'
    -                  
    -                    </
    -                    
    +                  
    +                    
    +                      
    +                        </
    +                      
                           span
                         
    -                    >
    +                    
    +                      >
    +                    
                       
    -                  
    -                    <
    -                    
    +                  
    +                    
    +                      
    +                        <
    +                      
                           span
                         
    -                    
    +                    
                           class
                         
    -                    =
    -                    
    -                      "token punctuation"
    +                    
    +                      
    +                        =
    +                      
    +                      
    +                        "
    +                      
    +                      token punctuation
    +                      
    +                        "
    +                      
    +                    
    +                    
    +                      >
                         
    -                    >
                       
                       ;
    -                  
    -                    </
    -                    
    +                  
    +                    
    +                      
    +                        </
    +                      
                           span
                         
    -                    >
    +                    
    +                      >
    +                    
                       
    -                  
    -                    </
    -                    
    +                  
    +                    
    +                      
    +                        </
    +                      
                           code
                         
    -                    >
    +                    
    +                      >
    +                    
                       
                     
                   
    -

    - +

    + marked uses the CSS class prefix - + language- to tag the code block with an appropriate language.

    -

    +

    + Usage +

    +

    To highlight the code blocks use - - + + prismjs and create a service like this:

    -
    -                
    -                  npm i --save prismjs
    +              
    +                
    +                  
    +                    npm
    +                  
    +                  i --save prismjs
     ng g s highlight
                     
                   
    -

    +

    The service will include all languages needed. The code looks like this:

    -
    -                
    -                  
    +              
    +                
    +                  
                         import
                       
    -                  { Injectable, Inject }
    -                  
    +                  
    +                    {
    +                  
    +                  Injectable
    +                  
    +                    ,
    +                  
    +                  Inject
    +                  
    +                    }
    +                  
    +                  
                         from
                       
    -                  
    +                  
                         '@angular/core'
                       
    -                  ;
    -                  
    +                  
    +                    ;
    +                  
    +                  
                         import
                       
    -                  { PLATFORM_ID }
    -                  
    +                  
    +                    {
    +                  
    +                  
    +                    PLATFORM_ID
    +                  
    +                  
    +                    }
    +                  
    +                  
                         from
                       
    -                  
    +                  
                         '@angular/core'
                       
    -                  ;
    -                  
    +                  
    +                    ;
    +                  
    +                  
                         import
                       
    -                  { isPlatformBrowser }
    -                  
    +                  
    +                    {
    +                  
    +                  isPlatformBrowser
    +                  
    +                    }
    +                  
    +                  
                         from
                       
    -                  
    +                  
                         '@angular/common'
                       
    -                  ;
    -                  
    +                  
    +                    ;
    +                  
    +                  
                         import
                       
    -                  
    +                  
                         'clipboard'
                       
    -                  ;
    -                  
    +                  
    +                    ;
    +                  
    +                  
                         import
                       
    -                  
    +                  
                         'prismjs'
                       
    -                  ;
    -                  
    +                  
    +                    ;
    +                  
    +                  
                         import
                       
    -                  
    +                  
                         'prismjs/plugins/toolbar/prism-toolbar'
                       
    -                  ;
    -                  
    +                  
    +                    ;
    +                  
    +                  
                         import
                       
    -                  
    +                  
                         'prismjs/plugins/copy-to-clipboard/prism-copy-to-clipboard'
                       
    -                  ;
    -                  
    +                  
    +                    ;
    +                  
    +                  
                         import
                       
    -                  
    +                  
                         'prismjs/components/prism-bash'
                       
    -                  ;
    -                  
    +                  
    +                    ;
    +                  
    +                  
                         import
                       
    -                  
    +                  
                         'prismjs/components/prism-css'
                       
    -                  ;
    -                  
    +                  
    +                    ;
    +                  
    +                  
                         import
                       
    -                  
    +                  
                         'prismjs/components/prism-javascript'
                       
    -                  ;
    -                  
    +                  
    +                    ;
    +                  
    +                  
                         import
                       
    -                  
    +                  
                         'prismjs/components/prism-json'
                       
    -                  ;
    -                  
    +                  
    +                    ;
    +                  
    +                  
                         import
                       
    -                  
    +                  
                         'prismjs/components/prism-markup'
                       
    -                  ;
    -                  
    +                  
    +                    ;
    +                  
    +                  
                         import
                       
    -                  
    +                  
                         'prismjs/components/prism-typescript'
                       
    -                  ;
    -                  
    +                  
    +                    ;
    +                  
    +                  
                         // ... probably more, check out node_modules/prismjs/components
                       
    -                  
    +                  
                         declare
                       
    -                  
    +                  
                         var
                       
    -                  Prism:
    -                  
    +                  Prism
    +                  
    +                    :
    +                  
    +                  
                         any
                       
    -                  ;
    -                  
    -                    @Injectable
    +                  
    +                    ;
                       
    -                  ()
    -                  
    +                  @
    +                  
    +                    Injectable
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    {
    +                  
    +                  providedIn
    +                  
    +                    :
    +                  
    +                  
    +                    'root'
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    )
    +                  
    +                  
                         export
                       
    -                  
    +                  
                         class
                       
    -                  HighlightService {
    -                  
    +                  
    +                    HighlightService
    +                  
    +                  
    +                    {
    +                  
    +                  
                         constructor
                       
    -                  (
    -                  
    -                    
    -                      @Inject
    +                  
    +                    (
    +                  
    +                  
    +                    @
    +                    
    +                      Inject
                         
    -                    (PLATFORM_ID)
    -                    
    +                    
    +                      (
    +                    
    +                    
    +                      PLATFORM_ID
    +                    
    +                    
    +                      )
    +                    
    +                    
                           private
                         
    -                    platformId:
    -                    
    -                      Object
    +                    platformId
    +                    
    +                      :
                         
    +                    Object
                       
    -                  ) {}
    -
    -  highlightAll() {
    -                  
    +                  
    +                    )
    +                  
    +                  
    +                    {
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    highlightAll
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    {
    +                  
    +                  
                         if
                       
    -                  (isPlatformBrowser(
    -                  
    +                  
    +                    (
    +                  
    +                  
    +                    isPlatformBrowser
    +                  
    +                  
    +                    (
    +                  
    +                  
                         this
                       
    -                  .platformId)) {
    -      Prism.highlightAll();
    -    }
    -  }
    -}
    +                  
    +                    .
    +                  
    +                  platformId
    +                  
    +                    )
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    {
    +                  
    +                  Prism
    +                  
    +                    .
    +                  
    +                  
    +                    highlightAll
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    }
    +                  
                     
                   
    -

    +

    Now, it needs to inject the service in the - + BlogComponent - that was generated by scully: + that was generated by Scully:

    -
    -                
    -                  
    +              
    +                
    +                  
                         import
                       
    -                  {
    -                  
    +                  
    +                    {
    +                  
    +                  
                         /* ... */
                       
    -                  , AfterViewChecked}
    -                  
    +                  
    +                    ,
    +                  
    +                  AfterViewChecked
    +                  
    +                    }
    +                  
    +                  
                         from
                       
    -                  
    +                  
                         '@angular/core'
                       
    -                  ;
    -                  
    +                  
    +                    ;
    +                  
    +                  
                         import
                       
    -                  {HighlightService}
    -                  
    +                  
    +                    {
    +                  
    +                  HighlightService
    +                  
    +                    }
    +                  
    +                  
                         from
                       
    -                  
    +                  
                         '../highlight.service'
                       
    -                  ;
    -                  
    +                  
    +                    ;
    +                  
    +                  
                         /* ... */
                       
    -                  
    +                  
                         export
                       
    -                  
    +                  
                         class
                       
    -                  BlogComponent
    -                  
    +                  
    +                    BlogComponent
    +                  
    +                  
                         implements
                       
    -                  OnInit, AfterViewChecked {
    -                  
    +                  
    +                    OnInit
    +                  
    +                  
    +                    ,
    +                  
    +                  AfterViewChecked
    +                  
    +                    {
    +                  
    +                  
                         constructor
                       
    -                  (
    -                  
    -                    
    -                      /* ... */
    -                    
    -                    
    -                      private
    -                    
    -                    highlightService: HighlightService
    +                  
    +                    (
                       
    -                  ) {}
    -                  
    +                  
                         /* ... */
                       
    -                  ngAfterViewChecked() {
    -                  
    +                  
    +                    private
    +                  
    +                  highlightService
    +                  
    +                    :
    +                  
    +                  HighlightService
    +                  
    +                    )
    +                  
    +                  
    +                    {
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    /* ... */
    +                  
    +                  
    +                    ngAfterViewChecked
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    {
    +                  
    +                  
                         this
                       
    -                  .highlightService.highlightAll();
    -  }
    -}
    +                  
    +                    .
    +                  
    +                  highlightService
    +                  
    +                    .
    +                  
    +                  
    +                    highlightAll
    +                  
    +                  
    +                    (
    +                  
    +                  
    +                    )
    +                  
    +                  
    +                    ;
    +                  
    +                  
    +                    }
    +                  
    +                  
    +                    }
    +                  
                     
                   
    -

    +

    Finally, include a Prism's theme like this:

    -
    -                
    -                  
    +              
    +                
    +                  
                         /* include CSS for prism toolbar */
                       
    -                  
    -                    @import
    -                  
    -                  
    -                    '~prismjs/plugins/toolbar/prism-toolbar.css'
    +                  
    +                    
    +                      @import
    +                    
    +                    
    +                      '~prismjs/plugins/toolbar/prism-toolbar.css'
    +                    
    +                    
    +                      ;
    +                    
                       
    -                  ;
    -                  
    +                  
                         /* check node_modules/prismjs/themes/ for the available themes */
                       
    -                  
    -                    @import
    -                  
    -                  
    -                    '~prismjs/themes/prism-tomorrow'
    +                  
    +                    
    +                      @import
    +                    
    +                    
    +                      '~prismjs/themes/prism-tomorrow'
    +                    
    +                    
    +                      ;
    +                    
                       
    -                  ;
                     
                   
    -

    +

    Visit - + prismjs for more information.

    - + - -
    -
    -
    -
    -
    - + + + + +
    diff --git a/tests/jest/src/__tests__/docsThere.spec.ts b/tests/jest/src/__tests__/docsThere.spec.ts index 21a7f0af1..11cbcaf9c 100644 --- a/tests/jest/src/__tests__/docsThere.spec.ts +++ b/tests/jest/src/__tests__/docsThere.spec.ts @@ -1,15 +1,16 @@ -import { readdirSync, readFileSync } from 'fs'; +import { readdirSync, readFileSync, existsSync } from 'fs'; import { join } from 'path'; import { readPage, replaceIndexNG } from '../test-config.helper'; const fm = require('front-matter'); import { expect } from '@jest/globals'; describe('docsSite', () => { - const path = join(__dirname, '../../../../docs'); + const startPath = join(__dirname, '../../../../docs'); + const basePath = join(__dirname, '../../../../'); describe('should have content for all markdown files', () => { - const files = readdirSync(path) - .filter((file) => file.endsWith('.md')) - .map((file) => getSlug(file, path)); + const files = getFiles(startPath) + .map((file) => file.p.split(basePath).join('')) + .map(getSlug); for (const file of files) { it(`check html for markdown ${file}`, () => { const index = readPage(file, 'doc-sites'); @@ -20,9 +21,22 @@ describe('docsSite', () => { }); }); -function getSlug(file, path) { - const content = readFileSync(join(path, file), 'utf-8'); +function getSlug(file) { + const content = readFileSync(file, 'utf-8'); const { attributes } = fm(content); const { slug } = attributes; - return 'docs/' + (slug ? encodeURIComponent(slug) : file.slice(0, -3)); + return '' + (slug ? encodeURIComponent(slug) : file.slice(0, -3)); +} + +function getFiles(path) { + const entries = readdirSync(path, { withFileTypes: true }); + const folders = entries.filter((folder) => folder.isDirectory()); + const files = entries + .filter((file) => !file.isDirectory() && file.name.endsWith('.md')) + .map((file) => ({ ...file, p: join(path, file.name) })); + for (const folder of folders) { + const newPath = `${path}/${folder.name}`; //? + files.push(...getFiles(newPath)); + } + return files; //? } diff --git a/workspace.json b/workspace.json index cbc1fc049..dc3d44195 100644 --- a/workspace.json +++ b/workspace.json @@ -205,8 +205,37 @@ "aot": true, "statsJson": true, "assets": ["apps/scully-docs/src/favicon.ico", "apps/scully-docs/src/assets"], - "styles": ["apps/scully-docs/src/styles.css"], - "scripts": [] + "styles": [ + "apps/scully-docs/src/app/app.component.css", + "apps/scully-docs/src/app/components/footer/component/footer.component.css", + "apps/scully-docs/src/app/components/header/component/nav-header/nav-header.component.css", + "apps/scully-docs/src/app/components/lang-select/component/lang-select/lang-select.component.css", + "apps/scully-docs/src/app/components/nav-list/components/child-list/child-list.component.css", + "apps/scully-docs/src/app/components/nav-list/components/nav-list/nav-list.component.css", + "apps/scully-docs/src/app/pages/docs/page/docs.page.component.css", + "apps/scully-docs/src/app/pages/landing/components/features/features.component.css", + "apps/scully-docs/src/app/pages/landing/components/intro/intro.component.css", + "apps/scully-docs/src/app/pages/landing/components/quote/quote.component.css", + "apps/scully-docs/src/app/pages/landing/components/resources/resources.component.css", + "apps/scully-docs/src/styles/_beta.css", + "apps/scully-docs/src/styles/_fonts.css", + "apps/scully-docs/src/styles/_reset.css", + "apps/scully-docs/src/styles/_variables.css", + "apps/scully-docs/src/styles/blockquote.css", + "apps/scully-docs/src/styles/code.css", + "apps/scully-docs/src/styles/details.css", + "apps/scully-docs/src/styles/headings.css", + "apps/scully-docs/src/styles/icon_button.css", + "apps/scully-docs/src/styles/link_table.css", + "apps/scully-docs/src/styles/links.css", + "apps/scully-docs/src/styles/paragraph_list.css", + "apps/scully-docs/src/styles/prev_next.css", + "apps/scully-docs/src/styles/prism-scully.css", + "apps/scully-docs/src/styles/showcase.css", + "apps/scully-docs/src/styles/table.css", + "apps/scully-docs/src/styles/toc.css" + ], + "scripts": ["apps/scully-docs/src/closeLangSelect.js"] }, "configurations": { "production": {

    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