master ab8c89e1f9c5 cached
326 files
381.1 KB
108.4k tokens
444 symbols
1 requests
Download .txt
Showing preview only (461K chars total). Download the full file or copy to clipboard to get everything.
Repository: patrickmichalina/fusebox-angular-universal-starter
Branch: master
Commit: ab8c89e1f9c5
Files: 326
Total size: 381.1 KB

Directory structure:
gitextract_3ok5m6pt/

├── .editorconfig
├── .firebaserc
├── .gitignore
├── .stylelintrc
├── .vscode/
│   ├── extensions.json
│   └── settings.json
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── Procfile
├── README.md
├── app.json
├── circle.yml
├── codecov.yml
├── data/
│   ├── security.rules.json
│   ├── seed.settings.json
│   └── seed.superusers.json
├── docs/
│   ├── angular-universal.md
│   ├── api-server.md
│   └── openid-server.md
├── e2e-spec.json
├── firebase.json
├── fuse.ts
├── package.json
├── src/
│   ├── client/
│   │   ├── app/
│   │   │   ├── __snapshots__/
│   │   │   │   └── app.component.spec.ts.snap
│   │   │   ├── about/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   └── about.component.spec.ts.snap
│   │   │   │   ├── about-routing.module.ts
│   │   │   │   ├── about.component.e2e-spec.ts
│   │   │   │   ├── about.component.html
│   │   │   │   ├── about.component.scss
│   │   │   │   ├── about.component.spec.ts
│   │   │   │   ├── about.component.ts
│   │   │   │   └── about.module.ts
│   │   │   ├── account/
│   │   │   │   ├── account-routing.module.ts
│   │   │   │   ├── account.component.html
│   │   │   │   ├── account.component.scss
│   │   │   │   ├── account.component.ts
│   │   │   │   └── account.module.ts
│   │   │   ├── admin/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   └── admin.component.spec.ts.snap
│   │   │   │   ├── admin-routing.module.ts
│   │   │   │   ├── admin.component.e2e-spec.ts
│   │   │   │   ├── admin.component.html
│   │   │   │   ├── admin.component.scss
│   │   │   │   ├── admin.component.spec.ts
│   │   │   │   ├── admin.component.ts
│   │   │   │   └── admin.module.ts
│   │   │   ├── app-routing.module.ts
│   │   │   ├── app.browser.module.ts
│   │   │   ├── app.component.html
│   │   │   ├── app.component.scss
│   │   │   ├── app.component.spec.ts
│   │   │   ├── app.component.ts
│   │   │   ├── app.config.ts
│   │   │   ├── app.module.ts
│   │   │   ├── changelog/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   └── changelog.component.spec.ts.snap
│   │   │   │   ├── changelog-routing.module.ts
│   │   │   │   ├── changelog.component.e2e-spec.ts
│   │   │   │   ├── changelog.component.html
│   │   │   │   ├── changelog.component.scss
│   │   │   │   ├── changelog.component.spec.ts
│   │   │   │   ├── changelog.component.ts
│   │   │   │   └── changelog.module.ts
│   │   │   ├── dashboard/
│   │   │   │   ├── dashboard-menu.ts
│   │   │   │   ├── dashboard-routing.module.ts
│   │   │   │   ├── dashboard.component.html
│   │   │   │   ├── dashboard.component.scss
│   │   │   │   ├── dashboard.component.ts
│   │   │   │   ├── dashboard.module.ts
│   │   │   │   ├── footer/
│   │   │   │   │   ├── __snapshots__/
│   │   │   │   │   │   └── dashboard-page-footer.component.spec.ts.snap
│   │   │   │   │   ├── dashboard-page-footer.component.html
│   │   │   │   │   ├── dashboard-page-footer.component.scss
│   │   │   │   │   ├── dashboard-page-footer.component.spec.ts
│   │   │   │   │   └── dashboard-page-footer.component.ts
│   │   │   │   ├── header/
│   │   │   │   │   ├── __snapshots__/
│   │   │   │   │   │   └── dashboard-page-header.component.spec.ts.snap
│   │   │   │   │   ├── dashboard-page-header.component.html
│   │   │   │   │   ├── dashboard-page-header.component.scss
│   │   │   │   │   ├── dashboard-page-header.component.spec.ts
│   │   │   │   │   └── dashboard-page-header.component.ts
│   │   │   │   ├── test/
│   │   │   │   │   ├── __snapshots__/
│   │   │   │   │   │   └── test.component.spec.ts.snap
│   │   │   │   │   ├── test-routing.module.ts
│   │   │   │   │   ├── test.component.html
│   │   │   │   │   ├── test.component.scss
│   │   │   │   │   ├── test.component.spec.ts
│   │   │   │   │   ├── test.component.ts
│   │   │   │   │   ├── test.module.ts
│   │   │   │   │   ├── test.service.ts
│   │   │   │   │   ├── testChild/
│   │   │   │   │   │   ├── __snapshots__/
│   │   │   │   │   │   │   └── testChild.component.spec.ts.snap
│   │   │   │   │   │   ├── testChild.component.html
│   │   │   │   │   │   ├── testChild.component.scss
│   │   │   │   │   │   ├── testChild.component.spec.ts
│   │   │   │   │   │   └── testChild.component.ts
│   │   │   │   │   └── testChild1/
│   │   │   │   │       ├── __snapshots__/
│   │   │   │   │       │   └── testChild1.component.spec.ts.snap
│   │   │   │   │       ├── testChild1.component.html
│   │   │   │   │       ├── testChild1.component.scss
│   │   │   │   │       ├── testChild1.component.spec.ts
│   │   │   │   │       └── testChild1.component.ts
│   │   │   │   └── test1/
│   │   │   │       ├── __snapshots__/
│   │   │   │       │   └── test1.component.spec.ts.snap
│   │   │   │       ├── test1-routing.module.ts
│   │   │   │       ├── test1.component.html
│   │   │   │       ├── test1.component.scss
│   │   │   │       ├── test1.component.spec.ts
│   │   │   │       ├── test1.component.ts
│   │   │   │       └── test1.module.ts
│   │   │   ├── home/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   └── home.component.spec.ts.snap
│   │   │   │   ├── home-routing.module.ts
│   │   │   │   ├── home.component.e2e-spec.ts
│   │   │   │   ├── home.component.html
│   │   │   │   ├── home.component.scss
│   │   │   │   ├── home.component.spec.ts
│   │   │   │   ├── home.component.ts
│   │   │   │   └── home.module.ts
│   │   │   ├── login/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   └── login.component.spec.ts.snap
│   │   │   │   ├── login-routing.module.ts
│   │   │   │   ├── login.component.e2e-spec.ts
│   │   │   │   ├── login.component.html
│   │   │   │   ├── login.component.scss
│   │   │   │   ├── login.component.spec.ts
│   │   │   │   ├── login.component.ts
│   │   │   │   └── login.module.ts
│   │   │   ├── logout/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   └── logout.component.spec.ts.snap
│   │   │   │   ├── logout-routing.module.ts
│   │   │   │   ├── logout.component.e2e-spec.ts
│   │   │   │   ├── logout.component.html
│   │   │   │   ├── logout.component.scss
│   │   │   │   ├── logout.component.spec.ts
│   │   │   │   ├── logout.component.ts
│   │   │   │   └── logout.module.ts
│   │   │   ├── not-found/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   └── not-found.component.spec.ts.snap
│   │   │   │   ├── not-found-routing.module.ts
│   │   │   │   ├── not-found.component.e2e-spec.ts
│   │   │   │   ├── not-found.component.html
│   │   │   │   ├── not-found.component.scss
│   │   │   │   ├── not-found.component.spec.ts
│   │   │   │   ├── not-found.component.ts
│   │   │   │   └── not-found.module.ts
│   │   │   ├── pages/
│   │   │   │   ├── page-form/
│   │   │   │   │   ├── page-form.component.html
│   │   │   │   │   ├── page-form.component.scss
│   │   │   │   │   └── page-form.component.ts
│   │   │   │   ├── pages-routing.module.ts
│   │   │   │   ├── pages.component.html
│   │   │   │   ├── pages.component.scss
│   │   │   │   ├── pages.component.ts
│   │   │   │   └── pages.module.ts
│   │   │   ├── shared/
│   │   │   │   ├── cache-form/
│   │   │   │   │   ├── cache-form.component.html
│   │   │   │   │   ├── cache-form.component.scss
│   │   │   │   │   └── cache-form.component.ts
│   │   │   │   ├── directives/
│   │   │   │   │   ├── avatar.directive.ts
│   │   │   │   │   ├── click-outside.directive.ts
│   │   │   │   │   ├── html-outlet.directive.ts
│   │   │   │   │   └── social-button.directive.ts
│   │   │   │   ├── http-cache-tag/
│   │   │   │   │   ├── http-cache-tag-interceptor.service.spec.ts
│   │   │   │   │   ├── http-cache-tag-interceptor.service.ts
│   │   │   │   │   └── http-cache-tag.module.ts
│   │   │   │   ├── injection-form/
│   │   │   │   │   ├── injection-form.component.html
│   │   │   │   │   ├── injection-form.component.scss
│   │   │   │   │   └── injection-form.component.ts
│   │   │   │   ├── key-value-form/
│   │   │   │   │   ├── key-value-form.component.html
│   │   │   │   │   ├── key-value-form.component.scss
│   │   │   │   │   └── key-value-form.component.ts
│   │   │   │   ├── login-card/
│   │   │   │   │   ├── login-card.component.html
│   │   │   │   │   ├── login-card.component.scss
│   │   │   │   │   └── login-card.component.ts
│   │   │   │   ├── material.module.ts
│   │   │   │   ├── modal-confirmation/
│   │   │   │   │   ├── modal-confirmation.component.html
│   │   │   │   │   ├── modal-confirmation.component.scss
│   │   │   │   │   └── modal-confirmation.component.ts
│   │   │   │   ├── navbar/
│   │   │   │   │   ├── __snapshots__/
│   │   │   │   │   │   └── navbar.component.spec.ts.snap
│   │   │   │   │   ├── navbar.component.html
│   │   │   │   │   ├── navbar.component.scss
│   │   │   │   │   ├── navbar.component.spec.ts
│   │   │   │   │   ├── navbar.component.ts
│   │   │   │   │   ├── navbar.service.spec.ts
│   │   │   │   │   └── navbar.service.ts
│   │   │   │   ├── pipes/
│   │   │   │   │   ├── key-value.pipe.ts
│   │   │   │   │   ├── keys.pipe.ts
│   │   │   │   │   └── sanitize-html.pipe.ts
│   │   │   │   ├── quill-editor/
│   │   │   │   │   ├── quill-editor.component.html
│   │   │   │   │   ├── quill-editor.component.scss
│   │   │   │   │   └── quill-editor.component.ts
│   │   │   │   ├── services/
│   │   │   │   │   ├── __snapshots__/
│   │   │   │   │   │   └── error-handler.service.spec.ts.snap
│   │   │   │   │   ├── adblock.service.spec.ts
│   │   │   │   │   ├── adblock.service.ts
│   │   │   │   │   ├── auth.service.ts
│   │   │   │   │   ├── cookie.service.spec.ts
│   │   │   │   │   ├── cookie.service.ts
│   │   │   │   │   ├── environment.service.spec.ts
│   │   │   │   │   ├── environment.service.ts
│   │   │   │   │   ├── error-handler.service.spec.ts
│   │   │   │   │   ├── error-handler.service.ts
│   │   │   │   │   ├── firebase-database.service.ts
│   │   │   │   │   ├── guard-admin.service.ts
│   │   │   │   │   ├── guard-login.service.ts
│   │   │   │   │   ├── http-config-interceptor.service.spec.ts
│   │   │   │   │   ├── http-config-interceptor.service.ts
│   │   │   │   │   ├── http-cookie-interceptor.service.spec.ts
│   │   │   │   │   ├── http-cookie-interceptor.service.ts
│   │   │   │   │   ├── injection.service.ts
│   │   │   │   │   ├── logging.service.spec.ts
│   │   │   │   │   ├── logging.service.ts
│   │   │   │   │   ├── minifier.service.ts
│   │   │   │   │   ├── platform.service.spec.ts
│   │   │   │   │   ├── platform.service.ts
│   │   │   │   │   ├── seo.service.ts
│   │   │   │   │   ├── server-response.service.spec.ts
│   │   │   │   │   ├── server-response.service.ts
│   │   │   │   │   ├── setting.service.spec.ts
│   │   │   │   │   ├── setting.service.ts
│   │   │   │   │   └── web-socket.service.ts
│   │   │   │   ├── shared.module.ts
│   │   │   │   ├── style-injection-form/
│   │   │   │   │   ├── style-injection-form.component.html
│   │   │   │   │   ├── style-injection-form.component.scss
│   │   │   │   │   └── style-injection-form.component.ts
│   │   │   │   └── web-app-installer/
│   │   │   │       ├── web-app-installer.component.html
│   │   │   │       ├── web-app-installer.component.scss
│   │   │   │       ├── web-app-installer.component.ts
│   │   │   │       ├── web-app-installer.module.ts
│   │   │   │       └── web-app-installer.service.ts
│   │   │   ├── signup/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   └── signup.component.spec.ts.snap
│   │   │   │   ├── signup-routing.module.ts
│   │   │   │   ├── signup.component.e2e-spec.ts
│   │   │   │   ├── signup.component.html
│   │   │   │   ├── signup.component.scss
│   │   │   │   ├── signup.component.spec.ts
│   │   │   │   ├── signup.component.ts
│   │   │   │   └── signup.module.ts
│   │   │   ├── unauthorized/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   └── unauthorized.component.spec.ts.snap
│   │   │   │   ├── unauthorized-routing.module.ts
│   │   │   │   ├── unauthorized.component.html
│   │   │   │   ├── unauthorized.component.scss
│   │   │   │   ├── unauthorized.component.spec.ts
│   │   │   │   ├── unauthorized.component.ts
│   │   │   │   └── unauthorized.module.ts
│   │   │   └── users/
│   │   │       ├── __snapshots__/
│   │   │       │   └── users.component.spec.ts.snap
│   │   │       ├── users-routing.module.ts
│   │   │       ├── users.component.html
│   │   │       ├── users.component.scss
│   │   │       ├── users.component.spec.ts
│   │   │       ├── users.component.ts
│   │   │       └── users.module.ts
│   │   ├── index.html
│   │   ├── main-prod.ts
│   │   ├── main.aot-prod.ts
│   │   ├── main.aot.ts
│   │   ├── main.ts
│   │   ├── ngsw.json
│   │   ├── operators.ts
│   │   ├── polyfills.ts
│   │   └── styles/
│   │       ├── main.scss
│   │       └── material2-app-themes.scss
│   ├── server/
│   │   ├── api/
│   │   │   ├── api.spec.ts
│   │   │   ├── controllers/
│   │   │   │   ├── index.ts
│   │   │   │   ├── settings.controller.spec.ts
│   │   │   │   └── settings.controller.ts
│   │   │   ├── index.ts
│   │   │   ├── middlewares/
│   │   │   │   ├── index.ts
│   │   │   │   └── zone-error-handler.ts
│   │   │   ├── repositories/
│   │   │   │   ├── index.ts
│   │   │   │   ├── setting.repository.ts
│   │   │   │   └── settings.ts
│   │   │   ├── services/
│   │   │   │   ├── index.ts
│   │   │   │   └── setting.service.ts
│   │   │   └── test-helper.ts
│   │   ├── server.angular-fire.service.ts
│   │   ├── server.angular.module.ts
│   │   ├── server.config.ts
│   │   ├── server.sitemap.ts
│   │   ├── server.ts
│   │   ├── server.web-socket.ts
│   │   └── service-account.json
│   ├── testing/
│   │   ├── app-testing.module.ts
│   │   ├── mock-cookie.service.ts
│   │   ├── mock-environment.service.ts
│   │   └── mock-firebase-database.service.ts
│   ├── tsconfig.json
│   └── tslint.json
├── tools/
│   ├── config/
│   │   ├── app.config.ts
│   │   ├── build.ci.replace.ts
│   │   ├── build.config.ts
│   │   ├── build.interfaces.ts
│   │   └── console.banner.256.txt
│   ├── env/
│   │   ├── base.ts
│   │   ├── dev.ts
│   │   ├── e2e.ts
│   │   └── prod.ts
│   ├── manual-typings/
│   │   ├── README.md
│   │   ├── project/
│   │   │   └── sample.package.d.ts
│   │   └── seed/
│   │       ├── bunyan.d.ts
│   │       ├── hash-files.d.ts
│   │       ├── json.d.ts
│   │       └── loglevel-std-streams.d.ts
│   ├── plugins/
│   │   ├── ng-aot.ts
│   │   ├── pwa-fused.ts
│   │   └── web-index.ts
│   ├── scripts/
│   │   ├── post-merge.sh
│   │   └── replace.ts
│   ├── tasks/
│   │   ├── index.ts
│   │   ├── project/
│   │   │   └── sample.ts
│   │   └── seed/
│   │       ├── assets.ts
│   │       ├── banner.ts
│   │       ├── changelog.ts
│   │       ├── clean.ts
│   │       ├── config.ts
│   │       ├── favicons.ts
│   │       ├── fonts.ts
│   │       ├── index.copy.ts
│   │       ├── index.minify.ts
│   │       ├── lint.ts
│   │       ├── mk-dist.ts
│   │       ├── ngc.ts
│   │       ├── ngsw-json.ts
│   │       ├── ngsw-worker.min.ts
│   │       ├── ngsw-worker.ts
│   │       ├── ngsw.ts
│   │       ├── sass.files.ts
│   │       ├── sass.ts
│   │       ├── serve.ts
│   │       └── web.ts
│   ├── test/
│   │   ├── jest.e2e-setup.ts
│   │   ├── jest.mocks.ts
│   │   └── jest.setup.ts
│   ├── tslint-rules/
│   │   └── validateDecoratorsRule.ts
│   └── web/
│       ├── ping.html
│       └── robots.txt
├── tsconfig-aot.json
├── tsconfig-e2e.json
└── tsconfig.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
# http://editorconfig.org

root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

[*.md]
insert_final_newline = false
trim_trailing_whitespace = false

================================================
FILE: .firebaserc
================================================
{
  "projects": {
    "default": "fuse-angular-universal-s-67402"
  }
}


================================================
FILE: .gitignore
================================================
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.DS_Store
dist
.env
.fusebox

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Typescript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

dist/

.DS_Store

test-report.xml
test-results.xml

ngc
.ngc
.aot
aot
.e2e

documentation

src/config.json

================================================
FILE: .stylelintrc
================================================
{
  "rules": {
    "block-no-empty": null,
    "color-no-invalid-hex": true,
    "comment-empty-line-before": [
        "always", {
            "ignore": ["stylelint-commands", "between-comments"]
        }
    ],
    "declaration-colon-space-after": "always",
    "indentation": 2,
    "max-empty-lines": 2,
    "unit-whitelist": ["em", "rem", "%", "px", "s", "ms", "vw", "vh", "deg"]
  }
}


================================================
FILE: .vscode/extensions.json
================================================
{
  "recommendations": [
    "msjsdiag.debugger-for-chrome",
    "michelemelluso.code-beautifier",
    "eg2.tslint",
    "eamodio.gitlens"
  ]
}

================================================
FILE: .vscode/settings.json
================================================
// Place your settings in this file to overwrite default and user settings.
{
  "editor.tabSize": 2,
  "beautify.tabSize": 2,
  "editor.insertSpaces": true,
  "autoimport.filesToScan": "src/**/*.{ts,tsx}",
  "typescript.tsdk": "node_modules/typescript/lib"
}

================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at patrickmichalina@mac.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]

[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing

We love pull requests from everyone. By participating in this project, you
agree to abide by our [code of conduct].

[code of conduct]: https://github.com/patrickmichalina/fusebox-angular-universal-starter/blob/master/CODE_OF_CONDUCT.md

Fork, then clone the repo:

    git clone https://github.com/patrickmichalina/fusebox-angular-universal-starter

Make sure the tests pass:

    npm test

Make your change. Add tests for your change. Make the tests pass:

    npm test

Push to your fork and [submit a pull request][pr].

[pr]: https://github.com/patrickmichalina/fusebox-angular-universal-starter/compare

At this point you're waiting on us. We like to at least comment on pull requests
within three business days (and, typically, one business day). We may suggest
some changes or improvements or alternatives.

Some things that will increase the chance that your pull request is accepted:

* Write tests.
* Write a [good commit message][commit].

[commit]: https://conventionalcommits.org


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2017 Patrick Michalina

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: Procfile
================================================
web: node dist/server.js --prod

================================================
FILE: README.md
================================================
## This project is archived and an improved version has been moved to [https://github.com/patrickmichalina/fusing-angular](https://github.com/patrickmichalina/fusing-angular)

# Introduction

[![CircleCI](https://circleci.com/gh/patrickmichalina/fusebox-angular-universal-starter.svg?style=shield)](https://circleci.com/gh/patrickmichalina/fusebox-angular-universal-starter)
[![codecov](https://codecov.io/gh/patrickmichalina/fusebox-angular-universal-starter/branch/master/graph/badge.svg)](https://codecov.io/gh/patrickmichalina/fusebox-angular-universal-starter)
[![dependencies Status](https://david-dm.org/patrickmichalina/fusebox-angular-universal-starter/status.svg)](https://david-dm.org/patrickmichalina/fusebox-angular-universal-starter)
[![devDependencies Status](https://david-dm.org/patrickmichalina/fusebox-angular-universal-starter/dev-status.svg)](https://david-dm.org/patrickmichalina/fusebox-angular-universal-starter?type=dev)
[![Greenkeeper badge](https://badges.greenkeeper.io/patrickmichalina/fusebox-angular-universal-starter.svg)](https://greenkeeper.io/)
[![Angular Style Guide](https://mgechev.github.io/angular2-style-guide/images/badge.svg)](https://angular.io/styleguide)
[![Fusebox-bundler](https://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg)](https://gitter.im/fusebox-angular-universal-starter/Lobby)

Provides an extremely fast seed project for the development of Angular Universal (isomorphic) projects. Check out the [live app](https://angular.patrickmichalina.com)

# Project Goals
This starter project is designed to get a basic application up and running with basic implementations of core features most applications need. It uses [Firebase](https://firebase.google.com) for the authentication and the database layers.

Note: Firebase doesn't have official support for Angular Universal at this time. However, we have implemented some of the basic features to render and transfer server state to the browser. Once an official support is released, we will use that.

# Features
- [x] [Angular](https://github.com/angular/angular/blob/master/CHANGELOG.md) as the application framework
- [x] [Angular Material](https://material.angular.io) as the UI language and component library
- [x] [Angular Flex Layout](https://github.com/angular/flex-layout) for dynamic responsive layouts
- [x] [FuseBox](http://fuse-box.org) as the TypeScript/JavaScript bundler
- [x] [Jest](https://facebook.github.io/jest) for unit and component testing
- [x] [Nightmare](https://github.com/segmentio/nightmare) for UI testing
- [x] [Sparky](http://fuse-box.org/page/sparky) as the task runner
- [x] Fully typed build tools using [TypeScript](https://www.typescriptlang.org)
- [x] Production and development builds
- [x] Manage your type definitions using [@types](https://www.npmjs.com/~types)
- [x] Simple [Heroku](https://www.heroku.com) Deployment
- [x] HttpStateTransfer for caching server responses on client boostrap (no flickering)
- [x] CDN asset configuration
- [x] Automatic sitemap generation
- [x] [SCSS](http://sass-lang.com) support for professional grade CSS management
- [x] [Brotli compression](https://github.com/google/brotli) with [gzip](http://www.gzip.org) fallback
- [x] [CircleCI](https://circleci.com) unit testing support 
- [x] Full favicon icon generation for multiple devices derived from a single seed image
- [x] SEO support for Title and Meta tags
- [x] OG (Open Graph) tags for social sharing
- [x] Simple Ad-Blocker detection service
- [x] Vendor-agnostic analytics using [angulartics2](https://github.com/angulartics/angulartics2)
- [x] Generic token based Authentication service with [JWT](https://jwt.io) cookie support.
- [x] Both Client and Server build tasks
- [x] Hot Module Reloading for faster browser reloads during client development
- [ ] [Ahead-of-Time](https://angular.io/guide/aot-compiler) (AOT) compilation support
- [x] [angular-tslint-rules](https://github.com/fulls1z3/angular-tslint-rules) as configuration preset for [TSLint](https://github.com/palantir/tslint) and [codelyzer](https://github.com/mgechev/codelyzer).
- [x] Automatic static file cache invalidation
- [x] [Lazy Loaded](https://angular-2-training-book.rangle.io/handout/modules/lazy-loading-module.html) modules
- [x] Analyze bundle sizes by using [source-map-explorer](https://github.com/danvk/source-map-explorer)
- [x] Support for [Angular Mobile Toolkit](https://mobile.angular.io) (Service Worker)
- [x] [Tree-Shaking](https://angular.io/guide/aot-compiler) for production builds

Built by [AngularUniversal.com](https://www.angularuniversal.com). For additional help please checkout our [services](https://www.angularuniversal.com/services)

# Quick Start

**Note that we strongly recommend node >= v7.0.0 and npm >= 4.0.0.**

To start the seed use:


```bash
$ git clone --depth 1 https://github.com/patrickmichalina/fusebox-angular-universal-starter
$ cd fusebox-angular-universal-starter

# Add Firebase Admin values to your project
# in a ".env" file for local deveopment
# in environment variables for other environments
See [Environment Variables](#environment-variables)

# install the project's dependencies
$ npm install

# start the Angular Universal server
$ npm start

# start the server while watching tests and updating app documentation
$ npm run start.deving

# start the Angular Universal server w/ AOT build step
$ npm run start.aot
# can also be called passing the parameter --aot
# npm start --aot

# start the application in Client only mode (not server driven), with HMR enabled
$ npm run start.spa

# start the server in production mode
$ npm run start.prod

```

# Table of Contents
* [Testing](#testing)
* [Configuration](#configuration)
* [Environment Variables](#environment-variables)
* [@Types](#types)
* [File Structure](#file-structure)
* [Change Log](#change-log)
* [License](#license)

# Bundling
Checkout how blazing fast bundling can be using FuseBox!

![fuse-box](https://thumbs.gfycat.com/WarmheartedUnfinishedHind-small.gif)

# Testing
```bash
# single test run
$ npm test 

# single test with coverage results
$ npm run test.coverage

# continuous testing
$ npm run test.watch

# e2e testing (primarilly for CI builds)
$ npm run test.e2e.ci

# continuous e2e testing
$ npm run test.e2e.watch
```

![jest](https://thumbs.gfycat.com/CooperativeMammothEland-small.gif)

# Configuration
```shell
Coming Soon
```

# @Types
When you include a module that doesn't include typings, you can include external type definitions using the npm @types repo.

i.e, to have youtube api support, run this command in terminal: 
```shell
npm i -D @types/youtube @types/gapi @types/gapi.youtube
``` 

# Environment Variables

```bash
# it is important to set the following environmental variables on your CI server (examples below)
HOST : angular.patrickmichalina.com # the root origin of your application server
CI : true 

# for Heroku Builds
HEROKU : true # to build on heroku, ssl settings are setup using this flag
NPM_CONFIG_PRODUCTION : false # to download all depenedencies on Heroku, including devDependencies

# Firebase Admin SDK
FB_SERVICE_ACCOUNT_PRIVATE_KEY_ID: Some_Secret
FB_SERVICE_ACCOUNT_PRIVATE_KEY: Some_Secret
FB_AUTH_KEY: Some_Secret

```

## File Structure
We use the component approach in our starter. This is the standard for developing Angular apps and a great way to ensure maintainable code
```
fusebox-angular-universal-starter/
 ├──.fusebox/                       * working folder for the js bundler
 ├──.vscode/                        * Visual Studio Code settings 
 ├──coverage/                       * stores recent reporting of test coverage
 ├──dist/                           * output files that represent the bundled application and its dependencies
 ├──node_modules/                   * project depdendencies
 |
 ├──src/
 |   ├──client/                     * client Angular code. (most your work should be done here)
 |   └──server/                     * server code
 |
 ├──tools/
 |   ├──config/
 |   |   ├──app.config.ts          * configuration interface for the web applications
 |   |   ├──build.config.ts        * configuration values for the build system
 |   |   ├──build.interfaces.ts    * configuration interfaces for the build system
 |   |   └──build.transformer.ts   * build system config transform helper
 |   |
 |   ├──env/
 |   |   ├──base.ts                * base app configuration 
 |   |   ├──dev.ts                 * dev app configuration
 |   |   ├──**.ts                  * arbitrary configuration called via the flag --env-config
 |   |   └──prod.ts                * production app configuration
 |   |
 |   ├──scripts/                   * misc. build helper scripts
 |   ├──tasks/                     * Sparky tasks
 |   ├──test/                      * testing system related configuration
 |   └──web/                       * static assets used for common web functions
 |
 ├──.gitignore                     * GIT settings
 ├──circl.yml                      * CirclCI configuration file
 ├──CODE_OF_CONDUCT.md             * standard code of conduct information
 ├──codecov.yml                    * codecov.io configuration file
 ├──CONTRIBUTING.md                * standard contributor information
 ├──fuse.ts                        * FuseBox entry point
 ├──LICENSE                        * software license
 ├──package-lock.json              * what npm uses to manage it's dependencies
 ├──package.json                   * what npm uses to manage it's dependencies
 ├──Procfile                       * Heroku deployment setting
 ├──README.md                      * project information
 ├──test-report.xml                * JUNIT test results
 ├──tsconfig-aot.json              * typescript config for AOT build using @angular-cli (ngc)
 └──tsconfig.json                  * typescript config
```

# Change Log

You can follow the [Angular change log here](https://github.com/angular/angular/blob/master/CHANGELOG.md).

# License

[MIT](https://github.com/patrickmichalina/fusebox-angular-universal-starter/blob/master/LICENSE)


================================================
FILE: app.json
================================================
{
  "name": "fusebox-angular-universal-star",
  "env": {
    "CI": {
      "required": true
    },
    "HOST": {
      "required": true
    },
    "HEROKU": {
      "required": true
    },
    "NODE_MODULES_CACHE": {
      "required": true
    },
    "NPM_CONFIG_PRODUCTION": {
      "required": true
    },
    "HEROKU_APP_NAME": {
      "required": true
    },
    "HEROKU_PARENT_APP_NAME": {
      "required": true
    },
    "FB_SERVICE_ACCOUNT_PRIVATE_KEY": {
      "required": true
    },
    "FB_SERVICE_ACCOUNT_PRIVATE_KEY_ID": {
      "required": true
    },
    "FB_AUTH_KEY": {
      "required": true
    }
  }
}

================================================
FILE: circle.yml
================================================
machine:
  node:
    version: 9.4.0
  npm:
    version: 5.6.0

general:
  artifacts:
    - ./coverage
    - ./dist

test:
  override:
    - npm run lint
    - npm run gen.config
    - npm run test.ci.before
    - node_modules/.bin/jest --ci --updateSnapshot --runInBand --coverage:
        environment:
          TEST_REPORT_PATH: $CIRCLE_TEST_REPORTS
          TEST_REPORT_FILENAME: test-results.xml
    - npm run test.ci.after

  post:
    - bash <(curl -s https://codecov.io/bash)
    - npm run semantic-release || true

deployment:
  production:
    branch: master
    heroku:
      appname: fusebox-angular-universal-star

================================================
FILE: codecov.yml
================================================
codecov:
  allow_coverage_offsets: false
  ignore:
    - "tools"

================================================
FILE: data/security.rules.json
================================================
{
  "rules": {
    "site-settings": {
      ".read": "true",
      ".write": "root.child('users').child(auth.uid).child('roles/superadmin').val() === true"
    },
    "posts": {
      ".read": "true",
      ".write": "true"
    },
    "pages": {
      ".read": "true",
      ".write": "true",
      "blog": {
        "$document": {
          ".read": "true",
          ".write": "true"
        }
      }
    },
    "users": {
      ".read": "auth != null && root.child('users').child(auth.uid).child('roles/superadmin').val() === true",
      "$uid": {
        ".read": "auth != null && auth.uid == $uid || root.child('users').child(auth.uid).child('roles/superadmin').val() === true",
        ".write": "auth != null && auth.uid == $uid || root.child('users').child(auth.uid).child('roles/superadmin').val() === true"
      }
    }
  }
}

================================================
FILE: data/seed.settings.json
================================================
{
  "host": "http://localhost:8000",
  "og": {
    "title": "Fusebox Angular Universal Starter",
    "description": "Seed project for Angular Universal apps featuring Server-Side Rendering (SSR), FuseBox, dev/prod builds, Brotli/Gzip, SCSS, favicon generation, @types, unit testing w/ Jest, and sitemap generator. Created by Patrick Michalina",
    "image": "https://d3anl5a3ibkrdg.cloudfront.net/assets/favicons/android-chrome-512x512.png",
    "type": "website",
    "locale": "en_US"
  },
  "firebase": {
    "appName": "fuse-angular-universal-starter",
    "config": {
      "apiKey": "AIzaSyDfE1owJZCbvasXieCKjMoGZddRhqcp7RM",
      "authDomain": "fuse-angular-universal-s-67402.firebaseapp.com",
      "databaseURL": "https://fuse-angular-universal-s-67402.firebaseio.com",
      "projectId": "fuse-angular-universal-s-67402",
      "storageBucket": "fuse-angular-universal-s-67402.appspot.com",
      "messagingSenderId": "883416191164"
    }
  },
  "assets": {
    "userAvatarImage": "https://firebasestorage.googleapis.com/v0/b/fuse-angular-universal-s-67402.appspot.com/o/avatar.jpg?alt=media&token=9a153021-6e12-460b-9d87-40c2eed02c82"
  },
  "tokens": {
    "facebookAppId": "117309532219749"
  },
  "injections": [
    {
      "inHead": true,
      "element": "link",
      "attributes": {
        "href": "/manifest.json",
        "rel": "manifest"
      }
    },
    {
      "inHead": true,
      "element": "meta",
      "attributes": {
        "name": "theme-color",
        "content": "#2196F3"
      }
    },
    {
      "inHead": false,
      "element": "link",
      "attributes": {
        "href": "https://fonts.googleapis.com/css?family=Roboto",
        "rel": "stylesheet",
        "type": "text/css",
        "media": "none",
        "onload": "if(media!=='all')media='all'"
      }
    },
    {
      "inHead": true,
      "element": "meta",
      "attributes": {
        "name": "google-site-verification",
        "content": "RW-hcjXEgPMoy2NF8pTl8IEzP8gnj3cEZ6aF1HDUiOc"
      }
    },
    {
      "inHead": true,
      "element": "script",
      "value": "window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;ga('create', 'UA-107089312-2', 'auto');",
      "attributes": {
        "type": "text/javascript"
      }
    },
    {
      "inHead": false,
      "element": "script",
      "attributes": {
        "async": "true",
        "type": "text/javascript",
        "src": "https://www.google-analytics.com/analytics.js"
      }
    }
  ],
  "i18n": {
    "en": {
      "about": {
        "title": "About",
        "description": "See contact information and details about the Angular Universal seed at angular.patrickmichalina.com"
      },
      "account": {
        "title": "Account",
        "description": "Update your profile and account settings"
      },
      "dashboard": {
        "title": "Dashboard",
        "description": "An example dashboard page"
      },
      "admin": {
        "title": "Admin",
        "description": "For application management"
      },
      "changelog": {
        "title": "Changelog",
        "description": "Version history of the application"
      },
      "home": {
        "title": "Home",
        "description": "A fullstack angular starter framework to quickly build mid-large scale web applications"
      },
      "login": {
        "title": "Login",
        "description": "Login to your account now."
      },
      "logout": {
        "title": "Logged Out",
        "description": "Come back again!"
      },
      "search": {
        "title": "Search",
        "description": "Search for angular related projects on github, to showcase the flicker-free http state transfer of an Angular isomorphic application."
      },
      "signup": {
        "title": "Signup",
        "description": "Sign up for an account with us. Create an account to start doing cool things with our application. It\"s easy to register"
      },
      "not-found": {
        "title": "Not Found",
        "description": "The page you requested can not be found."
      }
    },
    "jp": {
      "home": {
        "title": "こんにちは",
        "description": ""
      }
    }
  }
}

================================================
FILE: data/seed.superusers.json
================================================
{
  "9BthHoxklbgCzP2vlFI3ZrNggrl1": {
    "roles": {
      "superadmin": true,
      "admin": true
    }
  }
}

================================================
FILE: docs/angular-universal.md
================================================
# Universal "Gotchas"

> When building Universal components in Angular 2 there are a few things to keep in mind.

 - **`window`**, **`document`**, **`navigator`**, and other browser types - _do not exist on the server_ - so using them, or any library that uses them (jQuery for example) will not work. You do have some options, if you truly need some of this functionality:
    - If you need to use them, consider limiting them to only your client and wrapping them situationally. You can use the Object injected using the PLATFORM_ID token to check whether the current platform is browser or server. 
    
    ```
     import { PlatformService } from '../services';
     
     constructor(private platformService: PlatformService) { ... }
     
     ngOnInit() {
       if (this.platformService.isBrowser) {
          // Client only code.
          ...
       }
       if (this.platformService.isServer) {
         // Server only code.
         ...
       }
     }
    ```
    
     - Try to *limit or* **avoid** using **`setTimeout`**. It will slow down the server-side rendering process. Make sure to remove them in the [`ngOnDestroy`](https://angular.io/docs/ts/latest/api/core/index/OnDestroy-class.html) method of your Components.
   - Also for RxJs timeouts, make sure to _cancel_ their stream on success, for they can slow down rendering as well.
 - **Don't manipulate the nativeElement directly**. Use the _Renderer2_. We do this to ensure that in any environment we're able to change our view.
```
constructor(element: ElementRef, renderer: Renderer2) {
  renderer.setStyle(element.nativeElement, 'font-size', 'x-large');
}
```
 - The application runs XHR requests on the server & once again on the Client-side (when the application bootstraps)
    - Use a cache that's transferred from server to client (TODO: Point to the example)
 - Know the difference between attributes and properties in relation to the DOM.
 - Keep your directives stateless as much as possible. For stateful directives, you may need to provide an attribute that reflects the corresponding property with an initial string value such as url in img tag. For our native element the src attribute is reflected as the src property of the element type HTMLImageElement.

================================================
FILE: docs/api-server.md
================================================
# API
This project includes an example API that can be split off into a standalone server. The goal of this API is to provide a set of commonly used endpoints that could apply to most modern web applications. This inclides things like:

- Site Settings
- Image Uploads
- Tokens (login/logout)

# Stack
- [routing-controllers](https://github.com/pleerock/routing-controllers) Create structured, declarative and beautifully organized class-based controllers with heavy decorators usage in Express / Koa using TypeScript and Routing Controllers Framework.
- [swagger-jsdoc]() Generates swagger doc based on JSDoc.
- [swagger-ui-express]() Adds middleware to your express app to serve the Swagger UI bound to your Swagger document. This acts as living documentation for your API hosted from within your app.
- [typedi]() Dependency Injection for TypeScript.

# Structure
The API has an opinionted structure in order to better sperate the various layers of the applications:

- Controllers: gateway to the outside world, where users actually interact with the server
- Services: internal tools that can be used in controllers, other services, or anywhere in the API
- Repositories: data stores that are normally accessed via services
- Middlewares: express server plugins

## Removing from the project
... TODO

================================================
FILE: docs/openid-server.md
================================================
# Identity Server
This project includes an OpenID certifiec identity server that can be split off into a standalone OpenID server.

## Removing from the project
... TODO

================================================
FILE: e2e-spec.json
================================================
{
  "moduleFileExtensions": [
    "ts",
    "js",
    "html"
  ],
  "testRegex": "(/__tests__/.*|\\.(test|e2e-spec))\\.(ts|js)$",
  "transform": {
    "^.+\\.tsx?$": "<rootDir>/node_modules/ts-jest/preprocessor.js"
  },
  "globals": {
    "__TRANSFORM_HTML__": true,
    "__process_env__": {},
    "ts-jest": {
      "tsConfigFile": "tsconfig.json"
    }
  }
}

================================================
FILE: firebase.json
================================================
{
  "database": {
    "rules": "data/security.rules.json"
  }
}


================================================
FILE: fuse.ts
================================================
import { Ng2TemplatePlugin } from 'ng2-fused';
import { argv } from 'yargs';
import { BUILD_CONFIG, ENV_CONFIG_INSTANCE, isProdBuild, typeHelper } from './tools/config/build.config';
import { WebIndexPlugin } from './tools/plugins/web-index';
import { init, reload, active } from 'browser-sync';
import {
  EnvPlugin,
  FuseBox,
  HTMLPlugin,
  JSONPlugin,
  RawPlugin,
  SassPlugin,
  Sparky,
  QuantumPlugin
} from 'fuse-box';
import './tools/tasks';

const death = require('death')
const isReachable = require('is-reachable');
const isAot = argv.aot;
const isBuildServer = argv.ci;
const baseEntry = isAot ? 'main.aot' : 'main';
const appBundleName = `js/app`;
const vendorBundleName = `js/vendors`;
const mainEntryFileName = isProdBuild ? `${baseEntry}-prod` : `${baseEntry}`;
const vendorBundleInstructions = ` ~ client/${mainEntryFileName}.ts`;
const appBundleInstructions = ` !> [client/${mainEntryFileName}.ts]`;
const serverBundleInstructions = ' > [server/server.ts]';

if (isProdBuild) typeHelper()

const baseOptions = {
  homeDir: './src',
  output: `${BUILD_CONFIG.outputDir}/$name.js`,
  plugins: [
    Ng2TemplatePlugin(),
    ['*.component.html', RawPlugin()],
    ['*.component.scss',
      SassPlugin({ indentedSyntax: false, importer: true, sourceMap: false, outputStyle: 'compressed' } as any), RawPlugin()],
    JSONPlugin(),
    HTMLPlugin({ useDefault: false })
  ]
}

const appOptions = {
  ...baseOptions,
  hash: isProdBuild,
  plugins: [
    ...baseOptions.plugins,
    WebIndexPlugin({
      bundles: [vendorBundleName, appBundleName],
      startingDocumentPath: 'dist/index.html',
      appElement: {
        name: 'pm-app',
        innerHTML: 'Loading....'
      },
      additionalDeps: BUILD_CONFIG.dependencies as any[]
    }),
    isProdBuild && QuantumPlugin({
      target: "universal",
      warnings: false,
      uglify: true,
      treeshake: true,
      bakeApiIntoBundle: vendorBundleName,
      processPolyfill: true
    })
  ]
}

const serverOptions = {
  ...baseOptions,
  target: 'server',
  sourceMaps: false,
  plugins: [
    EnvPlugin(ENV_CONFIG_INSTANCE),
    ...baseOptions.plugins
  ]
}

Sparky.task('build.universal', () => {
  const fuseApp = FuseBox.init(appOptions as any);
  const fuseServer = FuseBox.init(serverOptions as any);
  const path = isAot ? 'client/.aot/src/client/app' : 'client/app';
  const serverBundle = fuseServer.bundle('server').instructions(serverBundleInstructions);
  const vendorBundle = fuseApp.bundle(`${vendorBundleName}`).instructions(vendorBundleInstructions)
  const appBundle = fuseApp
    .bundle(appBundleName)
    .splitConfig({ dest: 'js/modules' })
    .instructions(`${appBundleInstructions} + [${path}/**/!(*.spec|*.e2e-spec|*.ngsummary|*.snap).*]`)

  if (!isBuildServer && !argv['build-only']) {
    const proxy = `${BUILD_CONFIG.host}:${BUILD_CONFIG.port}`
    vendorBundle.watch()
    appBundle.watch()
    return fuseApp.run().then(() => {
      serverBundle.watch('src/**').completed(proc => {
        typeHelper(false, false)
        proc.start();
        isReachable(proxy).then(() => {
          active
            ? reload()
            : init({
              port: BUILD_CONFIG.browserSyncPort,
              proxy
            })
        })
        death(function (signal: any, err: any) {
          proc.kill()
          process.exit()
        })
      })
      return fuseServer.run()
    });
  } else {
    return fuseApp.run().then(() => fuseServer.run())
  }
});


================================================
FILE: package.json
================================================
{
  "name": "fusebox-angular-universal-starter",
  "version": "0.0.0-development",
  "description": "Angular Universal starter build pipeline using FuseBox",
  "license": "MIT",
  "homepage": "https://angular.patrickmichalina.com",
  "repository": {
    "type": "git",
    "url": "https://github.com/patrickmichalina/fusebox-angular-universal-starter"
  },
  "bugs": {
    "email": "patrickmichalina@mac.com",
    "url": "https://github.com/patrickmichalina/fusebox-angular-universal-starter/issues"
  },
  "author": {
    "email": "patrickmichalina@mac.com",
    "name": "Patrick Michalina",
    "url": "https://patrickmichalina.com"
  },
  "readme": "https://github.com/patrickmichalina/fusebox-angular-universal-starter/blob/master/README.md",
  "scripts": {
    "test": "npm run gen.config && jest",
    "test.ci": "npm run gen.config && jest --ci --updateSnapshot",
    "test.update": "npm run gen.config && jest --updateSnapshot",
    "test.coverage": "npm run gen.config && jest --coverage",
    "test.watch": "npm run gen.config && jest --watch",
    "test.ci.before": "greenkeeper-lockfile-update",
    "test.ci.after": "greenkeeper-lockfile-upload",
    "test.e2e": "npm run gen.config && jest -c e2e-spec.json",
    "test.e2e.ci": "npm run gen.config && npm run start.e2e && concurrently --kill-others --success first \"node dist/server.js --e2e --port 8000\" \"npm run test.e2e\"",
    "test.e2e.watch": "npm run gen.config && npm run start.e2e && concurrently --kill-others --success first --raw \"node dist/server.js --e2e\" \"jest -c e2e-spec.json --watch\" ",
    "start.mock.api": "json-server ./tools/test/db.json",
    "start.e2e": "ts-node fuse.ts serve --build-type prod --env-config e2e --ci --port 8000",
    "start": "ts-node fuse.ts serve --build-type dev --env-config dev",
    "start.deving": "concurrently \"npm run start\" \"npm run test.watch\" \"npm run compodoc\"",
    "start.spa": "ts-node fuse.ts serve --build-type dev --spa",
    "start.prod": "ts-node fuse.ts serve --build-type prod --env-config=prod",
    "start.prod.ci": "CI=true ts-node fuse.ts serve --build-type prod --env-config prod --ci --ci-vars",
    "heroku-postbuild": "npm run start.prod.ci",
    "source.tree.app": "ts-node fuse.ts build --build-only && source-map-explorer dist/js/app.js",
    "source.tree.server": "ts-node fuse.ts build --build-only &&  source-map-explorer dist/server.js",
    "compodoc": "./node_modules/.bin/compodoc -p tsconfig.json -t -s -w -o -r 8081 --theme readthedocs",
    "prepush": "npm run lint && npm test",
    "postmerge": "./tools/scripts/post-merge.sh || true",
    "semantic-release": "semantic-release pre && npm publish && semantic-release post",
    "lint": "ts-node fuse.ts lint --build-type prod",
    "postinstall": "./node_modules/.bin/ts-node fuse.ts clean",
    "firebase": "./node_modules/.bin/firebase",
    "firebase.update": "./node_modules/.bin/firebase deploy && npm run firebase.seed.superusers",
    "firebase.seed.site-settings": "./node_modules/.bin/firebase database:update /site-settings data/seed.settings.json -y",
    "firebase.seed.superusers": "./node_modules/.bin/firebase database:update /users data/seed.superusers.json -y",
    "gen.config": "ts-node fuse.ts config"
  },
  "devDependencies": {
    "@compodoc/compodoc": "1.1.2",
    "@pwa/manifest": "1.0.0",
    "@types/body-parser": "1.16.8",
    "@types/browser-sync": "0.0.39",
    "@types/bunyan": "1.8.4",
    "@types/clean-css": "3.4.30",
    "@types/compression": "0.0.36",
    "@types/cookie-parser": "1.4.1",
    "@types/dotenv": "4.0.3",
    "@types/express": "4.11.1",
    "@types/getos": "3.0.0",
    "@types/glob": "5.0.35",
    "@types/html-minifier": "3.5.2",
    "@types/jest": "22.2.3",
    "@types/js-cookie": "2.1.0",
    "@types/jsdom": "11.0.4",
    "@types/memory-cache": "0.2.0",
    "@types/mkdirp": "0.5.2",
    "@types/ms": "0.7.30",
    "@types/nightmare": "2.10.3",
    "@types/node-sass": "3.10.32",
    "@types/object-hash": "1.2.0",
    "@types/quill": "1.3.6",
    "@types/request": "2.47.0",
    "@types/serve-favicon": "2.2.30",
    "@types/stacktrace-js": "0.0.32",
    "@types/string-hash": "1.1.1",
    "@types/supertest": "2.0.4",
    "@types/ws": "4.0.2",
    "@types/yargs": "11.0.0",
    "angular-tslint-rules": "1.2.1",
    "browser-sync": "2.23.6",
    "codelyzer": "4.2.1",
    "concurrently": "3.5.1",
    "condition-circle": "2.0.1",
    "conventional-changelog": "1.1.24",
    "death": "1.1.0",
    "favicons": "4.8.6",
    "firebase-tools": "3.17.6",
    "font-awesome": "4.7.0",
    "fuse-box": "3.0.2",
    "fuse-box-typechecker": "2.7.1",
    "glob": "7.1.2",
    "greenkeeper-lockfile": "1.14.0",
    "hash-files": "1.1.1",
    "html-minifier": "3.5.15",
    "husky": "0.14.3",
    "is-reachable": "2.4.0",
    "jest": "22.4.2",
    "jest-junit-reporter": "1.1.0",
    "jest-preset-angular": "5.2.1",
    "jsdom": "11.6.2",
    "last-release-git": "0.0.3",
    "mkdirp": "0.5.1",
    "ng2-fused": "0.5.1",
    "node-run-cmd": "1.0.1",
    "node-sass": "4.8.3",
    "opn": "5.3.0",
    "semantic-release": "15.1.7",
    "source-map-explorer": "1.5.0",
    "string-hash": "1.1.3",
    "superagent": "3.8.2",
    "svg2png": "4.1.1",
    "ts-jest": "22.4.3",
    "ts-node": "5.0.1",
    "tslint": "5.9.1",
    "tslint-immutable": "4.5.2",
    "typescript": "2.7.2",
    "uglify-es": "3.3.9"
  },
  "dependencies": {
    "@angular/animations": "6.0.0-beta.7",
    "@angular/cdk": "5.1.1",
    "@angular/common": "6.0.0-beta.7",
    "@angular/compiler": "6.0.0-beta.7",
    "@angular/compiler-cli": "6.0.0-beta.7",
    "@angular/core": "6.0.0-beta.7",
    "@angular/flex-layout": "2.0.0-beta.12",
    "@angular/forms": "6.0.0-beta.7",
    "@angular/http": "6.0.0-beta.7",
    "@angular/material": "5.1.1",
    "@angular/platform-browser": "6.0.0-beta.7",
    "@angular/platform-browser-dynamic": "6.0.0-beta.7",
    "@angular/platform-server": "6.0.0-beta.7",
    "@angular/router": "6.0.0-beta.7",
    "@angular/service-worker": "6.0.0-beta.7",
    "@expo/bunyan": "1.8.10",
    "@nguniversal/common": "5.0.0",
    "@nguniversal/express-engine": "5.0.0",
    "@ngx-meta/core": "5.0.0",
    "angular2-jwt": "0.2.3",
    "angularfire2": "5.0.0-rc.6",
    "angulartics2": "5.1.2",
    "body-parser": "1.18.2",
    "bunyan-middleware": "0.8.0",
    "clean-css": "4.1.11",
    "compressible": "2.0.13",
    "compression": "1.7.2",
    "cookie-parser": "1.4.3",
    "core-js": "2.5.5",
    "cors": "2.8.4",
    "dotenv": "5.0.1",
    "express": "4.16.3",
    "express-minify-html": "0.12.0",
    "express-urlrewrite": "1.2.0",
    "firebase": "4.11.0",
    "firebase-admin": "5.10.0",
    "getos": "3.1.0",
    "hammerjs": "2.0.8",
    "js-cookie": "2.2.0",
    "markdown-to-html-pipe": "1.2.4",
    "ms": "2.1.1",
    "nightmare": "3.0.0",
    "object-hash": "1.3.0",
    "quill": "1.3.6",
    "reflect-metadata": "0.1.12",
    "request": "2.85.0",
    "routing-controllers": "0.7.7",
    "rxjs": "5.5.10",
    "serve-favicon": "2.4.5",
    "shrink-ray": "0.1.3",
    "sitemap-generator": "6.0.0",
    "stacktrace-js": "2.0.0",
    "supertest": "3.0.0",
    "swagger-jsdoc": "1.9.7",
    "swagger-ui-express": "3.0.8",
    "systemjs": "0.21.3",
    "ts-node": "5.0.1",
    "tsickle": "0.27.5",
    "typedi": "0.7.1",
    "url-parse": "1.3.0",
    "ws": "5.1.1",
    "xhr2": "0.1.4",
    "yargs": "11.0.0",
    "zone.js": "0.8.20"
  },
  "engines": {
    "node": "= 9.4.0",
    "npm": "= 5.6.0"
  },
  "release": {
    "branch": "master",
    "verifyConditions": "condition-circle",
    "getLastRelease": "last-release-git"
  },
  "jest": {
    "preset": "jest-preset-angular",
    "moduleNameMapper": {
      "./client/operators": "<rootDir>/src/client/operators.ts"
    },
    "setupTestFrameworkScriptFile": "./tools/test/jest.setup.ts",
    "testResultsProcessor": "./node_modules/jest-junit-reporter",
    "collectCoverageFrom": [
      "src/client/app/**/*(*.service|*.component|*.pipe|*.directive|*.module).{ts,html}",
      "!src/client/app/shared/shared.module.ts",
      "src/server/**/**.{ts}"
    ],
    "globals": {
      "__TRANSFORM_HTML__": true,
      "__process_env__": {},
      "ts-jest": {
        "tsConfigFile": "tsconfig.json"
      }
    }
  }
}


================================================
FILE: src/client/app/__snapshots__/app.component.spec.ts.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`App component should build without a problem 1`] = `
<div
  id="root0"
  ng-version="6.0.0-beta.7"
>
  <pm-app>
    <pm-navbar>
      <nav
        class="mat-elevation-z6"
      >
        <button
          angulartics2on="click"
          angularticsaction="ToggleSideMenu"
          class="mat-icon-button"
          id="toggle-menu-button"
          mat-icon-button=""
        >
          <span
            class="mat-button-wrapper"
          >
            <mat-icon
              aria-hidden="true"
              class="mat-icon"
              fonticon="fa-bars"
              fontset="fa"
              role="img"
            />
          </span>
          <div
            class="mat-button-ripple mat-ripple"
            matripple=""
          />
          <div
            class="mat-button-focus-overlay"
          />
        </button>
        <a
          class="nav-button mat-button"
          mat-button=""
          routerlink=""
        >
          <span
            class="mat-button-wrapper"
          >
            FB-ANGULAR-UNIVERSAL-STARTER
          </span>
          <div
            class="mat-button-ripple mat-ripple"
            matripple=""
          />
          <div
            class="mat-button-focus-overlay"
          />
        </a>
        <div
          class="flex-spacer"
        />
        
        <a
          class="nav-button mat-button"
          href="https://www.angularuniversal.com"
          mat-button=""
        >
          <span
            class="mat-button-wrapper"
          >
            Consulting
          </span>
          <div
            class="mat-button-ripple mat-ripple"
            matripple=""
          />
          <div
            class="mat-button-focus-overlay"
          />
        </a>
        <a
          class="nav-button mat-button"
          href="/api-docs"
          mat-button=""
        >
          <span
            class="mat-button-wrapper"
          >
            API
          </span>
          <div
            class="mat-button-ripple mat-ripple"
            matripple=""
          />
          <div
            class="mat-button-focus-overlay"
          />
        </a>
        <button
          aria-haspopup="true"
          class="mat-icon-button"
          id="user-menu-btn"
          mat-icon-button=""
        >
          <span
            class="mat-button-wrapper"
          >
            <mat-icon
              aria-hidden="true"
              class="mat-icon"
              fonticon="fa-user-circle-o"
              fontset="fa"
              role="img"
            />
          </span>
          <div
            class="mat-button-ripple mat-ripple"
            matripple=""
          />
          <div
            class="mat-button-focus-overlay"
          />
        </button>
        <mat-menu
          class="ng-tns-c8-1"
        >
          
        </mat-menu>
      </nav>
    </pm-navbar>
    <mat-sidenav-container
      class="sidenav-container mat-drawer-container mat-sidenav-container"
      exclude="#toggle-menu-button"
    >
      <div
        class="mat-drawer-backdrop"
      />
      <mat-sidenav
        class="sidenav mat-elevation-z6 mat-drawer mat-sidenav ng-tns-c1-0 ng-trigger ng-trigger-transform"
        tabindex="-1"
      >
        <mat-list
          class="mat-list"
        >
          <div
            id="menu-top"
          >
            <h3
              class="mat-subheader"
              matsubheader=""
            >
              Pages
            </h3>
            <mat-slide-toggle
              class="mat-slide-toggle mat-accent"
            >
              <label
                class="mat-slide-toggle-label"
              >
                <div
                  class="mat-slide-toggle-bar"
                >
                  <input
                    class="mat-slide-toggle-input cdk-visually-hidden"
                    type="checkbox"
                  />
                  <div
                    class="mat-slide-toggle-thumb-container"
                  >
                    <div
                      class="mat-slide-toggle-thumb"
                    />
                    <div
                      class="mat-slide-toggle-ripple mat-ripple"
                      mat-ripple=""
                    />
                  </div>
                </div>
                <span
                  class="mat-slide-toggle-content"
                />
              </label>
            </mat-slide-toggle>
          </div>
          <mat-list-item
            class="mat-list-item"
          >
            <div
              class="mat-list-item-content"
            >
              <div
                class="mat-list-item-ripple mat-ripple"
                mat-ripple=""
              />
              <div
                class="mat-list-text"
              >
                <a
                  class="mat-button mat-line"
                  mat-button=""
                  matline=""
                  routerlink="/"
                >
                  <span
                    class="mat-button-wrapper"
                  >
                    Home
                  </span>
                  <div
                    class="mat-button-ripple mat-ripple"
                    matripple=""
                  />
                  <div
                    class="mat-button-focus-overlay"
                  />
                </a>
                <a
                  class="mat-button mat-line"
                  mat-button=""
                  matline=""
                  routerlink="changelog"
                >
                  <span
                    class="mat-button-wrapper"
                  >
                    Changelog
                  </span>
                  <div
                    class="mat-button-ripple mat-ripple"
                    matripple=""
                  />
                  <div
                    class="mat-button-focus-overlay"
                  />
                </a>
                <a
                  class="mat-button mat-line"
                  href="/sitemap.xml"
                  mat-button=""
                  matline=""
                >
                  <span
                    class="mat-button-wrapper"
                  >
                    Sitemap
                  </span>
                  <div
                    class="mat-button-ripple mat-ripple"
                    matripple=""
                  />
                  <div
                    class="mat-button-focus-overlay"
                  />
                </a>
                <a
                  class="mat-button mat-line"
                  href="/robots.txt"
                  mat-button=""
                  matline=""
                >
                  <span
                    class="mat-button-wrapper"
                  >
                    Robots
                  </span>
                  <div
                    class="mat-button-ripple mat-ripple"
                    matripple=""
                  />
                  <div
                    class="mat-button-focus-overlay"
                  />
                </a>
                <a
                  class="mat-button mat-line"
                  href="https://www.angularuniversal.com"
                  mat-button=""
                  matline=""
                >
                  <span
                    class="mat-button-wrapper"
                  >
                    Consulting
                  </span>
                  <div
                    class="mat-button-ripple mat-ripple"
                    matripple=""
                  />
                  <div
                    class="mat-button-focus-overlay"
                  />
                </a>
              </div>
            </div>
          </mat-list-item>
          <mat-divider
            class="mat-divider"
            role="separator"
          />
          <h3
            class="mat-subheader"
            matsubheader=""
          >
            Boss Area
          </h3>
          <mat-list-item
            class="mat-list-item"
          >
            <div
              class="mat-list-item-content"
            >
              <div
                class="mat-list-item-ripple mat-ripple"
                mat-ripple=""
              />
              <div
                class="mat-list-text"
              >
                <a
                  class="mat-button mat-line"
                  mat-button=""
                  matline=""
                  routerlink="pages"
                >
                  <span
                    class="mat-button-wrapper"
                  >
                    Pages
                  </span>
                  <div
                    class="mat-button-ripple mat-ripple"
                    matripple=""
                  />
                  <div
                    class="mat-button-focus-overlay"
                  />
                </a>
                <a
                  class="mat-button mat-line"
                  mat-button=""
                  matline=""
                >
                  <span
                    class="mat-button-wrapper"
                  >
                    Assets
                  </span>
                  <div
                    class="mat-button-ripple mat-ripple"
                    matripple=""
                  />
                  <div
                    class="mat-button-focus-overlay"
                  />
                </a>
                <a
                  class="mat-button mat-line"
                  mat-button=""
                  matline=""
                  routerlink="users"
                >
                  <span
                    class="mat-button-wrapper"
                  >
                    Users
                  </span>
                  <div
                    class="mat-button-ripple mat-ripple"
                    matripple=""
                  />
                  <div
                    class="mat-button-focus-overlay"
                  />
                </a>
                <a
                  class="mat-button mat-line"
                  mat-button=""
                  matline=""
                  routerlink="admin"
                >
                  <span
                    class="mat-button-wrapper"
                  >
                    Admin
                  </span>
                  <div
                    class="mat-button-ripple mat-ripple"
                    matripple=""
                  />
                  <div
                    class="mat-button-focus-overlay"
                  />
                </a>
              </div>
            </div>
          </mat-list-item>
        </mat-list>
      </mat-sidenav>
      
    </mat-sidenav-container>
  </pm-app>
</div>
`;


================================================
FILE: src/client/app/about/__snapshots__/about.component.spec.ts.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`AboutComponent should compile 1`] = `
<test-component>
  <pm-about>
    <h1>
      About
    </h1>
    <p>
      An Angular starter with all the tools necessary to create server rendered Angular applications.
    </p>
    <form
      class="ng-untouched ng-pristine ng-invalid"
      ng-reflect-form="[object Object]"
      novalidate=""
    >
      <mat-form-field
        class="mat-input-container mat-form-field ng-tns-c0-0 mat-form-field-type-mat-input mat-form-field-can-float mat-form-field-hide-placeholder mat-primary ng-untouched ng-pristine ng-invalid"
      >
        <div
          class="mat-input-wrapper mat-form-field-wrapper"
        >
          <div
            class="mat-input-flex mat-form-field-flex"
          >
            
            <div
              class="mat-input-infix mat-form-field-infix"
            >
              <input
                aria-invalid="false"
                aria-required="false"
                class="mat-input-element mat-form-field-autofill-control ng-untouched ng-pristine ng-invalid"
                formcontrolname="title"
                id="mat-input-0"
                matinput=""
                ng-reflect-name="title"
                ng-reflect-placeholder="Title"
                placeholder="Title"
              />
              <span
                class="mat-form-field-label-wrapper mat-input-placeholder-wrapper mat-form-field-placeholder-wrapper"
              >
                
                <label
                  aria-owns="mat-input-0"
                  class="mat-form-field-label mat-input-placeholder mat-form-field-placeholder ng-tns-c0-0 mat-empty mat-form-field-empty ng-star-inserted"
                  for="mat-input-0"
                  ng-reflect-ng-switch="false"
                >
                  
                  
                  Title
                  
                  
                </label>
              </span>
            </div>
            
          </div>
          <div
            class="mat-input-underline mat-form-field-underline"
          >
            <span
              class="mat-input-ripple mat-form-field-ripple"
            />
          </div>
          <div
            class="mat-input-subscript-wrapper mat-form-field-subscript-wrapper"
            ng-reflect-ng-switch="hint"
          >
            
            
            <div
              class="mat-input-hint-wrapper mat-form-field-hint-wrapper ng-tns-c0-0 ng-trigger ng-trigger-transitionMessages ng-star-inserted"
              style="opacity: 1;"
            >
              
              <div
                class="mat-input-hint-spacer mat-form-field-hint-spacer"
              />
            </div>
          </div>
        </div>
      </mat-form-field>
      <mat-form-field
        class="mat-input-container mat-form-field ng-tns-c0-1 mat-form-field-type-mat-input mat-form-field-can-float mat-form-field-hide-placeholder mat-primary ng-untouched ng-pristine ng-invalid"
      >
        <div
          class="mat-input-wrapper mat-form-field-wrapper"
        >
          <div
            class="mat-input-flex mat-form-field-flex"
          >
            
            <div
              class="mat-input-infix mat-form-field-infix"
            >
              <textarea
                aria-invalid="false"
                aria-required="false"
                class="mat-input-element mat-form-field-autofill-control ng-untouched ng-pristine ng-invalid"
                formcontrolname="html"
                id="mat-input-1"
                matinput=""
                ng-reflect-name="html"
                ng-reflect-placeholder="html"
                placeholder="html"
              />
              <span
                class="mat-form-field-label-wrapper mat-input-placeholder-wrapper mat-form-field-placeholder-wrapper"
              >
                
                <label
                  aria-owns="mat-input-1"
                  class="mat-form-field-label mat-input-placeholder mat-form-field-placeholder ng-tns-c0-1 mat-empty mat-form-field-empty ng-star-inserted"
                  for="mat-input-1"
                  ng-reflect-ng-switch="false"
                >
                  
                  
                  html
                  
                  
                </label>
              </span>
            </div>
            
          </div>
          <div
            class="mat-input-underline mat-form-field-underline"
          >
            <span
              class="mat-input-ripple mat-form-field-ripple"
            />
          </div>
          <div
            class="mat-input-subscript-wrapper mat-form-field-subscript-wrapper"
            ng-reflect-ng-switch="hint"
          >
            
            
            <div
              class="mat-input-hint-wrapper mat-form-field-hint-wrapper ng-tns-c0-1 ng-trigger ng-trigger-transitionMessages ng-star-inserted"
              style="opacity: 1;"
            >
              
              <div
                class="mat-input-hint-spacer mat-form-field-hint-spacer"
              />
            </div>
          </div>
        </div>
      </mat-form-field>
      <button
        class="mat-raised-button mat-primary"
        color="primary"
        disabled=""
        mat-raised-button=""
        ng-reflect-color="primary"
        ng-reflect-disabled="true"
      >
        <span
          class="mat-button-wrapper"
        >
           Post 
        </span>
        <div
          class="mat-button-ripple mat-ripple"
          matripple=""
          ng-reflect-centered="false"
          ng-reflect-disabled="true"
          ng-reflect-trigger="[object HTMLButtonElement]"
        />
        <div
          class="mat-button-focus-overlay"
        />
      </button>
      <button
        class="mat-raised-button mat-warn"
        color="warn"
        mat-raised-button=""
        ng-reflect-color="warn"
      >
        <span
          class="mat-button-wrapper"
        >
           Delete All Posts 
        </span>
        <div
          class="mat-button-ripple mat-ripple"
          matripple=""
          ng-reflect-centered="false"
          ng-reflect-disabled="false"
          ng-reflect-trigger="[object HTMLButtonElement]"
        />
        <div
          class="mat-button-focus-overlay"
        />
      </button>
    </form>
    
  </pm-about>
</test-component>
`;


================================================
FILE: src/client/app/about/about-routing.module.ts
================================================
import { AboutComponent } from './about.component'
import { NgModule } from '@angular/core'
import { RouterModule } from '@angular/router'
import { MetaGuard } from '@ngx-meta/core'

@NgModule({
  imports: [
    RouterModule.forChild([
      {
        path: '',
        component: AboutComponent,
        canActivate: [MetaGuard],
        data: {
          meta: {
            title: 'i18n.about.title',
            description: 'i18n.about.description'
          },
          response: {
            cache: {
              directive: 'no-cache'
            }
          }
        }
      }
    ])
  ],
  exports: [RouterModule]
})
export class AboutRoutingModule { }


================================================
FILE: src/client/app/about/about.component.e2e-spec.ts
================================================
import { baseUrl, browser } from '../../../../tools/test/jest.e2e-setup'

describe('About Page', () => {
  it('should have title', async () => {
    expect.assertions(1)
    const page = browser.goto(`${baseUrl}/about`)

    const text = await page.evaluate(() => document.title)

    expect(text).toContain('About - Fusebox Angular Universal Starter')
  })
})


================================================
FILE: src/client/app/about/about.component.html
================================================
<h1>About</h1>
<p>An Angular starter with all the tools necessary to create server rendered Angular applications.</p>

<form [formGroup]="form" novalidate>
  <mat-form-field>
    <input matInput placeholder="Title" formControlName="title">
  </mat-form-field>
  <mat-form-field>
    <textarea matInput placeholder="html" formControlName="html"></textarea>
  </mat-form-field>
  <button mat-raised-button color="primary" (click)="create()" [disabled]="!form.valid">
    Post
  </button>
  <button mat-raised-button color="warn" (click)="removeAll()">
    Delete All Posts
  </button>
</form>

<mat-card *ngFor="let post of posts$ | async; trackBy: trackByPost">
  <h4>{{ post.title }}</h4>
  <div [innerHTML]="post.html"></div>
</mat-card>

================================================
FILE: src/client/app/about/about.component.scss
================================================


================================================
FILE: src/client/app/about/about.component.spec.ts
================================================
import { AboutComponent } from './about.component'
import { async, ComponentFixture, TestBed } from '@angular/core/testing'
import { Component } from '@angular/core'
import { AboutModule } from './about.module'
import { AppTestingModule } from '../../../testing/app-testing.module'

@Component({
  selector: 'test-component',
  template: '<pm-about></pm-about>'
})
class TestComponent {}

describe(AboutComponent.name, () => {
  let fixture: ComponentFixture<TestComponent>

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [AppTestingModule.forRoot(), AboutModule],
      declarations: [TestComponent]
    }).compileComponents()
  }))

  beforeEach(async(() => {
    fixture = TestBed.createComponent(TestComponent)
  }))

  afterEach(async(() => {
    TestBed.resetTestingModule()
  }))

  it('should compile', async(() => {
    fixture.detectChanges()
    expect(fixture.nativeElement).toBeDefined()
    expect(fixture).toMatchSnapshot()
  }))
})


================================================
FILE: src/client/app/about/about.component.ts
================================================
import { PlatformService } from './../shared/services/platform.service'
import { ChangeDetectionStrategy, Component } from '@angular/core'
import { FirebaseDatabaseService } from '../shared/services/firebase-database.service'
import { FormControl, FormGroup, Validators } from '@angular/forms'

@Component({
  selector: 'pm-about',
  templateUrl: './about.component.html',
  styleUrls: ['./about.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AboutComponent {
  readonly posts$ = this.db.getList<{ readonly title: string, readonly html: string }>('posts').map(a => {
    return a.map((b: any) => {
      return {
        title: b.title || '',
        html: b.html || ''
      }
    })
  })

  public readonly form = new FormGroup({
    title: new FormControl('', [
      Validators.required
    ]),
    html: new FormControl('', [
      Validators.required
    ])
  })

  constructor(private db: FirebaseDatabaseService, ps: PlatformService) { }

  create() {
    this.db.getListRef('posts').push(this.form.value)
  }

  removeAll() {
    this.db.getObjectRef('posts').remove()
  }

  trackByPost(index: number, item: any) {
    return index
  }
}


================================================
FILE: src/client/app/about/about.module.ts
================================================
import { AboutRoutingModule } from './about-routing.module'
import { AboutComponent } from './about.component'
import { NgModule } from '@angular/core'
import { SharedModule } from '../shared/shared.module'

@NgModule({
  imports: [AboutRoutingModule, SharedModule],
  declarations: [AboutComponent],
  exports: [AboutComponent]
})
export class AboutModule { }


================================================
FILE: src/client/app/account/account-routing.module.ts
================================================
import { AccountComponent } from './account.component'
import { NgModule } from '@angular/core'
import { RouterModule } from '@angular/router'
import { MetaGuard } from '@ngx-meta/core'
import { LoginGuard } from '../shared/services/guard-login.service'

@NgModule({
  imports: [
    RouterModule.forChild([
      {
        path: '',
        component: AccountComponent,
        canActivate: [MetaGuard, LoginGuard],
        data: {
          meta: {
            title: 'i18n.account.title',
            description: 'i18n.account.description'
          },
          response: {
            cache: {
              directive: 'private'
            }
          }
        }
      }
    ])
  ],
  exports: [RouterModule]
})
export class AccountRoutingModule { }


================================================
FILE: src/client/app/account/account.component.html
================================================
<div *ngIf="user$ | async as user" class="flex-center">
  <h2>{{ user.displayName }}</h2>
  <a class="flex-center">
    <img *ngIf="user.photoURL" [src]="user.photoURL" class="avatar" angulartics2On="mouseover" angularticsAction="HoveredOverAccountProfileImage">
    <a mat-button>Update Photo</a>
  </a>
  <mat-accordion class="headers-align">
    <mat-expansion-panel #profilePanel>
      <mat-expansion-panel-header>
        <mat-panel-title>
          Profile Info
        </mat-panel-title>
        <mat-panel-description>
          name, email, and phone
        </mat-panel-description>
      </mat-expansion-panel-header>
      <form [formGroup]="detailForm" (ngSubmit)="updateDetail()">
        <mat-form-field>
          <input matInput formControlName="displayName" [value]="user.displayName" type="text" placeholder="Name" angulartics2On="focus"
            angularticsAction="FocusedOnAccountDisplayNameInput">
        </mat-form-field>
        <mat-form-field>
          <input matInput formControlName="email" type="email" [value]="user.email" placeholder="Email" angulartics2On="focus" angularticsAction="FocusedOnAccountEmailInput">
          <!-- <mat-icon matSuffix [matTooltip]="user.emailTooltip" [color]="user.emailColor" fontSet="fa" [fontIcon]="user.emailIcon" angulartics2On="mouseover"
                angularticsAction="HoveredOverAccountEmailCheckmarkIcon"></mat-icon> -->
        </mat-form-field>
        <mat-form-field>
          <input matInput formControlName="phoneNumber" type="text" [value]="user.phone || ''" placeholder="Phone" angulartics2On="focus"
            angularticsAction="FocusedOnAccountPhonenumberInput">
        </mat-form-field>
        <button mat-raised-button type="submit"
        [disabled]="!detailForm.dirty"
        color="primary" id="update-btn" angulartics2On="input" angulartics2On="click" angularticsAction="ClickUpdateProfile">Save Changes</button>
      </form>
    </mat-expansion-panel>
    <mat-expansion-panel disabled=true #socialPanel>
      <mat-expansion-panel-header>
        <mat-panel-title>
          Social Login
        </mat-panel-title>
        <mat-panel-description>
          manage your accounts
        </mat-panel-description>
      </mat-expansion-panel-header>
      <section class="demo-section">
        <button mat-button pmSocialButton="facebook">
          <div class="social-spacer">
            <mat-icon fontSet="fa" fontIcon="fa-facebook-official"></mat-icon>
            <span>Link Facebook</span>
          </div>
        </button>
        <button mat-button pmSocialButton="google">
          <div class="social-spacer">
            <mat-icon fontSet="fa" fontIcon="fa-google"></mat-icon>
            <span>Link Google</span>
          </div>
        </button>
        <button mat-button pmSocialButton="twitter">
          <div class="social-spacer">
            <mat-icon fontSet="fa" fontIcon="fa-twitter"></mat-icon>
            <span>Link Twitter</span>
          </div>
        </button>
        <button mat-button pmSocialButton="github">
          <div class="social-spacer">
            <mat-icon fontSet="fa" fontIcon="fa-github"></mat-icon>
            <span>Link Github</span>
          </div>
        </button>
      </section>
    </mat-expansion-panel>
    <mat-expansion-panel #passwordPanel>
      <mat-error *ngIf="passwordError">
        {{ passwordError }}
      </mat-error>
      <mat-expansion-panel-header>
        <mat-panel-title>
          Password
        </mat-panel-title>
        <mat-panel-description>
          update your password
        </mat-panel-description>
      </mat-expansion-panel-header>
      <form [formGroup]="passForm" (ngSubmit)="updatePassword()">
        <mat-form-field>
          <input matInput formControlName="currentPassword" type="password" placeholder="Current Password" angulartics2On="focus" angularticsAction="FocusedOnAccountPasswordChangeInput">
          <mat-error *ngIf="passForm.controls.currentPassword.hasError('required')">
            <strong>required</strong>
          </mat-error>
        </mat-form-field>
        <mat-form-field>
          <input matInput formControlName="newPassword" type="password" placeholder="New Password" angulartics2On="focus" angularticsAction="FocusedOnAccountPasswordChangeInput">
          <mat-error *ngIf="passForm.controls.newPassword.hasError('required')">
            <strong>required</strong>
          </mat-error>
        </mat-form-field>
        <button mat-raised-button [disabled]="passForm.invalid" type="submit" color="primary" id="update-pass-btn" angulartics2On="input"
          angulartics2On="click" angularticsAction="ClickUpdateProfile">Save Changes</button>
      </form>
    </mat-expansion-panel>
  </mat-accordion>
</div>


================================================
FILE: src/client/app/account/account.component.scss
================================================
:host {
  .flex-center {
    display: flex;
    flex-direction: column;
    align-items: center;
    img {
      cursor: pointer;
    }
  }
  mat-accordion {
    margin-top: 1em;
  }
  form {
    display: flex;
    flex-direction: column;
  }
  #update-btn {
    width: 100%;
    &:hover {
      cursor: pointer;
    }
  }
  .headers-align .mat-expansion-panel-header-title,
  .headers-align .mat-expansion-panel-header-description {
    flex-basis: 0;
  }
  .headers-align .mat-expansion-panel-header-description {
    justify-content: space-between;
    align-items: center;
  }
  .avatar {
    height: 95px;
    width: 95px;
  }
  .social-spacer {
    display: flex;
    flex-direction: row;
    align-items: baseline;
  }
}

================================================
FILE: src/client/app/account/account.component.ts
================================================
import { AuthService } from './../shared/services/auth.service'
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostBinding, ViewChild } from '@angular/core'
import { PlatformService } from './../shared/services/platform.service'
import { MatExpansionPanel, MatSnackBar } from '@angular/material'
import { FormControl, FormGroup, Validators } from '@angular/forms'

@Component({
  selector: 'pm-account',
  templateUrl: './account.component.html',
  styleUrls: ['./account.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AccountComponent {
  @HostBinding('class.card-float-container') readonly containerClass = true
  @ViewChild('passwordPanel') readonly passwordPanel: MatExpansionPanel
  @ViewChild('profilePanel') readonly profilePanel: MatExpansionPanel
  @ViewChild('socialPanel') readonly socialPanel: MatExpansionPanel
  // private DEBOUNCE_TIME = 750

  public readonly detailForm = new FormGroup({
    displayName: new FormControl('', [
      Validators.required
    ]),
    email: new FormControl('', [
      Validators.required
    ]),
    phoneNumber: new FormControl('', [
      Validators.required
    ])
  })

  public readonly passForm = new FormGroup({
    currentPassword: new FormControl('', [
      Validators.required
    ]),
    newPassword: new FormControl('', [
      Validators.required
    ])
  })
  public readonly user$ = this.auth.user$
  // private userSource = new Subject()
  // private photoURL$ = new Subject<string>()
  // public us$ = this.afAuth.idToken
  // public user$ = this.userSource
  //   .startWith(this.ts.get(AUTH_TS_KEY, {}))
  //   .map(a => {
  //     const emailVerified = (a as any).emailVerified
  //     return {
  //       ...a,
  //       emailColor: emailVerified ? 'primary' : 'accent',
  //       emailIcon: emailVerified ? 'fa-check-circle' : 'fa-question-circle',
  //       emailTooltip: emailVerified ? 'confirmed email' : 'unconfirmed email'
  //     }
  //   })

  constructor(private auth: AuthService, private snackBar: MatSnackBar, ps: PlatformService, private cd: ChangeDetectorRef) {
    // if (ps.isBrowser) {
    //   Observable.combineLatest(
    //     this.us$,
    //     this.detailForm.controls['displayName'].valueChanges.debounceTime(this.DEBOUNCE_TIME).distinctUntilChanged(),
    //     this.photoURL$.startWith(undefined).debounceTime(this.DEBOUNCE_TIME).distinctUntilChanged(),
    //     (user, displayName, photoURL) => {
    //       return {
    //         user,
    //         update: {
    //           displayName: displayName ? displayName : user.displayName,
    //           photoURL: photoURL ? photoURL : user.photoURL
    //         }
    //       }
    //     })
    //     .flatMap(res => res.user.updateProfile(res.update))
    //     .do(() => this.openSnackBar('name updated'))
    //     .subscribe()

    //   Observable.combineLatest(
    //     this.us$,
    //     this.detailForm.controls['email'].valueChanges.debounceTime(2500).distinctUntilChanged(),
    //     (user, email) => {

    //       return {
    //         user,
    //         email
    //       }
    //     })
    //     .flatMap(res => res.user.updateEmail(res.email))
    //     .do(() => this.openSnackBar('email updated'))
    //     .subscribe(a => undefined, err => {
    //       if (err.code === '"auth/requires-recent-login"') {
    //         console.log('should re-auth')
    //       }
    //     })

    //   // this.detailForm.controls['displayName'].valueChanges.debounceTime(500).subscribe(name => {
    //   // })
    //   // this.detailForm.controls['phoneNumber'].valueChanges.debounceTime(500).subscribe(console.log)
    // }
  }

  openSnackBar(message: string, action = 'dismiss') {
    this.snackBar.open(message, action, {
      duration: 2000,
      horizontalPosition: 'right',
      verticalPosition: 'top'
    })
  }

  updateDetail() {
    this.auth
      .updateProfile(this.detailForm.value.displayName)
      .take(1)
      .subscribe(() => {
        this.openSnackBar('name updated')
      }, err => {
        console.log(err)
      })
  }

  updatePassword() {
    const permuteError = (err?: string) => {
      this.passwordError = err
      this.cd.markForCheck()
    }

    this.auth
      .updateEmailPassword(this.passForm.value.currentPassword, this.passForm.value.newPassword)
      .take(1)
      .subscribe(res => {
        permuteError()
        this.passForm.reset()
        // this.passwordPanel..close()
        this.openSnackBar('password updated')
      }, err => {
        permuteError(err.message)
      })
  }

  passwordError: string | undefined
}


================================================
FILE: src/client/app/account/account.module.ts
================================================
import { AccountRoutingModule } from './account-routing.module'
import { AccountComponent } from './account.component'
import { NgModule } from '@angular/core'
import { SharedModule } from '../shared/shared.module'

@NgModule({
  imports: [AccountRoutingModule, SharedModule],
  declarations: [AccountComponent],
  exports: [AccountComponent]
})
export class AccountModule { }


================================================
FILE: src/client/app/admin/__snapshots__/admin.component.spec.ts.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`AdminComponent should match snapshot 1`] = `
<pm-admin>
  <h1>
    Admin
  </h1><p>
    Your Admin module is routed here
  </p>
</pm-admin>
`;


================================================
FILE: src/client/app/admin/admin-routing.module.ts
================================================
import { AdminComponent } from './admin.component'
import { NgModule } from '@angular/core'
import { RouterModule } from '@angular/router'
import { MetaGuard } from '@ngx-meta/core'

@NgModule({
  imports: [
    RouterModule.forChild([
      {
        path: '',
        component: AdminComponent,
        canActivate: [MetaGuard],
        data: {
          meta: {
            title: 'i18n.admin.title',
            description: 'i18n.admin.description'
          },
          response: {
            cache: {
              directive: 'private'
            }
          }
        }
      }
    ])
  ],
  exports: [RouterModule]
})
export class AdminRoutingModule { }


================================================
FILE: src/client/app/admin/admin.component.e2e-spec.ts
================================================
import { baseUrl, browser } from '../../../../tools/test/jest.e2e-setup'

describe('Admin Page', () => {
  it('should have title', async () => {
    expect.assertions(1)
    const page = browser.goto(`${baseUrl}/admin`)

    const text = await page.evaluate(() => document.title)

    expect(text).toEqual('Admin - Fusebox Angular Universal Starter')
  })
})


================================================
FILE: src/client/app/admin/admin.component.html
================================================
<h1>Admin</h1>
<p>Your Admin module is routed here</p>

================================================
FILE: src/client/app/admin/admin.component.scss
================================================


================================================
FILE: src/client/app/admin/admin.component.spec.ts
================================================
import { AdminComponent } from './admin.component'
import { async, ComponentFixture, TestBed } from '@angular/core/testing'
import { Component } from '@angular/core'
import { AdminModule } from './admin.module'
import { AppTestingModule } from '../../../testing/app-testing.module'

describe(AdminComponent.name, () => {
  let fixture: ComponentFixture<AdminComponent>

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [AppTestingModule.forRoot(), AdminModule],
      declarations: [TestComponent]
    }).compileComponents()
  }))

  beforeEach(async(() => {
    fixture = TestBed.createComponent(AdminComponent)
  }))

  afterEach(async(() => {
    TestBed.resetTestingModule()
  }))

  it('should match snapshot', async(() => {
    expect(fixture).toMatchSnapshot()
  }))

  it('should compile', async(() => {
    expect(fixture.nativeElement).toBeDefined()
  }))
})

@Component({
  selector: 'test-component',
  template: '<pm-admin></pm-admin>'
})
class TestComponent {}


================================================
FILE: src/client/app/admin/admin.component.ts
================================================
import { ChangeDetectionStrategy, Component } from '@angular/core'

@Component({
  selector: 'pm-admin',
  templateUrl: './admin.component.html',
  styleUrls: ['./admin.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AdminComponent {
}


================================================
FILE: src/client/app/admin/admin.module.ts
================================================
import { AdminRoutingModule } from './admin-routing.module'
import { AdminComponent } from './admin.component'
import { NgModule } from '@angular/core'
import { SharedModule } from '../shared/shared.module'

@NgModule({
  imports: [AdminRoutingModule, SharedModule],
  declarations: [AdminComponent],
  exports: [AdminComponent]
})
export class AdminModule { }


================================================
FILE: src/client/app/app-routing.module.ts
================================================
import { NgModule } from '@angular/core'
import { RouterModule, Routes } from '@angular/router'

export const routes: Routes = [
  { path: '', loadChildren: async () => (await import('./home/home.module')).HomeModule },
  { path: 'unauthorized', loadChildren: async () => (await import('./unauthorized/unauthorized.module')).UnauthorizedModule },
  { path: 'about', loadChildren: async () => (await import('./about/about.module')).AboutModule },
  { path: 'account', loadChildren: async () => (await import('./account/account.module')).AccountModule },
  { path: 'login', loadChildren: async () => (await import('./login/login.module')).LoginModule },
  { path: 'logout', loadChildren: async () => (await import('./logout/logout.module')).LogoutModule },
  { path: 'signup', loadChildren: async () => (await import('./signup/signup.module')).SignupModule },
  { path: 'admin', loadChildren: async () => (await import('./admin/admin.module')).AdminModule },
  { path: 'changelog', loadChildren: async () => (await import('./changelog/changelog.module')).ChangelogModule },
  { path: 'dashboard', loadChildren: async () => (await import('./dashboard/dashboard.module')).DashboardModule },
  { path: 'pages', loadChildren: async () => (await import('./pages/pages.module')).PagesModule },
  { path: 'users', loadChildren: async () => (await import('./users/users.module')).UsersModule }
]

@NgModule({
  imports: [
    RouterModule.forRoot(routes, { initialNavigation: 'enabled' })
  ],
  exports: [RouterModule]
})
export class AppRoutingModule { }


================================================
FILE: src/client/app/app.browser.module.ts
================================================
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
import { BrowserModule, BrowserTransferStateModule, TransferState } from '@angular/platform-browser'
import { AppModule, REQ_KEY } from './app.module'
import { NgModule } from '@angular/core'
import { AppComponent } from './app.component'
import { REQUEST } from '@nguniversal/express-engine/tokens'
import 'hammerjs'

export function getRequest(transferState: TransferState): any {
  return transferState.get<any>(REQ_KEY, {})
}

@NgModule({
  bootstrap: [AppComponent],
  imports: [
    BrowserModule.withServerTransition({ appId: 'pm-app' }),
    BrowserTransferStateModule,
    BrowserAnimationsModule,
    // ServiceWorkerModule.register('/ngsw-worker.js'),
    AppModule
  ],
  providers: [
    {
      provide: REQUEST,
      useFactory: getRequest,
      deps: [TransferState]
    }
  ]
})
export class AppBrowserModule { }


================================================
FILE: src/client/app/app.component.html
================================================
<pm-navbar (menuIconClick)="sidenav.toggle()" [user]="user$ | async"></pm-navbar>
<mat-sidenav-container class="sidenav-container" (pmClickOutside)="handleOutsideClicks()" exclude="#toggle-menu-button">
  <mat-sidenav #sidenav class="sidenav mat-elevation-z6" [mode]="menuMode">
    <mat-list>
      <div id="menu-top">
        <h3 matSubheader>Pages</h3>
        <mat-slide-toggle [checked]="menuMode === 'slide'"></mat-slide-toggle>
      </div>
      <mat-list-item>
        <a #out matLine mat-button routerLink="/">Home</a>
        <a #out matLine mat-button routerLink="changelog">Changelog</a>
        <a #out matLine mat-button href="/sitemap.xml">Sitemap</a>
        <a #out matLine mat-button href="/robots.txt">Robots</a>
        <a #out matLine mat-button href="https://www.angularuniversal.com">Consulting</a>
      </mat-list-item>
      <mat-divider></mat-divider>
      <h3 matSubheader>Boss Area</h3>
      <mat-list-item>
        <a #out matLine mat-button routerLink="pages">Pages</a>
        <a #out matLine mat-button>Assets</a>
        <a #out matLine mat-button routerLink="users">Users</a>
        <a #out matLine mat-button routerLink="admin">Admin</a>
      </mat-list-item>
    </mat-list>
  </mat-sidenav>
  <router-outlet></router-outlet>
</mat-sidenav-container>

================================================
FILE: src/client/app/app.component.scss
================================================
:host {
  display: flex;
  flex: 1 0;
  flex-direction: column;
  .sidenav-container {
    overflow-y: auto;
    flex: 1 0;
    flex-direction: column;
  }
  .sidenav {
    width: 256px;
  }
  #menu-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    mat-slide-toggle {
      margin-right: 1em;
    }
  }
  ::ng-deep mat-sidenav-container {
    mat-sidenav {
      visibility: hidden;
    }
  }
}

================================================
FILE: src/client/app/app.component.spec.ts
================================================
import { SharedModule } from './shared/shared.module'
import { async, ComponentFixture, TestBed } from '@angular/core/testing'
import { APP_BASE_HREF } from '@angular/common'
import { Route } from '@angular/router'
import { RouterTestingModule } from '@angular/router/testing'
import { Component } from '@angular/core'
import { HomeComponent } from './home/home.component'
import { AppModule } from './app.module'
import { AppBrowserModule } from './app.browser.module'
import { EnvConfig } from '../../../tools/config/app.config'
import { ENV_CONFIG } from './app.config'
import { EnvironmentService } from './shared/services/environment.service'
import { Angulartics2Module } from 'angulartics2'
import { Angulartics2GoogleAnalytics } from 'angulartics2/ga'
import { HttpClientTestingModule } from '@angular/common/http/testing'
import { NavbarService } from './shared/navbar/navbar.service'
import { MatCardModule } from '@angular/material'
import { AngularFireDatabase } from 'angularfire2/database'
import { Observable } from 'rxjs/Observable'
import { AuthService } from './shared/services/auth.service'
import '../operators'

export const TESTING_CONFIG: EnvConfig = {
  name: 'Fusebox Angular Universal Starter',
  // tslint:disable-next-line:max-line-length
  description: 'Seed project for Angular Universal apps featuring Server-Side Rendering (SSR), FuseBox, dev/prod builds, Brotli/Gzip, SCSS, favicon generation, @types, unit testing w/ Jest, and sitemap generator. Created by Patrick Michalina',
  firebase: {

  } as any,
  endpoints: {
    api: 'http://localhost:8000/api',
    websocketServer: 'ws://localhost:8001'
  },
  host: 'http://localhost:8083'
}

@Component({
  selector: 'test-cmp',
  template: '<pm-app></pm-app>'
})
class TestComponent { }

describe('App component', () => {
  const config: Array<Route> = [
    { path: '', component: HomeComponent }
  ]

  let fixture: ComponentFixture<TestComponent>

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        AppModule,
        AppBrowserModule,
        SharedModule,
        HttpClientTestingModule,
        RouterTestingModule.withRoutes(config),
        Angulartics2Module.forRoot([Angulartics2GoogleAnalytics]),
        MatCardModule
      ],
      declarations: [TestComponent, HomeComponent],
      providers: [
        { provide: APP_BASE_HREF, useValue: '/' },
        { provide: ENV_CONFIG, useValue: TESTING_CONFIG },
        { provide: AuthService, useValue: { } },
        {
          provide: AngularFireDatabase, useValue: {
            object: () => {
              return {
                snapshotChanges: () => Observable.of(),
                valueChanges: () => Observable.of()
              }
            },
            list: () => {
              return {
                snapshotChanges: () => Observable.of(),
                valueChanges: () => Observable.of()
              }
            }
          }
        },
        EnvironmentService,
        NavbarService
      ]
    }).compileComponents()
  }))

  beforeEach(async(() => {
    fixture = TestBed.createComponent(TestComponent)
  }))

  afterEach(async(() => {
    TestBed.resetTestingModule()
  }))

  it('should build without a problem', async(() => {
    expect(fixture.nativeElement).toBeTruthy()
    expect(fixture.nativeElement).toMatchSnapshot()
  }))
})


================================================
FILE: src/client/app/app.component.ts
================================================
import { ISetting } from './../../server/api/repositories/setting.repository'
import { REQUEST } from '@nguniversal/express-engine/tokens'
import { PlatformService } from './shared/services/platform.service'
import { HttpCacheDirective, ServerResponseService } from './shared/services/server-response.service'
import { CookieService } from './shared/services/cookie.service'
import { AuthService } from './shared/services/auth.service'
import { HttpClient } from '@angular/common/http'
import { WebSocketService } from './shared/services/web-socket.service'
import { DOCUMENT, TransferState } from '@angular/platform-browser'
import { SettingService } from './shared/services/setting.service'
import { Angulartics2GoogleAnalytics } from 'angulartics2/ga'
import { MatIconRegistry, MatSidenav, MatSlideToggle } from '@angular/material'
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'
import { InjectionService } from './shared/services/injection.service'
import { MinifierService } from './shared/services/minifier.service'
import { SEOService } from './shared/services/seo.service'
import {
  AfterViewInit, ChangeDetectionStrategy, Component, ElementRef,
  Inject, QueryList, Renderer2, ViewChild, ViewChildren
} from '@angular/core'

@Component({
  selector: 'pm-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent implements AfterViewInit {
  @ViewChild(MatSidenav) readonly sidenav: MatSidenav
  @ViewChild(MatSlideToggle) readonly toggle: MatSlideToggle
  @ViewChildren('out', { read: ElementRef }) readonly menuButtons: QueryList<ElementRef>

  public readonly user$ = this.auth.user$
  public menuMode = 'over'

  constructor(ss: SettingService, analytics: Angulartics2GoogleAnalytics, wss: WebSocketService,
    renderer: Renderer2, @Inject(DOCUMENT) doc: HTMLDocument, http: HttpClient, matIconRegistry: MatIconRegistry,
    ps: PlatformService, router: Router, cs: CookieService, ts: TransferState, ar: ActivatedRoute, private auth: AuthService,
    srs: ServerResponseService, domInjector: InjectionService, mini: MinifierService, seo: SEOService, @Inject(REQUEST) req: any
    ) {
      matIconRegistry.registerFontClassAlias('fontawesome', 'fa')
    ss.settings$
      .take(1)
      .filter(Boolean)
      .subscribe((settings: ISetting) => {
        if (settings.tokens) seo.updateFbAppId(settings.tokens.facebookAppId)
        settings.injections.filter(Boolean).forEach(link => domInjector.inject(renderer, link))
      })

    ss.settings$
      .flatMap(settigns => router.events
        .filter(event => event instanceof NavigationEnd)
        .map(() => ar)
        .map(route => {
          seo.updateUrl(doc.location.href)
          while (route.firstChild) route = route.firstChild
          return route
        })
        .filter(route => route.outlet === 'primary')
        .mergeMap(route => route.data)
        .map(data => data['response']))
      .subscribe((response: {
        readonly cache: { readonly directive: HttpCacheDirective, readonly maxage?: string, readonly smaxage?: string },
        readonly headers: { readonly [key: string]: string }
      }) => {
        if (response && response.cache) {
          if (response.cache.directive === 'private') {
            srs.setCachePrivate()
          } else {
            srs.setCache(response.cache.directive, response.cache.maxage, response.cache.smaxage)
          }
        } else {
          srs.setCache('public', '7d', '7d')
        }
        if (response && response.headers) {
          srs.setHeaders(response.headers)
        }
      })

    // Uncomment to turn on direct web-socket connection with server
    // if (ps.isBrowser) {
    //   wss.messageBus$.subscribe()
    //   wss.send({ message: 'ws test' })
    // }
  }

  ngAfterViewInit() {
    this.toggle.change
      .map(a => a.checked)
      .subscribe(checked => {
        if (!checked) this.sidenav.close()
        checked
          ? this.menuMode = 'side'
          : this.menuMode = 'over'
      })
    this.menuButtons
      .map(a => a.nativeElement as HTMLAnchorElement)
      .forEach(a => a.addEventListener('click', () => this.handleOutsideClicks()))
  }

  handleOutsideClicks() {
    if (this.menuMode === 'side') return
    this.sidenav.close()
  }
}


================================================
FILE: src/client/app/app.config.ts
================================================
import { InjectionToken } from '@angular/core'
import { EnvConfig } from '../../../tools/config/app.config'

export const ENV_CONFIG = new InjectionToken<EnvConfig>('app.config')


================================================
FILE: src/client/app/app.module.ts
================================================
import { ErrorHandler, NgModule } from '@angular/core'
import { HttpConfigInterceptor } from './shared/services/http-config-interceptor.service'
import { HttpCookieInterceptor } from './shared/services/http-cookie-interceptor.service'
import { AppComponent } from './app.component'
import { SharedModule } from './shared/shared.module'
import { AppRoutingModule } from './app-routing.module'
import { MetaLoader, MetaModule, MetaStaticLoader, PageTitlePositioning } from '@ngx-meta/core'
import { NotFoundModule } from './not-found/not-found.module'
import { BrowserModule, makeStateKey } from '@angular/platform-browser'
import { EnvironmentService } from './shared/services/environment.service'
import { ServerResponseService } from './shared/services/server-response.service'
import { Angulartics2Module } from 'angulartics2'
import { Angulartics2GoogleAnalytics } from 'angulartics2/ga'
import { HTTP_INTERCEPTORS, HttpClientModule, HttpResponse } from '@angular/common/http'
import { GlobalErrorHandler } from './shared/services/error-handler.service'
import { SettingService } from './shared/services/setting.service'
import { AngularFireModule, FirebaseAppConfigToken, FirebaseAppName } from 'angularfire2'
import { AngularFireAuthModule } from 'angularfire2/auth'
import { AngularFireDatabaseModule } from 'angularfire2/database'
import { TransferHttpCacheModule } from '@nguniversal/common'
import { AuthService, FB_COOKIE_KEY } from './shared/services/auth.service'
import { CACHE_TAG_CONFIG, CACHE_TAG_FACTORY, CacheTagConfig, HttpCacheTagModule } from './shared/http-cache-tag/http-cache-tag.module'

export const REQ_KEY = makeStateKey<string>('req')

export function metaFactory(env: EnvironmentService, ss: SettingService): MetaLoader {
  const locale = 'en' // TODO: make this dynamic
  const urlKey = 'host'
  return new MetaStaticLoader({
    callback: (key: string) => {
      if (key && key.includes(urlKey)) {
        return key.replace(urlKey, env.config.host)
      }
      return (key.includes('i18n')
        ? ss.pluck(key.replace('i18n', `i18n.${locale}`))
        : ss.pluck(key)).map(a => a ? a : '')
    },
    pageTitlePositioning: PageTitlePositioning.PrependPageTitle,
    pageTitleSeparator: ' - ',
    applicationName: 'og.title',
    applicationUrl: 'host',
    defaults: {
      title: 'og.title',
      description: 'og.description',
      'og:image': 'og.image',
      'og:type': 'og.type',
      'og:locale': 'en_US',
      'og:locale:alternate': 'en_US'
    }
  })
}

export function firebaseConfigLoader(env: EnvironmentService) {
  return env.config.firebase.config
}

export function firebaseAppNameLoader(env: EnvironmentService) {
  return env.config.firebase.appName
}

export function cacheTagFactory(srs: ServerResponseService): any {
  return (httpResponse: HttpResponse<any>, config: CacheTagConfig) => {
    const cacheHeader = httpResponse.headers.get(config.headerKey)
    if (cacheHeader) {
      srs.appendHeader(config.headerKey, cacheHeader)
    }
  }
}

@NgModule({
  imports: [
    HttpClientModule,
    AppRoutingModule,
    NotFoundModule,
    AngularFireModule,
    AngularFireDatabaseModule,
    AngularFireAuthModule,
    TransferHttpCacheModule,
    SharedModule.forRoot(),
    Angulartics2Module.forRoot([Angulartics2GoogleAnalytics]),
    BrowserModule.withServerTransition({ appId: 'pm-app' }),
    MetaModule.forRoot({
      provide: MetaLoader,
      useFactory: (metaFactory),
      deps: [EnvironmentService, SettingService]
    }),
    HttpCacheTagModule.forRoot(
      {
        provide: CACHE_TAG_CONFIG,
        useValue: {
          headerKey: 'Cache-Tag',
          cacheableResponseCodes: [200]
        }
      },
      {
        provide: CACHE_TAG_FACTORY,
        useFactory: cacheTagFactory,
        deps: [ServerResponseService]
      })
  ],
  providers: [
    { provide: ErrorHandler, useClass: GlobalErrorHandler },
    { provide: HTTP_INTERCEPTORS, useClass: HttpConfigInterceptor, multi: true },
    { provide: HTTP_INTERCEPTORS, useClass: HttpCookieInterceptor, multi: true },
    { provide: FB_COOKIE_KEY, useValue: 'fbAuth' },
    {
      provide: FirebaseAppName,
      useFactory: firebaseAppNameLoader,
      deps: [EnvironmentService]
    },
    {
      provide: FirebaseAppConfigToken,
      useFactory: firebaseConfigLoader,
      deps: [EnvironmentService]
    },
    AuthService
  ],
  declarations: [AppComponent],
  bootstrap: [AppComponent],
  exports: [AppComponent]
})
export class AppModule { }


================================================
FILE: src/client/app/changelog/__snapshots__/changelog.component.spec.ts.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ChangelogComponent should compile 1`] = `
<test-component>
  <pm-changelog>
    <mat-card
      class="mat-card"
    >
      <div />
    </mat-card>
  </pm-changelog>
</test-component>
`;


================================================
FILE: src/client/app/changelog/changelog-routing.module.ts
================================================
import { ChangelogComponent } from './changelog.component'
import { NgModule } from '@angular/core'
import { RouterModule } from '@angular/router'
import { MetaGuard } from '@ngx-meta/core'

@NgModule({
  imports: [
    RouterModule.forChild([
      {
        path: '',
        component: ChangelogComponent,
        canActivate: [MetaGuard],
        data: {
          meta: {
            title: 'i18n.changelog.title',
            description: 'i18n.changelog.description'
          }
        }
      }
    ])
  ],
  exports: [RouterModule]
})
export class ChangelogRoutingModule { }


================================================
FILE: src/client/app/changelog/changelog.component.e2e-spec.ts
================================================
import { baseUrl, browser } from '../../../../tools/test/jest.e2e-setup'

describe('Changelog Page', () => {
  it('should have title', async () => {
    expect.assertions(1)

    const page = browser.goto(`${baseUrl}/changelog`)
    const text = await page.evaluate(() => document.title)

    expect(text).toContain('Changelog - Fusebox Angular Universal Starter')
  })
})


================================================
FILE: src/client/app/changelog/changelog.component.html
================================================
<mat-card>
  <div [innerHTML]="changelog$ | async | MarkdownToHtml"></div>
</mat-card>

================================================
FILE: src/client/app/changelog/changelog.component.scss
================================================


================================================
FILE: src/client/app/changelog/changelog.component.spec.ts
================================================
import { ChangelogComponent } from './changelog.component'
import { async, ComponentFixture, TestBed } from '@angular/core/testing'
import { Component } from '@angular/core'
import { ChangelogModule } from './changelog.module'
import { AppTestingModule } from '../../../testing/app-testing.module'

@Component({
  selector: 'test-component',
  template: '<pm-changelog></pm-changelog>'
})
class TestComponent { }

describe(ChangelogComponent.name, () => {
  let fixture: ComponentFixture<TestComponent>

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [AppTestingModule.forRoot(), ChangelogModule],
      declarations: [TestComponent]
    }).compileComponents()
  }))

  beforeEach(async(() => {
    fixture = TestBed.createComponent(TestComponent)
  }))

  afterEach(async(() => {
    TestBed.resetTestingModule()
  }))

  it('should compile', async(() => {
    expect(fixture.nativeElement).toBeDefined()
    expect(fixture).toMatchSnapshot()
  }))
})


================================================
FILE: src/client/app/changelog/changelog.component.ts
================================================
import { Observable } from 'rxjs/Observable'
import { HttpClient } from '@angular/common/http'
import { ChangeDetectionStrategy, Component } from '@angular/core'

@Component({
  selector: 'pm-changelog',
  templateUrl: './changelog.component.html',
  styleUrls: ['./changelog.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChangelogComponent {
  readonly changelog$ = this.http.get('./changelog.md', { responseType: 'text' })
    .catch(a => Observable.of('Error loading changelog.md'))

  constructor(private http: HttpClient) { }
}


================================================
FILE: src/client/app/changelog/changelog.module.ts
================================================
import { ChangelogComponent } from './changelog.component'
import { ChangelogRoutingModule } from './changelog-routing.module'
import { NgModule } from '@angular/core'
import { SharedModule } from '../shared/shared.module'

@NgModule({
  imports: [ChangelogRoutingModule, SharedModule],
  declarations: [ChangelogComponent],
  exports: [ChangelogComponent]
})
export class ChangelogModule { }


================================================
FILE: src/client/app/dashboard/dashboard-menu.ts
================================================
export const DASHBOARD_MENU = [
  {
    heading: 'Heading 1',
    children: [
      {
        path: 'test/test-child',
        title: 'Test Child'
      },
      {
        path: 'test/test-child-1',
        title: 'Test Child 1'
      }

    ]
  },
  {
    heading: 'Heading 2',
    children: [
      {
        path: 'test1',
        title: 'Test 1 Page'
      }
    ]
  }
]


================================================
FILE: src/client/app/dashboard/dashboard-routing.module.ts
================================================
import { NgModule } from '@angular/core'
import { RouterModule } from '@angular/router'
import { DashboardComponent } from './dashboard.component'

@NgModule({
  imports: [
    RouterModule.forChild([
      {
        path: '',
        component: DashboardComponent,
        children: [
          { path: '', redirectTo: 'test', pathMatch: 'full' },
          {
            path: 'test',
            loadChildren: async () => (await import('./test/test.module')).TestModule
          },
          {
            path: 'test1',
            loadChildren: async () => (await import('./test1/test1.module')).Test1Module
          }
        ]
      }
    ])
  ],
  exports: [RouterModule]
})
export class DashboardRoutingModule { }


================================================
FILE: src/client/app/dashboard/dashboard.component.html
================================================
<mat-sidenav-container class="dashboard-container">
  <mat-sidenav #sidenav class="dashboard-sidenav" mode="side" opened="true">
    <nav class="nav-back-button">
      <button mat-button="" (click)="toggleSidenav(true)">
                <span>
                    <mat-icon role="img" aria-hidden="true">
                            arrow_back
                    </mat-icon>
                </span>
            </button>
    </nav>
    <nav *ngFor="let menu of dashboardMenu; trackBy: trackByMenu">
      <h3>{{ menu.heading }}</h3>
      <ul>
        <li *ngFor="let child of menu.children; trackBy: trackByChild">
          <a mat-button [routerLink]="[child.path]" routerLinkActive="dashboard-sidenav-item-selected" (click)="setPageTitle(child.title)">
                        {{ child.title }}
                    </a>
        </li>
      </ul>
    </nav>
    <nav>
      <h3>Forms Control</h3>
      <ul>
        <li>
          <a routerlinkactive="dashboard-sidenav-item-selected">
                        Autocomplete
                    </a>
        </li>
      </ul>
    </nav>
    <nav>
      <h3>Forms Control</h3>
      <ul>
        <li>
          <a routerlinkactive="dashboard-sidenav-item-selected">
                        Autocomplete
                    </a>
        </li>
      </ul>
    </nav>
  </mat-sidenav>
  <div class="dashboard-sidenav-content">
    <pm-dashboard-page-header (toggleSidenav)="toggleSidenav(event)" [title]="pageTitle"></pm-dashboard-page-header>
    <router-outlet></router-outlet>
    <pm-dashboard-page-footer></pm-dashboard-page-footer>
  </div>
</mat-sidenav-container>

================================================
FILE: src/client/app/dashboard/dashboard.component.scss
================================================
:host {
  -webkit-box-flex: 1;
  -ms-flex: 1 1 auto;
  flex: 1 1 auto;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  .dashboard-container {
    //background-color: #fafafa;
    //color: rgba(0, 0, 0, 0.87);
    width: 100%;
    height: 700px;
    .dashboard-sidenav {
      box-shadow: 3px 0 6px rgba(0, 0, 0, .24);
      width: 240px;
      bottom: 0;
      overflow: auto;
      height: 100%;
      z-index: 1;
      .nav-back-button {
        display: none;
      }
      .mat-icon {
        padding: 10px 30px 0px 0px;
      }
      @media (max-width: 840px) {
        .nav-back-button {
          display: block;
        }
      }
      h3 {
        border: none;
        font-size: 10px;
        letter-spacing: 1px;
        line-height: 24px;
        text-transform: uppercase;
        font-weight: 400;
        margin: 0;
        padding: 0 16px;
        background: #9ba0a5;
        color: rgba(255, 255, 255, 0.87);
      }
      ul {
        list-style-type: none;
        margin: 0;
        padding: 0;
      }
      li {
        border-bottom-width: 1px;
        border-bottom-style: solid;
        margin: 0;
        padding: 0;
        border-color: rgba(0, 0, 0, 0.06);
        color: rgba(0, 0, 0, 0.54);
        a {
          box-sizing: border-box;
          display: flex;
          font-size: 14px;
          font-weight: 400;
          line-height: 47px;
          text-decoration: none;
          transition: all .3s;
          padding: 0 16px;
          position: relative;
          color: rgba(0, 0, 0, 0.54);
        }
      }
    }
    /deep/ .mat-drawer-content {
      margin-left: 240px !important;
    }
    @media (max-width: 840px) {
      /deep/ .mat-drawer-content {
        margin-left: 0px !important;
      }
    }
    .dashboard-sidenav-content {
      min-height: 100%;
      display: -webkit-box;
      display: -ms-flexbox;
      display: flex;
      -webkit-box-orient: vertical;
      -webkit-box-direction: normal;
      -ms-flex-direction: column;
      flex-direction: column;
    }
    .dashboard-sidenav-item-selected {
      background-color: #2196f3;
      color: white !important;
    }
  }
}

================================================
FILE: src/client/app/dashboard/dashboard.component.ts
================================================
import { Title } from '@angular/platform-browser'
import { ChangeDetectionStrategy, Component, HostListener, OnInit, ViewChild } from '@angular/core'
import { MatSidenav } from '@angular/material'
import { DASHBOARD_MENU } from './dashboard-menu'

@Component({
  selector: 'pm-dashboard',
  templateUrl: './dashboard.component.html',
  styleUrls: ['./dashboard.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class DashboardComponent implements OnInit {

  pageTitle: string

  readonly isMobile = false

  readonly dashboardMenu = DASHBOARD_MENU

  @ViewChild('sidenav') public readonly sidenav: MatSidenav

  @HostListener('window:resize', ['$event'])
  onResize(event: any) {
    if (event.target.innerWidth < 840) {
      this.sidenav.close()
    }
    if (event.target.innerWidth >= 840) {
      this.sidenav.open()
    }
  }

  constructor(private title: Title) { }

  ngOnInit() {
    const title = this.title.getTitle()
    this.setPageTitle(title.substr(0, title.indexOf('-')))
  }

  toggleSidenav(event: any) {
    this.sidenav.toggle()
  }

  setPageTitle(title: string) {
    this.pageTitle = title
  }

  trackByMenu(index: number, item: any) {
    return index
  }

  trackByChild(index: number, item: any) {
    return index
  }
}


================================================
FILE: src/client/app/dashboard/dashboard.module.ts
================================================
import { DashboardComponent } from './dashboard.component'
import { DashboardRoutingModule } from './dashboard-routing.module'
import { DashboardPageHeaderComponent } from './header/dashboard-page-header.component'
import { DashboardPageFooterComponent } from './footer/dashboard-page-footer.component'
import { NgModule } from '@angular/core'
import { SharedModule } from '../shared/shared.module'
import { MatIconModule, MatSidenavModule } from '@angular/material'

@NgModule({
  imports: [DashboardRoutingModule, SharedModule, MatSidenavModule, MatIconModule],
  declarations: [DashboardComponent, DashboardPageHeaderComponent, DashboardPageFooterComponent],
  exports: [DashboardComponent, DashboardPageHeaderComponent, DashboardPageFooterComponent]
})
export class DashboardModule { }


================================================
FILE: src/client/app/dashboard/footer/__snapshots__/dashboard-page-footer.component.spec.ts.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`DashboardPageFooterComponent should match snapshot 1`] = `
<pm-dashboard-page-footer>
  <footer
    class="dashboard-footer"
  >
    <div
      class="dashboard-footer-list"
    >
      <div
        class="logo"
      >
        <img
          alt="angular"
          class="logo"
          src="assets/angular-white-transparent.svg"
        />
      </div>
      <div
        class="dashboard-footer-links"
      >
        <ul>
          <li>
            <a
              href="https://angular.io"
            >
              Learn Angular
            </a>
          </li>
        </ul>
      </div>
      <div
        class="dashboard-footer-copyright"
      >
        <p>
          Powered by Google ©2010-2017. Code licensed under an MIT-style License. Documentation licensed under CC BY 4.0.
        </p>
      </div>
    </div>
  </footer>
</pm-dashboard-page-footer>
`;


================================================
FILE: src/client/app/dashboard/footer/dashboard-page-footer.component.html
================================================
<footer class="dashboard-footer">
  <div class="dashboard-footer-list">
    <div class="logo">
      <img alt="angular" class="logo" src="assets/angular-white-transparent.svg">
    </div>
    <div class="dashboard-footer-links">
      <ul>
        <li> <a href="https://angular.io">Learn Angular</a> </li>
      </ul>
    </div>
    <div class="dashboard-footer-copyright">
      <p>Powered by Google ©2010-2017. Code licensed under an MIT-style License. Documentation licensed under CC BY 4.0.</p>
    </div>
  </div>
</footer>

================================================
FILE: src/client/app/dashboard/footer/dashboard-page-footer.component.scss
================================================
:host {
  .dashboard-footer {
    margin-top: 40px;
    padding: 12px;
    font-size: 12px;
    background: #2196f3;
    color: rgba(255, 255, 255, 0.87);
    .dashboard-footer-list {
      -webkit-box-align: center;
      -ms-flex-align: center;
      align-items: center;
      display: -webkit-box;
      display: -ms-flexbox;
      display: flex;
      -webkit-box-orient: horizontal;
      -webkit-box-direction: normal;
      -ms-flex-flow: row wrap;
      flex-flow: row wrap;
      padding: 8px;
    }
    .logo {
      height: 50px;
    }
    .dashboard-footer-links {
      ul {
        list-style: none;
        margin: 0 40px;
        padding: 0;
        a {
          font-size: 16px;
          padding: 0;
          text-decoration: none;
          color: rgba(255, 255, 255, 0.87);
        }
      }
    }
    .dashboard-footer-copyright {
      display: -webkit-box;
      display: -ms-flexbox;
      display: flex;
      -webkit-box-flex: 1;
      -ms-flex: 1;
      flex: 1;
      -webkit-box-pack: end;
      -ms-flex-pack: end;
      justify-content: flex-end;
    }
  }
}

================================================
FILE: src/client/app/dashboard/footer/dashboard-page-footer.component.spec.ts
================================================
import { async, ComponentFixture, TestBed } from '@angular/core/testing'
import { Component } from '@angular/core'
import { DashboardPageFooterComponent } from './dashboard-page-footer.component'
import { DashboardModule } from '../dashboard.module'

describe(DashboardPageFooterComponent.name, () => {
  let fixture: ComponentFixture<DashboardPageFooterComponent>

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [DashboardModule],
      declarations: [TestComponent]
    }).compileComponents()
  }))

  beforeEach(async(() => {
    fixture = TestBed.createComponent(DashboardPageFooterComponent)
  }))

  afterEach(async(() => {
    TestBed.resetTestingModule()
  }))

  it('should match snapshot', async(() => {
    expect(fixture).toMatchSnapshot()
  }))

  it('should compile', async(() => {
    expect(fixture.nativeElement).toBeDefined()
  }))
})

@Component({
  selector: 'test-component',
  template: '<pm-dashboard-page-footer></pm-dashboard-page-footer>'
})
class TestComponent {}


================================================
FILE: src/client/app/dashboard/footer/dashboard-page-footer.component.ts
================================================
import { ChangeDetectionStrategy, Component } from '@angular/core'

@Component({
  selector: 'pm-dashboard-page-footer',
  templateUrl: './dashboard-page-footer.component.html',
  styleUrls: ['./dashboard-page-footer.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class DashboardPageFooterComponent {

}


================================================
FILE: src/client/app/dashboard/header/__snapshots__/dashboard-page-header.component.spec.ts.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`DashboardPageHeaderComponent should match snapshot 1`] = `
<pm-dashboard-page-header
  toggleSidenav={[Function EventEmitter]}
>
  <div
    class="docs-primary-header"
  >
    <button
      class="side-nav-toggle mat-button"
      mat-button=""
    >
      <span
        class="mat-button-wrapper"
      >
        <span>
          <mat-icon
            aria-hidden="true"
            class="mat-icon"
            role="img"
          >
             menu 
          </mat-icon>
        </span>
      </span>
      <div
        class="mat-button-ripple mat-ripple"
        matripple=""
      />
      <div
        class="mat-button-focus-overlay"
      />
    </button>
    <h1>
      
    </h1>
  </div>
</pm-dashboard-page-header>
`;


================================================
FILE: src/client/app/dashboard/header/dashboard-page-header.component.html
================================================
<div class="docs-primary-header">
  <button class="side-nav-toggle" mat-button="" (click)="toggle()">
    <span>
      <mat-icon role="img" aria-hidden="true">
        menu
      </mat-icon>
    </span>
  </button>
  <h1>{{ title }}</h1>
</div>

================================================
FILE: src/client/app/dashboard/header/dashboard-page-header.component.scss
================================================
:host {
  .docs-primary-header {
    background: #9ba0a5;
    padding-left: 20px;
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    h1 {
      font-size: 30px;
      font-weight: 300;
      margin: 0;
      padding: 20px 20px 20px 10px;
      color: hsla(0, 0%, 100%, .87);
    }
  }
  .side-nav-toggle {
    padding-top: 14px;
    margin: 8px;
    min-width: 64px;
    display: none;
  }
  .mat-icon {
    color: white;
  }
  @media (max-width: 840px) {
    .side-nav-toggle {
      display: block;
    }
    .docs-primary-header {
      padding-left: 0px;
    }
  }
}

================================================
FILE: src/client/app/dashboard/header/dashboard-page-header.component.spec.ts
================================================
import { async, ComponentFixture, TestBed } from '@angular/core/testing'
import { Component } from '@angular/core'
import { DashboardModule } from '../dashboard.module'
import { DashboardPageHeaderComponent } from './dashboard-page-header.component'

describe(DashboardPageHeaderComponent.name, () => {
  let fixture: ComponentFixture<DashboardPageHeaderComponent>

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [DashboardModule],
      declarations: [TestComponent]
    }).compileComponents()
  }))

  beforeEach(async(() => {
    fixture = TestBed.createComponent(DashboardPageHeaderComponent)
  }))

  afterEach(async(() => {
    TestBed.resetTestingModule()
  }))

  it('should match snapshot', async(() => {
    expect(fixture).toMatchSnapshot()
  }))

  it('should compile', async(() => {
    expect(fixture.nativeElement).toBeDefined()
  }))
})

@Component({
  selector: 'test-component',
  template: '<pm-dashboard-page-header></pm-dashboard-page-header>'
})
class TestComponent {}


================================================
FILE: src/client/app/dashboard/header/dashboard-page-header.component.ts
================================================
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'

@Component({
  selector: 'pm-dashboard-page-header',
  templateUrl: './dashboard-page-header.component.html',
  styleUrls: ['./dashboard-page-header.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class DashboardPageHeaderComponent {

  @Input() readonly title: string

  @Output() readonly toggleSidenav: EventEmitter<boolean> = new EventEmitter<boolean>()

  toggle() {
    this.toggleSidenav.emit(true)
  }
}


================================================
FILE: src/client/app/dashboard/test/__snapshots__/test.component.spec.ts.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`TestComponent should match snapshot 1`] = `
<pm-test>
  <router-outlet />
</pm-test>
`;


================================================
FILE: src/client/app/dashboard/test/test-routing.module.ts
================================================
import { TestComponent } from './test.component'
import { NgModule } from '@angular/core'
import { RouterModule } from '@angular/router'
import { MetaGuard } from '@ngx-meta/core'
import { TestChild1Component } from './testChild1/testChild1.component'
import { TestChildComponent } from './testChild/testChild.component'

@NgModule({
  imports: [
    RouterModule.forChild([
      {
        path: '',
        component: TestComponent,
        canActivateChild: [MetaGuard],
        children: [
          { path: '', redirectTo: 'test-child', pathMatch: 'full'  },
          {
            path: 'test-child',
            component: TestChildComponent,
            data: {
              meta: {
                title: 'Test Child',
                // tslint:disable-next-line:max-line-length
                description: 'Test for angular related projects on github, to showcase the flicker-free http state transfer of an Angular isomorphic application.'
              }
            }
          },
          {
            path: 'test-child-1',
            component: TestChild1Component,
            data: {
              meta: {
                title: 'Test Child 1 Page',
                // tslint:disable-next-line:max-line-length
                description: 'Test for angular related projects on github, to showcase the flicker-free http state transfer of an Angular isomorphic application.'
              }
            }
          }
        ]
      }
    ])
  ],
  exports: [RouterModule]
})
export class TestRoutingModule { }


================================================
FILE: src/client/app/dashboard/test/test.component.html
================================================
<router-outlet></router-outlet>

================================================
FILE: src/client/app/dashboard/test/test.component.scss
================================================


================================================
FILE: src/client/app/dashboard/test/test.component.spec.ts
================================================
import { async, ComponentFixture, TestBed } from '@angular/core/testing'
import { Component } from '@angular/core'
import { TestModule } from './test.module'
import { TestComponent } from './test.component'
import { RouterTestingModule } from '@angular/router/testing'
import { TestChildComponent } from './testChild/testChild.component'
import { TestChild1Component } from './testChild1/testChild1.component'
import { Route } from '@angular/router'
import { EnvironmentService } from '../../shared/services/environment.service'
import { APP_BASE_HREF } from '@angular/common'

describe(TestComponent.name, () => {
  const config: Array<Route> = [
    {
      path: '',
      component: TestComponent,
      pathMatch: 'full',
      children: [
        { path: '', redirectTo: 'test-child', pathMatch: 'full' },
        {
          path: 'test-child',
          component: TestChildComponent
        },
        {
          path: 'test-child-1',
          component: TestChild1Component
        }
      ]
    }
  ]

  let fixture: ComponentFixture<TestComponent>

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [TestModule, RouterTestingModule.withRoutes(config)],
      declarations: [TestingComponent],
      providers: [
        { provide: APP_BASE_HREF, useValue: '/' },
        EnvironmentService
      ]
    }).compileComponents()
  }))

  beforeEach(async(() => {
    fixture = TestBed.createComponent(TestComponent)
  }))

  afterEach(async(() => {
    TestBed.resetTestingModule()
  }))

  it('should match snapshot', async(() => {
    expect(fixture).toMatchSnapshot()
  }))

  it('should compile', async(() => {
    expect(fixture.nativeElement).toBeDefined()
  }))
})

@Component({
  selector: 'test-component',
  template: '<pm-test></pm-test>'
})
class TestingComponent {}


================================================
FILE: src/client/app/dashboard/test/test.component.ts
================================================
import { ChangeDetectionStrategy, Component } from '@angular/core'

@Component({
  selector: 'pm-test',
  templateUrl: './test.component.html',
  styleUrls: ['./test.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class TestComponent {
}


================================================
FILE: src/client/app/dashboard/test/test.module.ts
================================================
import { TestRoutingModule } from './test-routing.module'
import { TestComponent } from './test.component'
import { NgModule } from '@angular/core'
import { SharedModule } from '../../shared/shared.module'
import { TestChildComponent } from './testChild/testChild.component'
import { TestChild1Component } from './testChild1/testChild1.component'

@NgModule({
  imports: [TestRoutingModule, SharedModule],
  declarations: [TestComponent, TestChild1Component, TestChildComponent],
  exports: [TestComponent, TestChild1Component, TestChildComponent]
})
export class TestModule { }


================================================
FILE: src/client/app/dashboard/test/test.service.ts
================================================
import { Injectable } from '@angular/core'

@Injectable()
export class TestService {

}


================================================
FILE: src/client/app/dashboard/test/testChild/__snapshots__/testChild.component.spec.ts.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`TestChildComponent should match snapshot 1`] = `
<pm-test-child-1>
  <mat-card
    class="mat-card"
  >
     Test Child Project
  
  </mat-card>
</pm-test-child-1>
`;


================================================
FILE: src/client/app/dashboard/test/testChild/testChild.component.html
================================================
<mat-card>
    Test Child Project
</mat-card>

================================================
FILE: src/client/app/dashboard/test/testChild/testChild.component.scss
================================================
.mat-card {
    margin: 10px;
    height: 400px;
}

================================================
FILE: src/client/app/dashboard/test/testChild/testChild.component.spec.ts
================================================
import { async, ComponentFixture, TestBed } from '@angular/core/testing'
import { Component } from '@angular/core'
import { TestChildComponent } from './testChild.component'
import { TestModule } from '../test.module'

describe(TestChildComponent.name, () => {
  let fixture: ComponentFixture<TestChildComponent>

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [TestModule],
      declarations: [TestComponent]
    }).compileComponents()
  }))

  beforeEach(async(() => {
    fixture = TestBed.createComponent(TestChildComponent)
  }))

  afterEach(async(() => {
    TestBed.resetTestingModule()
  }))

  it('should match snapshot', async(() => {
    expect(fixture).toMatchSnapshot()
  }))

  it('should compile', async(() => {
    expect(fixture.nativeElement).toBeDefined()
  }))
})

@Component({
  selector: 'test-component',
  template: '<pm-test-child-1></pm-test-child-1>'
})
class TestComponent {}


================================================
FILE: src/client/app/dashboard/test/testChild/testChild.component.ts
================================================
import { ChangeDetectionStrategy, Component } from '@angular/core'

@Component({
  selector: 'pm-test-child-1',
  templateUrl: './testChild.component.html',
  styleUrls: ['./testChild.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class TestChildComponent {
}


================================================
FILE: src/client/app/dashboard/test/testChild1/__snapshots__/testChild1.component.spec.ts.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`TestChild1Component should match snapshot 1`] = `
<pm-test-child-2>
  <mat-card
    class="mat-card"
  >
     Test Child 1 Project
  
  </mat-card>
</pm-test-child-2>
`;


================================================
FILE: src/client/app/dashboard/test/testChild1/testChild1.component.html
================================================
<mat-card>
  Test Child 1 Project
</mat-card>

================================================
FILE: src/client/app/dashboard/test/testChild1/testChild1.component.scss
================================================
.mat-card {
  margin: 10px;
  height: 400px;
}

================================================
FILE: src/client/app/dashboard/test/testChild1/testChild1.component.spec.ts
================================================
import { async, ComponentFixture, TestBed } from '@angular/core/testing'
import { Component } from '@angular/core'
import { TestModule } from '../test.module'
import { TestChild1Component } from './testChild1.component'

describe(TestChild1Component.name, () => {
  let fixture: ComponentFixture<TestChild1Component>

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [TestModule],
      declarations: [TestComponent]
    }).compileComponents()
  }))

  beforeEach(async(() => {
    fixture = TestBed.createComponent(TestChild1Component)
  }))

  afterEach(async(() => {
    TestBed.resetTestingModule()
  }))

  it('should match snapshot', async(() => {
    expect(fixture).toMatchSnapshot()
  }))

  it('should compile', async(() => {
    expect(fixture.nativeElement).toBeDefined()
  }))
})

@Component({
  selector: 'test-component',
  template: '<pm-test-child-2></pm-test-child-2>'
})
class TestComponent {}


================================================
FILE: src/client/app/dashboard/test/testChild1/testChild1.component.ts
================================================
import { ChangeDetectionStrategy, Component } from '@angular/core'

@Component({
  selector: 'pm-test-child-2',
  templateUrl: './testChild1.component.html',
  styleUrls: ['./testChild1.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class TestChild1Component {
}


================================================
FILE: src/client/app/dashboard/test1/__snapshots__/test1.component.spec.ts.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Test1Component should match snapshot 1`] = `
<pm-test1>
  <mat-card
    class="mat-card"
  >
     Test 1 Project
  
  </mat-card>
</pm-test1>
`;


================================================
FILE: src/client/app/dashboard/test1/test1-routing.module.ts
================================================
import { Test1Component } from './test1.component'
import { NgModule } from '@angular/core'
import { RouterModule } from '@angular/router'
import { MetaGuard } from '@ngx-meta/core'

@NgModule({
  imports: [
    RouterModule.forChild([
      {
        path: '',
        component: Test1Component,
        canActivate: [MetaGuard],
        data: {
          meta: {
            title: 'Test 1 Page',
            // tslint:disable-next-line:max-line-length
            description: 'Test 1 for angular related projects on github, to showcase the flicker-free http state transfer of an Angular isomorphic application.'
          }
        }
      }
    ])
  ],
  exports: [RouterModule]
})
export class Test1RoutingModule { }


================================================
FILE: src/client/app/dashboard/test1/test1.component.html
================================================
<mat-card>
  Test 1 Project
</mat-card>

================================================
FILE: src/client/app/dashboard/test1/test1.component.scss
================================================
.mat-card {
  margin: 10px;
  height: 400px;
}

================================================
FILE: src/client/app/dashboard/test1/test1.component.spec.ts
================================================
import { async, ComponentFixture, TestBed } from '@angular/core/testing'
import { Component } from '@angular/core'
import { Test1Component } from './test1.component'
import { Test1Module } from './test1.module'

describe(Test1Component.name, () => {
  let fixture: ComponentFixture<Test1Component>

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [Test1Module],
      declarations: [TestComponent]
    }).compileComponents()
  }))

  beforeEach(async(() => {
    fixture = TestBed.createComponent(Test1Component)
  }))

  afterEach(async(() => {
    TestBed.resetTestingModule()
  }))

  it('should match snapshot', async(() => {
    expect(fixture).toMatchSnapshot()
  }))

  it('should compile', async(() => {
    expect(fixture.nativeElement).toBeDefined()
  }))
})

@Component({
  selector: 'test-component',
  template: '<pm-test1></pm-test1>'
})
class TestComponent {}


================================================
FILE: src/client/app/dashboard/test1/test1.component.ts
================================================
import { ChangeDetectionStrategy, Component } from '@angular/core'

@Component({
  selector: 'pm-test1',
  templateUrl: './test1.component.html',
  styleUrls: ['./test1.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class Test1Component {
}


================================================
FILE: src/client/app/dashboard/test1/test1.module.ts
================================================
import { Test1RoutingModule } from './test1-routing.module'
import { Test1Component } from './test1.component'
import { NgModule } from '@angular/core'
import { SharedModule } from '../../shared/shared.module'

@NgModule({
  imports: [Test1RoutingModule, SharedModule],
  declarations: [Test1Component],
  exports: [Test1Component]
})
export class Test1Module { }


================================================
FILE: src/client/app/home/__snapshots__/home.component.spec.ts.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`HomeComponent should compile 1`] = `
<pm-home
  containerClass={[Function Boolean]}
>
  <mat-card
    class="mat-card"
  >
    <div
      id="hero"
    >
      <h1
        class="display-3"
      >
        Hello, Angular Developer!
      </h1>
      <p
        class="lead"
      >
        Welcome to a blazing fast Angular Universal development starter
      </p>
      <a
        angulartics2on="click"
        angularticsaction="ViewRepo"
        class="mat-raised-button"
        color="primary"
        href="https://github.com/patrickmichalina/fusebox-angular-universal-starter"
        mat-raised-button=""
        role="button"
      >
        <span
          class="mat-button-wrapper"
        >
          <mat-icon
            aria-hidden="true"
            class="fa fa-github mat-icon"
            role="img"
          />
           Github
        </span>
        <div
          class="mat-button-ripple mat-ripple"
          matripple=""
        />
        <div
          class="mat-button-focus-overlay"
        />
      </a>
    </div>
    <mat-tab-group
      class="mat-tab-group mat-primary"
    >
      <mat-tab-header
        class="mat-tab-header"
      >
        <div
          aria-hidden="true"
          class="mat-tab-header-pagination mat-tab-header-pagination-before mat-elevation-z4 mat-ripple"
          mat-ripple=""
        >
          <div
            class="mat-tab-header-pagination-chevron"
          />
        </div>
        <div
          class="mat-tab-label-container"
        >
          <div
            class="mat-tab-list"
            role="tablist"
          >
            <div
              class="mat-tab-labels"
            >
              
            </div>
            <mat-ink-bar
              class="mat-ink-bar"
            />
          </div>
        </div>
        <div
          aria-hidden="true"
          class="mat-tab-header-pagination mat-tab-header-pagination-after mat-elevation-z4 mat-ripple"
          mat-ripple=""
        >
          <div
            class="mat-tab-header-pagination-chevron"
          />
        </div>
      </mat-tab-header>
      <div
        class="mat-tab-body-wrapper"
      >
        
      </div>
    </mat-tab-group>
  </mat-card>
</pm-home>
`;


================================================
FILE: src/client/app/home/home-routing.module.ts
================================================
import { HomeComponent } from './home.component'
import { NgModule } from '@angular/core'
import { RouterModule } from '@angular/router'
import { MetaGuard } from '@ngx-meta/core'

@NgModule({
  imports: [
    RouterModule.forChild([
      {
        path: '',
        component: HomeComponent,
        canActivate: [MetaGuard],
        data: {
          meta: {
            title: 'i18n.home.title',
            description: 'i18n.home.description'
          },
          response: {
            cache: {
              directive: 'public',
              maxage: '7d',
              smaxage: '7d'
            },
            headers: {
              'X-Cool-Tag': 'some-value'
            }
          }
        }
      }
    ])
  ],
  exports: [RouterModule]
})
export class HomeRoutingModule { }


================================================
FILE: src/client/app/home/home.component.e2e-spec.ts
================================================
import { baseUrl, browser } from '../../../../tools/test/jest.e2e-setup'

describe('Home Page', () => {
  it('should have title', async () => {
    expect.assertions(1)

    const page = browser.goto(`${baseUrl}`)

    const text = await page.evaluate(() => document.title)

    expect(text).toContain('Home - Fusebox Angular Universal Starter')
  })
})


================================================
FILE: src/client/app/home/home.component.html
================================================
<mat-card>
  <div id="hero">
    <h1 class="display-3">Hello, Angular Developer!</h1>
    <p class="lead">Welcome to a blazing fast Angular Universal development starter</p>
    <a mat-raised-button color="primary" href="https://github.com/patrickmichalina/fusebox-angular-universal-starter" role="button"
      angulartics2On="click" angularticsAction="ViewRepo">
      <mat-icon class="fa fa-github" aria-hidden="true"></mat-icon> Github</a>
  </div>
  <mat-tab-group>
    <mat-tab label="Developer Experience">
      <ul>
        <li>
          <a href="https://github.com/angular/angular/blob/master/CHANGELOG.md" target="_blank" rel="noopener">Angular</a> as the application framework
        </li>
        <li>
          <a href="https://material.angular.io" target="_blank" rel="noopener">Angular Material</a> as the UI language and component library</li>
        <li>
          <a href="https://github.com/angular/angularfire2" target="_blank" rel="noopener">Angular Firebase</a> for easy user authentication
        </li>
        <li>
          <a href="https://github.com/angular/flex-layout">Angular Flex Layout</a> for dynamic responsive layouts
          <li>Fully typed build tools and application using
            <a href="https://www.typescriptlang.org/" target="_blank" rel="noopener">TypeScript</a>
          </li>

          <li>Manage your type definitions using @types (easier than using
            <a href="https://github.com/typings/typings">typings</a>)</li>
          <li>Automatic sitemap generation</li>
          <li>
            <a href="https://mobile.angular.io" target="_blank" rel="noopener">SCSS</a> support for professional grade CSS management</li>
          <li>Full favicon icon generation for multiple devices derived from a single seed image</li>
          <li>Analyze bundle sizes by using
            <a href="https://github.com/danvk/source-map-explorer">source-map-explorer</a>
          </li>
          <li>Cookies Support</li>
          <li>Simple Ad-Blocker detection service</li>
          <li>Built by <a href="https://www.angularuniversal.com">Angular Universal Consulting</a></li>
      </ul>
    </mat-tab>
    <mat-tab label="Testing">
      <ul>
        <li>Angular testing with
          <a href="https://facebook.github.io/jest" target="_blank" rel="noopener">Jest</a> (faster than Karma)</li>
        <li>End-to-end (e2e) testing with
          <a href="https://github.com/segmentio/nightmare" target="_blank" rel="noopener">Nightmare</a>
        </li>
        <li>
          <a href="https://circleci.com" target="_blank" rel="noopener">CircleCI</a> unit testing support</li>
      </ul>
    </mat-tab>
    <mat-tab label="Performance">
      <ul>
        <li>
          <a href="http://fuse-box.org/">FuseBox</a> bundling (faster than
          <a href="https://webpack.github.io/" target="_blank" rel="noopener">Webpack</a> and
          <a href="http://jspm.io/" target="_blank" rel="noopener">JSPM</a>)</li>
        <li>
          <a href="https://github.com/google/brotli" target="_blank" rel="noopener">Brotli compression</a> with
          <a href="http://www.gzip.org" target="_blank" rel="noopener">gzip</a> fallback</li>
        <li>
          <a href="https://angular.io/guide/aot-compiler#tree-shaking-1" target="_blank" rel="noopener">Lazy Loaded</a> modules</li>
        <li>
          <strong>Coming Soon</strong>:
          <a href="https://angular-2-training-book.rangle.io/handout/modules/lazy-loading-module.html" target="_blank" rel="noopener">Tree-Shaking</a> builds</li>
        <li>
          <strong>Coming Soon</strong>: Support for
          <a href="https://mobile.angular.io" target="_blank" rel="noopener">Angular Mobile Toolkit</a> (Service Worker)</li>
      </ul>
    </mat-tab>
    <mat-tab label="Deployments">
      <ul>
        <li>Production and development builds</li>
        <li>Simple
          <a href="https://heroku.com" target="_blank" rel="noopener">Heroku</a> deployment</li>
      </ul>
    </mat-tab>
    <mat-tab label="SEO">
      <ul>
        <li>HttpStateTransfer for caching server responses on client boostrap (no flickering on load)</li>
        <li>SEO support for Title and Meta tags</li>
        <li>
          <a href="http://ogp.me" target="_blank" rel="noopener">OG (Open Graph)</a> tags for social sharing</li>
        <li>Vendor-agnostic analytics using
          <a href="https://angulartics.github.io">angulartics2</a>
        </li>
      </ul>
    </mat-tab>
  </mat-tab-group>
</mat-card>


================================================
FILE: src/client/app/home/home.component.scss
================================================
:host {
  #hero {
    display: flex;
    flex-direction: column;
    align-items: center;
    h1 {
      margin-bottom: 0;
    }
  }
}


================================================
FILE: src/client/app/home/home.component.spec.ts
================================================
import { By } from '@angular/platform-browser'
import { Angulartics2 } from 'angulartics2'
import { HomeComponent } from './home.component'
import { async, ComponentFixture, TestBed } from '@angular/core/testing'
import { Component } from '@angular/core'
import { HomeModule } from './home.module'
import { MatRaisedButtonCssMatStyler } from '@angular/material'
import { AppTestingModule } from '../../../testing/app-testing.module'

describe(HomeComponent.name, () => {
  let fixture: ComponentFixture<HomeComponent>

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [AppTestingModule.forRoot(), HomeModule],
      declarations: [TestComponent]
    }).compileComponents()
  }))

  beforeEach(async(() => {
    fixture = TestBed.createComponent(HomeComponent)
  }))

  afterEach(async(() => {
    TestBed.resetTestingModule()
  }))

  it('should compile', async(() => {
    expect(fixture.nativeElement).toBeDefined()
    expect(fixture).toMatchSnapshot()
  }))

  it('should track event when link clicked', async(() => {
    const analytics = TestBed.get(Angulartics2) as Angulartics2
    expect(analytics).toBeDefined()
    const button = fixture.debugElement.query(By.directive(MatRaisedButtonCssMatStyler))
    expect(button).toBeTruthy()
    const link = button.nativeElement as HTMLAnchorElement
    expect(link).toBeTruthy()
    analytics.eventTrack.subscribe(eventTrack => {
      expect(eventTrack).toBeDefined()
      expect(eventTrack.action).toEqual('ViewRepo')
      expect(eventTrack.properties.eventType).toEqual('click')
    })
    link.click()
  }))
})

@Component({
  selector: 'test-component',
  template: '<pm-home></pm-home>'
})
class TestComponent { }


================================================
FILE: src/client/app/home/home.component.ts
================================================
import { ChangeDetectionStrategy, Component, HostBinding } from '@angular/core'

@Component({
  selector: 'pm-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class HomeComponent {
  @HostBinding('class.card-float-container') containerClass = true
}


================================================
FILE: src/client/app/home/home.module.ts
================================================
import { HomeRoutingModule } from './home-routing.module'
import { HomeComponent } from './home.component'
import { NgModule } from '@angular/core'
import { SharedModule } from '../shared/shared.module'

@NgModule({
  imports: [HomeRoutingModule, SharedModule],
  declarations: [HomeComponent],
  exports: [HomeComponent]
})
export class HomeModule { }


================================================
FILE: src/client/app/login/__snapshots__/login.component.spec.ts.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`LoginComponent should compile 1`] = `
<pm-login>
  <div
    fxlayout="column"
    fxlayoutalign="center center"
  >
    <h1>
      Login
    </h1>
    <pm-login-card>
      
      
    </pm-login-card>
  </div>
</pm-login>
`;


================================================
FILE: src/client/app/login/login-routing.module.ts
================================================
import { LoginComponent } from './login.component'
import { NgModule } from '@angular/core'
import { RouterModule } from '@angular/router'
import { MetaGuard } from '@ngx-meta/core'

@NgModule({
  imports: [
    RouterModule.forChild([
      {
        path: '',
        component: LoginComponent,
        canActivate: [MetaGuard],
        data: {
          meta: {
            title: 'i18n.login.title',
            description: 'i18n.login.description'
          }
        }
      }
    ])
  ],
  exports: [RouterModule]
})
export class LoginRoutingModule { }


================================================
FILE: src/client/app/login/login.component.e2e-spec.ts
================================================
import { baseUrl, browser } from '../../../../tools/test/jest.e2e-setup'

describe('Login Page', () => {
  it('should have title', async () => {
    expect.assertions(1)

    const page = browser.goto(`${baseUrl}/login`)

    const text = await page.evaluate(() => document.title)

    expect(text).toContain('Login - Fusebox Angular Universal Starter')
  })
})


================================================
FILE: src/client/app/login/login.component.html
================================================
<div fxLayout="column" fxLayoutAlign="center center">
  <h1>Login</h1>
  <pm-login-card></pm-login-card>
</div>

================================================
FILE: src/client/app/login/login.component.scss
================================================


================================================
FILE: src/client/app/login/login.component.spec.ts
================================================
import { AuthService } from './../shared/services/auth.service'
import { AngularFireAuthModule } from 'angularfire2/auth'
import { LoginComponent } from './login.component'
import { async, ComponentFixture, TestBed } from '@angular/core/testing'
import { Component } from '@angular/core'
import { LoginModule } from './login.module'
import { AngularFireModule } from 'angularfire2'
import { AppTestingModule } from '../../../testing/app-testing.module'

describe(LoginComponent.name, () => {
  let fixture: ComponentFixture<LoginComponent>

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [AppTestingModule.forRoot(), LoginModule, AngularFireModule.initializeApp({
        'apiKey': '1',
        'authDomain': 'app.firebaseapp.com',
        'databaseURL': 'https://app.firebaseio.com',
        'projectId': 'firebase-app',
        'messagingSenderId': '1'
      }), AngularFireAuthModule],
      declarations: [TestComponent],
      providers: [
        { provide: AuthService, userValue: { }}
      ]
    }).compileComponents()
  }))

  beforeEach(async(() => {
    fixture = TestBed.createComponent(LoginComponent)
  }))

  afterEach(async(() => {
    TestBed.resetTestingModule()
  }))

  it('should compile', async(() => {
    expect(fixture.nativeElement).toBeDefined()
    expect(fixture).toMatchSnapshot()
  }))
})

@Component({
  selector: 'test-component',
  template: '<pm-login></pm-login>'
})
class TestComponent {}


================================================
FILE: src/client/app/login/login.component.ts
================================================
import { ChangeDetectionStrategy, Component } from '@angular/core'

@Component({
  selector: 'pm-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class LoginComponent {
}


================================================
FILE: src/client/app/login/login.module.ts
================================================
import { LoginComponent } from './login.component'
import { LoginRoutingModule } from './login-routing.module'
import { NgModule } from '@angular/core'
import { SharedModule } from '../shared/shared.module'

@NgModule({
  imports: [LoginRoutingModule, SharedModule],
  declarations: [LoginComponent],
  exports: [LoginComponent]
})
export class LoginModule { }


================================================
FILE: src/client/app/logout/__snapshots__/logout.component.spec.ts.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`LogoutComponent should compile 1`] = `
<pm-logout>
  You have been logged out. Come back soon!
</pm-logout>
`;


================================================
FILE: src/client/app/logout/logout-routing.module.ts
================================================
import { LogoutComponent } from './logout.component'
import { NgModule } from '@angular/core'
import { RouterModule } from '@angular/router'
import { MetaGuard } from '@ngx-meta/core'

@NgModule({
  imports: [
    RouterModule.forChild([
      {
        path: '',
        component: LogoutComponent,
        canActivate: [MetaGuard],
        data: {
          meta: {
            title: 'i18n.logout.title',
            description: 'i18n.logout.description'
          }
        }
      }
    ])
  ],
  exports: [RouterModule]
})
export class LogoutRoutingModule { }


================================================
FILE: src/client/app/logout/logout.component.e2e-spec.ts
================================================
import { baseUrl, browser } from '../../../../tools/test/jest.e2e-setup'

describe('Logout Page', () => {
  it('should have title', async () => {
    expect.assertions(1)

    const page = browser.goto(`${baseUrl}/logout`)

    const text = await page.evaluate(() => document.title)

    expect(text).toContain('Logged Out - Fusebox Angular Universal Starter')
  })
})


================================================
FILE: src/client/app/logout/logout.component.html
================================================
You have been logged out. Come back soon!

================================================
FILE: src/client/app/logout/logout.component.scss
================================================


================================================
FILE: src/client/app/logout/logout.component.spec.ts
================================================
import { AngularFireAuthModule } from 'angularfire2/auth'
import { LogoutComponent } from './logout.component'
import { async, ComponentFixture, TestBed } from '@angular/core/testing'
import { Component } from '@angular/core'
import { LogoutModule } from './logout.module'
import { AngularFireModule } from 'angularfire2'
import { AppTestingModule } from '../../../testing/app-testing.module'

describe(LogoutComponent.name, () => {
  let fixture: ComponentFixture<LogoutComponent>

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [AppTestingModule.forRoot(), LogoutModule, AngularFireAuthModule, AngularFireModule.initializeApp({
        'apiKey': '1',
        'authDomain': 'app.firebaseapp.com',
        'databaseURL': 'https://app.firebaseio.com',
        'projectId': 'firebase-app',
        'messagingSenderId': '1'
      })],
      declarations: [TestComponent]
    }).compileComponents()
  }))

  beforeEach(async(() => {
    fixture = TestBed.createComponent(LogoutComponent)
  }))

  afterEach(async(() => {
    TestBed.resetTestingModule()
  }))

  it('should compile', async(() => {
    expect(fixture.nativeElement).toBeDefined()
    expect(fixture).toMatchSnapshot()
  }))
})

@Component({
  selector: 'test-component',
  template: '<pm-logout></pm-logout>'
})
class TestComponent { }


================================================
FILE: src/client/app/logout/logout.component.ts
================================================
import { PlatformService } from './../shared/services/platform.service'
import { CookieService } from './../shared/services/cookie.service'
import { AngularFireAuth } from 'angularfire2/auth'
import { ChangeDetectionStrategy, Component } from '@angular/core'

@Component({
  selector: 'pm-logout',
  templateUrl: './logout.component.html',
  styleUrls: ['./logout.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class LogoutComponent {
  constructor(afAuth: AngularFireAuth, cs: CookieService, ps: PlatformService) {
    cs.remove('fbJwt')
    cs.remove('fbPhotoURL')
    cs.remove('fbProviderId')
    cs.remove('fbEmail')
    cs.remove('fbDisplayName')
    if (ps.isBrowser) {
      afAuth.auth.signOut()
    }
  }
}


================================================
FILE: src/client/app/logout/logout.module.ts
================================================
import { LogoutRoutingModule } from './logout-routing.module'
import { LogoutComponent } from './logout.component'
import { NgModule } from '@angular/core'
import { SharedModule } from '../shared/shared.module'

@NgModule({
  imports: [LogoutRoutingModule, SharedModule],
  declarations: [LogoutComponent],
  exports: [LogoutComponent]
})
export class LogoutModule { }


================================================
FILE: src/client/app/not-found/__snapshots__/not-found.component.spec.ts.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`NotFoundComponent should compile 1`] = `
<test-component>
  <pm-not-found
    class="vert-flex-fill"
  >
    
    <div
      class="vert-flex-fill"
      ng-reflect-ng-switch="false"
    >
      
      
      <div
        class="vert-flex-fill"
      >
        <div
          ng-reflect-html="SafeValue must use [property]="
          pmhtmloutlet=""
        />
        <footer
          class="footer mat-elevation-z6"
        >
          
          <button
            class="mat-raised-button mat-accent"
            color="accent"
            mat-raised-button=""
            ng-reflect-color="accent"
          >
            <span
              class="mat-button-wrapper"
            >
              Edit
            </span>
            <div
              class="mat-button-ripple mat-ripple"
              matripple=""
              ng-reflect-centered="false"
              ng-reflect-disabled="false"
              ng-reflect-trigger="[object HTMLButtonElement]"
            />
            <div
              class="mat-button-focus-overlay"
            />
          </button>
        </footer>
      </div>
    </div>
  </pm-not-found>
</test-component>
`;


================================================
FILE: src/client/app/not-found/not-found-routing.module.ts
================================================
import { NotFoundComponent } from './not-found.component'
import { NgModule } from '@angular/core'
import { RouterModule } from '@angular/router'

@NgModule({
  imports: [
    RouterModule.forChild([
      {
        path: '**',
        component: NotFoundComponent,
        data: {
          // meta: {
          //   title: 'i18n.not-found.title',
          //   description: 'i18n.not-found.description'
          // }
        }
      }
    ])
  ],
  exports: [RouterModule]
})
export class NotFoundRoutingModule { }


================================================
FILE: src/client/app/not-found/not-found.component.e2e-spec.ts
================================================
import { baseUrl, browser } from '../../../../tools/test/jest.e2e-setup'

describe('NotFound Page', () => {
  it('should have title', async () => {
    const page = browser.goto(`${baseUrl}/not-found`)

    const text = await page.evaluate(() => document.title)

    expect(text).toContain('Not Found - Fusebox Angular Universal Starter')
  })
})


================================================
FILE: src/client/app/not-found/not-found.component.html
================================================
<div *ngIf="view$ | async as view" [ngSwitch]="view.isEditing" class="vert-flex-fill">
  <div *ngSwitchCase="true" class="vert-flex-fill">
    <mat-tab-group [selectedIndex]="view.currentTab" (selectedIndexChange)="updateTabParam($event)">
      <mat-tab label="Content">
        <pm-quill-editor [content]="view.page.content"></pm-quill-editor>
      </mat-tab>
      <mat-tab label="Settings">
        <form [formGroup]="settingsForm" id="settingsForm" novalidate class="settings" *ngIf="view.currentTab === 1">
          <mat-accordion class="example-headers-align">
            <mat-expansion-panel hideToggle="true">
              <mat-expansion-panel-header>
                <mat-panel-title>
                  Basic Info
                </mat-panel-title>
                <mat-panel-description>
                  Title, description, and other page information
                  <mat-icon fontSet="fa" fontIcon="fa-info" aria-hidden="true"></mat-icon>
                </mat-panel-description>
              </mat-expansion-panel-header>
              <div class="field-spacer">
                <mat-form-field>
                  <input matInput placeholder="Title" type="text" formControlName="title">
                  <mat-hint align="end">appears in
                    <em>title</em> and
                    <em>meta:og:title</em>
                  </mat-hint>
                </mat-form-field>
                <mat-form-field>
                  <input matInput placeholder="Description" type="text" formControlName="description">
                  <mat-hint align="end">appears in
                    <em>meta:name:description</em> and
                    <em>meta:og:description</em>
                  </mat-hint>
                </mat-form-field>
                <mat-form-field>
                  <input matInput placeholder="Type" type="text" formControlName="type">
                  <mat-hint align="end">appears in
                    <em>meta:type</em>
                  </mat-hint>
                </mat-form-field>
              </div>
              <div class="field-spacer">
                <mat-form-field>
                  <input matInput placeholder="Published" [matDatepicker]="picker" formControlName="articlePublishedTime" (focus)="picker.open()">
                  <mat-datepicker touchUi="true" #picker></mat-datepicker>
                  <mat-hint align="end">appears in
                    <em>meta:og:article:published_time</em>
                  </mat-hint>
                </mat-form-field>
                <mat-form-field>
                  <input matInput placeholder="Modified" [matDatepicker]="pickerModified" formControlName="articleModifiedTime" (focus)="pickerModified.open()">
                  <mat-datepicker touchUi="true" #pickerModified></mat-datepicker>
                  <mat-hint align="end">appears in
                    <em>meta:og:article:modified_time</em>
                  </mat-hint>
                </mat-form-field>
                <mat-form-field>
                  <input matInput placeholder="Expiration" [matDatepicker]="pickerExpired" formControlName="articleExpirationTime" (focus)="pickerExpired.open()">
                  <mat-datepicker touchUi="true" #pickerExpired></mat-datepicker>
                  <mat-hint align="end">appears in
                    <em>meta:og:article:expiration_time</em>
                  </mat-hint>
                </mat-form-field>
              </div>
              <div class="field-spacer">
                <mat-form-field>
                  <input matInput placeholder="Author" type="text" formControlName="articleAuthor">
                  <mat-hint align="end">appears in
                    <em>meta:og:article:author</em>
                  </mat-hint>
                </mat-form-field>
                <mat-form-field>
                  <input matInput placeholder="Section" type="text" formControlName="articleSection">
                  <mat-hint align="end">appears in
                    <em>meta:og:article:section</em>
                  </mat-hint>
                </mat-form-field>
              </div>
              <div class="field-spacer">
                <mat-form-field>
                  <!-- <input matInput placeholder="Tags" type="text" formControlName="articleTag"> -->
                  <mat-chip-list #chipList>
                    <mat-chip *ngFor="let tag of tags; trackBy: trackByTag" [selectable]="selectable">
                      {{ tag }}
                      <mat-icon fontSet="fa" fontIcon="fa-times" aria-hidden="true" (click)="remove(tag)"></mat-icon>
                    </mat-chip>
                    <input placeholder="New tag..." [matChipInputFor]="chipList" [matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="addOnBlur"
                      (matChipInputTokenEnd)="add($event)" />
                  </mat-chip-list>
                  <mat-hint align="end">appears in
                    <em>meta:og:article:tag</em>
                  </mat-hint>
                </mat-form-field>
              </div>
            </mat-expansion-panel>
            <mat-expansion-panel hideToggle="true">
              <mat-expansion-panel-header>
                <mat-panel-title>
                  Caching
                </mat-panel-title>
                <mat-panel-description>
                  HTTP cache settings
                  <mat-icon fontSet="fa" fontIcon="fa-globe" aria-hidden="true"></mat-icon>
                </mat-panel-description>
              </mat-expansion-panel-header>
              <pm-cache-form (cacheChange)="updateCache($event)" [cache]="cacheSettings"></pm-cache-form>
            </mat-expansion-panel>
            <mat-expansion-panel hideToggle="true">
              <mat-expansion-panel-header>
                <mat-panel-title>
                  Images
                </mat-panel-title>
                <mat-panel-description>
                  Image settings for the Open Graph protocol
                  <mat-icon fontSet="fa" fontIcon="fa-picture-o" aria-hidden="true"></mat-icon>
                </mat-panel-description>
              </mat-expansion-panel-header>
              <div class="field-spacer">
                <mat-form-field>
                  <input matInput placeholder="Image URL" type="text" formControlName="imgUrl">
                  <mat-hint align="end">appears in
                    <em>meta:og:image</em>
                  </mat-hint>
                </mat-form-field>
                <mat-form-field>
                  <input matInput placeholder="Image Alternate Text" type="text" formControlName="imgAlt">
                  <mat-hint align="end">appears in
                    <em>meta:og:image:alt</em>
                  </mat-hint>
                </mat-form-field>
              </div>
              <div class="field-spacer">
                <mat-form-field>
                  <input matInput placeholder="Image Height" type="number" formControlName="imgHeight">
                  <mat-hint align="end">appears in
                    <em>meta:og:image:height</em>
                  </mat-hint>
                </mat-form-field>
                <mat-form-field>
                  <input matInput placeholder="Image Width" type="number" formControlName="imgWidth">
                  <mat-hint align="end">appears in
                    <em>meta:og:image:width</em>
                  </mat-hint>
                </mat-form-field>
                <mat-form-field>
                  <input matInput placeholder="Image Mime Type" type="text" formControlName="imgMime">
                  <mat-hint align="end">appears in
                    <em>meta:og:image:type</em>
                  </mat-hint>
                </mat-form-field>
              </div>
            </mat-expansion-panel>
            <mat-expansion-panel hideToggle="true" disabled>
              <mat-expansion-panel-header>
                <mat-panel-title>
                  Music
                </mat-panel-title>
                <mat-panel-description>
                  Music settings for the Open Graph protocol
                  <mat-icon fontSet="fa" fontIcon="fa-music" aria-hidden="true"></mat-icon>
                </mat-panel-description>
              </mat-expansion-panel-header>
            </mat-expansion-panel>
            <mat-expansion-panel hideToggle="true" disabled>
              <mat-expansion-panel-header>
                <mat-panel-title>
                  Videos
                </mat-panel-title>
                <mat-panel-description>
                  Video settings for the Open Graph protocol
                  <mat-icon fontSet="fa" fontIcon="fa-video-camera" aria-hidden="true"></mat-icon>
                </mat-panel-description>
              </mat-expansion-panel-header>
            </mat-expansion-panel>
          </mat-accordion>
          <br>
          <mat-slide-toggle formControlName="userCommentsEnabled">User Comments Enabled</mat-slide-toggle>
          <mat-slide-toggle formControlName="isDraft">Draft</mat-slide-toggle>
        </form>
      </mat-tab>
      <mat-tab label="Dynamic Code & Styling">
        <div class="pad-tab">
          <h3 mat-subheader>Add custom css and javascript for this page</h3>
          <div class="card-list" *ngFor="let keyVal of injections$ | async | pmKeyVal; trackBy: trackByInjection">
            <button mat-icon-button>
              <mat-icon fontSet="fa" fontIcon="fa-minus-circle" color="warn" aria-hidden="true" (click)="removeInjectable(keyVal.key)"></mat-icon>
            </button>
            <mat-card>
              <mat-form-field>
                <input matInput placeholder="Name" type="text" [value]="keyVal.key" #keyTest (keydown)="injectionFormChange($event, keyVal.value.type, $event)">
              </mat-form-field>
              <div [ngSwitch]="keyVal.value.type">
                <pm-injection-form *ngSwitchCase="'style'" [injectable]="keyVal.value" showDomString="true" (formChange)="injectionFormChange(keyTest.value, keyVal.value.type, $event)"></pm-injection-form>
                <pm-injection-form *ngSwitchCase="'script'" [injectable]="keyVal.value" showDomString="true" (formChange)="injectionFormChange(keyTest.value, keyVal.value.type, $event)"></pm-injection-form>
              </div>
            </mat-card>
          </div>
          <br>
          <div>
            <button mat-raised-button color="primary" (click)="addInjectable('style')">Add CSS</button>
            <button mat-raised-button color="primary" (click)="addInjectable('script')">Add JavaScript</button>
          </div>
          <br>
        </div>
      </mat-tab>
      <mat-tab label="Relationships" disabled>
      </mat-tab>
      <mat-tab label="Privileges" disabled>
      </mat-tab>
      <mat-tab label="Change History" disabled>
      </mat-tab>
    </mat-tab-group>
    <footer class="footer mat-elevation-z6">
      <button mat-button color="warn" (click)="delete()">Delete</button>
      <button mat-button (click)="viewCurrent()">View Current</button>
      <button mat-raised-button color="primary" (click)="publish()" [disabled]="settingsForm.invalid">Publish</button>
    </footer>
  </div>
  <div *ngSwitchCase="false" class="vert-flex-fill">
    <div pmHtmlOutlet [html]="view.page.content | pmSanitizeHtml"></div>
    <footer class="footer mat-elevation-z6">
      <button *ngIf="view.canEdit" mat-raised-button color="accent" (click)="edit()">Edit</button>
    </footer>
  </div>
</div>

================================================
FILE: src/client/app/not-found/not-found.component.scss
================================================
:host {
  .footer {
    text-align: right;
    padding: .75em;
  }
   ::ng-deep mat-tab-group {
    flex: 1;
    height: 100%;
    .mat-tab-body-wrapper {
      height: 100%;
    }
    mat-tab-body {
      .mat-tab-body-content {
        overflow: overlay;
      } // overflow-y: overlay;
      // .mat-tab-body-content {
      //   overflow-y: overlay;
      // }
    }
  }
  .settings {
    display: flex;
    flex-direction: column;
    padding: 1em;
    height: 100%;
    overflow-y: auto;
  }
   ::ng-deep dynamic-html {
    display: -webkit-inline-box;
    overflow-y: auto;
    height: 100%;
  }
   ::ng-deep mat-form-field {
    padding-bottom: 1em;
  }
  .example-headers-align .mat-expansion-panel-header-title,
  .example-headers-align .mat-expansion-panel-header-description {
    flex-basis: 0;
  }
  .example-headers-align .mat-expansion-panel-header-description {
    justify-content: space-between;
    align-items: center;
  }
  .field-spacer {
    display: flex;
    flex: 1;
    mat-form-field {
      width: 100%;
      margin-right: 1em;
    }
    @media only screen and (max-width: 959px) {
      flex-direction: column;
    }
  }
   ::ng-deep mat-chip {
    mat-icon {
      height: auto;
      width: auto;
      margin-left: 8px;
      padding-bottom: 4px;
      &:hover {
        cursor: pointer;
      }
    }
  }
  .pad-tab {
    padding: 0 1em;
  }
  .inj-list {
    mat-list-item {
      margin: 1em 0;
    }
    mat-card {
      width: 100%;
      padding: 1em;
    }
  }
  .card-list {
    margin-bottom: 1em;   
    display: flex;
    align-items: center;
    mat-card {
      width: 100%;
      display: inherit;
    }
  }
}

================================================
FILE: src/client/app/not-found/not-found.component.spec.ts
================================================
import { NotFoundComponent } from './not-found.component'
import { AuthService } from './../shared/services/auth.service'
import { of } from 'rxjs/observable/of'
import { TransferState } from '@angular/platform-browser'
import { ServerResponseService } from './../shared/services/server-response.service'
import { Observable } from 'rxjs/Observable'
import { async, ComponentFixture, TestBed } from '@angular/core/testing'
import { Component } from '@angular/core'
import { NotFoundModule } from './not-found.module'
import { FirebaseDatabaseService } from '../shared/services/firebase-database.service'
import { AppTestingModule } from '../../../testing/app-testing.module'

@Component({
  selector: 'test-component',
  template: '<pm-not-found></pm-not-found>'
})
class TestComponent { }

describe(NotFoundComponent.name, () => {
  let fixture: ComponentFixture<TestComponent>

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [NotFoundModule, AppTestingModule.forRoot()],
      declarations: [TestComponent],
      providers: [
        ServerResponseService,
        TransferState,
        {
          provide: FirebaseDatabaseService,
          useValue: {
            get() {
              return of({})
            }
          }
        },
        {
          provide: AuthService,
          useValue: {
            user$: Observable.of({})
          }
        }
      ]
    }).compileComponents()
  }))

  beforeEach(async(() => {
    fixture = TestBed.createComponent(TestComponent)
  }))

  afterEach(async(() => {
    TestBed.resetTestingModule()
  }))

  it('should compile', async(() => {
    fixture.detectChanges()
    expect(fixture.componentInstance).toBeDefined()
    expect(fixture).toMatchSnapshot()
  }))
})


================================================
FILE: src/client/app/not-found/not-found.component.ts
================================================
import { BehaviorSubject } from 'rxjs/BehaviorSubject'
import { DOMInjectable } from './../shared/services/injection.service'
import { ChangeDetectionStrategy, Component, HostBinding, ViewChild } from '@angular/core'
import { QuillEditorComponent } from './../shared/quill-editor/quill-editor.component'
import { FirebaseDatabaseService } from './../shared/services/firebase-database.service'
import { AuthService } from './../shared/services/auth.service'
import { FormControl, FormGroup, Validators } from '@angular/forms'
import { ServerResponseService } from './../shared/services/server-response.service'
import { ActivatedRoute, Router } from '@angular/router'
import { Observable } from 'rxjs/Observable'
import { filter } from 'rxjs/operators'
import { SEONode, SEOService } from '../shared/services/seo.service'
import { MatChipInputEvent, MatDialog, MatSnackBar } from '@angular/material'
import { ModalConfirmationComponent } from '../shared/modal-confirmation/modal-confirmation.component'
import { ENTER } from '@angular/cdk/keycodes'

const COMMA = 188

export interface Page {
  readonly content: string
  readonly title: string
  readonly isDraft: boolean
  readonly userCommentsEnabled?: boolean
  readonly cache?: { readonly [key: string]: boolean | string | number }
  readonly imgWidth?: number,
  readonly imgHeight?: number,
  readonly imgAlt?: string,
  readonly imgUrl?: string,
  readonly imgMime?: string
  readonly articleTag?: ReadonlyArray<string>
}

type types = 'script' | 'style'
interface InjectionMap { readonly [key: string]: { readonly type: types, readonly injectable: DOMInjectable } }

@Component({
  selector: 'pm-not-found',
  templateUrl: './not-found.component.html',
  styleUrls: ['./not-found.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class NotFoundComponent {
  @HostBinding('class.vert-flex-fill') readonly flexFill = true
  @ViewChild(QuillEditorComponent) readonly editor: QuillEditorComponent

  readonly addOnBlur = true
  readonly separatorKeysCodes: ReadonlyArray<any> = [ENTER, COMMA]
  tags: ReadonlyArray<string> = []
  readonly injections$ = new BehaviorSubject<InjectionMap>({})
  readonly injectionsToSave$ = new BehaviorSubject<InjectionMap>({})
  readonly styleInjDefault = {
    element: 'link',
    attributes: {
      href: 'https://',
      type: 'text/css',
      rel: 'stylesheet'
    }
  }

  cacheSettings = {} as any

  injectionFormChange(key: string, type: types, injectable: DOMInjectable) {
    console.log(key)
    // this.injectionsToSave$.next({
    //   ...this.injections$.getValue(),
    //   [key]: {
    //     type,
    //     injectable
    //   }
    // })
  }

  addInjectable(type: types) {
    this.injections$.next({
      ...this.injections$.getValue(),
      [`${type.toString()}_${Math.random().toPrecision(4)}`]: {
        type,
        injectable: {} as any
      }
    })
  }

  insertInjectable(key: string, type: types, injectable: DOMInjectable) {
    this.injections$.next({
      ...this.injections$.getValue(),
      [key]: {
        type,
        injectable
      }
    })
  }

  removeInjectable(key: string) {
    const current = this.injections$.getValue()
    this.injections$.next({
      ...Object.keys(current)
        .filter(k => k !== key)
        .reduce((a, c) => ({ ...a, [c]: current[c] }), {})
    })
  }

  add(event: MatChipInputEvent): void {
    if (event.input) event.input.value = '' // clear input value
    this.tags = [...this.tags, event.value.trim()]
      .filter(a => a !== '')
      .filter((elem, pos, arr) => arr.indexOf(elem) === pos)
    this.updateTags()
  }

  remove(tag: any): void {
    this.tags = [...this.tags].filter(a => a !== tag)
    this.updateTags()
  }

  updateTags() {
    this.settingsForm.controls['articleTag'].setValue(this.tags)
  }

  updateTabParam(tab: number) {
    this.router.navigate([this.router.url.split('?')[0]], { queryParams: { tab }, queryParamsHandling: 'merge' })
  }

  private readonly params$ = this.ar.queryParams.shareReplay()

  private readonly isEditMode$ = this.params$
    .map(a => a.edit ? true : false)

  private readonly currentTab$ = this.params$
    .map(a => a.tab ? +a.tab : 0)

  private readonly url$ = Observable.of(this.router.url.split('?')[0])
    .pipe(filter(a => !a.includes('.')))
    .shareReplay()

  public readonly settingsForm = new FormGroup({
    type: new FormControl('website', [Validators.required]),
    title: new FormControl('', [Validators.required]),
    description: new FormControl('', [Validators.required, Validators.max(158)]),
    imgUrl: new FormControl('', []),
    imgAlt: new FormControl('', []),
    imgMime: new FormControl('', []),
    imgHeight: new FormControl('', [Validators.min(1)]),
    imgWidth: new FormControl('', [Validators.min(1)]),
    articlePublishedTime: new FormControl(new Date(), []),
    articleModifiedTime: new FormControl('', []),
    articleExpirationTime: new FormControl('', []),
    articleAuthor: new FormControl('', []),
    articleSection: new FormControl('', []),
    articleTag: new FormControl('', []),
    userCommentsEnabled: new FormControl('', []),
    isDraft: new FormControl('', [])
  })

  public readonly page$ = this.url$
    .flatMap(url => this.db
      .get<Page & SEONode>(`/pages/${url}`)
      .flatMap(page => this.isEditMode$, (page, editMode) => ({ page, editMode }))
      .map(res => {
        if (res && res.page && (res.editMode || !res.page.isDraft)) {
          if (!res.editMode) {
            const pageCacheSettings = res.page.cache || {}
            const cacheControl = Object.keys(pageCacheSettings)
              .filter(key => pageCacheSettings[key])
              .reduce((acc, curr) => {
                const ret = typeof pageCacheSettings[curr] === 'boolean'
                  ? curr
                  : `${curr}=${pageCacheSettings[curr]}`

                return acc.concat(', ').concat(ret)
              }, '')
              .replace(/(^,)|(,$)/g, '')
              .trim()

            if (cacheControl) {
              this.rs.setHeader('Cache-Control', cacheControl)
            } else {
              this.rs.setCacheNone()
            }
          } else {
            this.rs.setCacheNone()
          }

          return {
            ...res.page,
            content: res.page.content
          }
        }
        this.rs.setNotFound()
        this.rs.setCacheNone()
        return {
          ...res.page,
          content: 'not found'
        } as Page & SEONode
      })
      .do(page => {
        this.cacheSettings = page.cache
        this.seo.updateNode({
          title: page.title,
          description: page.description,
          img: {
            width: page.imgWidth,
            height: page.imgHeight,
            type: page.imgMime,
            alt: page.imgAlt,
            url: page.imgUrl
          },
          tags: page.articleTag
        })

        // tslint:disable:no-null-keyword
        const formValues = Object.keys(this.settingsForm.controls)
          .reduce((acc: any, controlKey) =>
            ({ ...acc, [controlKey]: (page as any)[controlKey] || this.settingsForm.controls[controlKey].value || null }), {})
        this.settingsForm.setValue(formValues)
        this.tags = page.articleTag || []
      })
      .catch(err => {
        if (err.code === 'PERMISSION_DENIED') {
          this.rs.setStatus(401)
          return Observable.of({
            content: 'unauthorized'
          })
        } else {
          this.rs.setError()
          return Observable.of({
            content: err || 'server error'
          })
        }
      }))

  readonly view$ = Observable.combineLatest(this.auth.user$, this.page$, this.currentTab$,
    this.ar.queryParams.pluck('edit').map(a => a === 'true'),
    (user, page, currentTab, isEditing) => {
      return {
        currentTab,
        canEdit: true, // for demo only, user && user.roles && user.roles.admin,
        isEditing,
        page
      }
    })
    .catch(err => {
      this.rs.setError()
      return Observable.of({
        content: 'server error'
      })
    })

  publish() {
    const injections = this.injectionsToSave$.getValue()
    const cache = this.cacheSettings

    const settings = Object.keys(this.settingsForm.value)
      .filter(key => typeof this.settingsForm.value[key] !== 'undefined')
      .reduce((acc, curr) => ({ ...acc, [curr]: this.settingsForm.value[curr] }) as any, {})

    this.url$.flatMap(url => this.db.getObjectRef(`/pages/${url}`)
      .update({
        ...settings,
        injections,
        cache,
        content: this.editor.textValue.getValue()
      }), (url, update) => ({ url, update }))
      .take(1)
      .subscribe(a => {
        this.router.navigate([a.url])
        this.showSnack('Published! Page is now live.')
      })
  }

  showSnack(message: string) {
    this.snackBar.open(message, 'dismiss', {
      duration: 2000,
      horizontalPosition: 'left',
      verticalPosition: 'bottom'
    })
  }

  confirmDelete() {
    return this.dialog.open(ModalConfirmationComponent, {
      width: '460px',
      position: {
        top: '30px'
      },
      data: {
        message: 'Deleting this page will immediately remove it from the database and anyone reading it',
        title: 'Are you sure?'
      }
    })
  }

  delete() {
    this.confirmDelete()
      .afterClosed()
      .filter(Boolean)
      .flatMap(() => this.url$)
      .flatMap(url => this.db.getObjectRef(`/pages/${url}`).remove(), (url, update) => ({ url, update }))
      .take(1)
      .subscribe(a => {
        this.router.navigate(['/pages'])
        this.showSnack('Page removed!')
      })
  }

  viewCurrent() {
    this.url$
      .take(1)
      .subscribe(url => this.router.navigate([url]))
  }

  edit() {
    this.url$
      .take(1)
      .subscribe(url => this.router.navigate([url], { queryParams: { edit: true } }))
  }

  constructor(private rs: ServerResponseService, private db: FirebaseDatabaseService, private seo: SEOService,
    public auth: AuthService, private ar: ActivatedRoute, private router: Router, private dialog: MatDialog,
    private snackBar: MatSnackBar) {
  }

  updateCache(cache: any) {
    this.cacheSettings = cache
  }

  trackByInjection(index: number, item: any) {
    return item.key
  }

  trackByTag(index: number, item: string) {
    return item
  }
}


================================================
FILE: src/client/app/not-found/not-found.module.ts
================================================
import { NotFoundRoutingModule } from './not-found-routing.module'
import { NotFoundComponent } from './not-found.component'
import { NgModule } from '@angular/core'
import { SharedModule } from '../shared/shared.module'

@NgModule({
  imports: [NotFoundRoutingModule, SharedModule],
  declarations: [NotFoundComponent],
  exports: [NotFoundComponent]
})
export class NotFoundModule { }


================================================
FILE: src/client/app/pages/page-form/page-form.component.html
================================================
<h2>New Page</h2>
<form [formGroup]="form" id="pageForm" novalidate>
  <mat-form-field>
    <input matInput placeholder="Slug" formControlName="slug">
    <mat-error *ngIf="form.controls.slug.hasError('pattern')">
      must contain a forward slash and name
    </mat-error>
    <mat-error *ngIf="form.controls.slug.hasError('slugTaken')">
      slug already taken
    </mat-error>
    <mat-error *ngIf="form.controls.slug.hasError('required')">
      <span>slug is
        <strong>required</strong>
      </span>
    </mat-error>
  </mat-form-field>
  <mat-form-field>
    <input matInput placeholder="Title" formControlName="title">
    <mat-error *ngIf="form.controls.title.hasError('required')">
      <span>title is
        <strong>required</strong>
      </span>
    </mat-error>
  </mat-form-field>
  <mat-form-field>
    <input matInput placeholder="Description" formControlName="description">
    <mat-error *ngIf="form.controls.description.hasError('required')">
      <span>description is
        <strong>required</strong>
      </span>
    </mat-error>
  </mat-form-field>
  <mat-slide-toggle formControlName="isDraft">
    Draft (not visible to public)
  </mat-slide-toggle>
  <br>
  <button mat-raised-button color="primary" type="text" [disabled]="form.invalid" (click)="create()">Create</button>
</form>

================================================
FILE: src/client/app/pages/page-form/page-form.component.scss
================================================
:host {
  h2 {
    margin: 0 0 1em 0;
  }
  form {
    display: flex;
    flex-direction: column;
  }
}

================================================
FILE: src/client/app/pages/page-form/page-form.component.ts
================================================
import { FirebaseDatabaseService } from '../../shared/services/firebase-database.service'
import { ChangeDetectionStrategy, Component, EventEmitter, Output } from '@angular/core'
import { AbstractControl, FormControl, FormGroup, Validators } from '@angular/forms'
import { MatDialogRef } from '@angular/material'
import { ModalConfirmationComponent } from '../../shared/modal-confirmation/modal-confirmation.component'

@Component({
  selector: 'pm-page-form',
  templateUrl: './page-form.component.html',
  styleUrls: ['./page-form.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class PageFormComponent {
  @Output() created = new EventEmitter()

  public form = new FormGroup({
    slug: new FormControl('blog/', [
      Validators.required,
      // Validators.pattern(/^[^/A-Za-z0-9]+(?:-[A-Za-z0-9]+)*$/),
      Validators.pattern('^[^/]+/[^/]+$')
    ], this.validateSlugNotTaken.bind(this)),
    title: new FormControl('', [
      Validators.required
    ]),
    description: new FormControl('', [
      Validators.required
    ]),
    isDraft: new FormControl(true, [])
  })

  // tslint:disable:no-null-keyword
  validateSlugNotTaken(control: AbstractControl) {
    return this.db
      .getObjectRef(`/pages/${control.value}`)
      .valueChanges()
      .debounceTime(200)
      .take(1)
      .map(a => a ? ({ slugTaken: true }) : null)
  }

  create() {
    this.db.getObjectRef(`/pages/${this.form.value.slug}`).update({
      title: this.form.value.title,
      description: this.form.value.description,
      isDraft: this.form.value.isDraft,
      userCommentsEnabled: false,
      cache: {
        'no-cache': true,
        'no-store': true,
        'must-revalidate': true
      }
    })
    .then(() => this.dialog.close(true))
    .catch(() => this.dialog.close(false))
  }

  constructor(private db: FirebaseDatabaseService, public dialog: MatDialogRef<ModalConfirmationComponent>) { }
}


================================================
FILE: src/client/app/pages/pages-routing.module.ts
================================================
import { PagesComponent } from './pages.component'
import { NgModule } from '@angular/core'
import { RouterModule } from '@angular/router'
import { MetaGuard } from '@ngx-meta/core'

@NgModule({
  imports: [
    RouterModule.forChild([
      {
        path: '',
        component: PagesComponent,
        canActivate: [MetaGuard],
        data: {
          // meta: {
          //   title: 'i18n.admin.title',
          //   description: 'i18n.admin.description'
          // },
          response: {
            cache: {
              directive: 'private'
            }
          }
        }
      }
    ])
  ],
  exports: [RouterModule]
})
export class PagesRoutingModule { }


================================================
FILE: src/client/app/pages/pages.component.html
================================================
<div *ngIf="view$ | async as view">
  <div class="flex">
    <h1>Pages</h1>
    <button mat-fab color="accent" (click)="openDialog()">
      <mat-icon fontSet="fa" fontIcon="fa-plus" aria-label="create a page"></mat-icon>
    </button>
  </div>
  <mat-tab-group [selectedIndex]="view.currentTab" (selectedIndexChange)="updateTabParam($event)">
    <mat-tab *ngFor="let group of view.groups; trackBy: trackByGroup" [label]="group.name">
      <mat-table #table [dataSource]="group.table">
        <ng-container matColumnDef="slug">
          <mat-header-cell *matHeaderCellDef>Slug</mat-header-cell>
          <mat-cell *matCellDef="let element">
            <a [routerLink]="element.routerLink">{{ element.slug }}</a>
          </mat-cell>
        </ng-container>

        <ng-container matColumnDef="edit">
          <mat-header-cell *matHeaderCellDef></mat-header-cell>
          <mat-cell *matCellDef="let element">
            <a mat-icon-button [routerLink]="element.routerLink" [queryParams]="{ 'edit': true }">
              <mat-icon fontSet="fa" fontIcon="fa-pencil-square-o"></mat-icon>
            </a>
            <a mat-icon-button (click)="delete(group.name, element.slug)">
              <mat-icon fontSet="fa" fontIcon="fa-trash"></mat-icon>
            </a>
          </mat-cell>
        </ng-container>

        <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
        <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
      </mat-table>
    </mat-tab>
  </mat-tab-group>
</div>

================================================
FILE: src/client/app/pages/pages.component.scss
================================================
:host {
  .flex {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0 1em;
  }
}

================================================
FILE: src/client/app/pages/pages.component.ts
================================================
import { FirebaseDatabaseService } from './../shared/services/firebase-database.service'
import { ChangeDetectionStrategy, Component } from '@angular/core'
import { MatDialog, MatTableDataSource } from '@angular/material'
import { PageFormComponent } from './page-form/page-form.component'
import { ActivatedRoute, Router } from '@angular/router'
import { Observable } from 'rxjs/Observable'
import { ModalConfirmationComponent } from '../shared/modal-confirmation/modal-confirmation.component'

@Component({
  selector: 'pm-pages',
  templateUrl: './pages.component.html',
  styleUrls: ['./pages.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class PagesComponent {
  readonly pages$ = this.db.get('/pages')
  private readonly params$ = this.ar.queryParams.shareReplay()
  private readonly currentTab$ = this.params$
    .map(a => a.tab ? +a.tab : 0)

  readonly view$ = Observable.combineLatest(this.currentTab$, this.pages$,
    (currentTab, pages: { readonly [key: string]: string }) => {
      return {
        groups: Object.keys(pages || {}).map(group => {
          return {
            table: new MatTableDataSource(Object.keys(pages[group] || {}).map(slug => {
              return {
                ...(pages[group] as any)[slug],
                slug,
                routerLink: `/${group}/${slug}`
              }
            })),
            name: group
          }
        }),
        currentTab
      }
    })

  readonly displayedColumns: ReadonlyArray<any> = ['slug', 'edit']

  openDialog() {
    this.dialog.open(PageFormComponent, {
      width: '460px',
      position: {
        top: '30px'
      }
    })
  }

  confirmDelete() {
    return this.dialog.open(ModalConfirmationComponent, {
      width: '460px',
      position: {
        top: '30px'
      },
      data: {
        message: 'Deleting this page will immediately remove it from the database',
        title: 'Are you sure?'
      }
    })
  }

  delete(group: string, slug: string) {
    this.confirmDelete()
      .afterClosed()
      .filter(Boolean)
      .flatMap(() => this.db
        .getObjectRef(`/pages/${group}/${slug}`)
        .remove())
      .take(1)
      .subscribe(succ => {
        // todo
      }, err => {
        // todo
      })
  }

  updateTabParam(tab: number) {
    this.router.navigate([this.router.url.split('?')[0]], { queryParams: { tab }, queryParamsHandling: 'merge' })
  }

  constructor(private db: FirebaseDatabaseService, private dialog: MatDialog, private ar: ActivatedRoute, private router: Router) { }

  trackByGroup(index: number, item: any) {
    return index
  }
}


================================================
FILE: src/client/app/pages/pages.module.ts
================================================
import { PagesRoutingModule } from './pages-routing.module'
import { PagesComponent } from './pages.component'
import { NgModule } from '@angular/core'
import { SharedModule } from '../shared/shared.module'
import { PageFormComponent } from './page-form/page-form.component'

@NgModule({
  imports: [PagesRoutingModule, SharedModule],
  declarations: [PagesComponent, PageFormComponent],
  exports: [PagesComponent],
  entryComponents: [PageFormComponent]
})
export class PagesModule { }


================================================
FILE: src/client/app/shared/cache-form/cache-form.component.html
================================================
<form *ngIf="form" [formGroup]="form" fxLayout="column">
  <mat-checkbox *ngFor="let dir of dirsNoInput; trackBy: trackByDirsNoInput" [formControlName]="dir.key">{{ dir.key }}</mat-checkbox>
  <div *ngFor="let dir of dirsWithInput; trackBy: trackByDirsWithInput">
    <mat-checkbox [formControlName]="dir.key">{{ dir.key }}</mat-checkbox>
    <mat-form-field floatPlaceholder="never" *ngIf="form.get(dir.key).value">
      <input matInput [placeholder]="dir.inputKey" type="text" [formControlName]="dir.inputKey">
    </mat-form-field>
  </div>
</form>

================================================
FILE: src/client/app/shared/cache-form/cache-form.component.scss
================================================
:host {

}

================================================
FILE: src/client/app/shared/cache-form/cache-form.component.ts
================================================
import { Subscription } from 'rxjs/Subscription'
import { FormControl, FormGroup } from '@angular/forms'
import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'
// tslint:disable-next-line:no-require-imports
import ms = require('ms')

@Component({
  selector: 'pm-cache-form',
  templateUrl: './cache-form.component.html',
  styleUrls: ['./cache-form.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class CacheFormComponent implements OnDestroy, OnInit {
  private _cache: { [key: string]: boolean | number | string }
  @Input() set cache(val: any) {
    this._cache = val
  }
  get cache() {
    return this._cache || {}
  }
  @Output() cacheChange = new EventEmitter<{ [key: string]: boolean | number | string }>()
  @Output() cacheStringChange = this.cacheChange.asObservable()
    .scan((acc: string, value) => Object.keys(value).map(a => {
      return typeof value[a] === 'number' || typeof value[a] === 'string'
        ? `${a}=${value[a]}`
        : a
    }).join(', '), '')

  public form: FormGroup
  private sub = new Subscription()
  private readonly staticDirectives: ReadonlyArray<{ readonly key: string, readonly hasInput?: boolean }> = [
    { key: 'no-cache' },
    { key: 'no-store' },
    { key: 'no-transform' },
    { key: 'only-if-cached' },
    { key: 'must-revalidate' },
    { key: 'public' },
    { key: 'private' },
    { key: 'proxy-revalidate' },
    { key: 'max-age', hasInput: true },
    { key: 's-maxage', hasInput: true },
    { key: 'max-stale', hasInput: true },
    { key: 'min-fresh', hasInput: true }
  ]

  public readonly dirsNoInput: ReadonlyArray<{ readonly key: string, readonly hasInput?: boolean, readonly inputKey?: string }> =
    this.staticDirectives
      .filter(a => !a.hasInput)

  public readonly dirsWithInput = this.staticDirectives
    .filter(a => a.hasInput)
    .map(a => ({ ...a, inputKey: this.getInputKey(a.key) }))

  getInputKey(key: string) {
    return `${key}-input`
  }

  removeInputKey(key: string) {
    return key.replace('-input', '')
  }

  ngOnInit() {
    this.form = new FormGroup(this.staticDirectives.reduce((a, c) => {
      if (!c.hasInput) return ({ ...a, [c.key]: new FormControl(this.cache[c.key], []) })
      return {
        ...a,
        [c.key]: new FormControl(this.cache[c.key], []),
        [this.getInputKey(c.key)]: new FormControl(this.cache[c.key], [])
      }
    }, {}))

    this.sub = this.form.valueChanges
      .scan((acc, value) => Object.keys(value)
        .filter(a => value[a])
        .reduce((a, c) => {
          if (typeof value[c] === 'string' && !value[this.removeInputKey(c)]) return ({ ...a })
          return typeof value[c] === 'string'
            ? { ...a, [this.removeInputKey(c)]: this.compute(value[c]).toString() }
            : { ...a, [c]: value[c] }
        }, {}), {})
      .subscribe(res => this.cacheChange.next(res))
  }

  ngOnDestroy() {
    this.sub.unsubscribe()
  }

  compute(entry: string): number {
    if (!isNaN(+entry)) return +entry
    try {
      return ms(entry) / 1000
    } catch (err) {
      return 0
    }
  }

  trackByDirsNoInput(index: number, item: any) {
    return index
  }

  trackByDirsWithInput(index: number, item: any) {
    return index
  }
}


================================================
FILE: src/client/app/shared/directives/avatar.directive.ts
================================================


================================================
FILE: src/client/app/shared/di
Download .txt
gitextract_3ok5m6pt/

├── .editorconfig
├── .firebaserc
├── .gitignore
├── .stylelintrc
├── .vscode/
│   ├── extensions.json
│   └── settings.json
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── Procfile
├── README.md
├── app.json
├── circle.yml
├── codecov.yml
├── data/
│   ├── security.rules.json
│   ├── seed.settings.json
│   └── seed.superusers.json
├── docs/
│   ├── angular-universal.md
│   ├── api-server.md
│   └── openid-server.md
├── e2e-spec.json
├── firebase.json
├── fuse.ts
├── package.json
├── src/
│   ├── client/
│   │   ├── app/
│   │   │   ├── __snapshots__/
│   │   │   │   └── app.component.spec.ts.snap
│   │   │   ├── about/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   └── about.component.spec.ts.snap
│   │   │   │   ├── about-routing.module.ts
│   │   │   │   ├── about.component.e2e-spec.ts
│   │   │   │   ├── about.component.html
│   │   │   │   ├── about.component.scss
│   │   │   │   ├── about.component.spec.ts
│   │   │   │   ├── about.component.ts
│   │   │   │   └── about.module.ts
│   │   │   ├── account/
│   │   │   │   ├── account-routing.module.ts
│   │   │   │   ├── account.component.html
│   │   │   │   ├── account.component.scss
│   │   │   │   ├── account.component.ts
│   │   │   │   └── account.module.ts
│   │   │   ├── admin/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   └── admin.component.spec.ts.snap
│   │   │   │   ├── admin-routing.module.ts
│   │   │   │   ├── admin.component.e2e-spec.ts
│   │   │   │   ├── admin.component.html
│   │   │   │   ├── admin.component.scss
│   │   │   │   ├── admin.component.spec.ts
│   │   │   │   ├── admin.component.ts
│   │   │   │   └── admin.module.ts
│   │   │   ├── app-routing.module.ts
│   │   │   ├── app.browser.module.ts
│   │   │   ├── app.component.html
│   │   │   ├── app.component.scss
│   │   │   ├── app.component.spec.ts
│   │   │   ├── app.component.ts
│   │   │   ├── app.config.ts
│   │   │   ├── app.module.ts
│   │   │   ├── changelog/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   └── changelog.component.spec.ts.snap
│   │   │   │   ├── changelog-routing.module.ts
│   │   │   │   ├── changelog.component.e2e-spec.ts
│   │   │   │   ├── changelog.component.html
│   │   │   │   ├── changelog.component.scss
│   │   │   │   ├── changelog.component.spec.ts
│   │   │   │   ├── changelog.component.ts
│   │   │   │   └── changelog.module.ts
│   │   │   ├── dashboard/
│   │   │   │   ├── dashboard-menu.ts
│   │   │   │   ├── dashboard-routing.module.ts
│   │   │   │   ├── dashboard.component.html
│   │   │   │   ├── dashboard.component.scss
│   │   │   │   ├── dashboard.component.ts
│   │   │   │   ├── dashboard.module.ts
│   │   │   │   ├── footer/
│   │   │   │   │   ├── __snapshots__/
│   │   │   │   │   │   └── dashboard-page-footer.component.spec.ts.snap
│   │   │   │   │   ├── dashboard-page-footer.component.html
│   │   │   │   │   ├── dashboard-page-footer.component.scss
│   │   │   │   │   ├── dashboard-page-footer.component.spec.ts
│   │   │   │   │   └── dashboard-page-footer.component.ts
│   │   │   │   ├── header/
│   │   │   │   │   ├── __snapshots__/
│   │   │   │   │   │   └── dashboard-page-header.component.spec.ts.snap
│   │   │   │   │   ├── dashboard-page-header.component.html
│   │   │   │   │   ├── dashboard-page-header.component.scss
│   │   │   │   │   ├── dashboard-page-header.component.spec.ts
│   │   │   │   │   └── dashboard-page-header.component.ts
│   │   │   │   ├── test/
│   │   │   │   │   ├── __snapshots__/
│   │   │   │   │   │   └── test.component.spec.ts.snap
│   │   │   │   │   ├── test-routing.module.ts
│   │   │   │   │   ├── test.component.html
│   │   │   │   │   ├── test.component.scss
│   │   │   │   │   ├── test.component.spec.ts
│   │   │   │   │   ├── test.component.ts
│   │   │   │   │   ├── test.module.ts
│   │   │   │   │   ├── test.service.ts
│   │   │   │   │   ├── testChild/
│   │   │   │   │   │   ├── __snapshots__/
│   │   │   │   │   │   │   └── testChild.component.spec.ts.snap
│   │   │   │   │   │   ├── testChild.component.html
│   │   │   │   │   │   ├── testChild.component.scss
│   │   │   │   │   │   ├── testChild.component.spec.ts
│   │   │   │   │   │   └── testChild.component.ts
│   │   │   │   │   └── testChild1/
│   │   │   │   │       ├── __snapshots__/
│   │   │   │   │       │   └── testChild1.component.spec.ts.snap
│   │   │   │   │       ├── testChild1.component.html
│   │   │   │   │       ├── testChild1.component.scss
│   │   │   │   │       ├── testChild1.component.spec.ts
│   │   │   │   │       └── testChild1.component.ts
│   │   │   │   └── test1/
│   │   │   │       ├── __snapshots__/
│   │   │   │       │   └── test1.component.spec.ts.snap
│   │   │   │       ├── test1-routing.module.ts
│   │   │   │       ├── test1.component.html
│   │   │   │       ├── test1.component.scss
│   │   │   │       ├── test1.component.spec.ts
│   │   │   │       ├── test1.component.ts
│   │   │   │       └── test1.module.ts
│   │   │   ├── home/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   └── home.component.spec.ts.snap
│   │   │   │   ├── home-routing.module.ts
│   │   │   │   ├── home.component.e2e-spec.ts
│   │   │   │   ├── home.component.html
│   │   │   │   ├── home.component.scss
│   │   │   │   ├── home.component.spec.ts
│   │   │   │   ├── home.component.ts
│   │   │   │   └── home.module.ts
│   │   │   ├── login/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   └── login.component.spec.ts.snap
│   │   │   │   ├── login-routing.module.ts
│   │   │   │   ├── login.component.e2e-spec.ts
│   │   │   │   ├── login.component.html
│   │   │   │   ├── login.component.scss
│   │   │   │   ├── login.component.spec.ts
│   │   │   │   ├── login.component.ts
│   │   │   │   └── login.module.ts
│   │   │   ├── logout/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   └── logout.component.spec.ts.snap
│   │   │   │   ├── logout-routing.module.ts
│   │   │   │   ├── logout.component.e2e-spec.ts
│   │   │   │   ├── logout.component.html
│   │   │   │   ├── logout.component.scss
│   │   │   │   ├── logout.component.spec.ts
│   │   │   │   ├── logout.component.ts
│   │   │   │   └── logout.module.ts
│   │   │   ├── not-found/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   └── not-found.component.spec.ts.snap
│   │   │   │   ├── not-found-routing.module.ts
│   │   │   │   ├── not-found.component.e2e-spec.ts
│   │   │   │   ├── not-found.component.html
│   │   │   │   ├── not-found.component.scss
│   │   │   │   ├── not-found.component.spec.ts
│   │   │   │   ├── not-found.component.ts
│   │   │   │   └── not-found.module.ts
│   │   │   ├── pages/
│   │   │   │   ├── page-form/
│   │   │   │   │   ├── page-form.component.html
│   │   │   │   │   ├── page-form.component.scss
│   │   │   │   │   └── page-form.component.ts
│   │   │   │   ├── pages-routing.module.ts
│   │   │   │   ├── pages.component.html
│   │   │   │   ├── pages.component.scss
│   │   │   │   ├── pages.component.ts
│   │   │   │   └── pages.module.ts
│   │   │   ├── shared/
│   │   │   │   ├── cache-form/
│   │   │   │   │   ├── cache-form.component.html
│   │   │   │   │   ├── cache-form.component.scss
│   │   │   │   │   └── cache-form.component.ts
│   │   │   │   ├── directives/
│   │   │   │   │   ├── avatar.directive.ts
│   │   │   │   │   ├── click-outside.directive.ts
│   │   │   │   │   ├── html-outlet.directive.ts
│   │   │   │   │   └── social-button.directive.ts
│   │   │   │   ├── http-cache-tag/
│   │   │   │   │   ├── http-cache-tag-interceptor.service.spec.ts
│   │   │   │   │   ├── http-cache-tag-interceptor.service.ts
│   │   │   │   │   └── http-cache-tag.module.ts
│   │   │   │   ├── injection-form/
│   │   │   │   │   ├── injection-form.component.html
│   │   │   │   │   ├── injection-form.component.scss
│   │   │   │   │   └── injection-form.component.ts
│   │   │   │   ├── key-value-form/
│   │   │   │   │   ├── key-value-form.component.html
│   │   │   │   │   ├── key-value-form.component.scss
│   │   │   │   │   └── key-value-form.component.ts
│   │   │   │   ├── login-card/
│   │   │   │   │   ├── login-card.component.html
│   │   │   │   │   ├── login-card.component.scss
│   │   │   │   │   └── login-card.component.ts
│   │   │   │   ├── material.module.ts
│   │   │   │   ├── modal-confirmation/
│   │   │   │   │   ├── modal-confirmation.component.html
│   │   │   │   │   ├── modal-confirmation.component.scss
│   │   │   │   │   └── modal-confirmation.component.ts
│   │   │   │   ├── navbar/
│   │   │   │   │   ├── __snapshots__/
│   │   │   │   │   │   └── navbar.component.spec.ts.snap
│   │   │   │   │   ├── navbar.component.html
│   │   │   │   │   ├── navbar.component.scss
│   │   │   │   │   ├── navbar.component.spec.ts
│   │   │   │   │   ├── navbar.component.ts
│   │   │   │   │   ├── navbar.service.spec.ts
│   │   │   │   │   └── navbar.service.ts
│   │   │   │   ├── pipes/
│   │   │   │   │   ├── key-value.pipe.ts
│   │   │   │   │   ├── keys.pipe.ts
│   │   │   │   │   └── sanitize-html.pipe.ts
│   │   │   │   ├── quill-editor/
│   │   │   │   │   ├── quill-editor.component.html
│   │   │   │   │   ├── quill-editor.component.scss
│   │   │   │   │   └── quill-editor.component.ts
│   │   │   │   ├── services/
│   │   │   │   │   ├── __snapshots__/
│   │   │   │   │   │   └── error-handler.service.spec.ts.snap
│   │   │   │   │   ├── adblock.service.spec.ts
│   │   │   │   │   ├── adblock.service.ts
│   │   │   │   │   ├── auth.service.ts
│   │   │   │   │   ├── cookie.service.spec.ts
│   │   │   │   │   ├── cookie.service.ts
│   │   │   │   │   ├── environment.service.spec.ts
│   │   │   │   │   ├── environment.service.ts
│   │   │   │   │   ├── error-handler.service.spec.ts
│   │   │   │   │   ├── error-handler.service.ts
│   │   │   │   │   ├── firebase-database.service.ts
│   │   │   │   │   ├── guard-admin.service.ts
│   │   │   │   │   ├── guard-login.service.ts
│   │   │   │   │   ├── http-config-interceptor.service.spec.ts
│   │   │   │   │   ├── http-config-interceptor.service.ts
│   │   │   │   │   ├── http-cookie-interceptor.service.spec.ts
│   │   │   │   │   ├── http-cookie-interceptor.service.ts
│   │   │   │   │   ├── injection.service.ts
│   │   │   │   │   ├── logging.service.spec.ts
│   │   │   │   │   ├── logging.service.ts
│   │   │   │   │   ├── minifier.service.ts
│   │   │   │   │   ├── platform.service.spec.ts
│   │   │   │   │   ├── platform.service.ts
│   │   │   │   │   ├── seo.service.ts
│   │   │   │   │   ├── server-response.service.spec.ts
│   │   │   │   │   ├── server-response.service.ts
│   │   │   │   │   ├── setting.service.spec.ts
│   │   │   │   │   ├── setting.service.ts
│   │   │   │   │   └── web-socket.service.ts
│   │   │   │   ├── shared.module.ts
│   │   │   │   ├── style-injection-form/
│   │   │   │   │   ├── style-injection-form.component.html
│   │   │   │   │   ├── style-injection-form.component.scss
│   │   │   │   │   └── style-injection-form.component.ts
│   │   │   │   └── web-app-installer/
│   │   │   │       ├── web-app-installer.component.html
│   │   │   │       ├── web-app-installer.component.scss
│   │   │   │       ├── web-app-installer.component.ts
│   │   │   │       ├── web-app-installer.module.ts
│   │   │   │       └── web-app-installer.service.ts
│   │   │   ├── signup/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   └── signup.component.spec.ts.snap
│   │   │   │   ├── signup-routing.module.ts
│   │   │   │   ├── signup.component.e2e-spec.ts
│   │   │   │   ├── signup.component.html
│   │   │   │   ├── signup.component.scss
│   │   │   │   ├── signup.component.spec.ts
│   │   │   │   ├── signup.component.ts
│   │   │   │   └── signup.module.ts
│   │   │   ├── unauthorized/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   └── unauthorized.component.spec.ts.snap
│   │   │   │   ├── unauthorized-routing.module.ts
│   │   │   │   ├── unauthorized.component.html
│   │   │   │   ├── unauthorized.component.scss
│   │   │   │   ├── unauthorized.component.spec.ts
│   │   │   │   ├── unauthorized.component.ts
│   │   │   │   └── unauthorized.module.ts
│   │   │   └── users/
│   │   │       ├── __snapshots__/
│   │   │       │   └── users.component.spec.ts.snap
│   │   │       ├── users-routing.module.ts
│   │   │       ├── users.component.html
│   │   │       ├── users.component.scss
│   │   │       ├── users.component.spec.ts
│   │   │       ├── users.component.ts
│   │   │       └── users.module.ts
│   │   ├── index.html
│   │   ├── main-prod.ts
│   │   ├── main.aot-prod.ts
│   │   ├── main.aot.ts
│   │   ├── main.ts
│   │   ├── ngsw.json
│   │   ├── operators.ts
│   │   ├── polyfills.ts
│   │   └── styles/
│   │       ├── main.scss
│   │       └── material2-app-themes.scss
│   ├── server/
│   │   ├── api/
│   │   │   ├── api.spec.ts
│   │   │   ├── controllers/
│   │   │   │   ├── index.ts
│   │   │   │   ├── settings.controller.spec.ts
│   │   │   │   └── settings.controller.ts
│   │   │   ├── index.ts
│   │   │   ├── middlewares/
│   │   │   │   ├── index.ts
│   │   │   │   └── zone-error-handler.ts
│   │   │   ├── repositories/
│   │   │   │   ├── index.ts
│   │   │   │   ├── setting.repository.ts
│   │   │   │   └── settings.ts
│   │   │   ├── services/
│   │   │   │   ├── index.ts
│   │   │   │   └── setting.service.ts
│   │   │   └── test-helper.ts
│   │   ├── server.angular-fire.service.ts
│   │   ├── server.angular.module.ts
│   │   ├── server.config.ts
│   │   ├── server.sitemap.ts
│   │   ├── server.ts
│   │   ├── server.web-socket.ts
│   │   └── service-account.json
│   ├── testing/
│   │   ├── app-testing.module.ts
│   │   ├── mock-cookie.service.ts
│   │   ├── mock-environment.service.ts
│   │   └── mock-firebase-database.service.ts
│   ├── tsconfig.json
│   └── tslint.json
├── tools/
│   ├── config/
│   │   ├── app.config.ts
│   │   ├── build.ci.replace.ts
│   │   ├── build.config.ts
│   │   ├── build.interfaces.ts
│   │   └── console.banner.256.txt
│   ├── env/
│   │   ├── base.ts
│   │   ├── dev.ts
│   │   ├── e2e.ts
│   │   └── prod.ts
│   ├── manual-typings/
│   │   ├── README.md
│   │   ├── project/
│   │   │   └── sample.package.d.ts
│   │   └── seed/
│   │       ├── bunyan.d.ts
│   │       ├── hash-files.d.ts
│   │       ├── json.d.ts
│   │       └── loglevel-std-streams.d.ts
│   ├── plugins/
│   │   ├── ng-aot.ts
│   │   ├── pwa-fused.ts
│   │   └── web-index.ts
│   ├── scripts/
│   │   ├── post-merge.sh
│   │   └── replace.ts
│   ├── tasks/
│   │   ├── index.ts
│   │   ├── project/
│   │   │   └── sample.ts
│   │   └── seed/
│   │       ├── assets.ts
│   │       ├── banner.ts
│   │       ├── changelog.ts
│   │       ├── clean.ts
│   │       ├── config.ts
│   │       ├── favicons.ts
│   │       ├── fonts.ts
│   │       ├── index.copy.ts
│   │       ├── index.minify.ts
│   │       ├── lint.ts
│   │       ├── mk-dist.ts
│   │       ├── ngc.ts
│   │       ├── ngsw-json.ts
│   │       ├── ngsw-worker.min.ts
│   │       ├── ngsw-worker.ts
│   │       ├── ngsw.ts
│   │       ├── sass.files.ts
│   │       ├── sass.ts
│   │       ├── serve.ts
│   │       └── web.ts
│   ├── test/
│   │   ├── jest.e2e-setup.ts
│   │   ├── jest.mocks.ts
│   │   └── jest.setup.ts
│   ├── tslint-rules/
│   │   └── validateDecoratorsRule.ts
│   └── web/
│       ├── ping.html
│       └── robots.txt
├── tsconfig-aot.json
├── tsconfig-e2e.json
└── tsconfig.json
Download .txt
SYMBOL INDEX (444 symbols across 143 files)

FILE: src/client/app/about/about-routing.module.ts
  class AboutRoutingModule (line 29) | class AboutRoutingModule { }

FILE: src/client/app/about/about.component.spec.ts
  class TestComponent (line 7) | @Component({

FILE: src/client/app/about/about.component.ts
  class AboutComponent (line 12) | class AboutComponent {
    method constructor (line 31) | constructor(private db: FirebaseDatabaseService, ps: PlatformService) { }
    method create (line 33) | create() {
    method removeAll (line 37) | removeAll() {
    method trackByPost (line 41) | trackByPost(index: number, item: any) {

FILE: src/client/app/about/about.module.ts
  class AboutModule (line 11) | class AboutModule { }

FILE: src/client/app/account/account-routing.module.ts
  class AccountRoutingModule (line 30) | class AccountRoutingModule { }

FILE: src/client/app/account/account.component.ts
  class AccountComponent (line 13) | class AccountComponent {
    method constructor (line 56) | constructor(private auth: AuthService, private snackBar: MatSnackBar, ...
    method openSnackBar (line 99) | openSnackBar(message: string, action = 'dismiss') {
    method updateDetail (line 107) | updateDetail() {
    method updatePassword (line 118) | updatePassword() {

FILE: src/client/app/account/account.module.ts
  class AccountModule (line 11) | class AccountModule { }

FILE: src/client/app/admin/admin-routing.module.ts
  class AdminRoutingModule (line 29) | class AdminRoutingModule { }

FILE: src/client/app/admin/admin.component.spec.ts
  class TestComponent (line 34) | @Component({

FILE: src/client/app/admin/admin.component.ts
  class AdminComponent (line 9) | class AdminComponent {

FILE: src/client/app/admin/admin.module.ts
  class AdminModule (line 11) | class AdminModule { }

FILE: src/client/app/app-routing.module.ts
  class AppRoutingModule (line 25) | class AppRoutingModule { }

FILE: src/client/app/app.browser.module.ts
  function getRequest (line 9) | function getRequest(transferState: TransferState): any {
  class AppBrowserModule (line 30) | class AppBrowserModule { }

FILE: src/client/app/app.component.spec.ts
  constant TESTING_CONFIG (line 23) | const TESTING_CONFIG: EnvConfig = {
  class TestComponent (line 37) | @Component({

FILE: src/client/app/app.component.ts
  class AppComponent (line 28) | class AppComponent implements AfterViewInit {
    method constructor (line 36) | constructor(ss: SettingService, analytics: Angulartics2GoogleAnalytics...
    method ngAfterViewInit (line 87) | ngAfterViewInit() {
    method handleOutsideClicks (line 101) | handleOutsideClicks() {

FILE: src/client/app/app.config.ts
  constant ENV_CONFIG (line 4) | const ENV_CONFIG = new InjectionToken<EnvConfig>('app.config')

FILE: src/client/app/app.module.ts
  constant REQ_KEY (line 24) | const REQ_KEY = makeStateKey<string>('req')
  function metaFactory (line 26) | function metaFactory(env: EnvironmentService, ss: SettingService): MetaL...
  function firebaseConfigLoader (line 53) | function firebaseConfigLoader(env: EnvironmentService) {
  function firebaseAppNameLoader (line 57) | function firebaseAppNameLoader(env: EnvironmentService) {
  function cacheTagFactory (line 61) | function cacheTagFactory(srs: ServerResponseService): any {
  class AppModule (line 122) | class AppModule { }

FILE: src/client/app/changelog/changelog-routing.module.ts
  class ChangelogRoutingModule (line 24) | class ChangelogRoutingModule { }

FILE: src/client/app/changelog/changelog.component.spec.ts
  class TestComponent (line 7) | @Component({

FILE: src/client/app/changelog/changelog.component.ts
  class ChangelogComponent (line 11) | class ChangelogComponent {
    method constructor (line 15) | constructor(private http: HttpClient) { }

FILE: src/client/app/changelog/changelog.module.ts
  class ChangelogModule (line 11) | class ChangelogModule { }

FILE: src/client/app/dashboard/dashboard-menu.ts
  constant DASHBOARD_MENU (line 1) | const DASHBOARD_MENU = [

FILE: src/client/app/dashboard/dashboard-routing.module.ts
  class DashboardRoutingModule (line 27) | class DashboardRoutingModule { }

FILE: src/client/app/dashboard/dashboard.component.ts
  class DashboardComponent (line 12) | class DashboardComponent implements OnInit {
    method onResize (line 23) | onResize(event: any) {
    method constructor (line 32) | constructor(private title: Title) { }
    method ngOnInit (line 34) | ngOnInit() {
    method toggleSidenav (line 39) | toggleSidenav(event: any) {
    method setPageTitle (line 43) | setPageTitle(title: string) {
    method trackByMenu (line 47) | trackByMenu(index: number, item: any) {
    method trackByChild (line 51) | trackByChild(index: number, item: any) {

FILE: src/client/app/dashboard/dashboard.module.ts
  class DashboardModule (line 14) | class DashboardModule { }

FILE: src/client/app/dashboard/footer/dashboard-page-footer.component.spec.ts
  class TestComponent (line 33) | @Component({

FILE: src/client/app/dashboard/footer/dashboard-page-footer.component.ts
  class DashboardPageFooterComponent (line 9) | class DashboardPageFooterComponent {

FILE: src/client/app/dashboard/header/dashboard-page-header.component.spec.ts
  class TestComponent (line 33) | @Component({

FILE: src/client/app/dashboard/header/dashboard-page-header.component.ts
  class DashboardPageHeaderComponent (line 9) | class DashboardPageHeaderComponent {
    method toggle (line 15) | toggle() {

FILE: src/client/app/dashboard/test/test-routing.module.ts
  class TestRoutingModule (line 45) | class TestRoutingModule { }

FILE: src/client/app/dashboard/test/test.component.spec.ts
  class TestingComponent (line 62) | @Component({

FILE: src/client/app/dashboard/test/test.component.ts
  class TestComponent (line 9) | class TestComponent {

FILE: src/client/app/dashboard/test/test.module.ts
  class TestModule (line 13) | class TestModule { }

FILE: src/client/app/dashboard/test/test.service.ts
  class TestService (line 4) | class TestService {

FILE: src/client/app/dashboard/test/testChild/testChild.component.spec.ts
  class TestComponent (line 33) | @Component({

FILE: src/client/app/dashboard/test/testChild/testChild.component.ts
  class TestChildComponent (line 9) | class TestChildComponent {

FILE: src/client/app/dashboard/test/testChild1/testChild1.component.spec.ts
  class TestComponent (line 33) | @Component({

FILE: src/client/app/dashboard/test/testChild1/testChild1.component.ts
  class TestChild1Component (line 9) | class TestChild1Component {

FILE: src/client/app/dashboard/test1/test1-routing.module.ts
  class Test1RoutingModule (line 25) | class Test1RoutingModule { }

FILE: src/client/app/dashboard/test1/test1.component.spec.ts
  class TestComponent (line 33) | @Component({

FILE: src/client/app/dashboard/test1/test1.component.ts
  class Test1Component (line 9) | class Test1Component {

FILE: src/client/app/dashboard/test1/test1.module.ts
  class Test1Module (line 11) | class Test1Module { }

FILE: src/client/app/home/home-routing.module.ts
  class HomeRoutingModule (line 34) | class HomeRoutingModule { }

FILE: src/client/app/home/home.component.spec.ts
  class TestComponent (line 49) | @Component({

FILE: src/client/app/home/home.component.ts
  class HomeComponent (line 9) | class HomeComponent {

FILE: src/client/app/home/home.module.ts
  class HomeModule (line 11) | class HomeModule { }

FILE: src/client/app/login/login-routing.module.ts
  class LoginRoutingModule (line 24) | class LoginRoutingModule { }

FILE: src/client/app/login/login.component.spec.ts
  class TestComponent (line 43) | @Component({

FILE: src/client/app/login/login.component.ts
  class LoginComponent (line 9) | class LoginComponent {

FILE: src/client/app/login/login.module.ts
  class LoginModule (line 11) | class LoginModule { }

FILE: src/client/app/logout/logout-routing.module.ts
  class LogoutRoutingModule (line 24) | class LogoutRoutingModule { }

FILE: src/client/app/logout/logout.component.spec.ts
  class TestComponent (line 39) | @Component({

FILE: src/client/app/logout/logout.component.ts
  class LogoutComponent (line 12) | class LogoutComponent {
    method constructor (line 13) | constructor(afAuth: AngularFireAuth, cs: CookieService, ps: PlatformSe...

FILE: src/client/app/logout/logout.module.ts
  class LogoutModule (line 11) | class LogoutModule { }

FILE: src/client/app/not-found/not-found-routing.module.ts
  class NotFoundRoutingModule (line 22) | class NotFoundRoutingModule { }

FILE: src/client/app/not-found/not-found.component.spec.ts
  class TestComponent (line 13) | @Component({
  method get (line 32) | get() {

FILE: src/client/app/not-found/not-found.component.ts
  constant COMMA (line 17) | const COMMA = 188
  type Page (line 19) | interface Page {
  type types (line 33) | type types = 'script' | 'style'
  type InjectionMap (line 34) | interface InjectionMap { readonly [key: string]: { readonly type: types,...
  class NotFoundComponent (line 42) | class NotFoundComponent {
    method injectionFormChange (line 62) | injectionFormChange(key: string, type: types, injectable: DOMInjectabl...
    method addInjectable (line 73) | addInjectable(type: types) {
    method insertInjectable (line 83) | insertInjectable(key: string, type: types, injectable: DOMInjectable) {
    method removeInjectable (line 93) | removeInjectable(key: string) {
    method add (line 102) | add(event: MatChipInputEvent): void {
    method remove (line 110) | remove(tag: any): void {
    method updateTags (line 115) | updateTags() {
    method updateTabParam (line 119) | updateTabParam(tab: number) {
    method publish (line 248) | publish() {
    method showSnack (line 270) | showSnack(message: string) {
    method confirmDelete (line 278) | confirmDelete() {
    method delete (line 291) | delete() {
    method viewCurrent (line 304) | viewCurrent() {
    method edit (line 310) | edit() {
    method constructor (line 316) | constructor(private rs: ServerResponseService, private db: FirebaseDat...
    method updateCache (line 321) | updateCache(cache: any) {
    method trackByInjection (line 325) | trackByInjection(index: number, item: any) {
    method trackByTag (line 329) | trackByTag(index: number, item: string) {

FILE: src/client/app/not-found/not-found.module.ts
  class NotFoundModule (line 11) | class NotFoundModule { }

FILE: src/client/app/pages/page-form/page-form.component.ts
  class PageFormComponent (line 13) | class PageFormComponent {
    method validateSlugNotTaken (line 32) | validateSlugNotTaken(control: AbstractControl) {
    method create (line 41) | create() {
    method constructor (line 57) | constructor(private db: FirebaseDatabaseService, public dialog: MatDia...

FILE: src/client/app/pages/pages-routing.module.ts
  class PagesRoutingModule (line 29) | class PagesRoutingModule { }

FILE: src/client/app/pages/pages.component.ts
  class PagesComponent (line 15) | class PagesComponent {
    method openDialog (line 42) | openDialog() {
    method confirmDelete (line 51) | confirmDelete() {
    method delete (line 64) | delete(group: string, slug: string) {
    method updateTabParam (line 79) | updateTabParam(tab: number) {
    method constructor (line 83) | constructor(private db: FirebaseDatabaseService, private dialog: MatDi...
    method trackByGroup (line 85) | trackByGroup(index: number, item: any) {

FILE: src/client/app/pages/pages.module.ts
  class PagesModule (line 13) | class PagesModule { }

FILE: src/client/app/shared/cache-form/cache-form.component.ts
  class CacheFormComponent (line 13) | class CacheFormComponent implements OnDestroy, OnInit {
    method cache (line 15) | set cache(val: any) {
    method cache (line 18) | get cache() {
    method getInputKey (line 54) | getInputKey(key: string) {
    method removeInputKey (line 58) | removeInputKey(key: string) {
    method ngOnInit (line 62) | ngOnInit() {
    method ngOnDestroy (line 84) | ngOnDestroy() {
    method compute (line 88) | compute(entry: string): number {
    method trackByDirsNoInput (line 97) | trackByDirsNoInput(index: number, item: any) {
    method trackByDirsWithInput (line 101) | trackByDirsWithInput(index: number, item: any) {

FILE: src/client/app/shared/directives/click-outside.directive.ts
  class ClickOutsideDirective (line 6) | class ClickOutsideDirective {
    method constructor (line 10) | constructor(private elementRef: ElementRef) { }
    method onClick (line 13) | public onClick(event: MouseEvent, targetElement: any): void {

FILE: src/client/app/shared/directives/html-outlet.directive.ts
  function createComponentFactory (line 20) | function createComponentFactory(compiler: Compiler, metadata: Component)...
  class HtmlOutletDirective (line 38) | class HtmlOutletDirective implements OnChanges, OnDestroy {
    method constructor (line 42) | constructor(private vcRef: ViewContainerRef, private compiler: Compile...
    method ngOnChanges (line 44) | ngOnChanges() {
    method ngOnDestroy (line 66) | ngOnDestroy() {

FILE: src/client/app/shared/directives/social-button.directive.ts
  class SocialButtonDirective (line 6) | class SocialButtonDirective implements OnInit {
    method onMouseEnter (line 9) | onMouseEnter() {
    method onMouseLeave (line 13) | onMouseLeave() {
    method constructor (line 17) | constructor(private elementRef: ElementRef) { }
    method ngOnInit (line 26) | ngOnInit() {
    method setBaseSyles (line 30) | setBaseSyles(provider: string) {
    method getHover (line 37) | getHover(provider: string) {

FILE: src/client/app/shared/http-cache-tag/http-cache-tag-interceptor.service.spec.ts
  class ExpressResponse (line 12) | class ExpressResponse {
    method getHeader (line 14) | getHeader(key: string) {
    method header (line 18) | header(key: string, value: string) {
  function testDeps (line 23) | function testDeps() {

FILE: src/client/app/shared/http-cache-tag/http-cache-tag-interceptor.service.ts
  class HttpCacheTagInterceptor (line 6) | class HttpCacheTagInterceptor implements HttpInterceptor {
    method constructor (line 8) | constructor( @Inject(CACHE_TAG_CONFIG) private config: CacheTagConfig,
    method isCacheableCode (line 14) | isCacheableCode(code: number) {
    method isCacheableUrl (line 18) | isCacheableUrl(url: string | null) {
    method intercept (line 23) | intercept(req: HttpRequest<any>, next: HttpHandler) {

FILE: src/client/app/shared/http-cache-tag/http-cache-tag.module.ts
  constant CACHE_TAG_CONFIG (line 5) | const CACHE_TAG_CONFIG = new InjectionToken<CacheTagConfig>('app.config....
  constant CACHE_TAG_FACTORY (line 6) | const CACHE_TAG_FACTORY = new InjectionToken<CacheFactory>('app.config.h...
  type CacheTagConfig (line 8) | interface CacheTagConfig {
  type CacheFactory (line 14) | type CacheFactory = (httpResponse: HttpResponse<any>, config: CacheTagCo...
  class HttpCacheTagModule (line 17) | class HttpCacheTagModule {
    method forRoot (line 18) | static forRoot(configProvider: any, factoryProvider: any): ModuleWithP...
    method constructor (line 34) | constructor( @Optional() @SkipSelf() parentModule: HttpCacheTagModule) {

FILE: src/client/app/shared/injection-form/injection-form.component.ts
  class InjectionFormComponent (line 13) | class InjectionFormComponent implements OnInit, OnDestroy {
    method htmlString (line 22) | get htmlString() {
    method constructor (line 26) | constructor(private renderer: Renderer2, private inj: InjectionService...
    method ngOnInit (line 28) | ngOnInit() {
    method ngOnDestroy (line 41) | ngOnDestroy() {
    method attributesChanged (line 45) | attributesChanged(attrs: any) {

FILE: src/client/app/shared/key-value-form/key-value-form.component.ts
  class KeyValueFormComponent (line 11) | class KeyValueFormComponent implements OnChanges {
    method ngOnChanges (line 20) | ngOnChanges(changes: SimpleChanges) {
    method add (line 26) | add(obj: { key: string, value: string }) {
    method remove (line 33) | remove(key: string) {
    method trackByFn (line 41) | trackByFn(index: number, item: any) {

FILE: src/client/app/shared/login-card/login-card.component.ts
  constant EMAIL_REGEX (line 9) | const EMAIL_REGEX = /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\...
  class LoginCardComponent (line 17) | class LoginCardComponent {
    method constructor (line 18) | constructor(private cd: ChangeDetectorRef, private auth: AuthService, ...
    method login (line 35) | login(provider: string) {
    method networkError (line 64) | networkError(err: any) {
    method socialNetworkError (line 72) | socialNetworkError(err: any) {

FILE: src/client/app/shared/material.module.ts
  class MaterialModule (line 68) | class MaterialModule { }

FILE: src/client/app/shared/modal-confirmation/modal-confirmation.component.ts
  class ModalConfirmationComponent (line 10) | class ModalConfirmationComponent {
    method constructor (line 14) | constructor(public dialog: MatDialogRef<ModalConfirmationComponent>, @...

FILE: src/client/app/shared/navbar/navbar.component.spec.ts
  class TestComponent (line 50) | @Component({

FILE: src/client/app/shared/navbar/navbar.component.ts
  type User (line 4) | interface User {
  class NavbarComponent (line 16) | class NavbarComponent {
    method click (line 17) | click() {
    method constructor (line 24) | constructor(public navbarService: NavbarService) { }
    method trackByFn (line 26) | trackByFn(index: number, item: any) {

FILE: src/client/app/shared/navbar/navbar.service.ts
  type INavbarService (line 4) | interface INavbarService {
  class NavbarService (line 9) | class NavbarService implements INavbarService {

FILE: src/client/app/shared/pipes/key-value.pipe.ts
  class KeyValuePipe (line 4) | class KeyValuePipe implements PipeTransform {
    method transform (line 5) | public transform(value: { readonly [key: string]: any }): ReadonlyArra...

FILE: src/client/app/shared/pipes/keys.pipe.ts
  class KeysPipe (line 4) | class KeysPipe implements PipeTransform {
    method transform (line 5) | public transform(value: { readonly [key: string]: any }): ReadonlyArra...

FILE: src/client/app/shared/pipes/sanitize-html.pipe.ts
  class SanitizeHtmlPipe (line 7) | class SanitizeHtmlPipe implements PipeTransform {
    method constructor (line 8) | constructor(private sanitizer: DomSanitizer) { }
    method transform (line 10) | transform(v: string): SafeHtml {

FILE: src/client/app/shared/quill-editor/quill-editor.component.ts
  class QuillEditorComponent (line 13) | class QuillEditorComponent implements AfterViewInit {
    method constructor (line 22) | constructor(injector: InjectionService, renderer: Renderer2, private p...
    method serverStyles (line 25) | get serverStyles() {
    method ngAfterViewInit (line 31) | ngAfterViewInit() {
    method update (line 66) | private update() {
    method html (line 70) | get html() {

FILE: src/client/app/shared/services/adblock.service.spec.ts
  class MockPlatformService (line 58) | class MockPlatformService implements IPlatformService {

FILE: src/client/app/shared/services/adblock.service.ts
  type IAdblockService (line 6) | interface IAdblockService {
  class AdblockService (line 11) | class AdblockService implements IAdblockService {
    method constructor (line 18) | constructor(private platformService: PlatformService, private http: Ht...

FILE: src/client/app/shared/services/auth.service.ts
  type ExtendedUser (line 16) | interface ExtendedUser {
  type IAuthService (line 29) | interface IAuthService {
  constant FB_COOKIE_KEY (line 35) | const FB_COOKIE_KEY = new InjectionToken<string>('auth.cookie.key')
  class AuthService (line 38) | class AuthService implements IAuthService {
    method cookieMapper (line 50) | static cookieMapper(data: any, jwtHelper: JwtHelper): any {
    method isAdmin (line 64) | public isAdmin(user: ExtendedUser) {
    method constructor (line 68) | constructor(private cs: CookieService, private fbAuth: AngularFireAuth...
    method signInWithFacebookRedirect (line 112) | signInWithFacebookRedirect() {
    method signInWithGoogleRedirect (line 116) | signInWithGoogleRedirect() {
    method signInWithGithubRedirect (line 120) | signInWithGithubRedirect() {
    method signInWithTwitterRedirect (line 124) | signInWithTwitterRedirect() {
    method createUserWithEmailAndPassword (line 128) | createUserWithEmailAndPassword(email: string, password: string) {
    method signInWithEmailAndPassword (line 132) | signInWithEmailAndPassword(email: string, password: string) {
    method redirectToSignInPage (line 136) | redirectToSignInPage() {
    method logout (line 140) | logout() {
    method refreshEmailCredentials (line 148) | refreshEmailCredentials(paswword: string) {
    method updateEmailPassword (line 158) | updateEmailPassword(currentPassword: string, newPassword: string) {
    method updateProfile (line 170) | updateProfile(displayName?: string, photoURL?: string) {

FILE: src/client/app/shared/services/cookie.service.ts
  type ICookieService (line 8) | interface ICookieService {
  class CookieService (line 17) | class CookieService implements ICookieService {
    method constructor (line 21) | constructor(private platformService: PlatformService, @Inject(REQUEST)...
    method set (line 23) | public set(name: string, value: any, options?: CookieAttributes): void {
    method remove (line 30) | public remove(name: string, options?: CookieAttributes): void {
    method get (line 37) | public get(name: string): any {
    method getAll (line 49) | public getAll(): any {
    method updateSource (line 57) | private updateSource() {

FILE: src/client/app/shared/services/environment.service.ts
  type IEnvironmentService (line 5) | interface IEnvironmentService {
  class EnvironmentService (line 10) | class EnvironmentService implements IEnvironmentService {
    method constructor (line 11) | constructor(@Inject(ENV_CONFIG) private _config: any) { }
    method config (line 12) | get config(): EnvConfig {

FILE: src/client/app/shared/services/error-handler.service.spec.ts
  class MockLoggingService (line 76) | class MockLoggingService implements ILoggingService {
    method error (line 77) | error(msg: string, errObj?: { [key: string]: any; } | undefined, exten...
    method trace (line 78) | trace(msg: string, errObj?: { [key: string]: any; } | undefined, exten...
    method debug (line 79) | debug(msg: string, errObj?: { [key: string]: any; } | undefined, exten...
    method info (line 80) | info(msg: string, errObj?: { [key: string]: any; } | undefined, extend...
    method warn (line 81) | warn(msg: string, errObj?: { [key: string]: any; } | undefined, extend...
  class MockEnvironmentService (line 84) | class MockEnvironmentService implements IEnvironmentService {

FILE: src/client/app/shared/services/error-handler.service.ts
  class GlobalErrorHandler (line 8) | class GlobalErrorHandler implements ErrorHandler {
    method constructor (line 9) | constructor(private injector: Injector) { }
    method handleError (line 11) | handleError(error: any) {

FILE: src/client/app/shared/services/firebase-database.service.ts
  class FirebaseDatabaseService (line 10) | class FirebaseDatabaseService {
    method constructor (line 11) | constructor(private db: AngularFireDatabase, private ts: TransferState...
    method get (line 13) | get<T>(path: string) {
    method getList (line 20) | getList<T>(path: PathReference, queryFn?: (ref: database.Reference) =>...
    method getListKeyed (line 27) | getListKeyed<T>(path: PathReference, queryFn?: (ref: database.Referenc...
    method keyMapper (line 40) | keyMapper(res: any) {
    method getListRef (line 50) | getListRef<T>(path: PathReference, queryFn?: (ref: database.Reference)...
    method getObjectRef (line 54) | getObjectRef<T>(path: string) {
    method cacheKey (line 58) | cacheKey(path: string) {

FILE: src/client/app/shared/services/guard-admin.service.ts
  class AdminGuard (line 9) | class AdminGuard implements CanActivate {
    method constructor (line 11) | constructor(private auth: AuthService, private router: Router, private...
    method canActivate (line 13) | canActivate(ars: ActivatedRouteSnapshot, state: RouterStateSnapshot): ...

FILE: src/client/app/shared/services/guard-login.service.ts
  class LoginGuard (line 8) | class LoginGuard implements CanActivate {
    method constructor (line 10) | constructor(private auth: AuthService) { }
    method canActivate (line 12) | canActivate(ars: ActivatedRouteSnapshot, state: RouterStateSnapshot): ...

FILE: src/client/app/shared/services/http-config-interceptor.service.spec.ts
  class MockEnvironmentService (line 99) | class MockEnvironmentService implements IEnvironmentService {
    method config (line 100) | get config() {
    method constructor (line 108) | constructor(public value?: any) { }

FILE: src/client/app/shared/services/http-config-interceptor.service.ts
  class HttpConfigInterceptor (line 7) | class HttpConfigInterceptor implements HttpInterceptor {
    method constructor (line 9) | constructor(private env: EnvironmentService) { }
    method intercept (line 11) | intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEv...

FILE: src/client/app/shared/services/http-cookie-interceptor.service.spec.ts
  class MockPlatformService (line 174) | class MockPlatformService implements IPlatformService {
    method constructor (line 176) | constructor(public isBrowser = true) { }

FILE: src/client/app/shared/services/http-cookie-interceptor.service.ts
  constant URL (line 9) | const URL = require('url-parse')
  constant COOKIE_HOST_WHITELIST (line 11) | const COOKIE_HOST_WHITELIST = new InjectionToken<string[]>('app.cookie.w...
  class HttpCookieInterceptor (line 14) | class HttpCookieInterceptor implements HttpInterceptor {
    method constructor (line 16) | constructor(private ps: PlatformService, private injector: Injector) { }
    method intercept (line 18) | intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEv...

FILE: src/client/app/shared/services/injection.service.ts
  type DOMInjectable (line 5) | interface DOMInjectable {
  class InjectionService (line 13) | class InjectionService {
    method constructor (line 14) | constructor(@Inject(DOCUMENT) private doc: any) { }
    method createElement (line 16) | createElement<T extends HTMLElement>(renderer: Renderer2, injectable: ...
    method getElementStringForm (line 30) | getElementStringForm(renderer: Renderer2, injectable: DOMInjectable | ...
    method inject (line 36) | inject(renderer: Renderer2, injectable: DOMInjectable) {
    method injectCollection (line 46) | injectCollection(renderer: Renderer2, injectables: ReadonlyArray<DOMIn...

FILE: src/client/app/shared/services/logging.service.ts
  type ILoggingService (line 4) | interface ILoggingService {
  constant LOGGER_CONFIG (line 12) | const LOGGER_CONFIG = new InjectionToken<LoggerOptions>('app.logger.conf...
  class LoggingService (line 15) | class LoggingService implements ILoggingService {
    method constructor (line 18) | constructor(@Inject(LOGGER_CONFIG) private loggerConfig: LoggerOptions...
    method trace (line 20) | trace(msg: string, obj: { readonly [key: string]: any } = {}, extended...
    method debug (line 24) | debug(msg: string, obj: { readonly [key: string]: any } = {}, extended...
    method info (line 28) | info(msg: string, obj: { readonly [key: string]: any } = {}, extendedO...
    method warn (line 32) | warn(msg: string, obj: { readonly [key: string]: any } = {}, extendedO...
    method error (line 36) | error(msg: string, obj: { readonly [key: string]: any } = {}, extended...

FILE: src/client/app/shared/services/minifier.service.ts
  type IMinifierService (line 3) | interface IMinifierService {
  class MinifierService (line 8) | class MinifierService implements IMinifierService {
    method css (line 9) | css(css: string): string {

FILE: src/client/app/shared/services/platform.service.ts
  type IPlatformService (line 4) | interface IPlatformService {
  class PlatformService (line 10) | class PlatformService implements IPlatformService {
    method constructor (line 11) | constructor( @Inject(PLATFORM_ID) private platformId: any) { }
    method isBrowser (line 13) | public get isBrowser(): boolean {
    method isServer (line 17) | public get isServer(): boolean {

FILE: src/client/app/shared/services/seo.service.ts
  type SEONode (line 4) | interface SEONode {
  type SEOImage (line 15) | interface SEOImage {
  class SEOService (line 24) | class SEOService {
    method constructor (line 25) | constructor(private title: Title, private meta: Meta) { }
    method updateNode (line 27) | updateNode(node: SEONode) {
    method updateTitle (line 38) | updateTitle(title: string) {
    method updateDescription (line 43) | updateDescription(desc: string) {
    method updateFbAppId (line 48) | updateFbAppId(id: string) {
    method updateImg (line 52) | updateImg(img: SEOImage) {
    method updateType (line 60) | updateType(type = 'website') {
    method updateLocale (line 64) | updateLocale(locale = 'en_US') {
    method updateUrl (line 68) | updateUrl(url: string) {
    method updateTags (line 72) | updateTags(tags: ReadonlyArray<string>) {
    method createOgTag (line 77) | createOgTag(property: string, content: string, property2?: string) {

FILE: src/client/app/shared/services/server-response.service.spec.ts
  class MockResponse (line 92) | class MockResponse {
    method header (line 97) | header(key: string, value: string) {
    method getHeader (line 101) | getHeader(key: string) {

FILE: src/client/app/shared/services/server-response.service.ts
  type IServerResponseService (line 7) | interface IServerResponseService {
  class ServerResponseService (line 18) | class ServerResponseService implements IServerResponseService {
    method constructor (line 21) | constructor( @Optional() @Inject(RESPONSE) response: any) {
    method getHeader (line 25) | getHeader(key: string): string {
    method setHeader (line 29) | setHeader(key: string, value: string): this {
    method appendHeader (line 35) | appendHeader(key: string, value: string, delimiter = ','): this {
    method setHeaders (line 49) | setHeaders(dictionary: { [key: string]: string }): this {
    method setStatus (line 55) | setStatus(code: number, message?: string): this {
    method setNotFound (line 64) | setNotFound(message = 'not found'): this {
    method setUnauthorized (line 72) | setUnauthorized(message = 'Unauthorized'): this {
    method setCachePrivate (line 80) | setCachePrivate(): this {
    method setCacheNone (line 87) | setCacheNone(): this {
    method setCache (line 95) | setCache(directive: HttpCacheDirective, maxAge?: string, smaxAge?: str...
    method setError (line 109) | setError(message = 'internal server error'): this {
  type HttpCacheDirective (line 118) | type HttpCacheDirective = 'public' | 'private' | 'no-store' | 'no-cache'...

FILE: src/client/app/shared/services/setting.service.spec.ts
  class MockPlatformService (line 32) | class MockPlatformService implements IPlatformService {
  class MockDb (line 37) | class MockDb {
    method get (line 38) | get() {

FILE: src/client/app/shared/services/setting.service.ts
  type ISettingService (line 6) | interface ISettingService {
  class SettingService (line 12) | class SettingService implements ISettingService {
    method pluck (line 24) | public pluck(key: string) {
    method constructor (line 29) | constructor(private db: FirebaseDatabaseService) {

FILE: src/client/app/shared/services/web-socket.service.ts
  class WebSocketService (line 8) | class WebSocketService {
    method constructor (line 20) | constructor(private ps: PlatformService, private es: EnvironmentServic...
    method send (line 22) | send(obj: Object) {

FILE: src/client/app/shared/shared.module.ts
  function fuseBoxConfigFactory (line 41) | function fuseBoxConfigFactory() {
  function loggerConfigFactory (line 45) | function loggerConfigFactory(ps: PlatformService, gooogleAnalytics: Angu...
  class SharedModule (line 146) | class SharedModule {
    method forRoot (line 147) | static forRoot(): ModuleWithProviders {

FILE: src/client/app/shared/style-injection-form/style-injection-form.component.ts
  class StyleInjectionFormComponent (line 11) | class StyleInjectionFormComponent {
    method constructor (line 14) | constructor() {

FILE: src/client/app/shared/web-app-installer/web-app-installer.component.ts
  class WebAppInstallerComponent (line 9) | class WebAppInstallerComponent {

FILE: src/client/app/shared/web-app-installer/web-app-installer.module.ts
  class WebAppInstallerlModule (line 10) | class WebAppInstallerlModule { }

FILE: src/client/app/shared/web-app-installer/web-app-installer.service.ts
  class WebAppInstallerService (line 5) | class WebAppInstallerService {
    method isIosWebApp (line 6) | get isIosWebApp() {
    method constructor (line 12) | constructor(@Inject(PLATFORM_ID) private platformId: any) { }

FILE: src/client/app/signup/signup-routing.module.ts
  class SignupRoutingModule (line 24) | class SignupRoutingModule { }

FILE: src/client/app/signup/signup.component.spec.ts
  class TestComponent (line 36) | @Component({

FILE: src/client/app/signup/signup.component.ts
  class SignupComponent (line 9) | class SignupComponent { }

FILE: src/client/app/signup/signup.module.ts
  class SignupModule (line 11) | class SignupModule { }

FILE: src/client/app/unauthorized/unauthorized-routing.module.ts
  class UnauthorizedRoutingModule (line 24) | class UnauthorizedRoutingModule { }

FILE: src/client/app/unauthorized/unauthorized.component.spec.ts
  class TestComponent (line 10) | @Component({

FILE: src/client/app/unauthorized/unauthorized.component.ts
  class UnauthorizedComponent (line 9) | class UnauthorizedComponent {

FILE: src/client/app/unauthorized/unauthorized.module.ts
  class UnauthorizedModule (line 11) | class UnauthorizedModule { }

FILE: src/client/app/users/users-routing.module.ts
  class UsersRoutingModule (line 30) | class UsersRoutingModule { }

FILE: src/client/app/users/users.component.spec.ts
  class TestComponent (line 7) | @Component({

FILE: src/client/app/users/users.component.ts
  class UsersComponent (line 13) | class UsersComponent {
    method constructor (line 28) | constructor(private db: FirebaseDatabaseService, private ss: SettingSe...
    method trackByUsers (line 34) | trackByUsers(index: number, item: any) {

FILE: src/client/app/users/users.module.ts
  class UsersModule (line 11) | class UsersModule { }

FILE: src/server/api/controllers/settings.controller.ts
  class SettingsController (line 5) | class SettingsController {
    method constructor (line 6) | constructor(private settingService: SettingService) { }
    method get (line 28) | get() {

FILE: src/server/api/middlewares/zone-error-handler.ts
  class ZoneErrorHandler (line 5) | class ZoneErrorHandler implements ExpressErrorMiddlewareInterface {
    method error (line 7) | error(error: any, request: express.Request, response: express.Response) {

FILE: src/server/api/repositories/setting.repository.ts
  type ISetting (line 6) | interface ISetting {
  type Injectable (line 31) | interface Injectable {
  type ISettingRepository (line 38) | interface ISettingRepository {
  class SettingRepository (line 44) | class SettingRepository implements ISettingRepository {
    method getDictionary (line 47) | getDictionary(): Observable<ISetting> {

FILE: src/server/api/repositories/settings.ts
  constant SETTINGS (line 5) | const SETTINGS: ISetting = {

FILE: src/server/api/services/setting.service.ts
  type ISettingService (line 6) | interface ISettingService {
  class SettingService (line 14) | class SettingService implements ISettingService {
    method constructor (line 17) | constructor(private repo: SettingRepository) { }

FILE: src/server/server.angular-fire.service.ts
  constant FIREBASE_ADMIN_INSTANCE (line 7) | const FIREBASE_ADMIN_INSTANCE = new InjectionToken<string>('app.fb.admin')
  class FirebaseAdminService (line 10) | class FirebaseAdminService {
    method constructor (line 11) | constructor(private zone: NgZone, private ts: TransferState) { }
    method object (line 13) | public object(path: any, query?: any) {
    method list (line 42) | public list(path: any, query?: any) {
    method applyQuery (line 97) | applyQuery(ref: any, query: any) {

FILE: src/server/server.angular.module.ts
  function onBootstrap (line 25) | function onBootstrap(appRef: ApplicationRef, transferState: TransferStat...
  function createAngularFireServer (line 40) | function createAngularFireServer(req: express.Request, transferState: Tr...
  function getFirebaseServerModule (line 44) | function getFirebaseServerModule(zone: NgZone, ts: TransferState) {
  method css (line 82) | css(css: string): string {
  class AppServerModule (line 90) | class AppServerModule { }
  class AngularFireServer (line 92) | class AngularFireServer {
    method constructor (line 96) | constructor( @Inject(REQUEST) private req: any, ts: TransferState) {

FILE: src/server/server.config.ts
  function fuseBoxConfigFactory (line 6) | function fuseBoxConfigFactory() {
  type ServerEnvironmentConfig (line 10) | interface ServerEnvironmentConfig {
  constant ANGULAR_APP_CONFIG (line 16) | const ANGULAR_APP_CONFIG = fuseBoxConfigFactory()
  constant SERVER_CONFIG (line 36) | const SERVER_CONFIG: ServerEnvironmentConfig = process.env as any
  constant FB_SERVICE_ACCOUNT_CONFIG (line 41) | const FB_SERVICE_ACCOUNT_CONFIG = {

FILE: src/testing/app-testing.module.ts
  class AppTestingModule (line 42) | class AppTestingModule {
    method forRoot (line 43) | static forRoot(requestProvider?: any, windowTokenProvider?: any, authC...
    method constructor (line 53) | constructor(@Optional() @SkipSelf() parentModule: AppTestingModule) {

FILE: src/testing/mock-cookie.service.ts
  class MockCookieService (line 6) | class MockCookieService implements ICookieService {
    method get (line 11) | get(name: string): any {
    method getAll (line 15) | getAll() {
    method set (line 19) | set(name: string, value: any, options?: Cookies.CookieAttributes | und...
    method remove (line 24) | remove(name: string, options?: Cookies.CookieAttributes | undefined): ...

FILE: src/testing/mock-environment.service.ts
  class MockEnvironmentService (line 5) | class MockEnvironmentService implements IEnvironmentService {

FILE: src/testing/mock-firebase-database.service.ts
  class MockFirebaseDatabaseService (line 5) | class MockFirebaseDatabaseService {
    method get (line 6) | get() {
    method getList (line 9) | getList() {
    method getListKeyed (line 12) | getListKeyed() {

FILE: tools/config/app.config.ts
  type EnvConfig (line 1) | interface EnvConfig {

FILE: tools/config/build.ci.replace.ts
  constant OVERRIDES (line 4) | const OVERRIDES = argv['ci-vars'] ?

FILE: tools/config/build.config.ts
  constant BUILD_CONFIG (line 6) | const BUILD_CONFIG: BuildConfiguration = {
  constant ENV_CONFIG_INSTANCE (line 46) | const ENV_CONFIG_INSTANCE = envConfig

FILE: tools/config/build.interfaces.ts
  type BuildConfiguration (line 3) | interface BuildConfiguration {

FILE: tools/manual-typings/seed/loglevel-std-streams.d.ts
  type ILoglevelStdStreams (line 2) | interface ILoglevelStdStreams {

FILE: tools/plugins/ng-aot.ts
  type NgAotPluginOptions (line 6) | interface NgAotPluginOptions {
  class NgAotPluginClass (line 10) | class NgAotPluginClass {
    method constructor (line 13) | constructor(options: NgAotPluginOptions = {}) {
    method init (line 17) | public init(context: WorkFlowContext) {
    method transform (line 21) | public transform(file: File) {

FILE: tools/plugins/pwa-fused.ts
  type PwaFusedPluginOptions (line 4) | interface PwaFusedPluginOptions {
  class PwaFusedPluginClass (line 18) | class PwaFusedPluginClass {
    method constructor (line 21) | constructor(private opts: PwaFusedPluginOptions = {}) {
    method preBundle (line 38) | public preBundle(context: WorkFlowContext) {

FILE: tools/plugins/web-index.ts
  type WebIndexPluginOptions (line 9) | interface WebIndexPluginOptions {
  class WebIndexPluginClass (line 40) | class WebIndexPluginClass {
    method constructor (line 43) | constructor(public opts: WebIndexPluginOptions) {
    method producerEnd (line 48) | producerEnd(producer: BundleProducer) {
  type Dependency (line 120) | interface Dependency {
  type IConfigurationTransformer (line 129) | interface IConfigurationTransformer {
  class ConfigurationTransformer (line 133) | class ConfigurationTransformer implements IConfigurationTransformer {
    method applyTransform (line 134) | applyTransform(dependencies: Dependency[], document?: jsdom.JSDOM | st...

FILE: tools/tslint-rules/validateDecoratorsRule.ts
  class Rule (line 20) | class Rule extends Lint.Rules.AbstractRule {
    method apply (line 21) | apply(sourceFile: ts.SourceFile) {
  type DecoratorRuleSet (line 27) | type DecoratorRuleSet = {
  type DecoratorRules (line 33) | type DecoratorRules = {
  class Walker (line 37) | class Walker extends Lint.RuleWalker {
    method constructor (line 44) | constructor(sourceFile: ts.SourceFile, options: Lint.IOptions) {
    method visitClassDeclaration (line 58) | visitClassDeclaration(node: ts.ClassDeclaration) {
    method _validatedDecorator (line 73) | private _validatedDecorator(decorator: any) {
    method _generateRules (line 123) | private _generateRules(config: {[key: string]: {[key: string]: string}...
Condensed preview — 326 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (434K chars).
[
  {
    "path": ".editorconfig",
    "chars": 243,
    "preview": "# http://editorconfig.org\n\nroot = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size = 2\nend_of_line = lf\ninsert"
  },
  {
    "path": ".firebaserc",
    "chars": 72,
    "preview": "{\n  \"projects\": {\n    \"default\": \"fuse-angular-universal-s-67402\"\n  }\n}\n"
  },
  {
    "path": ".gitignore",
    "chars": 1019,
    "preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n.DS_Store\ndist\n.env\n.fusebox\n\n# Runtime data\npids\n*.pid"
  },
  {
    "path": ".stylelintrc",
    "chars": 392,
    "preview": "{\n  \"rules\": {\n    \"block-no-empty\": null,\n    \"color-no-invalid-hex\": true,\n    \"comment-empty-line-before\": [\n        "
  },
  {
    "path": ".vscode/extensions.json",
    "chars": 144,
    "preview": "{\n  \"recommendations\": [\n    \"msjsdiag.debugger-for-chrome\",\n    \"michelemelluso.code-beautifier\",\n    \"eg2.tslint\",\n   "
  },
  {
    "path": ".vscode/settings.json",
    "chars": 258,
    "preview": "// Place your settings in this file to overwrite default and user settings.\n{\n  \"editor.tabSize\": 2,\n  \"beautify.tabSize"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 3221,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 1010,
    "preview": "# Contributing\n\nWe love pull requests from everyone. By participating in this project, you\nagree to abide by our [code o"
  },
  {
    "path": "LICENSE",
    "chars": 1074,
    "preview": "MIT License\n\nCopyright (c) 2017 Patrick Michalina\n\nPermission is hereby granted, free of charge, to any person obtaining"
  },
  {
    "path": "Procfile",
    "chars": 31,
    "preview": "web: node dist/server.js --prod"
  },
  {
    "path": "README.md",
    "chars": 10073,
    "preview": "## This project is archived and an improved version has been moved to [https://github.com/patrickmichalina/fusing-angula"
  },
  {
    "path": "app.json",
    "chars": 623,
    "preview": "{\n  \"name\": \"fusebox-angular-universal-star\",\n  \"env\": {\n    \"CI\": {\n      \"required\": true\n    },\n    \"HOST\": {\n      \""
  },
  {
    "path": "circle.yml",
    "chars": 626,
    "preview": "machine:\n  node:\n    version: 9.4.0\n  npm:\n    version: 5.6.0\n\ngeneral:\n  artifacts:\n    - ./coverage\n    - ./dist\n\ntest"
  },
  {
    "path": "codecov.yml",
    "chars": 64,
    "preview": "codecov:\n  allow_coverage_offsets: false\n  ignore:\n    - \"tools\""
  },
  {
    "path": "data/security.rules.json",
    "chars": 838,
    "preview": "{\n  \"rules\": {\n    \"site-settings\": {\n      \".read\": \"true\",\n      \".write\": \"root.child('users').child(auth.uid).child("
  },
  {
    "path": "data/seed.settings.json",
    "chars": 4170,
    "preview": "{\n  \"host\": \"http://localhost:8000\",\n  \"og\": {\n    \"title\": \"Fusebox Angular Universal Starter\",\n    \"description\": \"See"
  },
  {
    "path": "data/seed.superusers.json",
    "chars": 110,
    "preview": "{\n  \"9BthHoxklbgCzP2vlFI3ZrNggrl1\": {\n    \"roles\": {\n      \"superadmin\": true,\n      \"admin\": true\n    }\n  }\n}"
  },
  {
    "path": "docs/angular-universal.md",
    "chars": 2246,
    "preview": "# Universal \"Gotchas\"\n\n> When building Universal components in Angular 2 there are a few things to keep in mind.\n\n - **`"
  },
  {
    "path": "docs/api-server.md",
    "chars": 1305,
    "preview": "# API\nThis project includes an example API that can be split off into a standalone server. The goal of this API is to pr"
  },
  {
    "path": "docs/openid-server.md",
    "chars": 169,
    "preview": "# Identity Server\nThis project includes an OpenID certifiec identity server that can be split off into a standalone Open"
  },
  {
    "path": "e2e-spec.json",
    "chars": 360,
    "preview": "{\n  \"moduleFileExtensions\": [\n    \"ts\",\n    \"js\",\n    \"html\"\n  ],\n  \"testRegex\": \"(/__tests__/.*|\\\\.(test|e2e-spec))\\\\.("
  },
  {
    "path": "firebase.json",
    "chars": 64,
    "preview": "{\n  \"database\": {\n    \"rules\": \"data/security.rules.json\"\n  }\n}\n"
  },
  {
    "path": "fuse.ts",
    "chars": 3476,
    "preview": "import { Ng2TemplatePlugin } from 'ng2-fused';\nimport { argv } from 'yargs';\nimport { BUILD_CONFIG, ENV_CONFIG_INSTANCE,"
  },
  {
    "path": "package.json",
    "chars": 8237,
    "preview": "{\n  \"name\": \"fusebox-angular-universal-starter\",\n  \"version\": \"0.0.0-development\",\n  \"description\": \"Angular Universal s"
  },
  {
    "path": "src/client/app/__snapshots__/app.component.spec.ts.snap",
    "chars": 10858,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`App component should build without a problem 1`] = `\n<div\n  id=\"roo"
  },
  {
    "path": "src/client/app/about/__snapshots__/about.component.spec.ts.snap",
    "chars": 6456,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`AboutComponent should compile 1`] = `\n<test-component>\n  <pm-about>"
  },
  {
    "path": "src/client/app/about/about-routing.module.ts",
    "chars": 667,
    "preview": "import { AboutComponent } from './about.component'\nimport { NgModule } from '@angular/core'\nimport { RouterModule } from"
  },
  {
    "path": "src/client/app/about/about.component.e2e-spec.ts",
    "chars": 361,
    "preview": "import { baseUrl, browser } from '../../../../tools/test/jest.e2e-setup'\n\ndescribe('About Page', () => {\n  it('should ha"
  },
  {
    "path": "src/client/app/about/about.component.html",
    "chars": 738,
    "preview": "<h1>About</h1>\n<p>An Angular starter with all the tools necessary to create server rendered Angular applications.</p>\n\n<"
  },
  {
    "path": "src/client/app/about/about.component.scss",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/client/app/about/about.component.spec.ts",
    "chars": 980,
    "preview": "import { AboutComponent } from './about.component'\nimport { async, ComponentFixture, TestBed } from '@angular/core/testi"
  },
  {
    "path": "src/client/app/about/about.component.ts",
    "chars": 1185,
    "preview": "import { PlatformService } from './../shared/services/platform.service'\nimport { ChangeDetectionStrategy, Component } fr"
  },
  {
    "path": "src/client/app/about/about.module.ts",
    "chars": 361,
    "preview": "import { AboutRoutingModule } from './about-routing.module'\nimport { AboutComponent } from './about.component'\nimport { "
  },
  {
    "path": "src/client/app/account/account-routing.module.ts",
    "chars": 758,
    "preview": "import { AccountComponent } from './account.component'\nimport { NgModule } from '@angular/core'\nimport { RouterModule } "
  },
  {
    "path": "src/client/app/account/account.component.html",
    "chars": 4760,
    "preview": "<div *ngIf=\"user$ | async as user\" class=\"flex-center\">\n  <h2>{{ user.displayName }}</h2>\n  <a class=\"flex-center\">\n    "
  },
  {
    "path": "src/client/app/account/account.component.scss",
    "chars": 727,
    "preview": ":host {\n  .flex-center {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    img {\n      cursor:"
  },
  {
    "path": "src/client/app/account/account.component.ts",
    "chars": 4630,
    "preview": "import { AuthService } from './../shared/services/auth.service'\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Com"
  },
  {
    "path": "src/client/app/account/account.module.ts",
    "chars": 377,
    "preview": "import { AccountRoutingModule } from './account-routing.module'\nimport { AccountComponent } from './account.component'\ni"
  },
  {
    "path": "src/client/app/admin/__snapshots__/admin.component.spec.ts.snap",
    "chars": 196,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`AdminComponent should match snapshot 1`] = `\n<pm-admin>\n  <h1>\n    "
  },
  {
    "path": "src/client/app/admin/admin-routing.module.ts",
    "chars": 666,
    "preview": "import { AdminComponent } from './admin.component'\nimport { NgModule } from '@angular/core'\nimport { RouterModule } from"
  },
  {
    "path": "src/client/app/admin/admin.component.e2e-spec.ts",
    "chars": 359,
    "preview": "import { baseUrl, browser } from '../../../../tools/test/jest.e2e-setup'\n\ndescribe('Admin Page', () => {\n  it('should ha"
  },
  {
    "path": "src/client/app/admin/admin.component.html",
    "chars": 54,
    "preview": "<h1>Admin</h1>\n<p>Your Admin module is routed here</p>"
  },
  {
    "path": "src/client/app/admin/admin.component.scss",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/client/app/admin/admin.component.spec.ts",
    "chars": 1005,
    "preview": "import { AdminComponent } from './admin.component'\nimport { async, ComponentFixture, TestBed } from '@angular/core/testi"
  },
  {
    "path": "src/client/app/admin/admin.component.ts",
    "chars": 272,
    "preview": "import { ChangeDetectionStrategy, Component } from '@angular/core'\n\n@Component({\n  selector: 'pm-admin',\n  templateUrl: "
  },
  {
    "path": "src/client/app/admin/admin.module.ts",
    "chars": 361,
    "preview": "import { AdminRoutingModule } from './admin-routing.module'\nimport { AdminComponent } from './admin.component'\nimport { "
  },
  {
    "path": "src/client/app/app-routing.module.ts",
    "chars": 1547,
    "preview": "import { NgModule } from '@angular/core'\nimport { RouterModule, Routes } from '@angular/router'\n\nexport const routes: Ro"
  },
  {
    "path": "src/client/app/app.browser.module.ts",
    "chars": 911,
    "preview": "import { BrowserAnimationsModule } from '@angular/platform-browser/animations'\nimport { BrowserModule, BrowserTransferSt"
  },
  {
    "path": "src/client/app/app.component.html",
    "chars": 1292,
    "preview": "<pm-navbar (menuIconClick)=\"sidenav.toggle()\" [user]=\"user$ | async\"></pm-navbar>\n<mat-sidenav-container class=\"sidenav-"
  },
  {
    "path": "src/client/app/app.component.scss",
    "chars": 434,
    "preview": ":host {\n  display: flex;\n  flex: 1 0;\n  flex-direction: column;\n  .sidenav-container {\n    overflow-y: auto;\n    flex: 1"
  },
  {
    "path": "src/client/app/app.component.spec.ts",
    "chars": 3359,
    "preview": "import { SharedModule } from './shared/shared.module'\nimport { async, ComponentFixture, TestBed } from '@angular/core/te"
  },
  {
    "path": "src/client/app/app.component.ts",
    "chars": 4363,
    "preview": "import { ISetting } from './../../server/api/repositories/setting.repository'\nimport { REQUEST } from '@nguniversal/expr"
  },
  {
    "path": "src/client/app/app.config.ts",
    "chars": 179,
    "preview": "import { InjectionToken } from '@angular/core'\nimport { EnvConfig } from '../../../tools/config/app.config'\n\nexport cons"
  },
  {
    "path": "src/client/app/app.module.ts",
    "chars": 4501,
    "preview": "import { ErrorHandler, NgModule } from '@angular/core'\nimport { HttpConfigInterceptor } from './shared/services/http-con"
  },
  {
    "path": "src/client/app/changelog/__snapshots__/changelog.component.spec.ts.snap",
    "chars": 241,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`ChangelogComponent should compile 1`] = `\n<test-component>\n  <pm-ch"
  },
  {
    "path": "src/client/app/changelog/changelog-routing.module.ts",
    "chars": 585,
    "preview": "import { ChangelogComponent } from './changelog.component'\nimport { NgModule } from '@angular/core'\nimport { RouterModul"
  },
  {
    "path": "src/client/app/changelog/changelog.component.e2e-spec.ts",
    "chars": 373,
    "preview": "import { baseUrl, browser } from '../../../../tools/test/jest.e2e-setup'\n\ndescribe('Changelog Page', () => {\n  it('shoul"
  },
  {
    "path": "src/client/app/changelog/changelog.component.html",
    "chars": 86,
    "preview": "<mat-card>\n  <div [innerHTML]=\"changelog$ | async | MarkdownToHtml\"></div>\n</mat-card>"
  },
  {
    "path": "src/client/app/changelog/changelog.component.scss",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/client/app/changelog/changelog.component.spec.ts",
    "chars": 985,
    "preview": "import { ChangelogComponent } from './changelog.component'\nimport { async, ComponentFixture, TestBed } from '@angular/co"
  },
  {
    "path": "src/client/app/changelog/changelog.component.ts",
    "chars": 571,
    "preview": "import { Observable } from 'rxjs/Observable'\nimport { HttpClient } from '@angular/common/http'\nimport { ChangeDetectionS"
  },
  {
    "path": "src/client/app/changelog/changelog.module.ts",
    "chars": 393,
    "preview": "import { ChangelogComponent } from './changelog.component'\nimport { ChangelogRoutingModule } from './changelog-routing.m"
  },
  {
    "path": "src/client/app/dashboard/dashboard-menu.ts",
    "chars": 375,
    "preview": "export const DASHBOARD_MENU = [\n  {\n    heading: 'Heading 1',\n    children: [\n      {\n        path: 'test/test-child',\n "
  },
  {
    "path": "src/client/app/dashboard/dashboard-routing.module.ts",
    "chars": 725,
    "preview": "import { NgModule } from '@angular/core'\nimport { RouterModule } from '@angular/router'\nimport { DashboardComponent } fr"
  },
  {
    "path": "src/client/app/dashboard/dashboard.component.html",
    "chars": 1619,
    "preview": "<mat-sidenav-container class=\"dashboard-container\">\n  <mat-sidenav #sidenav class=\"dashboard-sidenav\" mode=\"side\" opened"
  },
  {
    "path": "src/client/app/dashboard/dashboard.component.scss",
    "chars": 2166,
    "preview": ":host {\n  -webkit-box-flex: 1;\n  -ms-flex: 1 1 auto;\n  flex: 1 1 auto;\n  display: -webkit-box;\n  display: -ms-flexbox;\n "
  },
  {
    "path": "src/client/app/dashboard/dashboard.component.ts",
    "chars": 1277,
    "preview": "import { Title } from '@angular/platform-browser'\nimport { ChangeDetectionStrategy, Component, HostListener, OnInit, Vie"
  },
  {
    "path": "src/client/app/dashboard/dashboard.module.ts",
    "chars": 790,
    "preview": "import { DashboardComponent } from './dashboard.component'\nimport { DashboardRoutingModule } from './dashboard-routing.m"
  },
  {
    "path": "src/client/app/dashboard/footer/__snapshots__/dashboard-page-footer.component.spec.ts.snap",
    "chars": 929,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`DashboardPageFooterComponent should match snapshot 1`] = `\n<pm-dash"
  },
  {
    "path": "src/client/app/dashboard/footer/dashboard-page-footer.component.html",
    "chars": 528,
    "preview": "<footer class=\"dashboard-footer\">\n  <div class=\"dashboard-footer-list\">\n    <div class=\"logo\">\n      <img alt=\"angular\" "
  },
  {
    "path": "src/client/app/dashboard/footer/dashboard-page-footer.component.scss",
    "chars": 1092,
    "preview": ":host {\n  .dashboard-footer {\n    margin-top: 40px;\n    padding: 12px;\n    font-size: 12px;\n    background: #2196f3;\n   "
  },
  {
    "path": "src/client/app/dashboard/footer/dashboard-page-footer.component.spec.ts",
    "chars": 1023,
    "preview": "import { async, ComponentFixture, TestBed } from '@angular/core/testing'\nimport { Component } from '@angular/core'\nimpor"
  },
  {
    "path": "src/client/app/dashboard/footer/dashboard-page-footer.component.ts",
    "chars": 335,
    "preview": "import { ChangeDetectionStrategy, Component } from '@angular/core'\n\n@Component({\n  selector: 'pm-dashboard-page-footer',"
  },
  {
    "path": "src/client/app/dashboard/header/__snapshots__/dashboard-page-header.component.spec.ts.snap",
    "chars": 787,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`DashboardPageHeaderComponent should match snapshot 1`] = `\n<pm-dash"
  },
  {
    "path": "src/client/app/dashboard/header/dashboard-page-header.component.html",
    "chars": 244,
    "preview": "<div class=\"docs-primary-header\">\n  <button class=\"side-nav-toggle\" mat-button=\"\" (click)=\"toggle()\">\n    <span>\n      <"
  },
  {
    "path": "src/client/app/dashboard/header/dashboard-page-header.component.scss",
    "chars": 678,
    "preview": ":host {\n  .docs-primary-header {\n    background: #9ba0a5;\n    padding-left: 20px;\n    display: -webkit-box;\n    display:"
  },
  {
    "path": "src/client/app/dashboard/header/dashboard-page-header.component.spec.ts",
    "chars": 1023,
    "preview": "import { async, ComponentFixture, TestBed } from '@angular/core/testing'\nimport { Component } from '@angular/core'\nimpor"
  },
  {
    "path": "src/client/app/dashboard/header/dashboard-page-header.component.ts",
    "chars": 539,
    "preview": "import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'\n\n@Component({\n  selector"
  },
  {
    "path": "src/client/app/dashboard/test/__snapshots__/test.component.spec.ts.snap",
    "chars": 141,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`TestComponent should match snapshot 1`] = `\n<pm-test>\n  <router-out"
  },
  {
    "path": "src/client/app/dashboard/test/test-routing.module.ts",
    "chars": 1531,
    "preview": "import { TestComponent } from './test.component'\nimport { NgModule } from '@angular/core'\nimport { RouterModule } from '"
  },
  {
    "path": "src/client/app/dashboard/test/test.component.html",
    "chars": 31,
    "preview": "<router-outlet></router-outlet>"
  },
  {
    "path": "src/client/app/dashboard/test/test.component.scss",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/client/app/dashboard/test/test.component.spec.ts",
    "chars": 1818,
    "preview": "import { async, ComponentFixture, TestBed } from '@angular/core/testing'\nimport { Component } from '@angular/core'\nimpor"
  },
  {
    "path": "src/client/app/dashboard/test/test.component.ts",
    "chars": 268,
    "preview": "import { ChangeDetectionStrategy, Component } from '@angular/core'\n\n@Component({\n  selector: 'pm-test',\n  templateUrl: '"
  },
  {
    "path": "src/client/app/dashboard/test/test.module.ts",
    "chars": 579,
    "preview": "import { TestRoutingModule } from './test-routing.module'\nimport { TestComponent } from './test.component'\nimport { NgMo"
  },
  {
    "path": "src/client/app/dashboard/test/test.service.ts",
    "chars": 88,
    "preview": "import { Injectable } from '@angular/core'\n\n@Injectable()\nexport class TestService {\n\n}\n"
  },
  {
    "path": "src/client/app/dashboard/test/testChild/__snapshots__/testChild.component.spec.ts.snap",
    "chars": 220,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`TestChildComponent should match snapshot 1`] = `\n<pm-test-child-1>\n"
  },
  {
    "path": "src/client/app/dashboard/test/testChild/testChild.component.html",
    "chars": 45,
    "preview": "<mat-card>\n    Test Child Project\n</mat-card>"
  },
  {
    "path": "src/client/app/dashboard/test/testChild/testChild.component.scss",
    "chars": 50,
    "preview": ".mat-card {\n    margin: 10px;\n    height: 400px;\n}"
  },
  {
    "path": "src/client/app/dashboard/test/testChild/testChild.component.spec.ts",
    "chars": 938,
    "preview": "import { async, ComponentFixture, TestBed } from '@angular/core/testing'\nimport { Component } from '@angular/core'\nimpor"
  },
  {
    "path": "src/client/app/dashboard/test/testChild/testChild.component.ts",
    "chars": 291,
    "preview": "import { ChangeDetectionStrategy, Component } from '@angular/core'\n\n@Component({\n  selector: 'pm-test-child-1',\n  templa"
  },
  {
    "path": "src/client/app/dashboard/test/testChild1/__snapshots__/testChild1.component.spec.ts.snap",
    "chars": 223,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`TestChild1Component should match snapshot 1`] = `\n<pm-test-child-2>"
  },
  {
    "path": "src/client/app/dashboard/test/testChild1/testChild1.component.html",
    "chars": 45,
    "preview": "<mat-card>\n  Test Child 1 Project\n</mat-card>"
  },
  {
    "path": "src/client/app/dashboard/test/testChild1/testChild1.component.scss",
    "chars": 46,
    "preview": ".mat-card {\n  margin: 10px;\n  height: 400px;\n}"
  },
  {
    "path": "src/client/app/dashboard/test/testChild1/testChild1.component.spec.ts",
    "chars": 943,
    "preview": "import { async, ComponentFixture, TestBed } from '@angular/core/testing'\nimport { Component } from '@angular/core'\nimpor"
  },
  {
    "path": "src/client/app/dashboard/test/testChild1/testChild1.component.ts",
    "chars": 294,
    "preview": "import { ChangeDetectionStrategy, Component } from '@angular/core'\n\n@Component({\n  selector: 'pm-test-child-2',\n  templa"
  },
  {
    "path": "src/client/app/dashboard/test1/__snapshots__/test1.component.spec.ts.snap",
    "chars": 198,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`Test1Component should match snapshot 1`] = `\n<pm-test1>\n  <mat-card"
  },
  {
    "path": "src/client/app/dashboard/test1/test1-routing.module.ts",
    "chars": 723,
    "preview": "import { Test1Component } from './test1.component'\nimport { NgModule } from '@angular/core'\nimport { RouterModule } from"
  },
  {
    "path": "src/client/app/dashboard/test1/test1.component.html",
    "chars": 39,
    "preview": "<mat-card>\n  Test 1 Project\n</mat-card>"
  },
  {
    "path": "src/client/app/dashboard/test1/test1.component.scss",
    "chars": 46,
    "preview": ".mat-card {\n  margin: 10px;\n  height: 400px;\n}"
  },
  {
    "path": "src/client/app/dashboard/test1/test1.component.spec.ts",
    "chars": 906,
    "preview": "import { async, ComponentFixture, TestBed } from '@angular/core/testing'\nimport { Component } from '@angular/core'\nimpor"
  },
  {
    "path": "src/client/app/dashboard/test1/test1.component.ts",
    "chars": 272,
    "preview": "import { ChangeDetectionStrategy, Component } from '@angular/core'\n\n@Component({\n  selector: 'pm-test1',\n  templateUrl: "
  },
  {
    "path": "src/client/app/dashboard/test1/test1.module.ts",
    "chars": 364,
    "preview": "import { Test1RoutingModule } from './test1-routing.module'\nimport { Test1Component } from './test1.component'\nimport { "
  },
  {
    "path": "src/client/app/home/__snapshots__/home.component.spec.ts.snap",
    "chars": 2296,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`HomeComponent should compile 1`] = `\n<pm-home\n  containerClass={[Fu"
  },
  {
    "path": "src/client/app/home/home-routing.module.ts",
    "chars": 795,
    "preview": "import { HomeComponent } from './home.component'\nimport { NgModule } from '@angular/core'\nimport { RouterModule } from '"
  },
  {
    "path": "src/client/app/home/home.component.e2e-spec.ts",
    "chars": 354,
    "preview": "import { baseUrl, browser } from '../../../../tools/test/jest.e2e-setup'\n\ndescribe('Home Page', () => {\n  it('should hav"
  },
  {
    "path": "src/client/app/home/home.component.html",
    "chars": 4517,
    "preview": "<mat-card>\n  <div id=\"hero\">\n    <h1 class=\"display-3\">Hello, Angular Developer!</h1>\n    <p class=\"lead\">Welcome to a b"
  },
  {
    "path": "src/client/app/home/home.component.scss",
    "chars": 135,
    "preview": ":host {\n  #hero {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    h1 {\n      margin-bottom: "
  },
  {
    "path": "src/client/app/home/home.component.spec.ts",
    "chars": 1705,
    "preview": "import { By } from '@angular/platform-browser'\nimport { Angulartics2 } from 'angulartics2'\nimport { HomeComponent } from"
  },
  {
    "path": "src/client/app/home/home.component.ts",
    "chars": 348,
    "preview": "import { ChangeDetectionStrategy, Component, HostBinding } from '@angular/core'\n\n@Component({\n  selector: 'pm-home',\n  t"
  },
  {
    "path": "src/client/app/home/home.module.ts",
    "chars": 353,
    "preview": "import { HomeRoutingModule } from './home-routing.module'\nimport { HomeComponent } from './home.component'\nimport { NgMo"
  },
  {
    "path": "src/client/app/login/__snapshots__/login.component.spec.ts.snap",
    "chars": 279,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`LoginComponent should compile 1`] = `\n<pm-login>\n  <div\n    fxlayou"
  },
  {
    "path": "src/client/app/login/login-routing.module.ts",
    "chars": 561,
    "preview": "import { LoginComponent } from './login.component'\nimport { NgModule } from '@angular/core'\nimport { RouterModule } from"
  },
  {
    "path": "src/client/app/login/login.component.e2e-spec.ts",
    "chars": 362,
    "preview": "import { baseUrl, browser } from '../../../../tools/test/jest.e2e-setup'\n\ndescribe('Login Page', () => {\n  it('should ha"
  },
  {
    "path": "src/client/app/login/login.component.html",
    "chars": 111,
    "preview": "<div fxLayout=\"column\" fxLayoutAlign=\"center center\">\n  <h1>Login</h1>\n  <pm-login-card></pm-login-card>\n</div>"
  },
  {
    "path": "src/client/app/login/login.component.scss",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/client/app/login/login.component.spec.ts",
    "chars": 1459,
    "preview": "import { AuthService } from './../shared/services/auth.service'\nimport { AngularFireAuthModule } from 'angularfire2/auth"
  },
  {
    "path": "src/client/app/login/login.component.ts",
    "chars": 272,
    "preview": "import { ChangeDetectionStrategy, Component } from '@angular/core'\n\n@Component({\n  selector: 'pm-login',\n  templateUrl: "
  },
  {
    "path": "src/client/app/login/login.module.ts",
    "chars": 361,
    "preview": "import { LoginComponent } from './login.component'\nimport { LoginRoutingModule } from './login-routing.module'\nimport { "
  },
  {
    "path": "src/client/app/logout/__snapshots__/logout.component.spec.ts.snap",
    "chars": 164,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`LogoutComponent should compile 1`] = `\n<pm-logout>\n  You have been "
  },
  {
    "path": "src/client/app/logout/logout-routing.module.ts",
    "chars": 567,
    "preview": "import { LogoutComponent } from './logout.component'\nimport { NgModule } from '@angular/core'\nimport { RouterModule } fr"
  },
  {
    "path": "src/client/app/logout/logout.component.e2e-spec.ts",
    "chars": 369,
    "preview": "import { baseUrl, browser } from '../../../../tools/test/jest.e2e-setup'\n\ndescribe('Logout Page', () => {\n  it('should h"
  },
  {
    "path": "src/client/app/logout/logout.component.html",
    "chars": 41,
    "preview": "You have been logged out. Come back soon!"
  },
  {
    "path": "src/client/app/logout/logout.component.scss",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/client/app/logout/logout.component.spec.ts",
    "chars": 1330,
    "preview": "import { AngularFireAuthModule } from 'angularfire2/auth'\nimport { LogoutComponent } from './logout.component'\nimport { "
  },
  {
    "path": "src/client/app/logout/logout.component.ts",
    "chars": 748,
    "preview": "import { PlatformService } from './../shared/services/platform.service'\nimport { CookieService } from './../shared/servi"
  },
  {
    "path": "src/client/app/logout/logout.module.ts",
    "chars": 369,
    "preview": "import { LogoutRoutingModule } from './logout-routing.module'\nimport { LogoutComponent } from './logout.component'\nimpor"
  },
  {
    "path": "src/client/app/not-found/__snapshots__/not-found.component.spec.ts.snap",
    "chars": 1219,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`NotFoundComponent should compile 1`] = `\n<test-component>\n  <pm-not"
  },
  {
    "path": "src/client/app/not-found/not-found-routing.module.ts",
    "chars": 519,
    "preview": "import { NotFoundComponent } from './not-found.component'\nimport { NgModule } from '@angular/core'\nimport { RouterModule"
  },
  {
    "path": "src/client/app/not-found/not-found.component.e2e-spec.ts",
    "chars": 347,
    "preview": "import { baseUrl, browser } from '../../../../tools/test/jest.e2e-setup'\n\ndescribe('NotFound Page', () => {\n  it('should"
  },
  {
    "path": "src/client/app/not-found/not-found.component.html",
    "chars": 11508,
    "preview": "<div *ngIf=\"view$ | async as view\" [ngSwitch]=\"view.isEditing\" class=\"vert-flex-fill\">\n  <div *ngSwitchCase=\"true\" class"
  },
  {
    "path": "src/client/app/not-found/not-found.component.scss",
    "chars": 1658,
    "preview": ":host {\n  .footer {\n    text-align: right;\n    padding: .75em;\n  }\n   ::ng-deep mat-tab-group {\n    flex: 1;\n    height:"
  },
  {
    "path": "src/client/app/not-found/not-found.component.spec.ts",
    "chars": 1758,
    "preview": "import { NotFoundComponent } from './not-found.component'\nimport { AuthService } from './../shared/services/auth.service"
  },
  {
    "path": "src/client/app/not-found/not-found.component.ts",
    "chars": 10385,
    "preview": "import { BehaviorSubject } from 'rxjs/BehaviorSubject'\nimport { DOMInjectable } from './../shared/services/injection.ser"
  },
  {
    "path": "src/client/app/not-found/not-found.module.ts",
    "chars": 387,
    "preview": "import { NotFoundRoutingModule } from './not-found-routing.module'\nimport { NotFoundComponent } from './not-found.compon"
  },
  {
    "path": "src/client/app/pages/page-form/page-form.component.html",
    "chars": 1319,
    "preview": "<h2>New Page</h2>\n<form [formGroup]=\"form\" id=\"pageForm\" novalidate>\n  <mat-form-field>\n    <input matInput placeholder="
  },
  {
    "path": "src/client/app/pages/page-form/page-form.component.scss",
    "chars": 103,
    "preview": ":host {\n  h2 {\n    margin: 0 0 1em 0;\n  }\n  form {\n    display: flex;\n    flex-direction: column;\n  }\n}"
  },
  {
    "path": "src/client/app/pages/page-form/page-form.component.ts",
    "chars": 1941,
    "preview": "import { FirebaseDatabaseService } from '../../shared/services/firebase-database.service'\nimport { ChangeDetectionStrate"
  },
  {
    "path": "src/client/app/pages/pages-routing.module.ts",
    "chars": 678,
    "preview": "import { PagesComponent } from './pages.component'\nimport { NgModule } from '@angular/core'\nimport { RouterModule } from"
  },
  {
    "path": "src/client/app/pages/pages.component.html",
    "chars": 1536,
    "preview": "<div *ngIf=\"view$ | async as view\">\n  <div class=\"flex\">\n    <h1>Pages</h1>\n    <button mat-fab color=\"accent\" (click)=\""
  },
  {
    "path": "src/client/app/pages/pages.component.scss",
    "chars": 123,
    "preview": ":host {\n  .flex {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    padding: 0 1em;\n  "
  },
  {
    "path": "src/client/app/pages/pages.component.ts",
    "chars": 2626,
    "preview": "import { FirebaseDatabaseService } from './../shared/services/firebase-database.service'\nimport { ChangeDetectionStrateg"
  },
  {
    "path": "src/client/app/pages/pages.module.ts",
    "chars": 488,
    "preview": "import { PagesRoutingModule } from './pages-routing.module'\nimport { PagesComponent } from './pages.component'\nimport { "
  },
  {
    "path": "src/client/app/shared/cache-form/cache-form.component.html",
    "chars": 552,
    "preview": "<form *ngIf=\"form\" [formGroup]=\"form\" fxLayout=\"column\">\n  <mat-checkbox *ngFor=\"let dir of dirsNoInput; trackBy: trackB"
  },
  {
    "path": "src/client/app/shared/cache-form/cache-form.component.scss",
    "chars": 10,
    "preview": ":host {\n\n}"
  },
  {
    "path": "src/client/app/shared/cache-form/cache-form.component.ts",
    "chars": 3300,
    "preview": "import { Subscription } from 'rxjs/Subscription'\nimport { FormControl, FormGroup } from '@angular/forms'\nimport { Change"
  },
  {
    "path": "src/client/app/shared/directives/avatar.directive.ts",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/client/app/shared/directives/click-outside.directive.ts",
    "chars": 808,
    "preview": "import { Directive, ElementRef, EventEmitter, HostListener, Input, Output } from '@angular/core'\n\n@Directive({\n  selecto"
  },
  {
    "path": "src/client/app/shared/directives/html-outlet.directive.ts",
    "chars": 2096,
    "preview": "import {\n  Compiler,\n  Component,\n  ComponentFactory,\n  ComponentRef,\n  Directive,\n  Input,\n  ModuleWithComponentFactori"
  },
  {
    "path": "src/client/app/shared/directives/social-button.directive.ts",
    "chars": 1407,
    "preview": "import { Directive, ElementRef, HostListener, Input, OnInit } from '@angular/core'\n\n@Directive({\n  selector: '[pmSocialB"
  },
  {
    "path": "src/client/app/shared/http-cache-tag/http-cache-tag-interceptor.service.spec.ts",
    "chars": 6542,
    "preview": "import { CACHE_TAG_CONFIG, CACHE_TAG_FACTORY, CacheTagConfig } from './http-cache-tag.module'\nimport { RESPONSE } from '"
  },
  {
    "path": "src/client/app/shared/http-cache-tag/http-cache-tag-interceptor.service.ts",
    "chars": 1211,
    "preview": "import { Inject, Injectable } from '@angular/core'\nimport { HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } fr"
  },
  {
    "path": "src/client/app/shared/http-cache-tag/http-cache-tag.module.ts",
    "chars": 1401,
    "preview": "import { InjectionToken, ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core'\nimport { HTTP_INTERCEP"
  },
  {
    "path": "src/client/app/shared/injection-form/injection-form.component.html",
    "chars": 825,
    "preview": "<form [formGroup]=\"form\" novalidate>\n  <mat-form-field>\n    <input matInput placeholder=\"Element\" type=\"text\" formContro"
  },
  {
    "path": "src/client/app/shared/injection-form/injection-form.component.scss",
    "chars": 27,
    "preview": ":host {\n  display: block;\n}"
  },
  {
    "path": "src/client/app/shared/injection-form/injection-form.component.ts",
    "chars": 1805,
    "preview": "import { BehaviorSubject } from 'rxjs/BehaviorSubject'\nimport { ChangeDetectionStrategy, Component, EventEmitter, Input,"
  },
  {
    "path": "src/client/app/shared/key-value-form/key-value-form.component.html",
    "chars": 925,
    "preview": "<div *ngFor=\"let keyVal of change.asObservable() | async | pmKeyVal; trackBy: trackByFn\">\n  <button mat-icon-button colo"
  },
  {
    "path": "src/client/app/shared/key-value-form/key-value-form.component.scss",
    "chars": 27,
    "preview": ":host {\n  display: block;\n}"
  },
  {
    "path": "src/client/app/shared/key-value-form/key-value-form.component.ts",
    "chars": 1403,
    "preview": "import { BehaviorSubject } from 'rxjs/BehaviorSubject'\nimport { ChangeDetectionStrategy, Component, Input, OnChanges, Ou"
  },
  {
    "path": "src/client/app/shared/login-card/login-card.component.html",
    "chars": 2940,
    "preview": "<mat-spinner *ngIf=\"isLoading\"></mat-spinner>\n<mat-accordion class=\"headers-align\" *ngIf=\"!isLoading\">\n  <mat-expansion-"
  },
  {
    "path": "src/client/app/shared/login-card/login-card.component.scss",
    "chars": 888,
    "preview": ":host {\n  div {\n    display: flex;\n    flex-direction: column;\n    button,\n    p {\n      align-self: center;\n      width"
  },
  {
    "path": "src/client/app/shared/login-card/login-card.component.ts",
    "chars": 3056,
    "preview": "import { PlatformService } from './../services/platform.service'\nimport { Router } from '@angular/router'\nimport { AuthS"
  },
  {
    "path": "src/client/app/shared/material.module.ts",
    "chars": 1801,
    "preview": "import { NgModule } from '@angular/core'\nimport {\n  MatButtonModule, MatCardModule, MatCheckboxModule, MatChipsModule,\n "
  },
  {
    "path": "src/client/app/shared/modal-confirmation/modal-confirmation.component.html",
    "chars": 221,
    "preview": "<h1>{{ title }}</h1>\n<p>{{ message }}</p>\n<div class=\"footer\">\n  <button mat-button (click)=\"dialog.close(false)\">Cancel"
  },
  {
    "path": "src/client/app/shared/modal-confirmation/modal-confirmation.component.scss",
    "chars": 161,
    "preview": ":host {\n  display: flex;\n  flex-direction: column;\n  h1,h2,h3,h4,h5 {\n    margin: 0;\n  }\n  .footer {\n    display: flex;\n"
  },
  {
    "path": "src/client/app/shared/modal-confirmation/modal-confirmation.component.ts",
    "chars": 707,
    "preview": "import { ChangeDetectionStrategy, Component, Inject, Input } from '@angular/core'\nimport { MAT_DIALOG_DATA, MatDialogRef"
  },
  {
    "path": "src/client/app/shared/navbar/__snapshots__/navbar.component.spec.ts.snap",
    "chars": 9597,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`NavbarComponent should compile 1`] = `\n<div\n  id=\"root0\"\n  ng-versi"
  },
  {
    "path": "src/client/app/shared/navbar/navbar.component.html",
    "chars": 1455,
    "preview": "<nav class=\"mat-elevation-z6\">\n  <button id=\"toggle-menu-button\" mat-icon-button (click)=\"menuIconClick.next()\" angulart"
  },
  {
    "path": "src/client/app/shared/navbar/navbar.component.scss",
    "chars": 1038,
    "preview": "@import '../../../../../node_modules/@angular/material/_theming.scss';\n\n:host {\n  z-index: 10;\n  nav {\n    background-co"
  },
  {
    "path": "src/client/app/shared/navbar/navbar.component.spec.ts",
    "chars": 1672,
    "preview": "import { MaterialModule } from '../material.module'\nimport { RouterTestingModule } from '@angular/router/testing'\nimport"
  },
  {
    "path": "src/client/app/shared/navbar/navbar.component.ts",
    "chars": 787,
    "preview": "import { ChangeDetectionStrategy, Component, EventEmitter, HostListener, Input, Output } from '@angular/core'\nimport { N"
  },
  {
    "path": "src/client/app/shared/navbar/navbar.service.spec.ts",
    "chars": 709,
    "preview": "import { async, TestBed } from '@angular/core/testing'\nimport { INavbarService, NavbarService } from './navbar.service'\n"
  },
  {
    "path": "src/client/app/shared/navbar/navbar.service.ts",
    "chars": 371,
    "preview": "import { Observable } from 'rxjs/Observable'\nimport { Injectable } from '@angular/core'\n\nexport interface INavbarService"
  },
  {
    "path": "src/client/app/shared/pipes/key-value.pipe.ts",
    "chars": 340,
    "preview": "import { Pipe, PipeTransform } from '@angular/core'\n\n@Pipe({ name: 'pmKeyVal' })\nexport class KeyValuePipe implements Pi"
  },
  {
    "path": "src/client/app/shared/pipes/keys.pipe.ts",
    "chars": 254,
    "preview": "import { Pipe, PipeTransform } from '@angular/core'\n\n@Pipe({ name: 'pmKeys' })\nexport class KeysPipe implements PipeTran"
  },
  {
    "path": "src/client/app/shared/pipes/sanitize-html.pipe.ts",
    "chars": 359,
    "preview": "import { Pipe, PipeTransform } from '@angular/core'\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser'\n\n"
  },
  {
    "path": "src/client/app/shared/quill-editor/quill-editor.component.html",
    "chars": 82,
    "preview": "<div #editor [innerHTML]=\"content | pmSanitizeHtml\" [class]=\"serverStyles\"> </div>"
  },
  {
    "path": "src/client/app/shared/quill-editor/quill-editor.component.scss",
    "chars": 80,
    "preview": ":host {\n  display: flex;\n  flex-direction: column;\n  flex: 1;\n  height: 100%;\n}\n"
  },
  {
    "path": "src/client/app/shared/quill-editor/quill-editor.component.ts",
    "chars": 2576,
    "preview": "import { BehaviorSubject } from 'rxjs/BehaviorSubject'\nimport { PlatformService } from './../services/platform.service'\n"
  },
  {
    "path": "src/client/app/shared/services/__snapshots__/error-handler.service.spec.ts.snap",
    "chars": 10858,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`App component should build without a problem 1`] = `\n<div\n  id=\"roo"
  },
  {
    "path": "src/client/app/shared/services/adblock.service.spec.ts",
    "chars": 1944,
    "preview": "import { IPlatformService, PlatformService } from './platform.service'\nimport { AdblockService, IAdblockService } from '"
  },
  {
    "path": "src/client/app/shared/services/adblock.service.ts",
    "chars": 641,
    "preview": "import { HttpClient } from '@angular/common/http'\nimport { Injectable } from '@angular/core'\nimport { PlatformService } "
  },
  {
    "path": "src/client/app/shared/services/auth.service.ts",
    "chars": 6429,
    "preview": "import { PlatformService } from './platform.service'\nimport { BehaviorSubject } from 'rxjs/BehaviorSubject'\nimport { Set"
  },
  {
    "path": "src/client/app/shared/services/cookie.service.spec.ts",
    "chars": 708,
    "preview": "import { PlatformService } from './platform.service'\nimport { CookieService, ICookieService } from './cookie.service'\nim"
  },
  {
    "path": "src/client/app/shared/services/cookie.service.ts",
    "chars": 1764,
    "preview": "import { REQUEST } from '@nguniversal/express-engine/tokens'\nimport { PlatformService } from './platform.service'\nimport"
  },
  {
    "path": "src/client/app/shared/services/environment.service.spec.ts",
    "chars": 780,
    "preview": "import { EnvironmentService, IEnvironmentService } from './environment.service'\nimport { async, TestBed } from '@angular"
  },
  {
    "path": "src/client/app/shared/services/environment.service.ts",
    "chars": 433,
    "preview": "import { Inject, Injectable } from '@angular/core'\nimport { ENV_CONFIG } from '../../app.config'\nimport { EnvConfig } fr"
  },
  {
    "path": "src/client/app/shared/services/error-handler.service.spec.ts",
    "chars": 3255,
    "preview": "import { RouterTestingModule } from '@angular/router/testing'\nimport { PlatformService } from './platform.service'\nimpor"
  },
  {
    "path": "src/client/app/shared/services/error-handler.service.ts",
    "chars": 1216,
    "preview": "import { ErrorHandler, Injectable, Injector } from '@angular/core'\nimport { LocationStrategy, PathLocationStrategy } fro"
  },
  {
    "path": "src/client/app/shared/services/firebase-database.service.ts",
    "chars": 2280,
    "preview": "import { PlatformService } from './platform.service'\nimport { Observable } from 'rxjs/Observable'\nimport { Injectable } "
  },
  {
    "path": "src/client/app/shared/services/guard-admin.service.ts",
    "chars": 792,
    "preview": "import { AuthService } from './auth.service'\nimport { Injectable } from '@angular/core'\nimport { ActivatedRouteSnapshot,"
  },
  {
    "path": "src/client/app/shared/services/guard-login.service.ts",
    "chars": 517,
    "preview": "import { AuthService } from './auth.service'\nimport { Injectable } from '@angular/core'\nimport { ActivatedRouteSnapshot,"
  },
  {
    "path": "src/client/app/shared/services/http-config-interceptor.service.spec.ts",
    "chars": 3361,
    "preview": "import { EnvironmentService, IEnvironmentService } from './environment.service'\nimport { HttpConfigInterceptor } from '."
  },
  {
    "path": "src/client/app/shared/services/http-config-interceptor.service.ts",
    "chars": 1115,
    "preview": "import { EnvironmentService } from './environment.service'\nimport { Observable } from 'rxjs/Observable'\nimport { Injecta"
  },
  {
    "path": "src/client/app/shared/services/http-cookie-interceptor.service.spec.ts",
    "chars": 5506,
    "preview": "import { REQUEST } from '@nguniversal/express-engine/tokens'\nimport { IPlatformService, PlatformService } from './platfo"
  },
  {
    "path": "src/client/app/shared/services/http-cookie-interceptor.service.ts",
    "chars": 1536,
    "preview": "import { REQUEST } from '@nguniversal/express-engine/tokens'\nimport { PlatformService } from './platform.service'\nimport"
  },
  {
    "path": "src/client/app/shared/services/injection.service.ts",
    "chars": 1709,
    "preview": "import { DOCUMENT } from '@angular/platform-browser'\nimport { Inject, Injectable, Renderer2 } from '@angular/core'\nimpor"
  },
  {
    "path": "src/client/app/shared/services/logging.service.spec.ts",
    "chars": 1712,
    "preview": "import { PlatformService } from './platform.service'\nimport { ILoggingService, LOGGER_CONFIG, LoggingService } from './l"
  },
  {
    "path": "src/client/app/shared/services/logging.service.ts",
    "chars": 2027,
    "preview": "import { Inject, Injectable, InjectionToken } from '@angular/core'\nimport { createLogger, LoggerOptions } from '@expo/bu"
  },
  {
    "path": "src/client/app/shared/services/minifier.service.ts",
    "chars": 233,
    "preview": "import { Injectable } from '@angular/core'\n\nexport interface IMinifierService {\n  css(css: string): string\n}\n\n@Injectabl"
  }
]

// ... and 126 more files (download for full content)

About this extraction

This page contains the full source code of the patrickmichalina/fusebox-angular-universal-starter GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 326 files (381.1 KB), approximately 108.4k tokens, and a symbol index with 444 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!