master 8b2a1caf71ce cached
212 files
563.4 KB
144.0k tokens
66 symbols
1 requests
Download .txt
Showing preview only (619K chars total). Download the full file or copy to clipboard to get everything.
Repository: stormpath/stormpath-sdk-angularjs
Branch: master
Commit: 8b2a1caf71ce
Files: 212
Total size: 563.4 KB

Directory structure:
gitextract_pr66l4um/

├── .gitignore
├── .gitmodules
├── .jshintrc
├── .npmignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Gruntfile.js
├── LICENSE
├── OLD-README.md
├── README.md
├── TROUBLESHOOTING.md
├── bower.json
├── dist/
│   ├── stormpath-sdk-angularjs.js
│   └── stormpath-sdk-angularjs.tpls.js
├── docs/
│   ├── Makefile
│   ├── render
│   └── source/
│       ├── access_control.rst
│       ├── conf.py
│       ├── configure_angular.rst
│       ├── create_new_project.rst
│       ├── create_tenant.rst
│       ├── customize_menu.rst
│       ├── index.rst
│       ├── introduction.rst
│       ├── login.rst
│       ├── password_reset.rst
│       ├── protect_api.rst
│       ├── register.rst
│       ├── support.rst
│       ├── user_profile.rst
│       └── wait_for_user.rst
├── example/
│   ├── cors-app/
│   │   ├── .bowerrc
│   │   ├── README.md
│   │   ├── bower.json
│   │   ├── client/
│   │   │   ├── client.js
│   │   │   └── index.html
│   │   ├── package.json
│   │   └── server.js
│   ├── dashboard-app/
│   │   ├── .bowerrc
│   │   ├── .buildignore
│   │   ├── .editorconfig
│   │   ├── .gitattributes
│   │   ├── .gitignore
│   │   ├── .travis.yml
│   │   ├── .yo-rc.json
│   │   ├── Gruntfile.js
│   │   ├── README.md
│   │   ├── bower.json
│   │   ├── client/
│   │   │   ├── .htaccess
│   │   │   ├── .jshintrc
│   │   │   ├── app/
│   │   │   │   ├── app.css
│   │   │   │   ├── app.js
│   │   │   │   ├── forgot/
│   │   │   │   │   ├── forgot.controller.js
│   │   │   │   │   ├── forgot.controller.spec.js
│   │   │   │   │   ├── forgot.css
│   │   │   │   │   ├── forgot.html
│   │   │   │   │   └── forgot.js
│   │   │   │   ├── login/
│   │   │   │   │   ├── login.controller.js
│   │   │   │   │   ├── login.controller.spec.js
│   │   │   │   │   ├── login.css
│   │   │   │   │   ├── login.html
│   │   │   │   │   └── login.js
│   │   │   │   ├── main/
│   │   │   │   │   ├── main.controller.js
│   │   │   │   │   ├── main.controller.spec.js
│   │   │   │   │   ├── main.css
│   │   │   │   │   ├── main.html
│   │   │   │   │   └── main.js
│   │   │   │   ├── profile/
│   │   │   │   │   ├── profile.controller.js
│   │   │   │   │   ├── profile.controller.spec.js
│   │   │   │   │   ├── profile.css
│   │   │   │   │   ├── profile.html
│   │   │   │   │   └── profile.js
│   │   │   │   ├── register/
│   │   │   │   │   ├── register.controller.js
│   │   │   │   │   ├── register.controller.spec.js
│   │   │   │   │   ├── register.css
│   │   │   │   │   ├── register.html
│   │   │   │   │   └── register.js
│   │   │   │   ├── reset/
│   │   │   │   │   ├── reset.controller.js
│   │   │   │   │   ├── reset.controller.spec.js
│   │   │   │   │   ├── reset.css
│   │   │   │   │   ├── reset.html
│   │   │   │   │   └── reset.js
│   │   │   │   └── verify/
│   │   │   │       ├── verify.controller.js
│   │   │   │       ├── verify.controller.spec.js
│   │   │   │       ├── verify.css
│   │   │   │       ├── verify.html
│   │   │   │       └── verify.js
│   │   │   ├── components/
│   │   │   │   └── navbar/
│   │   │   │       ├── navbar.controller.js
│   │   │   │       └── navbar.html
│   │   │   ├── index.html
│   │   │   └── robots.txt
│   │   ├── e2e/
│   │   │   └── main/
│   │   │       ├── main.po.js
│   │   │       └── main.spec.js
│   │   ├── karma.conf.js
│   │   ├── package.json
│   │   ├── protractor.conf.js
│   │   └── server/
│   │       ├── .jshintrc
│   │       ├── .jshintrc-spec
│   │       ├── api/
│   │       │   └── thing/
│   │       │       ├── index.js
│   │       │       ├── thing.controller.js
│   │       │       └── thing.spec.js
│   │       ├── app.js
│   │       ├── components/
│   │       │   └── errors/
│   │       │       └── index.js
│   │       ├── config/
│   │       │   ├── environment/
│   │       │   │   ├── development.js
│   │       │   │   ├── index.js
│   │       │   │   ├── production.js
│   │       │   │   └── test.js
│   │       │   ├── express.js
│   │       │   └── local.env.sample.js
│   │       ├── routes.js
│   │       └── views/
│   │           └── 404.html
│   └── ng-route-app/
│       ├── .bowerrc
│       ├── .buildignore
│       ├── .editorconfig
│       ├── .gitattributes
│       ├── .gitignore
│       ├── .travis.yml
│       ├── .yo-rc.json
│       ├── Gruntfile.js
│       ├── README.md
│       ├── bower.json
│       ├── client/
│       │   ├── .htaccess
│       │   ├── .jshintrc
│       │   ├── app/
│       │   │   ├── app.css
│       │   │   ├── app.js
│       │   │   ├── forgot/
│       │   │   │   ├── forgot.controller.js
│       │   │   │   ├── forgot.controller.spec.js
│       │   │   │   ├── forgot.css
│       │   │   │   ├── forgot.html
│       │   │   │   └── forgot.js
│       │   │   ├── login/
│       │   │   │   ├── login.controller.js
│       │   │   │   ├── login.controller.spec.js
│       │   │   │   ├── login.css
│       │   │   │   ├── login.html
│       │   │   │   └── login.js
│       │   │   ├── main/
│       │   │   │   ├── main.controller.js
│       │   │   │   ├── main.controller.spec.js
│       │   │   │   ├── main.css
│       │   │   │   ├── main.html
│       │   │   │   └── main.js
│       │   │   ├── profile/
│       │   │   │   ├── profile.controller.js
│       │   │   │   ├── profile.controller.spec.js
│       │   │   │   ├── profile.css
│       │   │   │   ├── profile.html
│       │   │   │   └── profile.js
│       │   │   ├── register/
│       │   │   │   ├── register.controller.js
│       │   │   │   ├── register.controller.spec.js
│       │   │   │   ├── register.css
│       │   │   │   ├── register.html
│       │   │   │   └── register.js
│       │   │   ├── reset/
│       │   │   │   ├── reset.controller.js
│       │   │   │   ├── reset.controller.spec.js
│       │   │   │   ├── reset.css
│       │   │   │   ├── reset.html
│       │   │   │   └── reset.js
│       │   │   └── verify/
│       │   │       ├── verify.controller.js
│       │   │       ├── verify.controller.spec.js
│       │   │       ├── verify.css
│       │   │       ├── verify.html
│       │   │       └── verify.js
│       │   ├── components/
│       │   │   └── navbar/
│       │   │       ├── navbar.controller.js
│       │   │       └── navbar.html
│       │   ├── index.html
│       │   └── robots.txt
│       ├── e2e/
│       │   └── main/
│       │       ├── main.po.js
│       │       └── main.spec.js
│       ├── karma.conf.js
│       ├── package.json
│       ├── protractor.conf.js
│       └── server/
│           ├── .jshintrc
│           ├── .jshintrc-spec
│           ├── api/
│           │   └── thing/
│           │       ├── index.js
│           │       ├── thing.controller.js
│           │       └── thing.spec.js
│           ├── app.js
│           ├── components/
│           │   └── errors/
│           │       └── index.js
│           ├── config/
│           │   ├── environment/
│           │   │   ├── development.js
│           │   │   ├── index.js
│           │   │   ├── production.js
│           │   │   └── test.js
│           │   ├── express.js
│           │   └── local.env.sample.js
│           ├── routes.js
│           └── views/
│               └── 404.html
├── index.js
├── ngdoc_assets/
│   ├── example/
│   │   └── index.ngdoc
│   ├── index.ngdoc
│   ├── nav.html
│   ├── server/
│   │   └── index.ngdoc
│   └── stormpath-angular.css
├── package.json
├── protractor.conf.js
├── src/
│   ├── module.js
│   ├── spEmailVerification.tpl.html
│   ├── spLoginForm.tpl.html
│   ├── spPasswordResetForm.tpl.html
│   ├── spPasswordResetRequestForm.tpl.html
│   ├── spRegistrationForm.tpl.html
│   ├── stormpath.auth.js
│   ├── stormpath.config.js
│   ├── stormpath.emailverification.js
│   ├── stormpath.login.js
│   ├── stormpath.oauth.js
│   ├── stormpath.passwordreset.js
│   ├── stormpath.registration.js
│   ├── stormpath.social-login.js
│   ├── stormpath.tokenStore.js
│   ├── stormpath.user.js
│   ├── stormpath.utils.js
│   └── stormpath.view-model.js
└── test/
    ├── .jshintrc
    └── protractor/
        └── login.js

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

================================================
FILE: .gitignore
================================================
node_modules
bower_components
build
.tmp
.idea


================================================
FILE: .gitmodules
================================================
[submodule "docs/source/_themes/stormpath"]
	path = docs/source/_themes/stormpath
	url = https://github.com/stormpath/stormpath-sphinx-theme.git


================================================
FILE: .jshintrc
================================================
{
  "node": true,
  "browser": true,
  "esnext": true,
  "bitwise": true,
  "camelcase": true,
  "curly": true,
  "eqeqeq": true,
  "immed": true,
  "indent": 2,
  "latedef": true,
  "newcap": true,
  "noarg": true,
  "quotmark": "single",
  "regexp": true,
  "undef": true,
  "unused": true,
  "strict": true,
  "trailing": true,
  "smarttabs": true,
  "globals": {
    "angular": false
  }
}


================================================
FILE: .npmignore
================================================
app
docs
example
ngdoc_assets
test


================================================
FILE: CHANGELOG.md
================================================
# 2.0.1

Fixed a bug in `$isCurrentDomain` that would incorrectly report a cross-domain situation in IE11.

# 2.0.0

This release adds support for the [Stormpath Client API][], which allows you to authenticate the user directly with Stormpath (authentication does not require special software in your server).  The user receives an access token, which can be used to authorize requests on your server.  If you need to authorize requests on your server, you will will want to use one of our SDKs to make that process simpler.

Please see the Readme for the new instructions for using the Client API.

## Breaking Changes

Social Login now requires the use of the Client API, you will need to enable the Client API for your Stormpath Application.  This can be found under the Policies section of the application in our Admin Console.

# 1.1.1

Our UI Router integration will now look for `data.authorities` on UI state configuration, and apply the same behavior as `sp.authorize.group`.  This is a convenience for [JHipster](https://jhipster.github.io/) users, as they
already use `data.authorities` to declare the roles that a user must have in order to access a view.

# 1.1.0

* The `$user.get()` method now takes a boolean `bypassCache` option, e.g. `$user.get(true)` will make a new request of the `/me` endpoint, instead of returning the user data that was already cached on login.

* Logout requests (which makes a POST to `/logout` on our framework integration) are now using `Content-Type: application/x-www-form-urlencoded`, in order to prevent an un-necessary OPTIONS request.

* Fixed #151, an un-intended catching of error responses on all HTTP responses. Now we only handle error responses that come from our known framework endpoints.

# 1.0.0

This version needs at least version `3.0.0` of [express-stormpath](https://github.com/stormpath/express-stormpath).

* Added support for the registration view model ([#119](https://github.com/stormpath/stormpath-sdk-angularjs/pull/119))

  This allows you to customize the registration form using the Stormpath Express configuration: <https://docs.stormpath.com/nodejs/express/latest/registration.html#creating-custom-fields>

* Added support for the login view model ([#118](https://github.com/stormpath/stormpath-sdk-angularjs/pull/118))

  This allows you to customize the login form using the Stormpath Express configuration: <https://docs.stormpath.com/nodejs/express/latest/login.html#form-customization>

* Changed logout request to use POST ([#117](https://github.com/stormpath/stormpath-sdk-angularjs/pull/117))
* Added support for new error structure ([#114](https://github.com/stormpath/stormpath-sdk-angularjs/pull/114))
* Added X-Stormpath-Agent header to requests ([#107](https://github.com/stormpath/stormpath-sdk-angularjs/pull/107))

# 0.9.0

* Adding support for ngRoute.  Please see the API Documentation and the new
  `ng-route-app` in the examples folder!

* Bug fixed: you could navigate to the login form, even when logged in.

* Updating `express-stormpath` versions in example projects.

# 0.8.2

* Bug fixed: `stormpath-sdk-angularjs` now exports 'stormpath' instead of 'ui.router'

# 0.8.1

* Fixed bug that displayed social login titles without any social login providers
* Updated grunt-html2js to version 0.3.5
* Updated grunt-contrib-clean to version 0.7.0
* Updated grunt-contrib-uglify to version 0.10.1
* Removed dist folder from the ignored file so we can use this lib with webpack or browserify

# 0.8.0

* Added support for social login with Google and Facebook (requires use of
  [Express-Stormpath][] as your backend)

# 0.7.2

**Released on October 26th, 2015**

* Updating `grunt-contrib` dependencies

# 0.7.1

**Released on October 8th, 2015**

Fixed the [ifUserInGroup][] and [ifUserNotInGroup][] directives to expect the
new data format (expanded `account.groups`) from the `/me` route

# 0.7.0

### ! ** Many Breaking Changes ** !

This library has been upgraded to conform to our framework specification,
this means that many of the endpoints and default URLs have changed.

If you have built a server integration by hand, you will need to read this changelog
to know which URLs and HTTP responses that you will need to change.

If you are using [Stormpath Express SDK][], that module is being deprecated. You
will need to start using [Express-Stormpath][] if you want to use this and
future versions of this Angular SDK.  We suggest that you read the [Server
Configuration][] section of our [Yeoman Guide][], it will show you the new way
of initializing [Express-Stormpath][] and attaching it to your application

#### Login Changes

The login feature now uses `/login` as the location where posts the login
form.  Previously this was `/oauth/token`.  This can be configured with the
`AUTHENTICATION_ENDPOINT` property in `STORMPATH_CONFIG`

#### User Context Changes

This SDK now uses the `/me` URL to determine the context of the current user.
Previously this was `/api/users/current`.  This can be configured with the
`CURRENT_USER_URI` property in `STORMPATH_CONFIG`

#### Email Verification Changes

This SDK now uses the `/verify` URL to consume email verification tokens.
Previously this was `/api/emailVerificationTokens`.  This can be configured with the
`EMAIL_VERIFICATION_ENDPOINT` property in `STORMPATH_CONFIG`

The same URL, `/verify`, is now used to request a re-send of a verification email.
POST a JSON body with an `email` property to trigger this action.  Previously
this was `/api/verificationEmails` and the `RESEND_EMAIL_VERIFICATION_ENDPOINT`
property has been removed from `STORMPATH_CONFIG`.

#### Password Reset Changes

This SDK now uses `/forgot` to request a password reset email, POST a JSON body
to this endpoint with an `email` property to trigger this action.  Previously
this was `/api/passwordResetTokens` and the
`PASSWORD_RESET_TOKEN_COLLECTION_ENDPOINT` property has been removed from
`STORMPATH_CONFIG`.  The new property is `FORGOT_PASSWORD_ENDPOINT`

The `/change` URL is now used to POST a new password, with a valid `sptoken`.
Previously this feature was supported with the `/api/passwordResetTokens` URL
and the `PASSWORD_RESET_TOKEN_COLLECTION_ENDPOINT` property has been removed
from `STORMPATH_CONFIG`.  The new property is `CHANGE_PASSWORD_ENDPOINT`

The default login form now links to the forgot password flow via an href link
to `/forgot`. Previously it was using a UI Router state name of
`passwordResetRequest`

#### Registration Changes

The SDK now uses `/register` to POST data for a new account, previously this
was `/api/users` and the `USER_COLLECTION_URI` property has been removed from
`STORMPATH_CONFIG`.  The new property is `REGISTER_URI`.

The callback for `$user.create()` will now give you the entire account object.
Previously it gave you a truthy value that would indicate if the account required
email verification.  Now that the entire account object is passed, you need to
inspect the account object's `status` property to see if it is `UNVERIFIED`.

If your registration form is passing data for the new account's custom data
object, you will need to change your `ng-model` references from
`formModel.customData.<FIELD>` to `formModel.<FIELD>`.  We will automaticaly
find the properties that are not part of the base account object, and place them
on the custom data object for you.

#### Error responses

This SDK now expects any HTTP call which results in a `4xx` error to supply an
`error` property on the JSON body of the response.  Previously it expected
an `errorMessage` property


# 0.6.0

### Breaking Changes

Stormpath's password reset API accepts email address only,
not username.  This library was allowing a username to be
sent, but that will not work.  If using the [Stormpath Express SDK]
you will also need to update that library to `>=0.5.0`

# 0.5.5

Fix a redirect loop in the state change interceptor

# 0.5.4

Fix an undefined attribute bug with the group membership directives

# 0.5.3

Adding social login support.  **NOTE**: this is overloading oauth grant_type,
and we will change this API in the future so use with this disclaimer.

### Bug Fixes

# 0.5.2

### Improvements

* Remove un-used `$cookieStore` dependency

### Bug Fixes

* The config option FORM_CONTENT_TYPE was not being used to modify
  the body of the request (only the content-type header)

# 0.5.1

### Bug Fixes

The `defaultPostLoginState` option was not being used by the SDK, but now it is!

# 0.5.0

### New Features

XHR requests now set the `withCredentials` option to `true`, allowing you to
make cross-domain requests that will send the `access_token` and `XSRF-TOKEN`
cookies.  Your server must respond with the necessary
[Cross-Origin-Resource-Sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) headers.
If you are using our Express SDK this is done by specifying
[Allowed Origins on spConfig](https://github.com/stormpath/stormpath-sdk-express#allowedOrigins)

# 0.4.1

### New Features

The UI Router integration now accepts a `forbiddenState` option, this is the
state we will send the user to if they are unauthorized for a given state.
This is useful if you want to show a default "Forbidden" view in these
situations.

Added documentation for the [$stateChangeUnauthenticated] and
[$stateChangeUnauthorized] events!

# 0.4.0

### Breaking Changes

The [ifUserInGroup] and [ifUserNotInGroup] directives now requires you to pass
either a string expression or a reference to a scope variable.  I.E. this will
now throw a parse exception unless `admin` is a reference to a scope property:

```html
<div if-user-in-group="admin">Hello, Administrator</div>
```

It should be re-written to be a string expression with quotes:

```html
<div if-user-in-group="'admin'">Hello, Administrator</div>
```

## New Features

The [ifUserInGroup] and [ifUserNotInGroup] directives now support regular
expressions :)

See the documentation of [ifUserInGroup] for more information

# 0.3.0

### Breaking Changes

* The `logout` directive is renamed to
[`spLogout`](https://docs.stormpath.com/angularjs/sdk/#/api/stormpath.spLogout:spLogout)

* The registration form now uses property names of
`givenName` and `surname`, instead of `firstName` and `lastName`

* Form submissions now use `application/x-www-form-urlencoded` as the Content Type.
Your server needs to negotiate this type, if you are using our server SDKs this happens
for you.  If you wish to continue using `application/json` as the Content
Type you can define `STORMPATH_CONFIG.FORM_CONTENT_TYPE='application/json'` in a
config block

## Deprecation Notices

* [`whileResolvingUser`](https://docs.stormpath.com/angularjs/sdk/#/api/stormpath.whileResolvingUser:while-resolving-user)
is deprecatead.  Use
[`ifUserStateKnown`](https://docs.stormpath.com/angularjs/sdk/#/api/stormpath.ifUserStateKnown:ifUserStateKnown)
instead.

### New Features

* **Custom Data on Registration**.  You can now pass custom data during
registration, simply reference `formModel.customData.myCustomProperty` in your
`ng-model` directive.  This is only possible if you are supplying a custom
template to the directive.  See the
[`spRegistrationForm`](https://docs.stormpath.com/angularjs/sdk/#/api/stormpath.spRegistrationForm:spRegistrationForm)
directive for more detail.

* **Group-Based Access Control**.  This can now control access to UI Routes,
based on group membership.  See
[`SpStateConfig`](https://docs.stormpath.com/angularjs/sdk/#/api/stormpath.SpStateConfig:SpStateConfig)
for examples.  We've also introduced the
[`ifUserInGroup`](https://docs.stormpath.com/angularjs/sdk/#/api/stormpath.ifUserInGroup:ifUserInGroup)
and
[`ifUserNotInGroup`](https://docs.stormpath.com/angularjs/sdk/#/api/stormpath.ifUserNotInGroup:ifUserNotInGroup)
directives.

### Bug Fixes

* [`whileResolvingUser`](https://docs.stormpath.com/angularjs/sdk/#/api/stormpath.whileResolvingUser:while-resolving-user)
would break after logout (user state was not properly reflected after logout)

[Stormpath Express SDK]: https://github.com/stormpath/stormpath-sdk-express
[$stateChangeUnauthenticated]: https://docs.stormpath.com/angularjs/sdk/#/api/stormpath.$stormpath#events_$statechangeunauthenticated
[$stateChangeUnauthorized]: https://docs.stormpath.com/angularjs/sdk/#/api/stormpath.$stormpath#events_$statechangeunauthorized
[ifUserInGroup]: https://docs.stormpath.com/angularjs/sdk/#/api/stormpath.ifUserInGroup:ifUserInGroup
[ifUserNotInGroup]: https://docs.stormpath.com/angularjs/sdk/#/api/stormpath.ifUserNotInGroup:ifUserNotInGroup
[Express-Stormpath]: https://github.com/stormpath/express-stormpath
[Server Configuration]: http://docs.stormpath.com/angularjs/guide/protect_api.html
[Yeoman Guide]: http://docs.stormpath.com/angularjs/guide/
[Stormpath Client API]: https://docs.stormpath.com/client-api/product-guide/latest/index.html

================================================
FILE: CONTRIBUTING.md
================================================
# Contribution Guide

We love pull requests!

Here are a few things you'll need to know if you want to make a contribution to
this library.

### Development Workflow

All modifications should happen to the source files in the `src/` directory, not
the files minified in the `dist/` directory.  The latter is used for keeping a
minified version of the current, tagged build.  We give this to
[Bower](http://bower.io).

You can submit a PR after modifying the source files.  We will publish a new
version in `dist/` when we are ready to cut a new release.

### API Documentation

The API documentation is auto-generated from the the JS-Doc style comments
that you find in the `src/` files.  Do not edit files in `dist/`.

You can regenerate the API docs by running `grunt docs`.  If you want to
see your changes as you edit them you can use `grunt serve` to start a
livereload server that will reload your changes as you make them.

When editing the JS Doc comments, please follow this order for tags:

```
@ngdoc
@name
@methodOf (or eventOf, etc)
@eventType (if applicable)
@param
@returns
@description
@example
```

After you have made your edits, commit your changes and make a pull request.

And put a newline before and after the line that includes the tag.

### Product Guide Documentation

The source files for the product guide are located in the `docs/source`
directory.  The format is RST and they are compiled by Sphinx.

To work with the product guide, run `grunt guide`.  This will start a livereload
server which reloads the documents as you edit them.

After you have made your edits, commit the changes to the RST files and make
a pull request.

================================================
FILE: Gruntfile.js
================================================
// Generated on 2015-01-02 using generator-angular-fullstack 2.0.13
'use strict';

module.exports = function (grunt) {
  // Load grunt tasks automatically
  require('load-grunt-tasks')(grunt);


  grunt.initConfig({
    builddir: '.tmp/build',
    tmpdir: '.tmp',
    srcDir: './src',
    src: '<%= srcDir %>/**/*.js',
    pkg: grunt.file.readJSON('package.json'),
    buildtag: '-dev-' + grunt.template.today('yyyy-mm-dd'),
    meta: {
      banner: '/**\n' +
        ' * <%= pkg.name %>\n' +
        ' * Copyright <%= pkg.author %> '+grunt.template.today('yyyy')+'\n' +
        ' * <%= pkg.description %>\n' +
        ' * @version v<%= pkg.version %><%= buildtag %>\n' +
        ' * @link <%= pkg.homepage %>\n' +
        ' * @license <%= pkg.license %>\n' +
        ' */'
    },
    clean: {
      ngdocs: '<%= tmpdir %>/site/**/*'
    },
    replace: {
      dist: {
        options: {
          patterns: [
            {
              match: 'PACKAGE_VERSION',
              replacement: '<%= pkg.version %>'
            },
            {
              match: 'PACKAGE_NAME',
              replacement: '<%= pkg.name %>'
            }
          ]
        },
        files: [
          {expand: true, flatten: true, src: ['<%= builddir %>/<%= pkg.name %>*.js'], dest: '<%= builddir %>'}
        ]
      }
    },
    concat: {
      options: {
        banner: '<%= meta.banner %>\n\n'+
                '/* commonjs package manager support (eg componentjs) */\n'+
                'if (typeof module !== "undefined" && typeof exports !== "undefined" && module.exports === exports){\n'+
                '  module.exports = \'stormpath\';\n'+
                '}\n\n'+
                '(function (window, angular, undefined) {\n',
        footer: '})(window, window.angular);'
      },
      build: {
        src: '<%= src %>',
        dest: '<%= builddir %>/<%= pkg.name %>.js'
      }
    },
    uglify: {
      options: {
        banner: '<%= meta.banner %>\n'
      },
      build: {
        files: {
          '<%= builddir %>/<%= pkg.name %>.min.js': ['<banner:meta.banner>', '<%= concat.build.dest %>'],
          '<%= builddir %>/<%= pkg.name %>.tpls.min.js': ['<banner:meta.banner>', '<%= builddir %>/<%= pkg.name %>.tpls.js']
        }
      }
    },
    release: {
      files: ['<%= pkg.name %>.js', '<%= pkg.name %>.min.js'],
      src: '<%= builddir %>',
      dest: 'release'
    },
    jshint: {
      all: ['Gruntfile.js', 'src/*.js', '<%= builddir %>/<%= pkg.name %>.js'],
      options: {
        eqnull: true
      }
    },
    watch: {
      gruntfile: {
        files: ['Gruntfile.js']
      },
      ngdocs: {
        files: ['<%= src %>','ngdoc_assets/**/*'],
        tasks: ['docs'],
        options: {
          livereload: 35730,
          spawn: false
        }
      },
      guide: {
        files: ['docs/source/*.rst','docs/source/_themes/stormpath/*/**'],
        tasks: ['shell:guide'],
        options: {
          livereload: 35731,
          spawn: false
        }
      },
      src: {
        files: ['<%= src %>'],
        tasks: ['build']
      },
      develop: {
        files: ['<%= srcDir %>/*.{js,html}'],
        tasks: ['dist']
      }
    },
    connect: {
      ngdocs: {
        options: {
          port: 9001,
          base: '<%= tmpdir %>/site',
          livereload: 35730
        }
      },
      guide: {
        options: {
          port: 9002,
          livereload: 35731,
          base: ['docs/build/html']
        }
      }
    },
    open: {
      docs: {
        url: 'http://localhost:<%= connect.ngdocs.options.port %>'
      },
      guide:{
        url: 'http://localhost:<%= connect.guide.options.port %>'
      }
    },
    ngdocs: {
      options: {
        dest: '<%= tmpdir %>/site',
        scripts: [
          'angular.js'
        ],
        styles: [ 'ngdoc_assets/stormpath-angular.css' ],
        html5Mode: false,
        title: 'stormpath-sdk-angularjs',
        startPage: '/api',
        navTemplate: 'ngdoc_assets/nav.html'
      },
      api: {
        src: ['<%= src %>','ngdoc_assets/index.ngdoc'],
        title: 'API Reference',
        api: true
      }
    },
    copy: {
      dist: {
        files:[{
          expand: true,
          flatten: true,
          src: '<%= builddir %>/*',
          dest: 'dist/'
        }]
      }
    },
    html2js: {
      options: {
        module: 'stormpath.templates',
        fileHeaderString: '<%= meta.banner %>\n\n'+
                          '/* commonjs package manager support (eg componentjs) */\n'+
                          'if (typeof module !== "undefined" && typeof exports !== "undefined" && module.exports === exports){\n'+
                          '  module.exports = \'stormpath.templates\';\n'+
                          '}\n\n'+
                          '(function (window, angular, undefined) {\n',
        fileFooterString: '})(window, window.angular);',
        htmlmin: {
          collapseBooleanAttributes: false,
          collapseWhitespace: true,
          removeAttributeQuotes: true,
          removeComments: true,
          removeEmptyAttributes: false,
          removeRedundantAttributes: true,
          removeScriptTypeAttributes: false,
          removeStyleLinkTypeAttributes: false
        }
      },
      main: {
        src: ['src/**/*.tpl.html'],
        dest: '<%= builddir %>/<%= pkg.name %>.tpls.js'
      }
    },
    shell: {
      guide: {
        command: 'make clean && make html',
        options:{
          execOptions: {
            cwd: 'docs/'
          }
        }
      }
    }
  });

  grunt.registerTask('docs', 'Builds the Guide and ngDocs for deployment',function () {
    grunt.task.run(
      ['clean:ngdocs','ngdocs','shell:guide']
    );
  });

  grunt.registerTask('serve',
    'Serves the API documentation, and live reloads as you edit it',
    ['ngdocs','connect:ngdocs','open:docs','watch:ngdocs']
  );

  grunt.registerTask('build', 'Perform a normal build', ['concat', 'html2js','uglify','docs']);

  grunt.registerTask('dist', 'Perform a distribution', ['build', 'replace:dist', 'copy:dist']);

  grunt.registerTask('develop',
    'Build source and distribution, useful if you are modifying this module as a linked modue while developging another module',
    ['watch:develop']
  );

  grunt.registerTask('guide',
    'Serve and livereload the Guide from the docs/ folder',
    ['connect:guide','open:guide','watch:guide']
  );
};


================================================
FILE: LICENSE
================================================


                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright 2015 Stormpath, Inc.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: OLD-README.md
================================================
# Stormpath is Joining Okta
We are incredibly excited to announce that [Stormpath is joining forces with Okta](https://stormpath.com/blog/stormpaths-new-path?utm_source=github&utm_medium=readme&utm-campaign=okta-announcement). Please visit [the Migration FAQs](https://stormpath.com/oktaplusstormpath?utm_source=github&utm_medium=readme&utm-campaign=okta-announcement) for a detailed look at what this means for Stormpath users.

We're available to answer all questions at [support@stormpath.com](mailto:support@stormpath.com).

# Stormpath AngularJS SDK

[![NPM Version](https://img.shields.io/npm/v/stormpath-sdk-angularjs.svg?style=flat)](https://npmjs.org/package/stormpath-sdk-angularjs)
[![NPM Downloads](http://img.shields.io/npm/dm/stormpath-sdk-angularjs.svg?style=flat)](https://npmjs.org/package/stormpath-sdk-angularjs)
[![Bower Version](https://img.shields.io/bower/v/stormpath-sdk-angularjs.svg?style=flat)](https://bower.io)
[![Build Status](https://img.shields.io/travis/stormpath/stormpath-sdk-angularjs.svg?style=flat)](https://travis-ci.org/stormpath/stormpath-sdk-angularjs)

This module provides services and directives for AngularJS that will allow you to solve common user management tasks using [Stormpath](https://stormpath.com/), such as *login* and *signup*.

*Stormpath is a User Management API that reduces development time with instant-on, scalable user infrastructure. Stormpath's intuitive API and expert support make it easy for developers to authenticate, manage and secure users and roles in any application.*

* [Getting Started](#getting-started)
* [Documentation](#documentation)
* [Example](#example)
* [Help](#help)
* [Contributing](#contributing)
* [License](#license)

## Getting Started

Follow these steps to add Stormpath user authentication to your AngularJS app.

1. **Install or Download the Stormpath Angular SDK**

  If you are using Bower or NPM, you can install this module with the respective command:

  ```
  npm install stormpath-sdk-angularjs --save
  ```

  ```
  bower install stormpath-sdk-angularjs --save
  ```

  If you are not using a package manager, you can download the latest source from our Github CDN by using these links:

  * [stormpath-sdk-angularjs.min.js](https://raw.githubusercontent.com/stormpath/stormpath-sdk-angularjs/master/dist/stormpath-sdk-angularjs.min.js)
  * [stormpath-sdk-angularjs.tpls.min.js](https://raw.githubusercontent.com/stormpath/stormpath-sdk-angularjs/master/dist/stormpath-sdk-angularjs.tpls.min.js)

  Then include them in your *index.html* file:

  ```html
  <script src="stormpath-sdk-angularjs.min.js"></script>
  <script src="stormpath-sdk-angularjs.tpls.min.js"></script>
  ```

2. **Add the Module to Your App's Dependencies**

  Add the `stormpath` module and templates to your app's dependencies in *app.js*:

  ```javascript
  var app = angular.module('myApp', [..., 'stormpath', 'stormpath.templates']);
  ```

3. **Configure Stormpath**

  The Angular SDK leverages the [Stormpath Client API][] for its authentication needs. Login to your Stormpath Tenant, and find your Client API domain (inside your application's policy section).  Add your Client API domain as the `ENDPOINT_PREFIX` setting, via your `.config()` function:

  ```javascript
  angular.module('myApp', [..., 'stormpath', 'stormpath.templates'])
    .config(function (STORMPATH_CONFIG) {

      // Specify your Client API domain here:

      STORMPATH_CONFIG.ENDPOINT_PREFIX = 'https://{{clientApiDomainName}}';
    });
  ```
  You will need to tell Stormpath where your front-end application is running, by adding its domain to the list of Authorized Origin URIs on your Stormpath Application. This can be done from the Stormpath Admin Console. For example, if you are developing on a local sever that runs your front-end app at `http://localhost:3000`, you need to add that URI to the list

  If this is not done, you will see the error `Origin 'http://localhost:3000' is therefore not allowed access.` in the browser error log.

  If you will be using social login, you will also need to add this URI to the list of Authorized Callback URIs, otherwise you will see the error `Specified redirect_uri is not in the application's configured authorized callback uri's.` when you attempt social login.


4. **Configure Routing**

  In your app's `run()` block, configure the login state and the default state after login.

  For `ngRouter`:

  ```javascript
  angular.module('myApp')
    .run(function($stormpath){
      $stormpath.ngRouter({
        forbiddenRoute: '/forbidden',
        defaultPostLoginRoute: '/home',
        loginRoute: '/login'
      });
    });
  ```

  For `uiRouter`:

  ```javascript
  app.run(function($stormpath){
    $stormpath.uiRouter({
      loginState: 'login',
      defaultPostLoginState: 'home'
    });
  });
  ```

  Set `loginState` to your login state. If you don't have one, create one.
  Set `defaultPostLoginState` to your default state after login.



5. **Insert the Login and Registration Forms**

   You can use the [`sp-login-form`][] and [`sp-registration-form`][] directives to inject these default forms into your application, you should put this in the views/states where you want them to appear:

   ```html
   <div sp-login-form></div>
   ```

   ```html
   <div sp-registration-form></div>
   ```

    </p>
    These forms will read their configuration from the Client API and allow you to login or register for your application.
    You should now be able to use these forms to login to your application.

6. **Add Login and Logout Links**

  Use the [`sp-logout`][] directive to end the session:

  ```html
  <a ui-sref="main" sp-logout>Logout</a>
  ```

  For the login link, just point the user to your login state:

  ```html
  <a ui-sref="login">Login</a>
  ```

7. **Hide Elements When Logged In**

  Use the [`if-user`][] directive:

  ```html
  <a ui-sref="main" sp-logout if-user>Logout</a>
  ```

8. **Hide Elements When Logged Out**

  Use the [`if-not-user`][] directive:

  ```html
  <a ui-sref="login" if-not-user>Login</a>
  ```

9. **Protect Your States**

  On all states that you want to protect, add:

  ```javascript
  sp: {
    authenticate: true
  }
  ```

  For `ngRouter`:

  ```javascript
  angular.module('myApp')
    .config(function ($routeProvider) {
      $routeProvider
        .when('/profile', {
          templateUrl: 'app/profile/profile.html',
          controller: 'ProfileCtrl',
          sp: {
            authenticate: true
          }
        });
    });
  ```

  For `uiRouter`:

  ```javascript
  angular.module('myApp')
    .config(function ($stateProvider) {
      $stateProvider
        .state('profile', {
          url: '/profile',
          templateUrl: 'app/profile/profile.html',
          controller: 'ProfileCtrl',
          sp: {
            authenticate: true
          }
        });
    });
  ```


10. **Login!**

  That's it!  You just added user authentication to your app with Stormpath. See the [API Documentation][] for further information on how Stormpath can be used with your AngularJS app.

  Looking for social login?  Simply configure the directories in your Stormpath tenant, and the buttons will automatically appear in the login form.  For more reading, please see the [Social Login Product Guide][].

11. **Making Authenticated Requests**

  Once you are able to successfully authenticate (log in) from your application, you will want to authorize access to API endpoints on your server.  The Angular SDK provides methods for getting the current authenticated access token, and using it to authenticate requests.

  Imagine you have an API on your server, such as `http://localhost:3000/api/subscription`, and you want to authorize requests to this endpoint and know who the user is.

  If you want to manually construct a request, using the `$http` library, you can use our access token getter to add the access token to the request:

  ```javascript
  StormpathOAuthToken.getAccessToken()
    .then(function(accessToken){
      $http({
        url: 'http://localhost:3000/api/subscription',
        method: 'GET',
        headers: {
          Authorization: 'Bearer ' + accessToken
        }
      });
    })
    .catch(function() {
      // No access token, the user is not logged in
    });
  ```

  If you don't want to manually add the access token to every request, you can white-list URLs by expression and the Angular SDK will automatically add this token to all requests that have a matching URL:

  ```javascript
  angular.module('myApp', [..., 'stormpath', 'stormpath.templates'])
    .config(function (STORMPATH_CONFIG) {

      // Automatically add access token to all /api requests

      STORMPATH_CONFIG.AUTO_AUTHORIZED_URIS.push(new RegExp('/api'));
    });
  ```

12. **Authorizing Requests Server-Side**

  Once your app has made the request with the access token, your server will need to read the token and make an authorization decision.  We provide SDKs for your backend server that make this easy.  Please follow one of the following links for a language-specific or framework-specific guide:

  **Java**

  Spring Boot developers should make use of our Spring Boot plugin, and see the [Token Management Documentation](https://docs.stormpath.com/java/spring-boot-web/tutorial.html#token-management).

  **.NET**

  ASP.NET developers can leverage our [ASP.NET](https://docs.stormpath.com/dotnet/aspnet/latest/) and [ASP.NET Core](https://docs.stormpath.com/dotnet/aspnetcore/latest/) libraries to achieve authorization in their applications, please see the Authorization section of each guide.

  **Node.js**

  Express developers can use our [Express-Stormpath](https://docs.stormpath.com/nodejs/express/latest/) library to easily authenticate requests with access tokens and make authorization decisions, please see the [Token Authentication](https://docs.stormpath.com/nodejs/express/latest/authentication.html#token-authentication) documentation.

  Node applications can generically use the [Stormpath Node SDK](https://docs.stormpath.com/nodejs/jsdoc/) to validate tokens, using the [JwtAuthenticator](https://docs.stormpath.com/nodejs/jsdoc/JwtAuthenticator.html).

  **PHP**

  Laravel developers can use our <a href="https://docs.stormpath.com/php/laravel/latest/index.html">Stormpath-Laravel</a> or [Stormpath-Lumen](https://docs.stormpath.com/php/lumen/latest/index.html) libraries and their respective `stormpath.auth` middleware to authenticate requests, please see the User Data section of the documentation for each library.

  **Other**

  Don't see your environment listed?  Not a problem!  Our access tokens are simple JWTs, that can be validated with most generic JWT validation libraries.  Our product guide can walk you through the process, [Validating an Access Token](https://docs.stormpath.com/rest/product-guide/latest/auth_n.html#validating-an-access-token").

  Need more assistance? Feel free to contact our support channel, details are below.

## Documentation

For all available directives and services, see the [API Documentation][].

## Example

See the [example app][] in this repository for an example application that uses
Yeoman as it's boilerplate.

For a simplified example that does not use a boilerplate system, please see
this repository:

[Stormpath Angular + Express Fullstack Sample Project](https://github.com/stormpath/express-stormpath-angular-sample-project)

If you are hosting your API on a different domain than your Angular application,
please see the [CORS example app][] in this repository.

## Browserify

This module can be used with Browserify.  Please add the following lines to your
`package.json` file:

```json
"browser": {
  "stormpath": "./node_modules/stormpath-sdk-angularjs/dist/stormpath-sdk-angularjs.js",
  "stormpath.templates": "./node_modules/stormpath-sdk-angularjs/dist/stormpath-sdk-angularjs.tpls.js"
}
```

You should also install the package `angular-ui-router`, as our library
currently depends on it.

Then in your application you can use `require` to require our modules:

```javascript
var app = angular.module('todoApp', [
  require('angular-ui-router'),
  require('stormpath'),
  require('stormpath.templates')
]);
```

## Support

We're here to help if you get stuck.  There are several ways that you an get in
touch with a member of our team:

* Send an email to [support@stormpath.com](mailto:support@stormpath.com)
* Open a Github Issue on this repository.
* Join us on our Slack channel: [https://talkstormpath.shipit.xyz/](https://talkstormpath.shipit.xyz/)

[Stormpath AngularJS SDK]: https://github.com/stormpath/stormpath-sdk-angularjs
[Stormpath Product Guide]: https://docs.stormpath.com/rest/product-guide/latest/
[Stormpath React SDK]: https://github.com/stormpath/stormpath-sdk-react
[express-stormpath]: https://docs.stormpath.com/nodejs/express/latest/

## Contributing

Found something you want to change? Please see the [Contribution Guide](CONTRIBUTING.md),
we love your input!

## License

Apache 2.0, see [LICENSE](LICENSE).

[`if-user`]: https://docs.stormpath.com/angularjs/sdk/#/api/stormpath.ifUser:ifUser
[`if-not-user`]: https://docs.stormpath.com/angularjs/sdk/#/api/stormpath.ifNotUser:ifNotUser
[`sp-login-form`]: https://docs.stormpath.com/angularjs/sdk/#/api/stormpath.spLoginForm:spLoginForm
[`sp-logout`]: https://docs.stormpath.com/angularjs/sdk/#/api/stormpath.spLogout:spLogout
[`sp-registration-form`]: https://docs.stormpath.com/angularjs/sdk/#/api/stormpath.spRegistrationForm:spRegistrationForm
[example app]: https://github.com/stormpath/stormpath-sdk-angularjs/tree/master/example/dashboard-app
[API Documentation]: https://docs.stormpath.com/angularjs/sdk/
[Server Integration Guide]: https://docs.stormpath.com/angularjs/sdk/#/server
[express-stormpath]: https://github.com/stormpath/express-stormpath
[Stormpath SPA Development Server]: https://github.com/stormpath/stormpath-spa-dev-server
[UI-Router]: https://github.com/angular-ui/ui-router
[Yeoman Guide]: https://docs.stormpath.com/angularjs/guide
[support center]: https://support.stormpath.com
[CORS example app]: https://github.com/stormpath/stormpath-sdk-angularjs/tree/master/example/cors-app
[Stormpath Client API]: https://docs.stormpath.com/client-api/product-guide/latest/index.html
[Social Login Product Guide]: https://docs.stormpath.com/rest/product-guide/latest/auth_n.html#how-social-authentication-works


================================================
FILE: README.md
================================================
# Stormpath is Joining Okta
We are incredibly excited to announce that [Stormpath is joining forces with Okta](https://stormpath.com/blog/stormpaths-new-path?utm_source=github&utm_medium=readme&utm-campaign=okta-announcement). Please visit [the Migration FAQs](https://stormpath.com/oktaplusstormpath?utm_source=github&utm_medium=readme&utm-campaign=okta-announcement) for a detailed look at what this means for Stormpath users.

We're available to answer all questions at [support@stormpath.com](mailto:support@stormpath.com).

## What does this mean for developers who are using this library?

* If you have upgraded to the 2.x series from 1.x, you should downgrade to 1.1.1.  Why?  The 2.x series depends on the Stormpath Client API, which will not be migrated to the Okta platform.
* When downgrading to 1.1.1 you will need to use one of our backend framework integrations to serve the APIs that the 1.x series depends on.
* These backend integrations are being patched to work with Okta:
 - [Java Spring](https://docs.stormpath.com/java/#tab3)
 - [Java Spring Boot](https://docs.stormpath.com/java/#tab1)
 - [Node Express](https://docs.stormpath.com/nodejs/)
 - [ASP.NET 4.x](https://docs.stormpath.com/dotnet/#tab3)
 - [ASP.NET Core](https://docs.stormpath.com/dotnet/#tab2)
* If you are using the Express integration, please see the [Express-Stormpath Angular Sample Project][], it can be used to test your migration to Okta.

# README

If you are actively using this library, you can find the old readme in [OLD-README.md](OLD-README.md). It is not possible to register for new Stormpath tenants at this time, so you must already have a Stormpath tenant if you wish to use this library during the migration period.

[Express-Stormpath Angular Sample Project]: https://github.com/stormpath/express-stormpath-angular-sample-project


================================================
FILE: TROUBLESHOOTING.md
================================================
# Troubleshooting

This document contains a list of common problems that you may run into while
working with this library.

#### "Invalid username or password." when using Social Login

If you are using [express-stormpath][] as your back-end you may see this error
when attempting a social login.  This happens if the Body Parser module is
configured before the Express Stormpath module.  If you must do this, please
ensure that you are enabling the extended option for the parser:

```javascript
app.use(bodyParser.urlencoded({ extended: true }));
```

This issue is being tracked here:

https://github.com/stormpath/express-stormpath/issues/194

[express-stormpath]: https://github.com/stormpath/express-stormpath

================================================
FILE: bower.json
================================================
{
  "name": "stormpath-sdk-angularjs",
  "version": "2.0.1",
  "main": [
    "dist/stormpath-sdk-angularjs.min.js",
    "dist/stormpath-sdk-angularjs.tpls.min.js"
  ],
  "keywords": [
    "stormpath",
    "jwt",
    "token",
    "user",
    "angular",
    "token based authentication",
    "login",
    "password",
    "registration",
    "user management"
  ],
  "ignore": [
    ".tmp",
    "build",
    "docs",
    "example",
    "ngdoc_assets",
    "src"
  ],
  "dependencies": {
    "angular": ">=1.2.*"
  }
}


================================================
FILE: dist/stormpath-sdk-angularjs.js
================================================
/**
 * stormpath-sdk-angularjs
 * Copyright Stormpath, Inc. 2017
 * 
 * @version v2.0.1-dev-2017-04-04
 * @link https://github.com/stormpath/stormpath-sdk-angularjs
 * @license Apache-2.0
 */

/* commonjs package manager support (eg componentjs) */
if (typeof module !== "undefined" && typeof exports !== "undefined" && module.exports === exports){
  module.exports = 'stormpath';
}

(function (window, angular, undefined) {
'use strict';

/**
 * @ngdoc object
 *
 * @name stormpath.SpStateConfig:SpStateConfig
 *
 * @property {boolean} authenticate
 *
 * If `true`, the user must be authenticated in order to view this state.
 * If the user is not authenticated, they will
 * be redirected to the `login` state.  After they login, they will be redirected to
 * the state that was originally requested.
 *
 * @property {object} authorize
 *
 * An object that defines access control rules.  Currently, it supports a group-based
 * check.  See the example below.
 *
 * @property {boolean} waitForUser
 *
 * If `true`, delay the state transition until we know
 * if the user is authenticated or not.  This is useful for situations where
 * you want everyone to see this state, but the state may look different
 * depending on the user's authentication state.
 *
 *
 * @description
 *
 * The Stormpath State Config is an object that you can define on a UI Router
 * state.  Use this configuration to define access control for your routes, as
 * defined by UI Router.
 *
 * You will need to be using the UI Router module, and you need
 * to enable the integration by calling
 * {@link stormpath.$stormpath#methods_uiRouter $stormpath.uiRouter()} in your
 * application's config block.
 *
 * If you're using Angular's built-in `$routeProvider` instead of UI Router, please
 * use {@link stormpath.$stormpath#methods_ngRouter $stormpath.ngRouter()} instead.
 *
 * **NOTE:** Do not define this configuration on a abstract state, it must go on
 * the child state.  However, the controller of the abstract state will be
 * initialized AFTER any configuration rules of the child state have been met.
 *
 * # Support for `data.authorities`
 *
 * If you have used [JHipster](https://jhipster.github.io/) to generate your
 * project, you are likely using the `data.authorities` property to define
 * authorization for your views. This library will look for the `data.authorities`
 * property and apply the same logic as our own `sp.authorize` property.
 *
 * @example
 *
 * <pre>
 *
 * angular.module('myApp')
 *   .config(function ($stateProvider) {
 *
 *     // Wait until we know if the user is logged in before showing the homepage
 *     $stateProvider
 *       .state('main', {
 *         url: '/',
 *         sp: {
 *           waitForUser: true
 *         }
 *       });
 *
 *     // Require a user to be authenticated in order to see this state
 *     $stateProvider
 *       .state('secrets', {
 *         url: '/secrets',
 *         controller: 'SecretsCtrl',
 *         sp: {
 *           authenticate: true
 *         }
 *       });
 *
 *     // Require a user to be in the admins group in order to see this state
 *     $stateProvider
 *       .state('secrets', {
 *         url: '/admin',
 *         controller: 'AdminCtrl',
 *         sp: {
 *           authorize: {
 *             group: 'admins'
 *           }
 *         }
 *       });
 * });
 * </pre>
 *
 * If using JHipster generated code:
 *
 *  <pre>
 *     // Require a user to be in the admins group in order to see this state
 *     $stateProvider
 *       .state('secrets', {
 *         url: '/admin',
 *         controller: 'AdminCtrl',
 *         data: {
 *           authorities: ['admins']
 *         }
 *       });
 *  </pre>
 */

 /**
 * @ngdoc object
 *
 * @name stormpath.SpRouteConfig:SpRouteConfig
 *
 * @property {boolean} authenticate
 *
 * If `true`, the user must be authenticated in order to view this route.
 * If the user is not authenticated, they will
 * be redirected to the `login` route.  After they login, they will be redirected to
 * the route that was originally requested.
 *
 * @property {object} authorize
 *
 * An object that defines access control rules.  Currently, it supports a group-based
 * check.  See the example below.
 *
 * @property {boolean} waitForUser
 *
 * If `true`, delay the route transition until we know
 * if the user is authenticated or not.  This is useful for situations where
 * you want everyone to see this route, but the route may look different
 * depending on the user's authentication route.
 *
 *
 * @description
 *
 * The Stormpath Route Config is an object that you can define on a route.
 * Use this configuration to define access control for your routes, as
 * defined by the ngRoute module.
 *
 * You will need to be using the ngRoute module, and you need
 * to enable the integration by calling
 * {@link stormpath.$stormpath#methods_ngRouter $stormpath.ngRouter()} in your
 * application's config block.
 *
 * If you're using UI Router instead of Angular's built-in `$routeProvider`, please
 * use {@link stormpath.$stormpath#methods_uiRouter $stormpath.uiRouter()} instead.
 *
 * @example
 *
 * <pre>
 *
 * angular.module('myApp')
 *   .config(function ($routeProvider) {
 *     // Wait until we know if the user is logged in before showing the homepage
 *     $routeProvider
 *       .when('/main', {
*         controller: 'MainCtrl',
 *         sp: {
 *           waitForUser: true
 *         }
 *       });
 *
 *     // Require a user to be authenticated in order to see this route
 *     $routeProvider
 *       .when('/secrets', {
 *         controller: 'SecretsCtrl',
 *         sp: {
 *           authenticate: true
 *         }
 *       });
 *
 *     // Require a user to be in the admins group in order to see this route
 *     $routeProvider
 *       .when('/secrets', {
 *         controller: 'AdminCtrl',
 *         sp: {
 *           authorize: {
 *             group: 'admins'
 *           }
 *         }
 *       });
 * });
 * </pre>
 */
angular.module('stormpath', [
  'stormpath.CONFIG',
  'stormpath.utils',
  'stormpath.auth',
  'stormpath.userService',
  'stormpath.viewModelService',
  'stormpath.socialLogin',
  'stormpath.oauth'
])

.factory('StormpathAgentInterceptor',['$isCurrentDomain', '$spHeaders', function($isCurrentDomain, $spHeaders){
  function StormpathAgentInterceptor(){

  }
  /**
   * Adds the X-Stormpath-Agent header, if the requested URL is on the same
   * domain as the current document.
   *
   * @param  {Object} config $http config object.
   * @return {Object} config $http config object.
   */
  StormpathAgentInterceptor.prototype.request = function(config){

    var uriExpressions = [
      '/change$',
      '/forgot$',
      '/login$',
      '/logout$',
      '/me$',
      '/oauth/token$',
      '/oauth/token$',
      '/register$',
      '/revoke$',
      '/verify$'
    ];

    if (uriExpressions.some(function(expr){
      return new RegExp(expr).test(config.url);
    })) {
      config.headers = angular.extend(config.headers, $spHeaders);
    }

    return config;
  };

  return new StormpathAgentInterceptor();
}])
.config(['$httpProvider',function($httpProvider){
  $httpProvider.interceptors.push('StormpathAgentInterceptor');
}])
.provider('$stormpath', [function $stormpathProvider(){
  /**
   * @ngdoc object
   *
   * @name stormpath.$stormpath
   *
   * @description
   *
   * This service allows you to enable application-wide features of the library.
   *
   * At the moment the only feature is the UI Router integration, which is
   * documented below.
   */

  this.$get = [
    '$user', '$injector', 'STORMPATH_CONFIG', '$rootScope', '$location',
    function stormpathServiceFactory($user, $injector, STORMPATH_CONFIG, $rootScope, $location) {
      var $state;
      var $route;

      function StormpathService(){
        var encoder = new UrlEncodedFormParser();
        this.encodeUrlForm = encoder.encode.bind(encoder);

        if ($injector.has('$state')) {
          $state = $injector.get('$state');
        }

        if ($injector.has('$route')) {
          $route = $injector.get('$route');
        }

        return this;
      }
      function stateChangeUnauthenticatedEvent(toState, toParams){
        /**
         * @ngdoc event
         *
         * @name stormpath.$stormpath#$stateChangeUnauthenticated
         *
         * @eventOf stormpath.$stormpath
         *
         * @eventType broadcast on root scope
         *
         * @param {Object} event
         *
         * Angular event object.
         *
         * @param {Object} toState The state that the user attempted to access.
         *
         * @param {Object} toParams The state params of the state that the user
         * attempted to access.
         *
         * @description
         *
         * This event is broadcast when a UI state change is prevented,
         * because the user is not logged in.
         *
         * Use this event if you want to implement your own strategy for
         * presenting the user with a login form.
         *
         * To receive this event, you must be using the UI Router integration.
         *
         * @example
         *
         * <pre>
         *   $rootScope.$on('$stateChangeUnauthenticated',function(e,toState,toParams){
         *     // Your custom logic for deciding how the user should login, and
         *     // if you want to redirect them to the desired state afterwards
         *   });
         * </pre>
         */
        $rootScope.$broadcast(STORMPATH_CONFIG.STATE_CHANGE_UNAUTHENTICATED,toState,toParams);
      }
      function stateChangeUnauthorizedEvent(toState,toParams){
        /**
         * @ngdoc event
         *
         * @name stormpath.$stormpath#$stateChangeUnauthorized
         *
         * @eventOf stormpath.$stormpath
         *
         * @eventType broadcast on root scope
         *
         * @param {Object} event
         *
         * Angular event object.
         *
         * @param {Object} toState The state that the user attempted to access.
         *
         * @param {Object} toParams The state params of the state that the user
         * attempted to access.
         *
         * @description
         *
         * This event is broadcast when a UI state change is prevented,
         * because the user is not authorized by the rules defined in the
         * {@link stormpath.SpStateConfig:SpStateConfig Stormpath State Configuration}
         * for the requested state.
         *
         * Use this event if you want to implement your own strategy for telling
         * the user that they are forbidden from viewing that state.
         *
         * To receive this event, you must be using the UI Router integration.
         *
         * @example
         *
         * <pre>
         *   $rootScope.$on('$stateChangeUnauthorized',function(e,toState,toParams){
         *     // Your custom logic for deciding how the user should be
         *     // notified that they are forbidden from this state
         *   });
         * </pre>
         */
        $rootScope.$broadcast(STORMPATH_CONFIG.STATE_CHANGE_UNAUTHORIZED,toState,toParams);
      }
      StormpathService.prototype.stateChangeInterceptor = function stateChangeInterceptor(config) {
        $rootScope.$on('$stateChangeStart', function(e,toState,toParams){
          var sp = toState.sp || {}; // Grab the sp config for this state
          var authorities = (toState.data && toState.data.authorities) ? toState.data.authorities : undefined;

          if((sp.authenticate || sp.authorize || (authorities && authorities.length)) && (!$user.currentUser)){
            e.preventDefault();
            $user.get().then(function(){
              // The user is authenticated, continue to the requested state
              if(sp.authorize || (authorities && authorities.length)){
                if(authorizeStateConfig(sp, authorities)){
                  $state.go(toState.name,toParams);
                }else{
                  stateChangeUnauthorizedEvent(toState,toParams);
                }
              }else{
                $state.go(toState.name,toParams);
              }
            },function(){
              // The user is not authenticated, emit the necessary event
              stateChangeUnauthenticatedEvent(toState,toParams);
            });
          }else if(sp.waitForUser && ($user.currentUser===null)){
            e.preventDefault();
            $user.get().finally(function(){
              $state.go(toState.name,toParams);
            });
          }
          else if($user.currentUser && (sp.authorize || (authorities && authorities.length))){
            if(!authorizeStateConfig(sp, authorities)){
              e.preventDefault();
              stateChangeUnauthorizedEvent(toState,toParams);
            }
          }else if(toState.name===config.loginState){
            /*
              If the user is already logged in, we will redirect
              away from the login page and send the user to the
              post login state.
             */
            if($user.currentUser!==false){
              e.preventDefault();
              $user.get().finally(function(){
                if($user.currentUser && $user.currentUser.href){
                  $state.go(config.defaultPostLoginState);
                } else {
                  $state.go(toState.name,toParams);
                }
              });
            }
          }
        });
      };

      function authorizeStateConfig(spStateConfig, authorities){
        var sp = spStateConfig;
        if(sp && sp.authorize && sp.authorize.group) {
          return $user.currentUser.inGroup(sp.authorize.group);
        }else if(authorities){
          // add support for reading from JHipster's data: { authorities: ['ROLE_ADMIN'] }
          // https://github.com/stormpath/stormpath-sdk-angularjs/issues/190
          var roles = authorities.filter(function(authority){
            return $user.currentUser.inGroup(authority);
          });
          return roles.length > 0;
        }else{
          console.error('Unknown authorize configuration for spStateConfig',spStateConfig);
          return false;
        }
      }

      function routeChangeUnauthenticatedEvent(toRoute) {
        /**
         * @ngdoc event
         *
         * @name stormpath.$stormpath#$routeChangeUnauthenticated
         *
         * @eventOf stormpath.$stormpath
         *
         * @eventType broadcast on root scope
         *
         * @param {Object} event
         *
         * Angular event object.
         *
         * @param {Object} toRoute The route that the user attempted to access.
         *
         * @description
         *
         * This event is broadcast when a route change is prevented,
         * because the user is not logged in.
         *
         * Use this event if you want to implement your own strategy for
         * presenting the user with a login form.
         *
         * To receive this event, you must be using the ngRoute module.
         *
         * @example
         *
         * <pre>
         *   $rootScope.$on('$routeChangeUnauthenticated', function(event, toRoute) {
         *     // Your custom logic for deciding how the user should login, and
         *     // if you want to redirect them to the desired route afterwards
         *   });
         * </pre>
         */
        $rootScope.$broadcast(STORMPATH_CONFIG.ROUTE_CHANGE_UNAUTHENTICATED, toRoute);
      }

      function routeChangeUnauthorizedEvent(toRoute) {
        /**
         * @ngdoc event
         *
         * @name stormpath.$stormpath#$routeChangeUnauthorized
         *
         * @eventOf stormpath.$stormpath
         *
         * @eventType broadcast on root scope
         *
         * @param {Object} event
         *
         * Angular event object.
         *
         * @param {Object} toRoute The route that the user attempted to access.
         *
         * @description
         *
         * This event is broadcast when a route change is prevented,
         * because the user is not authorized by the rules defined in the
         * {@link stormpath.SpRouteConfig:SpRouteConfig Stormpath Route Configuration}
         * for the requested route.
         *
         * Use this event if you want to implement your own strategy for telling
         * the user that they are forbidden from viewing that route.
         *
         * To receive this event, you must be using the ngRoute module.
         *
         * @example
         *
         * <pre>
         *   $rootScope.$on('$routeChangeUnauthorized', function(event, toRoute) {
         *     // Your custom logic for deciding how the user should be
         *     // notified that they are forbidden from this route
         *   });
         * </pre>
         */
        $rootScope.$broadcast(STORMPATH_CONFIG.ROUTE_CHANGE_UNAUTHORIZED, toRoute);
      }

      StormpathService.prototype.routeChangeInterceptor = function routeChangeInterceptor(config) {
        function goToRoute(route) {
          setTimeout(function() {
            if (route.$$route.originalPath === $location.path()) {
              $route.reload();
            } else {
              $location.path(route);
            }
          });
        }

        $rootScope.$on('$routeChangeStart', function(event, toRoute) {
          if (!toRoute.$$route) {
            return;
          }

          var sp = toRoute.$$route.sp || {}; // Grab the sp config for this route

          if ((sp.authenticate || sp.authorize) && !$user.currentUser) {
            event.preventDefault();

            $user.get().then(function() {
              // The user is authenticated, continue to the requested route
              if (sp.authorize) {
                if (authorizeStateConfig(sp)) {
                  goToRoute(toRoute);
                } else {
                  stateChangeUnauthorizedEvent(toRoute);
                }
              } else {
                goToRoute(toRoute);
              }
            }, function() {
              // The user is not authenticated, emit the necessary event
              routeChangeUnauthenticatedEvent(toRoute);
            });
          } else if (sp.waitForUser && $user.currentUser === null) {
            event.preventDefault();

            $user.get().finally(function() {
              goToRoute(toRoute);
            });
          } else if ($user.currentUser && sp.authorize) {
            if (!authorizeStateConfig(sp)) {
              event.preventDefault();
              routeChangeUnauthorizedEvent(toRoute);
            }
          } else if (toRoute.$$route.originalPath === config.loginRoute) {
            /*
              If the user is already logged in, we will redirect
              away from the login page and send the user to the
              post login route.
             */
            if ($user.currentUser && $user.currentUser.href) {
              event.preventDefault();
              goToRoute(config.defaultPostLoginRoute);
            }
          }
        });
      };

      function authorizeRouteConfig(spRouteConfig) {
        var sp = spRouteConfig;

        if (sp && sp.authorize && sp.authorize.group) {
          return $user.currentUser.inGroup(sp.authorize.group);
        }

        console.error('Unknown authorize configuration for spRouteConfig', sp);
        return false;
      }

      /**
       * @ngdoc function
       *
       * @name stormpath#uiRouter
       *
       * @methodOf stormpath.$stormpath
       *
       * @param {object} config
       *
       * * **`autoRedirect`** - Defaults to true.  After the user logs in at
       * the state defined by `loginState`, they will be redirected back to the
       * state that was originally requested.
       *
       * * **`defaultPostLoginState`**  - Where the user should be sent, after login,
       * if they have visited the login page directly.  If you do not define a value,
       * nothing will happen at the login state.  You can alternatively use the
       * {@link stormpath.authService.$auth#events_$authenticated $authenticated} event to know
       * that login is successful.
       *
       * * **`forbiddenState`** - The UI state name that we should send the user
       * to if they try to an access a view that they are not authorized to view.
       * This happens in response to an `authorize` rule in one of your
       * {@link stormpath.SpStateConfig:SpStateConfig Stormpath State Configurations}
       *
       * * **`loginState`** - The UI state name that we should send the user
       * to if they need to login.  You'll probably use `login` for this value.
       *
       * @description
       *
       * Call this method to enable the integration with the UI Router module.
       *
       * When enabled, you can define {@link stormpath.SpStateConfig:SpStateConfig Stormpath State Configurations} on your UI states.
       * This object allows you to define access control for the state.
       *
       * You can pass config options to this integration, the options control the
       * default behavior around "need to login" and "forbidden" situations.
       * If you wish to implement your own logic for these situations, simply
       * omit the options and use the events (documented below) to know
       * what is happening in the application.
       *
       * @example
       *
       * <pre>
       * angular.module('myApp')
       *   .run(function($stormpath){
       *     $stormpath.uiRouter({
       *       forbiddenState: 'forbidden',
       *       defaultPostLoginState: 'main',
       *       loginState: 'login'
       *     });
       *   });
       * </pre>
       */
      StormpathService.prototype.uiRouter = function uiRouter(config){
        var self = this;
        config = typeof config === 'object' ? config : {};
        this.stateChangeInterceptor(config);

        if(config.loginState){
          self.unauthenticatedWather = $rootScope.$on(STORMPATH_CONFIG.STATE_CHANGE_UNAUTHENTICATED,function(e,toState,toParams){
            self.postLogin = {
              toState: toState,
              toParams: toParams
            };
            $state.go(config.loginState);
          });
        }

        $rootScope.$on(STORMPATH_CONFIG.AUTHENTICATION_SUCCESS_EVENT_NAME,function(){
          if(self.postLogin && (config.autoRedirect !== false)){
            $state.go(self.postLogin.toState,self.postLogin.toParams).then(function(){
              self.postLogin = null;
            });
          }else if(config.defaultPostLoginState){
            $state.go(config.defaultPostLoginState);
          }
        });

        if(config.forbiddenState){
          self.forbiddenWatcher = $rootScope.$on(STORMPATH_CONFIG.STATE_CHANGE_UNAUTHORIZED,function(){
            $state.go(config.forbiddenState);
          });
        }
      };

      /**
       * @ngdoc function
       *
       * @name stormpath#ngRouter
       *
       * @methodOf stormpath.$stormpath
       *
       * @param {object} config
       *
       * * **`autoRedirect`** - Defaults to true.  After the user logs in at
       * the route defined by `loginRoute`, they will be redirected back to the
       * route that was originally requested.
       *
       * * **`defaultPostLoginRoute`**  - Where the user should be sent, after login,
       * if they have visited the login page directly.  If you do not define a value,
       * nothing will happen at the login route.  You can alternatively use the
       * {@link stormpath.authService.$auth#events_$authenticated $authenticated} event to know
       * that login is successful.
       *
       * * **`forbiddenRoute`** - The route that we should send the user
       * to if they try to an access a view that they are not authorized to view.
       * This happens in response to an `authorize` rule in one of your
       * {@link stormpath.SpRouteConfig:SpRouteConfig Stormpath Route Configurations}
       *
       * * **`loginRoute`** - The route name that we should send the user
       * to if they need to login.  You'll probably use `login` for this value.
       *
       * @description
       *
       * Call this method to enable the integration with the ngRoute module.
       *
       * When enabled, you can define {@link stormpath.SpRouteConfig:SpRouteConfig Stormpath Route Configurations} on your routes.
       * This object allows you to define access control for the route.
       *
       * You can pass config options to this integration, the options control the
       * default behavior around "need to login" and "forbidden" situations.
       * If you wish to implement your own logic for these situations, simply
       * omit the options and use the events (documented below) to know
       * what is happening in the application.
       *
       * @example
       *
       * <pre>
       * angular.module('myApp')
       *   .run(function($stormpath){
       *     $stormpath.ngRouter({
       *       forbiddenRoute: '/forbidden',
       *       defaultPostLoginRoute: '/home',
       *       loginRoute: '/login'
       *     });
       *   });
       * </pre>
       */
      StormpathService.prototype.ngRouter = function ngRouter(config) {
        var self = this;

        config = typeof config === 'object' ? config : {};

        this.routeChangeInterceptor(config);

        if (config.loginRoute) {
          this.unauthenticatedWather = $rootScope.$on(STORMPATH_CONFIG.ROUTE_CHANGE_UNAUTHENTICATED, function(event, toRoute) {
            self.postLogin = {
              toRoute: toRoute
            };

            $location.path(config.loginRoute);
          });
        }

        $rootScope.$on(STORMPATH_CONFIG.AUTHENTICATION_SUCCESS_EVENT_NAME, function() {
          if (self.postLogin && config.autoRedirect !== false) {
            $location.path(self.postLogin.toRoute);
            self.postLogin = null;
          } else if (config.defaultPostLoginRoute) {
            $location.path(config.defaultPostLoginRoute);
          }
        });

        if (config.forbiddenRoute) {
          this.forbiddenWatcher = $rootScope.$on(STORMPATH_CONFIG.ROUTE_CHANGE_UNAUTHORIZED, function() {
            $location.path(config.forbiddenRoute);
          });
        }
      };

      StormpathService.prototype.regexAttrParser = function regexAttrParser(value){
        var expr;
        if(value instanceof RegExp){
          expr = value;
        }else if(value && /^\/.+\/[gim]?$/.test(value)){
          expr = new RegExp(value.split('/')[1],value.split('/')[2]);
        }else{
          expr = value;
        }
        return expr;
      };

      function UrlEncodedFormParser(){

        // Copy & modify from https://github.com/hapijs/qs/blob/master/lib/stringify.js

        this.delimiter = '&';
        this.arrayPrefixGenerators = {
          brackets: function (prefix) {
            return prefix + '[]';
          },
          indices: function (prefix, key) {
            return prefix + '[' + key + ']';
          },
          repeat: function (prefix) {
            return prefix;
          }
        };
        return this;
      }
      UrlEncodedFormParser.prototype.stringify = function stringify(obj, prefix, generateArrayPrefix) {

        if (obj instanceof Date) {
          obj = obj.toISOString();
        }
        else if (obj === null) {
          obj = '';
        }

        if (typeof obj === 'string' ||
          typeof obj === 'number' ||
          typeof obj === 'boolean') {

          return [encodeURIComponent(prefix) + '=' + encodeURIComponent(obj)];
        }

        var values = [];

        if (typeof obj === 'undefined') {
          return values;
        }

        var objKeys = Object.keys(obj);
        for (var i = 0, il = objKeys.length; i < il; ++i) {
          var key = objKeys[i];
          if (Array.isArray(obj)) {
            values = values.concat(this.stringify(obj[key], generateArrayPrefix(prefix, key), generateArrayPrefix));
          }
          else {
            values = values.concat(this.stringify(obj[key], prefix + '[' + key + ']', generateArrayPrefix));
          }
        }

        return values;
      };
      UrlEncodedFormParser.prototype.encode = function encode(obj, options) {

        options = options || {};
        var delimiter = typeof options.delimiter === 'undefined' ? this.delimiter : options.delimiter;

        var keys = [];

        if (typeof obj !== 'object' ||
          obj === null) {

          return '';
        }

        var arrayFormat;
        if (options.arrayFormat in this.arrayPrefixGenerators) {
          arrayFormat = options.arrayFormat;
        }
        else if ('indices' in options) {
          arrayFormat = options.indices ? 'indices' : 'repeat';
        }
        else {
          arrayFormat = 'indices';
        }

        var generateArrayPrefix = this.arrayPrefixGenerators[arrayFormat];

        var objKeys = Object.keys(obj);
        for (var i = 0, il = objKeys.length; i < il; ++i) {
          var key = objKeys[i];
          keys = keys.concat(this.stringify(obj[key], key, generateArrayPrefix));
        }

        return keys.join(delimiter);
      };

      return new StormpathService();
    }
  ];
}])
.run(['$rootScope','$user','STORMPATH_CONFIG',function($rootScope,$user,STORMPATH_CONFIG){
  $rootScope.user = $user.currentUser || null;
  $user.get().finally(function(){
    $rootScope.user = $user.currentUser;
  });
  $rootScope.$on(STORMPATH_CONFIG.GET_USER_EVENT,function(){
    $rootScope.user = $user.currentUser;
  });
  $rootScope.$on(STORMPATH_CONFIG.SESSION_END_EVENT,function(){
    $rootScope.user = $user.currentUser;
  });
  $rootScope.$on(STORMPATH_CONFIG.SESSION_END_ERROR_EVENT,function(event, error){
    console.error('Logout error', error);
  });
  $rootScope.$on(STORMPATH_CONFIG.UNAUTHENTICATED_EVENT,function(event, error){
    console.error('UNAUTHENTICATED_EVENT');
  });
}])

/**
 * @ngdoc directive
 *
 * @name stormpath.ifUser:ifUser
 *
 * @description
 *
 * Use this directive to conditionally show an element if the user is logged in.
 *
 * @example
 *
 * <pre>
 * <div class="container">
 *   <h3 if-user>Hello, {{user.fullName}}</h3>
 * </div>
 * </pre>
 */
.directive('ifUser',['$user','$rootScope',function($user,$rootScope){
  return {
    link: function(scope,element){
      $rootScope.$watch('user',function(user){
        if(user && user.href){
          element.removeClass('ng-hide');
        }else{
          element.addClass('ng-hide');
        }
      });
    }
  };
}])

/**
 * @ngdoc directive
 *
 * @name stormpath.ifNotUser:ifNotUser
 *
 * @description
 *
 * Use this directive to conditionally show an element if the user is NOT logged in.
 *
 * @example
 *
 * <pre>
 * <div class="container">
 *   <h3 if-not-user>Hello, you need to login</h3>
 * </div>
 * </pre>
 */
.directive('ifNotUser',['$user','$rootScope',function($user,$rootScope){
  return {
    link: function(scope,element){
      $rootScope.$watch('user',function(user){
        if(user && user.href){
          element.addClass('ng-hide');
        }else{
          element.removeClass('ng-hide');
        }
      });
    }
  };
}])

/**
 * @ngdoc directive
 *
 * @name stormpath.ifUserInGroup:ifUserInGroup
 *
 * @description
 *
 * Use this directive to conditionally show an element if the user is logged in
 * and is a member of the group that is specified by the expression.
 *
 * The attribute value MUST be one of:
 *
 * * A string expression, surrounded by quotes
 * * A reference to a property on the $scope.  That property can be a string or
 * regular expression.
 *
 * **Note**: This feature depends on the data that is returned by the
 * {@link api/stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG#properties_CURRENT_USER_URI CURRENT_USER_URI}.
 * Your server should expand the account's groups before returning the user.
 * If you are using [express-stormpath](https://github.com/stormpath/express-stormpath), simply use
 * [Automatic Expansion](http://docs.stormpath.com/nodejs/express/latest/user_data.html#automatic-expansion)
 *
 * # Using Regular Expressions
 *
 * If using a string expression as the attribute value, you can pass a regular
 * expression by wrapping it in the literal
 * syntax, e.g.
 *  * `'/admins/'` would match any group which has *admins* in the name
 *  * `'/admin$/'` would match any group were the name **ends with** *admin*
 *
 * If referencing a scope property, you should create the value as a RegExp type,
 * e.g.:
 *
 *  <pre>
 *    $scope.matchGroup = new RegExp(/admins/);
 *  </pre>
 *
 * All regular expressions are evaluated via
 * [RegExp.prototype.test](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test)
 *
 * @example
 *
 * <pre>
 *   <script type="text/javascript">
 *     function SomeController($scope){
 *       $scope.matchGroup = /admins/;
 *     }
 *   <script>
 *   <div ng-controller="SomeController">
 *     <h3 if-user-in-group="'admins'">
 *       Hello, {{user.fullName}}, you are an administrator
 *     </h3>
 *
 *     <div if-user-in-group="'/admins/'">
 *        <!-- would match any group which has *admins* in the name -->
 *     </div>
 *     <div if-user-in-group="matchGroup">
 *        <!-- equivalent to the last example -->
 *     </div>
 *     <div if-user-in-group="'/admin$/'">
 *        <!-- would match any group were the name **ends with** *admin* -->
 *     </div>
 *   </div>
 * </pre>
 */
.directive('ifUserInGroup',['$user','$rootScope','$parse','$stormpath',function($user,$rootScope,$parse,$stormpath){

  return {
    link: function(scope,element,attrs){

      var expr;
      var attrExpr = attrs.ifUserInGroup;

      function evalElement(){
        var user = $user.currentUser;
        if(user && user.groupTest(expr || attrExpr)){
          element.removeClass('ng-hide');
        }else{
          element.addClass('ng-hide');
        }
      }

      if(attrExpr){
        scope.$watch($parse(attrExpr),function(value){
          expr = $stormpath.regexAttrParser(value);
          evalElement();
        });
        $rootScope.$watch('user',function(){
          evalElement();
        });
      }
    }
  };
}])

/**
 * @ngdoc directive
 *
 * @name stormpath.ifUserNotInGroup:ifUserNotInGroup
 *
 * @description
 *
 * Use this directive to conditionally show an element if the user is logged in
 * and is NOT a member of the group that is specified by the expression.
 *
 * This is the inverse of {@link stormpath.ifUserInGroup:ifUserInGroup ifUserInGroup},
 * please refer to that directive for full usage information.
 *
 * **Note**: This feature depends on the data that is returned by the
 * {@link api/stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG#properties_CURRENT_USER_URI CURRENT_USER_URI}.
 * Your server should expand the account's groups before returning the user.
 * If you are using [express-stormpath](https://github.com/stormpath/express-stormpath), simply use
 * [Automatic Expansion](http://docs.stormpath.com/nodejs/express/latest/user_data.html#automatic-expansion)
 *
 * @example
 *
 * <pre>
 *   <div class="container">
 *     <h3 if-user-not-in-group="'admins'">
 *       Hello, {{user.fullName}}, please request administrator access
 *     </h3>
 *   </div>
 * </pre>
 */
.directive('ifUserNotInGroup',['$user','$rootScope','$parse','$stormpath',function($user,$rootScope,$parse,$stormpath){
  return {
    link: function(scope,element,attrs){

      var expr;
      var attrExpr = attrs.ifUserNotInGroup;

      function evalElement(){
        var user = $user.currentUser;
        if(user && user.groupTest(expr || attrExpr)){
          element.addClass('ng-hide');
        }else{
          element.removeClass('ng-hide');
        }
      }

      if(attrExpr){
        scope.$watch($parse(attrExpr),function(value){
          expr = $stormpath.regexAttrParser(value);
          evalElement();
        });
        $rootScope.$watch('user',function(){
          evalElement();
        });
      }
    }
  };
}])

/**
 * @ngdoc directive
 *
 * @name stormpath.whileResolvingUser:while-resolving-user
 *
 * @description
 *
 * # [DEPRECATED]
 * Please use {@link stormpath.ifUserStateUnknown:ifUserStateUnknown ifUserStateUnknown} instead.
 *
 */
.directive('whileResolvingUser',['$user','$rootScope',function($user,$rootScope){
  return {
    link: function(scope,element){
      $rootScope.$watch('user',function(){
        if($user.currentUser || ($user.currentUser===false)){
          element.addClass('ng-hide');
        }else{
          element.removeClass('ng-hide');
        }
      });
    }
  };
}])
/**
 * @ngdoc directive
 *
 * @name stormpath.ifUserStateKnown:ifUserStateKnown
 *
 * @description
 *
 * Use this directive to show an element once the user state is known.
 * The inverse of {@link stormpath.ifUserStateUnknown:ifUserStateUnknown ifUserStateUnknown}. You can
 * use this directive to show an element after we know if the user is logged in
 * or not.
 *
 * @example
 *
 * <pre>
 * <div if-user-state-known>
 *   <li if-not-user>
 *      <a ui-sref="login">Login</a>
 *    </li>
 *    <li if-user>
 *        <a ui-sref="main" sp-logout>Logout</a>
 *    </li>
 * </div>
 * </pre>
 */
.directive('ifUserStateKnown',['$user','$rootScope',function($user,$rootScope){
  return {
    link: function(scope,element){
      $rootScope.$watch('user',function(){
        if($user.currentUser || ($user.currentUser===false)){
          element.removeClass('ng-hide');
        }else{
          element.addClass('ng-hide');
        }
      });
    }
  };
}])
/**
 * @ngdoc directive
 *
 * @name stormpath.ifUserStateUnknown:ifUserStateUnknown
 *
 * @description
 *
 * Use this directive to show an element while waiting to know if the user
 * is logged in or not.  This is useful if you want to show a loading graphic
 * over your application while you are waiting for the user state.
 *
 * @example
 *
 * <pre>
 * <div if-user-state-unknown>
 *   <p>Loading.. </p>
 * </div>
 * </pre>
 */
.directive('ifUserStateUnknown',['$user','$rootScope',function($user,$rootScope){
  return {
    link: function(scope,element){
      $rootScope.$watch('user',function(){
        if($user.currentUser === null){
          element.removeClass('ng-hide');
        }else{
          element.addClass('ng-hide');
        }
      });
    }
  };
}])

/**
 * @ngdoc directive
 *
 * @name stormpath.spLogout:spLogout
 *
 * @description
 *
 * This directive adds a click handler to the element.  When clicked, the user will be logged out.
 *
 * **Note**: the click action triggers the logout request to the server and
 * deletes your authentication information, it does not automatically redirect
 * you to any view (we leave this in your control).
 *
 * The common use-case is to redirect users to the login view after they
 * logout.  This can be done by observing the
 * {@link stormpath.authService.$auth#events_$sessionEnd $sessionEnd} event.
 * For example, if you are using UI Router:
 *
 * ```javascript
 * $rootScope.$on('$sessionEnd',function () {
 *   $state.transitionTo('login');
 * });
 * ```
 *
 * @example
 *
 * <pre>
 *   <a ui-sref="main" sp-logout>Logout</a>
 * </pre>
 */
.directive('spLogout',['$auth',function($auth){
  return{
    link: function(scope,element){
      element.on('click',function(){
        $auth.endSession();
      });
    }
  };
}]);

'use strict';
/**
 * @ngdoc overview
 *
 * @name  stormpath.authService
 *
 * @description
 *
 * This module provides the {@link stormpath.authService.$auth $auth} service.
 *
 * Currently, this provider does not have any configuration methods.
 */
/**
 * @ngdoc object
 *
 * @name stormpath.authService.$authProvider
 *
 * @description
 *
 * Provides the {@link stormpath.authService.$auth $auth} service.
 *
 * Currently, this provider does not have any configuration methods.
 */
angular.module('stormpath.auth',['stormpath.CONFIG', 'stormpath.oauth', 'stormpath.utils'])
.config(['$injector','STORMPATH_CONFIG',function $authProvider($injector,STORMPATH_CONFIG){
  /**
   * @ngdoc object
   *
   * @name stormpath.authService.$auth
   *
   * @description
   *
   * The auth service provides methods for authenticating a user, aka
   * "logging in" the user.
   */
  var authServiceProvider = {
    $get: ['$http','$user','$rootScope','$spFormEncoder','$q','$spErrorTransformer', '$isCurrentDomain', 'StormpathOAuth', function authServiceFactory($http,$user,$rootScope,$spFormEncoder,$q, $spErrorTransformer, $isCurrentDomain, StormpathOAuth){

      function AuthService(){
        return this;
      }
      AuthService.prototype.authenticate = function authenticate(data) {
        /**
         * @ngdoc function
         *
         * @name  stormpath.authService.$auth#authenticate
         *
         * @methodOf stormpath.authService.$auth
         *
         * @param {Object} credentialData
         *
         * An object literal for passing username & password, or social provider
         * token.
         *
         * @returns {promise}
         *
         * A promise that is resolved with the authentication response or error
         * response (both are response objects from the $http service).
         *
         * @description
         *
         * Logs the user in.
         *
         * Sends the provided credential data to your backend server. The server
         * handler should verify the credentials and return an access token,
         * which is stored in an HTTP-only cookie.
         *
         * @example
         *
         * ## Username & Password example
         *
         * <pre>
         * myApp.controller('LoginCtrl', function ($scope, $auth, $state) {
         *   $scope.errorMessage = null;
         *   $scope.formData = {
         *     username: '',         // Expose to user as email/username field
         *     password: '',
         *   };
         *
         *   // Use this method with ng-submit on your form
         *   $scope.login = function login(formData){
         *     $auth.authenticate(formData)
         *      .then(function(){
         *        console.log('login success');
         *        $state.go('home');
         *      })
         *      .catch(function(err){
         *        $scope.errorMessage = err.message;
         *      });
         *   }
         *
         * });
         * </pre>
         *
         * ## Social Login example
         *
         * <pre>
         * myApp.controller('LoginCtrl', function ($scope, $auth, $state) {
         *   $scope.errorMessage = null;
         *   $scope.formData = {
         *     providerId: 'facebook',         // Get access token from FB sdk login
         *     accessToken: 'CABTmZxAZBxBADbr1l7ZCwHpjivBt9T0GZBqjQdTmgyO0OkUq37HYaBi4F23f49f5',
         *   };
         *
         *   // Use this method with ng-submit on your form
         *   $scope.login = function login(formData){
         *     $auth.authenticate(formData)
         *      .then(function(){
         *        console.log('login success');
         *        $state.go('home');
         *      })
         *      .catch(function(err){
         *        $scope.errorMessage = err.message;
         *      });
         *   }
         *
         * });
         * </pre>
         */


        function success(httpResponse){
          $user.get(true).then(function(){
            authenticatedEvent(httpResponse);
          });
        }

        function error(httpResponse){
          authenticationFailureEvent(httpResponse);
          return $q.reject($spErrorTransformer.transformError(httpResponse));
        }

        var headers = {
          Accept: 'application/json'
        };

        var authEndpoint = STORMPATH_CONFIG.getUrl('AUTHENTICATION_ENDPOINT');
        var op;

        if ($isCurrentDomain(authEndpoint)) {
          op = $http($spFormEncoder.formPost({
            url: authEndpoint,
            method: 'POST',
            headers: headers,
            withCredentials: true,
            data: data
          }));
        } else {
          var remoteData = angular.extend({}, data);

          // Handles different naming expected in local and client API login
          if (remoteData.login) {
            remoteData.username = remoteData.login;
            delete remoteData.login;
          }

          op = StormpathOAuth.authenticate(remoteData, headers);
        }

        return op.then(success, error);
      };

      /**
       * @ngdoc event
       *
       * @name stormpath.authService.$user#$sessionEnd
       *
       * @eventOf stormpath.authService.$auth
       *
       * @eventType broadcast on root scope
       *
       * @param {Object} event
       *
       * Angular event object.

       * @description
       *
       * This event is broadcast when a call to
       * {@link stormpath.authService.$auth#methods_endSession $auth.endSession()}
       * is successful.  Use this event when you want to do something after the
       * user has logged out.
       */
      function endSessionEvent () {
        $rootScope.$broadcast(STORMPATH_CONFIG.SESSION_END_EVENT);
      }

      /**
       * @ngdoc function
       *
       * @name stormpath.authService.$auth#endSession
       *
       * @methodOf stormpath.authService.$auth
       *
       * @return {promise} A promise that is resolved when the logout request
       * of the server is complete.
       *
       * @description Use this method to log the user out. It triggers a request
       * to the `/logout` endpoint on the server.  This will delete the cookies
       * that are used for authentication.  The
       * {@link stormpath.authService.$auth#events_$sessionEnd $sessionEnd}
       * event will be emitted after a successful logout.
       */
      AuthService.prototype.endSession = function endSession(){
        var destroyEndpoint = STORMPATH_CONFIG.getUrl('DESTROY_SESSION_ENDPOINT');
        var op;

        if ($isCurrentDomain(destroyEndpoint)) {
          op = $http.post(destroyEndpoint, null, {
            headers: {
              'Accept': 'application/json',
              'Content-Type': 'application/x-www-form-urlencoded'
            }
          });
        } else {
          op = StormpathOAuth.revoke();
        }

        op.finally(function(){
          endSessionEvent();
        }).catch(function(httpResponse){
          $rootScope.$broadcast(STORMPATH_CONFIG.SESSION_END_ERROR_EVENT, httpResponse);
        });

        return op;
      };

      function authenticatedEvent(response){
        /**
         * @ngdoc event
         *
         * @name stormpath.authService.$auth#$authenticated
         *
         * @eventOf stormpath.authService.$auth
         *
         * @eventType broadcast on root scope
         *
         * @param {Object} event
         *
         * Angular event object.
         *
         * @param {httpResponse} httpResponse
         *
         * The http response from the $http service.  If you are writing your access tokens to the response body
         * when a user authenticates, you will want to use this response object to get access to that token.
         *
         * @description
         *
         * This event is broadcast when a call to
         * {@link stormpath.authService.$auth#methods_authenticate $auth.authenticate()}
         * is successful.
         */
        $rootScope.$broadcast(STORMPATH_CONFIG.AUTHENTICATION_SUCCESS_EVENT_NAME,response);
      }
      function authenticationFailureEvent(response){
        $rootScope.$broadcast(STORMPATH_CONFIG.AUTHENTICATION_FAILURE_EVENT_NAME,response);
      }
      return new AuthService();
    }]
  };

  $injector.get('$provide')
    .provider(STORMPATH_CONFIG.AUTH_SERVICE_NAME,authServiceProvider);

}]);

'use strict';

/**
* @ngdoc object
*
* @name stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
*
* @description
*
* This constant allows you to configure the internal settings of the module,
* such as authentication endpoints and the names of events. These properties
* must be modified within a config block.
*
* **Example:**
* <pre>
*     angular.module('myapp')
*       .config(function(STORMPATH_CONFIG){
*           STORMPATH_CONFIG.ENDPOINT_PREFIX = 'http://api.mydomain.com';
*       });
* </pre>
*/

angular.module('stormpath.CONFIG',[])
.constant('STORMPATH_CONFIG',(function stormpathConfigBuilder(){
  var c={
    /**
    * @ngdoc property
    *
    * @name AUTHENTICATION_SUCCESS_EVENT_NAME
    *
    * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
    *
    * @description
    *
    * Default: `$authenticated`
    *
    * The name of the event that is fired when a user logs in, after
    * successfully submitting the login form.
    *
    */
    AUTHENTICATION_SUCCESS_EVENT_NAME: '$authenticated',


    /**
    * @ngdoc property
    *
    * @name AUTHENTICATION_FAILURE_EVENT_NAME
    *
    * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
    *
    * @description
    *
    * Default: `$authenticationFailure`
    *
    * The name of the event that is fired when the user posts
    * invalid login credentials to the login form.
    */
    AUTHENTICATION_FAILURE_EVENT_NAME: '$authenticationFailure',


    /**
     * @ngdoc property
     *
     * @name AUTH_SERVICE_NAME
     *
     * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
     *
     * @description
     *
     * Default: `$auth`
     *
     * The name of the authentication service, this changes the
     * service name that you inject.
    */
    AUTH_SERVICE_NAME: '$auth',

    /**
     * @ngdoc property
     *
     * @name AUTO_AUTHORIZED_URIS
     *
     * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
     *
     * @description
     *
     * Default: `['/me$']`
     *
     * The list of URLs to match when making requests.  If an OAuth strategy is
     * being used and the request matches this URL, this library will automatically
     * add the `Authorization: Bearer <token>` header to the request.
    */
    AUTO_AUTHORIZED_URIS: ['/me$'],


    /**
     * @ngdoc property
     *
     * @name SOCIAL_LOGIN_SERVICE_NAME
     *
     * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
     *
     * @description
     *
     * Default: `$socialLogin`
     *
     * The name of the social login service, this changes the
     * service name that you inject.
    */
    SOCIAL_LOGIN_SERVICE_NAME: '$socialLogin',

    /**
     * @ngdoc property
     *
     * @name SOCIAL_LOGIN_RESPONSE_TYPE
     *
     * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
     *
     * @description
     *
     * The response type requested from the Stormpath Social Login v2 API.
     * Determines the type of token that will be returned for OAuth authentication
     * against the Stormpath OAuth API, when making social login attempts.
    */
    SOCIAL_LOGIN_RESPONSE_TYPE: 'stormpath_token',

    /**
     * @ngdoc property
     *
     * @name SOCIAL_LOGIN_OPTIONS
     *
     * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
     *
     * @description
     *
     * Options that are set for a given social authentication provider when
     * making a social authentication request. These are appended to the request
     * as query parameters, and will override any default options, or options
     * set in the Stormpath admin console.
     *
     * The settings are mapped by providerId of a directory (e.g. `google`, `facebook`).
     *
     * Additional providers may be added to the object, but must all be in lowercase.
    */
    SOCIAL_LOGIN_OPTIONS: {
      google: {},
      facebook: {},
      twitter: {},
      linkedin: {}
    },

    /**
     * @ngdoc property
     *
     * @name SOCIAL_LOGIN_REDIRECT_URI
     *
     * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
     *
     * @description
     *
     * The URI that the social login flow will redirect to after a login attempt.
     * This URI is relative to the base application URI.
    */
    SOCIAL_LOGIN_REDIRECT_URI: '',

    /**
     * @ngdoc property
     *
     * @name SOCIAL_LOGIN_AUTHORIZE_URI
     *
     * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
     *
     * @description
     *
     * The relative URI of the endpoint used for social auth.
     * Should <b>not</b> be changed if Client API is used.
    */
    SOCIAL_LOGIN_AUTHORIZE_ENDPOINT: '/authorize',

    /**
    * @ngdoc property
    *
    * @name AUTHENTICATION_ENDPOINT
    *
    * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
    *
    * @description
    *
    * Default: `/login`
    *
    * The URI that the login form will post to.  The endpoint MUST accept data
    * in the following format:
    *
    * ```
    * {
    *     username: '',
    *     password: ''
    * }
    * ```
    */
    AUTHENTICATION_ENDPOINT: '/login',


    /**
    * @ngdoc property
    *
    * @name CURRENT_USER_URI
    *
    * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
    *
    * @description
    *
    * Default: `/me`
    *
    * The URI that is used to fetch the account object of
    * the currently logged in user.  This endpoint MUST:
    *  * Respond with a JSON object that is the Stormpath account object,
    *  if the user has an active session.
    *  * Respond with `401 Unauthorized` if the user has no session.
    */
    CURRENT_USER_URI: '/me',


    /**
    * @ngdoc property
    *
    * @name DESTROY_SESSION_ENDPOINT
    *
    * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
    *
    * @description
    *
    * Default: `/logout`
    *
    * The URL that the {@link stormpath.spLogout:spLogout spLogout} directive
    * will make a GET request to, this endpoint MUST delete the access token
    * cookie, XSRF token cookie, and any other cookies that relate to the user
    * session.
    */
    DESTROY_SESSION_ENDPOINT: '/logout',


    /**
    * @ngdoc property
    *
    * @name EMAIL_VERIFICATION_ENDPOINT
    *
    * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
    *
    * @description
    *
    * Default: `/verify`
    *
    * The endpoint that is used for verifying an account that requires email
    * verification.  Used by
    * {@link stormpath.userService.$user#methods_verify $user.verify()} to POST
    * the `sptoken` that was delivered to the user by email.
    *
    * This endpoint MUST accept a POST request with the following format and
    * use Stormpath to verify the token:
    * ```
    * {
    *   sptoken: '<token from email sent to user>'
    * }
    * ```
    *
    */
    EMAIL_VERIFICATION_ENDPOINT: '/verify',


    /**
    * @ngdoc property
    *
    * @name ENDPOINT_PREFIX
    *
    * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
    *
    * @description
    *
    * Default: *none*
    *
    * A prefix, e.g. "base URL" to add to all endpoints that are used by this SDK.
    * Use this if your backend API is running on a different port or domain than
    * your Angular application.  Omit the trailing forward slash.
    *
    * **NOTE:** This may trigger
    * [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS)
    * behaviour in the browser, and your server
    * will need to respond to requests accordingly.  If you are using our
    * Express SDK see
    * [allowedOrigins](https://github.com/stormpath/stormpath-sdk-express#allowedOrigins)
    *
    * **Example:**
    * <pre>
    *   ENDPOINT_PREFIX = 'http://api.mydomain.com'
    * </pre>
    */
    ENDPOINT_PREFIX: '',


    /**
    * @ngdoc property
    *
    * @name GET_USER_EVENT
    *
    * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
    *
    * @description
    *
    * Default: `$currentUser`
    *
    * The name of the event that is fired when
    * {@link stormpath.userService.$user#methods_get $user.get()}
    * is resolved with a user object.
    */
    GET_USER_EVENT: '$currentUser',


    /**
    * @ngdoc property
    *
    * @name NOT_LOGGED_IN_EVENT
    *
    * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
    *
    * @description
    *
    * Default: `$notLoggedin`
    *
    * The name of the event that is fired when
    * {@link stormpath.userService.$user#methods_get $user.get()}
    * is rejected without a user.
    */
    NOT_LOGGED_IN_EVENT: '$notLoggedin',


    /**
    * @ngdoc property
    *
    * @name FORGOT_PASSWORD_ENDPOINT
    *
    * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
    *
    * @description
    *
    * Default: `/forgot`
    *
    * The endpoint that is used by
    * {@link stormpath.userService.$user#methods_passwordResetRequest $user.passwordResetRequest()}
    * to create password reset tokens.
    */
    FORGOT_PASSWORD_ENDPOINT: '/forgot',


    /**
    * @ngdoc property
    *
    * @name CHANGE_PASSWORD_ENDPOINT
    *
    * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
    *
    * @description
    *
    * Default: `/change`
    *
    * The endpoint that is used by
    * {@link stormpath.userService.$user#methods_verifyPasswordResetToken $user.verifyPasswordResetToken()} and
    * {@link stormpath.userService.$user#methods_resetPassword $user.resetPassword()}
    * to verify and consume password reset tokens (change a user's password with the token).
    */
    CHANGE_PASSWORD_ENDPOINT: '/change',


    /**
    * @ngdoc property
    *
    * @name SESSION_END_EVENT
    *
    * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
    *
    * @description
    *
    * Default: `$sessionEnd`
    *
    * The name of the event that is fired when the user logs out via the
    * {@link stormpath.spLogout:spLogout spLogout}
    * directive
    */
    SESSION_END_EVENT: '$sessionEnd',

    SESSION_END_ERROR_EVENT: '$sessionEndError',


    /**
    * @ngdoc property
    *
    * @name STATE_CHANGE_UNAUTHENTICATED
    *
    * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
    *
    * @description
    *
    * Default: `$stateChangeUnauthenticated`
    *
    * The name of the event that is fired when the user attempts to visit a
    * UI Router state that requires authentication, but the user is not
    * authenticated.
    */
    STATE_CHANGE_UNAUTHENTICATED: '$stateChangeUnauthenticated',


    /**
    * @ngdoc property
    *
    * @name STATE_CHANGE_UNAUTHORIZED
    *
    * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
    *
    * @description
    *
    * Default: `$stateChangeUnauthorized`
    *
    * The name of the event that is fired when the user attempts to visit a
    * UI Router state that has an access control rule which the user does not
    * meet (such as not being in a specified group)
    */
    STATE_CHANGE_UNAUTHORIZED: '$stateChangeUnauthorized',


    /**
    * @ngdoc property
    *
    * @name ROUTE_CHANGE_UNAUTHENTICATED
    *
    * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
    *
    * @description
    *
    * Default: `$routeChangeUnauthenticated`
    *
    * The name of the event that is fired when the user attempts to visit a
    * route that requires authentication, but the user is not
    * authenticated.
    */
    ROUTE_CHANGE_UNAUTHENTICATED: '$routeChangeUnauthenticated',


    /**
    * @ngdoc property
    *
    * @name ROUTE_CHANGE_UNAUTHORIZED
    *
    * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
    *
    * @description
    *
    * Default: `$routeChangeUnauthorized`
    *
    * The name of the event that is fired when the user attempts to visit a
    * route that has an access control rule which the user does not
    * meet (such as not being in a specified group)
    */
    ROUTE_CHANGE_UNAUTHORIZED: '$routeChangeUnauthorized',

    /**
    * @ngdoc property
    *
    * @name OAUTH_REQUEST_ERROR
    *
    * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
    *
    * @description
    *
    * Default: `$oAuthRequestError`
    *
    * The name of the event that is fired when the user attempts OAuth-based
    * authentication, and fails due to an OAuth issue.
    */
    OAUTH_REQUEST_ERROR: '$oAuthRequestError',

    /**
    * @ngdoc property
    *
    * @name OAUTH_AUTHENTICATION_ENDPOINT
    *
    * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
    *
    * @description
    *
    * Default: `/oauth/token`
    *
    * The endpoint that is used to authenticate and refresh using OAuth tokens.
    * This endpoint MUST support password and refresh_token grant authentication
    * flows.
    */
    OAUTH_AUTHENTICATION_ENDPOINT: '/oauth/token',

    /**
    * @ngdoc property
    * @name OAUTH_REVOKE_ENDPOINT
    *
    * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
    *
    * @description
    *
    * Default: `/oauth/revoke`
    *
    * The endpoint that is used to revoke OAuth tokens.
    */
    OAUTH_REVOKE_ENDPOINT: '/oauth/revoke',

    /**
    * @ngdoc property
    * @name OAUTH_REVOKE_ENDPOINT
    *
    * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
    *
    * @description
    *
    * The name under which tokens are stored in the token storage mechanism.
    * Might not be relevant if the underlying storage mechanism is not key-value
    * based.
    *
    * See {@link stormpath.tokenStore.TokenStoreManager TokenStoreManager} for more detail.
    */
    OAUTH_TOKEN_STORAGE_NAME: 'stormpath:token',

    /**
    * @ngdoc property
    *
    * @name REGISTER_URI
    *
    * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
    *
    * @description
    *
    * Default: `/register`
    *
    * The endpoint that is used by
    * {@link stormpath.userService.$user#methods_create $user.create()}
    * to POST new users.  This endpoint MUST accept a stormpath account object
    * and use Stormpath to create the new user.
    */
    REGISTER_URI: '/register',

    /**
    * @ngdoc property
    *
    * @name REGISTERED_EVENT_NAME
    *
    * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
    *
    * @description
    *
    * Default: `$registered`
    *
    * The name of the event that is fired when
    * {@link stormpath.userService.$user#methods_create $user.create()}
    * is resolved with an account that was successfully created
    */
    REGISTERED_EVENT_NAME: '$registered',

    /**
    * @ngdoc property
    *
    * @name OAUTH_DEFAULT_TOKEN_STORE_TYPE
    *
    * @propertyOf stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
    *
    * @description
    *
    * Default: `localStorage`
    *
    * The default type of local storage used by
    * {@link stormpath.oauth.StormpathOAuthTokenProvider}.
    */
    OAUTH_DEFAULT_TOKEN_STORE_TYPE: 'localStorage'

  };

  c.getUrl = function(key) {
    return this.ENDPOINT_PREFIX + this[key];
  };

  c.getSocialLoginConfiguration = function(key) {
    var canonicalKey = key ? key.toLowerCase() : '';
    return this.SOCIAL_LOGIN_OPTIONS[canonicalKey] || {};
  };
  return c;
})());

'use strict';

angular.module('stormpath')

.controller('SpEmailVerificationCtrl', ['$scope','$location','$user',function ($scope,$location,$user) {
  $scope.showVerificationError = false;
  $scope.verifying = false;
  $scope.reVerificationSent = false;
  $scope.needsReVerification = false;
  $scope.resendFailed = false;
  $scope.formModel = {
    username: ''
  };
  if($location.search().sptoken){
    $scope.verifying = true;
    $user.verify($location.search().sptoken)
      .then(function(){
        $scope.verified = true;
      })
      .catch(function(){
        $scope.needsReVerification = true;
        $scope.showVerificationError = true;
      })
      .finally(function(){
        $scope.verifying = false;
      });
  }else{
    $scope.needsReVerification = true;
    $scope.showVerificationError = true;
  }
  $scope.submit = function(){
    $scope.posting = true;
    $scope.resendFailed = false;
    $scope.showVerificationError = false;
    $user.resendVerificationEmail({login: $scope.formModel.username})
      .then(function(){
        $scope.reVerificationSent = true;
      })
      .catch(function(){
        $scope.resendFailed = true;
      }).finally(function(){
        $scope.posting = false;
      });
  };
}])

/**
 * @ngdoc directive
 *
 * @name stormpath.spEmailVerification:spEmailVerification
 *
 * @param {string} template-url
 *
 * An alternate template URL if you want
 * to use your own template for the form.
 *
 * @description
 *
 * Use this directive on the page that users land on when they click an email verification link.
 * These links are sent after a user registers, see
 * {@link stormpath.spRegistrationForm:spRegistrationForm spRegistrationForm}.
 *
 * This directive will render a view that does the following:
 * * Verifies that the current URL has an `sptoken` in it.  Shows an error if not.
 * * Verifies the given `sptoken` with Stormpath, then:
 *   * If the token is valid, tell the user that the confirmation is complete and prompt the user to login.
 *   * If the token is invalid (it is expired or malformed), we prompt the user to enter
 *     their email address, so that we can try sending them a new link.
 *
 * @example
 *
 * <pre>
 * <!-- If you want to use the default template -->
 * <div class="container">
 *   <div sp-email-verification></div>
 * </div>
 *
 * <!-- If you want to use your own template -->
 * <div class="container">
 *   <div sp-email-verification template-url="/path/to/my-custom-template.html"></div>
 * </div>
 * </pre>
 */
.directive('spEmailVerification',function(){
  return {
    templateUrl: function(tElemenet,tAttrs){
      return tAttrs.templateUrl || 'spEmailVerification.tpl.html';
    },
    controller: 'SpEmailVerificationCtrl'
  };
});

'use strict';

angular.module('stormpath')

.controller('SpLoginFormCtrl', ['$scope','$auth','$viewModel',function ($scope,$auth,$viewModel) {
  $scope.viewModel = null;

  $viewModel.getLoginModel().then(function (model) {

    model.accountStores = model.accountStores.filter(function (accountStore) {
      return accountStore.authorizeUri && accountStore.authorizeUri !== null;
    });

    $scope.viewModel = model;
  }).catch(function (err) {
    throw new Error('Could not load login view model from back-end: ' + err.message);
  });

  $scope.formModel = {};
  $scope.posting = false;
  $scope.submit = function(){
    $scope.posting = true;
    $scope.error = null;
    $auth.authenticate($scope.formModel)
      .catch(function(err){
        $scope.posting = false;
        $scope.error = err.message;
      });
  };
}])


/**
 * @ngdoc directive
 *
 * @name stormpath.spLoginForm:spLoginForm
 *
 * @param {string} template-url
 *
 * An alternate template URL if you want
 * to use your own template for the form.
 *
 * @description
 *
 * This directive will render a pre-built login form with all
 * the necessary fields.  After the login is a success, the following
 * will happen:
 *
 * * The {@link stormpath.authService.$auth#events_$authenticated $authenticated} event will
 * be fired.
 * *  If you have configured the {@link stormpath.$stormpath#methods_uiRouter UI Router Integration},
 * the following can happen:
 *  * The user is sent back to the view they originally requested.
 *  * The user is sent to a default view of your choice.
 *
 * @example
 *
 * <pre>
 * <!-- If you want to use the default template -->
 * <div class="container">
 *   <div sp-login-form></div>
 * </div>
 *
 * <!-- If you want to use your own template -->
 * <div class="container">
 *   <div sp-login-form template-url="/path/to/my-custom-template.html"></div>
 * </div>
 * </pre>
 */
.directive('spLoginForm',function(){
  return {
    templateUrl: function(tElemenet,tAttrs){
      return tAttrs.templateUrl || 'spLoginForm.tpl.html';
    },
    controller: 'SpLoginFormCtrl'
  };
});

'use strict';

/**
* @ngdoc overview
*
* @name stormpath.oauth
*
* @description
*
* This module provides the {@link stormpath.oauth.StormpathOAuth StormpathOAuth}
* and {@link stormpath.oauth.StormpathOAuthToken StormpathOAuthToken} services,
* implementing a client-side OAuth2 workflow.
*/
angular.module('stormpath.oauth', ['stormpath.CONFIG', 'stormpath.utils', 'storpath.tokenStore'])

/**
* @ngdoc service
*
* @name stormpath.oauth.StormpathOAuthTokenProvider
* @requires stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
* @description
*
* Provides the {@link stormpath.oauth.StormpathOAuthToken StormpathOAuthToken}
* service.
*/
.provider('StormpathOAuthToken', ['STORMPATH_CONFIG',
function StormpathOAuthTokenProvider(STORMPATH_CONFIG) {
  var self = this;

  this._tokenStoreType = STORMPATH_CONFIG.OAUTH_DEFAULT_TOKEN_STORE_TYPE;

  /**
  * @ngdoc method
  * @name stormpath.oauth.StormpathOAuthTokenProvider#setTokenStoreType
  * @methodOf stormpath.oauth.StormpathOAuthTokenProvider
  *
  * @param {String} tokenStoreType The name of the token store type the tokens should use to record and read their data.
  *
  * @description
  *
  * Sets the name of the token store type that the tokens use to store and load its data.
  * See {@link stormpath.tokenStore.TokenStoreManager#getTokenStore TokenStoreManager.getTokenStore}
  * for details.
  */
  this.setTokenStoreType = function setTokenStoreType(tokenStoreType) {
    this._tokenStoreType = tokenStoreType;
  };

  /**
  * @ngdoc service
  * @name stormpath.oauth.StormpathOAuthToken
  * @requires $q
  * @requires stormpath.tokenStore.TokenStoreManager
  *
  * @description
  *
  * A service for managing OAuth tokens. It offers a simple interface for storing
  * and reading tokens into a generic storage (backed by
  * {@link stormpath.tokenStore.TokenStoreManager TokenStoreManager}), as well
  * as utility methods for getting specific components of the token - the access
  * token, refresh token, token type, as well as the Authorization header
  * constructed from the token.
  *
  * It uses the token store type set in the provider, unless overrided via
  * {@link stormpath.oauth.StormpathOAuthToken#setTokenStoreType StormpathOAuthToken.setTokenStoreType}.
  */
  this.$get = function $get($q, $normalizeObjectKeys, TokenStoreManager, $injector) {
    function StormpathOAuthToken() {
      this.tokenStore = TokenStoreManager.getTokenStore(self._tokenStoreType);
    }

    /**
    * @ngdoc method
    * @name stormpath.oauth.StormpathOAuthToken#setTokenStoreType
    * @methodOf stormpath.oauth.StormpathOAuthToken
    * @param {String} tokenStoreType The name of the token store type this token should use to record and read their data.
    *
    * @description
    *
    * Sets the name of the token store type that this token uses to store and load its data.
    * See {@link stormpath.tokenStore.TokenStoreManager#getTokenStore TokenStoreManager.getTokenStore}
    * for details.
    */
    StormpathOAuthToken.prototype.setTokenStoreType = function setTokenStoreType(tokenStoreType) {
      this.tokenStore = TokenStoreManager.getTokenStore(tokenStoreType);
    };

    /**
    * @ngdoc method
    * @name stormpath.oauth.StormpathOAuthToken#setToken
    * @methodOf stormpath.oauth.StormpathOAuthToken
    * @param {Object} token The OAuth authorization response returned by the API
    * @returns {Promise} A promise that is resolved or rejected when the storage attempt succeeds or fails
    *
    * @description
    *
    * Stores the OAuth token data object into storage, relying on its token store
    * for the storage implementation details. It transforms the snake-cased keys
    * returned from the API into camel-cased keys when storing the token.
    */
    StormpathOAuthToken.prototype.setTokenResponse = function setTokenResponse(token) {
      var canonicalToken = $normalizeObjectKeys(token);
      // Store a time at which we should renew the token, subtract off one second to give us some buffer of time
      canonicalToken.exp = new Date(new Date().setMilliseconds(0)+((token.expires_in-1)*1000));
      return this.tokenStore.put(STORMPATH_CONFIG.OAUTH_TOKEN_STORAGE_NAME, canonicalToken);
    };

    /**
    * @ngdoc method
    * @name stormpath.oauth.StormpathOAuthToken#getToken
    * @methodOf stormpath.oauth.StormpathOAuthToken
    *
    * @returns {Promise} A promise containing either the resolved token, or a rejection with a reason.
    *
    * @description
    *
    * Retrieves the OAuth token data object from storage, relying on its set token
    * store for the loading implementation details. The result will use camel-cased
    * keys, as noted in
    * {@link stormpath.oauth.StormpathOAuthToken#setTokenResponse StormpathOAuthToken.setTokenResponse}.
    */
    StormpathOAuthToken.prototype.getTokenResponse = function getTokenResponse() {
      return this.tokenStore.get(STORMPATH_CONFIG.OAUTH_TOKEN_STORAGE_NAME);
    };

    /**
    * @ngdoc method
    * @name stormpath.oauth.StormpathOAuthToken#removeToken
    * @methodOf stormpath.oauth.StormpathOAuthToken
    *
    * @returns {Promise} A promise indicating whether the operation had succeeded
    *
    * @description
    *
    * Removes the OAuth token from storage, relying on its set token store for the
    * implementation details.
    */
    StormpathOAuthToken.prototype.removeToken = function removeToken() {
      return this.tokenStore.remove(STORMPATH_CONFIG.OAUTH_TOKEN_STORAGE_NAME);
    };

    /**
    * @ngdoc method
    * @name stormpath.oauth.StormpathOAuthToken#getAccessToken
    * @methodOf stormpath.oauth.StormpathOAuthToken
    *
    * @returns {Promise} Promise containing the access token, or a rejection in case of failure
    *
    * @description
    *
    * Retrieves the access token from storage, relying on the token store for implementation.
    * In case there of storage failure or there being no access token, the result is instead
    * a rejected promise.
    */
    StormpathOAuthToken.prototype.getAccessToken = function getAccessToken() {
      var self = this;
      return this.getTokenResponse()
        .then(function(token) {
          var tokenType = token && token.tokenType;
          var accessToken = token && token.accessToken;

          if (!tokenType || !accessToken) {
            return $q.reject();
          }

          if (new Date() >= new Date(token.exp)) {
            var StormpathOAuth = $injector.get('StormpathOAuth');
            return StormpathOAuth.refresh().then(function(){
              return self.getAccessToken();
            });
          }

          return accessToken;
        });
    };

    /**
    * @ngdoc method
    * @name stormpath.oauth.StormpathOAuthToken#getRefreshToken
    * @methodOf stormpath.oauth.StormpathOAuthToken
    *
    * @returns {Promise} Promise containing the refresh token, or a rejection in case of failure
    *
    * @description
    *
    * Retrieves the refresh token from storage, relying on the token store for implementation.
    * In case there of storage failure or there being no refresh token, the result is instead
    * a rejected promise.
    */
    StormpathOAuthToken.prototype.getRefreshToken = function getRefreshToken() {
      return this.getTokenResponse().then(function(token) {
        if (token) {
          return token.refreshToken;
        }

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

    /**
    * @ngdoc method
    * @name stormpath.oauth.StormpathOAuthToken#getTokenType
    * @methodOf stormpath.oauth.StormpathOAuthToken
    *
    * @returns {Promise} Promise containing the token type, or a rejection in case of failure
    *
    * @description
    *
    * Retrieves the token type from storage, relying on the token store for implementation.
    * In case there of storage failure or there being no token type, the result is instead
    * a rejected promise.
    */
    StormpathOAuthToken.prototype.getTokenType = function getTokenType() {
      return this.getTokenResponse().then(function(token) {
        if (token) {
          return token.tokenType;
        }

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

    return new StormpathOAuthToken();
  };

  this.$get.$inject = ['$q', '$normalizeObjectKeys', 'TokenStoreManager', '$injector'];
}])

/**
* @ngdoc service
*
* @name stormpath.oauth.StormpathOAuthProvider
* @requires stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG
* @description
*
* Provides the {@link stormpath.oauth.StormpathOAuth StormpathOAuth}
* service.
*/
.provider('StormpathOAuth', ['STORMPATH_CONFIG', function StormpathOAuthProvider(STORMPATH_CONFIG) {

  var oauthInstance;

  /**
  * @ngdoc service
  * @name stormpath.oauth.StormpathOAuth
  * @requires $q
  * @requires stormpath.oauth.StormpathOAuthToken
  *
  * @description
  *
  * A service for managing the OAuth client-side authentication flow logic. It
  * offers methods for authenticating via the `password` grant type, refreshing
  * access tokens via refresh tokens, and revoking the current token.
  */
  this.$get = function($http, $spFormEncoder, StormpathOAuthToken) {
    function StormpathOAuth() {
      this.refreshPromise = null;
      return this;
    }

    /**
    * @ngdoc method
    * @methodOf stormpath.oauth.StormpathOAuth
    * @name #authenticate
    *
    *
    * @param {Object} requestData Authentication data object. Expects an email/username and a password field.
    * @param {Object=} opts Additional request options, (e.g. headers), optional.
    *
    * @returns {Promise} A promise containing the authentication response
    *
    * @description
    *
    * Attempts to authenticate the user, using the password grant flow by default,
    * although the method can be overriden via the `requestOpts` parameter. If
    * successful, automatically stores the token using
    * {@link stormpath.oauth.StormpathOAuthToken#setTokenResponse StormpathOAuthToken.setTokenResponse}.
    */
    StormpathOAuth.prototype.authenticate = function authenticate(requestData, extraHeaders) {
      var self = this;
      var data = angular.extend({
        grant_type: 'password'
      }, requestData);

      var headers = angular.extend({
        Accept: 'application/json'
      }, extraHeaders);

      return $http($spFormEncoder.formPost({
        url: STORMPATH_CONFIG.getUrl('OAUTH_AUTHENTICATION_ENDPOINT'),
        method: 'POST',
        headers: headers,
        data: data
      })).then(function(response) {
        StormpathOAuthToken.setTokenResponse(response.data);

        return response;
      });
    };

    /**
    * @ngdoc method
    * @methodOf stormpath.oauth.StormpathOAuth
    * @name revoke
    *
    * @returns {Promise} A promise containing the revokation response
    *
    * @description
    *
    * Attempts to revoke the currently active token. If successful, also removes
    * the token from storage, using
    * {@link stormpath.oauth.StormpathOAuthToken#removeToken StormpathOAuthToken.removeToken}.
    * This method is specific to an OAuth workflow, `$auth.endSession()` should be used instead
    * as it is generc and defers to this method when nedeed.
    */
    StormpathOAuth.prototype.revoke = function revoke() {

      return StormpathOAuthToken.getTokenResponse().then(function(token) {
        var data = {
          token: token.refreshToken || token.accessToken,
          token_type_hint: token.refreshToken ? 'refresh_token' : 'access_token'
        };

        return $http($spFormEncoder.formPost({
          url: STORMPATH_CONFIG.getUrl('OAUTH_REVOKE_ENDPOINT'),
          method: 'POST',
          data: data
        })).finally(function(response) {
          StormpathOAuthToken.removeToken();

          return response;
        });
      });
    };

    /**
     * @ngdoc method
    * @methodOf stormpath.oauth.StormpathOAuth
    * @name refresh
    *
    * @param {Object=} requestData Additional data to add to the refresh POST request, optional.
    * @param {Object=} opts Additional request options, (e.g. headers), optional.
    *
    * @returns {Promise} A promise containing the refresh attempt response
    *
    * @description
    *
    * Attempts to refresh the current token, using its refresh token. If successful,
    * updates the currently stored token using
    * {@link stormpath.oauth.StormpathOAuthToken#setTokenResponse StormpathOAuthToken.setTokenResponse}
    * with the response data.
    */
    StormpathOAuth.prototype.refresh = function(requestData, extraHeaders) {

      var self = this;

      if (self.refreshPromise) {
        return self.refreshPromise;
      }

      return self.refreshPromise = StormpathOAuthToken.getRefreshToken().then(function(refreshToken) {
        var data = angular.extend({
          grant_type: 'refresh_token',
          refresh_token: refreshToken
        }, requestData);

        var headers = angular.extend({
          Accept: 'application/json'
        }, extraHeaders);

        return $http($spFormEncoder.formPost({
          url: STORMPATH_CONFIG.getUrl('OAUTH_AUTHENTICATION_ENDPOINT'),
          method: 'POST',
          headers: headers,
          data: data
        })).then(function(response) {
          StormpathOAuthToken.setTokenResponse(response.data);
          return response;
        }).catch(function(response){
          StormpathOAuthToken.removeToken();
          return response;
        }).finally(function (){
          self.refreshPromise = null;
        });
      });
    };

    if (!oauthInstance) {
      oauthInstance = new StormpathOAuth();
    }

    return oauthInstance;
  };

  this.$get.$inject = ['$http', '$spFormEncoder', 'StormpathOAuthToken'];
}])

/**
* @ngdoc service
* @name stormpath.utils.StormpathOAuthInterceptor
*
* @description
*
* Processes requests and response errors to avoid manual OAuth flow integration.
* Adds property Authorization headers to outgoing requests to external domains
* and handles specific OAuth-based response errors.
*/
.factory('StormpathOAuthInterceptor', ['$isCurrentDomain', '$rootScope', '$q', '$injector', 'StormpathOAuthToken', 'STORMPATH_CONFIG',
function($isCurrentDomain, $rootScope, $q, $injector, StormpathOAuthToken, STORMPATH_CONFIG) {

  function StormpathOAuthInterceptor() {}

  /**
  * @ngdoc method
  * @name stormpath.utils.StormpathOAuthInterceptor#request
  * @methodOf stormpath.utils.StormpathOAuthInterceptor
  *
  * @param {Object} config $http config object.
  * @return {Promise} config Promise containing $http config object.
  *
  * @description
  *
  * Adds the Authorization header on all outgoing request that are going to a
  * different domain, if the match an expression in the  AUTO_AUTHORIZED_URIS list.
  */

  StormpathOAuthInterceptor.prototype.request = function request(config) {

    if (STORMPATH_CONFIG.AUTO_AUTHORIZED_URIS.some(function(expr){
      var regex = expr instanceof RegExp ? expr : new RegExp(expr);
      return regex.test(config.url);
    })) {
      return StormpathOAuthToken.getAccessToken()
        .then(function(token){
          config.headers.Authorization = 'Bearer ' + token;
          return config;
        }).catch(function(){
          return config;
        });
    }

    return config;
  };

  return new StormpathOAuthInterceptor();
}])
.config(['$httpProvider', function($httpProvider) {
  $httpProvider.interceptors.push('StormpathOAuthInterceptor');
}]);

'use strict';

angular.module('stormpath')
.controller('SpPasswordResetRequestCtrl', ['$scope','$user',function ($scope,$user) {
  $scope.sent = false;
  $scope.posting = false;
  $scope.formModel = {
    username: ''
  };
  $scope.error = null;
  $scope.submit = function(){
    $scope.posting = true;
    $scope.error = null;
    $user.passwordResetRequest({email: $scope.formModel.email})
      .then(function(){
        $scope.sent = true;
      })
      .catch(function(err){
        $scope.error = err.message;
      }).finally(function(){
        $scope.posting = false;
      });
  };
}])

.controller('SpPasswordResetCtrl', ['$scope','$location','$user',function ($scope,$location,$user) {
  var sptoken = $location.search().sptoken;
  $scope.showVerificationError = false;
  $scope.verifying = false;
  $scope.verified = false;
  $scope.posting = false;
  $scope.reset = false;
  $scope.error = null;

  $scope.resendFailed = false;
  $scope.formModel = {
    password: '',
    confirmPassword: ''
  };

  if(typeof sptoken==='string'){
    $scope.verifying = true;
    $user.verifyPasswordResetToken(sptoken)
      .then(function(){
        $scope.verified = true;
      })
      .catch(function(){
        $scope.showVerificationError = true;
      })
      .finally(function(){
        $scope.verifying = false;
      });
  }else{
    $scope.showVerificationError = true;
  }
  $scope.submit = function(){
    if($scope.formModel.password!==$scope.formModel.confirmPassword){
      $scope.error = 'Passwords do not match';
      return;
    }
    $scope.posting = true;
    $scope.error = null;
    $scope.showVerificationError = false;
    $user.resetPassword(sptoken, {password: $scope.formModel.password})
      .then(function(){
        $scope.reset = true;
      })
      .catch(function(err){
        $scope.error = err.message;
      }).finally(function(){
        $scope.posting = false;
      });
  };

}])

/**
 * @ngdoc directive
 *
 * @name stormpath.spPasswordResetRequestForm:spPasswordResetRequestForm
 *
 * @param {string} template-url
 *
 * An alternate template URL if you want
 * to use your own template for the form.
 *
 * @description
 *
 * This directive will render a pre-built form which prompts the user for their
 * username/email.  If an account is found, we will send them an email with a
 * password reset link.
 *
 * @example
 *
 * <pre>
 * <!-- If you want to use the default template -->
 * <div class="container">
 *   <div sp-password-reset-request-form></div>
 * </div>
 *
 * <!-- If you want to use your own template -->
 * <div class="container">
 *   <div sp-password-reset-request-form template-url="/path/to/my-custom-template.html"></div>
 * </div>
 * </pre>
 */
.directive('spPasswordResetRequestForm',function(){
  return {
    templateUrl: function(tElemenet,tAttrs){
      return tAttrs.templateUrl || 'spPasswordResetRequestForm.tpl.html';
    },
    controller: 'SpPasswordResetRequestCtrl'
  };
})
/**
 * @ngdoc directive
 *
 * @name stormpath.spPasswordResetForm:spPasswordResetForm
 *
 * @param {string} template-url
 *
 * An alternate template URL if you want
 * to use your own template for the form.
 *
 *
 * @description
 *
 * Use this directive on the page that users land on when they click on a password
 * reset link.  To send users a password reset link, see
 * {@link stormpath.spPasswordResetRequestForm:spPasswordResetRequestForm spPasswordResetRequestForm}.
 *
 * This directive will render a password reset form that does the following:
 * * Verifies that the current URL has an `sptoken` in it.  Shows an error if not.
 * * Verifies the given `sptoken` with Stormpath, then:
 *   * If the token is valid, shows a form that allows the user to enter a new password.
 *   * If the token is invalid (it is expired or malformed), we prompt the user to enter
 *     their email address, so that we can try sending them a new link.
 *
 * @example
 *
 * <pre>
 * <!-- If you want to use the default template -->
 * <div class="container">
 *   <div sp-password-reset-form></div>
 * </div>
 *
 * <!-- If you want to use your own template -->
 * <div class="container">
 *   <div sp-password-reset-form template-url="/path/to/my-custom-template.html"></div>
 * </div>
 * </pre>
 */
.directive('spPasswordResetForm',function(){
  return {
    templateUrl: function(tElemenet,tAttrs){
      return tAttrs.templateUrl || 'spPasswordResetForm.tpl.html';
    },
    controller: 'SpPasswordResetCtrl'
  };
});

'use strict';

angular.module('stormpath')
.controller('SpRegistrationFormCtrl', ['$scope','$user','$auth','$location','$viewModel','$injector', function ($scope,$user,$auth,$location,$viewModel, $injector) {
  $scope.formModel = (typeof $scope.formModel==='object') ? $scope.formModel : {};
  $scope.created = false;
  $scope.enabled = false;
  $scope.creating = false;
  $scope.authenticating = false;
  $scope.viewModel = null;

  $viewModel.getRegisterModel().then(function (model) {

    model.accountStores = model.accountStores.filter(function (accountStore) {
      return accountStore.authorizeUri && accountStore.authorizeUri !== null;
    });

    $scope.viewModel = model;
  }).catch(function (err) {
    throw new Error('Could not load login view model from back-end: ' + err.message);
  });

  $scope.submit = function(){
    $scope.creating = true;
    $scope.error = null;
    $user.create($scope.formModel)
      .then(function(account){
        $scope.created = true;
        $scope.enabled = account.status === 'ENABLED';
        if($scope.enabled && $scope.autoLogin){
          $scope.authenticating = true;
          $auth.authenticate({
            username: $scope.formModel.email,
            password: $scope.formModel.password
          })
          .then(function(){
            var $state = $injector.has('$state') ? $injector.get('$state') : null;
            if($scope.postLoginState && $state){
              $state.go($scope.postLoginState);
            }
            else if($scope.postLoginPath){
              $location.path($scope.postLoginPath);
            }
          })
          .catch(function(err){
            $scope.error = err.message;
          })
          .finally(function(){
            $scope.authenticating = false;
            $scope.creating = false;
          });
        }else{
          $scope.creating = false;
        }
      })
      .catch(function(err){
        $scope.creating = false;
        $scope.error = err.message;
      });
  };
}])


/**
 * @ngdoc directive
 *
 * @name stormpath.spRegistrationForm:spRegistrationForm
 *
 * @param {boolean} autoLogin
 *
 * Default `false`. Automatically authenticate the user
 * after creation.  This makes a call to
 * {@link stormpath.authService.$auth#methods_authenticate $auth.authenticate}, which will
 * trigger the event {@link stormpath.authService.$auth#events_$authenticated $authenticated}.
 * This is not possible if the email verification workflow is enabled on the directory that
 * the account is created in.
 *
 * @param {string} postLoginState
 *
 * If using the `autoLogin` option, you can specify the name of a UI state that the user
 * should be redirected to after they successfully have registered.  This is a UI Router
 * integration, and requires that module.
 *
 * @param {string} postLoginPath
 *
 * If using the `autoLogin` option, you can specify the path that the user
 * should be sent to after registration.  This value is passed to
 * `$location.path()` and does not require a specific routing module.
 *
 * @param {string} template-url
 *
 * An alternate template URL if you want
 * to use your own template for the form.
 *
 *
 * @description
 *
 * This directive will render a pre-built user registration form with the following
 * fields:
 *  * First Name
 *  * Last Name
 *  * Email
 *  * Password
 *
 * # Customizing the Form Fields
 *
 * Our library will make a JSON GET request to the `/register` endpoint on your
 * server, and it expects to receive a view model that describes the form and
 * it's fields.  As such, you will define your custom registration fields in
 * your server-side configuration.  Please see the relevant documentation:
 *
 * * Node.js: [Express-Stormpath - Registration](https://docs.stormpath.com/nodejs/express/latest/registration.html)
 * * PHP: [Stormpath Laravel - Registration](https://docs.stormpath.com/php/laravel/latest/registration.html)
 * * All other frameworks: please see the server integration guide or contact
 *   [support@stormpath.com](support@stormpath.com) for assistance.
 *
 * # Customizing the Form Template
 *
 * If you would like to modify the HTML template that renders our form, you can
 * do that as well.  Here is what you'll need to do:
 *
 * * Create a new view file in your application.
 * * Copy our default template HTML code into your file, found here:
 * <a href="https://github.com/stormpath/stormpath-sdk-angularjs/blob/master/src/spRegistrationForm.tpl.html" target="_blank">spRegistrationForm.tpl.html</a>.
 * * Modify the template to fit your needs, making sure to use `formModel.<FIELD>` as the
 * value for `ng-model` where `.<FIELD>` is the name of the field you want to set on
 * the new account (such as `middleName`).
 * * Use the `template-url` option on the directive to point to your new view file.
 *
 * Any form fields you supply that are not one of the default fields (first
 * name, last name) will need to be defined in the view model (see above) and
 * will be automatically placed into the new account's customa data object.
 *
 * # Email Verification
 *
 * If you are using the email verification workflow, the default template has a message,
 * which will be shown to the user, telling them that they need to check their email
 * for verification.
 *
 * If you are NOT using the email verification workflow, you can, optionally,
 * automatically login the user and redirect them to a UI state in your application.
 * See the options below.
 *
 * # Server Interaction
 *
 * This directive makes a call to
 * {@link stormpath.userService.$user#methods_create $user.create()}
 * when it is ready to POST the form to the server. Please see that method
 * for more information.
 *
 * @example
 *
 * <pre>
 * <!-- If you want to use the default template -->
 * <div class="container">
 *   <div sp-registration-form post-login-state="main"></div>
 * </div>
 *
 * <!-- If you want to use your own template -->
 * <div class="container">
 *   <div sp-registration-form template-url="/path/to/my-custom-template.html"></div>
 * </div>
 * </pre>
 */
.directive('spRegistrationForm',function(){
  return {
    templateUrl: function(tElemenet,tAttrs){
      return tAttrs.templateUrl || 'spRegistrationForm.tpl.html';
    },
    controller: 'SpRegistrationFormCtrl',
    link: function(scope,element,attrs){
      scope.autoLogin = attrs.autoLogin==='true';
      scope.postLoginPath = attrs.postLoginPath || '';
      scope.postLoginState = attrs.postLoginState || '';
    }
  };
});
(function() {
  'use strict';

/**
 * @ngdoc overview
 *
 * @name  stormpath.socialLoginService
 *
 * @description
 *
 * This module provides the {@link stormpath.socialLoginService.$socialLogin $socialLogin} service.
 *
 * Currently, this provider does not have any configuration methods.
 */

 /**
  * @ngdoc object
  *
  * @name stormpath.socialLoginService.$socialLogin
  *
  * @description
  *
  * The social login service provides a generic authorization interface through
  * the Stormpath social login interface.
  */
  function SocialLoginService(STORMPATH_CONFIG, $encodeQueryParams, $getLocalUrl, $http, $window) {
    this.providersPromise = null;
    this.STORMPATH_CONFIG = STORMPATH_CONFIG;
    this.$encodeQueryParams = $encodeQueryParams;
    this.$getLocalUrl = $getLocalUrl;
    this.$http = $http;
    this.$window = $window;
  }

  /**
  * @ngdoc method
  *
  * @name authorize
  * @methodOf stormpath.socialLoginService.$socialLogin
  * @description
  *
  * Authorizes the user using a social authentication provider. This method starts
  * the redirect flow that attempts to authenticate the user, and, if successful,
  * ends in the redirect uri configured via {@link STORMPATH_CONFIG.SOCIAL_LOGIN_REDIRECT_URI}.
  *
  * @param {String} accountStoreHref
  * The HREF of the account store (directory) that is set up to provide the social
  * authentication service.
  *
  * @param {Object} options
  * Additional options (query parameters) to send with the authentication request.
  *
  */
  SocialLoginService.prototype.authorize = function(accountStore, options) {
    var requestParams = angular.extend({
      response_type: this.STORMPATH_CONFIG.SOCIAL_LOGIN_RESPONSE_TYPE,
      account_store_href: accountStore.href,
      redirect_uri: this.$getLocalUrl(this.STORMPATH_CONFIG.SOCIAL_LOGIN_REDIRECT_URI)
    }, options);

    var queryParams = this.$encodeQueryParams(requestParams);
    var socialAuthUri = accountStore.authorizeUri + queryParams;

    this.$window.location = socialAuthUri;
  };

  angular.module('stormpath.socialLogin', ['stormpath.CONFIG', 'stormpath.utils'])

  /**
   * @ngdoc object
   *
   * @name stormpath.socialLoginService.$socialLoginProvider
   *
   * @description
   *
   * Provides the {@link stormpath.socialLoginService.$socialLogin $socialLogin} service.
   *
   * Currently, this provider does not have any configuration methods.
   */
  .config(['$injector', 'STORMPATH_CONFIG', function $socialLoginProvider($injector, STORMPATH_CONFIG) {
    var socialLoginFactory = ['$encodeQueryParams', '$http', '$window', '$getLocalUrl', function socialLoginFactory($encodeQueryParams, $http, $window, $getLocalUrl) {
      return new SocialLoginService(STORMPATH_CONFIG, $encodeQueryParams, $getLocalUrl, $http, $window);
    }];

    $injector.get('$provide').factory(STORMPATH_CONFIG.SOCIAL_LOGIN_SERVICE_NAME, socialLoginFactory);
  }])

  /**
   * @ngdoc directive
   *
   * @name stormpath.spSocialLogin:spSocialLogin
   *
   * @description
   *
   * Add this directive to a button or link in order to authenticate using a social provider.
   * The value should be the account store HREF a social provider, such as Google or Facebook.
   *
   * The `sp-name` field must be set to the provider ID of the corresponding provider, e.g.
   * `google` or `facebook`.
   *
   * Any additional fields can be specified as an object, via the `sp-options` field. These
   * options will additionally be augmented (and overriden) by the options set for the given
   * provider (determined by value of `sp-name`) in {@link STORMPATH_CONFIG.SOCIAL_LOGIN_OPTIONS}.
   *
   * {@link http://docs.stormpath.com/guides/social-integrations/}
   *
   * @example
   *
   * <pre>
   * <div class="container">
   *   <button sp-social-login="http://url.example/facebook-href" sp-name="facebook" sp-options="{scope: 'email'}">Login with Facebook</button>
   * </div>
   * </pre>
   */
  .directive('spSocialLogin', ['$viewModel', '$auth', '$http', '$injector', 'STORMPATH_CONFIG', function($viewModel, $auth, $http, $injector, STORMPATH_CONFIG) {
    return {
      link: function(scope, element, attrs) {
        var accountStore = scope.$eval(attrs.spSocialLogin);
        var blacklist = ['href', 'providerId', 'clientId'];
        var social = $injector.get(STORMPATH_CONFIG.SOCIAL_LOGIN_SERVICE_NAME);

        scope.providerName = accountStore.provider.providerId;

        element.bind('click', function() {

          var cleanOptions = {};

          angular.forEach(accountStore.provider, function(value, key) {
            if (value && blacklist.indexOf(key) !== -1) {
              cleanOptions[key] = value;
            }
          });

          cleanOptions = angular.extend(
            cleanOptions,
            STORMPATH_CONFIG.getSocialLoginConfiguration(accountStore.provider.providerId)
          );

          social.authorize(accountStore, cleanOptions);
        });
      }
    };
  }])

  /**
  * @private
  *
  * @ngdoc service
  * @name stormpath.socialLogin.$processSocialAuthToken
  * @description
  *
  * Executes the flow for processing social authentication tokens returned from
  * the social login authentication redirect flow. If the token is present, it
  * is used to authenticate the user using the `stormpath_token` grant type.
  *
  * Appropriate authentication success or failure events are broadcast when the
  * authentication concludes.
  *
  * If the token is not present in the URL query parameters, the function returns
  * a resolved promise immediatelly.
  */
  .factory('$processSocialAuthToken', ['STORMPATH_CONFIG', '$parseUrl', '$window', '$injector', '$q', '$rootScope',
    function(STORMPATH_CONFIG, $parseUrl, $window, $injector, $q, $rootScope) {
      return function processSocialAuthToken() {
        var parsedUrl = $parseUrl($window.location.href);

        // If this field is present, this means that we have been redirected here
        // from a social login flow
        if (parsedUrl.search.jwtResponse) {
          var AuthService = $injector.get(STORMPATH_CONFIG.AUTH_SERVICE_NAME);
          return AuthService.authenticate({
            grant_type: 'stormpath_token',
            token: parsedUrl.search.jwtResponse
          }).then(function() {
            // Clears the URL of the token in both hashbang and HTML5 mode
            $window.location.search = '';

            $rootScope.$broadcast(STORMPATH_CONFIG.AUTHENTICATION_SUCCESS_EVENT_NAME)
          }).catch(function(err) {
            $rootScope.$broadcast(STORMPATH_CONFIG.AUTHENTICATION_FAILURE_EVENT_NAME);
            throw err;
          });
        }

        return $q.resolve();
      };
    }]);
}());

'use strict';

/**
* @ngdoc overview
*
* @name stormpath.tokenStore
*
* @description
*
* This module provides a global access point for registering and fetching token
* store mechanisms, as used by the {@link stormpath.oauth} module.
*/

/**
* @ngdoc object
* @interface
* @name stormpath.tokenStore.TokenStore
*
* @description
* A token store implementation. It allows simple key-value pair storing, fetching,
* and deleting. Its methods may be synchronous, but must always return promises.
*/

/**
* @ngdoc method
* @name stormpath.tokenStore.TokenStore#put
* @methodOf stormpath.tokenStore.TokenStore
*
* @param {String} name The name under which to store a value.
* @param {Any} value The string representation of a value.
* @returns {Promise} Indication of success
*
* @description
*
* Stores a string value in a key-value store.
*/

/**
* @ngdoc method
* @name stormpath.tokenStore.TokenStore#get
* @methodOf stormpath.tokenStore.TokenStore
*
* @param {String} name The name for which to retrieve a value.
* @returns {Promise} The resolved value retrieved from the store, or a rejection with a reason.
*
* @description
*
* Retrieves a value from a key-value store.
*/

/**
* @ngdoc method
* @name stormpath.tokenStore.TokenStore#remove
* @methodOf stormpath.tokenStore.TokenStore
*
* @param {String} name The name for which to remove a value.
* @returns {Promise} Indication of success. Should resolve if there is no value to remove.
*
* @description
*
* Remove a value from a key-value store.
*/

angular.module('storpath.tokenStore', ['stormpath.CONFIG'])

/**
* @ngdoc service
*
* @name stormpath.tokenStore.TokenStoreManagerProvider
*
* @description
*
* Provides the {@link stormpath.tokenStore.TokenStoreManager TokenStoreManager} service.
*/
.provider('TokenStoreManager', function() {
  var tokenStores = {};

  /**
  * @ngdoc object
  *
  * @name stormpath.tokenStore.TokenStoreManager
  *
  * @description
  *
  * This service provides methods for registering token stores (with duck-typed
  * validation), as well as retrieving them by name.
  *
  * Token store implementations must implement the
  * {@link stormpath.tokenStore.TokenStore TokenStore interface}.
  *
  * All token stores are expected to satisfy the following contract:
  *   - Instances must have a `put` method that takes a key and a value, stores them, and returns a promise indicating success
  *   - Instances must have a `get` method that takes a key and returns a promise containing the value for the given key, or a rejection with a reason
  *   - Instances must have a `remove` method that takes a key and removes the value, returning the result as a promise
  *
  * See {@link stormpath.tokenStore.LocalStorageTokenStore LocalStorageTokenStore}
  * for an example of an implementation.
  *
  * @example
  *
  * <pre>
  *   angular.module('app')
  *     .run(['$q', 'TokenStoreManager', function($q, TokenStoreManager) {
  *       // Can also be provided by a service/factory for better code organisation
  *       var myStore = {
  *         data: {},
  *         get: function get(key) {
  *           return this.data[key] ? $q.resolve(this.data[key]) : $q.reject();
  *         },
  *         put: function put(key, value) {
  *           this.data[key] = value;
  *           return $q.resolve();
  *         },
  *         remove: function remove(key) {
  *           delete this.data[key];
  *           return $q.resolve();
  *         }
  *       };
  *
  *       TokenStoreManager.registerTokenStore('basicStore', myStore);
  *
  *       var alsoMyStore = TokenStoreManager.getTokenStore('basicStore');
  *     }]);
  * </pre>
  */
  this.$get = function $get() {
    return {
      /**
      * @ngdoc method
      * @name stormpath.tokenStore.TokenStoreManager#registerTokenStore
      *
      * @methodOf stormpath.tokenStore.TokenStoreManager
      *
      * @param {String} name The name under which to store the token store implementation
      * @param {TokenStore} tokenStore A concrete {@link stormpath.tokenStore.TokenStore TokenStore}
      *
      * @throws {Error} tokenStore must satisfy the token store contract methods (get, put, remove).
      */
      registerTokenStore: function registerTokenStore(name, tokenStore) {
        var requiredMethods = ['get', 'put', 'remove'];

        var isValid = tokenStore && requiredMethods.reduce(function(valid, method) {
          return valid && angular.isFunction(tokenStore[method]);
        }, true);

        if (!isValid) {
          throw new Error('Invalid token store. `get`, `put` and `remove` methods must be implemented');
        }

        tokenStores[name] = tokenStore;
      },
      /**
      * @ngdoc method
      * @name stormpath.tokenStore.TokenStoreManager#getTokenStore
      *
      * @methodOf stormpath.tokenStore.TokenStoreManager
      *
      * @param {String} name The name of the token store implementation.
      * @returns {TokenStore} The token store implementation stored under that name
      * @throws {Error} When no token store is present for that name.
      */
      getTokenStore: function getTokenStore(name) {
        if (angular.isUndefined(tokenStores[name])) {
          throw new Error('Unrecognised token store: ' + name);
        }

        return tokenStores[name];
      }
    };
  };
})

/**
* @ngdoc service
* @name stormpath.tokenStore.LocalStorageTokenStore
* @augments stormpath.tokenStore.TokenStore
*
* @description
*
* Implements token storage via browser localStorage.
*/
.factory('LocalStorageTokenStore', ['$q', function($q) {
  function LocalStorageTokenStore() {
    this._checkAvailability();
  }

  // Checks whether the current environment supports localStorage and sets the
  // internal state accordingly
  LocalStorageTokenStore.prototype._checkAvailability = function _checkAvailability() {
    if (typeof localStorage === undefined) {
      this.hasLocalStorage = false;
    } else {
      try {
        localStorage.setItem('sp:feature_test', 'test');

        if (localStorage.getItem('sp:feature_test') === 'test') {
          localStorage.removeItem('sp:feature_test');
          this.hasLocalStorage = true;
        } else {
          this.hasLocalStorage = false;
        }
      } catch (e) {
        this.hasLocalStorage = false;
      }
    }
  };

  // Provides uniform rejection method for when localStorage is not supported
  LocalStorageTokenStore.prototype._notImplementedError = function _notImplementedError() {
    return $q.reject({
      error: {
        message: 'Local storage not supported in this environment'
      }
    });
  };

  /**
  * @ngdoc method
  * @name stormpath.tokenStore.LocalStorageTokenStore#put
  * @methodOf stormpath.tokenStore.LocalStorageTokenStore
  *
  * @param {String} name The name under which to store a value.
  * @param {Any} value The string representation of a value.
  * @returns {Promise} Indication of success
  *
  * @description
  *
  * Attempts to store a key-value pair using the localStorage API.
  */
  LocalStorageTokenStore.prototype.put = function put(key, value) {
    if (!this.hasLocalStorage) {
      return this._notImplementedError();
    }

    var stringValue;

    try {
      stringValue = JSON.stringify(value);
    } catch (e) {
      return $q.reject(e);
    }

    localStorage.setItem(key, stringValue);
    return $q.resolve();
  };

  /**
  * @ngdoc method
  * @name stormpath.tokenStore.LocalStorageTokenStore#get
  * @methodOf stormpath.tokenStore.LocalStorageTokenStore
  *
  * @param {String} name The name for which to retrieve a value.
  * @returns {Promise} Resolved with value or rejected if local storage is unsupported, or value not present.
  *
  * @description
  *
  * Attempts to retrieve a value for a given key using the localStorage API.
  */
  LocalStorageTokenStore.prototype.get = function get(key) {
    if (!this.hasLocalStorage) {
      return this._notImplementedError();
    }

    var value = localStorage.getItem(key);

    if (angular.isDefined(value)) {
      try {
        return $q.resolve(JSON.parse(value));
      } catch (e) {
        return $q.reject(e);
      }
    }

    return $q.reject(new Error('Token not found'));
  };

  /**
  * @ngdoc method
  * @name stormpath.tokenStore.LocalStorageTokenStore#remove
  * @methodOf stormpath.tokenStore.LocalStorageTokenStore
  *
  * @param {String} name The name for which to remove the value.
  * @returns {Promise} Indication of success
  *
  * @description
  *
  * Attempts to remove a value for a key from store using the localStorage API.
  */
  LocalStorageTokenStore.prototype.remove = function remove(key) {
    if (!this.hasLocalStorage) {
      return this._notImplementedError();
    }

    localStorage.removeItem(key);
    return $q.resolve();
  };

  return new LocalStorageTokenStore();
}])

// Register the basic localStorage provider when run
.run(['TokenStoreManager', 'LocalStorageTokenStore',
function(TokenStoreManager, LocalStorageTokenStore) {
  TokenStoreManager.registerTokenStore('localStorage', LocalStorageTokenStore);
}]);

'use strict';
/**
 * @ngdoc overview
 *
 * @name stormpath.userService
 *
 * @description
 *
 * This module provides the {@link stormpath.userService.$user $user} service.
 */

/**
 * @ngdoc object
 *
 * @name stormpath.userService.$userProvider
 *
 * @description
 *
 * Provides the {@link stormpath.userService.$user $user} service.
 *
 * Currently, this provider does not have any configuration methods.
 */

angular.module('stormpath.userService',['stormpath.CONFIG', 'stormpath.utils', 'stormpath.socialLogin'])
.provider('$user', [function $userProvider(){

  /**
   * @ngdoc object
   *
   * @name stormpath.userService.$user
   *
   * @description
   *
   * Use this service to get the current user and do access control checks
   * on the user.
   */

  function User(data){
    var self = this;
    Object.keys(data).map(function(k){
      self[k] = data[k];
    });
  }
  /**
  * This method may change in the future, do not use.
  * Please use the `ifUserInGroup` directive instead
  */
  User.prototype.inGroup = function inGroup(groupName) {
    return this.groups.items.filter(function(group){
      return group.name === groupName;
    }).length >0;
  };
  /**
  * This method may change in the future, do not use.
  * Please use the `ifUserInGroup` directive instead
  */
  User.prototype.matchesGroupExpression = function matchesGroupExpression(regex) {
    return this.groups.items.filter(function(group){
      return regex.test(group.name);
    }).length >0;
  };
  /**
  * This method may change in the future, do not use.
  * Please use the `ifUserInGroup` directive instead
  */
  User.prototype.groupTest = function groupTest(expr) {
    if(expr instanceof RegExp && this.matchesGroupExpression(expr)){
      return true;
    }else if(this.inGroup(expr)){
      return true;
    }else{
      return false;
    }
  };

  this.$get = [
    '$q','$http','STORMPATH_CONFIG','$rootScope','$spFormEncoder','$spErrorTransformer', '$processSocialAuthToken',
    function userServiceFactory($q,$http,STORMPATH_CONFIG,$rootScope,$spFormEncoder,$spErrorTransformer, $processSocialAuthToken){
      function UserService(){
        this.cachedUserOp = null;

        /**
          * @ngdoc property
          *
          * @name currentUser
          *
          * @propertyOf stormpath.userService.$user
          *
          * @description
          *
          * Retains the result of the last call to {@link stormpath.userService.$user#methods_get $user.get()}.
          * This property is set after every resolution of the {@link stormpath.userService.$user#methods_get $user.get()} promise.
          *
          * If the user state is unknown (while {@link stormpath.userService.$user#methods_get $user.get()}
          * is waiting to be resolved), this value is `null`.
          *
          * If the call to {@link stormpath.userService.$user#methods_get $user.get()} has resolved, one of the following will happen:
          * * If the user is not logged in, this value will be `false`.
          * * If the user is logged in, this value will be the account object of the user.
          *
          */

        this.currentUser = null;
        return this;
      }
      UserService.prototype.create = function(accountData){
        /**
         * @ngdoc function
         *
         * @name create
         *
         * @methodOf stormpath.userService.$user
         *
         * @param {Object} accountData
         *
         * An object literal for passing the data
         * to the new account.
         *
         * Required fields:
         * * `givenName` - the user's first name
         * * `surname` - the user's last name
         * * `email` - the email address of the user
         * * `password` - the password that the user wishes to use for their
         * account.  Must meet the password requirements that you have specified
         * on the directory that this account will be created in.
         *
         * @returns {promise}
         *
         * A promise representing the operation to create a
         * new user.  If an error occurs (duplicate email, weak password), the
         * promise will be rejected and the http response will be passed.
         * If the operation is successful, the promise
         * will be resolved with a boolean `enabled` value.
         *
         * * If `true`, the account's status is Enabled and you can proceed with authenticating the user.
         *
         * * If `false`, the account's status is Unverified.
         * This will be the case when you have enabled the email verification workflow on the directory of this
         * account.
         *
         * @description
         *
         * Attempts to create a new user by submitting the given `accountData` as
         * JSON to `/register`.  The POST endpoint can be modified via the
         * {@link api/stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG#properties_REGISTER_URI REGISTER_URI}
         * config option.
         *
         * @example
         *
         * <pre>
         * $user.create(accountData)
         *   .then(function(account){
         *     if(account.status === 'ENABLED'){
         *       // The account is enabled and ready to use
         *     }else if(account.status === 'UNVERIFIED'){
         *       // The account requires email verification
         *     }
         *   })
         *   .catch(function(err){
         *     // Show the error message to the user
         *     $scope.error = err.message;
         *   });
         * </pre>
         */

        return $http({
          url: STORMPATH_CONFIG.getUrl('REGISTER_URI'),
          method: 'POST',
          data: accountData
        })
        .then(function(response){
          var account = response.data.account || response.data;
          registeredEvent(account);
          return $q.resolve(account);
        },function(httpResponse){
          return $q.reject($spErrorTransformer.transformError(httpResponse));
        });

      };
      UserService.prototype.get = function get(bypassCache) {
        /**
         * @ngdoc function
         *
         * @name get
         *
         * @methodOf stormpath.userService.$user
         *
         * @param {Boolean} [bypassCache=false]
         *
         * By default, the UserService will cache the user object after it is
         * retrieved the first time.  Specify `true` if you need to bypass this
         * cache, e.g. after updating the user's custom data.
         *
         * @returns {promise}
         *
         * A promise representing the operation to get the current user data.
         *
         * @description
         *
         * Attempt to get the current user.  Returns a promise.  If the user
         * is authenticated, the promise will be resolved with the user object.
         * If the user is not authenticated, the promise will be rejected and
         * passed the error response from the $http service.
         *
         * If you cannot make use of the promise, you can also observe the
         * {@link $notLoggedin $notLoggedin} or {@link $currentUser $currentUser}
         * events.  They are emitted when this method has a success or failure.
         *
         * The result of this operation will be cached on the {@link stormpath.userService.$user#properties_currentuser $user.currentUser}
         * property.
         *
         * The user object is a Stormpath Account object, which is wrapped by a
         * {@link eh User} type.  It is fetched from the `/me` endpoint on your
         * server, which is provided by our framework integrations.
         *
         * @example
         *
         * <pre>
         * var myApp = angular.module('myApp', ['stormpath']);
         *
         * myApp.controller('MyAppCtrl', function ($scope, $user) {
         *   $user.get()
         *     .then(function (user) {
         *       console.log('The current user is', user);
         *     })
         *     .catch(function (error) {
         *       console.log('Error getting user', error);
         *     });
         * });
         * </pre>
         *
         */
        var op = $q.defer();
        var self = this;

        if (self.cachedUserOp) {
          return self.cachedUserOp.promise;
        }

        if (self.currentUser !== null && self.currentUser!==false && bypassCache!==true) {
          op.resolve(self.currentUser);
          return op.promise;
        }

        self.cachedUserOp = op;
        var beforeLoad = self.currentUser ? $q.resolve() : $processSocialAuthToken();

        return beforeLoad.then(function() {
          $http.get(STORMPATH_CONFIG.getUrl('CURRENT_USER_URI')).then(function(response) {
            self.cachedUserOp = null;
            self.currentUser = new User(response.data.account || response.data);
            currentUserEvent(self.currentUser);
            op.resolve(self.currentUser);
          }, function(response) {
            self.currentUser = false;
            if (response.status===401) {
              notLoggedInEvent();
            }
            self.cachedUserOp = null;
            op.reject(response);
          });
          return op.promise;
        });
      };

      /**
       * @ngdoc function
       *
       * @name resendVerificationEmail
       *
       * @methodOf stormpath.userService.$user
       *
       * @returns {promise}
       *
       * An $http promise representing the operation to resend a verification token
       * to the given email address.  Will resolve, even if the email address
       * does not exist.  If rejected there was a network error.
       *
       * @description
       *
       * Re-sends the verification email to the account specified by the
       * username or email address.
       *
       * @param  {Object} data
       *
       * An object literal for passing the username or email.
       * ```
       * {
       *   username: 'email address or username'
       * }
       * ```
       */
      UserService.prototype.resendVerificationEmail = function resendVerificationEmail(data){
        return $http({
          method: 'POST',
          url: STORMPATH_CONFIG.getUrl('EMAIL_VERIFICATION_ENDPOINT'),
          data: data
        });
      };

      /**
       * @ngdoc function
       *
       * @name verify
       *
       * @methodOf stormpath.userService.$user
       *
       * @returns {promise}
       *
       * An $http promise representing the operation to verify the given
       * email verification token token.  If resolved the account has been
       * verified and can be used for login.  If rejected the token is expired
       * or has already been used.
       *
       * @param  {String} sptoken
       *
       * The value of the `sptoken` that was sent by email to the user
       *
       * @description
       *
       * Verifies a new account, using the `sptoken` that was sent to the user
       * by email.
       */
      UserService.prototype.verify = function verify(token){
        return $http({
          url: STORMPATH_CONFIG.getUrl('EMAIL_VERIFICATION_ENDPOINT') + '?sptoken='+token
        });
      };

      /**
       * @ngdoc function
       *
       * @name verifyPasswordResetToken
       *
       * @methodOf stormpath.userService.$user
       *
       * @returns {promise}
       *
       * A $http promise representing the operation to verify the given password
       * reset token token.  If resolved, the token can be used.  If rejected
       * the token cannot be used.
       *
       * @description
       *
       * Verifies a password reset token that was sent to the user by email.
       * If valid, the token can be used to reset the user's password.  If not
       * valid it means that the token has expired or has already been used.
       *
       * Use this method to verify the token, before asking the user to specify
       * a new password.  If the token is invalid the user must ask for another.
       *
       * @param  {String} sptoken
       *
       * The `sptoken` that was delivered to the user by email
       */
      UserService.prototype.verifyPasswordResetToken = function verifyPasswordResetToken(token){
        return $http({
          url: STORMPATH_CONFIG.getUrl('CHANGE_PASSWORD_ENDPOINT')+'?sptoken='+token
        });
      };

      /**
       * @ngdoc function
       *
       * @name passwordResetRequest
       *
       * @methodOf stormpath.userService.$user
       *
       * @returns {promise}
       *
       * An $http promise representing the operation to generate a password
       * reset token for the given email address.  Will resolve, even if the
       * email address does not exist.  If rejected there was a network error.
       *
       * @description
       *
       * Triggers a password reset email to the given username or email address.
       *
       * @param  {Object} data
       *
       * An object literal for passing the email address.
       * ```
       * {
       *   email: 'email address of the user'
       * }
       * ```
       */
      UserService.prototype.passwordResetRequest = function passwordResetRequest(data){
        return $http({
          method: 'POST',
          url: STORMPATH_CONFIG.getUrl('FORGOT_PASSWORD_ENDPOINT'),
          data: data
        })
        .catch(function(httpResponse){
          return $q.reject($spErrorTransformer.transformError(httpResponse));
        });
      };

      /**
       * @ngdoc function
       *
       * @name resetPassword
       *
       * @methodOf stormpath.userService.$user
       *
       * @returns {promise}
       *
       * An $http promise representing the operation to reset the password and
       * consume the token.  If resolved the password was successfully changed,
       * if rejected the token is invalid or the posted password does not meet
       * the password strength rules of the directory.
       *
       * @description
       *
       * Resets a user's password, using a token that was emailed to the user.
       *
       * @param {String} token
       *
       * The `sptoken` that was sent to the user via email.
       *
       * @param  {Object} data
       *
       * An object literal for passing the new password.  Must follow this
       * format:
       * ```
       * {
       *   password: 'the new password'
       * }
       * ```
       */
      UserService.prototype.resetPassword = function resetPassword(token,data){
        data.sptoken = token;
        return $http({
          method: 'POST',
          url:STORMPATH_CONFIG.getUrl('CHANGE_PASSWORD_ENDPOINT'),
          data: data
        })
        .catch(function(httpResponse){
          return $q.reject($spErrorTransformer.transformError(httpResponse));
        });
      };
      function registeredEvent(account){
        /**
         * @ngdoc event
         *
         * @name stormpath.userService.$user#$registered
         *
         * @eventOf stormpath.userService.$user
         *
         * @eventType broadcast on root scope
         *
         * @param {Object} event
         *
         * Angular event object.
         *
         * @param {account} account
         *
         * The object of the account that was created.
         *
         * @description
         *
         * This event is broadcast when a call to
         * {@link stormpath.userService.$user#methods_create $user.create()}
         * is successful.  The account object is returned, and you can inspec
         * the account's status to know if email verification is required.
         */
        $rootScope.$broadcast(STORMPATH_CONFIG.REGISTERED_EVENT_NAME,account);
      }
      function currentUserEvent(user){
        /**
         * @ngdoc event
         *
         * @name stormpath.userService.$user#$currentUser
         *
         * @eventOf stormpath.userService.$user
         *
         * @eventType broadcast on root scope
         *
         * @param {Object} event
         *
         * Angular event object.
         *
         * @param {User} user
         *
         * The current user object.
         *
         * @description
         *
         * This event is broadcast when a call to
         * {@link stormpath.userService.$user#methods_get $user.get()}
         * and provides the user object as the second parameter.
         *
         * See the next section, the $notLoggeInEvent, for example usage.
         */
        $rootScope.$broadcast(STORMPATH_CONFIG.GET_USER_EVENT,user);
      }
      function notLoggedInEvent(){
        /**
         * @ngdoc event
         *
         * @name stormpath.userService.$user#$notLoggedIn
         *
         * @eventOf stormpath.userService.$user
         *
         * @eventType broadcast on root scope
         *
         * @param {Object} event
         *
         * Angular event object.
         *
         * @description
         *
         * This event is broadcast when a call to
         * {@link stormpath.userService.$user#methods_get $user.get()}
         * results in an authentication failure.
         *
         * This event is useful for situations where you want to trigger
         * the call to get the current user, but need to respond to it
         * from some other place in your application.  An example could be,
         * during application bootstrap, you make a single call to get the current
         * user from the run function, then react to it inside your
         * application controller.
         *
         * @example
         *
         * <pre>
         * var myApp = angular.module('myApp', ['stormpath']);
         * myApp.run(function($user){
         *   //
         *   // Once our app is ready to run, trigger a call to $user.get()
         *   // We can then do other things while we wait for the result
         *   //
         *   $user.get();
         * });
         *
         * myApp.controller('MyAppCtrl', function ($scope, $rootScope) {
         *   $scope.isVisible = false; // Wait for authentication
         *   $rootScope.$on('$notLoggedIn',function(){
         *      $state.$go('login');
         *   });
         *   $rootScope.$on('$currentUser',function(e,user){
         *      $scope.isVisible = true;
         *   });
         *
         * });
         * </pre>
         */
        $rootScope.$broadcast(STORMPATH_CONFIG.NOT_LOGGED_IN_EVENT);
      }

      var userService = new UserService();
      $rootScope.$on(STORMPATH_CONFIG.SESSION_END_EVENT,function(){
        userService.currentUser = false;
      });
      return userService;
    }
  ];
}]);

'use strict';

/**
 * This module and factory are intentionally excluded from NG Docs.
 *
 * The factory is an internal utility used to check whether an URL is on the
 * same domain on which the SPA is hosted.
 */

angular.module('stormpath.utils', ['stormpath.CONFIG'])
.factory('$isCurrentDomain', ['$window', function($window) {
  return function(url) {
    var link = $window.document.createElement('a');
    link.href = url;

    return (link.host === "") || $window.location.host === link.host.replace(/:443$/, "");
  };
}])
.constant('$spHeaders', {
  // The placeholders in the value are replaced by the `grunt dist` command.
  'X-Stormpath-Agent': 'stormpath-sdk-angularjs/2.0.1' + ' angularjs/' + angular.version.full
})
.provider('$spErrorTransformer', [function $spErrorTransformer(){
  /**
   * This service is intentionally excluded from NG Docs.
   *
   * It is an internal utility for producing error objects from $http response
   * errors.
   */

  this.$get = [
    function formEncoderServiceFactory(){

      function ErrorTransformerService(){

      }

      ErrorTransformerService.prototype.transformError = function transformError(httpResponse){
        var errorMessage = null;

        if (httpResponse.data) {
          errorMessage = httpResponse.data.message || httpResponse.data.error;
        }

        if (!errorMessage) {
          errorMessage = 'An error occured when communicating with the server.';
        }

        var error = new Error(errorMessage);

        error.httpResponse = httpResponse;
        error.statusCode = httpResponse.status;
        return error;
      };

      return new ErrorTransformerService();
    }
  ];
}])
.provider('$spFormEncoder', [function $spFormEncoder(){
  /**
   * This service is intentionally excluded from NG Docs.
   * It is an internal utility.
   */

  this.$get = [
    function formEncoderServiceFactory(){

      function FormEncoderService(){
        var encoder = new UrlEncodedFormParser();
        this.encodeUrlForm = encoder.encode.bind(encoder);
        return this;
      }

      FormEncoderService.prototype.formPost = function formPost(httpRequest){
        var h = httpRequest.headers ? httpRequest.headers : (httpRequest.headers = {});
        h['Content-Type'] = 'application/x-www-form-urlencoded';
        httpRequest.data = this.encodeUrlForm(httpRequest.data);
        return httpRequest;
      };

      function UrlEncodedFormParser(){

        // Copy & modify from https://github.com/hapijs/qs/blob/master/lib/stringify.js

        this.delimiter = '&';
        this.arrayPrefixGenerators = {
          brackets: function (prefix) {
            return prefix + '[]';
          },
          indices: function (prefix, key) {
            return prefix + '[' + key + ']';
          },
          repeat: function (prefix) {
            return prefix;
          }
        };
        return this;
      }
      UrlEncodedFormParser.prototype.stringify = function stringify(obj, prefix, generateArrayPrefix) {

        if (obj instanceof Date) {
          obj = obj.toISOString();
        }
        else if (obj === null) {
          obj = '';
        }

        if (typeof obj === 'string' ||
          typeof obj === 'number' ||
          typeof obj === 'boolean') {

          return [encodeURIComponent(prefix) + '=' + encodeURIComponent(obj)];
        }

        var values = [];

        if (typeof obj === 'undefined') {
          return values;
        }

        var objKeys = Object.keys(obj);
        for (var i = 0, il = objKeys.length; i < il; ++i) {
          var key = objKeys[i];
          if (Array.isArray(obj)) {
            values = values.concat(this.stringify(obj[key], generateArrayPrefix(prefix, key), generateArrayPrefix));
          }
          else {
            values = values.concat(this.stringify(obj[key], prefix + '[' + key + ']', generateArrayPrefix));
          }
        }

        return values;
      };
      UrlEncodedFormParser.prototype.encode = function encode(obj, options) {

        options = options || {};
        var delimiter = typeof options.delimiter === 'undefined' ? this.delimiter : options.delimiter;

        var keys = [];

        if (typeof obj !== 'object' ||
          obj === null) {

          return '';
        }

        var arrayFormat;
        if (options.arrayFormat in this.arrayPrefixGenerators) {
          arrayFormat = options.arrayFormat;
        }
        else if ('indices' in options) {
          arrayFormat = options.indices ? 'indices' : 'repeat';
        }
        else {
          arrayFormat = 'indices';
        }

        var generateArrayPrefix = this.arrayPrefixGenerators[arrayFormat];

        var objKeys = Object.keys(obj);
        for (var i = 0, il = objKeys.length; i < il; ++i) {
          var key = objKeys[i];
          keys = keys.concat(this.stringify(obj[key], key, generateArrayPrefix));
        }

        return keys.join(delimiter);
      };

      return new FormEncoderService();
    }
  ];
}])
/**
* Intentionally excluded from the NG Docs.
*
* Shallow-transforms snake-cased keys in an object into camelCased keys
*/
.factory('$normalizeObjectKeys', function() {
  return function normalizeObjectKeys(obj) {
    var camelCasedObj = {};

    Object.keys(obj).forEach(function(key) {
      if (obj.hasOwnProperty(key)) {
        var camelCasedKey = key.replace(/_([A-Za-z])/g, function(all, char) {
          return char.toUpperCase();
        });

        camelCasedObj[camelCasedKey] = obj[key];
      }
    });

    return camelCasedObj;
  };
})

.factory('$encodeQueryParams', function() {
  return function encodeQueryParams(obj) {
    if (!angular.isObject(obj)) {
      return '';
    }

    var query = Object.keys(obj).map(function(key) {
      return encodeURIComponent(key) + '=' + encodeURIComponent(obj[key]);
    }).join('&');

    return query ? ('?' + query) : query;
  };
})

.factory('$decodeQueryParams', function() {
  return function decodeQueryParams(str) {
    if (!angular.isString(str) || str.length === 0) {
      return {};
    }

    var params = {};

    str.substr(1).split('&').forEach(function(pair) {
      var parts = pair.split('=');
      params[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
    });

    return params;
  };
})

.factory('$parseUrl', ['$decodeQueryParams', function($decodeQueryParams) {
  return function parseUrl(url) {
    var parser = document.createElement('a');
    parser.href = url;

    return {
      protocol: parser.protocol,
      hash: parser.hash,
      host: parser.hostname,
      port: parser.port,
      pathname: parser.pathname,
      query: parser.search,
      search: $decodeQueryParams(parser.search)
    };
  };
}])

.factory('$getLocalUrl', ['$location', '$parseUrl', function($location, $parseUrl) {

  return function(uri) {
    if (uri && uri.charAt(0) !== '/') {
      var parsedUri = $parseUrl(uri);
      uri = parsedUri.pathname + parsedUri.query + parsedUri.hash;
    }

    return $location.protocol()
      + '://'
      + $location.host()
      + ($location.port() ? (':' + $location.port()) : '')
      + uri;

  };
}]);

(function () {
  'use strict';

  function ViewModelService($http, STORMPATH_CONFIG) {
    this.$http = $http;
    this.STORMPATH_CONFIG = STORMPATH_CONFIG;
  }

  ViewModelService.prototype.getLoginModel = function getLoginModel() {
    return this.$http.get(this.STORMPATH_CONFIG.getUrl('AUTHENTICATION_ENDPOINT'), {
      headers: {
        'Accept': 'application/json'
      }
    }).then(function (response) {
      return response.data;
    });
  };

  ViewModelService.prototype.getRegisterModel = function getRegisterModel() {
    return this.$http.get(this.STORMPATH_CONFIG.getUrl('REGISTER_URI'), {
      headers: {
        'Accept': 'application/json'
      }
    }).then(function (response) {
      return response.data;
    });
  };

  angular.module('stormpath.viewModelService', ['stormpath.utils'])
  .provider('$viewModel', function () {
    this.$get = ['$http', 'STORMPATH_CONFIG', function viewModelFactory($http, STORMPATH_CONFIG) {
      return new ViewModelService($http, STORMPATH_CONFIG);
    }];
  });
}());
})(window, window.angular);

================================================
FILE: dist/stormpath-sdk-angularjs.tpls.js
================================================
/**
 * stormpath-sdk-angularjs
 * Copyright Stormpath, Inc. 2017
 * 
 * @version v2.0.1-dev-2017-04-04
 * @link https://github.com/stormpath/stormpath-sdk-angularjs
 * @license Apache-2.0
 */

/* commonjs package manager support (eg componentjs) */
if (typeof module !== "undefined" && typeof exports !== "undefined" && module.exports === exports){
  module.exports = 'stormpath.templates';
}

(function (window, angular, undefined) {

angular.module('stormpath.templates', ['spEmailVerification.tpl.html', 'spLoginForm.tpl.html', 'spPasswordResetForm.tpl.html', 'spPasswordResetRequestForm.tpl.html', 'spRegistrationForm.tpl.html']);

angular.module("spEmailVerification.tpl.html", []).run(["$templateCache", function ($templateCache) {
  $templateCache.put("spEmailVerification.tpl.html",
    "<div class=row><div class=\"col-sm-offset-4 col-xs-12 col-sm-4\"><p ng-show=verifying class=\"alert alert-warning\">We are verifying your account</p><p ng-show=verified class=\"alert alert-success\">Your account has has been verified! <a href=/login>Login Now.</a></p><p ng-show=reVerificationSent class=\"alert alert-success\">We have sent a new verification message to your email address, please check your email for this message.</p><div ng-show=showVerificationError class=\"alert alert-danger\">This email verification link is not valid. If you need us to re-send an email verification message, please enter your email address or username below.</div><div ng-show=resendFailed class=\"alert alert-danger\">Sorry, there was a problem with that email or username. Please try again.</div></div></div><div class=row><div class=col-xs-12><form class=form-horizontal ng-show=\"needsReVerification && !reVerificationSent\" ng-submit=submit()><div class=form-group><label for=spEmail class=\"col-xs-12 col-sm-4 control-label\">Email or Username</label><div class=\"col-xs-12 col-sm-4\"><input class=form-control id=spUsername ng-model=formModel.username placeholder=\"Username or Email\" ng-disabled=posting></div></div><div class=form-group><div class=\"col-sm-offset-4 col-xs-12\"><p class=text-danger ng-show=error ng-bind=error></p><button type=submit class=\"btn btn-primary\" ng-disabled=posting>Re-Send Verification</button></div></div></form></div></div>");
}]);

angular.module("spLoginForm.tpl.html", []).run(["$templateCache", function ($templateCache) {
  $templateCache.put("spLoginForm.tpl.html",
    "<style>.btn.btn-social {\n" +
    "    margin-right: 7px;\n" +
    "    min-width: 100px;\n" +
    "  }\n" +
    "\n" +
    "  .btn.btn-facebook {\n" +
    "    color: white;\n" +
    "    background-color: #3B5998;\n" +
    "    border-color: #37528C;\n" +
    "  }\n" +
    "  .btn.btn-facebook:hover,\n" +
    "  .btn.btn-facebook:focus {\n" +
    "    color: white;\n" +
    "    background-color: #2F487B;\n" +
    "    border-color: #2F487B;\n" +
    "  }\n" +
    "\n" +
    "  .btn.btn-google {\n" +
    "    color: white;\n" +
    "    background-color: #dc4e41;\n" +
    "    border-color: #C1453A;\n" +
    "  }\n" +
    "  .btn.btn-google:hover,\n" +
    "  .btn.btn-google:focus {\n" +
    "    color: white;\n" +
    "    background-color: #C74539;\n" +
    "    border-color: #AF4138;\n" +
    "  }\n" +
    "\n" +
    "  .sp-loading {\n" +
    "    text-align: center;\n" +
    "  }</style><div class=row><div class=col-xs-12><div ng-show=!viewModel class=sp-loading>Loading...</div><form class=form-horizontal ng-hide=\"accepted || !viewModel\" ng-submit=submit()><div class=form-group ng-repeat=\"field in viewModel.form.fields\"><label for=sp-{{field.name}} class=\"col-xs-12 col-sm-4 control-label\">{{field.label}}</label><div class=\"col-xs-12 col-sm-4\"><input class=form-control name={{field.name}} id=sp-{{field.name}} type={{field.type}} ng-model=formModel[field.name] placeholder={{field.placeholder}} ng-disabled=posting ng-required=field.required></div></div><div class=form-group><div class=\"col-sm-offset-4 col-sm-4\"><p class=text-danger ng-show=error ng-bind=error></p><button type=submit class=\"btn btn-primary\" ng-disabled=posting>Login</button> <a href=/forgot class=pull-right>Forgot Password</a></div></div><div class=form-group ng-show=viewModel.accountStores.length><div class=\"col-sm-offset-4 col-sm-4\"><p>Or login with:</p><button ng-repeat=\"accountStore in viewModel.accountStores\" type=button class=\"btn btn-social btn-{{accountStore.provider.providerId}}\" sp-social-login=accountStore sp-options={{accountStore.provider}} style=\"text-transform: capitalize\">{{providerName}}</button></div></div></form></div></div>");
}]);

angular.module("spPasswordResetForm.tpl.html", []).run(["$templateCache", function ($templateCache) {
  $templateCache.put("spPasswordResetForm.tpl.html",
    "<div class=row><div class=\"col-sm-offset-4 col-xs-12 col-sm-4\"><p ng-show=verifying class=\"alert alert-warning text-center\">We are verifying this link</p><p class=\"alert alert-success\" ng-show=reset>Your new password has been set. Please <a href=/login>Login Now</a>.</p><div ng-show=showVerificationError class=\"alert alert-danger\">This password reset link is not valid. You may request another link by <a href=/forgot>clicking here</a>.</div></div></div><div class=row><div class=col-xs-12><form class=form-horizontal ng-show=\"verified && !reset\" ng-submit=submit()><div class=form-group><label for=spEmail class=\"col-xs-12 col-sm-4 control-label\">New Password</label><div class=\"col-xs-12 col-sm-4\"><input class=form-control id=spUsername ng-model=formModel.password placeholder=\"New Password\" type=password ng-disabled=posting></div></div><div class=form-group><label for=spEmail class=\"col-xs-12 col-sm-4 control-label\">Confirm New Password</label><div class=\"col-xs-12 col-sm-4\"><input class=form-control id=spUsername ng-model=formModel.confirmPassword placeholder=\"Confirm New Password\" type=password ng-disabled=posting></div></div><div class=form-group><div class=\"col-sm-offset-4 col-sm-4\"><p class=\"alert alert-danger\" ng-show=error ng-bind=error></p><button type=submit class=\"btn btn-primary\" ng-disabled=posting>Set New Password</button></div></div></form></div></div>");
}]);

angular.module("spPasswordResetRequestForm.tpl.html", []).run(["$templateCache", function ($templateCache) {
  $templateCache.put("spPasswordResetRequestForm.tpl.html",
    "<div class=row><div class=\"col-sm-offset-4 col-xs-12 col-sm-4\"><p ng-show=sent class=\"alert alert-success\">We have sent a password reset link to the email address of the account that you specified. Please check your email for this message, then click on the link.</p><p ng-show=sent class=pull-right><a href=/login>Back to Login</a></p><div ng-show=error class=\"alert alert-danger\" ng-bind=error></div></div></div><div class=row><div class=col-xs-12><form class=form-horizontal ng-hide=sent ng-submit=submit()><div class=form-group><label for=spEmail class=\"col-xs-12 col-sm-4 control-label\">Email or Username</label><div class=\"col-xs-12 col-sm-4\"><input class=form-control id=spEmail ng-model=formModel.email placeholder=\"Your Email Address\" ng-disabled=posting></div></div><div class=form-group><div class=\"col-sm-offset-4 col-xs-12\"><p class=text-danger ng-show=error ng-bind=error></p><button type=submit class=\"btn btn-primary\" ng-disabled=posting>Request Password Reset</button></div></div></form></div></div>");
}]);

angular.module("spRegistrationForm.tpl.html", []).run(["$templateCache", function ($templateCache) {
  $templateCache.put("spRegistrationForm.tpl.html",
    "<style>.btn.btn-social {\n" +
    "    margin-right: 7px;\n" +
    "    min-width: 100px;\n" +
    "  }\n" +
    "\n" +
    "  .btn.btn-facebook {\n" +
    "    color: white;\n" +
    "    background-color: #3B5998;\n" +
    "    border-color: #37528C;\n" +
    "  }\n" +
    "  .btn.btn-facebook:hover,\n" +
    "  .btn.btn-facebook:focus {\n" +
    "    color: white;\n" +
    "    background-color: #2F487B;\n" +
    "    border-color: #2F487B;\n" +
    "  }\n" +
    "\n" +
    "  .btn.btn-google {\n" +
    "    color: white;\n" +
    "    background-color: #dc4e41;\n" +
    "    border-color: #C1453A;\n" +
    "  }\n" +
    "  .btn.btn-google:hover,\n" +
    "  .btn.btn-google:focus {\n" +
    "    color: white;\n" +
    "    background-color: #C74539;\n" +
    "    border-color: #AF4138;\n" +
    "  }\n" +
    "\n" +
    "  .sp-loading {\n" +
    "    text-align: center;\n" +
    "  }</style><div class=row><div class=\"col-sm-offset-4 col-xs-12 col-sm-4\"><p class=\"alert alert-success\" ng-show=\"created && !enabled\">Your account has been created. Please check your email for a verification link.</p><p ng-show=\"created && !enabled\" class=pull-right><a href=/login>Back to Login</a></p><p class=\"alert alert-success\" ng-show=\"created && enabled && !authenticating\">Your account has been created. <a href=/login>Login Now</a>.</p></div></div><div class=row><div class=col-xs-12><div ng-show=!viewModel class=sp-loading>Loading...</div><form class=form-horizontal ng-hide=\"!viewModel || (created && !authenticating)\" ng-submit=submit()><div class=form-group ng-repeat=\"field in viewModel.form.fields\"><label for=sp-{{field.name}} class=\"col-xs-12 col-sm-4 control-label\">{{field.label}}</label><div class=\"col-xs-12 col-sm-4\"><input class=form-control name={{field.name}} id=sp-{{field.name}} type={{field.type}} ng-model=formModel[field.name] placeholder={{field.placeholder}} ng-disabled=creating ng-required=field.required></div></div><div class=form-group><div class=\"col-sm-offset-4 col-sm-4\"><p class=\"alert alert-danger\" ng-show=error ng-bind=error></p><button type=submit class=\"btn btn-primary\" ng-disabled=creating>Register</button></div></div><div class=form-group ng-show=viewModel.accountStores.length><div class=\"col-sm-offset-4 col-sm-4\"><p>Or register with:</p><button ng-repeat=\"accountStore in viewModel.accountStores\" type=button class=\"btn btn-social btn-{{accountStore.provider.providerId}}\" sp-social-login=accountStore sp-options={{accountStore.provider}} style=\"text-transform: capitalize\">{{providerName}}</button></div></div></form></div></div>");
}]);
})(window, window.angular);


================================================
FILE: docs/Makefile
================================================
# Makefile for Sphinx documentation
#

# You can set these variables from the command line.
SPHINXOPTS    =
SPHINXBUILD   = sphinx-build
PAPER         =
BUILDDIR      = build

# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif

# Internal variables.
PAPEROPT_a4     = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source

.PHONY: help
Download .txt
gitextract_pr66l4um/

├── .gitignore
├── .gitmodules
├── .jshintrc
├── .npmignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Gruntfile.js
├── LICENSE
├── OLD-README.md
├── README.md
├── TROUBLESHOOTING.md
├── bower.json
├── dist/
│   ├── stormpath-sdk-angularjs.js
│   └── stormpath-sdk-angularjs.tpls.js
├── docs/
│   ├── Makefile
│   ├── render
│   └── source/
│       ├── access_control.rst
│       ├── conf.py
│       ├── configure_angular.rst
│       ├── create_new_project.rst
│       ├── create_tenant.rst
│       ├── customize_menu.rst
│       ├── index.rst
│       ├── introduction.rst
│       ├── login.rst
│       ├── password_reset.rst
│       ├── protect_api.rst
│       ├── register.rst
│       ├── support.rst
│       ├── user_profile.rst
│       └── wait_for_user.rst
├── example/
│   ├── cors-app/
│   │   ├── .bowerrc
│   │   ├── README.md
│   │   ├── bower.json
│   │   ├── client/
│   │   │   ├── client.js
│   │   │   └── index.html
│   │   ├── package.json
│   │   └── server.js
│   ├── dashboard-app/
│   │   ├── .bowerrc
│   │   ├── .buildignore
│   │   ├── .editorconfig
│   │   ├── .gitattributes
│   │   ├── .gitignore
│   │   ├── .travis.yml
│   │   ├── .yo-rc.json
│   │   ├── Gruntfile.js
│   │   ├── README.md
│   │   ├── bower.json
│   │   ├── client/
│   │   │   ├── .htaccess
│   │   │   ├── .jshintrc
│   │   │   ├── app/
│   │   │   │   ├── app.css
│   │   │   │   ├── app.js
│   │   │   │   ├── forgot/
│   │   │   │   │   ├── forgot.controller.js
│   │   │   │   │   ├── forgot.controller.spec.js
│   │   │   │   │   ├── forgot.css
│   │   │   │   │   ├── forgot.html
│   │   │   │   │   └── forgot.js
│   │   │   │   ├── login/
│   │   │   │   │   ├── login.controller.js
│   │   │   │   │   ├── login.controller.spec.js
│   │   │   │   │   ├── login.css
│   │   │   │   │   ├── login.html
│   │   │   │   │   └── login.js
│   │   │   │   ├── main/
│   │   │   │   │   ├── main.controller.js
│   │   │   │   │   ├── main.controller.spec.js
│   │   │   │   │   ├── main.css
│   │   │   │   │   ├── main.html
│   │   │   │   │   └── main.js
│   │   │   │   ├── profile/
│   │   │   │   │   ├── profile.controller.js
│   │   │   │   │   ├── profile.controller.spec.js
│   │   │   │   │   ├── profile.css
│   │   │   │   │   ├── profile.html
│   │   │   │   │   └── profile.js
│   │   │   │   ├── register/
│   │   │   │   │   ├── register.controller.js
│   │   │   │   │   ├── register.controller.spec.js
│   │   │   │   │   ├── register.css
│   │   │   │   │   ├── register.html
│   │   │   │   │   └── register.js
│   │   │   │   ├── reset/
│   │   │   │   │   ├── reset.controller.js
│   │   │   │   │   ├── reset.controller.spec.js
│   │   │   │   │   ├── reset.css
│   │   │   │   │   ├── reset.html
│   │   │   │   │   └── reset.js
│   │   │   │   └── verify/
│   │   │   │       ├── verify.controller.js
│   │   │   │       ├── verify.controller.spec.js
│   │   │   │       ├── verify.css
│   │   │   │       ├── verify.html
│   │   │   │       └── verify.js
│   │   │   ├── components/
│   │   │   │   └── navbar/
│   │   │   │       ├── navbar.controller.js
│   │   │   │       └── navbar.html
│   │   │   ├── index.html
│   │   │   └── robots.txt
│   │   ├── e2e/
│   │   │   └── main/
│   │   │       ├── main.po.js
│   │   │       └── main.spec.js
│   │   ├── karma.conf.js
│   │   ├── package.json
│   │   ├── protractor.conf.js
│   │   └── server/
│   │       ├── .jshintrc
│   │       ├── .jshintrc-spec
│   │       ├── api/
│   │       │   └── thing/
│   │       │       ├── index.js
│   │       │       ├── thing.controller.js
│   │       │       └── thing.spec.js
│   │       ├── app.js
│   │       ├── components/
│   │       │   └── errors/
│   │       │       └── index.js
│   │       ├── config/
│   │       │   ├── environment/
│   │       │   │   ├── development.js
│   │       │   │   ├── index.js
│   │       │   │   ├── production.js
│   │       │   │   └── test.js
│   │       │   ├── express.js
│   │       │   └── local.env.sample.js
│   │       ├── routes.js
│   │       └── views/
│   │           └── 404.html
│   └── ng-route-app/
│       ├── .bowerrc
│       ├── .buildignore
│       ├── .editorconfig
│       ├── .gitattributes
│       ├── .gitignore
│       ├── .travis.yml
│       ├── .yo-rc.json
│       ├── Gruntfile.js
│       ├── README.md
│       ├── bower.json
│       ├── client/
│       │   ├── .htaccess
│       │   ├── .jshintrc
│       │   ├── app/
│       │   │   ├── app.css
│       │   │   ├── app.js
│       │   │   ├── forgot/
│       │   │   │   ├── forgot.controller.js
│       │   │   │   ├── forgot.controller.spec.js
│       │   │   │   ├── forgot.css
│       │   │   │   ├── forgot.html
│       │   │   │   └── forgot.js
│       │   │   ├── login/
│       │   │   │   ├── login.controller.js
│       │   │   │   ├── login.controller.spec.js
│       │   │   │   ├── login.css
│       │   │   │   ├── login.html
│       │   │   │   └── login.js
│       │   │   ├── main/
│       │   │   │   ├── main.controller.js
│       │   │   │   ├── main.controller.spec.js
│       │   │   │   ├── main.css
│       │   │   │   ├── main.html
│       │   │   │   └── main.js
│       │   │   ├── profile/
│       │   │   │   ├── profile.controller.js
│       │   │   │   ├── profile.controller.spec.js
│       │   │   │   ├── profile.css
│       │   │   │   ├── profile.html
│       │   │   │   └── profile.js
│       │   │   ├── register/
│       │   │   │   ├── register.controller.js
│       │   │   │   ├── register.controller.spec.js
│       │   │   │   ├── register.css
│       │   │   │   ├── register.html
│       │   │   │   └── register.js
│       │   │   ├── reset/
│       │   │   │   ├── reset.controller.js
│       │   │   │   ├── reset.controller.spec.js
│       │   │   │   ├── reset.css
│       │   │   │   ├── reset.html
│       │   │   │   └── reset.js
│       │   │   └── verify/
│       │   │       ├── verify.controller.js
│       │   │       ├── verify.controller.spec.js
│       │   │       ├── verify.css
│       │   │       ├── verify.html
│       │   │       └── verify.js
│       │   ├── components/
│       │   │   └── navbar/
│       │   │       ├── navbar.controller.js
│       │   │       └── navbar.html
│       │   ├── index.html
│       │   └── robots.txt
│       ├── e2e/
│       │   └── main/
│       │       ├── main.po.js
│       │       └── main.spec.js
│       ├── karma.conf.js
│       ├── package.json
│       ├── protractor.conf.js
│       └── server/
│           ├── .jshintrc
│           ├── .jshintrc-spec
│           ├── api/
│           │   └── thing/
│           │       ├── index.js
│           │       ├── thing.controller.js
│           │       └── thing.spec.js
│           ├── app.js
│           ├── components/
│           │   └── errors/
│           │       └── index.js
│           ├── config/
│           │   ├── environment/
│           │   │   ├── development.js
│           │   │   ├── index.js
│           │   │   ├── production.js
│           │   │   └── test.js
│           │   ├── express.js
│           │   └── local.env.sample.js
│           ├── routes.js
│           └── views/
│               └── 404.html
├── index.js
├── ngdoc_assets/
│   ├── example/
│   │   └── index.ngdoc
│   ├── index.ngdoc
│   ├── nav.html
│   ├── server/
│   │   └── index.ngdoc
│   └── stormpath-angular.css
├── package.json
├── protractor.conf.js
├── src/
│   ├── module.js
│   ├── spEmailVerification.tpl.html
│   ├── spLoginForm.tpl.html
│   ├── spPasswordResetForm.tpl.html
│   ├── spPasswordResetRequestForm.tpl.html
│   ├── spRegistrationForm.tpl.html
│   ├── stormpath.auth.js
│   ├── stormpath.config.js
│   ├── stormpath.emailverification.js
│   ├── stormpath.login.js
│   ├── stormpath.oauth.js
│   ├── stormpath.passwordreset.js
│   ├── stormpath.registration.js
│   ├── stormpath.social-login.js
│   ├── stormpath.tokenStore.js
│   ├── stormpath.user.js
│   ├── stormpath.utils.js
│   └── stormpath.view-model.js
└── test/
    ├── .jshintrc
    └── protractor/
        └── login.js
Download .txt
SYMBOL INDEX (66 symbols across 11 files)

FILE: dist/stormpath-sdk-angularjs.js
  function StormpathAgentInterceptor (line 210) | function StormpathAgentInterceptor(){
  function StormpathService (line 269) | function StormpathService(){
  function stateChangeUnauthenticatedEvent (line 283) | function stateChangeUnauthenticatedEvent(toState, toParams){
  function stateChangeUnauthorizedEvent (line 323) | function stateChangeUnauthorizedEvent(toState,toParams){
  function authorizeStateConfig (line 418) | function authorizeStateConfig(spStateConfig, authorities){
  function routeChangeUnauthenticatedEvent (line 435) | function routeChangeUnauthenticatedEvent(toRoute) {
  function routeChangeUnauthorizedEvent (line 473) | function routeChangeUnauthorizedEvent(toRoute) {
  function goToRoute (line 514) | function goToRoute(route) {
  function authorizeRouteConfig (line 574) | function authorizeRouteConfig(spRouteConfig) {
  function UrlEncodedFormParser (line 768) | function UrlEncodedFormParser(){
  function evalElement (line 1014) | function evalElement(){
  function evalElement (line 1072) | function evalElement(){
  function AuthService (line 1267) | function AuthService(){
  function success (line 1350) | function success(httpResponse){
  function error (line 1356) | function error(httpResponse){
  function endSessionEvent (line 1411) | function endSessionEvent () {
  function authenticatedEvent (line 1455) | function authenticatedEvent(response){
  function authenticationFailureEvent (line 1482) | function authenticationFailureEvent(response){
  function StormpathOAuthToken (line 2321) | function StormpathOAuthToken() {
  function StormpathOAuth (line 2509) | function StormpathOAuth() {
  function StormpathOAuthInterceptor (line 2664) | function StormpathOAuthInterceptor() {}
  function SocialLoginService (line 3067) | function SocialLoginService(STORMPATH_CONFIG, $encodeQueryParams, $getLo...
  function LocalStorageTokenStore (line 3413) | function LocalStorageTokenStore() {
  function User (line 3574) | function User(data){
  function UserService (line 3615) | function UserService(){
  function registeredEvent (line 3978) | function registeredEvent(account){
  function currentUserEvent (line 4005) | function currentUserEvent(user){
  function notLoggedInEvent (line 4033) | function notLoggedInEvent(){
  function ErrorTransformerService (line 4129) | function ErrorTransformerService(){
  function FormEncoderService (line 4164) | function FormEncoderService(){
  function UrlEncodedFormParser (line 4177) | function UrlEncodedFormParser(){
  function ViewModelService (line 4360) | function ViewModelService($http, STORMPATH_CONFIG) {

FILE: example/dashboard-app/server/config/environment/index.js
  function requiredProcessEnv (line 6) | function requiredProcessEnv(name) {

FILE: example/ng-route-app/server/config/environment/index.js
  function requiredProcessEnv (line 6) | function requiredProcessEnv(name) {

FILE: src/module.js
  function StormpathAgentInterceptor (line 195) | function StormpathAgentInterceptor(){
  function StormpathService (line 254) | function StormpathService(){
  function stateChangeUnauthenticatedEvent (line 268) | function stateChangeUnauthenticatedEvent(toState, toParams){
  function stateChangeUnauthorizedEvent (line 308) | function stateChangeUnauthorizedEvent(toState,toParams){
  function authorizeStateConfig (line 403) | function authorizeStateConfig(spStateConfig, authorities){
  function routeChangeUnauthenticatedEvent (line 420) | function routeChangeUnauthenticatedEvent(toRoute) {
  function routeChangeUnauthorizedEvent (line 458) | function routeChangeUnauthorizedEvent(toRoute) {
  function goToRoute (line 499) | function goToRoute(route) {
  function authorizeRouteConfig (line 559) | function authorizeRouteConfig(spRouteConfig) {
  function UrlEncodedFormParser (line 753) | function UrlEncodedFormParser(){
  function evalElement (line 999) | function evalElement(){
  function evalElement (line 1057) | function evalElement(){

FILE: src/stormpath.auth.js
  function AuthService (line 39) | function AuthService(){
  function success (line 122) | function success(httpResponse){
  function error (line 128) | function error(httpResponse){
  function endSessionEvent (line 183) | function endSessionEvent () {
  function authenticatedEvent (line 227) | function authenticatedEvent(response){
  function authenticationFailureEvent (line 254) | function authenticationFailureEvent(response){

FILE: src/stormpath.oauth.js
  function StormpathOAuthToken (line 68) | function StormpathOAuthToken() {
  function StormpathOAuth (line 256) | function StormpathOAuth() {
  function StormpathOAuthInterceptor (line 411) | function StormpathOAuthInterceptor() {}

FILE: src/stormpath.social-login.js
  function SocialLoginService (line 26) | function SocialLoginService(STORMPATH_CONFIG, $encodeQueryParams, $getLo...

FILE: src/stormpath.tokenStore.js
  function LocalStorageTokenStore (line 183) | function LocalStorageTokenStore() {

FILE: src/stormpath.user.js
  function User (line 38) | function User(data){
  function UserService (line 79) | function UserService(){
  function registeredEvent (line 442) | function registeredEvent(account){
  function currentUserEvent (line 469) | function currentUserEvent(user){
  function notLoggedInEvent (line 497) | function notLoggedInEvent(){

FILE: src/stormpath.utils.js
  function ErrorTransformerService (line 34) | function ErrorTransformerService(){
  function FormEncoderService (line 69) | function FormEncoderService(){
  function UrlEncodedFormParser (line 82) | function UrlEncodedFormParser(){

FILE: src/stormpath.view-model.js
  function ViewModelService (line 4) | function ViewModelService($http, STORMPATH_CONFIG) {
Condensed preview — 212 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (614K chars).
[
  {
    "path": ".gitignore",
    "chars": 47,
    "preview": "node_modules\nbower_components\nbuild\n.tmp\n.idea\n"
  },
  {
    "path": ".gitmodules",
    "chars": 145,
    "preview": "[submodule \"docs/source/_themes/stormpath\"]\n\tpath = docs/source/_themes/stormpath\n\turl = https://github.com/stormpath/st"
  },
  {
    "path": ".jshintrc",
    "chars": 394,
    "preview": "{\n  \"node\": true,\n  \"browser\": true,\n  \"esnext\": true,\n  \"bitwise\": true,\n  \"camelcase\": true,\n  \"curly\": true,\n  \"eqeqe"
  },
  {
    "path": ".npmignore",
    "chars": 35,
    "preview": "app\ndocs\nexample\nngdoc_assets\ntest\n"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 12887,
    "preview": "# 2.0.1\n\nFixed a bug in `$isCurrentDomain` that would incorrectly report a cross-domain situation in IE11.\n\n# 2.0.0\n\nThi"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 1658,
    "preview": "# Contribution Guide\n\nWe love pull requests!\n\nHere are a few things you'll need to know if you want to make a contributi"
  },
  {
    "path": "Gruntfile.js",
    "chars": 6437,
    "preview": "// Generated on 2015-01-02 using generator-angular-fullstack 2.0.13\n'use strict';\n\nmodule.exports = function (grunt) {\n "
  },
  {
    "path": "LICENSE",
    "chars": 11347,
    "preview": "\n\n                                 Apache License\n                           Version 2.0, January 2004\n                 "
  },
  {
    "path": "OLD-README.md",
    "chars": 14434,
    "preview": "# Stormpath is Joining Okta\nWe are incredibly excited to announce that [Stormpath is joining forces with Okta](https://s"
  },
  {
    "path": "README.md",
    "chars": 1838,
    "preview": "# Stormpath is Joining Okta\nWe are incredibly excited to announce that [Stormpath is joining forces with Okta](https://s"
  },
  {
    "path": "TROUBLESHOOTING.md",
    "chars": 715,
    "preview": "# Troubleshooting\n\nThis document contains a list of common problems that you may run into while\nworking with this librar"
  },
  {
    "path": "bower.json",
    "chars": 514,
    "preview": "{\n  \"name\": \"stormpath-sdk-angularjs\",\n  \"version\": \"2.0.1\",\n  \"main\": [\n    \"dist/stormpath-sdk-angularjs.min.js\",\n    "
  },
  {
    "path": "dist/stormpath-sdk-angularjs.js",
    "chars": 136561,
    "preview": "/**\n * stormpath-sdk-angularjs\n * Copyright Stormpath, Inc. 2017\n * \n * @version v2.0.1-dev-2017-04-04\n * @link https://"
  },
  {
    "path": "dist/stormpath-sdk-angularjs.tpls.js",
    "chars": 10195,
    "preview": "/**\n * stormpath-sdk-angularjs\n * Copyright Stormpath, Inc. 2017\n * \n * @version v2.0.1-dev-2017-04-04\n * @link https://"
  },
  {
    "path": "docs/Makefile",
    "chars": 6831,
    "preview": "# Makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS    =\nSPHINXBUILD "
  },
  {
    "path": "docs/render",
    "chars": 34,
    "preview": "#!/bin/bash\n\nmake clean\nmake html\n"
  },
  {
    "path": "docs/source/access_control.rst",
    "chars": 2913,
    "preview": ".. _access_control:\n\nAccess Control\n===================\n\nParts of your application may only be available to certain user"
  },
  {
    "path": "docs/source/conf.py",
    "chars": 8311,
    "preview": "# -*- coding: utf-8 -*-\n#\n# stormpath-sdk-angular documentation build configuration file, created by\n# sphinx-quickstart"
  },
  {
    "path": "docs/source/configure_angular.rst",
    "chars": 2219,
    "preview": ".. _configure_angular:\n\nConfigure the Angular Application\n---------------------------------\n\nThere are a few things we n"
  },
  {
    "path": "docs/source/create_new_project.rst",
    "chars": 4366,
    "preview": ".. _create_new_project:\n\nCreating a Fullstack Project\n============================\n\nThis part of the guide will walk you"
  },
  {
    "path": "docs/source/create_tenant.rst",
    "chars": 2124,
    "preview": ".. _create_tenant:\n\nCreate a Stormpath Tenant\n==============================\n\nIf you have already signed up for Stormpat"
  },
  {
    "path": "docs/source/customize_menu.rst",
    "chars": 1971,
    "preview": ".. _customize_menu:\n\nCustomize the Menu\n===================\n\nNow that our Angular application is configured, let's get o"
  },
  {
    "path": "docs/source/index.rst",
    "chars": 1228,
    "preview": ".. stormpath-sdk-angular documentation master file, created by\n   sphinx-quickstart on Mon Feb 16 11:15:30 2015.\n   You "
  },
  {
    "path": "docs/source/introduction.rst",
    "chars": 2417,
    "preview": ".. _introduction:\n\nIntroduction\n=============\n\nThe purpose of this guide is to walk you through the creation of an Angul"
  },
  {
    "path": "docs/source/login.rst",
    "chars": 2502,
    "preview": ".. _login:\n\nCreate the Login Form\n=====================\n\nLogin forms are pretty straightforward, why re-invent the wheel"
  },
  {
    "path": "docs/source/password_reset.rst",
    "chars": 3592,
    "preview": ".. _password_reset:\n\nPassword Reset Flow\n===================\n\nStormpath provides a secure solution that allows your user"
  },
  {
    "path": "docs/source/protect_api.rst",
    "chars": 3907,
    "preview": ".. _protect_api:\n\nConfigure the Server\n====================\n\nIn the previous section, :ref:`create_new_project`, we crea"
  },
  {
    "path": "docs/source/register.rst",
    "chars": 8804,
    "preview": ".. _register:\n\nCreate the Registration Form\n============================\n\nWe want our users to sign up for our service s"
  },
  {
    "path": "docs/source/support.rst",
    "chars": 351,
    "preview": ".. _support:\n\nSupport\n==============\n\nWe're here to help if you get stuck.  There are several ways that you an get in\nto"
  },
  {
    "path": "docs/source/user_profile.rst",
    "chars": 3024,
    "preview": ".. _user_dashboard:\n\nCreate the Profile View\n=======================\n\nMost user-centric applications have a Profile view"
  },
  {
    "path": "docs/source/wait_for_user.rst",
    "chars": 1670,
    "preview": ".. _wait_for_user:\n\nWaiting For User State\n=======================\n\nNow that we have a complete application, you should "
  },
  {
    "path": "example/cors-app/.bowerrc",
    "chars": 47,
    "preview": "{\n    \"directory\": \"client/bower_components\"\n}\n"
  },
  {
    "path": "example/cors-app/README.md",
    "chars": 1618,
    "preview": "# Stormpath Angular + Express + CORS\n\nThis folder contains an example application that is built with the\n[Stormpath Angu"
  },
  {
    "path": "example/cors-app/bower.json",
    "chars": 495,
    "preview": "{\n  \"name\": \"cors-app\",\n  \"homepage\": \"https://github.com/stormpath/stormpath-sdk-angularjs\",\n  \"authors\": [\n    \"Robert"
  },
  {
    "path": "example/cors-app/client/client.js",
    "chars": 629,
    "preview": "'use strict';\n\nangular.module('loginApp',[\n  'stormpath',\n  'stormpath.templates'\n])\n.config(['STORMPATH_CONFIG',functio"
  },
  {
    "path": "example/cors-app/client/index.html",
    "chars": 1000,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n  <title>CORS Demo Application</title>\n  <link rel=\"stylesheet\" href=\"bower_components/boo"
  },
  {
    "path": "example/cors-app/package.json",
    "chars": 364,
    "preview": "{\n  \"name\": \"cors-app\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"server.js\",\n  \"scripts\": {\n    \"test\": \"ec"
  },
  {
    "path": "example/cors-app/server.js",
    "chars": 1263,
    "preview": "var cors = require('cors');\nvar express = require('express');\nvar stormpath = require('express-stormpath');\nvar open = r"
  },
  {
    "path": "example/dashboard-app/.bowerrc",
    "chars": 47,
    "preview": "{\n    \"directory\": \"client/bower_components\"\n}\n"
  },
  {
    "path": "example/dashboard-app/.buildignore",
    "chars": 8,
    "preview": "*.coffee"
  },
  {
    "path": "example/dashboard-app/.editorconfig",
    "chars": 415,
    "preview": "# EditorConfig helps developers define and maintain consistent\n# coding styles between different editors and IDEs\n# edit"
  },
  {
    "path": "example/dashboard-app/.gitattributes",
    "chars": 11,
    "preview": "* text=auto"
  },
  {
    "path": "example/dashboard-app/.gitignore",
    "chars": 102,
    "preview": "node_modules\npublic\n.tmp\n.idea\nclient/bower_components\ndist\n/server/config/local.env.js\nstormpath.yml\n"
  },
  {
    "path": "example/dashboard-app/.travis.yml",
    "chars": 134,
    "preview": "language: node_js\nnode_js:\n  - '0.10'\n  - '0.11'\nbefore_script:\n  - npm install -g bower grunt-cli\n  - bower install\nser"
  },
  {
    "path": "example/dashboard-app/.yo-rc.json",
    "chars": 1118,
    "preview": "{\n  \"generator-angular-fullstack\": {\n    \"insertRoutes\": true,\n    \"registerRoutesFile\": \"server/routes.js\",\n    \"routes"
  },
  {
    "path": "example/dashboard-app/Gruntfile.js",
    "chars": 15346,
    "preview": "// Generated on 2015-09-24 using generator-angular-fullstack 2.0.13\n'use strict';\n\nmodule.exports = function (grunt) {\n "
  },
  {
    "path": "example/dashboard-app/README.md",
    "chars": 1268,
    "preview": "# Stormpath Angular SDK Example\n\nThis folder contains an example application that is built with the [Stormpath Angular S"
  },
  {
    "path": "example/dashboard-app/bower.json",
    "chars": 529,
    "preview": "{\n  \"name\": \"dashboard\",\n  \"version\": \"0.0.0\",\n  \"dependencies\": {\n    \"angular\": \">=1.2.*\",\n    \"json3\": \"~3.3.1\",\n    "
  },
  {
    "path": "example/dashboard-app/client/.htaccess",
    "chars": 24135,
    "preview": "# Apache Configuration File\n\n# (!) Using `.htaccess` files slows down Apache, therefore, if you have access\n# to the mai"
  },
  {
    "path": "example/dashboard-app/client/.jshintrc",
    "chars": 664,
    "preview": "{\n  \"node\": true,\n  \"browser\": true,\n  \"esnext\": true,\n  \"bitwise\": true,\n  \"camelcase\": true,\n  \"curly\": true,\n  \"eqeqe"
  },
  {
    "path": "example/dashboard-app/client/app/app.css",
    "chars": 1395,
    "preview": "\n/**\n * Bootstrap Fonts\n */\n\n@font-face {\n    font-family: 'Glyphicons Halflings';\n    src: url('../bower_components/boo"
  },
  {
    "path": "example/dashboard-app/client/app/app.js",
    "chars": 932,
    "preview": "'use strict';\n\nangular.module('dashboardApp', [\n  'ngCookies',\n  'ngResource',\n  'ngSanitize',\n  'ui.router',\n  'stormpa"
  },
  {
    "path": "example/dashboard-app/client/app/forgot/forgot.controller.js",
    "chars": 130,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .controller('ForgotCtrl', function ($scope) {\n    $scope.message = 'Hell"
  },
  {
    "path": "example/dashboard-app/client/app/forgot/forgot.controller.spec.js",
    "chars": 450,
    "preview": "'use strict';\n\ndescribe('Controller: ForgotCtrl', function () {\n\n  // load the controller's module\n  beforeEach(module('"
  },
  {
    "path": "example/dashboard-app/client/app/forgot/forgot.css",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "example/dashboard-app/client/app/forgot/forgot.html",
    "chars": 243,
    "preview": "<div ng-include=\"'components/navbar/navbar.html'\"></div>\n\n<div class=\"container\">\n  <div class=\"row\">\n    <div class=\"co"
  },
  {
    "path": "example/dashboard-app/client/app/forgot/forgot.js",
    "chars": 247,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .config(function ($stateProvider) {\n    $stateProvider\n      .state('for"
  },
  {
    "path": "example/dashboard-app/client/app/login/login.controller.js",
    "chars": 129,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .controller('LoginCtrl', function ($scope) {\n    $scope.message = 'Hello"
  },
  {
    "path": "example/dashboard-app/client/app/login/login.controller.spec.js",
    "chars": 446,
    "preview": "'use strict';\n\ndescribe('Controller: LoginCtrl', function () {\n\n  // load the controller's module\n  beforeEach(module('d"
  },
  {
    "path": "example/dashboard-app/client/app/login/login.css",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "example/dashboard-app/client/app/login/login.html",
    "chars": 216,
    "preview": "<div ng-include=\"'components/navbar/navbar.html'\"></div>\n\n<div class=\"container\">\n  <div class=\"row\">\n    <div class=\"co"
  },
  {
    "path": "example/dashboard-app/client/app/login/login.js",
    "chars": 242,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .config(function ($stateProvider) {\n    $stateProvider\n      .state('log"
  },
  {
    "path": "example/dashboard-app/client/app/main/main.controller.js",
    "chars": 253,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .controller('MainCtrl', function ($scope, $http) {\n    $scope.awesomeThi"
  },
  {
    "path": "example/dashboard-app/client/app/main/main.controller.spec.js",
    "chars": 715,
    "preview": "'use strict';\n\ndescribe('Controller: MainCtrl', function () {\n\n  // load the controller's module\n  beforeEach(module('da"
  },
  {
    "path": "example/dashboard-app/client/app/main/main.css",
    "chars": 472,
    "preview": ".thing-form {\n    margin: 20px 0;\n}\n\n#banner {\n    border-bottom: none;\n    margin-top: -20px;\n}\n\n#banner h1 {\n    font-"
  },
  {
    "path": "example/dashboard-app/client/app/main/main.html",
    "chars": 917,
    "preview": "<div ng-include=\"'components/navbar/navbar.html'\"></div>\n\n<header class=\"hero-unit\" id=\"banner\">\n  <div class=\"container"
  },
  {
    "path": "example/dashboard-app/client/app/main/main.js",
    "chars": 233,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .config(function ($stateProvider) {\n    $stateProvider\n      .state('mai"
  },
  {
    "path": "example/dashboard-app/client/app/profile/profile.controller.js",
    "chars": 131,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .controller('ProfileCtrl', function ($scope) {\n    $scope.message = 'Hel"
  },
  {
    "path": "example/dashboard-app/client/app/profile/profile.controller.spec.js",
    "chars": 454,
    "preview": "'use strict';\n\ndescribe('Controller: ProfileCtrl', function () {\n\n  // load the controller's module\n  beforeEach(module("
  },
  {
    "path": "example/dashboard-app/client/app/profile/profile.css",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "example/dashboard-app/client/app/profile/profile.html",
    "chars": 303,
    "preview": "<div ng-include=\"'components/navbar/navbar.html'\"></div>\n\n<div class=\"container\">\n  <div class=\"row\">\n    <div class=\"co"
  },
  {
    "path": "example/dashboard-app/client/app/profile/profile.js",
    "chars": 306,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .config(function ($stateProvider) {\n    $stateProvider\n      .state('pro"
  },
  {
    "path": "example/dashboard-app/client/app/register/register.controller.js",
    "chars": 132,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .controller('RegisterCtrl', function ($scope) {\n    $scope.message = 'He"
  },
  {
    "path": "example/dashboard-app/client/app/register/register.controller.spec.js",
    "chars": 458,
    "preview": "'use strict';\n\ndescribe('Controller: RegisterCtrl', function () {\n\n  // load the controller's module\n  beforeEach(module"
  },
  {
    "path": "example/dashboard-app/client/app/register/register.css",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "example/dashboard-app/client/app/register/register.html",
    "chars": 254,
    "preview": "<div ng-include=\"'components/navbar/navbar.html'\"></div>\n\n<div class=\"container\">\n  <div class=\"row\">\n    <div class=\"co"
  },
  {
    "path": "example/dashboard-app/client/app/register/register.js",
    "chars": 257,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .config(function ($stateProvider) {\n    $stateProvider\n      .state('reg"
  },
  {
    "path": "example/dashboard-app/client/app/reset/reset.controller.js",
    "chars": 129,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .controller('ResetCtrl', function ($scope) {\n    $scope.message = 'Hello"
  },
  {
    "path": "example/dashboard-app/client/app/reset/reset.controller.spec.js",
    "chars": 446,
    "preview": "'use strict';\n\ndescribe('Controller: ResetCtrl', function () {\n\n  // load the controller's module\n  beforeEach(module('d"
  },
  {
    "path": "example/dashboard-app/client/app/reset/reset.css",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "example/dashboard-app/client/app/reset/reset.html",
    "chars": 239,
    "preview": "<div ng-include=\"'components/navbar/navbar.html'\"></div>\n\n<div class=\"container\">\n  <div class=\"row\">\n    <div class=\"co"
  },
  {
    "path": "example/dashboard-app/client/app/reset/reset.js",
    "chars": 250,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .config(function ($stateProvider) {\n    $stateProvider\n      .state('res"
  },
  {
    "path": "example/dashboard-app/client/app/verify/verify.controller.js",
    "chars": 130,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .controller('VerifyCtrl', function ($scope) {\n    $scope.message = 'Hell"
  },
  {
    "path": "example/dashboard-app/client/app/verify/verify.controller.spec.js",
    "chars": 450,
    "preview": "'use strict';\n\ndescribe('Controller: VerifyCtrl', function () {\n\n  // load the controller's module\n  beforeEach(module('"
  },
  {
    "path": "example/dashboard-app/client/app/verify/verify.css",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "example/dashboard-app/client/app/verify/verify.html",
    "chars": 238,
    "preview": "<div ng-include=\"'components/navbar/navbar.html'\"></div>\n\n<div class=\"container\">\n  <div class=\"row\">\n    <div class=\"co"
  },
  {
    "path": "example/dashboard-app/client/app/verify/verify.js",
    "chars": 255,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .config(function ($stateProvider) {\n    $stateProvider\n      .state('ver"
  },
  {
    "path": "example/dashboard-app/client/components/navbar/navbar.controller.js",
    "chars": 301,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .controller('NavbarCtrl', function ($scope, $location) {\n    $scope.menu"
  },
  {
    "path": "example/dashboard-app/client/components/navbar/navbar.html",
    "chars": 1285,
    "preview": "<div class=\"navbar navbar-default navbar-static-top\" ng-controller=\"NavbarCtrl\">\n  <div class=\"container\">\n    <div clas"
  },
  {
    "path": "example/dashboard-app/client/index.html",
    "chars": 4474,
    "preview": "<!doctype html>\n<!--[if lt IE 7]>      <html class=\"no-js lt-ie9 lt-ie8 lt-ie7\"> <![endif]-->\n<!--[if IE 7]>         <ht"
  },
  {
    "path": "example/dashboard-app/client/robots.txt",
    "chars": 31,
    "preview": "# robotstxt.org\n\nUser-agent: *\n"
  },
  {
    "path": "example/dashboard-app/e2e/main/main.po.js",
    "chars": 400,
    "preview": "/**\n * This file uses the Page Object pattern to define the main page for tests\n * https://docs.google.com/presentation/"
  },
  {
    "path": "example/dashboard-app/e2e/main/main.spec.js",
    "chars": 429,
    "preview": "'use strict';\n\ndescribe('Main View', function() {\n  var page;\n\n  beforeEach(function() {\n    browser.get('/');\n    page "
  },
  {
    "path": "example/dashboard-app/karma.conf.js",
    "chars": 2254,
    "preview": "// Karma configuration\n// http://karma-runner.github.io/0.10/config/configuration-file.html\n\nmodule.exports = function(c"
  },
  {
    "path": "example/dashboard-app/package.json",
    "chars": 2628,
    "preview": "{\n  \"name\": \"dashboard\",\n  \"version\": \"0.0.0\",\n  \"main\": \"server/app.js\",\n  \"dependencies\": {\n    \"body-parser\": \"~1.5.0"
  },
  {
    "path": "example/dashboard-app/protractor.conf.js",
    "chars": 1598,
    "preview": "// Protractor configuration\n// https://github.com/angular/protractor/blob/master/referenceConf.js\n\n'use strict';\n\nexport"
  },
  {
    "path": "example/dashboard-app/server/.jshintrc",
    "chars": 237,
    "preview": "{\n  \"node\": true,\n  \"esnext\": true,\n  \"bitwise\": true,\n  \"eqeqeq\": true,\n  \"immed\": true,\n  \"latedef\": \"nofunc\",\n  \"newc"
  },
  {
    "path": "example/dashboard-app/server/.jshintrc-spec",
    "chars": 172,
    "preview": "{\n  \"extends\": \".jshintrc\",\n  \"globals\": {\n    \"describe\": true,\n    \"it\": true,\n    \"before\": true,\n    \"beforeEach\": t"
  },
  {
    "path": "example/dashboard-app/server/api/thing/index.js",
    "chars": 190,
    "preview": "'use strict';\n\nvar express = require('express');\nvar controller = require('./thing.controller');\n\nvar router = express.R"
  },
  {
    "path": "example/dashboard-app/server/api/thing/thing.controller.js",
    "chars": 1414,
    "preview": "/**\n * Using Rails-like standard naming convention for endpoints.\n * GET     /things              ->  index\n * POST    /"
  },
  {
    "path": "example/dashboard-app/server/api/thing/thing.spec.js",
    "chars": 463,
    "preview": "'use strict';\n\nvar should = require('should');\nvar app = require('../../app');\nvar request = require('supertest');\n\ndesc"
  },
  {
    "path": "example/dashboard-app/server/app.js",
    "chars": 2329,
    "preview": "/**\n * Main application file\n */\n\n'use strict';\n\n// Set default node environment to development\nprocess.env.NODE_ENV = p"
  },
  {
    "path": "example/dashboard-app/server/components/errors/index.js",
    "chars": 367,
    "preview": "/**\n * Error responses\n */\n\n'use strict';\n\nmodule.exports[404] = function pageNotFound(req, res) {\n  var viewFilePath = "
  },
  {
    "path": "example/dashboard-app/server/config/environment/development.js",
    "chars": 222,
    "preview": "'use strict';\n\n// Development specific configuration\n// ==================================\nmodule.exports = {\n  // Mongo"
  },
  {
    "path": "example/dashboard-app/server/config/environment/index.js",
    "chars": 1083,
    "preview": "'use strict';\n\nvar path = require('path');\nvar _ = require('lodash');\n\nfunction requiredProcessEnv(name) {\n  if(!process"
  },
  {
    "path": "example/dashboard-app/server/config/environment/production.js",
    "chars": 596,
    "preview": "'use strict';\n\n// Production specific configuration\n// =================================\nmodule.exports = {\n  // Server "
  },
  {
    "path": "example/dashboard-app/server/config/environment/test.js",
    "chars": 191,
    "preview": "'use strict';\n\n// Test specific configuration\n// ===========================\nmodule.exports = {\n  // MongoDB connection "
  },
  {
    "path": "example/dashboard-app/server/config/express.js",
    "chars": 1413,
    "preview": "/**\n * Express configuration\n */\n\n'use strict';\n\nvar express = require('express');\nvar favicon = require('serve-favicon'"
  },
  {
    "path": "example/dashboard-app/server/config/local.env.sample.js",
    "chars": 437,
    "preview": "'use strict';\n\n// Use local.env.js for environment variables that grunt will set when the server starts locally.\n// Use "
  },
  {
    "path": "example/dashboard-app/server/routes.js",
    "chars": 601,
    "preview": "/**\n * Main application routes\n */\n\n'use strict';\n\nvar errors = require('./components/errors');\nvar ExpressStormpath = r"
  },
  {
    "path": "example/dashboard-app/server/views/404.html",
    "chars": 3529,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>Page Not Found :(</title>\n    <style>\n  "
  },
  {
    "path": "example/ng-route-app/.bowerrc",
    "chars": 47,
    "preview": "{\n    \"directory\": \"client/bower_components\"\n}\n"
  },
  {
    "path": "example/ng-route-app/.buildignore",
    "chars": 8,
    "preview": "*.coffee"
  },
  {
    "path": "example/ng-route-app/.editorconfig",
    "chars": 415,
    "preview": "# EditorConfig helps developers define and maintain consistent\n# coding styles between different editors and IDEs\n# edit"
  },
  {
    "path": "example/ng-route-app/.gitattributes",
    "chars": 11,
    "preview": "* text=auto"
  },
  {
    "path": "example/ng-route-app/.gitignore",
    "chars": 102,
    "preview": "node_modules\npublic\n.tmp\n.idea\nclient/bower_components\ndist\n/server/config/local.env.js\nstormpath.yml\n"
  },
  {
    "path": "example/ng-route-app/.travis.yml",
    "chars": 134,
    "preview": "language: node_js\nnode_js:\n  - '0.10'\n  - '0.11'\nbefore_script:\n  - npm install -g bower grunt-cli\n  - bower install\nser"
  },
  {
    "path": "example/ng-route-app/.yo-rc.json",
    "chars": 1118,
    "preview": "{\n  \"generator-angular-fullstack\": {\n    \"insertRoutes\": true,\n    \"registerRoutesFile\": \"server/routes.js\",\n    \"routes"
  },
  {
    "path": "example/ng-route-app/Gruntfile.js",
    "chars": 15346,
    "preview": "// Generated on 2015-09-24 using generator-angular-fullstack 2.0.13\n'use strict';\n\nmodule.exports = function (grunt) {\n "
  },
  {
    "path": "example/ng-route-app/README.md",
    "chars": 1432,
    "preview": "# Stormpath Angular SDK Example\n\nThis folder contains an example application that is built with the [Stormpath Angular S"
  },
  {
    "path": "example/ng-route-app/bower.json",
    "chars": 524,
    "preview": "{\n  \"name\": \"dashboard\",\n  \"version\": \"0.0.0\",\n  \"dependencies\": {\n    \"angular\": \">=1.2.*\",\n    \"json3\": \"~3.3.1\",\n    "
  },
  {
    "path": "example/ng-route-app/client/.htaccess",
    "chars": 24135,
    "preview": "# Apache Configuration File\n\n# (!) Using `.htaccess` files slows down Apache, therefore, if you have access\n# to the mai"
  },
  {
    "path": "example/ng-route-app/client/.jshintrc",
    "chars": 664,
    "preview": "{\n  \"node\": true,\n  \"browser\": true,\n  \"esnext\": true,\n  \"bitwise\": true,\n  \"camelcase\": true,\n  \"curly\": true,\n  \"eqeqe"
  },
  {
    "path": "example/ng-route-app/client/app/app.css",
    "chars": 1395,
    "preview": "\n/**\n * Bootstrap Fonts\n */\n\n@font-face {\n    font-family: 'Glyphicons Halflings';\n    src: url('../bower_components/boo"
  },
  {
    "path": "example/ng-route-app/client/app/app.js",
    "chars": 527,
    "preview": "'use strict';\n\nangular.module('dashboardApp', [\n  'ngCookies',\n  'ngResource',\n  'ngSanitize',\n  'ngRoute',\n  'stormpath"
  },
  {
    "path": "example/ng-route-app/client/app/forgot/forgot.controller.js",
    "chars": 130,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .controller('ForgotCtrl', function ($scope) {\n    $scope.message = 'Hell"
  },
  {
    "path": "example/ng-route-app/client/app/forgot/forgot.controller.spec.js",
    "chars": 450,
    "preview": "'use strict';\n\ndescribe('Controller: ForgotCtrl', function () {\n\n  // load the controller's module\n  beforeEach(module('"
  },
  {
    "path": "example/ng-route-app/client/app/forgot/forgot.css",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "example/ng-route-app/client/app/forgot/forgot.html",
    "chars": 243,
    "preview": "<div ng-include=\"'components/navbar/navbar.html'\"></div>\n\n<div class=\"container\">\n  <div class=\"row\">\n    <div class=\"co"
  },
  {
    "path": "example/ng-route-app/client/app/forgot/forgot.js",
    "chars": 223,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .config(function ($routeProvider) {\n    $routeProvider\n      .when('/for"
  },
  {
    "path": "example/ng-route-app/client/app/login/login.controller.js",
    "chars": 129,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .controller('LoginCtrl', function ($scope) {\n    $scope.message = 'Hello"
  },
  {
    "path": "example/ng-route-app/client/app/login/login.controller.spec.js",
    "chars": 446,
    "preview": "'use strict';\n\ndescribe('Controller: LoginCtrl', function () {\n\n  // load the controller's module\n  beforeEach(module('d"
  },
  {
    "path": "example/ng-route-app/client/app/login/login.css",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "example/ng-route-app/client/app/login/login.html",
    "chars": 216,
    "preview": "<div ng-include=\"'components/navbar/navbar.html'\"></div>\n\n<div class=\"container\">\n  <div class=\"row\">\n    <div class=\"co"
  },
  {
    "path": "example/ng-route-app/client/app/login/login.js",
    "chars": 219,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .config(function ($routeProvider) {\n    $routeProvider\n      .when('/log"
  },
  {
    "path": "example/ng-route-app/client/app/main/main.controller.js",
    "chars": 253,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .controller('MainCtrl', function ($scope, $http) {\n    $scope.awesomeThi"
  },
  {
    "path": "example/ng-route-app/client/app/main/main.controller.spec.js",
    "chars": 715,
    "preview": "'use strict';\n\ndescribe('Controller: MainCtrl', function () {\n\n  // load the controller's module\n  beforeEach(module('da"
  },
  {
    "path": "example/ng-route-app/client/app/main/main.css",
    "chars": 472,
    "preview": ".thing-form {\n    margin: 20px 0;\n}\n\n#banner {\n    border-bottom: none;\n    margin-top: -20px;\n}\n\n#banner h1 {\n    font-"
  },
  {
    "path": "example/ng-route-app/client/app/main/main.html",
    "chars": 917,
    "preview": "<div ng-include=\"'components/navbar/navbar.html'\"></div>\n\n<header class=\"hero-unit\" id=\"banner\">\n  <div class=\"container"
  },
  {
    "path": "example/ng-route-app/client/app/main/main.js",
    "chars": 211,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .config(function ($routeProvider) {\n    $routeProvider\n      .when('/', "
  },
  {
    "path": "example/ng-route-app/client/app/profile/profile.controller.js",
    "chars": 131,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .controller('ProfileCtrl', function ($scope) {\n    $scope.message = 'Hel"
  },
  {
    "path": "example/ng-route-app/client/app/profile/profile.controller.spec.js",
    "chars": 454,
    "preview": "'use strict';\n\ndescribe('Controller: ProfileCtrl', function () {\n\n  // load the controller's module\n  beforeEach(module("
  },
  {
    "path": "example/ng-route-app/client/app/profile/profile.css",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "example/ng-route-app/client/app/profile/profile.html",
    "chars": 303,
    "preview": "<div ng-include=\"'components/navbar/navbar.html'\"></div>\n\n<div class=\"container\">\n  <div class=\"row\">\n    <div class=\"co"
  },
  {
    "path": "example/ng-route-app/client/app/profile/profile.js",
    "chars": 281,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .config(function ($routeProvider) {\n    $routeProvider\n      .when('/pro"
  },
  {
    "path": "example/ng-route-app/client/app/register/register.controller.js",
    "chars": 132,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .controller('RegisterCtrl', function ($scope) {\n    $scope.message = 'He"
  },
  {
    "path": "example/ng-route-app/client/app/register/register.controller.spec.js",
    "chars": 458,
    "preview": "'use strict';\n\ndescribe('Controller: RegisterCtrl', function () {\n\n  // load the controller's module\n  beforeEach(module"
  },
  {
    "path": "example/ng-route-app/client/app/register/register.css",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "example/ng-route-app/client/app/register/register.html",
    "chars": 254,
    "preview": "<div ng-include=\"'components/navbar/navbar.html'\"></div>\n\n<div class=\"container\">\n  <div class=\"row\">\n    <div class=\"co"
  },
  {
    "path": "example/ng-route-app/client/app/register/register.js",
    "chars": 231,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .config(function ($routeProvider) {\n    $routeProvider\n      .when('/reg"
  },
  {
    "path": "example/ng-route-app/client/app/reset/reset.controller.js",
    "chars": 129,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .controller('ResetCtrl', function ($scope) {\n    $scope.message = 'Hello"
  },
  {
    "path": "example/ng-route-app/client/app/reset/reset.controller.spec.js",
    "chars": 446,
    "preview": "'use strict';\n\ndescribe('Controller: ResetCtrl', function () {\n\n  // load the controller's module\n  beforeEach(module('d"
  },
  {
    "path": "example/ng-route-app/client/app/reset/reset.css",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "example/ng-route-app/client/app/reset/reset.html",
    "chars": 239,
    "preview": "<div ng-include=\"'components/navbar/navbar.html'\"></div>\n\n<div class=\"container\">\n  <div class=\"row\">\n    <div class=\"co"
  },
  {
    "path": "example/ng-route-app/client/app/reset/reset.js",
    "chars": 219,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .config(function ($routeProvider) {\n    $routeProvider\n      .when('/res"
  },
  {
    "path": "example/ng-route-app/client/app/verify/verify.controller.js",
    "chars": 130,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .controller('VerifyCtrl', function ($scope) {\n    $scope.message = 'Hell"
  },
  {
    "path": "example/ng-route-app/client/app/verify/verify.controller.spec.js",
    "chars": 450,
    "preview": "'use strict';\n\ndescribe('Controller: VerifyCtrl', function () {\n\n  // load the controller's module\n  beforeEach(module('"
  },
  {
    "path": "example/ng-route-app/client/app/verify/verify.css",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "example/ng-route-app/client/app/verify/verify.html",
    "chars": 238,
    "preview": "<div ng-include=\"'components/navbar/navbar.html'\"></div>\n\n<div class=\"container\">\n  <div class=\"row\">\n    <div class=\"co"
  },
  {
    "path": "example/ng-route-app/client/app/verify/verify.js",
    "chars": 223,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .config(function ($routeProvider) {\n    $routeProvider\n      .when('/ver"
  },
  {
    "path": "example/ng-route-app/client/components/navbar/navbar.controller.js",
    "chars": 301,
    "preview": "'use strict';\n\nangular.module('dashboardApp')\n  .controller('NavbarCtrl', function ($scope, $location) {\n    $scope.menu"
  },
  {
    "path": "example/ng-route-app/client/components/navbar/navbar.html",
    "chars": 1273,
    "preview": "<div class=\"navbar navbar-default navbar-static-top\" ng-controller=\"NavbarCtrl\">\n  <div class=\"container\">\n    <div clas"
  },
  {
    "path": "example/ng-route-app/client/index.html",
    "chars": 4455,
    "preview": "<!doctype html>\n<!--[if lt IE 7]>      <html class=\"no-js lt-ie9 lt-ie8 lt-ie7\"> <![endif]-->\n<!--[if IE 7]>         <ht"
  },
  {
    "path": "example/ng-route-app/client/robots.txt",
    "chars": 31,
    "preview": "# robotstxt.org\n\nUser-agent: *\n"
  },
  {
    "path": "example/ng-route-app/e2e/main/main.po.js",
    "chars": 400,
    "preview": "/**\n * This file uses the Page Object pattern to define the main page for tests\n * https://docs.google.com/presentation/"
  },
  {
    "path": "example/ng-route-app/e2e/main/main.spec.js",
    "chars": 429,
    "preview": "'use strict';\n\ndescribe('Main View', function() {\n  var page;\n\n  beforeEach(function() {\n    browser.get('/');\n    page "
  },
  {
    "path": "example/ng-route-app/karma.conf.js",
    "chars": 2254,
    "preview": "// Karma configuration\n// http://karma-runner.github.io/0.10/config/configuration-file.html\n\nmodule.exports = function(c"
  },
  {
    "path": "example/ng-route-app/package.json",
    "chars": 2627,
    "preview": "{\n  \"name\": \"dashboard\",\n  \"version\": \"0.0.0\",\n  \"main\": \"server/app.js\",\n  \"dependencies\": {\n    \"body-parser\": \"~1.5.0"
  },
  {
    "path": "example/ng-route-app/protractor.conf.js",
    "chars": 1598,
    "preview": "// Protractor configuration\n// https://github.com/angular/protractor/blob/master/referenceConf.js\n\n'use strict';\n\nexport"
  },
  {
    "path": "example/ng-route-app/server/.jshintrc",
    "chars": 237,
    "preview": "{\n  \"node\": true,\n  \"esnext\": true,\n  \"bitwise\": true,\n  \"eqeqeq\": true,\n  \"immed\": true,\n  \"latedef\": \"nofunc\",\n  \"newc"
  },
  {
    "path": "example/ng-route-app/server/.jshintrc-spec",
    "chars": 172,
    "preview": "{\n  \"extends\": \".jshintrc\",\n  \"globals\": {\n    \"describe\": true,\n    \"it\": true,\n    \"before\": true,\n    \"beforeEach\": t"
  },
  {
    "path": "example/ng-route-app/server/api/thing/index.js",
    "chars": 190,
    "preview": "'use strict';\n\nvar express = require('express');\nvar controller = require('./thing.controller');\n\nvar router = express.R"
  },
  {
    "path": "example/ng-route-app/server/api/thing/thing.controller.js",
    "chars": 1414,
    "preview": "/**\n * Using Rails-like standard naming convention for endpoints.\n * GET     /things              ->  index\n * POST    /"
  },
  {
    "path": "example/ng-route-app/server/api/thing/thing.spec.js",
    "chars": 463,
    "preview": "'use strict';\n\nvar should = require('should');\nvar app = require('../../app');\nvar request = require('supertest');\n\ndesc"
  },
  {
    "path": "example/ng-route-app/server/app.js",
    "chars": 1514,
    "preview": "/**\n * Main application file\n */\n\n'use strict';\n\n// Set default node environment to development\nprocess.env.NODE_ENV = p"
  },
  {
    "path": "example/ng-route-app/server/components/errors/index.js",
    "chars": 367,
    "preview": "/**\n * Error responses\n */\n\n'use strict';\n\nmodule.exports[404] = function pageNotFound(req, res) {\n  var viewFilePath = "
  },
  {
    "path": "example/ng-route-app/server/config/environment/development.js",
    "chars": 222,
    "preview": "'use strict';\n\n// Development specific configuration\n// ==================================\nmodule.exports = {\n  // Mongo"
  },
  {
    "path": "example/ng-route-app/server/config/environment/index.js",
    "chars": 1083,
    "preview": "'use strict';\n\nvar path = require('path');\nvar _ = require('lodash');\n\nfunction requiredProcessEnv(name) {\n  if(!process"
  },
  {
    "path": "example/ng-route-app/server/config/environment/production.js",
    "chars": 596,
    "preview": "'use strict';\n\n// Production specific configuration\n// =================================\nmodule.exports = {\n  // Server "
  },
  {
    "path": "example/ng-route-app/server/config/environment/test.js",
    "chars": 191,
    "preview": "'use strict';\n\n// Test specific configuration\n// ===========================\nmodule.exports = {\n  // MongoDB connection "
  },
  {
    "path": "example/ng-route-app/server/config/express.js",
    "chars": 1414,
    "preview": "/**\n * Express configuration\n */\n\n'use strict';\n\nvar express = require('express');\nvar favicon = require('serve-favicon'"
  },
  {
    "path": "example/ng-route-app/server/config/local.env.sample.js",
    "chars": 437,
    "preview": "'use strict';\n\n// Use local.env.js for environment variables that grunt will set when the server starts locally.\n// Use "
  },
  {
    "path": "example/ng-route-app/server/routes.js",
    "chars": 601,
    "preview": "/**\n * Main application routes\n */\n\n'use strict';\n\nvar errors = require('./components/errors');\nvar ExpressStormpath = r"
  },
  {
    "path": "example/ng-route-app/server/views/404.html",
    "chars": 3529,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>Page Not Found :(</title>\n    <style>\n  "
  },
  {
    "path": "index.js",
    "chars": 126,
    "preview": "var name = require('./dist/stormpath-sdk-angularjs');\nrequire('./dist/stormpath-sdk-angularjs.tpls');\n\nmodule.exports = "
  },
  {
    "path": "ngdoc_assets/example/index.ngdoc",
    "chars": 398,
    "preview": "@ngdoc overview\n@name Example\n@description\n\n\n## Example\n\nWe have a complete sample application which shows you how to cr"
  },
  {
    "path": "ngdoc_assets/index.ngdoc",
    "chars": 776,
    "preview": "@ngdoc overview\n@name API Documentation\n@description\n\n# Stormpath Angular JS SDK Ng Docs\n\n[![Bower Version](https://img."
  },
  {
    "path": "ngdoc_assets/nav.html",
    "chars": 172,
    "preview": "<ul class=\"nav pull-left\">\n  <li><a href=\"https://github.com/stormpath/stormpath-sdk-angularjs\" target=\"_blank\"><i class"
  },
  {
    "path": "ngdoc_assets/server/index.ngdoc",
    "chars": 6053,
    "preview": "@ngdoc overview\n@name Server Integration Guide\n@description\n\n# Server Integration Guide\n\nFront-end applications can not "
  },
  {
    "path": "ngdoc_assets/stormpath-angular.css",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "package.json",
    "chars": 1002,
    "preview": "{\n  \"name\": \"stormpath-sdk-angularjs\",\n  \"version\": \"2.0.1\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n "
  },
  {
    "path": "protractor.conf.js",
    "chars": 94,
    "preview": "'use strict';\n\nexports.config = {\n  directConnect: true,\n  specs: ['test/protractor/*.js']\n};\n"
  },
  {
    "path": "src/module.js",
    "chars": 38999,
    "preview": "'use strict';\n\n/**\n * @ngdoc object\n *\n * @name stormpath.SpStateConfig:SpStateConfig\n *\n * @property {boolean} authenti"
  },
  {
    "path": "src/spEmailVerification.tpl.html",
    "chars": 1707,
    "preview": "<div class=\"row\">\n  <div class=\"col-sm-offset-4 col-xs-12 col-sm-4\">\n    <p ng-show=\"verifying\" class=\"alert alert-warni"
  },
  {
    "path": "src/spLoginForm.tpl.html",
    "chars": 2133,
    "preview": "<style>\n  .btn.btn-social {\n    margin-right: 7px;\n    min-width: 100px;\n  }\n\n  .btn.btn-facebook {\n    color: white;\n  "
  },
  {
    "path": "src/spPasswordResetForm.tpl.html",
    "chars": 1661,
    "preview": "<div class=\"row\">\n  <div class=\"col-sm-offset-4 col-xs-12 col-sm-4\">\n    <p ng-show=\"verifying\" class=\"alert alert-warni"
  },
  {
    "path": "src/spPasswordResetRequestForm.tpl.html",
    "chars": 1242,
    "preview": "<div class=\"row\">\n  <div class=\"col-sm-offset-4 col-xs-12 col-sm-4\">\n    <p ng-show=\"sent\" class=\"alert alert-success\">\n"
  },
  {
    "path": "src/spRegistrationForm.tpl.html",
    "chars": 2593,
    "preview": "<style>\n  .btn.btn-social {\n    margin-right: 7px;\n    min-width: 100px;\n  }\n\n  .btn.btn-facebook {\n    color: white;\n  "
  },
  {
    "path": "src/stormpath.auth.js",
    "chars": 8369,
    "preview": "'use strict';\n/**\n * @ngdoc overview\n *\n * @name  stormpath.authService\n *\n * @description\n *\n * This module provides th"
  },
  {
    "path": "src/stormpath.config.js",
    "chars": 15058,
    "preview": "'use strict';\n\n/**\n* @ngdoc object\n*\n* @name stormpath.STORMPATH_CONFIG:STORMPATH_CONFIG\n*\n* @description\n*\n* This const"
  }
]

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

About this extraction

This page contains the full source code of the stormpath/stormpath-sdk-angularjs GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 212 files (563.4 KB), approximately 144.0k tokens, and a symbol index with 66 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!