npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

my-demo-pkg-test

v0.0.0

Published

A fullstack, multi-feature Angular2/Redux app made from several single-feature apps

Downloads

13

Readme

Build Status Dependency Status

Live Demo

Background and Motivation

This project is my attempt to infer from available demos what the codebase might look like for the real-world, commercial codebases that you don't get to see until you are hired by a real company and sign an NDA.

The rationale behind this is pretty simple...

1. Real, complete code examples are better than docs, lessons and Gitter Q&A. And MUCH better 
than ellipses (...).

2. If you want a job making commercial-grade code, you should study commercial-grade code,
not tutorial-grade code. Anything you learn in a tutorial must be approached with caution 
because corners have probably been cut, it's probably been simplified and it probably doesn't 
show you the exact way anyone does it on a real job. The difference between exact and almost 
exact is huge. Tutorials show you how you *can* use a feature of the technology but often they 
do so in situations when in real life you would not do things that way. This can cost a lot of 
time. It's just as important to know how to use a technology's features as it is to know when.

3. If you want to know how fast a big Angular app will build, run and test before investing
the time to learn Angular - and you should - then you need source code for a big app before
you even write Hello World.

4. If you want to know the complexity limits a technology will place on your app before you
commit to using it, there's no better way than to see a complex example made with that technology.

5. It's a whole lot easier to vet an idea or accept an approach others have taken when you have
a complete application with all of its edge cases to show you what needs to be accommodatedd. 
By containing many edge cases, a big application will quickly answer the common learner's question:
"Why isn't this done the easy way I think it should be done?", or "What if we tried X instead?"

Hopefully, when the project is done it will make the learning process for others much easier and prepare them to make real things rather than instructional ones. I expect it to reduce the time to implement your own real application from months to days.

Coming from different demos, the features of the app are not related to each other and it won't make any sense to have them together but the point is just to demonstrate how things should work technically, so that's okay.

A huge thanks to those who created the example demos from which I put together this amalgam.

To make this big app from the small ones, I took these projects and integrated/restructured/restyled their code according to the following pesplritization. Disagreements in approach between two influences are resolved by the lower authority yielding to the higher one:

  1. Angular Style Guide by Google
  2. Tour of Heroes (ngModules, Routing, App Specs, HTTP, Server Communication versions) by Google
  3. Angular CLI by Google and the community
  4. Redux Docs Redux.org
  5. ngrx example app - book collection by @MikeRyan52
  6. angular-seed-advanced by Minko Gechev + Nathan Walker + community
  7. ng2-state-talk - drag/editable notes by @JavascriptMick
  8. rangle-starter Angular 2 with TypeScript and Redux version - counter by @SethDavenport

In addition to the features from these demos, I added one of my own. I replaced

  1. this other project

which was made with JQuery and Google Scripts. The data is contained in this Google Sheet and served as JSON by a Google script.

See the Angular Change log for updates to the Angular team's opinions.

My Innovations

While the goal of the project is to combine the wisdom of different experts, nobody can resist introducing improvements when there's no obvious case against doing so. So you will see a couple of practices in this project that came from my head rather than the sources of expertise from which the project was assembled. If you can think of reasons not to do these things, please let me know.

  1. I have put the Redux store reducers in app/core/store separate from the feature directories located under app and did not make folders for reducers, actions, and effects. There is a many-to-many relationship between Redux store slices and features. So putting the Redux code for a given slice into the same directory as one of the features that uses it doesn't make sense. How do you decide which feature gets it?

  2. As much as practical the names of files in a directory begin with the directory name. I did this to prevent directories from having a mixture of unrelated concerns. If a directory in a source demo had files for two different things, I created more directories. I thought about removing that part of the file name, src/app/app.page.ts -> src/app/page.ts, for the sake of DRY, but that makes it too confusing when you are working on multiple files with the same names and different directories.

  3. I noticed a lot of duplication and boilerplate of identical CRUD code for each of my types of entities. So I made utility functions and the related actions and models for each of three types of store slice - entities, id lists, and slices (everything else).

  4. I came up with a mini lexicon of file types to keep file names shorter and more expressive. A "page" is understood to be a smart @Component class that fills the page and might have a router-outlet and route configurations. A "guard" is understood to be an @Injectable "service" class that returns a boolean. A "routing" is a @NgModule class that contains route configurations. So I memorize this simple lexicon, and drop the redundant, less-clear words from the names. For example, I use the name app.page.ts rather than app.component.ts or app-page.component.ts. I use auth.guard.ts instead of auth-guard.service.ts. I use books.routing.ts instead of books-routing.module.ts.

| A | is a class decorated with | that | Example file name | Example class name | |:--- | :--- | :--- | :--- | :--- | | page | @Component | more or less fills the screen - a "smart" component that gets data from something other than @Inputs and dispatches actions to change state | app.page.ts | AppPage | | component | @Component | has to be contained by a page or other components - a "dumb" component that only gets data from @Inputs | login.component.ts | LoginComponent | | guard | @Injectable | returns a boolean and does whatever an Angular guard does | auth.guard.ts | AuthGuard | | service | @Injectable | provides a service or data | auth.service.ts | AuthService | | routing | @NgModule | contains route configurations | books.routing.ts | BooksRouting | | module | @NgModule | associates related components and providers | books.module.ts | BooksModule |

That's it. It shouldn't be too hard to remember these, and in return you will have consistent, short, expressive file names.

Prerequisites

You will need to have Git and Node.js + NPM installed on your machine.

You will also need to install the angular-cli NPM package globally via npm i -g angular-cli.

If you want to debug server-side code, install Visual Studio Code. This project has the configuration to use VS Code for debugging.

If you want to Dockerize your app, go here to setup Docker, and install PhantomJS. It's used by Docker.

Make it go

This is a standard angular-cli generated application so you can use all of the ng XXX commands to manage the application.

# Download the code
$ git clone https://github.com/dancancro/great-big-angular2-example.git
$ cd great-big-angular2-example

# Install dependencies
$ npm install

# Run the backend server 

... in debug mode
Select Launch via NPM from VSCode debug menu. Click DEBUG.

... without debugging
$npm run dev:server

# Build and start the frontend server
$ npm run dev:client

# Continuously run the tests
$ ng test

Then navigate to http://localhost:4200 in your browser. If you get stuck on anything, no matter how little, please let me know. I know how the little things are what cause the problems and I don't want you to have any problems.

Special Heroku instruction

Set Config var NPM_CONFIG_PRODUCT to false on the Settings tab of your app admin page.

Blocking Dependency Issues

| Issue | Description | Features | | :-- | :-- | :-- | | 14480 | Angular 2 relative pathing from siblings doesn't work | Compose Message box on Crisis Center and login success routing | | 14201 | Duplicate instantiation of lazy loaded modules | ngrx Effects | | 3781 | Cannot read property 'newLine' of undefined | Travis build |

And other problems

There's something the matter with TypeScript that produces warnings claiming certain classes can't be found. This was merely annoying until a new release of angular-cli came out that put an overlay with warnings on top of the app instead of just putting them in the console.

To turn off this new overlay, you need to change line 140 of node_modules/@angular/cli/tasks/serve.js from

overlay: serveTaskOptions.target === 'development'

to

overlay: false // serveTaskOptions.target === 'development'

FAQ

1) In many ngrx examples it seems like there is a lot of boilerplate and duplicate code per store slice. Why not have the Action Types be created dynamically by combining the store slice name nouns and action name verbs?

I agree. That's why I created utility functions to hold all the common code and got rid of plural names to enable generic handling, and I replaced static action type definitions with dynamic functions that combine slice nouns and action verbs. It also turns out that most of the tricky RxJS code is also boilerplate code that now resides inside functions that you don't have to mess with most of the time. So you should be able to get productive on an app that uses Observables without first having to be an expert at them, which is hard.

That's a pretty big benefit. What could be seen as costs of doing that?

  1. You lose some static type checking of action types.

Given that most Redux apps are done with React and React doesn't have any static type checking at all, I decided that was a small price to pay. You can also mix this approach and the other one if you really want to. Use the general, un-type-checked, CRUD stuff for ordinary parts of your app (most of it), and use hard-coded, specialty action types when you really need TypeScript's compiler to help you.

Here's some code from the ngrx example app that gives you type checking for the action types. You won't get these checks using my approach.

export function reducer(state: Entities<Book> = initialEntities<Book>({}, slices.BOOK, actions, {}),
  action: book.Actions | collection.Actions): Entities<Book> {
  switch (action.type) {
    ...

action: book.Actions | collection.Actions means that action must be an object of a class in this union of two unions of class definitions

That gives us two checks: action.type must be a string value among the union of string values of the type properties of the classes that action can be. If any of the case values are not among this union of string values, Typescript will point that out to you. And same with action.payload. It must be an object with the structure of the payload property of one of the classes that action can be.

  1. Using only generic action classes like LoadSuccess instead of SearchComplete, the dispatch calls in your components will be more explicit and refer to details of the store.

I see this as a plus in most cases. Otherwise you have extraneous levels of abstraction and you have to look into three files to see exactly what's going on. In most cases, the same person is writing the component, action and reducer files, so what's the point in hiding details in one of them from the other? Now you can get the whole story by reading one line of code. You should decouple things when the need arises, but you can overdo it too.

2) Why isn't the server directory under /src? It contains source code.

This directory is not located inside /src because if it were there then the front-end server which watches /src would restart after any change to back-end code. That can probably be fixed by configuring which I haven't done.

3) Why are entities modeled as a hash (map) of objects and an array of IDs instead of just an array of objects?

I got the idea from the ngrx example app. I asked about it once and was told that it was done for performance reasons but I'm not sure under what conditions they apply.

Any other questions? Just ask.

Demonstrations and Features

| Developer Experience |great big angular2 example|Angular-kitchen-sink|ngrx example app|angular-redux-starter|angular-seed-advanced| |:------ | :------: | :------: | :------: | :------: | :------: | Authentication|X|X| |X| | Authentication, with two-factor authentication| |UNIQUE| | | | Can run on a desktop without a browser| | | | |UNIQUE| Client-side unit tests|X|X| |X|X| Code coverage reporting (?)|X|X|X|X| | Command line interface (CLI)|X|X|X|X| | Compiled, supports ahead of time (AOT) compilation| | | | |UNIQUE| Components communicate with events|X|X|X| | | Core Module|X| | | |X| CSS style checking|X| | |X| | Deployment automation, to a mobile native executable| | | | |UNIQUE| Deployment automation, using Docker (?)|X| | |X|X| Deployment automation, using Heroku (?)|X| | |X| | Error handling, Client-side logging| | | |X|X| In-memory server-side database| |UNIQUE| | | | Local storage|X|X|X|X| | No pluralization|UNIQUE| | | | | Production build, generate docs (?)| |X| | |X| Separation of smart containers and dumb components (?)|X| |X| | | Server-side integration & unit tests|X|X|X| | | Shared Module|X|X| | | | Single source of truth, central state management, without lots of boilerplate (?)|UNIQUE| | | | | Style guide for code (?)|X| | | |X| There is a book about it| | | |UNIQUE| | Update generated code in an existing app| | | | |UNIQUE| | | | | | | | User Experience |great big angular2 example|Angular-kitchen-sink|ngrx example app|angular-redux-starter|angular-seed-advanced| Account Management, Forgotten Password with Resetting| |UNIQUE| | | | Account Management, login/logout|X|X| |X| | Analytics| | | | |UNIQUE| Asynchronously loaded data example|X|X|X| |X| Breadcrumbs (?)| |UNIQUE| | | | Derived, computed properties|X|X| | | | Dynamic component creation| |UNIQUE| | | | External, 3rd party, API interaction|X|X|X| | | Footer| |UNIQUE| | | | Front-end CRUD|X|X| | |X| Full-stack CRUD (?)|X|X| | | | Full-stack CRUD, with Create, Update and Delete|X|X| | | | Full-stack CRUD, with Create, Update and Delete, individual records|X|X| | | | Full-stack CRUD, with Create, Update and Delete, whole data structures|UNIQUE| | | | | Full-stack CRUD, with Read|X|X| | | | i18n, localization (?)| | | | |UNIQUE| Many-to-many data|UNIQUE| | | | | Mouse wheel (?)| |UNIQUE| | | | Navigation bar|X|X|X| | | Panels, draggable|X|X| | | | Responsive styles|X| | |X| | Search, actually works with backend API|X| |X| | | | | | | | | | Dependencies |great big angular2 example|Angular-kitchen-sink|ngrx example app|angular-redux-starter|angular-seed-advanced| Backend Frameworks |Express | | |Express |Express Client-side API interfaces |@angular/http |@angular/http |@angular/http |@angular/http |@angular/http Continuous integration testers |Travis | | | |Travis Convenience method libraries |lodash |lodash |lodash | |lodash Databases | |Redis | | | Documentation generators | |typedoc | | |typedoc Frontend Frameworks |Angular 2.0 |Angular 2.0 |Angular 2.0 |Angular 2.0 |Angular 2.0 Languages |JS ES5, JS ES6 (ES2015), JSX (opt), Typescript |JS ES5, JS ES6 (ES2015), Typescript |JS ES5, JS ES6 (ES2015), Typescript |JS ES5, JS ES6 (ES2015), JSX (opt), Python, Typescript |JS ES2016, JS ES5, JS ES6 (ES2015), Typescript Linters |codelyzer, ESLint, stylelint, tslint | |codelyzer, tslint |ESLint, stylelint |codelyzer, tslint Loaders/Bundlers |Webpack |Webpack |Webpack |Webpack |Rollup, SystemJS Misc |Angular Style Guide, Helmet, nodemon, Redux, redux-devtools, RxJS |Immutable, Redux, redux-devtools, RxJS |Redux, redux-devtools, RxJS (opt) |autoprefixer, cssnano, Helmet, Immutable, nodemon, Redux, redux-devtools, redux-logging, RxJS |Angular Style Guide, cssnano, Electron, Redux, redux-devtools, RxJS Package Managers |npm |npm |npm |npm |npm Routers |Angular Component Router |Angular Component Router |Angular Component Router |Angular Component Router |Angular Component Router Runtime Environments |Node |Node |Node |Node |NativeScript, Node Stacks |angular-cli |angular-cli |angular-cli | |mgechev's angular-seed State Managers |ngrx |ng-redux |ngrx |ng-redux |ngrx Task Runners | |Gulp | | |Gulp Test assertion libraries |Chai, Jasmine, Mocha |Chai, Jasmine, Mocha |Chai, Jasmine, Mocha |Jasmine |Jasmine Test coverage reporters |Istanbul | | |Istanbul | Test runners |Karma | |Karma, Protractor |Karma, Robot |BrowserSync (opt), Karma Transpilers |libsass |libsass |libsass |libsass | Widget collections |Angular Material |Angular Material | | |

File Structure

.
├── README.md
├── docker-compose.production.yml
├── docker-compose.yml
├── e2e
│   ├── about.e2e-spec.ts
│   ├── app.e2e-spec.ts
│   ├── app.po.ts
│   ├── not-found.e2e-spec.ts
│   └── tsconfig.e2e.json
├── karma.conf.js
├── nodemon.json
├── package.json
├── protractor.conf.js
├── proxy.conf.json
├── server
│   ├── Procfile
│   ├── auth-passport.js
│   ├── db
│   │   ├── claim.json
│   │   ├── claimRebuttal.json
│   │   ├── contact.json
│   │   ├── crisis.json
│   │   ├── hero.json
│   │   ├── note.json
│   │   ├── rebuttal.json
│   │   └── user.json
│   ├── node-proxy.js
│   ├── node-server.js
│   ├── proxy-config.js
│   └── webpack-dev-proxy.js
├── src
│   ├── app
│   │   ├── app.module.ts
│   │   ├── app.page.css
│   │   ├── app.page.html
│   │   ├── app.page.spec.ts
│   │   ├── app.page.ts
│   │   ├── app.routing.ts
│   │   ├── app.spec.ts
│   │   ├── bernie
│   │   │   ├── README.md
│   │   │   ├── bernie.module.ts
│   │   │   ├── bernie.page.css
│   │   │   ├── bernie.page.html
│   │   │   ├── bernie.page.ts
│   │   │   ├── bernie.routing.ts
│   │   │   ├── claim
│   │   │   │   ├── claim.component.css
│   │   │   │   ├── claim.component.html
│   │   │   │   ├── claim.component.spec.ts
│   │   │   │   └── claim.component.ts
│   │   │   └── rebuttal
│   │   │       ├── rebuttal.component.css
│   │   │       ├── rebuttal.component.html
│   │   │       ├── rebuttal.component.spec.ts
│   │   │       └── rebuttal.component.ts
│   │   ├── books
│   │   │   ├── README.md
│   │   │   ├── add-commas
│   │   │   │   └── add-commas.pipe.ts
│   │   │   ├── book-authors
│   │   │   │   └── book-authors.component.ts
│   │   │   ├── book-detail
│   │   │   │   └── book-detail.component.ts
│   │   │   ├── book-exists
│   │   │   │   └── book-exists.guard.ts
│   │   │   ├── book-preview
│   │   │   │   ├── book-preview-list.component.ts
│   │   │   │   └── book-preview.component.ts
│   │   │   ├── book-search
│   │   │   │   └── book-search.component.ts
│   │   │   ├── books.module.ts
│   │   │   ├── books.routing.ts
│   │   │   ├── collection.page.spec.ts
│   │   │   ├── collection.page.ts
│   │   │   ├── ellipsis
│   │   │   │   ├── ellipsis.pipe.ts
│   │   │   │   └── ellipsis.spec.ts
│   │   │   ├── find-book.page.ts
│   │   │   ├── selected-book.page.ts
│   │   │   └── view-book.page.ts
│   │   ├── contact
│   │   │   ├── contact.module.ts
│   │   │   ├── contact.page.css
│   │   │   ├── contact.page.html
│   │   │   ├── contact.page.ts
│   │   │   └── contact.routing.ts
│   │   ├── core
│   │   │   ├── about
│   │   │   │   └── about.page.ts
│   │   │   ├── auth
│   │   │   │   ├── auth.guard.ts
│   │   │   │   ├── auth.module.ts
│   │   │   │   ├── auth.service.ts
│   │   │   │   └── login
│   │   │   │       ├── login-form
│   │   │   │       │   ├── login-form.component.css
│   │   │   │       │   ├── login-form.component.spec.ts
│   │   │   │       │   └── login-form.component.ts
│   │   │   │       ├── login-modal
│   │   │   │       │   ├── login-modal.component.spec.ts
│   │   │   │       │   └── login-modal.component.ts
│   │   │   │       ├── login.component.ts
│   │   │   │       ├── login.module.ts
│   │   │   │       └── login.routing.ts
│   │   │   ├── core.module.ts
│   │   │   ├── core.routing.ts
│   │   │   ├── index.ts
│   │   │   ├── interfaces
│   │   │   │   ├── iconsole.ts
│   │   │   │   ├── ilang.ts
│   │   │   │   ├── index.ts
│   │   │   │   └── iwindow.ts
│   │   │   ├── navigator
│   │   │   │   ├── layout.component.ts
│   │   │   │   ├── nav-item.component.ts
│   │   │   │   ├── navigator.module.ts
│   │   │   │   ├── sidenav.component.ts
│   │   │   │   └── toolbar.component.ts
│   │   │   ├── not-found
│   │   │   │   └── not-found.page.ts
│   │   │   ├── platform
│   │   │   │   ├── platform.directive.spec.ts
│   │   │   │   └── platform.directive.ts
│   │   │   ├── services
│   │   │   │   ├── app.service.ts
│   │   │   │   ├── console.service.ts
│   │   │   │   ├── data.service.spec.ts
│   │   │   │   ├── data.service.ts
│   │   │   │   ├── default-request-options.service.ts
│   │   │   │   ├── exception.service.ts
│   │   │   │   ├── in-memory-data.service.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── log.service.spec.ts
│   │   │   │   ├── log.service.ts
│   │   │   │   ├── router-extensions.service.ts
│   │   │   │   ├── user.service.ts
│   │   │   │   └── window.service.ts
│   │   │   ├── spinner.component.ts
│   │   │   ├── store
│   │   │   │   ├── book
│   │   │   │   │   ├── book.effects.spec.ts
│   │   │   │   │   ├── book.effects.ts
│   │   │   │   │   ├── book.model.ts
│   │   │   │   │   ├── book.reducer.ts
│   │   │   │   │   └── google-books.service.ts
│   │   │   │   ├── claim
│   │   │   │   │   ├── README.md
│   │   │   │   │   ├── claim.effects.ts
│   │   │   │   │   ├── claim.model.ts
│   │   │   │   │   └── claim.reducer.ts
│   │   │   │   ├── claim-rebuttal
│   │   │   │   │   ├── claim-rebuttal.effects.ts
│   │   │   │   │   ├── claim-rebuttal.model.ts
│   │   │   │   │   └── claim-rebuttal.reducer.ts
│   │   │   │   ├── collection
│   │   │   │   │   ├── collection.effects.spec.ts
│   │   │   │   │   ├── collection.effects.ts
│   │   │   │   │   └── collection.reducer.ts
│   │   │   │   ├── contact
│   │   │   │   │   ├── contact.effects.ts
│   │   │   │   │   ├── contact.model.ts
│   │   │   │   │   └── contact.reducer.ts
│   │   │   │   ├── counter
│   │   │   │   │   ├── counter.actions.test.ts
│   │   │   │   │   ├── counter.effects.ts
│   │   │   │   │   ├── counter.model.ts
│   │   │   │   │   └── counter.reducer.ts
│   │   │   │   ├── crisis
│   │   │   │   │   ├── crisis.effects.ts
│   │   │   │   │   ├── crisis.model.ts
│   │   │   │   │   └── crisis.reducer.ts
│   │   │   │   ├── db.ts
│   │   │   │   ├── entity
│   │   │   │   │   ├── entity.actions.ts
│   │   │   │   │   ├── entity.functions.ts
│   │   │   │   │   └── entity.model.ts
│   │   │   │   ├── hero
│   │   │   │   │   ├── hero.effects.ts
│   │   │   │   │   ├── hero.model.ts
│   │   │   │   │   └── hero.reducer.ts
│   │   │   │   ├── id
│   │   │   │   │   ├── id.actions.ts
│   │   │   │   │   ├── id.functions.ts
│   │   │   │   │   └── id.model.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── layout
│   │   │   │   │   ├── layout.model.ts
│   │   │   │   │   └── layout.reducer.ts
│   │   │   │   ├── note
│   │   │   │   │   ├── note.effects.ts
│   │   │   │   │   ├── note.model.ts
│   │   │   │   │   └── note.reducer.ts
│   │   │   │   ├── rebuttal
│   │   │   │   │   ├── rebuttal.effects.ts
│   │   │   │   │   ├── rebuttal.model.ts
│   │   │   │   │   └── rebuttal.reducer.ts
│   │   │   │   ├── search
│   │   │   │   │   └── search.reducer.ts
│   │   │   │   ├── session
│   │   │   │   │   ├── session.effects.ts
│   │   │   │   │   ├── session.model.ts
│   │   │   │   │   └── session.reducer.ts
│   │   │   │   ├── slice
│   │   │   │   │   ├── slice.actions.ts
│   │   │   │   │   └── slice.functions.ts
│   │   │   │   └── util.ts
│   │   │   ├── title
│   │   │   │   ├── title.component.html
│   │   │   │   └── title.component.ts
│   │   │   └── utils
│   │   │       ├── config.spec.ts
│   │   │       ├── config.ts
│   │   │       ├── index.ts
│   │   │       ├── type.ts
│   │   │       ├── view-broker.spec.ts
│   │   │       └── view-broker.ts
│   │   ├── counter
│   │   │   ├── README.md
│   │   │   ├── counter.component.css
│   │   │   ├── counter.component.ts
│   │   │   ├── counter.module.ts
│   │   │   ├── counter.page.ts
│   │   │   └── counter.routing.ts
│   │   ├── heroes
│   │   │   ├── admin
│   │   │   │   ├── admin-dashboard
│   │   │   │   │   └── admin-dashboard.component.ts
│   │   │   │   ├── admin.module.ts
│   │   │   │   ├── admin.page.css
│   │   │   │   ├── admin.page.ts
│   │   │   │   └── admin.routing.ts
│   │   │   ├── crisis-center
│   │   │   │   ├── compose-message
│   │   │   │   │   ├── compose-message.component.html
│   │   │   │   │   └── compose-message.component.ts
│   │   │   │   ├── crisis-center-home
│   │   │   │   │   └── crisis-center-home.component.ts
│   │   │   │   ├── crisis-center.module.ts
│   │   │   │   ├── crisis-center.page.css
│   │   │   │   ├── crisis-center.page.html
│   │   │   │   ├── crisis-center.page.ts
│   │   │   │   ├── crisis-center.routing.ts
│   │   │   │   ├── crisis-detail
│   │   │   │   │   ├── crisis-detail-resolver.service.ts
│   │   │   │   │   └── crisis-detail.component.ts
│   │   │   │   └── crisis-list
│   │   │   │       ├── crisis-list.component.css
│   │   │   │       └── crisis-list.component.ts
│   │   │   ├── dashboard
│   │   │   │   ├── dashboard-crisis
│   │   │   │   │   ├── dashboard-crisis.component.css
│   │   │   │   │   ├── dashboard-crisis.component.html
│   │   │   │   │   └── dashboard-crisis.component.ts
│   │   │   │   ├── dashboard-hero
│   │   │   │   │   ├── dashboard-hero.component.css
│   │   │   │   │   ├── dashboard-hero.component.html
│   │   │   │   │   ├── dashboard-hero.component.spec.ts
│   │   │   │   │   └── dashboard-hero.component.ts
│   │   │   │   ├── dashboard.component.css
│   │   │   │   ├── dashboard.component.html
│   │   │   │   ├── dashboard.component.ts
│   │   │   │   ├── dashboard.module.ts
│   │   │   │   ├── dashboard.routing.ts
│   │   │   │   └── hero-search
│   │   │   │       ├── hero-search.component.css
│   │   │   │       ├── hero-search.component.html
│   │   │   │       └── hero-search.component.ts
│   │   │   ├── hero
│   │   │   │   ├── hero-detail
│   │   │   │   │   ├── hero-detail.component.css
│   │   │   │   │   ├── hero-detail.component.html
│   │   │   │   │   ├── hero-detail.component.no-testbed.spec.ts
│   │   │   │   │   ├── hero-detail.component.spec.ts
│   │   │   │   │   └── hero-detail.component.ts
│   │   │   │   ├── hero-list
│   │   │   │   │   ├── hero-list.component.css
│   │   │   │   │   ├── hero-list.component.html
│   │   │   │   │   ├── hero-list.component.spec.ts
│   │   │   │   │   └── hero-list.component.ts
│   │   │   │   ├── hero.module.ts
│   │   │   │   └── hero.routing.ts
│   │   │   ├── heroes.module.ts
│   │   │   ├── heroes.page.css
│   │   │   ├── heroes.page.html
│   │   │   ├── heroes.page.ts
│   │   │   └── heroes.routing.ts
│   │   ├── notes
│   │   │   ├── README.md
│   │   │   ├── add-button
│   │   │   │   ├── add-button.component.css
│   │   │   │   ├── add-button.component.html
│   │   │   │   └── add-button.component.ts
│   │   │   ├── note
│   │   │   │   ├── note.component.css
│   │   │   │   ├── note.component.html
│   │   │   │   └── note.component.ts
│   │   │   ├── notes.module.ts
│   │   │   ├── notes.page.css
│   │   │   ├── notes.page.html
│   │   │   ├── notes.page.spec.ts
│   │   │   ├── notes.page.ts
│   │   │   └── notes.routing.ts
│   │   ├── shared
│   │   │   ├── alert
│   │   │   │   ├── alert.component.spec.ts
│   │   │   │   ├── alert.component.ts
│   │   │   │   └── index.ts
│   │   │   ├── analytics
│   │   │   │   ├── analytics.module.ts
│   │   │   │   ├── index.ts
│   │   │   │   └── services
│   │   │   │       ├── analytics.service.spec.ts
│   │   │   │       └── analytics.service.ts
│   │   │   ├── animations.ts
│   │   │   ├── awesome
│   │   │   │   └── awesome.pipe.ts
│   │   │   ├── banner
│   │   │   │   ├── banner.component.css
│   │   │   │   ├── banner.component.detect-changes.spec.ts
│   │   │   │   ├── banner.component.html
│   │   │   │   ├── banner.component.spec.ts
│   │   │   │   └── banner.component.ts
│   │   │   ├── button
│   │   │   │   ├── button.component.spec.ts
│   │   │   │   ├── button.component.ts
│   │   │   │   └── index.ts
│   │   │   ├── can-deactivate
│   │   │   │   └── can-deactivate.guard.ts
│   │   │   ├── container
│   │   │   │   ├── container.component.spec.ts
│   │   │   │   └── container.component.ts
│   │   │   ├── dialog
│   │   │   │   └── dialog.service.ts
│   │   │   ├── draggable
│   │   │   │   └── draggable.directive.ts
│   │   │   ├── form
│   │   │   │   ├── form.component.spec.ts
│   │   │   │   ├── form.component.ts
│   │   │   │   └── index.ts
│   │   │   ├── form-error
│   │   │   │   ├── form-error.component.spec.ts
│   │   │   │   └── form-error.component.ts
│   │   │   ├── form-group
│   │   │   │   ├── form-group.component.spec.ts
│   │   │   │   └── form-group.component.ts
│   │   │   ├── highlight
│   │   │   │   ├── highlight.directive.spec.ts
│   │   │   │   └── highlight.directive.ts
│   │   │   ├── input
│   │   │   │   ├── input.component.spec.ts
│   │   │   │   └── input.component.ts
│   │   │   ├── label
│   │   │   │   ├── label.component.spec.ts
│   │   │   │   └── label.component.ts
│   │   │   ├── logo
│   │   │   │   ├── index.ts
│   │   │   │   ├── logo.component.css
│   │   │   │   ├── logo.component.spec.ts
│   │   │   │   └── logo.component.ts
│   │   │   ├── modal
│   │   │   │   ├── modal.component.css
│   │   │   │   ├── modal.component.spec.ts
│   │   │   │   └── modal.component.ts
│   │   │   ├── modal-content
│   │   │   │   ├── modal-content.component.spec.ts
│   │   │   │   └── modal-content.component.ts
│   │   │   ├── selective-preloading-strategy.ts
│   │   │   ├── shared.module.ts
│   │   │   ├── test
│   │   │   │   ├── browser-test-shim.js
│   │   │   │   ├── e2e
│   │   │   │   │   └── dropdowns.ts
│   │   │   │   ├── jasmine-matchers.d.ts
│   │   │   │   ├── jasmine-matchers.ts
│   │   │   │   ├── mocks
│   │   │   │   │   ├── mock-location-strategy.ts
│   │   │   │   │   ├── ng2-config.mock.ts
│   │   │   │   │   ├── router-extensions.mock.ts
│   │   │   │   │   └── window.mock.ts
│   │   │   │   ├── providers
│   │   │   │   │   ├── core.ts
│   │   │   │   │   ├── http.ts
│   │   │   │   │   └── router.ts
│   │   │   │   ├── router-stubs.ts
│   │   │   │   ├── shorthand
│   │   │   │   │   └── ng2-jasmine.ts
│   │   │   │   ├── test.module.ts
│   │   │   │   └── util.ts
│   │   │   ├── title-case
│   │   │   │   ├── title-case.pipe.spec.ts
│   │   │   │   └── title-case.pipe.ts
│   │   │   ├── twain
│   │   │   │   ├── twain.component.spec.ts
│   │   │   │   ├── twain.component.ts
│   │   │   │   └── twain.service.ts
│   │   │   └── welcome
│   │   │       ├── welcome.component.spec.ts
│   │   │       └── welcome.component.ts
│   │   └── wiki
│   │       ├── wiki-smart.component.ts
│   │       ├── wiki.component.ts
│   │       ├── wiki.css
│   │       ├── wiki.module.ts
│   │       ├── wiki.page.ts
│   │       ├── wiki.routing.ts
│   │       └── wikipedia.service.ts
│   ├── assets
│   │   ├── bernie-app.png
│   │   ├── bernie-sanders-128.jpg
│   │   ├── bernie-spreadsheet.png
│   │   ├── collection.png
│   │   ├── counter.png
│   │   ├── notes.png
│   │   ├── question-mark.png
│   │   ├── rangleio-logo.svg
│   │   └── styles
│   │       ├── align.css
│   │       ├── background-colors.css
│   │       ├── basscss.scss
│   │       ├── colors.css
│   │       ├── flexbox.css
│   │       ├── grid.css
│   │       ├── hero-styles.css
│   │       ├── heroes.css
│   │       ├── hide.css
│   │       ├── index.scss
│   │       ├── media-object.css
│   │       ├── position.css
│   │       ├── responsive-margin.css
│   │       └── responsive-padding.css
│   ├── environments
│   │   ├── environment.prod.ts
│   │   └── environment.ts
│   ├── favicon.ico
│   ├── index.html
│   ├── main.ts
│   ├── polyfills.ts
│   ├── styles.scss
│   ├── test.ts
│   ├── tsconfig.app.json
│   └── tsconfig.spec.json
├── tsconfig.json
└── tslint.json