Full Code of codeschool/NoteWrangler for AI

master 86e64771ea12 cached
91 files
1.3 MB
354.4k tokens
299 symbols
1 requests
Download .txt
Showing preview only (1,414K chars total). Download the full file or copy to clipboard to get everything.
Repository: codeschool/NoteWrangler
Branch: master
Commit: 86e64771ea12
Files: 91
Total size: 1.3 MB

Directory structure:
gitextract_2p63vstu/

├── .gitignore
├── .nvmrc
├── Gruntfile.js
├── README-old.md
├── README.md
├── app/
│   ├── css/
│   │   └── application.css
│   ├── fonts/
│   │   └── icons.otf
│   ├── js/
│   │   ├── app.js
│   │   ├── controllers/
│   │   │   ├── notes-create-controller.js
│   │   │   ├── notes-edit-controller.js
│   │   │   ├── notes-index-controller.js
│   │   │   ├── notes-show-controller.js
│   │   │   ├── profile-edit-controller.js
│   │   │   ├── users-index-controller.js
│   │   │   └── users-show-controller.js
│   │   ├── directives/
│   │   │   ├── nw-card.js
│   │   │   ├── nw-category-item.js
│   │   │   ├── nw-category-select.js
│   │   │   ├── nw-page-nav-item.js
│   │   │   ├── nw-session.js
│   │   │   └── title.js
│   │   ├── filters/
│   │   │   └── notes-filter.js
│   │   ├── resources/
│   │   │   ├── note.js
│   │   │   └── user.js
│   │   ├── routes.js
│   │   ├── services/
│   │   │   ├── category.js
│   │   │   ├── markdown.js
│   │   │   ├── note.js
│   │   │   ├── session.js
│   │   │   └── user.js
│   │   └── vendor/
│   │       ├── angular-resource.js
│   │       ├── angular-route.js
│   │       ├── angular.js
│   │       ├── bootstrap.js
│   │       ├── gravatar.js
│   │       ├── jquery.js
│   │       ├── markdown.js
│   │       └── md5.js
│   ├── sass/
│   │   ├── application.sass
│   │   ├── components/
│   │   │   ├── _bucket.sass
│   │   │   ├── _card.sass
│   │   │   ├── _cell.sass
│   │   │   ├── _form.sass
│   │   │   ├── _grid.sass
│   │   │   ├── _list.sass
│   │   │   ├── _panel.sass
│   │   │   ├── _row.sass
│   │   │   └── _well.sass
│   │   ├── foundation/
│   │   │   ├── _base.sass
│   │   │   ├── _config.sass
│   │   │   ├── _helpers.sass
│   │   │   └── _reset.scss
│   │   ├── structures/
│   │   │   ├── _button.sass
│   │   │   ├── _dropdown.sass
│   │   │   ├── _hero.sass
│   │   │   ├── _icons.sass
│   │   │   ├── _registration.sass
│   │   │   └── _sort.sass
│   │   └── vendor/
│   │       └── _tooltip.sass
│   ├── server/
│   │   ├── modules/
│   │   │   ├── dataSeeds.js
│   │   │   ├── encrypt.js
│   │   │   ├── expressConfig.js
│   │   │   ├── models/
│   │   │   │   ├── category.js
│   │   │   │   ├── note.js
│   │   │   │   └── user.js
│   │   │   ├── models.js
│   │   │   ├── routes/
│   │   │   │   ├── category.js
│   │   │   │   ├── note.js
│   │   │   │   ├── session.js
│   │   │   │   └── user.js
│   │   │   └── routes.js
│   │   └── views/
│   │       ├── index.html
│   │       └── session/
│   │           ├── sign_in.ejs
│   │           └── sign_up.ejs
│   └── templates/
│       ├── .gitkeep
│       ├── directives/
│       │   ├── nw-card.html
│       │   ├── nw-category-item.html
│       │   ├── nw-category-select.html
│       │   ├── nw-page-nav-item.html
│       │   └── nw-session.html
│       └── pages/
│           ├── notes/
│           │   ├── edit.html
│           │   ├── index.html
│           │   └── show.html
│           ├── profile/
│           │   └── edit.html
│           └── users/
│               ├── index.html
│               └── show.html
├── app.js
├── dbSeed.js
├── inspector-config.json
├── npm-shrinkwrap.json
└── package.json

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

================================================
FILE: .gitignore
================================================
/node_modules
npm-debug.log
.DS_Store

================================================
FILE: .nvmrc
================================================
5.5.0


================================================
FILE: Gruntfile.js
================================================
module.exports = function(grunt) {
  grunt.initConfig({
    sass: {
      dist: {
        files: {
          'app/css/application.css': 'app/sass/application.sass'
        }
      }
    },
    watch: {
      css: {
        files: ['app/sass/**/*.sass'],
        tasks: ['sass'],
        options: {
          livereload: true,
        },
      },
    }
  });

  // Load the npm installed tasks
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-sass');
  grunt.registerTask('default', ['sass','watch']);
};


================================================
FILE: README-old.md
================================================
# angular-seed — the seed for AngularJS apps

This project started from the Angular seed app: [AngularJS](http://angularjs.org/) .
You can use it to quickly bootstrap your angular webapp projects and dev environment for these
projects.

For this specific Code School project we will not be testing, so we have removed all things testing related for simplicity.

## Getting Started

To get you started you can simply clone the angular-ansible repo and install the dependencies:

### Prerequisites

You need git to clone the angular-ansible repository. You can get it from
[http://](http://). **alyssa here**

We also use a number of node.js tools to initialize and include packages for angular-ansible. You must have node.js and its package manager (npm) installed.  You can get them from [http://nodejs.org/](http://nodejs.org/).

### Clone angular-seed

If you would like to start from the angular-seed project you can clone it using [git][git]:

```
git clone https://github.com/angular/angular-seed.git
cd angular-seed
```

If you would like to start with the fully completed angular-ansible repository you can clone like so using [git][git]:

```
git clone https://github.com/...
cd angular-seed
```
**alyssa here**

### Install Dependencies

We have two kinds of dependencies in this project: tools and angular framework code.  The tools help
us manage and test the application.

* We get the tools we depend upon via `npm`, the [node package manager][npm].
* We get the angular code via `bower`, a [client-side code package manager][bower].

We have preconfigured `npm` to automatically run `bower` so we can simply do:

```
npm install
```

Behind the scenes this will also call `bower install`.  You should find that you have two new
folders in your project.

* `node_modules` - contains the npm packages for the tools we need
* `app/bower_components` - contains the angular framework files

*Note that the `bower_components` folder would normally be installed in the root folder but
angular-seed changes this location through the `.bowerrc` file.  Putting it in the app folder makes
it easier to serve the files by a webserver.* -angular-seed comment

### Run the Application

We have preconfigured the project with a simple development web server.  The simplest way to start
this server is:

```
npm start
```

Now pull up your application at `http://localhost:8000/app/index.html`. You can change this in `package.json`.



## Directory Layout

    app/                --> all of the files to be used in production **alyssa here**
      css/              --> css files
        app.css         --> default stylesheet
      img/              --> image files
      index.html        --> app layout file (the main html template file of the app)
      js/               --> javascript files
        app.js          --> application
        controllers.js  --> application controllers
        directives.js   --> application directives
        filters.js      --> custom angular filters
        services.js     --> custom angular services
      partials/             --> angular view partials (partial html templates)
        partial1.html
        partial2.html




## Testing

There are two kinds of tests in the angular-seed application: Unit tests and End to End tests.

### Running Unit Tests

The angular-seed app comes preconfigured with unit tests. These are written in
[Jasmine][jasmine], which we run with the [Karma Test Runner][karma]. We provide a Karma
configuration file to run them.

* the configuration is found at `test/karma.conf.js`
* the unit tests are found in `test/unit/`.

The easiest way to run the unit tests is to use the supplied npm script:

```
npm test
```

This script will start the Karma test runner to execute the unit tests. Moreover, Karma will sit and
watch the source and test files for changes and then re-run the tests whenever any of them change.
This is the recommended strategy; if your unit tests are being run every time you save a file then
you receive instant feedback on any changes that break the expected code functionality.

You can also ask Karma to do a single run of the tests and then exit.  This is useful if you want to
check that a particular version of the code is operating as expected.  The project contains a
predefined script to do this:

```
npm run test-single-run
```


### End to end testing

The angular-seed app comes with end-to-end tests, again written in [Jasmine][jasmine]. These tests
are run with the [Protractor][protractor] End-to-End test runner.  It uses native events and has
special features for Angular applications.

* the configuration is found at `test/protractor-conf.js`
* the end-to-end tests are found in `test/e2e/`

Protractor simulates interaction with our web app and verifies that the application responds
correctly. Therefore, our web server needs to be serving up the application, so that Protractor
can interact with it.

```
npm start
```


## Updating Angular

Previously the Angular team recommended that you merge in changes to angular-seed into your own fork of the project.
Now that the angular framework library code and tools are acquired through package managers (npm and
bower) you can use these tools instead to update the dependencies.

You can update the tool dependencies by running:

```
npm update
```

This will find the latest versions that match the version ranges specified in the `package.json` file.

You can update the Angular dependencies by running:

```
bower update
```

This will find the latest versions that match the version ranges specified in the `bower.json` file.


## Loading Angular Asynchronously

The angular-seed project supports loading the framework and application scripts asynchronously.  The
special `index-async.html` is designed to support this style of loading.  For it to work you must
inject a piece of Angular JavaScript into the HTML page.  The project has a predefined script to help
do this.

```
npm run update-index-async
```

This will copy the contents of the `angular-loader.js` library file into the `index-async.html` page.
You can run this every time you update the version of Angular that you are using.


## Serving the Application Files

While angular is client-side-only technology and it's possible to create angular webapps that
don't require a backend server at all, we recommend serving the project files using a local
webserver during development to avoid issues with security restrictions (sandbox) in browsers. The
sandbox implementation varies between browsers, but quite often prevents things like cookies, xhr,
etc to function properly when an html page is opened via `file://` scheme instead of `http://`.


### Running the App during Development

The angular-seed project comes preconfigured with a local development webserver.  It is a node.js
tool called [http-server][http-server].  You can start this webserver with `npm start` but you may choose to
install the tool globally:

```
sudo npm install -g http-server
```

Then you can start your own development web server to serve static files from a folder by
running:

```
http-server
```

Alternatively, you can choose to configure your own webserver, such as apache or nginx. Just
configure your server to serve the files under the `app/` directory.


### Running the App in Production

This really depends on how complex is your app and the overall infrastructure of your system, but
the general rule is that all you need in production are all the files under the `app/` directory.
Everything else should be omitted.

Angular apps are really just a bunch of static html, css and js files that just need to be hosted
somewhere they can be accessed by browsers.

If your Angular app is talking to the backend server via xhr or other means, you need to figure
out what is the best way to host the static files to comply with the same origin policy if
applicable. Usually this is done by hosting the files by the backend server or through
reverse-proxying the backend server(s) and webserver(s).


## Contact

For more information on AngularJS and other kick-butt languages check out [Code School](https://www.codeschool.com/)!

[angular]: http://angularjs.org/
[git]: http://git-scm.com/
[bower]: http://bower.io
[npm]: https://www.npmjs.org/
[node]: http://nodejs.org
[http-server]: https://github.com/nodeapps/http-server


================================================
FILE: README.md
================================================
## Getting Started

To get you started you can simply clone the note-wrangler repo and install the dependencies:

### Install Dependencies

You will need node.js **version 5.5** (version 6 is **not** supported) installed to run this sample app, I recommend [Node Version Manager][nvm]. 
Check out the repo for installation directions: [nvm github][nvm]

* Install the server side node libraries we depend upon via `npm`, the [node package manager][npm].

We have preconfigured the app using `npm` to automatically run `bower` so we can simply do:

```
npm install
```
This creates a `node_modules` folder which contains the npm packages installed in the previous step

### Run the Application

We have preconfigured the project with a simple development web server.  The simplest way to start
this server is:

```
npm start
```

Now pull up your application at `http://localhost:8000/`. The default user is `demo` with a password of `secret`

```
npm run debug
```
This starts the app in debug mode which allows you you to use [node-inspector](https://github.com/node-inspector/node-inspector)
You can open another browser tab at: `http://127.0.0.1:8080/debug?port=5858` to get to the web console.

## Additional Resources

For more information on AngularJS and other kick-butt languages check out [Code School](https://www.codeschool.com/)!

[angular]: http://angularjs.org/
[git]: http://git-scm.com/
[npm]: https://www.npmjs.org/
[node]: http://nodejs.org
[http-server]: https://github.com/nodeapps/http-server
[nvm]: https://github.com/creationix/nvm


================================================
FILE: app/css/application.css
================================================
@charset "UTF-8";
/*! normalize.css v3.0.0 | MIT License | git.io/normalize */
/**
 * 1. Set default font family to sans-serif.
 * 2. Prevent iOS text size adjust after orientation change, without disabling
 *    user zoom.
 */
html {
  font-family: sans-serif;
  /* 1 */
  -ms-text-size-adjust: 100%;
  /* 2 */
  -webkit-text-size-adjust: 100%;
  /* 2 */ }

/**
 * Remove default margin.
 */
body {
  margin: 0; }

/* HTML5 display definitions
   ========================================================================== */
/**
 * Correct `block` display not defined in IE 8/9.
 */
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
nav,
section,
summary {
  display: block; }

/**
 * 1. Correct `inline-block` display not defined in IE 8/9.
 * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
 */
audio,
canvas,
progress,
video {
  display: inline-block;
  /* 1 */
  vertical-align: baseline;
  /* 2 */ }

/**
 * Prevent modern browsers from displaying `audio` without controls.
 * Remove excess height in iOS 5 devices.
 */
audio:not([controls]) {
  display: none;
  height: 0; }

/**
 * Address `[hidden]` styling not present in IE 8/9.
 * Hide the `template` element in IE, Safari, and Firefox < 22.
 */
[hidden],
template {
  display: none; }

/* Links
   ========================================================================== */
/**
 * Remove the gray background color from active links in IE 10.
 */
a {
  background: transparent; }

/**
 * Improve readability when focused and also mouse hovered in all browsers.
 */
a:active,
a:hover {
  outline: 0; }

/* Text-level semantics
   ========================================================================== */
/**
 * Address styling not present in IE 8/9, Safari 5, and Chrome.
 */
abbr[title] {
  border-bottom: 1px dotted; }

/**
 * Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
 */
b,
strong {
  font-weight: bold; }

/**
 * Address styling not present in Safari 5 and Chrome.
 */
dfn {
  font-style: italic; }

/**
 * Address variable `h1` font-size and margin within `section` and `article`
 * contexts in Firefox 4+, Safari 5, and Chrome.
 */
h1 {
  font-size: 2em;
  margin: 0.67em 0; }

/**
 * Address styling not present in IE 8/9.
 */
mark {
  background: #ff0;
  color: #000; }

/**
 * Address inconsistent and variable font size in all browsers.
 */
small {
  font-size: 80%; }

/**
 * Prevent `sub` and `sup` affecting `line-height` in all browsers.
 */
sub,
sup {
  font-size: 75%;
  line-height: 0;
  position: relative;
  vertical-align: baseline; }

sup {
  top: -0.5em; }

sub {
  bottom: -0.25em; }

/* Embedded content
   ========================================================================== */
/**
 * Remove border when inside `a` element in IE 8/9.
 */
img {
  border: 0; }

/**
 * Correct overflow displayed oddly in IE 9.
 */
svg:not(:root) {
  overflow: hidden; }

/* Grouping content
   ========================================================================== */
/**
 * Address margin not present in IE 8/9 and Safari 5.
 */
figure {
  margin: 1em 40px; }

/**
 * Address differences between Firefox and other browsers.
 */
hr {
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  height: 0; }

/**
 * Contain overflow in all browsers.
 */
pre {
  overflow: auto; }

/**
 * Address odd `em`-unit font size rendering in all browsers.
 */
code,
kbd,
pre,
samp {
  font-family: monospace, monospace;
  font-size: 1em; }

/* Forms
   ========================================================================== */
/**
 * Known limitation: by default, Chrome and Safari on OS X allow very limited
 * styling of `select`, unless a `border` property is set.
 */
/**
 * 1. Correct color not being inherited.
 *    Known issue: affects color of disabled elements.
 * 2. Correct font properties not being inherited.
 * 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome.
 */
button,
input,
optgroup,
select,
textarea {
  color: inherit;
  /* 1 */
  font: inherit;
  /* 2 */
  margin: 0;
  /* 3 */ }

/**
 * Address `overflow` set to `hidden` in IE 8/9/10.
 */
button {
  overflow: visible; }

/**
 * Address inconsistent `text-transform` inheritance for `button` and `select`.
 * All other form control elements do not inherit `text-transform` values.
 * Correct `button` style inheritance in Firefox, IE 8+, and Opera
 * Correct `select` style inheritance in Firefox.
 */
button,
select {
  text-transform: none; }

/**
 * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
 *    and `video` controls.
 * 2. Correct inability to style clickable `input` types in iOS.
 * 3. Improve usability and consistency of cursor style between image-type
 *    `input` and others.
 */
button,
html input[type="button"],
input[type="reset"],
input[type="submit"] {
  -webkit-appearance: button;
  /* 2 */
  cursor: pointer;
  /* 3 */ }

/**
 * Re-set default cursor for disabled elements.
 */
button[disabled],
html input[disabled] {
  cursor: default; }

/**
 * Remove inner padding and border in Firefox 4+.
 */
button::-moz-focus-inner,
input::-moz-focus-inner {
  border: 0;
  padding: 0; }

/**
 * Address Firefox 4+ setting `line-height` on `input` using `!important` in
 * the UA stylesheet.
 */
input {
  line-height: normal; }

/**
 * It's recommended that you don't attempt to style these elements.
 * Firefox's implementation doesn't respect box-sizing, padding, or width.
 *
 * 1. Address box sizing set to `content-box` in IE 8/9/10.
 * 2. Remove excess padding in IE 8/9/10.
 */
input[type="checkbox"],
input[type="radio"] {
  box-sizing: border-box;
  /* 1 */
  padding: 0;
  /* 2 */ }

/**
 * Fix the cursor style for Chrome's increment/decrement buttons. For certain
 * `font-size` values of the `input`, it causes the cursor style of the
 * decrement button to change from `default` to `text`.
 */
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
  height: auto; }

/**
 * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
 * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
 *    (include `-moz` to future-proof).
 */
input[type="search"] {
  -webkit-appearance: textfield;
  /* 1 */
  -moz-box-sizing: content-box;
  -webkit-box-sizing: content-box;
  /* 2 */
  box-sizing: content-box; }

/**
 * Remove inner padding and search cancel button in Safari and Chrome on OS X.
 * Safari (but not Chrome) clips the cancel button when the search input has
 * padding (and `textfield` appearance).
 */
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
  -webkit-appearance: none; }

/**
 * Define consistent border, margin, and padding.
 */
fieldset {
  border: 1px solid #c0c0c0;
  margin: 0 2px;
  padding: 0.35em 0.625em 0.75em; }

/**
 * 1. Correct `color` not being inherited in IE 8/9.
 * 2. Remove padding so people aren't caught out if they zero out fieldsets.
 */
legend {
  border: 0;
  /* 1 */
  padding: 0;
  /* 2 */ }

/**
 * Remove default vertical scrollbar in IE 8/9.
 */
textarea {
  overflow: auto; }

/**
 * Don't inherit the `font-weight` (applied by a rule above).
 * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
 */
optgroup {
  font-weight: bold; }

/* Tables
   ========================================================================== */
/**
 * Remove most spacing between table cells.
 */
table {
  border-collapse: collapse;
  border-spacing: 0; }

td,
th {
  padding: 0; }

.bucket::after, .note-wrapper::after, .users-wrapper::after, .wrapper::after {
  clear: both;
  content: "";
  display: table; }

.card-hidden, .dropdown-menu {
  height: 0;
  opacity: 0;
  overflow: hidden;
  visibility: hidden; }

.card:hover .card-hidden, .dropdown:hover .dropdown-menu {
  height: auto;
  opacity: 1;
  overflow: visible;
  visibility: visible; }

.dropdown-menu {
  -moz-box-sizing: border-box;
  box-sizing: border-box; }

html {
  background: #171b1f;
  color: #919191;
  font-family: sans-serif;
  font-size: 16px;
  line-height: 1.5; }

body {
  font-size: 100%; }

ul, p {
  margin-bottom: 1.25em;
  margin-top: 0; }

li {
  margin-bottom: 0.625em;
  margin-top: 0; }

h1, .h1,
h2, .h2,
h3, .h3,
h4, .h4, .sort-menu h2, .notes-header h1 {
  font-family: sans-serif;
  font-weight: bold;
  line-height: 1.2;
  margin-bottom: 0.3125em;
  margin-top: 0; }

h1, .h1 {
  color: #12a9d5;
  font-size: 170%;
  text-transform: uppercase; }

h2, .h2 {
  font-size: 150%; }

h3, .h3 {
  font-size: 105%; }

h4, .h4, .sort-menu h2, .notes-header h1 {
  font-size: 110%; }

a {
  color: #0F6A85;
  text-decoration: none; }
  a:hover, a:focus {
    color: #148fb3; }

img {
  height: auto;
  max-width: 100%; }

.bucket--flag {
  display: table; }
  .bucket--flag .bucket-content {
    vertical-align: middle; }

.bucket-media--center {
  position: relative;
  transform: translate(0, 20%); }

.bucket-content {
  display: table-cell;
  width: 10000px; }

.bucket-media {
  float: left;
  margin-right: 1.25em; }
  .bucket-media > img {
    display: block;
    max-width: none; }

.card, .card-hidden, .dropdown-menu, .registration, .new-note-container {
  background: #F7F9FA;
  border-radius: 3px;
  box-shadow: 0 2px 0 rgba(0, 0, 0, 0.15);
  padding: 1.25em;
  position: relative; }

.card--f, .card-hidden, .sort-menu .card {
  padding: 0; }

.card-users,
.card-notes {
  text-align: center; }
  .card-users .card,
  .card-notes .card {
    margin-bottom: 1.25em; }

.card--a {
  min-height: 150px; }

.card--b, .sort-menu .card {
  background: #22282e; }

.card--center, .registration {
  left: 50%;
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 80%; }
  @media screen and (min-width: 43.75em) {
    .card--center, .registration {
      width: 50%; } }
  @media screen and (min-width: 64em) {
    .card--center, .registration {
      width: 30%; } }

.card-hidden {
  padding: 1.25em; }

.card-notes {
  min-height: 150px; }
  .card-notes .card {
    height: 150px; }

.card-notes:nth-of-type(2n+1) {
  clear: left; }

.card-type {
  color: #919191;
  font-size: 90%;
  margin-bottom: 0; }

.card-link {
  color: #0F6A85; }

.card:hover .card-hidden {
  overflow: hidden; }

.hero-content, .main-wrapper, .nav-content, .new-note-container {
  margin-left: auto;
  margin-right: auto;
  max-width: 64em;
  position: relative; }

.new-note-container {
  max-width: 43.75em; }

.form {
  margin-bottom: 1.25em; }

.form--condensed .form-field {
  margin-bottom: 0.625em; }

.form-input-search {
  margin-right: 1.25em;
  background: #2C3438;
  border-radius: 3px;
  border: none;
  display: inline-block;
  float: right;
  padding: 0.25em; }

.form-field {
  border: 0;
  margin-bottom: 1.25em;
  padding: 0; }

.form-field--inline .form-btn {
  display: block;
  line-height: 2.9;
  min-width: 100%; }

.form-input {
  background: #fff;
  border: 2px solid #ddd;
  box-sizing: border-box;
  font-size: 100%;
  padding: 0.625em;
  position: relative;
  transition: border-color 0.2s ease-in-out;
  width: 100%; }
  .form-input:focus {
    border-color: #4e4e5b;
    outline: none; }

.form-label {
  display: block;
  font-size: 90%;
  font-weight: bold;
  margin-bottom: 0.25em; }

.form-select {
  min-width: 12.5em; }

.note-wrapper, .users-wrapper, .wrapper {
  display: block;
  margin-left: -20px;
  margin-right: -20px; }

.card-notes, .card-users, .sort-menu, .nav-content-layout, .note-content {
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  float: left;
  margin: 0;
  padding-left: 20px;
  padding-right: 20px;
  width: 100%; }

.card-notes, .card-users {
  width: 100%; }

.nav-content-layout {
  width: 50%; }

.sort-menu {
  width: 25%; }

.note-content {
  width: 75%; }

@media screen and (min-width: 30em) {
  .card-users {
    width: 50%; } }
@media screen and (min-width: 50em) {
  .card-notes {
    width: 50%; }

  .card-users {
    width: 33.333%; } }
@media screen and (min-width: 64em) {
  .card-users {
    width: 25%; } }
.list, .sort-menu .card, .nav-list {
  list-style-type: none;
  margin: 0;
  padding: 0; }

.list-item {
  border-bottom: 1px solid #171b1f;
  color: #4d5b68;
  cursor: pointer;
  display: block;
  padding: 0.75em; }
  .list-item:last-child {
    margin-bottom: 0;
    border-bottom: none; }
  .list-item:hover, .list-item:focus, .list-item:active {
    background: #2d343c;
    color: #0F6A85; }
  .list-item.active {
    background: #2d343c;
    color: #0F6A85; }

.stretch, .card-hidden, .panel {
  bottom: 0;
  left: 0;
  position: absolute;
  right: 0;
  top: 0; }

.panel {
  box-sizing: border-box;
  overflow: hidden; }

.panel-content {
  padding: 1.25em; }

.hero-wrapper, .main-wrapper, .nav-wrapper, .new-note {
  overflow: hidden;
  padding: 0 1.25em; }

.main-wrapper {
  background: #171b1f; }

.well, .main-wrapper {
  margin-bottom: 1.25em;
  margin-top: 1.25em; }

.well--l {
  margin-bottom: 2.5em;
  margin-top: 2.5em; }

.well--m, .nav-content {
  margin-bottom: 0.9375em;
  margin-top: 0.9375em; }

.well--s {
  margin-bottom: 0.625em;
  margin-top: 0.625em; }

.btn, .btn-b {
  display: inline-block;
  background: #0F6A85;
  padding: 0.3125em 0.625em;
  border: none;
  color: #F7F9FA;
  border-radius: 3px;
  font-size: 90%; }
  .btn:hover, .btn:focus, .btn-b:hover, .btn-b:focus {
    color: #F7F9FA;
    background: #127c9c; }

.btn--s {
  line-height: 2.5;
  padding-left: 1.25em;
  padding-right: 1.25em; }

.btn-b {
  float: right; }

.btn--c {
  background: none;
  color: #0F6A85; }
  .btn--c:hover, .btn--c:focus {
    background: #0F6A85;
    color: #fff; }

.dropdown {
  max-width: 150px;
  position: relative;
  width: auto;
  z-index: 30; }

.dropdown:hover .dropdown-btn {
  color: #fff; }
  .dropdown:hover .dropdown-btn::after {
    color: #fff; }
.dropdown:hover .dropdown-menu {
  -webkit-transition: opacity 0.3s ease-in-out, top 0.3s ease-in-out;
  transition: opacity 0.3s ease-in-out, top 0.3s ease-in-out;
  top: 130%; }

.has-dropdown {
  overflow: visible; }

.dropdown-btn {
  display: block; }
  .dropdown-btn:hover::after, .dropdown-btn:focus::after {
    color: #fff; }
  .dropdown-btn::after {
    color: #0F6A85;
    font-size: 7px;
    left: auto;
    line-height: 30px;
    padding-left: 1.5625em;
    padding-right: 1.5625em; }

.dropdown-item {
  border-bottom: 2px solid #22282e;
  margin: 0; }
  .dropdown-item:last-child {
    border: 0; }
  .dropdown-item:hover {
    background: #d9d9d9; }

.dropdown-item-link {
  border: 0;
  display: block;
  padding: 0.625em 1.25em; }

.dropdown-menu {
  border-radius: 0;
  font-size: 90%;
  left: 50%;
  margin-left: -75px;
  padding: 0;
  position: absolute;
  text-align: center;
  top: 4.375em;
  width: 150px;
  z-index: 10; }
  .dropdown-menu::after {
    border: 8px solid transparent;
    border-bottom: 8px solid #fff;
    border-top: 0;
    bottom: auto;
    content: "";
    display: block;
    height: 0;
    left: 50%;
    margin: -8px 0 0 -8px;
    margin-top: 0;
    position: absolute;
    right: auto;
    top: 50%;
    width: 0;
    top: -8px;
    bottom: auto; }

.hero {
  min-height: 320px;
  background-color: #000000;
  background-image: url("../images/note-wrangler-hero.jpg");
  background-position: center;
  background-repeat: no-repeat; }

.hero-wrapper {
  background-color: #000000; }

.hero-cover {
  background-image: url("../images/hero-cover.jpg");
  background-size: cover; }

@font-face {
  font-family: "Icons";
  src: url(../fonts/icons.eot);
  src: url(../fonts/icons.eot?#iefix) format("embedded-opentype"), url(../fonts/icons.svg#icons) format("svg"), url(../fonts/icons.woff) format("woff"), url(../fonts/icons.ttf) format("truetype");
  font-style: normal;
  font-weight: normal;
  font-variant: normal;
  text-decoration: inherit;
  text-transform: none; }
i.icon {
  display: inline-block;
  font-family: "Icons";
  font-style: normal;
  font-weight: normal;
  speak: none; }

i.icon.icon-card {
  color: #0F6A85;
  font-size: 360%; }

i.icon.code:before {
  content: ""; }

i.icon.edit.sign:before {
  content: ""; }

i.icon.edit:before {
  content: ""; }

i.icon.tumblr.sign:before {
  content: ""; }

i.icon.tumblr:before {
  content: ""; }

i.icon.pencil:before {
  content: ""; }

i.icon.terminal:before {
  content: ""; }

i.icon.lightbulb:before {
  content: ""; }

i.icon.warning:before {
  content: ""; }

i.icon.question:before {
  content: ""; }

i.icon.thumbs.up.outline:before {
  content: ""; }

i.icon.thumbs.up:before {
  content: ""; }

i.icon.info:before {
  content: ""; }

i.icon.user:before {
  content: ""; }

i.icon.settings:before {
  content: ""; }

/* left side icons */
i.icon.left {
  width: auto;
  margin: 0em 0.5em 0em 0em; }

/* right side icons */
i.icon.search,
i.icon.right {
  width: auto;
  margin: 0em 0em 0em 0.5em; }

i.icon.after {
  float: right; }

.registration {
  text-align: center; }
  .registration .form-input {
    margin-bottom: 0.625em; }
  .registration .btn {
    font-size: 115%;
    margin-bottom: 0.625em;
    padding: 0.625em;
    width: 100%; }
  .registration h2 {
    border-bottom: 1px solid #d3d3d3;
    margin-bottom: 0.625em;
    padding-bottom: 0.625em;
    color: #0F6A85;
    text-transform: uppercase; }

.sort-menu .card {
  text-align: left; }
.sort-menu h2 {
  color: #12a9d5;
  display: inline-block;
  margin-bottom: 0.9375em;
  text-transform: uppercase; }

.sort-menu-item {
  border-bottom: 1px solid #171b1f;
  color: #4d5b68;
  cursor: pointer;
  display: block;
  font-style: italic;
  padding: 0.75em; }
  .sort-menu-item:last-child {
    margin-bottom: 0;
    border-bottom: none; }
  .sort-menu-item:hover, .sort-menu-item:focus, .sort-menu-item:active {
    background: #2d343c;
    color: #0F6A85; }
  .sort-menu-item.active {
    background: #2d343c;
    color: #0F6A85; }

.tooltip {
  position: absolute;
  z-index: 1070;
  display: block;
  visibility: visible;
  font-size: 12px;
  line-height: 1.4;
  opacity: 0;
  filter: alpha(opacity=0); }

.tooltip.in {
  opacity: 0.9;
  filter: alpha(opacity=90); }

.tooltip.top {
  margin-top: -3px;
  padding: 5px 0; }

.tooltip.right {
  margin-left: 3px;
  padding: 0 5px; }

.tooltip.bottom {
  margin-top: 3px;
  padding: 5px 0; }

.tooltip.left {
  margin-left: -3px;
  padding: 0 5px; }

.tooltip-inner {
  max-width: 200px;
  padding: 3px 8px;
  color: #000;
  text-align: center;
  text-decoration: none;
  background-color: #fff;
  border-radius: 4px; }

.tooltip-arrow {
  position: absolute;
  width: 0;
  height: 0;
  border-color: transparent;
  border-style: solid; }

.tooltip.top .tooltip-arrow {
  bottom: 0;
  left: 50%;
  margin-left: -5px;
  border-width: 5px 5px 0;
  border-top-color: #fff; }

.tooltip.top-left .tooltip-arrow {
  bottom: 0;
  left: 5px;
  border-width: 5px 5px 0;
  border-top-color: #fff; }

.tooltip.top-right .tooltip-arrow {
  bottom: 0;
  right: 5px;
  border-width: 5px 5px 0;
  border-top-color: #fff; }

.tooltip.right .tooltip-arrow {
  top: 50%;
  left: 0;
  margin-top: -5px;
  border-width: 5px 5px 5px 0;
  border-right-color: #fff; }

.tooltip.left .tooltip-arrow {
  top: 50%;
  right: 0;
  margin-top: -5px;
  border-width: 5px 0 5px 5px;
  border-left-color: #fff; }

.tooltip.bottom .tooltip-arrow {
  top: 0;
  left: 50%;
  margin-left: -5px;
  border-width: 0 5px 5px;
  border-bottom-color: #fff; }

.tooltip.bottom-left .tooltip-arrow {
  top: 0;
  left: 5px;
  border-width: 0 5px 5px;
  border-bottom-color: #fff; }

.tooltip.bottom-right .tooltip-arrow {
  top: 0;
  right: 5px;
  border-width: 0 5px 5px;
  border-bottom-color: #fff; }

.nav-list .list-item {
  border-bottom: none;
  color: #0F6A85;
  display: inline;
  margin-right: 0.75em; }
  .nav-list .list-item:last-child {
    margin-right: 0; }
  .nav-list .list-item:hover, .nav-list .list-item:focus, .nav-list .list-item:active {
    background: none;
    border-bottom: none;
    color: #148fb3; }
  .nav-list .list-item.active {
    background: none;
    border-bottom: none;
    color: #148fb3; }

.new-note-container {
  text-align: left; }

.session {
  float: right;
  display: inline-block; }

.session-create {
  float: right; }

.notes-header {
  margin-bottom: 0.9375em; }
  .notes-header h1 {
    display: inline-block; }

.user-name {
  color: #0F6A85; }

/*# sourceMappingURL=application.css.map */


================================================
FILE: app/js/app.js
================================================
// Declare app level module which depends on ngRoute
angular.module('NoteWrangler', ['ngRoute', 'ngResource', 'Gravatar'])
.config(function($gravatarProvider){
  $gravatarProvider.setSize(100);
});


================================================
FILE: app/js/controllers/notes-create-controller.js
================================================
angular.module('NoteWrangler').controller('NotesCreateController', function($scope, Note, Category, Session) {
  
  // redirect if a user is not logged in
  Session.authenticate();

  // Create a new blank note
  $scope.note = new Note();

  // Fetch the node types to use within the sorting menu
  Category.all().then(function(categoryData) {
    $scope.categories = categoryData;
    $scope.note.CategoryId = categoryData[0].id;
  });

  $scope.updateNote = function(note) {
    $scope.errors = null;
    $scope.updating = true;
    
    // Without NgResource
    // Note.create(note).catch(function(noteData) {
    //   $scope.errors = [noteData.data.error];
    // }).finally(function() {
    //   $scope.updating = false;
    // });
    
    // With NgResource
    note.$save().catch(function(noteData) {
      $scope.errors = [noteData.data.error];
    }).finally(function() {
      $scope.updating = false;
    });
  };
});


================================================
FILE: app/js/controllers/notes-edit-controller.js
================================================
angular.module('NoteWrangler').controller('NotesEditController', function($scope, $routeParams, Note, Category, Session) {
  // Without NgResource
  // Note.find($routeParams.id).success(function(noteData) {
  //   $scope.note = noteData;
  // });
  
  Session.authenticate();
    
  // With NgResource
  $scope.note = Note.get({id: $routeParams.id})

  // Fetch the node types to use within the sorting menu
  Category.all().then(function(categoryData) {
    $scope.categories = categoryData;
  });
  
  $scope.updateNote = function(note) {
    $scope.errors = null;
    $scope.updating = true;

    // Without NgResource
    // Note.update(note).catch(function(noteData) {
    //   $scope.errors = [noteData.data.error];
    // }).finally(function() {
    //   $scope.updating = false;
    // });
    
    // With NgResource
    note.$update().catch(function(noteData) {
      $scope.errors = [noteData.data.error];
    }).finally(function() {
      $scope.updating = false;
    });
  };
});


================================================
FILE: app/js/controllers/notes-index-controller.js
================================================
angular.module('NoteWrangler').controller('NotesIndexController', function($scope, Note, Session) {
  // Without NgResource
  // Note.all().success(function(data) {
  //   $scope.notes = data;
  // });
  
  // With NgResource
  $scope.notes = Note.query();

  Session.sessionData().success(function(sessionUser) {
    // Create a new User from the session user data
    $scope.loggedIn = !!sessionUser;
  });
});


================================================
FILE: app/js/controllers/notes-show-controller.js
================================================
angular.module('NoteWrangler').controller('NotesShowController', function($scope, $routeParams, Note, Session) {
  // Without NgResource
  // Note.find($routeParams.id).success(function(data) {
  //   $scope.note = data;
  // });
  
  // With NgResource
  $scope.note = Note.get({id: $routeParams.id})

  Session.sessionData().success(function(sessionUser) {
    $scope.currentUser = sessionUser;
  });
});


================================================
FILE: app/js/controllers/profile-edit-controller.js
================================================
angular.module('NoteWrangler').controller('ProfileEditController', function($scope, $location, User, Session) {
  
  // Redirect if a user is not logged in
  Session.authenticate();
  
  // Grab the current session user for it's ID
  Session.sessionData().success(function(sessionUser) {
    // Create a new User from the session user data
    $scope.user = new User(sessionUser);
  });
  
  $scope.updateUser = function(user) {
    $scope.errors = null;
    $scope.updating = true;

    // Without NgResource
    // User.update($scope.user).catch(function(userData) {
    //   $scope.errors = [userData.data.error];
    // }).finally(function() {
    //   $scope.updating = false;
    // });
    
    // With NgResource
    user.$update().catch(function(userData) {
      $scope.errors = [userData.data.error];
    }).finally(function() {
      $scope.updating = false;
    });
  };
});


================================================
FILE: app/js/controllers/users-index-controller.js
================================================
angular.module('NoteWrangler').controller('UsersIndexController', function($scope, User, $gravatar) {
  
  // Without NgResource
  // User.all().success(function(data) {
  //   $scope.users = data;
  // });
  
  // With NgResource
  $scope.users = User.query();
  
  $scope.gravatarUrl = function(user) {
    return $gravatar.generate(user.email);
  }
});


================================================
FILE: app/js/controllers/users-show-controller.js
================================================
angular.module('NoteWrangler').controller('UsersShowController', function($scope, $routeParams, User, $gravatar) {
  
  // Without NgResource
  // User.find($routeParams.id).success(function(data) {
  //   $scope.user = data;
  // });
  
  // With NgResource
  $scope.user = User.get({id: $routeParams.id});
  
  $scope.gravatarUrl = function(user) {
    return $gravatar.generate(user.email);
  }
});


================================================
FILE: app/js/directives/nw-card.js
================================================
angular.module('NoteWrangler')
.directive('nwCard', ['$sce', function($sce) {
  return {
    replace: true,
    restrict: "E",
    scope: {
      header: "=",
      body: "=",
      image: "=",
      icon: "@",
      id: "=",
      type: "@"
    },
    templateUrl: "templates/directives/nw-card.html",
    link: function(scope, element) {
      if(scope.body){
        scope.body = $sce.trustAsHtml(markdown.toHTML(scope.body.toString()));
      }
    }
  };
}]);


/*
//  In Level 3 Challenges, after they refactored the above and created a markdownFactory Service they will need to change the nwCard Directive to actually USE the Service.

angular.module('NoteWrangler').directive('nwCard', ['markdown', '$sce', function(markdown, $sce) {
  return {
    replace: true,
    restrict: "E",
    scope: {
      title: "=",
      body: "=",
      image: "=",
      icon: "@",
      id: "=",
      type: "@"
    },
    templateUrl: "templates/directives/nw-card.html",
    link: function(scope, element) {
      scope.body = $sce.trustAsHtml(markdown.parse(scope.body));
    }
  };
}]);

*/


================================================
FILE: app/js/directives/nw-category-item.js
================================================
angular.module('NoteWrangler')
.directive('nwCategoryItem', function() {
  return {
    restrict: "E",
    require: "^nwCategorySelect",
    scope: {
      category: "="
    },
    templateUrl: '/templates/directives/nw-category-item.html',
    link: function(scope, element, attrs, nwCategorySelectCtrl) {
      scope.isActive = function() {
        return nwCategorySelectCtrl.getActiveCategory() === scope.category.name;
      }

      scope.makeActive = function(){
        nwCategorySelectCtrl.setActiveCategory(scope.category);
      }

      scope.categoryCount = function() {
        return nwCategorySelectCtrl.getNotesCountForCategory(scope.category);
      }

      scope.makeInactive = function(evt){
        // Required to stop the makeActive click handler from firing on the parent element
        evt.stopPropagation();
        nwCategorySelectCtrl.setActiveCategory(false)
      }
    }
  };
});

//simple version
// angular.module('NoteWrangler')
// .directive('nwCategoryItem', function() {
//   return {
//     restrict: "E",
//     require: "^nwCategorySelect",
//     scope: {
//       category: "="
//     },
//     templateUrl: '/templates/directives/nw-category-item.html',
//     link: function(scope, element, attrs, nwCategorySelectCtrl) {
//       scope.categoryActive = function() {
//         return nwCategorySelectCtrl.getActiveCategory() === scope.category.name;
//       }
//
//       scope.makeActive = function(){
//         nwCategorySelectCtrl.setActiveCategory(scope.category);
//       }
//     }
//   };
// });


================================================
FILE: app/js/directives/nw-category-select.js
================================================
angular.module('NoteWrangler')
.directive('nwCategorySelect', function(Category) {
  return {
    replace: true,
    restrict: "E",
    scope: {
      activeCategory: "=",
      notes: "="
    },
    controller: function($scope) {
      this.getActiveCategory = function(){
        return $scope.activeCategory
      }

      this.setActiveCategory = function(category) {
        $scope.activeCategory = category && category.name;
      }

      this.getNotesCountForCategory = function(category) {
        if(!$scope.notes) {
          return 0;
        }

        var count = 0;
        for(var i=0, l = $scope.notes.length; i < l; i++ ) {
          if($scope.notes[i].category.id === category.id) {
            count++;
          }
        }

        return count;
      }
    },
    templateUrl: '/templates/directives/nw-category-select.html',
    link: function(scope, element, attrs) {

      // Initially fetch the categories to use within the sorting menu
      Category.all().then(function(categoryData) {
        scope.categories = categoryData;
      });
    }
  };
});


//simple version

// angular.module('NoteWrangler')
// .directive('nwCategorySelect', function(Category) {
//   return {
//     replace: true,
//     restrict: "E",
//     scope:{activeCategory: '='},
//     controller: function($scope) {
//       this.getActiveCategory = function(){
//         // return $scope.activeCategory
//         return $scope.activeCategory
//
//       }
//
//       this.setActiveCategory = function(category) {
//         // $scope.activeCategory = category.name;
//         $scope.activeCategory = category && category.name;
//       }
//
//       return this;
//     },
//     templateUrl: '/templates/directives/nw-category-select.html',
//     link: function(scope, element, attrs) {
//
//       // Initially fetch the categories to use within the sorting menu
//       Category.all().then(function(categoryData) {
//         scope.categories = categoryData;
//       });
//     }
//   };
// });


================================================
FILE: app/js/directives/nw-page-nav-item.js
================================================
angular.module('NoteWrangler').directive('nwPageNavItem', function($location) {
  return {
    replace: true,
    restrict: "E",
    scope: {},
    transclude: true,
    templateUrl: '/templates/directives/nw-page-nav-item.html',
    link: function(scope, element, attrs, ctrl, transclude) {

      // Perform a manual transclude here so we can get the page name from the contents
      // of the pageNav item.
      transclude(function(clonedElement) {
        scope.pageName = clonedElement.text().toLowerCase();
        element.append(clonedElement);
      });
      
      // This regex finds the first part of a url ex:
      // /notes/2/edit returns notes
      //
      // \/([^\/]*)\/?
      //            ^ Look for 0 or 1 of an escaped `/` to ensure we don't go past the first url item
      //      ^ look for an unlimited number of all characters except for `/`, capture the result (the '^' within `[]` part excludes all following characters)
      //  ^ escaped `/`
      scope.selected = function() {
        return $location.path().match(/\/([^\/]*)\/?/)[1];
      };
    }
  };
});


================================================
FILE: app/js/directives/nw-session.js
================================================
angular.module('NoteWrangler').directive('nwSession', function(Session) {
  return {
    replace: true,
    restrict: 'E',
    scope: {},
    templateUrl: '/templates/directives/nw-session.html',
    link: function(scope, element, attrs) {
      Session.sessionData().success(function(data) {
        scope.session = data;
      });
    }
  };
});


================================================
FILE: app/js/directives/title.js
================================================
angular.module('NoteWrangler')
.directive('title', function($timeout) {
  return function(scope, element) {
    $timeout(function(){
      $(element).tooltip({ container: 'body' });
    });

    scope.$on('$destroy', function(){
      $(element).tooltip('destroy');
    });
  }
});


================================================
FILE: app/js/filters/notes-filter.js
================================================
// This is a custom filter which will filter by the filter value and search within the result
// of the category filter using the value from the search. If there is no category value, then
// the search is applied to the entire pool of notes.

// Usage:
//   ng-repeat='note in notes | notesFilter:searchTerm:categoryFilterTerm'
//
// The search term value should come first, followed by the category filter term
//
angular.module('NoteWrangler')
.filter('notesFilter', function(){
  return function(notesInput, titleSearch, category) {
    var note, categoryMatches, titleMatches;
    var result = [];

    for(var i=0, l = notesInput.length; i < l; i++) {
      note = notesInput[i];

      // If the category doesn't exist we'll assume there is no category selected, and not filter by a category
      // if the category does exist, then check to see if the note has a category that matches the category given
      categoryMatches = !category || note.category.name === category;

      // If the titleSearch doesn't exist, we'll assume the search box is empty and not filter by title
      // If the titleSearch does exist, then we'll use a case insensitive(i) regular expression
      // to match the search value to the title.
      titleMatches = !titleSearch || note.header.match(new RegExp(titleSearch, 'i'));

      // If the category matches and title matches then save the note as a result
      if(categoryMatches && titleMatches) {
        result.push(note);
      }
    }

    return result;
  };
});


================================================
FILE: app/js/resources/note.js
================================================
/*
This is a way of handling ajax requests using NgResource, it performs a similar function
to the Note Service.
*/

angular.module('NoteWrangler').factory('Note', function NoteFactory($resource) {  
  return $resource('/notes/:id', {}, {
    update: {
      method: "PUT"
    }
  });
});


================================================
FILE: app/js/resources/user.js
================================================
/*
This is a way of handling ajax requests using NgResource, it performs a similar function
to the UserService.
*/

angular.module('NoteWrangler').factory('User', function UserFactory($resource) {  
  return $resource('/users/:id', {}, {
    update: {
      method: "PUT"
    }
  });
});


================================================
FILE: app/js/routes.js
================================================
/*
  Configure routes used with ngRoute. We chose not to use $locationProvider.html5Mode(true);
  because using HTML5 pushstate requires that server routes are setup to mirror the routes
  in this file. Since this isn't a node course we're going to skip it. For all intensive
  purposes, html5 mode and url hash mode perform the same when within an angular app.
*/
angular.module('NoteWrangler').config(['$routeProvider', function($routeProvider) {
  $routeProvider
    .when('/', {
      // redirect to the notes index
      redirectTo: '/notes'
    })
    
    .when('/users', {
      templateUrl: 'templates/pages/users/index.html',
      controller: 'UsersIndexController'
    })
    
    .when('/users/:id', {
      templateUrl: 'templates/pages/users/show.html',
      controller: 'UsersShowController'
    })
    
    .when('/notes', {
      templateUrl: 'templates/pages/notes/index.html',
      controller: 'NotesIndexController'
    })
    
    .when('/notes/new', {
      templateUrl: 'templates/pages/notes/edit.html',
      controller: 'NotesCreateController'
    })
    
    .when('/notes/:id', {
      templateUrl: 'templates/pages/notes/show.html',
      controller: 'NotesShowController'
    })

    .when('/notes/:id/edit', {
      templateUrl: 'templates/pages/notes/edit.html',
      controller: 'NotesEditController'
    })
    
    .when('/profile/edit', {
      templateUrl: 'templates/pages/profile/edit.html',
      controller: 'ProfileEditController'
    })

    .otherwise({redirectTo: '/'});
}]);


================================================
FILE: app/js/services/category.js
================================================
angular.module('NoteWrangler').factory('Category', function CategoryFactory($http, $q) {
  var categories;
  
  return {
    all: function() {      
      var deferred = $q.defer();
      
      /*
        Since categories hardly ever change, we want to cache the value after it's been fetched
        once. We use a promise here so that we intercept the value from the $http service and
        save it. If the value has been saved we can resolve with `categories` if not we make
        the ajax call with $http and resolve the promise with the result.
      */
      if(categories) {
        deferred.resolve(categories);
      } else {
        $http({method: 'GET', url: "/categories"})
          .success(function(data) {
            categories = data;
            deferred.resolve(data);
          })
          .error(function(err) {
            deferred.reject(err)
          });
      }
      
      return deferred.promise;
    }
  };
});


================================================
FILE: app/js/services/markdown.js
================================================
// In level 3 they need to refactor the code from nw-card.js into a Service:

angular.module('NoteWrangler').factory( 'markdown',  function markdownFactory(){
  return {
    parse: function(text){
      return markdown.toHTML(text);
    }
  }
});


================================================
FILE: app/js/services/note.js
================================================
/*
This is an example of how to handle ajax data calls without using NgResource
This is for reference only, we favor using Note over this in the app.
*/

angular.module('NoteWrangler')
.factory('Note', ['$http', function NoteFactory($http) {
  return {
    all: function() {
      return $http({method: 'GET', url: "/notes"});
    },
    find: function(id){
      return $http({method:'GET', url: '/notes/' + id});
    },
    update: function(noteObj) {
      return $http({method: 'PUT', url: '/notes', data: noteObj});
    },
    create: function(noteObj) {
      return $http({method: 'POST', url: '/notes', data: noteObj});
    }
  };
}]);


================================================
FILE: app/js/services/session.js
================================================
/*
  The idea behind this service is that we start off the fetching of the session as soon
  as the service loads. Any subsequent requests for the session data are just returned
  the promise so redunant ajax calls are not made.
*/
angular.module('NoteWrangler').factory('Session', function SessionFactory($http, $location) {
  var sessionPromise = $http({method: 'GET', url: "/session"});

  return {
    sessionData: function() {
      return sessionPromise;
    },
    
    authenticate: function() {
      this.sessionData().then(function(sessionUser){
        if(!sessionUser || !sessionUser.data.id) {
          $location.path('/');
        }
      });
    }
  };
});


================================================
FILE: app/js/services/user.js
================================================
/*
This is an example of how to handle ajax data calls without using NgResource
This is for reference only, we favor using Note over this in the app.
*/
angular.module('NoteWrangler').factory('User', function UserFactory($http) {
  return {
    all: function() {
      return $http({method: 'GET', url: '/users'});
    },
    find: function(id){
      return $http({method:'GET', url: '/users/' + id});
    },
    update: function(userObj){
      return $http({method: 'PUT', url: '/users/' + userObj.id, data: userObj});
    }
  }
});


================================================
FILE: app/js/vendor/angular-resource.js
================================================
/**
 * @license AngularJS v1.2.21
 * (c) 2010-2014 Google, Inc. http://angularjs.org
 * License: MIT
 */
(function(window, angular, undefined) {'use strict';

var $resourceMinErr = angular.$$minErr('$resource');

// Helper functions and regex to lookup a dotted path on an object
// stopping at undefined/null.  The path must be composed of ASCII
// identifiers (just like $parse)
var MEMBER_NAME_REGEX = /^(\.[a-zA-Z_$][0-9a-zA-Z_$]*)+$/;

function isValidDottedPath(path) {
  return (path != null && path !== '' && path !== 'hasOwnProperty' &&
      MEMBER_NAME_REGEX.test('.' + path));
}

function lookupDottedPath(obj, path) {
  if (!isValidDottedPath(path)) {
    throw $resourceMinErr('badmember', 'Dotted member path "@{0}" is invalid.', path);
  }
  var keys = path.split('.');
  for (var i = 0, ii = keys.length; i < ii && obj !== undefined; i++) {
    var key = keys[i];
    obj = (obj !== null) ? obj[key] : undefined;
  }
  return obj;
}

/**
 * Create a shallow copy of an object and clear other fields from the destination
 */
function shallowClearAndCopy(src, dst) {
  dst = dst || {};

  angular.forEach(dst, function(value, key){
    delete dst[key];
  });

  for (var key in src) {
    if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
      dst[key] = src[key];
    }
  }

  return dst;
}

/**
 * @ngdoc module
 * @name ngResource
 * @description
 *
 * # ngResource
 *
 * The `ngResource` module provides interaction support with RESTful services
 * via the $resource service.
 *
 *
 * <div doc-module-components="ngResource"></div>
 *
 * See {@link ngResource.$resource `$resource`} for usage.
 */

/**
 * @ngdoc service
 * @name $resource
 * @requires $http
 *
 * @description
 * A factory which creates a resource object that lets you interact with
 * [RESTful](http://en.wikipedia.org/wiki/Representational_State_Transfer) server-side data sources.
 *
 * The returned resource object has action methods which provide high-level behaviors without
 * the need to interact with the low level {@link ng.$http $http} service.
 *
 * Requires the {@link ngResource `ngResource`} module to be installed.
 *
 * @param {string} url A parametrized URL template with parameters prefixed by `:` as in
 *   `/user/:username`. If you are using a URL with a port number (e.g.
 *   `http://example.com:8080/api`), it will be respected.
 *
 *   If you are using a url with a suffix, just add the suffix, like this:
 *   `$resource('http://example.com/resource.json')` or `$resource('http://example.com/:id.json')`
 *   or even `$resource('http://example.com/resource/:resource_id.:format')`
 *   If the parameter before the suffix is empty, :resource_id in this case, then the `/.` will be
 *   collapsed down to a single `.`.  If you need this sequence to appear and not collapse then you
 *   can escape it with `/\.`.
 *
 * @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in
 *   `actions` methods. If any of the parameter value is a function, it will be executed every time
 *   when a param value needs to be obtained for a request (unless the param was overridden).
 *
 *   Each key value in the parameter object is first bound to url template if present and then any
 *   excess keys are appended to the url search query after the `?`.
 *
 *   Given a template `/path/:verb` and parameter `{verb:'greet', salutation:'Hello'}` results in
 *   URL `/path/greet?salutation=Hello`.
 *
 *   If the parameter value is prefixed with `@` then the value of that parameter will be taken
 *   from the corresponding key on the data object (useful for non-GET operations).
 *
 * @param {Object.<Object>=} actions Hash with declaration of custom action that should extend
 *   the default set of resource actions. The declaration should be created in the format of {@link
 *   ng.$http#usage_parameters $http.config}:
 *
 *       {action1: {method:?, params:?, isArray:?, headers:?, ...},
 *        action2: {method:?, params:?, isArray:?, headers:?, ...},
 *        ...}
 *
 *   Where:
 *
 *   - **`action`** – {string} – The name of action. This name becomes the name of the method on
 *     your resource object.
 *   - **`method`** – {string} – Case insensitive HTTP method (e.g. `GET`, `POST`, `PUT`,
 *     `DELETE`, `JSONP`, etc).
 *   - **`params`** – {Object=} – Optional set of pre-bound parameters for this action. If any of
 *     the parameter value is a function, it will be executed every time when a param value needs to
 *     be obtained for a request (unless the param was overridden).
 *   - **`url`** – {string} – action specific `url` override. The url templating is supported just
 *     like for the resource-level urls.
 *   - **`isArray`** – {boolean=} – If true then the returned object for this action is an array,
 *     see `returns` section.
 *   - **`transformRequest`** –
 *     `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
 *     transform function or an array of such functions. The transform function takes the http
 *     request body and headers and returns its transformed (typically serialized) version.
 *   - **`transformResponse`** –
 *     `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
 *     transform function or an array of such functions. The transform function takes the http
 *     response body and headers and returns its transformed (typically deserialized) version.
 *   - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
 *     GET request, otherwise if a cache instance built with
 *     {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
 *     caching.
 *   - **`timeout`** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise} that
 *     should abort the request when resolved.
 *   - **`withCredentials`** - `{boolean}` - whether to set the `withCredentials` flag on the
 *     XHR object. See
 *     [requests with credentials](https://developer.mozilla.org/en/http_access_control#section_5)
 *     for more information.
 *   - **`responseType`** - `{string}` - see
 *     [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
 *   - **`interceptor`** - `{Object=}` - The interceptor object has two optional methods -
 *     `response` and `responseError`. Both `response` and `responseError` interceptors get called
 *     with `http response` object. See {@link ng.$http $http interceptors}.
 *
 * @returns {Object} A resource "class" object with methods for the default set of resource actions
 *   optionally extended with custom `actions`. The default set contains these actions:
 *   ```js
 *   { 'get':    {method:'GET'},
 *     'save':   {method:'POST'},
 *     'query':  {method:'GET', isArray:true},
 *     'remove': {method:'DELETE'},
 *     'delete': {method:'DELETE'} };
 *   ```
 *
 *   Calling these methods invoke an {@link ng.$http} with the specified http method,
 *   destination and parameters. When the data is returned from the server then the object is an
 *   instance of the resource class. The actions `save`, `remove` and `delete` are available on it
 *   as  methods with the `$` prefix. This allows you to easily perform CRUD operations (create,
 *   read, update, delete) on server-side data like this:
 *   ```js
 *   var User = $resource('/user/:userId', {userId:'@id'});
 *   var user = User.get({userId:123}, function() {
 *     user.abc = true;
 *     user.$save();
 *   });
 *   ```
 *
 *   It is important to realize that invoking a $resource object method immediately returns an
 *   empty reference (object or array depending on `isArray`). Once the data is returned from the
 *   server the existing reference is populated with the actual data. This is a useful trick since
 *   usually the resource is assigned to a model which is then rendered by the view. Having an empty
 *   object results in no rendering, once the data arrives from the server then the object is
 *   populated with the data and the view automatically re-renders itself showing the new data. This
 *   means that in most cases one never has to write a callback function for the action methods.
 *
 *   The action methods on the class object or instance object can be invoked with the following
 *   parameters:
 *
 *   - HTTP GET "class" actions: `Resource.action([parameters], [success], [error])`
 *   - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])`
 *   - non-GET instance actions:  `instance.$action([parameters], [success], [error])`
 *
 *   Success callback is called with (value, responseHeaders) arguments. Error callback is called
 *   with (httpResponse) argument.
 *
 *   Class actions return empty instance (with additional properties below).
 *   Instance actions return promise of the action.
 *
 *   The Resource instances and collection have these additional properties:
 *
 *   - `$promise`: the {@link ng.$q promise} of the original server interaction that created this
 *     instance or collection.
 *
 *     On success, the promise is resolved with the same resource instance or collection object,
 *     updated with data from server. This makes it easy to use in
 *     {@link ngRoute.$routeProvider resolve section of $routeProvider.when()} to defer view
 *     rendering until the resource(s) are loaded.
 *
 *     On failure, the promise is resolved with the {@link ng.$http http response} object, without
 *     the `resource` property.
 *
 *     If an interceptor object was provided, the promise will instead be resolved with the value
 *     returned by the interceptor.
 *
 *   - `$resolved`: `true` after first server interaction is completed (either with success or
 *      rejection), `false` before that. Knowing if the Resource has been resolved is useful in
 *      data-binding.
 *
 * @example
 *
 * # Credit card resource
 *
 * ```js
     // Define CreditCard class
     var CreditCard = $resource('/user/:userId/card/:cardId',
      {userId:123, cardId:'@id'}, {
       charge: {method:'POST', params:{charge:true}}
      });

     // We can retrieve a collection from the server
     var cards = CreditCard.query(function() {
       // GET: /user/123/card
       // server returns: [ {id:456, number:'1234', name:'Smith'} ];

       var card = cards[0];
       // each item is an instance of CreditCard
       expect(card instanceof CreditCard).toEqual(true);
       card.name = "J. Smith";
       // non GET methods are mapped onto the instances
       card.$save();
       // POST: /user/123/card/456 {id:456, number:'1234', name:'J. Smith'}
       // server returns: {id:456, number:'1234', name: 'J. Smith'};

       // our custom method is mapped as well.
       card.$charge({amount:9.99});
       // POST: /user/123/card/456?amount=9.99&charge=true {id:456, number:'1234', name:'J. Smith'}
     });

     // we can create an instance as well
     var newCard = new CreditCard({number:'0123'});
     newCard.name = "Mike Smith";
     newCard.$save();
     // POST: /user/123/card {number:'0123', name:'Mike Smith'}
     // server returns: {id:789, number:'0123', name: 'Mike Smith'};
     expect(newCard.id).toEqual(789);
 * ```
 *
 * The object returned from this function execution is a resource "class" which has "static" method
 * for each action in the definition.
 *
 * Calling these methods invoke `$http` on the `url` template with the given `method`, `params` and
 * `headers`.
 * When the data is returned from the server then the object is an instance of the resource type and
 * all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD
 * operations (create, read, update, delete) on server-side data.

   ```js
     var User = $resource('/user/:userId', {userId:'@id'});
     User.get({userId:123}, function(user) {
       user.abc = true;
       user.$save();
     });
   ```
 *
 * It's worth noting that the success callback for `get`, `query` and other methods gets passed
 * in the response that came from the server as well as $http header getter function, so one
 * could rewrite the above example and get access to http headers as:
 *
   ```js
     var User = $resource('/user/:userId', {userId:'@id'});
     User.get({userId:123}, function(u, getResponseHeaders){
       u.abc = true;
       u.$save(function(u, putResponseHeaders) {
         //u => saved user object
         //putResponseHeaders => $http header getter
       });
     });
   ```
 *
 * You can also access the raw `$http` promise via the `$promise` property on the object returned
 *
   ```
     var User = $resource('/user/:userId', {userId:'@id'});
     User.get({userId:123})
         .$promise.then(function(user) {
           $scope.user = user;
         });
   ```

 * # Creating a custom 'PUT' request
 * In this example we create a custom method on our resource to make a PUT request
 * ```js
 *    var app = angular.module('app', ['ngResource', 'ngRoute']);
 *
 *    // Some APIs expect a PUT request in the format URL/object/ID
 *    // Here we are creating an 'update' method
 *    app.factory('Notes', ['$resource', function($resource) {
 *    return $resource('/notes/:id', null,
 *        {
 *            'update': { method:'PUT' }
 *        });
 *    }]);
 *
 *    // In our controller we get the ID from the URL using ngRoute and $routeParams
 *    // We pass in $routeParams and our Notes factory along with $scope
 *    app.controller('NotesCtrl', ['$scope', '$routeParams', 'Notes',
                                      function($scope, $routeParams, Notes) {
 *    // First get a note object from the factory
 *    var note = Notes.get({ id:$routeParams.id });
 *    $id = note.id;
 *
 *    // Now call update passing in the ID first then the object you are updating
 *    Notes.update({ id:$id }, note);
 *
 *    // This will PUT /notes/ID with the note object in the request payload
 *    }]);
 * ```
 */
angular.module('ngResource', ['ng']).
  factory('$resource', ['$http', '$q', function($http, $q) {

    var DEFAULT_ACTIONS = {
      'get':    {method:'GET'},
      'save':   {method:'POST'},
      'query':  {method:'GET', isArray:true},
      'remove': {method:'DELETE'},
      'delete': {method:'DELETE'}
    };
    var noop = angular.noop,
        forEach = angular.forEach,
        extend = angular.extend,
        copy = angular.copy,
        isFunction = angular.isFunction;

    /**
     * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
     * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
     * segments:
     *    segment       = *pchar
     *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
     *    pct-encoded   = "%" HEXDIG HEXDIG
     *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
     *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
     *                     / "*" / "+" / "," / ";" / "="
     */
    function encodeUriSegment(val) {
      return encodeUriQuery(val, true).
        replace(/%26/gi, '&').
        replace(/%3D/gi, '=').
        replace(/%2B/gi, '+');
    }


    /**
     * This method is intended for encoding *key* or *value* parts of query component. We need a
     * custom method because encodeURIComponent is too aggressive and encodes stuff that doesn't
     * have to be encoded per http://tools.ietf.org/html/rfc3986:
     *    query       = *( pchar / "/" / "?" )
     *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
     *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
     *    pct-encoded   = "%" HEXDIG HEXDIG
     *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
     *                     / "*" / "+" / "," / ";" / "="
     */
    function encodeUriQuery(val, pctEncodeSpaces) {
      return encodeURIComponent(val).
        replace(/%40/gi, '@').
        replace(/%3A/gi, ':').
        replace(/%24/g, '$').
        replace(/%2C/gi, ',').
        replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
    }

    function Route(template, defaults) {
      this.template = template;
      this.defaults = defaults || {};
      this.urlParams = {};
    }

    Route.prototype = {
      setUrlParams: function(config, params, actionUrl) {
        var self = this,
            url = actionUrl || self.template,
            val,
            encodedVal;

        var urlParams = self.urlParams = {};
        forEach(url.split(/\W/), function(param){
          if (param === 'hasOwnProperty') {
            throw $resourceMinErr('badname', "hasOwnProperty is not a valid parameter name.");
          }
          if (!(new RegExp("^\\d+$").test(param)) && param &&
               (new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) {
            urlParams[param] = true;
          }
        });
        url = url.replace(/\\:/g, ':');

        params = params || {};
        forEach(self.urlParams, function(_, urlParam){
          val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
          if (angular.isDefined(val) && val !== null) {
            encodedVal = encodeUriSegment(val);
            url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), function(match, p1) {
              return encodedVal + p1;
            });
          } else {
            url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function(match,
                leadingSlashes, tail) {
              if (tail.charAt(0) == '/') {
                return tail;
              } else {
                return leadingSlashes + tail;
              }
            });
          }
        });

        // strip trailing slashes and set the url
        url = url.replace(/\/+$/, '') || '/';
        // then replace collapse `/.` if found in the last URL path segment before the query
        // E.g. `http://url.com/id./format?q=x` becomes `http://url.com/id.format?q=x`
        url = url.replace(/\/\.(?=\w+($|\?))/, '.');
        // replace escaped `/\.` with `/.`
        config.url = url.replace(/\/\\\./, '/.');


        // set params - delegate param encoding to $http
        forEach(params, function(value, key){
          if (!self.urlParams[key]) {
            config.params = config.params || {};
            config.params[key] = value;
          }
        });
      }
    };


    function resourceFactory(url, paramDefaults, actions) {
      var route = new Route(url);

      actions = extend({}, DEFAULT_ACTIONS, actions);

      function extractParams(data, actionParams){
        var ids = {};
        actionParams = extend({}, paramDefaults, actionParams);
        forEach(actionParams, function(value, key){
          if (isFunction(value)) { value = value(); }
          ids[key] = value && value.charAt && value.charAt(0) == '@' ?
            lookupDottedPath(data, value.substr(1)) : value;
        });
        return ids;
      }

      function defaultResponseInterceptor(response) {
        return response.resource;
      }

      function Resource(value){
        shallowClearAndCopy(value || {}, this);
      }

      forEach(actions, function(action, name) {
        var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method);

        Resource[name] = function(a1, a2, a3, a4) {
          var params = {}, data, success, error;

          /* jshint -W086 */ /* (purposefully fall through case statements) */
          switch(arguments.length) {
          case 4:
            error = a4;
            success = a3;
            //fallthrough
          case 3:
          case 2:
            if (isFunction(a2)) {
              if (isFunction(a1)) {
                success = a1;
                error = a2;
                break;
              }

              success = a2;
              error = a3;
              //fallthrough
            } else {
              params = a1;
              data = a2;
              success = a3;
              break;
            }
          case 1:
            if (isFunction(a1)) success = a1;
            else if (hasBody) data = a1;
            else params = a1;
            break;
          case 0: break;
          default:
            throw $resourceMinErr('badargs',
              "Expected up to 4 arguments [params, data, success, error], got {0} arguments",
              arguments.length);
          }
          /* jshint +W086 */ /* (purposefully fall through case statements) */

          var isInstanceCall = this instanceof Resource;
          var value = isInstanceCall ? data : (action.isArray ? [] : new Resource(data));
          var httpConfig = {};
          var responseInterceptor = action.interceptor && action.interceptor.response ||
                                    defaultResponseInterceptor;
          var responseErrorInterceptor = action.interceptor && action.interceptor.responseError ||
                                    undefined;

          forEach(action, function(value, key) {
            if (key != 'params' && key != 'isArray' && key != 'interceptor') {
              httpConfig[key] = copy(value);
            }
          });

          if (hasBody) httpConfig.data = data;
          route.setUrlParams(httpConfig,
                             extend({}, extractParams(data, action.params || {}), params),
                             action.url);

          var promise = $http(httpConfig).then(function (response) {
            var data = response.data,
              promise = value.$promise;

            if (data) {
              // Need to convert action.isArray to boolean in case it is undefined
              // jshint -W018
              if (angular.isArray(data) !== (!!action.isArray)) {
                throw $resourceMinErr('badcfg',
                    'Error in resource configuration. Expected ' +
                    'response to contain an {0} but got an {1}',
                  action.isArray ? 'array' : 'object',
                  angular.isArray(data) ? 'array' : 'object');
              }
              // jshint +W018
              if (action.isArray) {
                value.length = 0;
                forEach(data, function (item) {
                  if (typeof item === "object") {
                    value.push(new Resource(item));
                  } else {
                    // Valid JSON values may be string literals, and these should not be converted
                    // into objects. These items will not have access to the Resource prototype
                    // methods, but unfortunately there
                    value.push(item);
                  }
                });
              } else {
                shallowClearAndCopy(data, value);
                value.$promise = promise;
              }
            }

            value.$resolved = true;

            response.resource = value;

            return response;
          }, function(response) {
            value.$resolved = true;

            (error||noop)(response);

            return $q.reject(response);
          });

          promise = promise.then(
              function(response) {
                var value = responseInterceptor(response);
                (success||noop)(value, response.headers);
                return value;
              },
              responseErrorInterceptor);

          if (!isInstanceCall) {
            // we are creating instance / collection
            // - set the initial promise
            // - return the instance / collection
            value.$promise = promise;
            value.$resolved = false;

            return value;
          }

          // instance call
          return promise;
        };


        Resource.prototype['$' + name] = function(params, success, error) {
          if (isFunction(params)) {
            error = success; success = params; params = {};
          }
          var result = Resource[name].call(this, params, this, success, error);
          return result.$promise || result;
        };
      });

      Resource.bind = function(additionalParamDefaults){
        return resourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions);
      };

      return Resource;
    }

    return resourceFactory;
  }]);


})(window, window.angular);


================================================
FILE: app/js/vendor/angular-route.js
================================================
/**
 * @license AngularJS v1.2.21
 * (c) 2010-2014 Google, Inc. http://angularjs.org
 * License: MIT
 */
(function(window, angular, undefined) {'use strict';

/**
 * @ngdoc module
 * @name ngRoute
 * @description
 *
 * # ngRoute
 *
 * The `ngRoute` module provides routing and deeplinking services and directives for angular apps.
 *
 * ## Example
 * See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`.
 *
 *
 * <div doc-module-components="ngRoute"></div>
 */
 /* global -ngRouteModule */
var ngRouteModule = angular.module('ngRoute', ['ng']).
                        provider('$route', $RouteProvider);

/**
 * @ngdoc provider
 * @name $routeProvider
 * @kind function
 *
 * @description
 *
 * Used for configuring routes.
 *
 * ## Example
 * See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`.
 *
 * ## Dependencies
 * Requires the {@link ngRoute `ngRoute`} module to be installed.
 */
function $RouteProvider(){
  function inherit(parent, extra) {
    return angular.extend(new (angular.extend(function() {}, {prototype:parent}))(), extra);
  }

  var routes = {};

  /**
   * @ngdoc method
   * @name $routeProvider#when
   *
   * @param {string} path Route path (matched against `$location.path`). If `$location.path`
   *    contains redundant trailing slash or is missing one, the route will still match and the
   *    `$location.path` will be updated to add or drop the trailing slash to exactly match the
   *    route definition.
   *
   *    * `path` can contain named groups starting with a colon: e.g. `:name`. All characters up
   *        to the next slash are matched and stored in `$routeParams` under the given `name`
   *        when the route matches.
   *    * `path` can contain named groups starting with a colon and ending with a star:
   *        e.g.`:name*`. All characters are eagerly stored in `$routeParams` under the given `name`
   *        when the route matches.
   *    * `path` can contain optional named groups with a question mark: e.g.`:name?`.
   *
   *    For example, routes like `/color/:color/largecode/:largecode*\/edit` will match
   *    `/color/brown/largecode/code/with/slashes/edit` and extract:
   *
   *    * `color: brown`
   *    * `largecode: code/with/slashes`.
   *
   *
   * @param {Object} route Mapping information to be assigned to `$route.current` on route
   *    match.
   *
   *    Object properties:
   *
   *    - `controller` – `{(string|function()=}` – Controller fn that should be associated with
   *      newly created scope or the name of a {@link angular.Module#controller registered
   *      controller} if passed as a string.
   *    - `controllerAs` – `{string=}` – A controller alias name. If present the controller will be
   *      published to scope under the `controllerAs` name.
   *    - `template` – `{string=|function()=}` – html template as a string or a function that
   *      returns an html template as a string which should be used by {@link
   *      ngRoute.directive:ngView ngView} or {@link ng.directive:ngInclude ngInclude} directives.
   *      This property takes precedence over `templateUrl`.
   *
   *      If `template` is a function, it will be called with the following parameters:
   *
   *      - `{Array.<Object>}` - route parameters extracted from the current
   *        `$location.path()` by applying the current route
   *
   *    - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html
   *      template that should be used by {@link ngRoute.directive:ngView ngView}.
   *
   *      If `templateUrl` is a function, it will be called with the following parameters:
   *
   *      - `{Array.<Object>}` - route parameters extracted from the current
   *        `$location.path()` by applying the current route
   *
   *    - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
   *      be injected into the controller. If any of these dependencies are promises, the router
   *      will wait for them all to be resolved or one to be rejected before the controller is
   *      instantiated.
   *      If all the promises are resolved successfully, the values of the resolved promises are
   *      injected and {@link ngRoute.$route#$routeChangeSuccess $routeChangeSuccess} event is
   *      fired. If any of the promises are rejected the
   *      {@link ngRoute.$route#$routeChangeError $routeChangeError} event is fired. The map object
   *      is:
   *
   *      - `key` – `{string}`: a name of a dependency to be injected into the controller.
   *      - `factory` - `{string|function}`: If `string` then it is an alias for a service.
   *        Otherwise if function, then it is {@link auto.$injector#invoke injected}
   *        and the return value is treated as the dependency. If the result is a promise, it is
   *        resolved before its value is injected into the controller. Be aware that
   *        `ngRoute.$routeParams` will still refer to the previous route within these resolve
   *        functions.  Use `$route.current.params` to access the new route parameters, instead.
   *
   *    - `redirectTo` – {(string|function())=} – value to update
   *      {@link ng.$location $location} path with and trigger route redirection.
   *
   *      If `redirectTo` is a function, it will be called with the following parameters:
   *
   *      - `{Object.<string>}` - route parameters extracted from the current
   *        `$location.path()` by applying the current route templateUrl.
   *      - `{string}` - current `$location.path()`
   *      - `{Object}` - current `$location.search()`
   *
   *      The custom `redirectTo` function is expected to return a string which will be used
   *      to update `$location.path()` and `$location.search()`.
   *
   *    - `[reloadOnSearch=true]` - {boolean=} - reload route when only `$location.search()`
   *      or `$location.hash()` changes.
   *
   *      If the option is set to `false` and url in the browser changes, then
   *      `$routeUpdate` event is broadcasted on the root scope.
   *
   *    - `[caseInsensitiveMatch=false]` - {boolean=} - match routes without being case sensitive
   *
   *      If the option is set to `true`, then the particular route can be matched without being
   *      case sensitive
   *
   * @returns {Object} self
   *
   * @description
   * Adds a new route definition to the `$route` service.
   */
  this.when = function(path, route) {
    routes[path] = angular.extend(
      {reloadOnSearch: true},
      route,
      path && pathRegExp(path, route)
    );

    // create redirection for trailing slashes
    if (path) {
      var redirectPath = (path[path.length-1] == '/')
            ? path.substr(0, path.length-1)
            : path +'/';

      routes[redirectPath] = angular.extend(
        {redirectTo: path},
        pathRegExp(redirectPath, route)
      );
    }

    return this;
  };

   /**
    * @param path {string} path
    * @param opts {Object} options
    * @return {?Object}
    *
    * @description
    * Normalizes the given path, returning a regular expression
    * and the original path.
    *
    * Inspired by pathRexp in visionmedia/express/lib/utils.js.
    */
  function pathRegExp(path, opts) {
    var insensitive = opts.caseInsensitiveMatch,
        ret = {
          originalPath: path,
          regexp: path
        },
        keys = ret.keys = [];

    path = path
      .replace(/([().])/g, '\\$1')
      .replace(/(\/)?:(\w+)([\?\*])?/g, function(_, slash, key, option){
        var optional = option === '?' ? option : null;
        var star = option === '*' ? option : null;
        keys.push({ name: key, optional: !!optional });
        slash = slash || '';
        return ''
          + (optional ? '' : slash)
          + '(?:'
          + (optional ? slash : '')
          + (star && '(.+?)' || '([^/]+)')
          + (optional || '')
          + ')'
          + (optional || '');
      })
      .replace(/([\/$\*])/g, '\\$1');

    ret.regexp = new RegExp('^' + path + '$', insensitive ? 'i' : '');
    return ret;
  }

  /**
   * @ngdoc method
   * @name $routeProvider#otherwise
   *
   * @description
   * Sets route definition that will be used on route change when no other route definition
   * is matched.
   *
   * @param {Object} params Mapping information to be assigned to `$route.current`.
   * @returns {Object} self
   */
  this.otherwise = function(params) {
    this.when(null, params);
    return this;
  };


  this.$get = ['$rootScope',
               '$location',
               '$routeParams',
               '$q',
               '$injector',
               '$http',
               '$templateCache',
               '$sce',
      function($rootScope, $location, $routeParams, $q, $injector, $http, $templateCache, $sce) {

    /**
     * @ngdoc service
     * @name $route
     * @requires $location
     * @requires $routeParams
     *
     * @property {Object} current Reference to the current route definition.
     * The route definition contains:
     *
     *   - `controller`: The controller constructor as define in route definition.
     *   - `locals`: A map of locals which is used by {@link ng.$controller $controller} service for
     *     controller instantiation. The `locals` contain
     *     the resolved values of the `resolve` map. Additionally the `locals` also contain:
     *
     *     - `$scope` - The current route scope.
     *     - `$template` - The current route template HTML.
     *
     * @property {Object} routes Object with all route configuration Objects as its properties.
     *
     * @description
     * `$route` is used for deep-linking URLs to controllers and views (HTML partials).
     * It watches `$location.url()` and tries to map the path to an existing route definition.
     *
     * Requires the {@link ngRoute `ngRoute`} module to be installed.
     *
     * You can define routes through {@link ngRoute.$routeProvider $routeProvider}'s API.
     *
     * The `$route` service is typically used in conjunction with the
     * {@link ngRoute.directive:ngView `ngView`} directive and the
     * {@link ngRoute.$routeParams `$routeParams`} service.
     *
     * @example
     * This example shows how changing the URL hash causes the `$route` to match a route against the
     * URL, and the `ngView` pulls in the partial.
     *
     * Note that this example is using {@link ng.directive:script inlined templates}
     * to get it working on jsfiddle as well.
     *
     * <example name="$route-service" module="ngRouteExample"
     *          deps="angular-route.js" fixBase="true">
     *   <file name="index.html">
     *     <div ng-controller="MainController">
     *       Choose:
     *       <a href="Book/Moby">Moby</a> |
     *       <a href="Book/Moby/ch/1">Moby: Ch1</a> |
     *       <a href="Book/Gatsby">Gatsby</a> |
     *       <a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
     *       <a href="Book/Scarlet">Scarlet Letter</a><br/>
     *
     *       <div ng-view></div>
     *
     *       <hr />
     *
     *       <pre>$location.path() = {{$location.path()}}</pre>
     *       <pre>$route.current.templateUrl = {{$route.current.templateUrl}}</pre>
     *       <pre>$route.current.params = {{$route.current.params}}</pre>
     *       <pre>$route.current.scope.name = {{$route.current.scope.name}}</pre>
     *       <pre>$routeParams = {{$routeParams}}</pre>
     *     </div>
     *   </file>
     *
     *   <file name="book.html">
     *     controller: {{name}}<br />
     *     Book Id: {{params.bookId}}<br />
     *   </file>
     *
     *   <file name="chapter.html">
     *     controller: {{name}}<br />
     *     Book Id: {{params.bookId}}<br />
     *     Chapter Id: {{params.chapterId}}
     *   </file>
     *
     *   <file name="script.js">
     *     angular.module('ngRouteExample', ['ngRoute'])
     *
     *      .controller('MainController', function($scope, $route, $routeParams, $location) {
     *          $scope.$route = $route;
     *          $scope.$location = $location;
     *          $scope.$routeParams = $routeParams;
     *      })
     *
     *      .controller('BookController', function($scope, $routeParams) {
     *          $scope.name = "BookController";
     *          $scope.params = $routeParams;
     *      })
     *
     *      .controller('ChapterController', function($scope, $routeParams) {
     *          $scope.name = "ChapterController";
     *          $scope.params = $routeParams;
     *      })
     *
     *     .config(function($routeProvider, $locationProvider) {
     *       $routeProvider
     *        .when('/Book/:bookId', {
     *         templateUrl: 'book.html',
     *         controller: 'BookController',
     *         resolve: {
     *           // I will cause a 1 second delay
     *           delay: function($q, $timeout) {
     *             var delay = $q.defer();
     *             $timeout(delay.resolve, 1000);
     *             return delay.promise;
     *           }
     *         }
     *       })
     *       .when('/Book/:bookId/ch/:chapterId', {
     *         templateUrl: 'chapter.html',
     *         controller: 'ChapterController'
     *       });
     *
     *       // configure html5 to get links working on jsfiddle
     *       $locationProvider.html5Mode(true);
     *     });
     *
     *   </file>
     *
     *   <file name="protractor.js" type="protractor">
     *     it('should load and compile correct template', function() {
     *       element(by.linkText('Moby: Ch1')).click();
     *       var content = element(by.css('[ng-view]')).getText();
     *       expect(content).toMatch(/controller\: ChapterController/);
     *       expect(content).toMatch(/Book Id\: Moby/);
     *       expect(content).toMatch(/Chapter Id\: 1/);
     *
     *       element(by.partialLinkText('Scarlet')).click();
     *
     *       content = element(by.css('[ng-view]')).getText();
     *       expect(content).toMatch(/controller\: BookController/);
     *       expect(content).toMatch(/Book Id\: Scarlet/);
     *     });
     *   </file>
     * </example>
     */

    /**
     * @ngdoc event
     * @name $route#$routeChangeStart
     * @eventType broadcast on root scope
     * @description
     * Broadcasted before a route change. At this  point the route services starts
     * resolving all of the dependencies needed for the route change to occur.
     * Typically this involves fetching the view template as well as any dependencies
     * defined in `resolve` route property. Once  all of the dependencies are resolved
     * `$routeChangeSuccess` is fired.
     *
     * @param {Object} angularEvent Synthetic event object.
     * @param {Route} next Future route information.
     * @param {Route} current Current route information.
     */

    /**
     * @ngdoc event
     * @name $route#$routeChangeSuccess
     * @eventType broadcast on root scope
     * @description
     * Broadcasted after a route dependencies are resolved.
     * {@link ngRoute.directive:ngView ngView} listens for the directive
     * to instantiate the controller and render the view.
     *
     * @param {Object} angularEvent Synthetic event object.
     * @param {Route} current Current route information.
     * @param {Route|Undefined} previous Previous route information, or undefined if current is
     * first route entered.
     */

    /**
     * @ngdoc event
     * @name $route#$routeChangeError
     * @eventType broadcast on root scope
     * @description
     * Broadcasted if any of the resolve promises are rejected.
     *
     * @param {Object} angularEvent Synthetic event object
     * @param {Route} current Current route information.
     * @param {Route} previous Previous route information.
     * @param {Route} rejection Rejection of the promise. Usually the error of the failed promise.
     */

    /**
     * @ngdoc event
     * @name $route#$routeUpdate
     * @eventType broadcast on root scope
     * @description
     *
     * The `reloadOnSearch` property has been set to false, and we are reusing the same
     * instance of the Controller.
     */

    var forceReload = false,
        $route = {
          routes: routes,

          /**
           * @ngdoc method
           * @name $route#reload
           *
           * @description
           * Causes `$route` service to reload the current route even if
           * {@link ng.$location $location} hasn't changed.
           *
           * As a result of that, {@link ngRoute.directive:ngView ngView}
           * creates new scope, reinstantiates the controller.
           */
          reload: function() {
            forceReload = true;
            $rootScope.$evalAsync(updateRoute);
          }
        };

    $rootScope.$on('$locationChangeSuccess', updateRoute);

    return $route;

    /////////////////////////////////////////////////////

    /**
     * @param on {string} current url
     * @param route {Object} route regexp to match the url against
     * @return {?Object}
     *
     * @description
     * Check if the route matches the current url.
     *
     * Inspired by match in
     * visionmedia/express/lib/router/router.js.
     */
    function switchRouteMatcher(on, route) {
      var keys = route.keys,
          params = {};

      if (!route.regexp) return null;

      var m = route.regexp.exec(on);
      if (!m) return null;

      for (var i = 1, len = m.length; i < len; ++i) {
        var key = keys[i - 1];

        var val = m[i];

        if (key && val) {
          params[key.name] = val;
        }
      }
      return params;
    }

    function updateRoute() {
      var next = parseRoute(),
          last = $route.current;

      if (next && last && next.$$route === last.$$route
          && angular.equals(next.pathParams, last.pathParams)
          && !next.reloadOnSearch && !forceReload) {
        last.params = next.params;
        angular.copy(last.params, $routeParams);
        $rootScope.$broadcast('$routeUpdate', last);
      } else if (next || last) {
        forceReload = false;
        $rootScope.$broadcast('$routeChangeStart', next, last);
        $route.current = next;
        if (next) {
          if (next.redirectTo) {
            if (angular.isString(next.redirectTo)) {
              $location.path(interpolate(next.redirectTo, next.params)).search(next.params)
                       .replace();
            } else {
              $location.url(next.redirectTo(next.pathParams, $location.path(), $location.search()))
                       .replace();
            }
          }
        }

        $q.when(next).
          then(function() {
            if (next) {
              var locals = angular.extend({}, next.resolve),
                  template, templateUrl;

              angular.forEach(locals, function(value, key) {
                locals[key] = angular.isString(value) ?
                    $injector.get(value) : $injector.invoke(value);
              });

              if (angular.isDefined(template = next.template)) {
                if (angular.isFunction(template)) {
                  template = template(next.params);
                }
              } else if (angular.isDefined(templateUrl = next.templateUrl)) {
                if (angular.isFunction(templateUrl)) {
                  templateUrl = templateUrl(next.params);
                }
                templateUrl = $sce.getTrustedResourceUrl(templateUrl);
                if (angular.isDefined(templateUrl)) {
                  next.loadedTemplateUrl = templateUrl;
                  template = $http.get(templateUrl, {cache: $templateCache}).
                      then(function(response) { return response.data; });
                }
              }
              if (angular.isDefined(template)) {
                locals['$template'] = template;
              }
              return $q.all(locals);
            }
          }).
          // after route change
          then(function(locals) {
            if (next == $route.current) {
              if (next) {
                next.locals = locals;
                angular.copy(next.params, $routeParams);
              }
              $rootScope.$broadcast('$routeChangeSuccess', next, last);
            }
          }, function(error) {
            if (next == $route.current) {
              $rootScope.$broadcast('$routeChangeError', next, last, error);
            }
          });
      }
    }


    /**
     * @returns {Object} the current active route, by matching it against the URL
     */
    function parseRoute() {
      // Match a route
      var params, match;
      angular.forEach(routes, function(route, path) {
        if (!match && (params = switchRouteMatcher($location.path(), route))) {
          match = inherit(route, {
            params: angular.extend({}, $location.search(), params),
            pathParams: params});
          match.$$route = route;
        }
      });
      // No route matched; fallback to "otherwise" route
      return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}});
    }

    /**
     * @returns {string} interpolation of the redirect path with the parameters
     */
    function interpolate(string, params) {
      var result = [];
      angular.forEach((string||'').split(':'), function(segment, i) {
        if (i === 0) {
          result.push(segment);
        } else {
          var segmentMatch = segment.match(/(\w+)(.*)/);
          var key = segmentMatch[1];
          result.push(params[key]);
          result.push(segmentMatch[2] || '');
          delete params[key];
        }
      });
      return result.join('');
    }
  }];
}

ngRouteModule.provider('$routeParams', $RouteParamsProvider);


/**
 * @ngdoc service
 * @name $routeParams
 * @requires $route
 *
 * @description
 * The `$routeParams` service allows you to retrieve the current set of route parameters.
 *
 * Requires the {@link ngRoute `ngRoute`} module to be installed.
 *
 * The route parameters are a combination of {@link ng.$location `$location`}'s
 * {@link ng.$location#search `search()`} and {@link ng.$location#path `path()`}.
 * The `path` parameters are extracted when the {@link ngRoute.$route `$route`} path is matched.
 *
 * In case of parameter name collision, `path` params take precedence over `search` params.
 *
 * The service guarantees that the identity of the `$routeParams` object will remain unchanged
 * (but its properties will likely change) even when a route change occurs.
 *
 * Note that the `$routeParams` are only updated *after* a route change completes successfully.
 * This means that you cannot rely on `$routeParams` being correct in route resolve functions.
 * Instead you can use `$route.current.params` to access the new route's parameters.
 *
 * @example
 * ```js
 *  // Given:
 *  // URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
 *  // Route: /Chapter/:chapterId/Section/:sectionId
 *  //
 *  // Then
 *  $routeParams ==> {chapterId:'1', sectionId:'2', search:'moby'}
 * ```
 */
function $RouteParamsProvider() {
  this.$get = function() { return {}; };
}

ngRouteModule.directive('ngView', ngViewFactory);
ngRouteModule.directive('ngView', ngViewFillContentFactory);


/**
 * @ngdoc directive
 * @name ngView
 * @restrict ECA
 *
 * @description
 * # Overview
 * `ngView` is a directive that complements the {@link ngRoute.$route $route} service by
 * including the rendered template of the current route into the main layout (`index.html`) file.
 * Every time the current route changes, the included view changes with it according to the
 * configuration of the `$route` service.
 *
 * Requires the {@link ngRoute `ngRoute`} module to be installed.
 *
 * @animations
 * enter - animation is used to bring new content into the browser.
 * leave - animation is used to animate existing content away.
 *
 * The enter and leave animation occur concurrently.
 *
 * @scope
 * @priority 400
 * @param {string=} onload Expression to evaluate whenever the view updates.
 *
 * @param {string=} autoscroll Whether `ngView` should call {@link ng.$anchorScroll
 *                  $anchorScroll} to scroll the viewport after the view is updated.
 *
 *                  - If the attribute is not set, disable scrolling.
 *                  - If the attribute is set without value, enable scrolling.
 *                  - Otherwise enable scrolling only if the `autoscroll` attribute value evaluated
 *                    as an expression yields a truthy value.
 * @example
    <example name="ngView-directive" module="ngViewExample"
             deps="angular-route.js;angular-animate.js"
             animations="true" fixBase="true">
      <file name="index.html">
        <div ng-controller="MainCtrl as main">
          Choose:
          <a href="Book/Moby">Moby</a> |
          <a href="Book/Moby/ch/1">Moby: Ch1</a> |
          <a href="Book/Gatsby">Gatsby</a> |
          <a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
          <a href="Book/Scarlet">Scarlet Letter</a><br/>

          <div class="view-animate-container">
            <div ng-view class="view-animate"></div>
          </div>
          <hr />

          <pre>$location.path() = {{main.$location.path()}}</pre>
          <pre>$route.current.templateUrl = {{main.$route.current.templateUrl}}</pre>
          <pre>$route.current.params = {{main.$route.current.params}}</pre>
          <pre>$route.current.scope.name = {{main.$route.current.scope.name}}</pre>
          <pre>$routeParams = {{main.$routeParams}}</pre>
        </div>
      </file>

      <file name="book.html">
        <div>
          controller: {{book.name}}<br />
          Book Id: {{book.params.bookId}}<br />
        </div>
      </file>

      <file name="chapter.html">
        <div>
          controller: {{chapter.name}}<br />
          Book Id: {{chapter.params.bookId}}<br />
          Chapter Id: {{chapter.params.chapterId}}
        </div>
      </file>

      <file name="animations.css">
        .view-animate-container {
          position:relative;
          height:100px!important;
          position:relative;
          background:white;
          border:1px solid black;
          height:40px;
          overflow:hidden;
        }

        .view-animate {
          padding:10px;
        }

        .view-animate.ng-enter, .view-animate.ng-leave {
          -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
          transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;

          display:block;
          width:100%;
          border-left:1px solid black;

          position:absolute;
          top:0;
          left:0;
          right:0;
          bottom:0;
          padding:10px;
        }

        .view-animate.ng-enter {
          left:100%;
        }
        .view-animate.ng-enter.ng-enter-active {
          left:0;
        }
        .view-animate.ng-leave.ng-leave-active {
          left:-100%;
        }
      </file>

      <file name="script.js">
        angular.module('ngViewExample', ['ngRoute', 'ngAnimate'])
          .config(['$routeProvider', '$locationProvider',
            function($routeProvider, $locationProvider) {
              $routeProvider
                .when('/Book/:bookId', {
                  templateUrl: 'book.html',
                  controller: 'BookCtrl',
                  controllerAs: 'book'
                })
                .when('/Book/:bookId/ch/:chapterId', {
                  templateUrl: 'chapter.html',
                  controller: 'ChapterCtrl',
                  controllerAs: 'chapter'
                });

              // configure html5 to get links working on jsfiddle
              $locationProvider.html5Mode(true);
          }])
          .controller('MainCtrl', ['$route', '$routeParams', '$location',
            function($route, $routeParams, $location) {
              this.$route = $route;
              this.$location = $location;
              this.$routeParams = $routeParams;
          }])
          .controller('BookCtrl', ['$routeParams', function($routeParams) {
            this.name = "BookCtrl";
            this.params = $routeParams;
          }])
          .controller('ChapterCtrl', ['$routeParams', function($routeParams) {
            this.name = "ChapterCtrl";
            this.params = $routeParams;
          }]);

      </file>

      <file name="protractor.js" type="protractor">
        it('should load and compile correct template', function() {
          element(by.linkText('Moby: Ch1')).click();
          var content = element(by.css('[ng-view]')).getText();
          expect(content).toMatch(/controller\: ChapterCtrl/);
          expect(content).toMatch(/Book Id\: Moby/);
          expect(content).toMatch(/Chapter Id\: 1/);

          element(by.partialLinkText('Scarlet')).click();

          content = element(by.css('[ng-view]')).getText();
          expect(content).toMatch(/controller\: BookCtrl/);
          expect(content).toMatch(/Book Id\: Scarlet/);
        });
      </file>
    </example>
 */


/**
 * @ngdoc event
 * @name ngView#$viewContentLoaded
 * @eventType emit on the current ngView scope
 * @description
 * Emitted every time the ngView content is reloaded.
 */
ngViewFactory.$inject = ['$route', '$anchorScroll', '$animate'];
function ngViewFactory(   $route,   $anchorScroll,   $animate) {
  return {
    restrict: 'ECA',
    terminal: true,
    priority: 400,
    transclude: 'element',
    link: function(scope, $element, attr, ctrl, $transclude) {
        var currentScope,
            currentElement,
            previousElement,
            autoScrollExp = attr.autoscroll,
            onloadExp = attr.onload || '';

        scope.$on('$routeChangeSuccess', update);
        update();

        function cleanupLastView() {
          if(previousElement) {
            previousElement.remove();
            previousElement = null;
          }
          if(currentScope) {
            currentScope.$destroy();
            currentScope = null;
          }
          if(currentElement) {
            $animate.leave(currentElement, function() {
              previousElement = null;
            });
            previousElement = currentElement;
            currentElement = null;
          }
        }

        function update() {
          var locals = $route.current && $route.current.locals,
              template = locals && locals.$template;

          if (angular.isDefined(template)) {
            var newScope = scope.$new();
            var current = $route.current;

            // Note: This will also link all children of ng-view that were contained in the original
            // html. If that content contains controllers, ... they could pollute/change the scope.
            // However, using ng-view on an element with additional content does not make sense...
            // Note: We can't remove them in the cloneAttchFn of $transclude as that
            // function is called before linking the content, which would apply child
            // directives to non existing elements.
            var clone = $transclude(newScope, function(clone) {
              $animate.enter(clone, null, currentElement || $element, function onNgViewEnter () {
                if (angular.isDefined(autoScrollExp)
                  && (!autoScrollExp || scope.$eval(autoScrollExp))) {
                  $anchorScroll();
                }
              });
              cleanupLastView();
            });

            currentElement = clone;
            currentScope = current.scope = newScope;
            currentScope.$emit('$viewContentLoaded');
            currentScope.$eval(onloadExp);
          } else {
            cleanupLastView();
          }
        }
    }
  };
}

// This directive is called during the $transclude call of the first `ngView` directive.
// It will replace and compile the content of the element with the loaded template.
// We need this directive so that the element content is already filled when
// the link function of another directive on the same element as ngView
// is called.
ngViewFillContentFactory.$inject = ['$compile', '$controller', '$route'];
function ngViewFillContentFactory($compile, $controller, $route) {
  return {
    restrict: 'ECA',
    priority: -400,
    link: function(scope, $element) {
      var current = $route.current,
          locals = current.locals;

      $element.html(locals.$template);

      var link = $compile($element.contents());

      if (current.controller) {
        locals.$scope = scope;
        var controller = $controller(current.controller, locals);
        if (current.controllerAs) {
          scope[current.controllerAs] = controller;
        }
        $element.data('$ngControllerController', controller);
        $element.children().data('$ngControllerController', controller);
      }

      link(scope);
    }
  };
}


})(window, window.angular);


================================================
FILE: app/js/vendor/angular.js
================================================
/**
 * @license AngularJS v1.2.21
 * (c) 2010-2014 Google, Inc. http://angularjs.org
 * License: MIT
 */
(function(window, document, undefined) {'use strict';

/**
 * @description
 *
 * This object provides a utility for producing rich Error messages within
 * Angular. It can be called as follows:
 *
 * var exampleMinErr = minErr('example');
 * throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
 *
 * The above creates an instance of minErr in the example namespace. The
 * resulting error will have a namespaced error code of example.one.  The
 * resulting error will replace {0} with the value of foo, and {1} with the
 * value of bar. The object is not restricted in the number of arguments it can
 * take.
 *
 * If fewer arguments are specified than necessary for interpolation, the extra
 * interpolation markers will be preserved in the final string.
 *
 * Since data will be parsed statically during a build step, some restrictions
 * are applied with respect to how minErr instances are created and called.
 * Instances should have names of the form namespaceMinErr for a minErr created
 * using minErr('namespace') . Error codes, namespaces and template strings
 * should all be static strings, not variables or general expressions.
 *
 * @param {string} module The namespace to use for the new minErr instance.
 * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
 */

function minErr(module) {
  return function () {
    var code = arguments[0],
      prefix = '[' + (module ? module + ':' : '') + code + '] ',
      template = arguments[1],
      templateArgs = arguments,
      stringify = function (obj) {
        if (typeof obj === 'function') {
          return obj.toString().replace(/ \{[\s\S]*$/, '');
        } else if (typeof obj === 'undefined') {
          return 'undefined';
        } else if (typeof obj !== 'string') {
          return JSON.stringify(obj);
        }
        return obj;
      },
      message, i;

    message = prefix + template.replace(/\{\d+\}/g, function (match) {
      var index = +match.slice(1, -1), arg;

      if (index + 2 < templateArgs.length) {
        arg = templateArgs[index + 2];
        if (typeof arg === 'function') {
          return arg.toString().replace(/ ?\{[\s\S]*$/, '');
        } else if (typeof arg === 'undefined') {
          return 'undefined';
        } else if (typeof arg !== 'string') {
          return toJson(arg);
        }
        return arg;
      }
      return match;
    });

    message = message + '\nhttp://errors.angularjs.org/1.2.21/' +
      (module ? module + '/' : '') + code;
    for (i = 2; i < arguments.length; i++) {
      message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
        encodeURIComponent(stringify(arguments[i]));
    }

    return new Error(message);
  };
}

/* We need to tell jshint what variables are being exported */
/* global angular: true,
    msie: true,
    jqLite: true,
    jQuery: true,
    slice: true,
    push: true,
    toString: true,
    ngMinErr: true,
    angularModule: true,
    nodeName_: true,
    uid: true,
    VALIDITY_STATE_PROPERTY: true,

    lowercase: true,
    uppercase: true,
    manualLowercase: true,
    manualUppercase: true,
    nodeName_: true,
    isArrayLike: true,
    forEach: true,
    sortedKeys: true,
    forEachSorted: true,
    reverseParams: true,
    nextUid: true,
    setHashKey: true,
    extend: true,
    int: true,
    inherit: true,
    noop: true,
    identity: true,
    valueFn: true,
    isUndefined: true,
    isDefined: true,
    isObject: true,
    isString: true,
    isNumber: true,
    isDate: true,
    isArray: true,
    isFunction: true,
    isRegExp: true,
    isWindow: true,
    isScope: true,
    isFile: true,
    isBlob: true,
    isBoolean: true,
    isPromiseLike: true,
    trim: true,
    isElement: true,
    makeMap: true,
    map: true,
    size: true,
    includes: true,
    indexOf: true,
    arrayRemove: true,
    isLeafNode: true,
    copy: true,
    shallowCopy: true,
    equals: true,
    csp: true,
    concat: true,
    sliceArgs: true,
    bind: true,
    toJsonReplacer: true,
    toJson: true,
    fromJson: true,
    toBoolean: true,
    startingTag: true,
    tryDecodeURIComponent: true,
    parseKeyValue: true,
    toKeyValue: true,
    encodeUriSegment: true,
    encodeUriQuery: true,
    angularInit: true,
    bootstrap: true,
    snake_case: true,
    bindJQuery: true,
    assertArg: true,
    assertArgFn: true,
    assertNotHasOwnProperty: true,
    getter: true,
    getBlockElements: true,
    hasOwnProperty: true,
*/

////////////////////////////////////

/**
 * @ngdoc module
 * @name ng
 * @module ng
 * @description
 *
 * # ng (core module)
 * The ng module is loaded by default when an AngularJS application is started. The module itself
 * contains the essential components for an AngularJS application to function. The table below
 * lists a high level breakdown of each of the services/factories, filters, directives and testing
 * components available within this core module.
 *
 * <div doc-module-components="ng"></div>
 */

// The name of a form control's ValidityState property.
// This is used so that it's possible for internal tests to create mock ValidityStates.
var VALIDITY_STATE_PROPERTY = 'validity';

/**
 * @ngdoc function
 * @name angular.lowercase
 * @module ng
 * @kind function
 *
 * @description Converts the specified string to lowercase.
 * @param {string} string String to be converted to lowercase.
 * @returns {string} Lowercased string.
 */
var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;};
var hasOwnProperty = Object.prototype.hasOwnProperty;

/**
 * @ngdoc function
 * @name angular.uppercase
 * @module ng
 * @kind function
 *
 * @description Converts the specified string to uppercase.
 * @param {string} string String to be converted to uppercase.
 * @returns {string} Uppercased string.
 */
var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;};


var manualLowercase = function(s) {
  /* jshint bitwise: false */
  return isString(s)
      ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
      : s;
};
var manualUppercase = function(s) {
  /* jshint bitwise: false */
  return isString(s)
      ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
      : s;
};


// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
// with correct but slower alternatives.
if ('i' !== 'I'.toLowerCase()) {
  lowercase = manualLowercase;
  uppercase = manualUppercase;
}


var /** holds major version number for IE or NaN for real browsers */
    msie,
    jqLite,           // delay binding since jQuery could be loaded after us.
    jQuery,           // delay binding
    slice             = [].slice,
    push              = [].push,
    toString          = Object.prototype.toString,
    ngMinErr          = minErr('ng'),

    /** @name angular */
    angular           = window.angular || (window.angular = {}),
    angularModule,
    nodeName_,
    uid               = ['0', '0', '0'];

/**
 * IE 11 changed the format of the UserAgent string.
 * See http://msdn.microsoft.com/en-us/library/ms537503.aspx
 */
msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
if (isNaN(msie)) {
  msie = int((/trident\/.*; rv:(\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
}


/**
 * @private
 * @param {*} obj
 * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
 *                   String ...)
 */
function isArrayLike(obj) {
  if (obj == null || isWindow(obj)) {
    return false;
  }

  var length = obj.length;

  if (obj.nodeType === 1 && length) {
    return true;
  }

  return isString(obj) || isArray(obj) || length === 0 ||
         typeof length === 'number' && length > 0 && (length - 1) in obj;
}

/**
 * @ngdoc function
 * @name angular.forEach
 * @module ng
 * @kind function
 *
 * @description
 * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
 * object or an array. The `iterator` function is invoked with `iterator(value, key)`, where `value`
 * is the value of an object property or an array element and `key` is the object property key or
 * array element index. Specifying a `context` for the function is optional.
 *
 * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
 * using the `hasOwnProperty` method.
 *
   ```js
     var values = {name: 'misko', gender: 'male'};
     var log = [];
     angular.forEach(values, function(value, key) {
       this.push(key + ': ' + value);
     }, log);
     expect(log).toEqual(['name: misko', 'gender: male']);
   ```
 *
 * @param {Object|Array} obj Object to iterate over.
 * @param {Function} iterator Iterator function.
 * @param {Object=} context Object to become context (`this`) for the iterator function.
 * @returns {Object|Array} Reference to `obj`.
 */
function forEach(obj, iterator, context) {
  var key;
  if (obj) {
    if (isFunction(obj)) {
      for (key in obj) {
        // Need to check if hasOwnProperty exists,
        // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
        if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
          iterator.call(context, obj[key], key);
        }
      }
    } else if (isArray(obj) || isArrayLike(obj)) {
      for (key = 0; key < obj.length; key++) {
        iterator.call(context, obj[key], key);
      }
    } else if (obj.forEach && obj.forEach !== forEach) {
        obj.forEach(iterator, context);
    } else {
      for (key in obj) {
        if (obj.hasOwnProperty(key)) {
          iterator.call(context, obj[key], key);
        }
      }
    }
  }
  return obj;
}

function sortedKeys(obj) {
  var keys = [];
  for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
      keys.push(key);
    }
  }
  return keys.sort();
}

function forEachSorted(obj, iterator, context) {
  var keys = sortedKeys(obj);
  for ( var i = 0; i < keys.length; i++) {
    iterator.call(context, obj[keys[i]], keys[i]);
  }
  return keys;
}


/**
 * when using forEach the params are value, key, but it is often useful to have key, value.
 * @param {function(string, *)} iteratorFn
 * @returns {function(*, string)}
 */
function reverseParams(iteratorFn) {
  return function(value, key) { iteratorFn(key, value); };
}

/**
 * A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric
 * characters such as '012ABC'. The reason why we are not using simply a number counter is that
 * the number string gets longer over time, and it can also overflow, where as the nextId
 * will grow much slower, it is a string, and it will never overflow.
 *
 * @returns {string} an unique alpha-numeric string
 */
function nextUid() {
  var index = uid.length;
  var digit;

  while(index) {
    index--;
    digit = uid[index].charCodeAt(0);
    if (digit == 57 /*'9'*/) {
      uid[index] = 'A';
      return uid.join('');
    }
    if (digit == 90  /*'Z'*/) {
      uid[index] = '0';
    } else {
      uid[index] = String.fromCharCode(digit + 1);
      return uid.join('');
    }
  }
  uid.unshift('0');
  return uid.join('');
}


/**
 * Set or clear the hashkey for an object.
 * @param obj object
 * @param h the hashkey (!truthy to delete the hashkey)
 */
function setHashKey(obj, h) {
  if (h) {
    obj.$$hashKey = h;
  }
  else {
    delete obj.$$hashKey;
  }
}

/**
 * @ngdoc function
 * @name angular.extend
 * @module ng
 * @kind function
 *
 * @description
 * Extends the destination object `dst` by copying all of the properties from the `src` object(s)
 * to `dst`. You can specify multiple `src` objects.
 *
 * @param {Object} dst Destination object.
 * @param {...Object} src Source object(s).
 * @returns {Object} Reference to `dst`.
 */
function extend(dst) {
  var h = dst.$$hashKey;
  forEach(arguments, function(obj) {
    if (obj !== dst) {
      forEach(obj, function(value, key) {
        dst[key] = value;
      });
    }
  });

  setHashKey(dst,h);
  return dst;
}

function int(str) {
  return parseInt(str, 10);
}


function inherit(parent, extra) {
  return extend(new (extend(function() {}, {prototype:parent}))(), extra);
}

/**
 * @ngdoc function
 * @name angular.noop
 * @module ng
 * @kind function
 *
 * @description
 * A function that performs no operations. This function can be useful when writing code in the
 * functional style.
   ```js
     function foo(callback) {
       var result = calculateResult();
       (callback || angular.noop)(result);
     }
   ```
 */
function noop() {}
noop.$inject = [];


/**
 * @ngdoc function
 * @name angular.identity
 * @module ng
 * @kind function
 *
 * @description
 * A function that returns its first argument. This function is useful when writing code in the
 * functional style.
 *
   ```js
     function transformer(transformationFn, value) {
       return (transformationFn || angular.identity)(value);
     };
   ```
 */
function identity($) {return $;}
identity.$inject = [];


function valueFn(value) {return function() {return value;};}

/**
 * @ngdoc function
 * @name angular.isUndefined
 * @module ng
 * @kind function
 *
 * @description
 * Determines if a reference is undefined.
 *
 * @param {*} value Reference to check.
 * @returns {boolean} True if `value` is undefined.
 */
function isUndefined(value){return typeof value === 'undefined';}


/**
 * @ngdoc function
 * @name angular.isDefined
 * @module ng
 * @kind function
 *
 * @description
 * Determines if a reference is defined.
 *
 * @param {*} value Reference to check.
 * @returns {boolean} True if `value` is defined.
 */
function isDefined(value){return typeof value !== 'undefined';}


/**
 * @ngdoc function
 * @name angular.isObject
 * @module ng
 * @kind function
 *
 * @description
 * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
 * considered to be objects. Note that JavaScript arrays are objects.
 *
 * @param {*} value Reference to check.
 * @returns {boolean} True if `value` is an `Object` but not `null`.
 */
function isObject(value){return value != null && typeof value === 'object';}


/**
 * @ngdoc function
 * @name angular.isString
 * @module ng
 * @kind function
 *
 * @description
 * Determines if a reference is a `String`.
 *
 * @param {*} value Reference to check.
 * @returns {boolean} True if `value` is a `String`.
 */
function isString(value){return typeof value === 'string';}


/**
 * @ngdoc function
 * @name angular.isNumber
 * @module ng
 * @kind function
 *
 * @description
 * Determines if a reference is a `Number`.
 *
 * @param {*} value Reference to check.
 * @returns {boolean} True if `value` is a `Number`.
 */
function isNumber(value){return typeof value === 'number';}


/**
 * @ngdoc function
 * @name angular.isDate
 * @module ng
 * @kind function
 *
 * @description
 * Determines if a value is a date.
 *
 * @param {*} value Reference to check.
 * @returns {boolean} True if `value` is a `Date`.
 */
function isDate(value) {
  return toString.call(value) === '[object Date]';
}


/**
 * @ngdoc function
 * @name angular.isArray
 * @module ng
 * @kind function
 *
 * @description
 * Determines if a reference is an `Array`.
 *
 * @param {*} value Reference to check.
 * @returns {boolean} True if `value` is an `Array`.
 */
var isArray = (function() {
  if (!isFunction(Array.isArray)) {
    return function(value) {
      return toString.call(value) === '[object Array]';
    };
  }
  return Array.isArray;
})();

/**
 * @ngdoc function
 * @name angular.isFunction
 * @module ng
 * @kind function
 *
 * @description
 * Determines if a reference is a `Function`.
 *
 * @param {*} value Reference to check.
 * @returns {boolean} True if `value` is a `Function`.
 */
function isFunction(value){return typeof value === 'function';}


/**
 * Determines if a value is a regular expression object.
 *
 * @private
 * @param {*} value Reference to check.
 * @returns {boolean} True if `value` is a `RegExp`.
 */
function isRegExp(value) {
  return toString.call(value) === '[object RegExp]';
}


/**
 * Checks if `obj` is a window object.
 *
 * @private
 * @param {*} obj Object to check
 * @returns {boolean} True if `obj` is a window obj.
 */
function isWindow(obj) {
  return obj && obj.document && obj.location && obj.alert && obj.setInterval;
}


function isScope(obj) {
  return obj && obj.$evalAsync && obj.$watch;
}


function isFile(obj) {
  return toString.call(obj) === '[object File]';
}


function isBlob(obj) {
  return toString.call(obj) === '[object Blob]';
}


function isBoolean(value) {
  return typeof value === 'boolean';
}


function isPromiseLike(obj) {
  return obj && isFunction(obj.then);
}


var trim = (function() {
  // native trim is way faster: http://jsperf.com/angular-trim-test
  // but IE doesn't have it... :-(
  // TODO: we should move this into IE/ES5 polyfill
  if (!String.prototype.trim) {
    return function(value) {
      return isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value;
    };
  }
  return function(value) {
    return isString(value) ? value.trim() : value;
  };
})();


/**
 * @ngdoc function
 * @name angular.isElement
 * @module ng
 * @kind function
 *
 * @description
 * Determines if a reference is a DOM element (or wrapped jQuery element).
 *
 * @param {*} value Reference to check.
 * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
 */
function isElement(node) {
  return !!(node &&
    (node.nodeName  // we are a direct element
    || (node.prop && node.attr && node.find)));  // we have an on and find method part of jQuery API
}

/**
 * @param str 'key1,key2,...'
 * @returns {object} in the form of {key1:true, key2:true, ...}
 */
function makeMap(str) {
  var obj = {}, items = str.split(","), i;
  for ( i = 0; i < items.length; i++ )
    obj[ items[i] ] = true;
  return obj;
}


if (msie < 9) {
  nodeName_ = function(element) {
    element = element.nodeName ? element : element[0];
    return (element.scopeName && element.scopeName != 'HTML')
      ? uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName;
  };
} else {
  nodeName_ = function(element) {
    return element.nodeName ? element.nodeName : element[0].nodeName;
  };
}


function map(obj, iterator, context) {
  var results = [];
  forEach(obj, function(value, index, list) {
    results.push(iterator.call(context, value, index, list));
  });
  return results;
}


/**
 * @description
 * Determines the number of elements in an array, the number of properties an object has, or
 * the length of a string.
 *
 * Note: This function is used to augment the Object type in Angular expressions. See
 * {@link angular.Object} for more information about Angular arrays.
 *
 * @param {Object|Array|string} obj Object, array, or string to inspect.
 * @param {boolean} [ownPropsOnly=false] Count only "own" properties in an object
 * @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array.
 */
function size(obj, ownPropsOnly) {
  var count = 0, key;

  if (isArray(obj) || isString(obj)) {
    return obj.length;
  } else if (isObject(obj)) {
    for (key in obj)
      if (!ownPropsOnly || obj.hasOwnProperty(key))
        count++;
  }

  return count;
}


function includes(array, obj) {
  return indexOf(array, obj) != -1;
}

function indexOf(array, obj) {
  if (array.indexOf) return array.indexOf(obj);

  for (var i = 0; i < array.length; i++) {
    if (obj === array[i]) return i;
  }
  return -1;
}

function arrayRemove(array, value) {
  var index = indexOf(array, value);
  if (index >=0)
    array.splice(index, 1);
  return value;
}

function isLeafNode (node) {
  if (node) {
    switch (node.nodeName) {
    case "OPTION":
    case "PRE":
    case "TITLE":
      return true;
    }
  }
  return false;
}

/**
 * @ngdoc function
 * @name angular.copy
 * @module ng
 * @kind function
 *
 * @description
 * Creates a deep copy of `source`, which should be an object or an array.
 *
 * * If no destination is supplied, a copy of the object or array is created.
 * * If a destination is provided, all of its elements (for array) or properties (for objects)
 *   are deleted and then all elements/properties from the source are copied to it.
 * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
 * * If `source` is identical to 'destination' an exception will be thrown.
 *
 * @param {*} source The source that will be used to make a copy.
 *                   Can be any type, including primitives, `null`, and `undefined`.
 * @param {(Object|Array)=} destination Destination into which the source is copied. If
 *     provided, must be of the same type as `source`.
 * @returns {*} The copy or updated `destination`, if `destination` was specified.
 *
 * @example
 <example module="copyExample">
 <file name="index.html">
 <div ng-controller="ExampleController">
 <form novalidate class="simple-form">
 Name: <input type="text" ng-model="user.name" /><br />
 E-mail: <input type="email" ng-model="user.email" /><br />
 Gender: <input type="radio" ng-model="user.gender" value="male" />male
 <input type="radio" ng-model="user.gender" value="female" />female<br />
 <button ng-click="reset()">RESET</button>
 <button ng-click="update(user)">SAVE</button>
 </form>
 <pre>form = {{user | json}}</pre>
 <pre>master = {{master | json}}</pre>
 </div>

 <script>
  angular.module('copyExample', [])
    .controller('ExampleController', ['$scope', function($scope) {
      $scope.master= {};

      $scope.update = function(user) {
        // Example with 1 argument
        $scope.master= angular.copy(user);
      };

      $scope.reset = function() {
        // Example with 2 arguments
        angular.copy($scope.master, $scope.user);
      };

      $scope.reset();
    }]);
 </script>
 </file>
 </example>
 */
function copy(source, destination, stackSource, stackDest) {
  if (isWindow(source) || isScope(source)) {
    throw ngMinErr('cpws',
      "Can't copy! Making copies of Window or Scope instances is not supported.");
  }

  if (!destination) {
    destination = source;
    if (source) {
      if (isArray(source)) {
        destination = copy(source, [], stackSource, stackDest);
      } else if (isDate(source)) {
        destination = new Date(source.getTime());
      } else if (isRegExp(source)) {
        destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
        destination.lastIndex = source.lastIndex;
      } else if (isObject(source)) {
        destination = copy(source, {}, stackSource, stackDest);
      }
    }
  } else {
    if (source === destination) throw ngMinErr('cpi',
      "Can't copy! Source and destination are identical.");

    stackSource = stackSource || [];
    stackDest = stackDest || [];

    if (isObject(source)) {
      var index = indexOf(stackSource, source);
      if (index !== -1) return stackDest[index];

      stackSource.push(source);
      stackDest.push(destination);
    }

    var result;
    if (isArray(source)) {
      destination.length = 0;
      for ( var i = 0; i < source.length; i++) {
        result = copy(source[i], null, stackSource, stackDest);
        if (isObject(source[i])) {
          stackSource.push(source[i]);
          stackDest.push(result);
        }
        destination.push(result);
      }
    } else {
      var h = destination.$$hashKey;
      forEach(destination, function(value, key) {
        delete destination[key];
      });
      for ( var key in source) {
        result = copy(source[key], null, stackSource, stackDest);
        if (isObject(source[key])) {
          stackSource.push(source[key]);
          stackDest.push(result);
        }
        destination[key] = result;
      }
      setHashKey(destination,h);
    }

  }
  return destination;
}

/**
 * Creates a shallow copy of an object, an array or a primitive
 */
function shallowCopy(src, dst) {
  if (isArray(src)) {
    dst = dst || [];

    for ( var i = 0; i < src.length; i++) {
      dst[i] = src[i];
    }
  } else if (isObject(src)) {
    dst = dst || {};

    for (var key in src) {
      if (hasOwnProperty.call(src, key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
        dst[key] = src[key];
      }
    }
  }

  return dst || src;
}


/**
 * @ngdoc function
 * @name angular.equals
 * @module ng
 * @kind function
 *
 * @description
 * Determines if two objects or two values are equivalent. Supports value types, regular
 * expressions, arrays and objects.
 *
 * Two objects or values are considered equivalent if at least one of the following is true:
 *
 * * Both objects or values pass `===` comparison.
 * * Both objects or values are of the same type and all of their properties are equal by
 *   comparing them with `angular.equals`.
 * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
 * * Both values represent the same regular expression (In JavaScript,
 *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
 *   representation matches).
 *
 * During a property comparison, properties of `function` type and properties with names
 * that begin with `$` are ignored.
 *
 * Scope and DOMWindow objects are being compared only by identify (`===`).
 *
 * @param {*} o1 Object or value to compare.
 * @param {*} o2 Object or value to compare.
 * @returns {boolean} True if arguments are equal.
 */
function equals(o1, o2) {
  if (o1 === o2) return true;
  if (o1 === null || o2 === null) return false;
  if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
  var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
  if (t1 == t2) {
    if (t1 == 'object') {
      if (isArray(o1)) {
        if (!isArray(o2)) return false;
        if ((length = o1.length) == o2.length) {
          for(key=0; key<length; key++) {
            if (!equals(o1[key], o2[key])) return false;
          }
          return true;
        }
      } else if (isDate(o1)) {
        return isDate(o2) && o1.getTime() == o2.getTime();
      } else if (isRegExp(o1) && isRegExp(o2)) {
        return o1.toString() == o2.toString();
      } else {
        if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(o2)) return false;
        keySet = {};
        for(key in o1) {
          if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
          if (!equals(o1[key], o2[key])) return false;
          keySet[key] = true;
        }
        for(key in o2) {
          if (!keySet.hasOwnProperty(key) &&
              key.charAt(0) !== '$' &&
              o2[key] !== undefined &&
              !isFunction(o2[key])) return false;
        }
        return true;
      }
    }
  }
  return false;
}

var csp = function() {
  if (isDefined(csp.isActive_)) return csp.isActive_;

  var active = !!(document.querySelector('[ng-csp]') ||
                  document.querySelector('[data-ng-csp]'));

  if (!active) {
    try {
      /* jshint -W031, -W054 */
      new Function('');
      /* jshint +W031, +W054 */
    } catch (e) {
      active = true;
    }
  }

  return (csp.isActive_ = active);
};



function concat(array1, array2, index) {
  return array1.concat(slice.call(array2, index));
}

function sliceArgs(args, startIndex) {
  return slice.call(args, startIndex || 0);
}


/* jshint -W101 */
/**
 * @ngdoc function
 * @name angular.bind
 * @module ng
 * @kind function
 *
 * @description
 * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
 * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
 * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
 * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
 *
 * @param {Object} self Context which `fn` should be evaluated in.
 * @param {function()} fn Function to be bound.
 * @param {...*} args Optional arguments to be prebound to the `fn` function call.
 * @returns {function()} Function that wraps the `fn` with all the specified bindings.
 */
/* jshint +W101 */
function bind(self, fn) {
  var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
  if (isFunction(fn) && !(fn instanceof RegExp)) {
    return curryArgs.length
      ? function() {
          return arguments.length
            ? fn.apply(self, curryArgs.concat(slice.call(arguments, 0)))
            : fn.apply(self, curryArgs);
        }
      : function() {
          return arguments.length
            ? fn.apply(self, arguments)
            : fn.call(self);
        };
  } else {
    // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
    return fn;
  }
}


function toJsonReplacer(key, value) {
  var val = value;

  if (typeof key === 'string' && key.charAt(0) === '$') {
    val = undefined;
  } else if (isWindow(value)) {
    val = '$WINDOW';
  } else if (value &&  document === value) {
    val = '$DOCUMENT';
  } else if (isScope(value)) {
    val = '$SCOPE';
  }

  return val;
}


/**
 * @ngdoc function
 * @name angular.toJson
 * @module ng
 * @kind function
 *
 * @description
 * Serializes input into a JSON-formatted string. Properties with leading $ characters will be
 * stripped since angular uses this notation internally.
 *
 * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
 * @param {boolean=} pretty If set to true, the JSON output will contain newlines and whitespace.
 * @returns {string|undefined} JSON-ified string representing `obj`.
 */
function toJson(obj, pretty) {
  if (typeof obj === 'undefined') return undefined;
  return JSON.stringify(obj, toJsonReplacer, pretty ? '  ' : null);
}


/**
 * @ngdoc function
 * @name angular.fromJson
 * @module ng
 * @kind function
 *
 * @description
 * Deserializes a JSON string.
 *
 * @param {string} json JSON string to deserialize.
 * @returns {Object|Array|string|number} Deserialized thingy.
 */
function fromJson(json) {
  return isString(json)
      ? JSON.parse(json)
      : json;
}


function toBoolean(value) {
  if (typeof value === 'function') {
    value = true;
  } else if (value && value.length !== 0) {
    var v = lowercase("" + value);
    value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
  } else {
    value = false;
  }
  return value;
}

/**
 * @returns {string} Returns the string representation of the element.
 */
function startingTag(element) {
  element = jqLite(element).clone();
  try {
    // turns out IE does not let you set .html() on elements which
    // are not allowed to have children. So we just ignore it.
    element.empty();
  } catch(e) {}
  // As Per DOM Standards
  var TEXT_NODE = 3;
  var elemHtml = jqLite('<div>').append(element).html();
  try {
    return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) :
        elemHtml.
          match(/^(<[^>]+>)/)[1].
          replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
  } catch(e) {
    return lowercase(elemHtml);
  }

}


/////////////////////////////////////////////////

/**
 * Tries to decode the URI component without throwing an exception.
 *
 * @private
 * @param str value potential URI component to check.
 * @returns {boolean} True if `value` can be decoded
 * with the decodeURIComponent function.
 */
function tryDecodeURIComponent(value) {
  try {
    return decodeURIComponent(value);
  } catch(e) {
    // Ignore any invalid uri component
  }
}


/**
 * Parses an escaped url query string into key-value pairs.
 * @returns {Object.<string,boolean|Array>}
 */
function parseKeyValue(/**string*/keyValue) {
  var obj = {}, key_value, key;
  forEach((keyValue || "").split('&'), function(keyValue) {
    if ( keyValue ) {
      key_value = keyValue.replace(/\+/g,'%20').split('=');
      key = tryDecodeURIComponent(key_value[0]);
      if ( isDefined(key) ) {
        var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
        if (!hasOwnProperty.call(obj, key)) {
          obj[key] = val;
        } else if(isArray(obj[key])) {
          obj[key].push(val);
        } else {
          obj[key] = [obj[key],val];
        }
      }
    }
  });
  return obj;
}

function toKeyValue(obj) {
  var parts = [];
  forEach(obj, function(value, key) {
    if (isArray(value)) {
      forEach(value, function(arrayValue) {
        parts.push(encodeUriQuery(key, true) +
                   (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
      });
    } else {
    parts.push(encodeUriQuery(key, true) +
               (value === true ? '' : '=' + encodeUriQuery(value, true)));
    }
  });
  return parts.length ? parts.join('&') : '';
}


/**
 * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
 * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
 * segments:
 *    segment       = *pchar
 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
 *    pct-encoded   = "%" HEXDIG HEXDIG
 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
 *                     / "*" / "+" / "," / ";" / "="
 */
function encodeUriSegment(val) {
  return encodeUriQuery(val, true).
             replace(/%26/gi, '&').
             replace(/%3D/gi, '=').
             replace(/%2B/gi, '+');
}


/**
 * This method is intended for encoding *key* or *value* parts of query component. We need a custom
 * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
 * encoded per http://tools.ietf.org/html/rfc3986:
 *    query       = *( pchar / "/" / "?" )
 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
 *    pct-encoded   = "%" HEXDIG HEXDIG
 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
 *                     / "*" / "+" / "," / ";" / "="
 */
function encodeUriQuery(val, pctEncodeSpaces) {
  return encodeURIComponent(val).
             replace(/%40/gi, '@').
             replace(/%3A/gi, ':').
             replace(/%24/g, '$').
             replace(/%2C/gi, ',').
             replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
}


/**
 * @ngdoc directive
 * @name ngApp
 * @module ng
 *
 * @element ANY
 * @param {angular.Module} ngApp an optional application
 *   {@link angular.module module} name to load.
 *
 * @description
 *
 * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
 * designates the **root element** of the application and is typically placed near the root element
 * of the page - e.g. on the `<body>` or `<html>` tags.
 *
 * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
 * found in the document will be used to define the root element to auto-bootstrap as an
 * application. To run multiple applications in an HTML document you must manually bootstrap them using
 * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
 *
 * You can specify an **AngularJS module** to be used as the root module for the application.  This
 * module will be loaded into the {@link auto.$injector} when the application is bootstrapped and
 * should contain the application code needed or have dependencies on other modules that will
 * contain the code. See {@link angular.module} for more information.
 *
 * In the example below if the `ngApp` directive were not placed on the `html` element then the
 * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
 * would not be resolved to `3`.
 *
 * `ngApp` is the easiest, and most common, way to bootstrap an application.
 *
 <example module="ngAppDemo">
   <file name="index.html">
   <div ng-controller="ngAppDemoController">
     I can add: {{a}} + {{b}} =  {{ a+b }}
   </div>
   </file>
   <file name="script.js">
   angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
     $scope.a = 1;
     $scope.b = 2;
   });
   </file>
 </example>
 *
 */
function angularInit(element, bootstrap) {
  var elements = [element],
      appElement,
      module,
      names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'],
      NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;

  function append(element) {
    element && elements.push(element);
  }

  forEach(names, function(name) {
    names[name] = true;
    append(document.getElementById(name));
    name = name.replace(':', '\\:');
    if (element.querySelectorAll) {
      forEach(element.querySelectorAll('.' + name), append);
      forEach(element.querySelectorAll('.' + name + '\\:'), append);
      forEach(element.querySelectorAll('[' + name + ']'), append);
    }
  });

  forEach(elements, function(element) {
    if (!appElement) {
      var className = ' ' + element.className + ' ';
      var match = NG_APP_CLASS_REGEXP.exec(className);
      if (match) {
        appElement = element;
        module = (match[2] || '').replace(/\s+/g, ',');
      } else {
        forEach(element.attributes, function(attr) {
          if (!appElement && names[attr.name]) {
            appElement = element;
            module = attr.value;
          }
        });
      }
    }
  });
  if (appElement) {
    bootstrap(appElement, module ? [module] : []);
  }
}

/**
 * @ngdoc function
 * @name angular.bootstrap
 * @module ng
 * @description
 * Use this function to manually start up angular application.
 *
 * See: {@link guide/bootstrap Bootstrap}
 *
 * Note that ngScenario-based end-to-end tests cannot use this function to bootstrap manually.
 * They must use {@link ng.directive:ngApp ngApp}.
 *
 * Angular will detect if it has been loaded into the browser more than once and only allow the
 * first loaded script to be bootstrapped and will report a warning to the browser console for
 * each of the subsequent scripts. This prevents strange results in applications, where otherwise
 * multiple instances of Angular try to work on the DOM.
 *
 * <example name="multi-bootstrap" module="multi-bootstrap">
 * <file name="index.html">
 * <script src="../../../angular.js"></script>
 * <div ng-controller="BrokenTable">
 *   <table>
 *   <tr>
 *     <th ng-repeat="heading in headings">{{heading}}</th>
 *   </tr>
 *   <tr ng-repeat="filling in fillings">
 *     <td ng-repeat="fill in filling">{{fill}}</td>
 *   </tr>
 * </table>
 * </div>
 * </file>
 * <file name="controller.js">
 * var app = angular.module('multi-bootstrap', [])
 *
 * .controller('BrokenTable', function($scope) {
 *     $scope.headings = ['One', 'Two', 'Three'];
 *     $scope.fillings = [[1, 2, 3], ['A', 'B', 'C'], [7, 8, 9]];
 * });
 * </file>
 * <file name="protractor.js" type="protractor">
 * it('should only insert one table cell for each item in $scope.fillings', function() {
 *  expect(element.all(by.css('td')).count())
 *      .toBe(9);
 * });
 * </file>
 * </example>
 *
 * @param {DOMElement} element DOM element which is the root of angular application.
 * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
 *     Each item in the array should be the name of a predefined module or a (DI annotated)
 *     function that will be invoked by the injector as a run block.
 *     See: {@link angular.module modules}
 * @returns {auto.$injector} Returns the newly created injector for this app.
 */
function bootstrap(element, modules) {
  var doBootstrap = function() {
    element = jqLite(element);

    if (element.injector()) {
      var tag = (element[0] === document) ? 'document' : startingTag(element);
      throw ngMinErr('btstrpd', "App Already Bootstrapped with this Element '{0}'", tag);
    }

    modules = modules || [];
    modules.unshift(['$provide', function($provide) {
      $provide.value('$rootElement', element);
    }]);
    modules.unshift('ng');
    var injector = createInjector(modules);
    injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animate',
       function(scope, element, compile, injector, animate) {
        scope.$apply(function() {
          element.data('$injector', injector);
          compile(element)(scope);
        });
      }]
    );
    return injector;
  };

  var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;

  if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
    return doBootstrap();
  }

  window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
  angular.resumeBootstrap = function(extraModules) {
    forEach(extraModules, function(module) {
      modules.push(module);
    });
    doBootstrap();
  };
}

var SNAKE_CASE_REGEXP = /[A-Z]/g;
function snake_case(name, separator) {
  separator = separator || '_';
  return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
    return (pos ? separator : '') + letter.toLowerCase();
  });
}

function bindJQuery() {
  // bind to jQuery if present;
  jQuery = window.jQuery;
  // Use jQuery if it exists with proper functionality, otherwise default to us.
  // Angular 1.2+ requires jQuery 1.7.1+ for on()/off() support.
  if (jQuery && jQuery.fn.on) {
    jqLite = jQuery;
    extend(jQuery.fn, {
      scope: JQLitePrototype.scope,
      isolateScope: JQLitePrototype.isolateScope,
      controller: JQLitePrototype.controller,
      injector: JQLitePrototype.injector,
      inheritedData: JQLitePrototype.inheritedData
    });
    // Method signature:
    //     jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments)
    jqLitePatchJQueryRemove('remove', true, true, false);
    jqLitePatchJQueryRemove('empty', false, false, false);
    jqLitePatchJQueryRemove('html', false, false, true);
  } else {
    jqLite = JQLite;
  }
  angular.element = jqLite;
}

/**
 * throw error if the argument is falsy.
 */
function assertArg(arg, name, reason) {
  if (!arg) {
    throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
  }
  return arg;
}

function assertArgFn(arg, name, acceptArrayAnnotation) {
  if (acceptArrayAnnotation && isArray(arg)) {
      arg = arg[arg.length - 1];
  }

  assertArg(isFunction(arg), name, 'not a function, got ' +
      (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
  return arg;
}

/**
 * throw error if the name given is hasOwnProperty
 * @param  {String} name    the name to test
 * @param  {String} context the context in which the name is used, such as module or directive
 */
function assertNotHasOwnProperty(name, context) {
  if (name === 'hasOwnProperty') {
    throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
  }
}

/**
 * Return the value accessible from the object by path. Any undefined traversals are ignored
 * @param {Object} obj starting object
 * @param {String} path path to traverse
 * @param {boolean} [bindFnToScope=true]
 * @returns {Object} value as accessible by path
 */
//TODO(misko): this function needs to be removed
function getter(obj, path, bindFnToScope) {
  if (!path) return obj;
  var keys = path.split('.');
  var key;
  var lastInstance = obj;
  var len = keys.length;

  for (var i = 0; i < len; i++) {
    key = keys[i];
    if (obj) {
      obj = (lastInstance = obj)[key];
    }
  }
  if (!bindFnToScope && isFunction(obj)) {
    return bind(lastInstance, obj);
  }
  return obj;
}

/**
 * Return the DOM siblings between the first and last node in the given array.
 * @param {Array} array like object
 * @returns {DOMElement} object containing the elements
 */
function getBlockElements(nodes) {
  var startNode = nodes[0],
      endNode = nodes[nodes.length - 1];
  if (startNode === endNode) {
    return jqLite(startNode);
  }

  var element = startNode;
  var elements = [element];

  do {
    element = element.nextSibling;
    if (!element) break;
    elements.push(element);
  } while (element !== endNode);

  return jqLite(elements);
}

/**
 * @ngdoc type
 * @name angular.Module
 * @module ng
 * @description
 *
 * Interface for configuring angular {@link angular.module modules}.
 */

function setupModuleLoader(window) {

  var $injectorMinErr = minErr('$injector');
  var ngMinErr = minErr('ng');

  function ensure(obj, name, factory) {
    return obj[name] || (obj[name] = factory());
  }

  var angular = ensure(window, 'angular', Object);

  // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
  angular.$$minErr = angular.$$minErr || minErr;

  return ensure(angular, 'module', function() {
    /** @type {Object.<string, angular.Module>} */
    var modules = {};

    /**
     * @ngdoc function
     * @name angular.module
     * @module ng
     * @description
     *
     * The `angular.module` is a global place for creating, registering and retrieving Angular
     * modules.
     * All modules (angular core or 3rd party) that should be available to an application must be
     * registered using this mechanism.
     *
     * When passed two or more arguments, a new module is created.  If passed only one argument, an
     * existing module (the name passed as the first argument to `module`) is retrieved.
     *
     *
     * # Module
     *
     * A module is a collection of services, directives, controllers, filters, and configuration information.
     * `angular.module` is used to configure the {@link auto.$injector $injector}.
     *
     * ```js
     * // Create a new module
     * var myModule = angular.module('myModule', []);
     *
     * // register a new service
     * myModule.value('appName', 'MyCoolApp');
     *
     * // configure existing services inside initialization blocks.
     * myModule.config(['$locationProvider', function($locationProvider) {
     *   // Configure existing providers
     *   $locationProvider.hashPrefix('!');
     * }]);
     * ```
     *
     * Then you can create an injector and load your modules like this:
     *
     * ```js
     * var injector = angular.injector(['ng', 'myModule'])
     * ```
     *
     * However it's more likely that you'll just use
     * {@link ng.directive:ngApp ngApp} or
     * {@link angular.bootstrap} to simplify this process for you.
     *
     * @param {!string} name The name of the module to create or retrieve.
     * @param {!Array.<string>=} requires If specified then new module is being created. If
     *        unspecified then the module is being retrieved for further configuration.
     * @param {Function=} configFn Optional configuration function for the module. Same as
     *        {@link angular.Module#config Module#config()}.
     * @returns {module} new module with the {@link angular.Module} api.
     */
    return function module(name, requires, configFn) {
      var assertNotHasOwnProperty = function(name, context) {
        if (name === 'hasOwnProperty') {
          throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
        }
      };

      assertNotHasOwnProperty(name, 'module');
      if (requires && modules.hasOwnProperty(name)) {
        modules[name] = null;
      }
      return ensure(modules, name, function() {
        if (!requires) {
          throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
             "the module name or forgot to load it. If registering a module ensure that you " +
             "specify the dependencies as the second argument.", name);
        }

        /** @type {!Array.<Array.<*>>} */
        var invokeQueue = [];

        /** @type {!Array.<Function>} */
        var runBlocks = [];

        var config = invokeLater('$injector', 'invoke');

        /** @type {angular.Module} */
        var moduleInstance = {
          // Private state
          _invokeQueue: invokeQueue,
          _runBlocks: runBlocks,

          /**
           * @ngdoc property
           * @name angular.Module#requires
           * @module ng
           * @returns {Array.<string>} List of module names which must be loaded before this module.
           * @description
           * Holds the list of modules which the injector will load before the current module is
           * loaded.
           */
          requires: requires,

          /**
           * @ngdoc property
           * @name angular.Module#name
           * @module ng
           * @returns {string} Name of the module.
           * @description
           */
          name: name,


          /**
           * @ngdoc method
           * @name angular.Module#provider
           * @module ng
           * @param {string} name service name
           * @param {Function} providerType Construction function for creating new instance of the
           *                                service.
           * @description
           * See {@link auto.$provide#provider $provide.provider()}.
           */
          provider: invokeLater('$provide', 'provider'),

          /**
           * @ngdoc method
           * @name angular.Module#factory
           * @module ng
           * @param {string} name service name
           * @param {Function} providerFunction Function for creating new instance of the service.
           * @description
           * See {@link auto.$provide#factory $provide.factory()}.
           */
          factory: invokeLater('$provide', 'factory'),

          /**
           * @ngdoc method
           * @name angular.Module#service
           * @module ng
           * @param {string} name service name
           * @param {Function} constructor A constructor function that will be instantiated.
           * @description
           * See {@link auto.$provide#service $provide.service()}.
           */
          service: invokeLater('$provide', 'service'),

          /**
           * @ngdoc method
           * @name angular.Module#value
           * @module ng
           * @param {string} name service name
           * @param {*} object Service instance object.
           * @description
           * See {@link auto.$provide#value $provide.value()}.
           */
          value: invokeLater('$provide', 'value'),

          /**
           * @ngdoc method
           * @name angular.Module#constant
           * @module ng
           * @param {string} name constant name
           * @param {*} object Constant value.
           * @description
           * Because the constant are fixed, they get applied before other provide methods.
           * See {@link auto.$provide#constant $provide.constant()}.
           */
          constant: invokeLater('$provide', 'constant', 'unshift'),

          /**
           * @ngdoc method
           * @name angular.Module#animation
           * @module ng
           * @param {string} name animation name
           * @param {Function} animationFactory Factory function for creating new instance of an
           *                                    animation.
           * @description
           *
           * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
           *
           *
           * Defines an animation hook that can be later used with
           * {@link ngAnimate.$animate $animate} service and directives that use this service.
           *
           * ```js
           * module.animation('.animation-name', function($inject1, $inject2) {
           *   return {
           *     eventName : function(element, done) {
           *       //code to run the animation
           *       //once complete, then run done()
           *       return function cancellationFunction(element) {
           *         //code to cancel the animation
           *       }
           *     }
           *   }
           * })
           * ```
           *
           * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and
           * {@link ngAnimate ngAnimate module} for more information.
           */
          animation: invokeLater('$animateProvider', 'register'),

          /**
           * @ngdoc method
           * @name angular.Module#filter
           * @module ng
           * @param {string} name Filter name.
           * @param {Function} filterFactory Factory function for creating new instance of filter.
           * @description
           * See {@link ng.$filterProvider#register $filterProvider.register()}.
           */
          filter: invokeLater('$filterProvider', 'register'),

          /**
           * @ngdoc method
           * @name angular.Module#controller
           * @module ng
           * @param {string|Object} name Controller name, or an object map of controllers where the
           *    keys are the names and the values are the constructors.
           * @param {Function} constructor Controller constructor function.
           * @description
           * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
           */
          controller: invokeLater('$controllerProvider', 'register'),

          /**
           * @ngdoc method
           * @name angular.Module#directive
           * @module ng
           * @param {string|Object} name Directive name, or an object map of directives where the
           *    keys are the names and the values are the factories.
           * @param {Function} directiveFactory Factory function for creating new instance of
           * directives.
           * @description
           * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
           */
          directive: invokeLater('$compileProvider', 'directive'),

          /**
           * @ngdoc method
           * @name angular.Module#config
           * @module ng
           * @param {Function} configFn Execute this function on module load. Useful for service
           *    configuration.
           * @description
           * Use this method to register work which needs to be performed on module loading.
           * For more about how to configure services, see
           * {@link providers#providers_provider-recipe Provider Recipe}.
           */
          config: config,

          /**
           * @ngdoc method
           * @name angular.Module#run
           * @module ng
           * @param {Function} initializationFn Execute this function after injector creation.
           *    Useful for application initialization.
           * @description
           * Use this method to register work which should be performed when the injector is done
           * loading all modules.
           */
          run: function(block) {
            runBlocks.push(block);
            return this;
          }
        };

        if (configFn) {
          config(configFn);
        }

        return  moduleInstance;

        /**
         * @param {string} provider
         * @param {string} method
         * @param {String=} insertMethod
         * @returns {angular.Module}
         */
        function invokeLater(provider, method, insertMethod) {
          return function() {
            invokeQueue[insertMethod || 'push']([provider, method, arguments]);
            return moduleInstance;
          };
        }
      });
    };
  });

}

/* global angularModule: true,
  version: true,

  $LocaleProvider,
  $CompileProvider,

    htmlAnchorDirective,
    inputDirective,
    inputDirective,
    formDirective,
    scriptDirective,
    selectDirective,
    styleDirective,
    optionDirective,
    ngBindDirective,
    ngBindHtmlDirective,
    ngBindTemplateDirective,
    ngClassDirective,
    ngClassEvenDirective,
    ngClassOddDirective,
    ngCspDirective,
    ngCloakDirective,
    ngControllerDirective,
    ngFormDirective,
    ngHideDirective,
    ngIfDirective,
    ngIncludeDirective,
    ngIncludeFillContentDirective,
    ngInitDirective,
    ngNonBindableDirective,
    ngPluralizeDirective,
    ngRepeatDirective,
    ngShowDirective,
    ngStyleDirective,
    ngSwitchDirective,
    ngSwitchWhenDirective,
    ngSwitchDefaultDirective,
    ngOptionsDirective,
    ngTranscludeDirective,
    ngModelDirective,
    ngListDirective,
    ngChangeDirective,
    requiredDirective,
    requiredDirective,
    ngValueDirective,
    ngAttributeAliasDirectives,
    ngEventDirectives,

    $AnchorScrollProvider,
    $AnimateProvider,
    $BrowserProvider,
    $CacheFactoryProvider,
    $ControllerProvider,
    $DocumentProvider,
    $ExceptionHandlerProvider,
    $FilterProvider,
    $InterpolateProvider,
    $IntervalProvider,
    $HttpProvider,
    $HttpBackendProvider,
    $LocationProvider,
    $LogProvider,
    $ParseProvider,
    $RootScopeProvider,
    $QProvider,
    $$SanitizeUriProvider,
    $SceProvider,
    $SceDelegateProvider,
    $SnifferProvider,
    $TemplateCacheProvider,
    $TimeoutProvider,
    $$RAFProvider,
    $$AsyncCallbackProvider,
    $WindowProvider
*/


/**
 * @ngdoc object
 * @name angular.version
 * @module ng
 * @description
 * An object that contains information about the current AngularJS version. This object has the
 * following properties:
 *
 * - `full` – `{string}` – Full version string, such as "0.9.18".
 * - `major` – `{number}` – Major version number, such as "0".
 * - `minor` – `{number}` – Minor version number, such as "9".
 * - `dot` – `{number}` – Dot version number, such as "18".
 * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
 */
var version = {
  full: '1.2.21',    // all of these placeholder strings will be replaced by grunt's
  major: 1,    // package task
  minor: 2,
  dot: 21,
  codeName: 'wizard-props'
};


function publishExternalAPI(angular){
  extend(angular, {
    'bootstrap': bootstrap,
    'copy': copy,
    'extend': extend,
    'equals': equals,
    'element': jqLite,
    'forEach': forEach,
    'injector': createInjector,
    'noop':noop,
    'bind':bind,
    'toJson': toJson,
    'fromJson': fromJson,
    'identity':identity,
    'isUndefined': isUndefined,
    'isDefined': isDefined,
    'isString': isString,
    'isFunction': isFunction,
    'isObject': isObject,
    'isNumber': isNumber,
    'isElement': isElement,
    'isArray': isArray,
    'version': version,
    'isDate': isDate,
    'lowercase': lowercase,
    'uppercase': uppercase,
    'callbacks': {counter: 0},
    '$$minErr': minErr,
    '$$csp': csp
  });

  angularModule = setupModuleLoader(window);
  try {
    angularModule('ngLocale');
  } catch (e) {
    angularModule('ngLocale', []).provider('$locale', $LocaleProvider);
  }

  angularModule('ng', ['ngLocale'], ['$provide',
    function ngModule($provide) {
      // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
      $provide.provider({
        $$sanitizeUri: $$SanitizeUriProvider
      });
      $provide.provider('$compile', $CompileProvider).
        directive({
            a: htmlAnchorDirective,
            input: inputDirective,
            textarea: inputDirective,
            form: formDirective,
            script: scriptDirective,
            select: selectDirective,
            style: styleDirective,
            option: optionDirective,
            ngBind: ngBindDirective,
            ngBindHtml: ngBindHtmlDirective,
            ngBindTemplate: ngBindTemplateDirective,
            ngClass: ngClassDirective,
            ngClassEven: ngClassEvenDirective,
            ngClassOdd: ngClassOddDirective,
            ngCloak: ngCloakDirective,
            ngController: ngControllerDirective,
            ngForm: ngFormDirective,
            ngHide: ngHideDirective,
            ngIf: ngIfDirective,
            ngInclude: ngIncludeDirective,
            ngInit: ngInitDirective,
            ngNonBindable: ngNonBindableDirective,
            ngPluralize: ngPluralizeDirective,
            ngRepeat: ngRepeatDirective,
            ngShow: ngShowDirective,
            ngStyle: ngStyleDirective,
            ngSwitch: ngSwitchDirective,
            ngSwitchWhen: ngSwitchWhenDirective,
            ngSwitchDefault: ngSwitchDefaultDirective,
            ngOptions: ngOptionsDirective,
            ngTransclude: ngTranscludeDirective,
            ngModel: ngModelDirective,
            ngList: ngListDirective,
            ngChange: ngChangeDirective,
            required: requiredDirective,
            ngRequired: requiredDirective,
            ngValue: ngValueDirective
        }).
        directive({
          ngInclude: ngIncludeFillContentDirective
        }).
        directive(ngAttributeAliasDirectives).
        directive(ngEventDirectives);
      $provide.provider({
        $anchorScroll: $AnchorScrollProvider,
        $animate: $AnimateProvider,
        $browser: $BrowserProvider,
        $cacheFactory: $CacheFactoryProvider,
        $controller: $ControllerProvider,
        $document: $DocumentProvider,
        $exceptionHandler: $ExceptionHandlerProvider,
        $filter: $FilterProvider,
        $interpolate: $InterpolateProvider,
        $interval: $IntervalProvider,
        $http: $HttpProvider,
        $httpBackend: $HttpBackendProvider,
        $location: $LocationProvider,
        $log: $LogProvider,
        $parse: $ParseProvider,
        $rootScope: $RootScopeProvider,
        $q: $QProvider,
        $sce: $SceProvider,
        $sceDelegate: $SceDelegateProvider,
        $sniffer: $SnifferProvider,
        $templateCache: $TemplateCacheProvider,
        $timeout: $TimeoutProvider,
        $window: $WindowProvider,
        $$rAF: $$RAFProvider,
        $$asyncCallback : $$AsyncCallbackProvider
      });
    }
  ]);
}

/* global JQLitePrototype: true,
  addEventListenerFn: true,
  removeEventListenerFn: true,
  BOOLEAN_ATTR: true
*/

//////////////////////////////////
//JQLite
//////////////////////////////////

/**
 * @ngdoc function
 * @name angular.element
 * @module ng
 * @kind function
 *
 * @description
 * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
 *
 * If jQuery is available, `angular.element` is an alias for the
 * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
 * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."
 *
 * <div class="alert alert-success">jqLite is a tiny, API-compatible subset of jQuery that allows
 * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
 * commonly needed functionality with the goal of having a very small footprint.</div>
 *
 * To use jQuery, simply load it before `DOMContentLoaded` event fired.
 *
 * <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or
 * jqLite; they are never raw DOM references.</div>
 *
 * ## Angular's jqLite
 * jqLite provides only the following jQuery methods:
 *
 * - [`addClass()`](http://api.jquery.com/addClass/)
 * - [`after()`](http://api.jquery.com/after/)
 * - [`append()`](http://api.jquery.com/append/)
 * - [`attr()`](http://api.jquery.com/attr/)
 * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
 * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
 * - [`clone()`](http://api.jquery.com/clone/)
 * - [`contents()`](http://api.jquery.com/contents/)
 * - [`css()`](http://api.jquery.com/css/)
 * - [`data()`](http://api.jquery.com/data/)
 * - [`empty()`](http://api.jquery.com/empty/)
 * - [`eq()`](http://api.jquery.com/eq/)
 * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
 * - [`hasClass()`](http://api.jquery.com/hasClass/)
 * - [`html()`](http://api.jquery.com/html/)
 * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
 * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
 * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors
 * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
 * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
 * - [`prepend()`](http://api.jquery.com/prepend/)
 * - [`prop()`](http://api.jquery.com/prop/)
 * - [`ready()`](http://api.jquery.com/ready/)
 * - [`remove()`](http://api.jquery.com/remove/)
 * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
 * - [`removeClass()`](http://api.jquery.com/removeClass/)
 * - [`removeData()`](http://api.jquery.com/removeData/)
 * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
 * - [`text()`](http://api.jquery.com/text/)
 * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
 * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
 * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces
 * - [`val()`](http://api.jquery.com/val/)
 * - [`wrap()`](http://api.jquery.com/wrap/)
 *
 * ## jQuery/jqLite Extras
 * Angular also provides the following additional methods and events to both jQuery and jqLite:
 *
 * ### Events
 * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
 *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
 *    element before it is removed.
 *
 * ### Methods
 * - `controller(name)` - retrieves the controller of the current element or its parent. By default
 *   retrieves controller associated with the `ngController` directive. If `name` is provided as
 *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
 *   `'ngModel'`).
 * - `injector()` - retrieves the injector of the current element or its parent.
 * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
 *   element or its parent.
 * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
 *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
 *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
 * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
 *   parent element is reached.
 *
 * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
 * @returns {Object} jQuery object.
 */

JQLite.expando = 'ng339';

var jqCache = JQLite.cache = {},
    jqId = 1,
    addEventListenerFn = (window.document.addEventListener
      ? function(element, type, fn) {element.addEventListener(type, fn, false);}
      : function(element, type, fn) {element.attachEvent('on' + type, fn);}),
    removeEventListenerFn = (window.document.removeEventListener
      ? function(element, type, fn) {element.removeEventListener(type, fn, false); }
      : function(element, type, fn) {element.detachEvent('on' + type, fn); });

/*
 * !!! This is an undocumented "private" function !!!
 */
var jqData = JQLite._data = function(node) {
  //jQuery always returns an object on cache miss
  return this.cache[node[this.expando]] || {};
};

function jqNextId() { return ++jqId; }


var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
var MOZ_HACK_REGEXP = /^moz([A-Z])/;
var jqLiteMinErr = minErr('jqLite');

/**
 * Converts snake_case to camelCase.
 * Also there is special case for Moz prefix starting with upper case letter.
 * @param name Name to normalize
 */
function camelCase(name) {
  return name.
    replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
      return offset ? letter.toUpperCase() : letter;
    }).
    replace(MOZ_HACK_REGEXP, 'Moz$1');
}

/////////////////////////////////////////////
// jQuery mutation patch
//
// In conjunction with bindJQuery intercepts all jQuery's DOM destruction apis and fires a
// $destroy event on all DOM nodes being removed.
//
/////////////////////////////////////////////

function jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments) {
  var originalJqFn = jQuery.fn[name];
  originalJqFn = originalJqFn.$original || originalJqFn;
  removePatch.$original = originalJqFn;
  jQuery.fn[name] = removePatch;

  function removePatch(param) {
    // jshint -W040
    var list = filterElems && param ? [this.filter(param)] : [this],
        fireEvent = dispatchThis,
        set, setIndex, setLength,
        element, childIndex, childLength, children;

    if (!getterIfNoArguments || param != null) {
      while(list.length) {
        set = list.shift();
        for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
          element = jqLite(set[setIndex]);
          if (fireEvent) {
            element.triggerHandler('$destroy');
          } else {
            fireEvent = !fireEvent;
          }
          for(childIndex = 0, childLength = (children = element.children()).length;
              childIndex < childLength;
              childIndex++) {
            list.push(jQuery(children[childIndex]));
          }
        }
      }
    }
    return originalJqFn.apply(this, arguments);
  }
}

var SINGLE_TAG_REGEXP = /^<(\w+)\s*\/?>(?:<\/\1>|)$/;
var HTML_REGEXP = /<|&#?\w+;/;
var TAG_NAME_REGEXP = /<([\w:]+)/;
var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi;

var wrapMap = {
  'option': [1, '<select multiple="multiple">', '</select>'],

  'thead': [1, '<table>', '</table>'],
  'col': [2, '<table><colgroup>', '</colgroup></table>'],
  'tr': [2, '<table><tbody>', '</tbody></table>'],
  'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
  '_default': [0, "", ""]
};

wrapMap.optgroup = wrapMap.option;
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
wrapMap.th = wrapMap.td;

function jqLiteIsTextNode(html) {
  return !HTML_REGEXP.test(html);
}

function jqLiteBuildFragment(html, context) {
  var elem, tmp, tag, wrap,
      fragment = context.createDocumentFragment(),
      nodes = [], i, j, jj;

  if (jqLiteIsTextNode(html)) {
    // Convert non-html into a text node
    nodes.push(context.createTextNode(html));
  } else {
    tmp = fragment.appendChild(context.createElement('div'));
    // Convert html into DOM nodes
    tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
    wrap = wrapMap[tag] || wrapMap._default;
    tmp.innerHTML = '<div>&#160;</div>' +
      wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
    tmp.removeChild(tmp.firstChild);

    // Descend through wrappers to the right content
    i = wrap[0];
    while (i--) {
      tmp = tmp.lastChild;
    }

    for (j=0, jj=tmp.childNodes.length; j<jj; ++j) nodes.push(tmp.childNodes[j]);

    tmp = fragment.firstChild;
    tmp.textContent = "";
  }

  // Remove wrapper from fragment
  fragment.textContent = "";
  fragment.innerHTML = ""; // Clear inner HTML
  return nodes;
}

function jqLiteParseHTML(html, context) {
  context = context || document;
  var parsed;

  if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
    return [context.createElement(parsed[1])];
  }

  return jqLiteBuildFragment(html, context);
}

/////////////////////////////////////////////
function JQLite(element) {
  if (element instanceof JQLite) {
    return element;
  }
  if (isString(element)) {
    element = trim(element);
  }
  if (!(this instanceof JQLite)) {
    if (isString(element) && element.charAt(0) != '<') {
      throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
    }
    return new JQLite(element);
  }

  if (isString(element)) {
    jqLiteAddNodes(this, jqLiteParseHTML(element));
    var fragment = jqLite(document.createDocumentFragment());
    fragment.append(this);
  } else {
    jqLiteAddNodes(this, element);
  }
}

function jqLiteClone(element) {
  return element.cloneNode(true);
}

function jqLiteDealoc(element){
  jqLiteRemoveData(element);
  for ( var i = 0, children = element.childNodes || []; i < children.length; i++) {
    jqLiteDealoc(children[i]);
  }
}

function jqLiteOff(element, type, fn, unsupported) {
  if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');

  var events = jqLiteExpandoStore(element, 'events'),
      handle = jqLiteExpandoStore(element, 'handle');

  if (!handle) return; //no listeners registered

  if (isUndefined(type)) {
    forEach(events, function(eventHandler, type) {
      removeEventListenerFn(element, type, eventHandler);
      delete events[type];
    });
  } else {
    forEach(type.split(' '), function(type) {
      if (isUndefined(fn)) {
        removeEventListenerFn(element, type, events[type]);
        delete events[type];
      } else {
        arrayRemove(events[type] || [], fn);
      }
    });
  }
}

function jqLiteRemoveData(element, name) {
  var expandoId = element.ng339,
      expandoStore = jqCache[expandoId];

  if (expandoStore) {
    if (name) {
      delete jqCache[expandoId].data[name];
      return;
    }

    if (expandoStore.handle) {
      expandoStore.events.$destroy && expandoStore.handle({}, '$destroy');
      jqLiteOff(element);
    }
    delete jqCache[expandoId];
    element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
  }
}

function jqLiteExpandoStore(element, key, value) {
  var expandoId = element.ng339,
      expandoStore = jqCache[expandoId || -1];

  if (isDefined(value)) {
    if (!expandoStore) {
      element.ng339 = expandoId = jqNextId();
      expandoStore = jqCache[expandoId] = {};
    }
    expandoStore[key] = value;
  } else {
    return expandoStore && expandoStore[key];
  }
}

function jqLiteData(element, key, value) {
  var data = jqLiteExpandoStore(element, 'data'),
      isSetter = isDefined(value),
      keyDefined = !isSetter && isDefined(key),
      isSimpleGetter = keyDefined && !isObject(key);

  if (!data && !isSimpleGetter) {
    jqLiteExpandoStore(element, 'data', data = {});
  }

  if (isSetter) {
    data[key] = value;
  } else {
    if (keyDefined) {
      if (isSimpleGetter) {
        // don't create data in this case.
        return data && data[key];
      } else {
        extend(data, key);
      }
    } else {
      return data;
    }
  }
}

function jqLiteHasClass(element, selector) {
  if (!element.getAttribute) return false;
  return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
      indexOf( " " + selector + " " ) > -1);
}

function jqLiteRemoveClass(element, cssClasses) {
  if (cssClasses && element.setAttribute) {
    forEach(cssClasses.split(' '), function(cssClass) {
      element.setAttribute('class', trim(
          (" " + (element.getAttribute('class') || '') + " ")
          .replace(/[\n\t]/g, " ")
          .replace(" " + trim(cssClass) + " ", " "))
      );
    });
  }
}

function jqLiteAddClass(element, cssClasses) {
  if (cssClasses && element.setAttribute) {
    var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
                            .replace(/[\n\t]/g, " ");

    forEach(cssClasses.split(' '), function(cssClass) {
      cssClass = trim(cssClass);
      if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
        existingClasses += cssClass + ' ';
      }
    });

    element.setAttribute('class', trim(existingClasses));
  }
}

function jqLiteAddNodes(root, elements) {
  if (elements) {
    elements = (!elements.nodeName && isDefined(elements.length) && !isWindow(elements))
      ? elements
      : [ elements ];
    for(var i=0; i < elements.length; i++) {
      root.push(elements[i]);
    }
  }
}

function jqLiteController(element, name) {
  return jqLiteInheritedData(element, '$' + (name || 'ngController' ) + 'Controller');
}

function jqLiteInheritedData(element, name, value) {
  // if element is the document object work with the html element instead
  // this makes $(document).scope() possible
  if(element.nodeType == 9) {
    element = element.documentElement;
  }
  var names = isArray(name) ? name : [name];

  while (element) {
    for (var i = 0, ii = names.length; i < ii; i++) {
      if ((value = jqLite.data(element, names[i])) !== undefined) return value;
    }

    // If dealing with a document fragment node with a host element, and no parent, use the host
    // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
    // to lookup parent controllers.
    element = element.parentNode || (element.nodeType === 11 && element.host);
  }
}

function jqLiteEmpty(element) {
  for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
    jqLiteDealoc(childNodes[i]);
  }
  while (element.firstChild) {
    element.removeChild(element.firstChild);
  }
}

//////////////////////////////////////////
// Functions which are declared directly.
//////////////////////////////////////////
var JQLitePrototype = JQLite.prototype = {
  ready: function(fn) {
    var fired = false;

    function trigger() {
      if (fired) return;
      fired = true;
      fn();
    }

    // check if document already is loaded
    if (document.readyState === 'complete'){
      setTimeout(trigger);
    } else {
      this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
      // we can not use jqLite since we are not done loading and jQuery could be loaded later.
      // jshint -W064
      JQLite(window).on('load', trigger); // fallback to window.onload for others
      // jshint +W064
    }
  },
  toString: function() {
    var value = [];
    forEach(this, function(e){ value.push('' + e);});
    return '[' + value.join(', ') + ']';
  },

  eq: function(index) {
      return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
  },

  length: 0,
  push: push,
  sort: [].sort,
  splice: [].splice
};

//////////////////////////////////////////
// Functions iterating getter/setters.
// these functions return self on setter and
// value on get.
//////////////////////////////////////////
var BOOLEAN_ATTR = {};
forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
  BOOLEAN_ATTR[lowercase(value)] = value;
});
var BOOLEAN_ELEMENTS = {};
forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
  BOOLEAN_ELEMENTS[uppercase(value)] = true;
});

function getBooleanAttrName(element, name) {
  // check dom last since we will most likely fail on name
  var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];

  // booleanAttr is here twice to minimize DOM access
  return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;
}

forEach({
  data: jqLiteData,
  removeData: jqLiteRemoveData
}, function(fn, name) {
  JQLite[name] = fn;
});

forEach({
  data: jqLiteData,
  inheritedData: jqLiteInheritedData,

  scope: function(element) {
    // Can't use jqLiteData here directly so we stay compatible with jQuery!
    return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
  },

  isolateScope: function(element) {
    // Can't use jqLiteData here directly so we stay compatible with jQuery!
    return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
  },

  controller: jqLiteController,

  injector: function(element) {
    return jqLiteInheritedData(element, '$injector');
  },

  removeAttr: function(element,name) {
    element.removeAttribute(name);
  },

  hasClass: jqLiteHasClass,

  css: function(element, name, value) {
    name = camelCase(name);

    if (isDefined(value)) {
      element.style[name] = value;
    } else {
      var val;

      if (msie <= 8) {
        // this is some IE specific weirdness that jQuery 1.6.4 does not sure why
        val = element.currentStyle && element.currentStyle[name];
        if (val === '') val = 'auto';
      }

      val = val || element.style[name];

      if (msie <= 8) {
        // jquery weirdness :-/
        val = (val === '') ? undefined : val;
      }

      return  val;
    }
  },

  attr: function(element, name, value){
    var lowercasedName = lowercase(name);
    if (BOOLEAN_ATTR[lowercasedName]) {
      if (isDefined(value)) {
        if (!!value) {
          element[name] = true;
          element.setAttribute(name, lowercasedName);
        } else {
          element[name] = false;
          element.removeAttribute(lowercasedName);
        }
      } else {
        return (element[name] ||
                 (element.attributes.getNamedItem(name)|| noop).specified)
               ? lowercasedName
               : undefined;
      }
    } else if (isDefined(value)) {
      element.setAttribute(name, value);
    } else if (element.getAttribute) {
      // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
      // some elements (e.g. Document) don't have get attribute, so return undefined
      var ret = element.getAttribute(name, 2);
      // normalize non-existing attributes to undefined (as jQuery)
      return ret === null ? undefined : ret;
    }
  },

  prop: function(element, name, value) {
    if (isDefined(value)) {
      element[name] = value;
    } else {
      return element[name];
    }
  },

  text: (function() {
    var NODE_TYPE_TEXT_PROPERTY = [];
    if (msie < 9) {
      NODE_TYPE_TEXT_PROPERTY[1] = 'innerText';    /** Element **/
      NODE_TYPE_TEXT_PROPERTY[3] = 'nodeValue';    /** Text **/
    } else {
      NODE_TYPE_TEXT_PROPERTY[1] =                 /** Element **/
      NODE_TYPE_TEXT_PROPERTY[3] = 'textContent';  /** Text **/
    }
    getText.$dv = '';
    return getText;

    function getText(element, value) {
      var textProp = NODE_TYPE_TEXT_PROPERTY[element.nodeType];
      if (isUndefined(value)) {
        return textProp ? element[textProp] : '';
      }
      element[textProp] = value;
    }
  })(),

  val: function(element, value) {
    if (isUndefined(value)) {
      if (nodeName_(element) === 'SELECT' && element.multiple) {
        var result = [];
        forEach(element.options, function (option) {
          if (option.selected) {
            result.push(option.value || option.text);
          }
        });
        return result.length === 0 ? null : result;
      }
      return element.value;
    }
    element.value = value;
  },

  html: function(element, value) {
    if (isUndefined(value)) {
      return element.innerHTML;
    }
    for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
      jqLiteDealoc(childNodes[i]);
    }
    element.innerHTML = value;
  },

  empty: jqLiteEmpty
}, function(fn, name){
  /**
   * Properties: writes return selection, reads return first value
   */
  JQLite.prototype[name] = function(arg1, arg2) {
    var i, key;
    var nodeCount = this.length;

    // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
    // in a way that survives minification.
    // jqLiteEmpty takes no arguments but is a setter.
    if (fn !== jqLiteEmpty &&
        (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined)) {
      if (isObject(arg1)) {

        // we are a write, but the object properties are the key/values
        for (i = 0; i < nodeCount; i++) {
          if (fn === jqLiteData) {
            // data() takes the whole object in jQuery
            fn(this[i], arg1);
          } else {
            for (key in arg1) {
              fn(this[i], key, arg1[key]);
            }
          }
        }
        // return self for chaining
        return this;
      } else {
        // we are a read, so read the first child.
        // TODO: do we still need this?
        var value = fn.$dv;
        // Only if we have $dv do we iterate over all, otherwise it is just the first element.
        var jj = (value === undefined) ? Math.min(nodeCount, 1) : nodeCount;
        for (var j = 0; j < jj; j++) {
          var nodeValue = fn(this[j], arg1, arg2);
          value = value ? value + nodeValue : nodeValue;
        }
        return value;
      }
    } else {
      // we are a write, so apply to all children
      for (i = 0; i < nodeCount; i++) {
        fn(this[i], arg1, arg2);
      }
      // return self for chaining
      return this;
    }
  };
});

function createEventHandler(element, events) {
  var eventHandler = function (event, type) {
    if (!event.preventDefault) {
      event.preventDefault = function() {
        event.returnValue = false; //ie
      };
    }

    if (!event.stopPropagation) {
      event.stopPropagation = function() {
        event.cancelBubble = true; //ie
      };
    }

    if (!event.target) {
      event.target = event.srcElement || document;
    }

    if (isUndefined(event.defaultPrevented)) {
      var prevent = event.preventDefault;
      event.preventDefault = function() {
        event.defaultPrevented = true;
        prevent.call(event);
      };
      event.defaultPrevented = false;
    }

    event.isDefaultPrevented = function() {
      return event.defaultPrevented || event.returnValue === false;
    };

    // Copy event handlers in case event handlers array is modified during execution.
    var eventHandlersCopy = shallowCopy(events[type || event.type] || []);

    forEach(eventHandlersCopy, function(fn) {
      fn.call(element, event);
    });

    // Remove monkey-patched methods (IE),
    // as they would cause memory leaks in IE8.
    if (msie <= 8) {
      // IE7/8 does not allow to delete property on native object
      event.preventDefault = null;
      event.stopPropagation = null;
      event.isDefaultPrevented = null;
    } else {
      // It shouldn't affect normal browsers (native methods are defined on prototype).
      delete event.preventDefault;
      delete event.stopPropagation;
      delete event.isDefaultPrevented;
    }
  };
  eventHandler.elem = element;
  return eventHandler;
}

//////////////////////////////////////////
// Functions iterating traversal.
// These functions chain results into a single
// selector.
//////////////////////////////////////////
forEach({
  removeData: jqLiteRemoveData,

  dealoc: jqLiteDealoc,

  on: function onFn(element, type, fn, unsupported){
    if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');

    var events = jqLiteExpandoStore(element, 'events'),
        handle = jqLiteExpandoStore(element, 'handle');

    if (!events) jqLiteExpandoStore(element, 'events', events = {});
    if (!handle) jqLiteExpandoStore(element, 'handle', handle = createEventHandler(element, events));

    forEach(type.split(' '), function(type){
      var eventFns = events[type];

      if (!eventFns) {
        if (type == 'mouseenter' || type == 'mouseleave') {
          var contains = document.body.contains || document.body.compareDocumentPosition ?
          function( a, b ) {
            // jshint bitwise: false
            var adown = a.nodeType === 9 ? a.documentElement : a,
            bup = b && b.parentNode;
            return a === bup || !!( bup && bup.nodeType === 1 && (
              adown.contains ?
              adown.contains( bup ) :
              a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
              ));
            } :
            function( a, b ) {
              if ( b ) {
                while ( (b = b.parentNode) ) {
                  if ( b === a ) {
                    return true;
                  }
                }
              }
              return false;
            };

          events[type] = [];

          // Refer to jQuery's implementation of mouseenter & mouseleave
          // Read about mouseenter and mouseleave:
          // http://www.quirksmode.org/js/events_mouse.html#link8
          var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"};

          onFn(element, eventmap[type], function(event) {
            var target = this, related = event.relatedTarget;
            // For mousenter/leave call the handler if related is outside the target.
            // NB: No relatedTarget if the mouse left/entered the browser window
            if ( !related || (related !== target && !contains(target, related)) ){
              handle(event, type);
            }
          });

        } else {
          addEventListenerFn(element, type, handle);
          events[type] = [];
        }
        eventFns = events[type];
      }
      eventFns.push(fn);
    });
  },

  off: jqLiteOff,

  one: function(element, type, fn) {
    element = jqLite(element);

    //add the listener twice so that when it is called
    //you can remove the original function and still be
    //able to call element.off(ev, fn) normally
    element.on(type, function onFn() {
      element.off(type, fn);
      element.off(type, onFn);
    });
    element.on(type, fn);
  },

  replaceWith: function(element, replaceNode) {
    var index, parent = element.parentNode;
    jqLiteDealoc(element);
    forEach(new JQLite(replaceNode), function(node){
      if (index) {
        parent.insertBefore(node, index.nextSibling);
      } else {
        parent.replaceChild(node, element);
      }
      index = node;
    });
  },

  children: function(element) {
    var chi
Download .txt
gitextract_2p63vstu/

├── .gitignore
├── .nvmrc
├── Gruntfile.js
├── README-old.md
├── README.md
├── app/
│   ├── css/
│   │   └── application.css
│   ├── fonts/
│   │   └── icons.otf
│   ├── js/
│   │   ├── app.js
│   │   ├── controllers/
│   │   │   ├── notes-create-controller.js
│   │   │   ├── notes-edit-controller.js
│   │   │   ├── notes-index-controller.js
│   │   │   ├── notes-show-controller.js
│   │   │   ├── profile-edit-controller.js
│   │   │   ├── users-index-controller.js
│   │   │   └── users-show-controller.js
│   │   ├── directives/
│   │   │   ├── nw-card.js
│   │   │   ├── nw-category-item.js
│   │   │   ├── nw-category-select.js
│   │   │   ├── nw-page-nav-item.js
│   │   │   ├── nw-session.js
│   │   │   └── title.js
│   │   ├── filters/
│   │   │   └── notes-filter.js
│   │   ├── resources/
│   │   │   ├── note.js
│   │   │   └── user.js
│   │   ├── routes.js
│   │   ├── services/
│   │   │   ├── category.js
│   │   │   ├── markdown.js
│   │   │   ├── note.js
│   │   │   ├── session.js
│   │   │   └── user.js
│   │   └── vendor/
│   │       ├── angular-resource.js
│   │       ├── angular-route.js
│   │       ├── angular.js
│   │       ├── bootstrap.js
│   │       ├── gravatar.js
│   │       ├── jquery.js
│   │       ├── markdown.js
│   │       └── md5.js
│   ├── sass/
│   │   ├── application.sass
│   │   ├── components/
│   │   │   ├── _bucket.sass
│   │   │   ├── _card.sass
│   │   │   ├── _cell.sass
│   │   │   ├── _form.sass
│   │   │   ├── _grid.sass
│   │   │   ├── _list.sass
│   │   │   ├── _panel.sass
│   │   │   ├── _row.sass
│   │   │   └── _well.sass
│   │   ├── foundation/
│   │   │   ├── _base.sass
│   │   │   ├── _config.sass
│   │   │   ├── _helpers.sass
│   │   │   └── _reset.scss
│   │   ├── structures/
│   │   │   ├── _button.sass
│   │   │   ├── _dropdown.sass
│   │   │   ├── _hero.sass
│   │   │   ├── _icons.sass
│   │   │   ├── _registration.sass
│   │   │   └── _sort.sass
│   │   └── vendor/
│   │       └── _tooltip.sass
│   ├── server/
│   │   ├── modules/
│   │   │   ├── dataSeeds.js
│   │   │   ├── encrypt.js
│   │   │   ├── expressConfig.js
│   │   │   ├── models/
│   │   │   │   ├── category.js
│   │   │   │   ├── note.js
│   │   │   │   └── user.js
│   │   │   ├── models.js
│   │   │   ├── routes/
│   │   │   │   ├── category.js
│   │   │   │   ├── note.js
│   │   │   │   ├── session.js
│   │   │   │   └── user.js
│   │   │   └── routes.js
│   │   └── views/
│   │       ├── index.html
│   │       └── session/
│   │           ├── sign_in.ejs
│   │           └── sign_up.ejs
│   └── templates/
│       ├── .gitkeep
│       ├── directives/
│       │   ├── nw-card.html
│       │   ├── nw-category-item.html
│       │   ├── nw-category-select.html
│       │   ├── nw-page-nav-item.html
│       │   └── nw-session.html
│       └── pages/
│           ├── notes/
│           │   ├── edit.html
│           │   ├── index.html
│           │   └── show.html
│           ├── profile/
│           │   └── edit.html
│           └── users/
│               ├── index.html
│               └── show.html
├── app.js
├── dbSeed.js
├── inspector-config.json
├── npm-shrinkwrap.json
└── package.json
Download .txt
SYMBOL INDEX (299 symbols across 7 files)

FILE: app/js/vendor/angular-resource.js
  function isValidDottedPath (line 15) | function isValidDottedPath(path) {
  function lookupDottedPath (line 20) | function lookupDottedPath(obj, path) {
  function shallowClearAndCopy (line 35) | function shallowClearAndCopy(src, dst) {
  function encodeUriSegment (line 351) | function encodeUriSegment(val) {
  function encodeUriQuery (line 370) | function encodeUriQuery(val, pctEncodeSpaces) {
  function Route (line 379) | function Route(template, defaults) {
  function resourceFactory (line 444) | function resourceFactory(url, paramDefaults, actions) {

FILE: app/js/vendor/angular-route.js
  function $RouteProvider (line 42) | function $RouteProvider(){
  function $RouteParamsProvider (line 636) | function $RouteParamsProvider() {
  function ngViewFactory (line 821) | function ngViewFactory(   $route,   $anchorScroll,   $animate) {
  function ngViewFillContentFactory (line 897) | function ngViewFillContentFactory($compile, $controller, $route) {

FILE: app/js/vendor/angular.js
  function minErr (line 36) | function minErr(module) {
  function isArrayLike (line 268) | function isArrayLike(obj) {
  function forEach (line 312) | function forEach(obj, iterator, context) {
  function sortedKeys (line 340) | function sortedKeys(obj) {
  function forEachSorted (line 350) | function forEachSorted(obj, iterator, context) {
  function reverseParams (line 364) | function reverseParams(iteratorFn) {
  function nextUid (line 376) | function nextUid() {
  function setHashKey (line 404) | function setHashKey(obj, h) {
  function extend (line 427) | function extend(dst) {
  function int (line 441) | function int(str) {
  function inherit (line 446) | function inherit(parent, extra) {
  function noop (line 466) | function noop() {}
  function identity (line 486) | function identity($) {return $;}
  function valueFn (line 490) | function valueFn(value) {return function() {return value;};}
  function isUndefined (line 504) | function isUndefined(value){return typeof value === 'undefined';}
  function isDefined (line 519) | function isDefined(value){return typeof value !== 'undefined';}
  function isObject (line 535) | function isObject(value){return value != null && typeof value === 'objec...
  function isString (line 550) | function isString(value){return typeof value === 'string';}
  function isNumber (line 565) | function isNumber(value){return typeof value === 'number';}
  function isDate (line 580) | function isDate(value) {
  function isFunction (line 618) | function isFunction(value){return typeof value === 'function';}
  function isRegExp (line 628) | function isRegExp(value) {
  function isWindow (line 640) | function isWindow(obj) {
  function isScope (line 645) | function isScope(obj) {
  function isFile (line 650) | function isFile(obj) {
  function isBlob (line 655) | function isBlob(obj) {
  function isBoolean (line 660) | function isBoolean(value) {
  function isPromiseLike (line 665) | function isPromiseLike(obj) {
  function isElement (line 697) | function isElement(node) {
  function makeMap (line 707) | function makeMap(str) {
  function map (line 728) | function map(obj, iterator, context) {
  function size (line 749) | function size(obj, ownPropsOnly) {
  function includes (line 764) | function includes(array, obj) {
  function indexOf (line 768) | function indexOf(array, obj) {
  function arrayRemove (line 777) | function arrayRemove(array, value) {
  function isLeafNode (line 784) | function isLeafNode (node) {
  function copy (line 854) | function copy(source, destination, stackSource, stackDest) {
  function shallowCopy (line 923) | function shallowCopy(src, dst) {
  function equals (line 973) | function equals(o1, o2) {
  function concat (line 1034) | function concat(array1, array2, index) {
  function sliceArgs (line 1038) | function sliceArgs(args, startIndex) {
  function bind (line 1062) | function bind(self, fn) {
  function toJsonReplacer (line 1083) | function toJsonReplacer(key, value) {
  function toJson (line 1114) | function toJson(obj, pretty) {
  function fromJson (line 1132) | function fromJson(json) {
  function toBoolean (line 1139) | function toBoolean(value) {
  function startingTag (line 1154) | function startingTag(element) {
  function tryDecodeURIComponent (line 1186) | function tryDecodeURIComponent(value) {
  function parseKeyValue (line 1199) | function parseKeyValue(/**string*/keyValue) {
  function toKeyValue (line 1220) | function toKeyValue(obj) {
  function encodeUriSegment (line 1248) | function encodeUriSegment(val) {
  function encodeUriQuery (line 1267) | function encodeUriQuery(val, pctEncodeSpaces) {
  function angularInit (line 1323) | function angularInit(element, bootstrap) {
  function bootstrap (line 1421) | function bootstrap(element, modules) {
  function snake_case (line 1463) | function snake_case(name, separator) {
  function bindJQuery (line 1470) | function bindJQuery() {
  function assertArg (line 1498) | function assertArg(arg, name, reason) {
  function assertArgFn (line 1505) | function assertArgFn(arg, name, acceptArrayAnnotation) {
  function assertNotHasOwnProperty (line 1520) | function assertNotHasOwnProperty(name, context) {
  function getter (line 1534) | function getter(obj, path, bindFnToScope) {
  function getBlockElements (line 1558) | function getBlockElements(nodes) {
  function setupModuleLoader (line 1586) | function setupModuleLoader(window) {
  function publishExternalAPI (line 1988) | function publishExternalAPI(angular){
  function jqNextId (line 2223) | function jqNextId() { return ++jqId; }
  function camelCase (line 2235) | function camelCase(name) {
  function jqLitePatchJQueryRemove (line 2251) | function jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getter...
  function jqLiteIsTextNode (line 2305) | function jqLiteIsTextNode(html) {
  function jqLiteBuildFragment (line 2309) | function jqLiteBuildFragment(html, context) {
  function jqLiteParseHTML (line 2344) | function jqLiteParseHTML(html, context) {
  function JQLite (line 2356) | function JQLite(element) {
  function jqLiteClone (line 2379) | function jqLiteClone(element) {
  function jqLiteDealoc (line 2383) | function jqLiteDealoc(element){
  function jqLiteOff (line 2390) | function jqLiteOff(element, type, fn, unsupported) {
  function jqLiteRemoveData (line 2415) | function jqLiteRemoveData(element, name) {
  function jqLiteExpandoStore (line 2434) | function jqLiteExpandoStore(element, key, value) {
  function jqLiteData (line 2449) | function jqLiteData(element, key, value) {
  function jqLiteHasClass (line 2475) | function jqLiteHasClass(element, selector) {
  function jqLiteRemoveClass (line 2481) | function jqLiteRemoveClass(element, cssClasses) {
  function jqLiteAddClass (line 2493) | function jqLiteAddClass(element, cssClasses) {
  function jqLiteAddNodes (line 2509) | function jqLiteAddNodes(root, elements) {
  function jqLiteController (line 2520) | function jqLiteController(element, name) {
  function jqLiteInheritedData (line 2524) | function jqLiteInheritedData(element, name, value) {
  function jqLiteEmpty (line 2544) | function jqLiteEmpty(element) {
  function trigger (line 2560) | function trigger() {
  function getBooleanAttrName (line 2607) | function getBooleanAttrName(element, name) {
  function getText (line 2721) | function getText(element, value) {
  function createEventHandler (line 2808) | function createEventHandler(element, events) {
  function hashKey (line 3113) | function hashKey(obj, nextUidFn) {
  function HashMap (line 3134) | function HashMap(array, isolatedUid) {
  function annotate (line 3238) | function annotate(fn) {
  function createInjector (line 3759) | function createInjector(modulesToLoad) {
  function $AnchorScrollProvider (line 4017) | function $AnchorScrollProvider() {
  function async (line 4152) | function async(fn) {
  function $$AsyncCallbackProvider (line 4315) | function $$AsyncCallbackProvider(){
  function Browser (line 4347) | function Browser(window, document, $log, $sniffer) {
  function $BrowserProvider (line 4701) | function $BrowserProvider(){
  function $CacheFactoryProvider (line 4787) | function $CacheFactoryProvider() {
  function $TemplateCacheProvider (line 5099) | function $TemplateCacheProvider() {
  function $CompileProvider (line 5618) | function $CompileProvider($provide, $$sanitizeUriProvider) {
  function directiveNormalize (line 7095) | function directiveNormalize(name) {
  function nodesetLinkingFn (line 7142) | function nodesetLinkingFn(
  function directiveLinkingFn (line 7149) | function directiveLinkingFn(
  function tokenDifference (line 7157) | function tokenDifference(str1, str2) {
  function $ControllerProvider (line 7183) | function $ControllerProvider() {
  function $DocumentProvider (line 7286) | function $DocumentProvider(){
  function $ExceptionHandlerProvider (line 7324) | function $ExceptionHandlerProvider() {
  function parseHeaders (line 7338) | function parseHeaders(headers) {
  function headersGetter (line 7369) | function headersGetter(headers) {
  function transformData (line 7394) | function transformData(data, headers, fns) {
  function isSuccess (line 7406) | function isSuccess(status) {
  function $HttpProvider (line 7417) | function $HttpProvider() {
  function createXhr (line 8394) | function createXhr(method) {
  function $HttpBackendProvider (line 8424) | function $HttpBackendProvider() {
  function createHttpBackend (line 8430) | function createHttpBackend($browser, createXhr, $browserDefer, callbacks...
  function $InterpolateProvider (line 8645) | function $InterpolateProvider() {
  function $IntervalProvider (line 8857) | function $IntervalProvider() {
  function $LocaleProvider (line 9052) | function $LocaleProvider(){
  function encodePath (line 9125) | function encodePath(path) {
  function parseAbsoluteUrl (line 9136) | function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) {
  function parseAppUrl (line 9145) | function parseAppUrl(relativeUrl, locationObj, appBase) {
  function beginsWith (line 9170) | function beginsWith(begin, whole) {
  function stripHash (line 9177) | function stripHash(url) {
  function stripFile (line 9183) | function stripFile(url) {
  function serverBase (line 9188) | function serverBase(url) {
  function LocationHtml5Url (line 9201) | function LocationHtml5Url(appBase, basePrefix) {
  function LocationHashbangUrl (line 9269) | function LocationHashbangUrl(appBase, hashPrefix) {
  function LocationHashbangInHtml5Url (line 9362) | function LocationHashbangInHtml5Url(appBase, hashPrefix) {
  function locationGetter (line 9616) | function locationGetter(property) {
  function locationGetterSetter (line 9623) | function locationGetterSetter(property, preprocess) {
  function $LocationProvider (line 9668) | function $LocationProvider(){
  function $LogProvider (line 9917) | function $LogProvider(){
  function ensureSafeMemberName (line 10062) | function ensureSafeMemberName(name, fullExpression) {
  function ensureSafeObject (line 10073) | function ensureSafeObject(obj, fullExpression) {
  function ensureSafeFunction (line 10104) | function ensureSafeFunction(obj, fullExpression) {
  function setter (line 10873) | function setter(obj, path, setValue, fullExp, options) {
  function cspSafeGetterFn (line 10913) | function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
  function getterFn (line 11017) | function getterFn(path, options, fullExp) {
  function $ParseProvider (line 11140) | function $ParseProvider() {
  function $QProvider (line 11437) | function $QProvider() {
  function qFactory (line 11455) | function qFactory(nextTick, exceptionHandler) {
  function $$RAFProvider (line 11793) | function $$RAFProvider(){ //rAF
  function $RootScopeProvider (line 11892) | function $RootScopeProvider(){
  function $$SanitizeUriProvider (line 12978) | function $$SanitizeUriProvider() {
  function escapeForRegexp (line 13064) | function escapeForRegexp(s) {
  function adjustMatcher (line 13070) | function adjustMatcher(matcher) {
  function adjustMatchers (line 13098) | function adjustMatchers(matchers) {
  function $SceDelegateProvider (line 13176) | function $SceDelegateProvider() {
  function $SceProvider (line 13706) | function $SceProvider() {
  function $SnifferProvider (line 14119) | function $SnifferProvider() {
  function $TimeoutProvider (line 14196) | function $TimeoutProvider() {
  function urlResolve (line 14342) | function urlResolve(url, base) {
  function urlIsSameOrigin (line 14376) | function urlIsSameOrigin(requestUrl) {
  function $WindowProvider (line 14423) | function $WindowProvider(){
  function $FilterProvider (line 14530) | function $FilterProvider($provide) {
  function filterFilter (line 14698) | function filterFilter() {
  function currencyFilter (line 14853) | function currencyFilter($locale) {
  function numberFilter (line 14914) | function numberFilter($locale) {
  function formatNumber (line 14923) | function formatNumber(number, pattern, groupSep, decimalSep, fractionSiz...
  function padNumber (line 15001) | function padNumber(num, digits, trim) {
  function dateGetter (line 15015) | function dateGetter(name, size, offset, trim) {
  function dateStrGetter (line 15026) | function dateStrGetter(name, shortForm) {
  function timeZoneGetter (line 15035) | function timeZoneGetter(date) {
  function ampmGetter (line 15045) | function ampmGetter(date, formats) {
  function dateFilter (line 15161) | function dateFilter($locale) {
  function jsonFilter (line 15260) | function jsonFilter() {
  function limitToFilter (line 15358) | function limitToFilter(){
  function orderByFilter (line 15511) | function orderByFilter($parse){
  function ngDirective (line 15572) | function ngDirective(directive) {
  function FormController (line 16073) | function FormController(element, attrs, $scope, $animate) {
  function validate (line 16886) | function validate(ctrl, validatorName, validity, value){
  function testFlags (line 16891) | function testFlags(validity, flags) {
  function addNativeHtml5Validators (line 16905) | function addNativeHtml5Validators(ctrl, validatorName, badFlags, ignoreF...
  function textInputType (line 16923) | function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
  function numberInputType (line 17076) | function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
  function urlInputType (line 17121) | function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
  function emailInputType (line 17132) | function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
  function radioInputType (line 17143) | function radioInputType(scope, element, attr, ctrl) {
  function checkboxInputType (line 17165) | function checkboxInputType(scope, element, attr, ctrl) {
  function toggleValidCss (line 17556) | function toggleValidCss(isValid, validationErrorKey) {
  function getStringValue (line 18273) | function getStringValue() {
  function classDirective (line 18285) | function classDirective(name, selector) {
  function getBlockStart (line 20520) | function getBlockStart(block) {
  function getBlockEnd (line 20524) | function getBlockEnd(block) {
  function setupAsSingle (line 21463) | function setupAsSingle(scope, selectElement, ngModelCtrl, selectCtrl) {
  function setupAsMultiple (line 21488) | function setupAsMultiple(scope, selectElement, ctrl) {
  function setupAsOptions (line 21519) | function setupAsOptions(scope, selectElement, ctrl) {

FILE: app/js/vendor/bootstrap.js
  function removeElement (line 58) | function removeElement() {
  function Plugin (line 74) | function Plugin(option) {
  function Plugin (line 177) | function Plugin(option) {
  function Plugin (line 382) | function Plugin(option) {
  function clearMenus (line 527) | function clearMenus(e) {
  function getParent (line 540) | function getParent($this) {
  function Plugin (line 557) | function Plugin(option) {
  function Plugin (line 825) | function Plugin(option, _relatedTarget) {
  function complete (line 1157) | function complete() {
  function Plugin (line 1304) | function Plugin(option) {
  function Plugin (line 1418) | function Plugin(option) {
  function next (line 1505) | function next() {
  function Plugin (line 1540) | function Plugin(option) {
  function Plugin (line 1673) | function Plugin(option) {
  function Plugin (line 1837) | function Plugin(option) {
  function ScrollSpy (line 1904) | function ScrollSpy(element, options) {
  function Plugin (line 2022) | function Plugin(option) {
  function transitionEnd (line 2075) | function transitionEnd() {

FILE: app/js/vendor/jquery.js
  function isArraylike (line 534) | function isArraylike( obj ) {
  function Sizzle (line 737) | function Sizzle( selector, context, results, seed ) {
  function createCache (line 852) | function createCache() {
  function markFunction (line 870) | function markFunction( fn ) {
  function assert (line 879) | function assert( fn ) {
  function addHandle (line 901) | function addHandle( attrs, handler ) {
  function siblingCheck (line 916) | function siblingCheck( a, b ) {
  function createInputPseudo (line 943) | function createInputPseudo( type ) {
  function createButtonPseudo (line 954) | function createButtonPseudo( type ) {
  function createPositionalPseudo (line 965) | function createPositionalPseudo( fn ) {
  function testContext (line 988) | function testContext( context ) {
  function setFilters (line 1985) | function setFilters() {}
  function toSelector (line 2056) | function toSelector( tokens ) {
  function addCombinator (line 2066) | function addCombinator( matcher, combinator, base ) {
  function elementMatcher (line 2119) | function elementMatcher( matchers ) {
  function multipleContexts (line 2133) | function multipleContexts( selector, contexts, results ) {
  function condense (line 2142) | function condense( unmatched, map, filter, context, xml ) {
  function setMatcher (line 2163) | function setMatcher( preFilter, selector, matcher, postFilter, postFinde...
  function matcherFromTokens (line 2256) | function matcherFromTokens( tokens ) {
  function matcherFromGroupMatchers (line 2311) | function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
  function winnow (line 2607) | function winnow( elements, qualifier, not ) {
  function sibling (line 2932) | function sibling( cur, dir ) {
  function createOptions (line 3010) | function createOptions( options ) {
  function completed (line 3404) | function completed() {
  function Data (line 3509) | function Data() {
  function dataAttr (line 3701) | function dataAttr( elem, key, data ) {
  function returnTrue (line 4040) | function returnTrue() {
  function returnFalse (line 4044) | function returnFalse() {
  function safeActiveElement (line 4048) | function safeActiveElement() {
  function manipulationTarget (line 4920) | function manipulationTarget( elem, content ) {
  function disableScript (line 4930) | function disableScript( elem ) {
  function restoreScript (line 4934) | function restoreScript( elem ) {
  function setGlobalEval (line 4947) | function setGlobalEval( elems, refElements ) {
  function cloneCopyEvent (line 4958) | function cloneCopyEvent( src, dest ) {
  function getAll (line 4992) | function getAll( context, tag ) {
  function fixInput (line 5003) | function fixInput( src, dest ) {
  function actualDisplay (line 5460) | function actualDisplay( name, doc ) {
  function defaultDisplay (line 5482) | function defaultDisplay( nodeName ) {
  function curCSS (line 5522) | function curCSS( elem, name, computed ) {
  function addGetHookIf (line 5570) | function addGetHookIf( conditionFn, hookFn ) {
  function computePixelPositionAndBoxSizingReliable (line 5610) | function computePixelPositionAndBoxSizingReliable() {
  function vendorPropName (line 5712) | function vendorPropName( style, name ) {
  function setPositiveNumber (line 5734) | function setPositiveNumber( elem, value, subtract ) {
  function augmentWidthOrHeight (line 5742) | function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
  function getWidthOrHeight (line 5781) | function getWidthOrHeight( elem, name, extra ) {
  function showHide (line 5825) | function showHide( elements, show ) {
  function Tween (line 6124) | function Tween( elem, options, prop, end, easing ) {
  function createFxNow (line 6293) | function createFxNow() {
  function genFx (line 6301) | function genFx( type, includeWidth ) {
  function createTween (line 6321) | function createTween( value, prop, animation ) {
  function defaultPrefilter (line 6335) | function defaultPrefilter( elem, props, opts ) {
  function propFilter (line 6469) | function propFilter( props, specialEasing ) {
  function Animation (line 6506) | function Animation( elem, properties, options ) {
  function addToPrefiltersOrTransports (line 7573) | function addToPrefiltersOrTransports( structure ) {
  function inspectPrefiltersOrTransports (line 7605) | function inspectPrefiltersOrTransports( structure, options, originalOpti...
  function ajaxExtend (line 7632) | function ajaxExtend( target, src ) {
  function ajaxHandleResponses (line 7652) | function ajaxHandleResponses( s, jqXHR, responses ) {
  function ajaxConvert (line 7708) | function ajaxConvert( s, response, jqXHR, isSuccess ) {
  function done (line 8165) | function done( status, nativeStatusText, responses, headers ) {
  function buildParams (line 8417) | function buildParams( prefix, obj, traditional, add ) {
  function getWindow (line 8900) | function getWindow( elem ) {

FILE: app/js/vendor/markdown.js
  function mk_block_toSource (line 118) | function mk_block_toSource() {
  function mk_block_inspect (line 129) | function mk_block_inspect() {
  function count_lines (line 157) | function count_lines( str ) {
  function regex_for_depth (line 434) | function regex_for_depth( depth ) {
  function expand_tab (line 443) | function expand_tab( input ) {
  function add (line 449) | function add(li, loose, inline, nl) {
  function get_contained_blocks (line 476) | function get_contained_blocks( depth, blocks ) {
  function paragraphify (line 498) | function paragraphify(s, i, stack) {
  function make_list (line 521) | function make_list( m ) {
  function add (line 806) | function add(x) {
  function strong_em (line 1007) | function strong_em( tag, md ) {
  function Block (line 1133) | function Block() {}
  function Inline (line 1135) | function Inline() {}
  function split_meta_hash (line 1175) | function split_meta_hash( meta_string ) {
  function extract_attr (line 1463) | function extract_attr( jsonml ) {
  function escapeHTML (line 1511) | function escapeHTML( text ) {
  function render_tree (line 1519) | function render_tree( jsonml ) {
  function convert_tree_to_html (line 1551) | function convert_tree_to_html( tree, references, options ) {
  function merge_text_nodes (line 1694) | function merge_text_nodes( jsonml ) {

FILE: app/js/vendor/md5.js
  function p (line 14) | function p(a,k,b,h,l,j,m){a=a+(k&b|~k&h)+l+m;return(a<<j|a>>>32-j)+k}
  function m (line 14) | function m(a,k,b,h,l,j,m){a=a+(k&h|b&~h)+l+m;return(a<<j|a>>>32-j)+k}
  function l (line 14) | function l(a,k,b,h,l,j,m){a=a+(k^b^h)+l+m;return(a<<j|a>>>32-j)+k}
  function n (line 14) | function n(a,k,b,h,l,j,m){a=a+(b^(k|~h))+l+m;return(a<<j|a>>>32-j)+k}
Condensed preview — 91 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,478K chars).
[
  {
    "path": ".gitignore",
    "chars": 37,
    "preview": "/node_modules\nnpm-debug.log\n.DS_Store"
  },
  {
    "path": ".nvmrc",
    "chars": 6,
    "preview": "5.5.0\n"
  },
  {
    "path": "Gruntfile.js",
    "chars": 536,
    "preview": "module.exports = function(grunt) {\n  grunt.initConfig({\n    sass: {\n      dist: {\n        files: {\n          'app/css/ap"
  },
  {
    "path": "README-old.md",
    "chars": 8358,
    "preview": "# angular-seed — the seed for AngularJS apps\n\nThis project started from the Angular seed app: [AngularJS](http://angular"
  },
  {
    "path": "README.md",
    "chars": 1555,
    "preview": "## Getting Started\n\nTo get you started you can simply clone the note-wrangler repo and install the dependencies:\n\n### In"
  },
  {
    "path": "app/css/application.css",
    "chars": 20429,
    "preview": "@charset \"UTF-8\";\n/*! normalize.css v3.0.0 | MIT License | git.io/normalize */\n/**\n * 1. Set default font family to sans"
  },
  {
    "path": "app/js/app.js",
    "chars": 198,
    "preview": "// Declare app level module which depends on ngRoute\nangular.module('NoteWrangler', ['ngRoute', 'ngResource', 'Gravatar'"
  },
  {
    "path": "app/js/controllers/notes-create-controller.js",
    "chars": 931,
    "preview": "angular.module('NoteWrangler').controller('NotesCreateController', function($scope, Note, Category, Session) {\n  \n  // r"
  },
  {
    "path": "app/js/controllers/notes-edit-controller.js",
    "chars": 994,
    "preview": "angular.module('NoteWrangler').controller('NotesEditController', function($scope, $routeParams, Note, Category, Session)"
  },
  {
    "path": "app/js/controllers/notes-index-controller.js",
    "chars": 413,
    "preview": "angular.module('NoteWrangler').controller('NotesIndexController', function($scope, Note, Session) {\n  // Without NgResou"
  },
  {
    "path": "app/js/controllers/notes-show-controller.js",
    "chars": 407,
    "preview": "angular.module('NoteWrangler').controller('NotesShowController', function($scope, $routeParams, Note, Session) {\n  // Wi"
  },
  {
    "path": "app/js/controllers/profile-edit-controller.js",
    "chars": 888,
    "preview": "angular.module('NoteWrangler').controller('ProfileEditController', function($scope, $location, User, Session) {\n  \n  // "
  },
  {
    "path": "app/js/controllers/users-index-controller.js",
    "chars": 356,
    "preview": "angular.module('NoteWrangler').controller('UsersIndexController', function($scope, User, $gravatar) {\n  \n  // Without Ng"
  },
  {
    "path": "app/js/controllers/users-show-controller.js",
    "chars": 402,
    "preview": "angular.module('NoteWrangler').controller('UsersShowController', function($scope, $routeParams, User, $gravatar) {\n  \n  "
  },
  {
    "path": "app/js/directives/nw-card.js",
    "chars": 1088,
    "preview": "angular.module('NoteWrangler')\n.directive('nwCard', ['$sce', function($sce) {\n  return {\n    replace: true,\n    restrict"
  },
  {
    "path": "app/js/directives/nw-category-item.js",
    "chars": 1552,
    "preview": "angular.module('NoteWrangler')\n.directive('nwCategoryItem', function() {\n  return {\n    restrict: \"E\",\n    require: \"^nw"
  },
  {
    "path": "app/js/directives/nw-category-select.js",
    "chars": 2013,
    "preview": "angular.module('NoteWrangler')\n.directive('nwCategorySelect', function(Category) {\n  return {\n    replace: true,\n    res"
  },
  {
    "path": "app/js/directives/nw-page-nav-item.js",
    "chars": 1098,
    "preview": "angular.module('NoteWrangler').directive('nwPageNavItem', function($location) {\n  return {\n    replace: true,\n    restri"
  },
  {
    "path": "app/js/directives/nw-session.js",
    "chars": 348,
    "preview": "angular.module('NoteWrangler').directive('nwSession', function(Session) {\n  return {\n    replace: true,\n    restrict: 'E"
  },
  {
    "path": "app/js/directives/title.js",
    "chars": 282,
    "preview": "angular.module('NoteWrangler')\n.directive('title', function($timeout) {\n  return function(scope, element) {\n    $timeout"
  },
  {
    "path": "app/js/filters/notes-filter.js",
    "chars": 1516,
    "preview": "// This is a custom filter which will filter by the filter value and search within the result\n// of the category filter "
  },
  {
    "path": "app/js/resources/note.js",
    "chars": 289,
    "preview": "/*\nThis is a way of handling ajax requests using NgResource, it performs a similar function\nto the Note Service.\n*/\n\nang"
  },
  {
    "path": "app/js/resources/user.js",
    "chars": 288,
    "preview": "/*\nThis is a way of handling ajax requests using NgResource, it performs a similar function\nto the UserService.\n*/\n\nangu"
  },
  {
    "path": "app/js/routes.js",
    "chars": 1525,
    "preview": "/*\n  Configure routes used with ngRoute. We chose not to use $locationProvider.html5Mode(true);\n  because using HTML5 pu"
  },
  {
    "path": "app/js/services/category.js",
    "chars": 948,
    "preview": "angular.module('NoteWrangler').factory('Category', function CategoryFactory($http, $q) {\n  var categories;\n  \n  return {"
  },
  {
    "path": "app/js/services/markdown.js",
    "chars": 247,
    "preview": "// In level 3 they need to refactor the code from nw-card.js into a Service:\n\nangular.module('NoteWrangler').factory( 'm"
  },
  {
    "path": "app/js/services/note.js",
    "chars": 644,
    "preview": "/*\nThis is an example of how to handle ajax data calls without using NgResource\nThis is for reference only, we favor usi"
  },
  {
    "path": "app/js/services/session.js",
    "chars": 674,
    "preview": "/*\n  The idea behind this service is that we start off the fetching of the session as soon\n  as the service loads. Any s"
  },
  {
    "path": "app/js/services/user.js",
    "chars": 536,
    "preview": "/*\nThis is an example of how to handle ajax data calls without using NgResource\nThis is for reference only, we favor usi"
  },
  {
    "path": "app/js/vendor/angular-resource.js",
    "chars": 24278,
    "preview": "/**\n * @license AngularJS v1.2.21\n * (c) 2010-2014 Google, Inc. http://angularjs.org\n * License: MIT\n */\n(function(windo"
  },
  {
    "path": "app/js/vendor/angular-route.js",
    "chars": 33032,
    "preview": "/**\n * @license AngularJS v1.2.21\n * (c) 2010-2014 Google, Inc. http://angularjs.org\n * License: MIT\n */\n(function(windo"
  },
  {
    "path": "app/js/vendor/angular.js",
    "chars": 777516,
    "preview": "/**\n * @license AngularJS v1.2.21\n * (c) 2010-2014 Google, Inc. http://angularjs.org\n * License: MIT\n */\n(function(windo"
  },
  {
    "path": "app/js/vendor/bootstrap.js",
    "chars": 60873,
    "preview": "/*!\n * Bootstrap v3.2.0 (http://getbootstrap.com)\n * Copyright 2011-2014 Twitter, Inc.\n * Licensed under MIT (https://gi"
  },
  {
    "path": "app/js/vendor/gravatar.js",
    "chars": 1434,
    "preview": "// This module depends on the google CryptoJS library, you can load it by adding:\n// <script src=\"http://crypto-js.googl"
  },
  {
    "path": "app/js/vendor/jquery.js",
    "chars": 247351,
    "preview": "/*!\n * jQuery JavaScript Library v2.1.1\n * http://jquery.com/\n *\n * Includes Sizzle.js\n * http://sizzlejs.com/\n *\n * Cop"
  },
  {
    "path": "app/js/vendor/markdown.js",
    "chars": 50969,
    "preview": "// Released under MIT license\n// Copyright (c) 2009-2010 Dominic Baggott\n// Copyright (c) 2009-2010 Ash Berlin\n// Copyri"
  },
  {
    "path": "app/js/vendor/md5.js",
    "chars": 6269,
    "preview": "/*\nCryptoJS v3.1.2\ncode.google.com/p/crypto-js\n(c) 2009-2013 by Jeff Mott. All rights reserved.\ncode.google.com/p/crypto"
  },
  {
    "path": "app/sass/application.sass",
    "chars": 2243,
    "preview": "// *************************************\n//\n//   [Project Name] - MVCSS v4.0.2\n//   -> Manifest\n//\n// ******************"
  },
  {
    "path": "app/sass/components/_bucket.sass",
    "chars": 976,
    "preview": "// *************************************\n//\n//   Bucket\n//   -> Based on:\n//      * http://jsfiddle.net/necolas/rZvEF/\n/"
  },
  {
    "path": "app/sass/components/_card.sass",
    "chars": 1536,
    "preview": "// *************************************\n//\n//   Card\n//   -> Individual style containers\n//\n// ------------------------"
  },
  {
    "path": "app/sass/components/_cell.sass",
    "chars": 522,
    "preview": "// *************************************\n//\n//   Cell\n//   -> Width-limiting blocks\n//\n// ------------------------------"
  },
  {
    "path": "app/sass/components/_form.sass",
    "chars": 2284,
    "preview": "// *************************************\n//\n//   Form\n//   -> Fields, selects, & such\n//\n// ----------------------------"
  },
  {
    "path": "app/sass/components/_grid.sass",
    "chars": 2135,
    "preview": "// *************************************\n//\n//   Grid\n//   -> Based on the following:\n//      * https://github.com/necol"
  },
  {
    "path": "app/sass/components/_list.sass",
    "chars": 1217,
    "preview": "// *************************************\n//\n//   List\n//   -> Enumeration of items\n//\n// -------------------------------"
  },
  {
    "path": "app/sass/components/_panel.sass",
    "chars": 995,
    "preview": "// *************************************\n//\n//   Panel\n//   -> Sticky panel\n//\n// -------------------------------------\n"
  },
  {
    "path": "app/sass/components/_row.sass",
    "chars": 474,
    "preview": "// *************************************\n//\n//   Row\n//   -> Width-spanning blocks\n//\n// -------------------------------"
  },
  {
    "path": "app/sass/components/_well.sass",
    "chars": 668,
    "preview": "// *************************************\n//\n//   Well\n//   -> Vertical spacing\n//\n// -----------------------------------"
  },
  {
    "path": "app/sass/foundation/_base.sass",
    "chars": 1157,
    "preview": "// *************************************\n//\n//   Base\n//   -> Tag-level settings\n//\n// *********************************"
  },
  {
    "path": "app/sass/foundation/_config.sass",
    "chars": 2149,
    "preview": "// *************************************\n//\n//   Config\n//   -> Fonts, Variables\n//\n// *********************************"
  },
  {
    "path": "app/sass/foundation/_helpers.sass",
    "chars": 4147,
    "preview": "// *************************************\n//\n//   Helpers\n//   -> Functions, Mixins, Extends, Animations\n//\n// **********"
  },
  {
    "path": "app/sass/foundation/_reset.scss",
    "chars": 7583,
    "preview": "/*! normalize.css v3.0.0 | MIT License | git.io/normalize */\n\n/**\n * 1. Set default font family to sans-serif.\n * 2. Pre"
  },
  {
    "path": "app/sass/structures/_button.sass",
    "chars": 896,
    "preview": "// *************************************\n//\n//   Button\n//   -> Button Styles\n//\n// ************************************"
  },
  {
    "path": "app/sass/structures/_dropdown.sass",
    "chars": 2376,
    "preview": "// *************************************\n//\n//   Dropdown\n//   -> Dropdown menus\n//\n// ---------------------------------"
  },
  {
    "path": "app/sass/structures/_hero.sass",
    "chars": 515,
    "preview": "// *************************************\n//\n//   Hero\n//   -> Main Hero image in header\n//\n// **************************"
  },
  {
    "path": "app/sass/structures/_icons.sass",
    "chars": 1506,
    "preview": "// *************************************\n//\n//   Icons\n//   -> Icons\n//\n// *************************************\n\n@font-"
  },
  {
    "path": "app/sass/structures/_registration.sass",
    "chars": 526,
    "preview": "// *************************************\n//\n//   Registration\n//   -> Sign-in and Sign-up Styles\n//\n// *****************"
  },
  {
    "path": "app/sass/structures/_sort.sass",
    "chars": 766,
    "preview": "// *************************************\n//\n//   Sort\n//   -> Sort-menu\n//\n// *************************************\n\n.so"
  },
  {
    "path": "app/sass/vendor/_tooltip.sass",
    "chars": 1800,
    "preview": "// *************************************\n//\n//   Tooltip\n//   -> Bootstrap Tooltip\n//\n// *******************************"
  },
  {
    "path": "app/server/modules/dataSeeds.js",
    "chars": 8637,
    "preview": "/*\nThis file is used to add some default seed data to the database when the app is initially\nsetup. Normally this module"
  },
  {
    "path": "app/server/modules/encrypt.js",
    "chars": 744,
    "preview": "var bcrypt, encryptionUtil;\nbcrypt = require('bcrypt');\nvar salt = \"$2a$10$4u0KgeI40vhqD4DN73Ljsu\"\n\n// This is a simplis"
  },
  {
    "path": "app/server/modules/expressConfig.js",
    "chars": 1937,
    "preview": "var passport = require('passport');\nvar cookieSession = require('cookie-session');\nvar bodyParser = require('body-parser"
  },
  {
    "path": "app/server/modules/models/category.js",
    "chars": 345,
    "preview": "/*\nThis is a combination model/migration/database table definition. See:\nhttp://sequelizejs.com/docs/1.7.8/models#defini"
  },
  {
    "path": "app/server/modules/models/note.js",
    "chars": 427,
    "preview": "/*\nThis is a combination model/migration/database table definition. See:\nhttp://sequelizejs.com/docs/1.7.8/models#defini"
  },
  {
    "path": "app/server/modules/models/user.js",
    "chars": 465,
    "preview": "/*\nThis is a combination model/migration/database table definition. See:\nhttp://sequelizejs.com/docs/1.7.8/models#defini"
  },
  {
    "path": "app/server/modules/models.js",
    "chars": 1177,
    "preview": "/*\nThis file is for configuring the model relations. For example, users can have many\nnotes and notes belong to a user. "
  },
  {
    "path": "app/server/modules/routes/category.js",
    "chars": 358,
    "preview": "var models = require('../models');\nvar Category = models.Category;\n\nmodule.exports = function(app) {\n  // Return a list "
  },
  {
    "path": "app/server/modules/routes/note.js",
    "chars": 2461,
    "preview": "var models = require('../models');\nvar Note = models.Note;\nvar User = models.User;\nvar Category = models.Category;\nvar n"
  },
  {
    "path": "app/server/modules/routes/session.js",
    "chars": 3253,
    "preview": "var passport = require('passport');\nvar LocalStrategy = require('passport-local').Strategy;\nvar encrypt = require('../en"
  },
  {
    "path": "app/server/modules/routes/user.js",
    "chars": 1556,
    "preview": "var models = require('../models');\nvar User = models.User;\nvar Note = models.Note;\nvar userSafeParams = ['id', 'name', '"
  },
  {
    "path": "app/server/modules/routes.js",
    "chars": 501,
    "preview": "var express = require('express');\nvar app = express();\n\n// Load Express Configuration\nrequire('./expressConfig')(app, ex"
  },
  {
    "path": "app/server/views/index.html",
    "chars": 3540,
    "preview": "<!DOCTYPE html>\n<!--[if lt IE 7]>      <html lang=\"en\" ng-app=\"NoteWrangler\" class=\"no-js lt-ie9 lt-ie8 lt-ie7\"> <![endi"
  },
  {
    "path": "app/server/views/session/sign_in.ejs",
    "chars": 1269,
    "preview": "<!DOCTYPE html>\n<!--[if lt IE 7]>      <html lang=\"en\" class=\"no-js lt-ie9 lt-ie8 lt-ie7\"> <![endif]-->\n<!--[if IE 7]>  "
  },
  {
    "path": "app/server/views/session/sign_up.ejs",
    "chars": 1499,
    "preview": "<!DOCTYPE html>\n<!--[if lt IE 7]>      <html lang=\"en\" class=\"no-js lt-ie9 lt-ie8 lt-ie7\"> <![endif]-->\n<!--[if IE 7]>  "
  },
  {
    "path": "app/templates/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "app/templates/directives/nw-card.html",
    "chars": 336,
    "preview": "<div class=\"card\" title=\"{{header}}\">\n\n  <img ng-src='{{image}}' ng-if='image'>\n\n  <div ng-if='icon'>\n    <i class=\"icon"
  },
  {
    "path": "app/templates/directives/nw-category-item.html",
    "chars": 475,
    "preview": "<a class=\"sort-menu-item\"\n   ng-class=\"{'active': isActive()}\"\n   ng-click=\"makeActive()\">\n\n  <i class=\"icon left {{cate"
  },
  {
    "path": "app/templates/directives/nw-category-select.html",
    "chars": 185,
    "preview": "<div class=\"sort-menu\">\n  <h2>Categories</h2>\n  <div class=\"card\">\n    <nw-category-item ng-repeat=\"category in categori"
  },
  {
    "path": "app/templates/directives/nw-page-nav-item.html",
    "chars": 96,
    "preview": "<a href=\"#/{{pageName}}\" class=\"list-item\" ng-class=\"{'active': selected() === pageName}\">\n</a>\n"
  },
  {
    "path": "app/templates/directives/nw-session.html",
    "chars": 662,
    "preview": "<div class='session'>\n  <div class=\"dropdown\" ng-if='session.id'>\n    <a class=\"dropdown-btn\">{{session.username}} <i cl"
  },
  {
    "path": "app/templates/pages/notes/edit.html",
    "chars": 1696,
    "preview": "<div class=\"new-note\">\n  <div class=\"new-note-container\">\n    <ul class='errors' ng-if=\"errors\">\n      <li ng-repeat=\"er"
  },
  {
    "path": "app/templates/pages/notes/index.html",
    "chars": 778,
    "preview": "<div class=\"note-wrapper\">\n  <div class=\"note-content\">\n    <div class=\"notes-header\">\n      <h1 title=\"Notes\">Notes</h1"
  },
  {
    "path": "app/templates/pages/notes/show.html",
    "chars": 349,
    "preview": "<div class=\"card\">\n  <h1><i class=\"{{note.icon}} icon left\"></i>{{note.header}}</h1>\n  <p>Created by: {{note.user.name |"
  },
  {
    "path": "app/templates/pages/profile/edit.html",
    "chars": 1833,
    "preview": "<div class=\"new-note\">\n  <div class=\"new-note-container\">\n    <h2>{{user.name}}</h2>\n    <i class=\"icon {{user.type}}\"><"
  },
  {
    "path": "app/templates/pages/users/index.html",
    "chars": 266,
    "preview": "<div class=\"users-wrapper\">\n  <a class=\"card-users\" ng-repeat=\"user in users | filter:search\" ng-href=\"#/users/{{user.id"
  },
  {
    "path": "app/templates/pages/users/show.html",
    "chars": 492,
    "preview": "<div class=\"card\">\n  <img ng-src='{{gravatarUrl(user)}}'/>\n  <h1 class=\"user-name\">{{user.name}}</h1>\n  <h3>Bio</h3>\n  <"
  },
  {
    "path": "app.js",
    "chars": 180,
    "preview": "var app = require(\"./app/server/modules/routes\");\n\n\n// Start the server\nvar server = app.listen(8000, function() {\n cons"
  },
  {
    "path": "dbSeed.js",
    "chars": 301,
    "preview": "// This would normally be in a grunt task or something similar and ran separately \n// when you setup the app, but it mak"
  },
  {
    "path": "inspector-config.json",
    "chars": 176,
    "preview": "// node-inspector --config ./inspector-config.json & node --debug app.js\n\n{\n  \"webPort\": 8080,\n  \"webHost\": null,\n  \"deb"
  },
  {
    "path": "npm-shrinkwrap.json",
    "chars": 72722,
    "preview": "{\n  \"name\": \"note-wrangler\",\n  \"version\": \"0.0.0\",\n  \"dependencies\": {\n    \"abbrev\": {\n      \"version\": \"1.0.7\",\n      \""
  },
  {
    "path": "package.json",
    "chars": 881,
    "preview": "{\n  \"name\": \"note-wrangler\",\n  \"private\": true,\n  \"version\": \"0.0.0\",\n  \"description\": \"A Code School Angular Production"
  }
]

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

About this extraction

This page contains the full source code of the codeschool/NoteWrangler GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 91 files (1.3 MB), approximately 354.4k tokens, and a symbol index with 299 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!